From e59411ffe049b89de9313c9af659610abf3ca684 Mon Sep 17 00:00:00 2001 From: Patrick Connolly Date: Mon, 13 Apr 2026 21:50:16 -0400 Subject: [PATCH 1/4] Add CLAUDE.md with build commands and architecture overview Co-Authored-By: Claude Sonnet 4.6 --- CLAUDE.md | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..25a808c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,61 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Commands + +**Build:** +```sh +npm run build # TypeScript compilation (tsc) + Rollup bundling +npm run dev # Watch mode for development +``` + +**Test:** +```sh +npm test # Run full test suite (Node + Browser via Playwright) +npm run test:coverage # Run tests with v8 coverage reporting +npm run test:types # TypeScript type checking +npm run test:types:strict # Strict TypeScript type checking +``` + +To run a single test file: +```sh +npx vitest run test/dimred/PCA.test.js +``` + +**Code Quality:** +```sh +npm run lint # Biomejs lint on ./src +npm run format # Biomejs format ./src and ./test +npm run check # Biomejs check with auto-write on ./src +``` + +**Docs:** +```sh +npm run docs:dev # VitePress dev server +npm run docs:build # Build TypeDoc API docs + VitePress static site +``` + +## Architecture + +DruidJS is a dimensionality reduction library. Source lives in `src/` and distributes as both ESM (`dist/druid.js`) and CJS (`dist/druid.cjs`). The main entry point is `src/index.js`, which re-exports all submodules. + +**Module breakdown:** +- `src/dimred/` — 17 DR algorithms (PCA, MDS, TSNE, UMAP, ISOMAP, LDA, LLE, etc.) plus a base DR class +- `src/clustering/` — 8 clustering algorithms (KMeans, KMedoids, OPTICS, CURE, MeanShift, etc.) +- `src/knn/` — 7 nearest-neighbor implementations (BallTree, KDTree, HNSW, NNDescent, Annoy, LSH, NaiveKNN) +- `src/matrix/` — Core Matrix class with linear algebra operations (transpose, dot, inverse, QR, eigen) +- `src/linear_algebra/` — QR decomposition, eigendecomposition via simultaneous power iteration +- `src/metrics/` — 17 distance metrics (Euclidean, Cosine, Jaccard, Wasserstein, etc.) +- `src/datastructure/` — Heap, DisjointSet +- `src/numerical/` — Numerically stable summation (Kahan, Neumair) +- `src/optimization/` — Powell optimizer +- `src/util/` — Randomizer, min/max utilities + +Each subdirectory exports its public API through a local `index.js`. + +**Type system:** The project uses plain JavaScript with JSDoc annotations. TypeScript (`tsc`) reads those annotations to emit declaration files into `dist/types/`, which Rollup then bundles into `dist/druid.d.ts` (ESM) and `dist/druid.d.cts` (CJS). Type tests live in `test/types/`. + +**Testing:** Vitest runs two project environments simultaneously — standard Node and multi-browser via Playwright (Chromium, Firefox, WebKit). Test files mirror the `src/` directory layout under `test/`. + +**Package manager:** pnpm (v10+). From 272141b0154c39c93acb7a62d748f2aef512888f Mon Sep 17 00:00:00 2001 From: Patrick Connolly Date: Mon, 13 Apr 2026 22:23:11 -0400 Subject: [PATCH 2/4] Add PaCMAP and LocalMAP dimensionality reduction algorithms Ports the Python PaCMAP implementation to JavaScript, following the existing UMAP/TriMap stylistic patterns. PaCMAP uses three explicit pair types (NN, MN, FP) with a dynamic three-phase weight schedule and Adam optimization. LocalMAP extends PaCMAP with embedding-space FP resampling in phase 3 for sharper local cluster separation. Co-Authored-By: Claude Sonnet 4.6 --- dist/druid.cjs | 21089 ++++++++++++++++---------------- dist/druid.cjs.map | 2 +- dist/druid.d.cts | 7438 ++++++------ dist/druid.d.cts.map | 2 +- dist/druid.d.ts | 7438 ++++++------ dist/druid.d.ts.map | 2 +- dist/druid.js | 21150 +++++++++++++++++---------------- dist/druid.js.map | 2 +- docs/.vitepress/config.ts | 8 + docs/dimred/localmap.md | 48 + docs/dimred/pacmap.md | 45 + src/dimred/LocalMAP.js | 232 + src/dimred/PaCMAP.js | 409 + src/dimred/index.js | 27 + test/dimred/LocalMAP.test.js | 75 + test/dimred/PaCMAP.test.js | 79 + 16 files changed, 30001 insertions(+), 28045 deletions(-) create mode 100644 docs/dimred/localmap.md create mode 100644 docs/dimred/pacmap.md create mode 100644 src/dimred/LocalMAP.js create mode 100644 src/dimred/PaCMAP.js create mode 100644 test/dimred/LocalMAP.test.js create mode 100644 test/dimred/PaCMAP.test.js diff --git a/dist/druid.cjs b/dist/druid.cjs index a5084b8..6f4a2bf 100644 --- a/dist/druid.cjs +++ b/dist/druid.cjs @@ -1,9 +1,8 @@ -"use strict"; +'use strict'; var version$1 = "0.8.0"; var pkg = { - version: version$1, -}; + version: version$1}; /** * Computes the Bray-Curtis distance between `a` and `b`. @@ -15,14 +14,14 @@ var pkg = { * @see {@link https://en.wikipedia.org/wiki/Bray%E2%80%93Curtis_dissimilarity} */ function bray_curtis(a, b) { - if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); - let sum_abs_diff = 0; - let sum_ab = 0; - for (let i = 0; i < a.length; ++i) { - sum_abs_diff += Math.abs(a[i] - b[i]); - sum_ab += a[i] + b[i]; - } - return sum_abs_diff / sum_ab; + if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); + let sum_abs_diff = 0; + let sum_ab = 0; + for (let i = 0; i < a.length; ++i) { + sum_abs_diff += Math.abs(a[i] - b[i]); + sum_ab += a[i] + b[i]; + } + return sum_abs_diff / sum_ab; } /** @@ -35,13 +34,13 @@ function bray_curtis(a, b) { * @see {@link https://en.wikipedia.org/wiki/Canberra_distance} */ function canberra(a, b) { - if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); - const n = a.length; - let sum = 0; - for (let i = 0; i < n; ++i) { - sum += Math.abs(a[i] - b[i]) / (Math.abs(a[i]) + Math.abs(b[i])); - } - return sum; + if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); + const n = a.length; + let sum = 0; + for (let i = 0; i < n; ++i) { + sum += Math.abs(a[i] - b[i]) / (Math.abs(a[i]) + Math.abs(b[i])); + } + return sum; } /** @@ -53,13 +52,13 @@ function canberra(a, b) { * @returns {number} The chebyshev distance between `a` and `b`. */ function chebyshev(a, b) { - if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); - const n = a.length; - const res = []; - for (let i = 0; i < n; ++i) { - res.push(Math.abs(a[i] - b[i])); - } - return Math.max(...res); + if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); + const n = a.length; + const res = []; + for (let i = 0; i < n; ++i) { + res.push(Math.abs(a[i] - b[i])); + } + return Math.max(...res); } /** @@ -76,17 +75,17 @@ function chebyshev(a, b) { * const distance = cosine(a, b); // 0.9746318461970762 */ function cosine(a, b) { - if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); - const n = a.length; - let sum = 0; - let sum_a = 0; - let sum_b = 0; - for (let i = 0; i < n; ++i) { - sum += a[i] * b[i]; - sum_a += a[i] * a[i]; - sum_b += b[i] * b[i]; - } - return Math.acos(sum / (Math.sqrt(sum_a) * Math.sqrt(sum_b))); + if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); + const n = a.length; + let sum = 0; + let sum_a = 0; + let sum_b = 0; + for (let i = 0; i < n; ++i) { + sum += a[i] * b[i]; + sum_a += a[i] * a[i]; + sum_b += b[i] * b[i]; + } + return Math.acos(sum / (Math.sqrt(sum_a) * Math.sqrt(sum_b))); } /** @@ -99,14 +98,14 @@ function cosine(a, b) { */ function euclidean_squared(a, b) { - if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); - const n = a.length; - let sum = 0; - for (let i = 0; i < n; ++i) { - const a_b = a[i] - b[i]; - sum += a_b * a_b; - } - return sum; + if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); + const n = a.length; + let sum = 0; + for (let i = 0; i < n; ++i) { + const a_b = a[i] - b[i]; + sum += a_b * a_b; + } + return sum; } /** @@ -118,7 +117,7 @@ function euclidean_squared(a, b) { * @returns {number} The euclidean distance between `a` and `b`. */ function euclidean(a, b) { - return Math.sqrt(euclidean_squared(a, b)); + return Math.sqrt(euclidean_squared(a, b)); } /** @@ -131,42 +130,41 @@ function euclidean(a, b) { * @see {@link https://en.wikipedia.org/wiki/Goodman_and_Kruskal%27s_gamma} */ function goodman_kruskal(a, b) { - if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); - const n = a.length; - if (n < 2) return 0; - - let concordant = 0; - let discordant = 0; - let tie_a = 0; - let tie_b = 0; - - for (let i = 0; i < n; ++i) { - for (let j = i + 1; j < n; ++j) { - const a_diff = a[i] - a[j]; - const b_diff = b[i] - b[j]; - const a_tied = a_diff === 0; - const b_tied = b_diff === 0; - - if (a_tied && b_tied); - else if (a_tied) { - tie_a++; - } else if (b_tied) { - tie_b++; - } else if (a_diff * b_diff > 0) { - concordant++; - } else { - discordant++; - } - } - } - - const denominator = concordant + discordant + tie_a + tie_b; - if (denominator === 0) return 0; - - const numerator = concordant + discordant; - if (numerator === 0) return 0; - - return (concordant - discordant) / numerator; + if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); + const n = a.length; + if (n < 2) return 0; + + let concordant = 0; + let discordant = 0; + let tie_a = 0; + let tie_b = 0; + + for (let i = 0; i < n; ++i) { + for (let j = i + 1; j < n; ++j) { + const a_diff = a[i] - a[j]; + const b_diff = b[i] - b[j]; + const a_tied = a_diff === 0; + const b_tied = b_diff === 0; + + if (a_tied && b_tied) ; else if (a_tied) { + tie_a++; + } else if (b_tied) { + tie_b++; + } else if (a_diff * b_diff > 0) { + concordant++; + } else { + discordant++; + } + } + } + + const denominator = concordant + discordant + tie_a + tie_b; + if (denominator === 0) return 0; + + const numerator = concordant + discordant; + if (numerator === 0) return 0; + + return (concordant - discordant) / numerator; } /** @@ -178,15 +176,15 @@ function goodman_kruskal(a, b) { * @returns {number} The hamming distance between `a` and `b`. */ function hamming(a, b) { - if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); - const n = a.length; - let disagree = 0; - for (let i = 0; i < n; ++i) { - const x = a[i]; - const y = b[i]; - disagree += x !== y ? 1 : 0; - } - return disagree / n; + if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); + const n = a.length; + let disagree = 0; + for (let i = 0; i < n; ++i) { + const x = a[i]; + const y = b[i]; + disagree += x !== y ? 1 : 0; + } + return disagree / n; } /** @@ -199,23 +197,23 @@ function hamming(a, b) { * @see {@link https://en.wikipedia.org/wiki/Haversine_formula} */ function haversine(a, b) { - if (a.length !== 2 || b.length !== 2) - throw new Error("Haversine distance requires exactly 2 coordinates [lat, lon] for each point!"); - const lat1 = a[0]; - const lon1 = a[1]; - const lat2 = b[0]; - const lon2 = b[1]; + if (a.length !== 2 || b.length !== 2) + throw new Error("Haversine distance requires exactly 2 coordinates [lat, lon] for each point!"); + const lat1 = a[0]; + const lon1 = a[1]; + const lat2 = b[0]; + const lon2 = b[1]; - const dlat = lat2 - lat1; - const dlon = lon2 - lon1; + const dlat = lat2 - lat1; + const dlon = lon2 - lon1; - const sin_dlat2 = Math.sin(dlat / 2); - const sin_dlon2 = Math.sin(dlon / 2); + const sin_dlat2 = Math.sin(dlat / 2); + const sin_dlon2 = Math.sin(dlon / 2); - const x = sin_dlat2 * sin_dlat2 + Math.cos(lat1) * Math.cos(lat2) * sin_dlon2 * sin_dlon2; - const c = 2 * Math.atan2(Math.sqrt(x), Math.sqrt(1 - x)); + const x = sin_dlat2 * sin_dlat2 + Math.cos(lat1) * Math.cos(lat2) * sin_dlon2 * sin_dlon2; + const c = 2 * Math.atan2(Math.sqrt(x), Math.sqrt(1 - x)); - return c; + return c; } /** @@ -227,17 +225,17 @@ function haversine(a, b) { * @returns {number} The jaccard distance between `a` and `b`. */ function jaccard(a, b) { - if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); - const n = a.length; - let num_non_zero = 0; - let num_equal = 0; - for (let i = 0; i < n; ++i) { - const x = a[i] !== 0; - const y = b[i] !== 0; - num_non_zero += x || y ? 1 : 0; - num_equal += x && y ? 1 : 0; - } - return (num_non_zero - num_equal) / num_non_zero; + if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); + const n = a.length; + let num_non_zero = 0; + let num_equal = 0; + for (let i = 0; i < n; ++i) { + const x = a[i] !== 0; + const y = b[i] !== 0; + num_non_zero += x || y ? 1 : 0; + num_equal += x && y ? 1 : 0; + } + return (num_non_zero - num_equal) / num_non_zero; } /** @@ -249,13 +247,13 @@ function jaccard(a, b) { * @returns {number} The manhattan distance between `a` and `b`. */ function manhattan(a, b) { - if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); - const n = a.length; - let sum = 0; - for (let i = 0; i < n; ++i) { - sum += Math.abs(a[i] - b[i]); - } - return sum; + if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); + const n = a.length; + let sum = 0; + for (let i = 0; i < n; ++i) { + sum += Math.abs(a[i] - b[i]); + } + return sum; } /** @@ -268,15 +266,15 @@ function manhattan(a, b) { */ function sokal_michener(a, b) { - if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); - const n = a.length; - let num_not_equal = 0; - for (let i = 0; i < n; ++i) { - const x = a[i] !== 0; - const y = b[i] !== 0; - num_not_equal += x !== y ? 1 : 0; - } - return (2 * num_not_equal) / (n + num_not_equal); + if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); + const n = a.length; + let num_not_equal = 0; + for (let i = 0; i < n; ++i) { + const x = a[i] !== 0; + const y = b[i] !== 0; + num_not_equal += x !== y ? 1 : 0; + } + return (2 * num_not_equal) / (n + num_not_equal); } /** @@ -289,28 +287,28 @@ function sokal_michener(a, b) { * @see {@link https://en.wikipedia.org/wiki/Wasserstein_metric} */ function wasserstein(a, b) { - if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); - const n = a.length; - let sumA = 0; - let sumB = 0; - for (let i = 0; i < n; i++) { - sumA += a[i]; - sumB += b[i]; - } - - // Fallback if sums are 0 - if (sumA === 0 && sumB === 0) return 0; - if (sumA === 0 || sumB === 0) return Infinity; - - let distance = 0; - let cumA = 0; - let cumB = 0; - for (let i = 0; i < n; i++) { - cumA += a[i] / sumA; - cumB += b[i] / sumB; - distance += Math.abs(cumA - cumB); - } - return distance; + if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); + const n = a.length; + let sumA = 0; + let sumB = 0; + for (let i = 0; i < n; i++) { + sumA += a[i]; + sumB += b[i]; + } + + // Fallback if sums are 0 + if (sumA === 0 && sumB === 0) return 0; + if (sumA === 0 || sumB === 0) return Infinity; + + let distance = 0; + let cumA = 0; + let cumB = 0; + for (let i = 0; i < n; i++) { + cumA += a[i] / sumA; + cumB += b[i] / sumB; + distance += Math.abs(cumA - cumB); + } + return distance; } /** @@ -322,23 +320,22 @@ function wasserstein(a, b) { * @returns {number} The yule distance between `a` and `b`. */ function yule(a, b) { - if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); - const n = a.length; - let num_true_true = 0; - let num_true_false = 0; - let num_false_true = 0; - for (let i = 0; i < n; ++i) { - const x = a[i] !== 0; - const y = b[i] !== 0; - num_true_true += x && y ? 1 : 0; - num_true_false += x && !y ? 1 : 0; - num_false_true += !x && y ? 1 : 0; - } - const num_false_false = n - num_true_true - num_true_false - num_false_true; - return num_true_false === 0 || num_false_true === 0 - ? 0 - : (2 * num_true_false * num_false_true) / - (num_true_true * num_false_false + num_true_false * num_false_true); + if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); + const n = a.length; + let num_true_true = 0; + let num_true_false = 0; + let num_false_true = 0; + for (let i = 0; i < n; ++i) { + const x = a[i] !== 0; + const y = b[i] !== 0; + num_true_true += x && y ? 1 : 0; + num_true_false += x && !y ? 1 : 0; + num_false_true += !x && y ? 1 : 0; + } + const num_false_false = n - num_true_true - num_true_false - num_false_true; + return num_true_false === 0 || num_false_true === 0 + ? 0 + : (2 * num_true_false * num_false_true) / (num_true_true * num_false_false + num_true_false * num_false_true); } /** @import { Metric } from "../metrics/index.js" */ @@ -348,7 +345,7 @@ function yule(a, b) { * @returns {A is Matrix} */ function isMatrix(A) { - return A instanceof Matrix; + return A instanceof Matrix; } /** @@ -360,22 +357,23 @@ function isMatrix(A) { * @returns {Matrix} The distance matrix of `A`. */ function distance_matrix(A, metric = euclidean) { - /** @type {number} */ - const n = isMatrix(A) ? A.shape[0] : A.length; - const D = new Matrix(n, n); - for (let i = 0; i < n; ++i) { - const A_i = isMatrix(A) ? A.row(i) : A[i]; - for (let j = i + 1; j < n; ++j) { - const dist = metric(A_i, isMatrix(A) ? A.row(j) : A[j]); - D.set_entry(i, j, dist); - D.set_entry(j, i, dist); - } - } - return D; + /** @type {number} */ + const n = isMatrix(A) ? A.shape[0] : A.length; + const D = new Matrix(n, n); + for (let i = 0; i < n; ++i) { + const A_i = isMatrix(A) ? A.row(i) : A[i]; + for (let j = i + 1; j < n; ++j) { + const dist = metric(A_i, isMatrix(A) ? A.row(j) : A[j]); + D.set_entry(i, j, dist); + D.set_entry(j, i, dist); + } + } + return D; } //@ts-check + /** @import { Metric } from "../metrics/index.js" */ /** @@ -388,25 +386,25 @@ function distance_matrix(A, metric = euclidean) { * @returns {{ i: number; j: number; distance: number }[][]} The kNN graph. */ function k_nearest_neighbors(A, k, metric = euclidean) { - A = A instanceof Matrix ? A : Matrix.from(A); - const rows = A.shape[0]; - const D = metric === "precomputed" ? A : distance_matrix(A, metric); - /** @type {{ i: number; j: number; distance: number }[][]} */ - const nN = []; - for (let row = 0; row < rows; ++row) { - const res = Array.from(D.row(row)) - .map((distance, col) => { - return { - i: row, - j: col, - distance: distance, - }; - }) - .sort((a, b) => a.distance - b.distance) - .slice(1, k + 1); - nN.push(res); - } - return nN; + A = A instanceof Matrix ? A : Matrix.from(A); + const rows = A.shape[0]; + const D = metric === "precomputed" ? A : distance_matrix(A, metric); + /** @type {{ i: number; j: number; distance: number }[][]} */ + const nN = []; + for (let row = 0; row < rows; ++row) { + const res = Array.from(D.row(row)) + .map((distance, col) => { + return { + i: row, + j: col, + distance: distance, + }; + }) + .sort((a, b) => a.distance - b.distance) + .slice(1, k + 1); + nN.push(res); + } + return nN; } /** @@ -419,18 +417,18 @@ function k_nearest_neighbors(A, k, metric = euclidean) { * @returns {number[]} An array with `number` entries, beginning at `start` ending at `end`. */ function linspace(start, end, number) { - if (number === undefined || number === null) { - number = Math.max(Math.round(end - start) + 1, 1); - } - if (number < 2) { - return number === 1 ? [start] : []; - } - const result = new Array(number); - number -= 1; - for (let i = number; i >= 0; --i) { - result[i] = (i * end + (number - i) * start) / number; - } - return result; + if (number === undefined || number === null) { + number = Math.max(Math.round(end - start) + 1, 1); + } + if (number < 2) { + return number === 1 ? [start] : []; + } + const result = new Array(number); + number -= 1; + for (let i = number; i >= 0; --i) { + result[i] = (i * end + (number - i) * start) / number; + } + return result; } /** @@ -442,15 +440,15 @@ function linspace(start, end, number) { * @returns The inner product between `a` and `b`. */ function inner_product(a, b) { - const N = a.length; - if (N !== b.length) { - throw new Error("Array a and b must have the same length!"); - } - let sum = 0; - for (let i = 0; i < N; ++i) { - sum += a[i] * b[i]; - } - return sum; + const N = a.length; + if (N !== b.length) { + throw new Error("Array a and b must have the same length!"); + } + let sum = 0; + for (let i = 0; i < N; ++i) { + sum += a[i] * b[i]; + } + return sum; } /** @@ -462,18 +460,18 @@ function inner_product(a, b) { * @see {@link https://en.wikipedia.org/wiki/Kahan_summation_algorithm} */ function kahan_sum(summands) { - const n = summands.length; - let sum = 0; - let compensation = 0; - let y, t; - - for (let i = 0; i < n; ++i) { - y = summands[i] - compensation; - t = sum + y; - compensation = t - sum - y; - sum = t; - } - return sum; + const n = summands.length; + let sum = 0; + let compensation = 0; + let y, t; + + for (let i = 0; i < n; ++i) { + y = summands[i] - compensation; + t = sum + y; + compensation = t - sum - y; + sum = t; + } + return sum; } /** @@ -485,21 +483,21 @@ function kahan_sum(summands) { * @see {@link https://en.wikipedia.org/wiki/Kahan_summation_algorithm#Further_enhancements} */ function neumair_sum(summands) { - const n = summands.length; - let sum = 0; - let compensation = 0; - - for (let i = 0; i < n; ++i) { - const summand = summands[i]; - const t = sum + summand; - if (Math.abs(sum) >= Math.abs(summand)) { - compensation += sum - t + summand; - } else { - compensation += summand - t + sum; + const n = summands.length; + let sum = 0; + let compensation = 0; + + for (let i = 0; i < n; ++i) { + const summand = summands[i]; + const t = sum + summand; + if (Math.abs(sum) >= Math.abs(summand)) { + compensation += sum - t + summand; + } else { + compensation += summand - t + sum; + } + sum = t; } - sum = t; - } - return sum + compensation; + return sum + compensation; } /** @@ -511,27 +509,27 @@ function neumair_sum(summands) { * @see {@link https://en.wikipedia.org/wiki/QR_decomposition#Using_the_Gram%E2%80%93Schmidt_process} */ function qr(A) { - const [rows, cols] = A.shape; - const Q = new Matrix(rows, cols, "identity"); - const R = new Matrix(cols, cols, 0); - - for (let j = 0; j < cols; ++j) { - const v = A.col(j); - for (let i = 0; i < j; ++i) { - const q = Q.col(i); - const q_dot_v = neumair_sum(q.map((q_, k) => q_ * v[k])); - for (let k = 0; k < rows; ++k) { - v[k] -= q_dot_v * q[k]; - } - R.set_entry(i, j, q_dot_v); - } - const v_norm = norm(v, euclidean); - for (let k = 0; k < rows; ++k) { - Q.set_entry(k, j, v[k] / v_norm); - } - R.set_entry(j, j, v_norm); - } - return { R, Q }; + const [rows, cols] = A.shape; + const Q = new Matrix(rows, cols, "identity"); + const R = new Matrix(cols, cols, 0); + + for (let j = 0; j < cols; ++j) { + const v = A.col(j); + for (let i = 0; i < j; ++i) { + const q = Q.col(i); + const q_dot_v = neumair_sum(q.map((q_, k) => q_ * v[k])); + for (let k = 0; k < rows; ++k) { + v[k] -= q_dot_v * q[k]; + } + R.set_entry(i, j, q_dot_v); + } + const v_norm = norm(v, euclidean); + for (let k = 0; k < rows; ++k) { + Q.set_entry(k, j, v[k] / v_norm); + } + R.set_entry(j, j, v_norm); + } + return { R, Q }; } /** @@ -544,28 +542,28 @@ function qr(A) { * @see {@link http://mlwiki.org/index.php/Householder_Transformation} */ function qr_householder(A) { - const [rows, cols] = A.shape; - const Q = new Matrix(rows, rows, "I"); - const R = A.clone(); - - for (let j = 0; j < cols; ++j) { - const x = Matrix.from_vector(R.col(j).slice(j), "row"); - const x_norm = norm(x); - const x0 = x.entry(0, 0); - const rho = -Math.sign(x0); - const u1 = x0 - rho * x_norm; - const u = x.divide(u1).set_entry(0, 0, 1); - const beta = (-rho * u1) / x_norm; - - const u_outer_u = u.outer(u); - const R_block = R.get_block(j, 0); - const new_R = R_block.sub(u_outer_u.dot(R_block).mult(beta)); - const Q_block = Q.get_block(0, j); - const new_Q = Q_block.sub(Q_block.dot(u_outer_u).mult(beta)); - R.set_block(j, 0, new_R); - Q.set_block(0, j, new_Q); - } - return { R, Q }; + const [rows, cols] = A.shape; + const Q = new Matrix(rows, rows, "I"); + const R = A.clone(); + + for (let j = 0; j < cols; ++j) { + const x = Matrix.from_vector(R.col(j).slice(j), "row"); + const x_norm = norm(x); + const x0 = x.entry(0, 0); + const rho = -Math.sign(x0); + const u1 = x0 - rho * x_norm; + const u = x.divide(u1).set_entry(0, 0, 1); + const beta = (-rho * u1) / x_norm; + + const u_outer_u = u.outer(u); + const R_block = R.get_block(j, 0); + const new_R = R_block.sub(u_outer_u.dot(R_block).mult(beta)); + const Q_block = Q.get_block(0, j); + const new_Q = Q_block.sub(Q_block.dot(u_outer_u).mult(beta)); + R.set_block(j, 0, new_R); + Q.set_block(0, j, new_Q); + } + return { R, Q }; } /** @@ -576,13 +574,13 @@ function qr_householder(A) { * @returns {number} */ function max(values) { - let max = -Infinity; - for (const value of values) { - if (value !== null && max < value) { - max = value; + let max = -Infinity; + for (const value of values) { + if (value !== null && max < value) { + max = value; + } } - } - return max; + return max; } /** @@ -593,13 +591,13 @@ function max(values) { * @returns {number} */ function min(values) { - let min = Infinity; - for (const value of values) { - if (value !== null && min > value) { - min = value; + let min = Infinity; + for (const value of values) { + if (value !== null && min > value) { + min = value; + } } - } - return min; + return min; } /** @@ -607,174 +605,173 @@ function min(values) { * @class */ class Randomizer { - _N = 624; - _M = 397; - _MATRIX_A = 0x9908b0df; - _UPPER_MASK = 0x80000000; - _LOWER_MASK = 0x7fffffff; - - /** @type {number[]} */ - _mt; - /** @type {number} */ - _mti; - /** @type {number} */ - _seed; - - /** - * Mersenne Twister random number generator. - * - * @param {number} [_seed=new Date().getTime()] - The seed for the random number generator. If `_seed == null` then - * the actual time gets used as seed. Default is `new Date().getTime()` - * @see https://github.com/bmurray7/mersenne-twister-examples/blob/master/javascript-mersenne-twister.js - */ - constructor(_seed) { - this._mt = new Array(this._N); - this._mti = this._N + 1; - this._seed = _seed ?? Date.now(); - this.seed = this._seed; - } - - /** @type {number} seed */ - set seed(_seed) { - this._seed = _seed; - const mt = this._mt; - - mt[0] = _seed >>> 0; - for (this._mti = 1; this._mti < this._N; this._mti += 1) { - const mti = this._mti; - const s = mt[mti - 1] ^ (mt[mti - 1] >>> 30); - mt[mti] = - ((((s & 0xffff0000) >>> 16) * 1812433253) << 16) + (s & 0x0000ffff) * 1812433253 + mti; - mt[mti] >>>= 0; - } - } - - /** - * Returns the seed of the random number generator. - * - * @returns {number} - The seed. - */ - get seed() { - return this._seed; - } - - /** - * Returns a float between 0 and 1. - * - * @returns {number} - A random number between [0, 1] - */ - get random() { - return this.random_int * (1.0 / 4294967296.0); - } - - /** - * Returns an integer between 0 and MAX_INTEGER. - * - * @returns {number} - A random integer. - */ - get random_int() { - let y, - mag01 = [0x0, this._MATRIX_A]; - if (this._mti >= this._N) { - let kk; - - /* if (this._mti == this._N + 1) { + _N = 624; + _M = 397; + _MATRIX_A = 0x9908b0df; + _UPPER_MASK = 0x80000000; + _LOWER_MASK = 0x7fffffff; + + /** @type {number[]} */ + _mt; + /** @type {number} */ + _mti; + /** @type {number} */ + _seed; + + /** + * Mersenne Twister random number generator. + * + * @param {number} [_seed=new Date().getTime()] - The seed for the random number generator. If `_seed == null` then + * the actual time gets used as seed. Default is `new Date().getTime()` + * @see https://github.com/bmurray7/mersenne-twister-examples/blob/master/javascript-mersenne-twister.js + */ + constructor(_seed) { + this._mt = new Array(this._N); + this._mti = this._N + 1; + this._seed = _seed ?? Date.now(); + this.seed = this._seed; + } + + /** @type {number} seed */ + set seed(_seed) { + this._seed = _seed; + const mt = this._mt; + + mt[0] = _seed >>> 0; + for (this._mti = 1; this._mti < this._N; this._mti += 1) { + const mti = this._mti; + const s = mt[mti - 1] ^ (mt[mti - 1] >>> 30); + mt[mti] = ((((s & 0xffff0000) >>> 16) * 1812433253) << 16) + (s & 0x0000ffff) * 1812433253 + mti; + mt[mti] >>>= 0; + } + } + + /** + * Returns the seed of the random number generator. + * + * @returns {number} - The seed. + */ + get seed() { + return this._seed; + } + + /** + * Returns a float between 0 and 1. + * + * @returns {number} - A random number between [0, 1] + */ + get random() { + return this.random_int * (1.0 / 4294967296.0); + } + + /** + * Returns an integer between 0 and MAX_INTEGER. + * + * @returns {number} - A random integer. + */ + get random_int() { + let y, + mag01 = [0x0, this._MATRIX_A]; + if (this._mti >= this._N) { + let kk; + + /* if (this._mti == this._N + 1) { this.seed = 5489; } */ - const N_M = this._N - this._M; - const M_N = this._M - this._N; - - for (kk = 0; kk < N_M; ++kk) { - y = (this._mt[kk] & this._UPPER_MASK) | (this._mt[kk + 1] & this._LOWER_MASK); - this._mt[kk] = this._mt[kk + this._M] ^ (y >>> 1) ^ mag01[y & 0x1]; - } - for (; kk < this._N - 1; ++kk) { - y = (this._mt[kk] & this._UPPER_MASK) | (this._mt[kk + 1] & this._LOWER_MASK); - this._mt[kk] = this._mt[kk + M_N] ^ (y >>> 1) ^ mag01[y & 0x1]; - } - - y = (this._mt[this._N - 1] & this._UPPER_MASK) | (this._mt[0] & this._LOWER_MASK); - this._mt[this._N - 1] = this._mt[this._M - 1] ^ (y >>> 1) ^ mag01[y & 0x1]; - - this._mti = 0; - } - this._mti += 1; - y = this._mt[this._mti]; - y ^= y >>> 11; - y ^= (y << 7) & 0x9d2c5680; - y ^= (y << 15) & 0xefc60000; - y ^= y >>> 18; - - return y >>> 0; - } - - gauss_random() { - let x, y, r; - if (this._val != null) { - x = this._val; - this._val = null; - return x; - } else - do { - x = 2 * this.random - 1; - y = 2 * this.random - 1; - r = x * x + y * y; - } while (!r || r > 1); - const c = Math.sqrt((-2 * Math.log(r)) / r); - this._val = y * c; // cache this for next function call for efficiency - return x * c; - } - - /** - * @template T Returns samples from an input Matrix or Array. - * @param {T[]} A - The input Matrix or Array. - * @param {number} n - The number of samples. - * @returns {T[]} A random selection form `A` of `n` samples. - */ - choice(A, n) { - if (!Array.isArray(A)) throw new Error("A must be an Array!"); - // if (A instanceof Matrix) { - // let rows = A.shape[0]; - // if (n > rows) { - // throw new Error("n bigger than A!"); - // } - // /** @type {number[]} */ - // let sample = new Array(n); - // let index_list = linspace(0, rows - 1); - // for (let i = 0, l = index_list.length; i < n; ++i, --l) { - // let random_index = this.random_int % l; - // sample[i] = index_list.splice(random_index, 1)[0]; - // } - // return sample.map((d) => A.row(d)); - // } else if (Array.isArray(A) || A instanceof Float64Array) { - const rows = A.length; - if (n > rows) { - throw new Error("n bigger than A!"); - } - const sample = new Array(n); - const index_list = linspace(0, rows - 1); - for (let i = 0, l = index_list.length; i < n; ++i, --l) { - const random_index = this.random_int % l; - sample[i] = index_list.splice(random_index, 1)[0]; - } - return sample.map((d) => A[d]); - //} else { - //throw new Error("A must be of type Matrix or Float64Array or number[]!"); - // } - } - - /** - * @template T Returns samples from an input Matrix or Array. - * @param {T[]} A - The input Matrix or Array. - * @param {number} n - The number of samples. - * @param {number} seed - The seed for the random number generator. - * @returns {T[]} - A random selection form `A` of `n` samples. - */ - static choice(A, n, seed = 1212) { - const R = new Randomizer(seed); - return R.choice(A, n); - } + const N_M = this._N - this._M; + const M_N = this._M - this._N; + + for (kk = 0; kk < N_M; ++kk) { + y = (this._mt[kk] & this._UPPER_MASK) | (this._mt[kk + 1] & this._LOWER_MASK); + this._mt[kk] = this._mt[kk + this._M] ^ (y >>> 1) ^ mag01[y & 0x1]; + } + for (; kk < this._N - 1; ++kk) { + y = (this._mt[kk] & this._UPPER_MASK) | (this._mt[kk + 1] & this._LOWER_MASK); + this._mt[kk] = this._mt[kk + M_N] ^ (y >>> 1) ^ mag01[y & 0x1]; + } + + y = (this._mt[this._N - 1] & this._UPPER_MASK) | (this._mt[0] & this._LOWER_MASK); + this._mt[this._N - 1] = this._mt[this._M - 1] ^ (y >>> 1) ^ mag01[y & 0x1]; + + this._mti = 0; + } + this._mti += 1; + y = this._mt[this._mti]; + y ^= y >>> 11; + y ^= (y << 7) & 0x9d2c5680; + y ^= (y << 15) & 0xefc60000; + y ^= y >>> 18; + + return y >>> 0; + } + + gauss_random() { + let x, y, r; + if (this._val != null) { + x = this._val; + this._val = null; + return x; + } else + do { + x = 2 * this.random - 1; + y = 2 * this.random - 1; + r = x * x + y * y; + } while (!r || r > 1); + const c = Math.sqrt((-2 * Math.log(r)) / r); + this._val = y * c; // cache this for next function call for efficiency + return x * c; + } + + /** + * @template T Returns samples from an input Matrix or Array. + * @param {T[]} A - The input Matrix or Array. + * @param {number} n - The number of samples. + * @returns {T[]} A random selection form `A` of `n` samples. + */ + choice(A, n) { + if (!Array.isArray(A)) throw new Error("A must be an Array!"); + // if (A instanceof Matrix) { + // let rows = A.shape[0]; + // if (n > rows) { + // throw new Error("n bigger than A!"); + // } + // /** @type {number[]} */ + // let sample = new Array(n); + // let index_list = linspace(0, rows - 1); + // for (let i = 0, l = index_list.length; i < n; ++i, --l) { + // let random_index = this.random_int % l; + // sample[i] = index_list.splice(random_index, 1)[0]; + // } + // return sample.map((d) => A.row(d)); + // } else if (Array.isArray(A) || A instanceof Float64Array) { + const rows = A.length; + if (n > rows) { + throw new Error("n bigger than A!"); + } + const sample = new Array(n); + const index_list = linspace(0, rows - 1); + for (let i = 0, l = index_list.length; i < n; ++i, --l) { + const random_index = this.random_int % l; + sample[i] = index_list.splice(random_index, 1)[0]; + } + return sample.map((d) => A[d]); + //} else { + //throw new Error("A must be of type Matrix or Float64Array or number[]!"); + // } + } + + /** + * @template T Returns samples from an input Matrix or Array. + * @param {T[]} A - The input Matrix or Array. + * @param {number} n - The number of samples. + * @param {number} seed - The seed for the random number generator. + * @returns {T[]} - A random selection form `A` of `n` samples. + */ + static choice(A, n, seed = 1212) { + const R = new Randomizer(seed); + return R.choice(A, n); + } } /** @import { EigenArgs } from "./index.js" */ @@ -791,29 +788,29 @@ class Randomizer { * of Matrix `A`. */ function simultaneous_poweriteration( - A, - k = 2, - { seed = 1212, max_iterations = 100, qr: qr$1 = qr, tol = 1e-8 } = {}, + A, + k = 2, + { seed = 1212, max_iterations = 100, qr: qr$1 = qr, tol = 1e-8 } = {}, ) { - const randomizer = seed instanceof Randomizer ? seed : new Randomizer(seed); - if (!(A instanceof Matrix)) A = Matrix.from(A); - const n = A.shape[0]; - let { Q, R } = qr$1(new Matrix(n, k, () => (randomizer.random - 0.5) * 2)); - while (max_iterations--) { - const oldQ = Q; - const Z = A.dot(Q); - const QR = qr$1(Z); - Q = QR.Q; - R = QR.R; - const error = euclidean_squared(Q.values, oldQ.values); - if (error < tol) { - break; - } - } - - const eigenvalues = R.diag(); - const eigenvectors = Q.transpose().to2dArray(); - return { eigenvalues, eigenvectors }; + const randomizer = seed instanceof Randomizer ? seed : new Randomizer(seed); + if (!(A instanceof Matrix)) A = Matrix.from(A); + const n = A.shape[0]; + let { Q, R } = qr$1(new Matrix(n, k, () => (randomizer.random - 0.5) * 2)); + while (max_iterations--) { + const oldQ = Q; + const Z = A.dot(Q); + const QR = qr$1(Z); + Q = QR.Q; + R = QR.R; + const error = euclidean_squared(Q.values, oldQ.values); + if (error < tol) { + break; + } + } + + const eigenvalues = R.diag(); + const eigenvectors = Q.transpose().to2dArray(); + return { eigenvalues, eigenvectors }; } /** @typedef {(i: number, j: number) => number} Accessor */ @@ -823,9333 +820,9918 @@ function simultaneous_poweriteration( * @category Matrix */ class Matrix { - /** - * Creates a new Matrix. Entries are stored in a Float64Array. - * - * @example let A = new Matrix(10, 10, () => Math.random()); //creates a 10 times 10 random matrix. let B = new - * Matrix(3, 3, "I"); // creates a 3 times 3 identity matrix. - * - * @param {number} rows - The amount of rows of the matrix. - * @param {number} cols - The amount of columns of the matrix. - * @param {Accessor | string | number} value - Can be a function with row and col as parameters, a number, or - * "zeros", "identity" or "I", or "center". - * - * - **function**: for each entry the function gets called with the parameters for the actual row and column. - * - **string**: allowed are - * - * - "zero", creates a zero matrix. - * - "identity" or "I", creates an identity matrix. - * - "center", creates an center matrix. - * - **number**: create a matrix filled with the given value. - */ - constructor(rows, cols, value = 0) { - /** @type {number} */ this._rows = rows; - /** @type {number} */ this._cols = cols; - /** @type {Float64Array} */ this._data; - - if (rows && cols) { - if (!value) { - this._data = new Float64Array(rows * cols); - } - if (typeof value === "function") { - this._data = new Float64Array(rows * cols); - for (let row = 0; row < rows; ++row) { - for (let col = 0; col < cols; ++col) { - this._data[row * cols + col] = value(row, col); - } - } - } - if (typeof value === "string") { - if (value === "zeros") { - this._data = new Float64Array(rows * cols); - for (let row = 0; row < rows; ++row) { - for (let col = 0; col < cols; ++col) { - this._data[row * cols + col] = 0; + /** + * Creates a new Matrix. Entries are stored in a Float64Array. + * + * @example let A = new Matrix(10, 10, () => Math.random()); //creates a 10 times 10 random matrix. let B = new + * Matrix(3, 3, "I"); // creates a 3 times 3 identity matrix. + * + * @param {number} rows - The amount of rows of the matrix. + * @param {number} cols - The amount of columns of the matrix. + * @param {Accessor | string | number} value - Can be a function with row and col as parameters, a number, or + * "zeros", "identity" or "I", or "center". + * + * - **function**: for each entry the function gets called with the parameters for the actual row and column. + * - **string**: allowed are + * + * - "zero", creates a zero matrix. + * - "identity" or "I", creates an identity matrix. + * - "center", creates an center matrix. + * - **number**: create a matrix filled with the given value. + */ + constructor(rows, cols, value = 0) { + /** @type {number} */ this._rows = rows; + /** @type {number} */ this._cols = cols; + /** @type {Float64Array} */ this._data; + + if (rows && cols) { + if (!value) { + this._data = new Float64Array(rows * cols); } - } - } - if (value === "identity" || value === "I") { - this._data = new Float64Array(rows * cols); - for (let row = 0; row < rows; ++row) { - this._data[row * cols + row] = 1; - } - } - if (value === "center" && rows === cols) { - this._data = new Float64Array(rows * cols); - value = (i, j) => (i === j ? 1 : 0) - 1 / rows; - for (let row = 0; row < rows; ++row) { - for (let col = 0; col < cols; ++col) { - this._data[row * cols + col] = value(row, col); + if (typeof value === "function") { + this._data = new Float64Array(rows * cols); + for (let row = 0; row < rows; ++row) { + for (let col = 0; col < cols; ++col) { + this._data[row * cols + col] = value(row, col); + } + } + } + if (typeof value === "string") { + if (value === "zeros") { + this._data = new Float64Array(rows * cols); + for (let row = 0; row < rows; ++row) { + for (let col = 0; col < cols; ++col) { + this._data[row * cols + col] = 0; + } + } + } + if (value === "identity" || value === "I") { + this._data = new Float64Array(rows * cols); + for (let row = 0; row < rows; ++row) { + this._data[row * cols + row] = 1; + } + } + if (value === "center" && rows === cols) { + this._data = new Float64Array(rows * cols); + value = (i, j) => (i === j ? 1 : 0) - 1 / rows; + for (let row = 0; row < rows; ++row) { + for (let col = 0; col < cols; ++col) { + this._data[row * cols + col] = value(row, col); + } + } + } + } + if (typeof value === "number") { + this._data = new Float64Array(rows * cols); + for (let row = 0; row < rows; ++row) { + for (let col = 0; col < cols; ++col) { + this._data[row * cols + col] = value; + } + } + } + if (Array.isArray(value)) { + this._data = new Float64Array(rows * cols); + for (let row = 0; row < rows; ++row) { + for (let col = 0; col < cols; ++col) { + this._data[row * cols + col] = value[row][col]; + } + } } - } - } - } - if (typeof value === "number") { - this._data = new Float64Array(rows * cols); - for (let row = 0; row < rows; ++row) { - for (let col = 0; col < cols; ++col) { - this._data[row * cols + col] = value; - } } - } - if (Array.isArray(value)) { - this._data = new Float64Array(rows * cols); - for (let row = 0; row < rows; ++row) { - for (let col = 0; col < cols; ++col) { - this._data[row * cols + col] = value[row][col]; - } - } - } - } - } - - /** - * Creates a Matrix out of `A`. - * @param {Matrix | Float64Array[] | number[][]} A - The matrix, array, or number, which should converted to a Matrix. - * @returns {Matrix} - * @example - * let A = Matrix.from([ [1, 0], [0, 1], ]); //creates a two by two identity matrix. - */ - static from(A) { - if (A instanceof Matrix) { - return A.clone(); - } - if (Matrix.is2dArray(A)) { - const m = A.length; - const n = A[0].length; - for (let row = 0; row < m; ++row) { - if (A[row].length !== n) { - throw new Error("various array lengths"); - } - } - return new Matrix(m, n, (i, j) => A[i][j]); - } - throw new Error("error"); - } - - /** - * Creates a Matrix with the diagonal being the values of `v`. - * - * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]] - * - * @param {number[] | Float64Array} v - * @returns {Matrix} - */ - static from_diag(v) { - const N = v.length; - return new Matrix(N, N, (i, j) => (i === j ? v[i] : 0)); - } - - /** - * Creates a Matrix with the diagonal being the values of `v`. - * - * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]] - * - * @param {number[] | Float64Array} v - * @param {"col" | "row"} type - * @returns {Matrix} - */ - static from_vector(v, type) { - const N = v.length; - if (type === "col") { - return new Matrix(N, 1, (i, _) => v[i]); - } else { - return new Matrix(1, N, (_, j) => v[j]); - } - } - - /** - * Returns the `row`th row from the Matrix. - * - * @param {number} row - * @returns {Float64Array} - */ - row(row) { - const data = this.values; - const cols = this._cols; - return data.subarray(row * cols, (row + 1) * cols); - } - - /** - * Returns an generator yielding each row of the Matrix. - * - * @yields {Float64Array} - */ - *iterate_rows() { - const cols = this._cols; - const rows = this._rows; - const data = this.values; - for (let row = 0; row < rows; ++row) { - yield data.subarray(row * cols, (row + 1) * cols); - } - } - - /** - * Makes a `Matrix` object an iterable object. - * - * @yields {Float64Array} - */ - *[Symbol.iterator]() { - for (const row of this.iterate_rows()) { - yield row; - } - } - - /** - * Sets the entries of `row`th row from the Matrix to the entries from `values`. - * - * @param {number} row - * @param {number[]} values - * @returns {Matrix} - */ - set_row(row, values) { - const cols = this._cols; - if (Matrix.isArray(values) && values.length === cols) { - const offset = row * cols; - for (let col = 0; col < cols; ++col) { - this.values[offset + col] = values[col]; - } - } else if (values instanceof Matrix && values.shape[1] === cols && values.shape[0] === 1) { - const offset = row * cols; - for (let col = 0; col < cols; ++col) { - this.values[offset + col] = values._data[col]; - } - } else { - throw new Error( - "Values not valid! Needs to be either an Array, a Float64Array, or a fitting Matrix!", - ); - } - return this; - } - - /** - * Swaps the rows `row1` and `row2` of the Matrix. - * - * @param {number} row1 - * @param {number} row2 - * @returns {Matrix} - */ - swap_rows(row1, row2) { - const cols = this._cols; - const data = this.values; - for (let i = row1 * cols, j = row2 * cols, col = 0; col < cols; ++col, ++i, ++j) { - const t = data[i]; - data[i] = data[j]; - data[j] = t; - } - return this; - } - - /** - * Returns the colth column from the Matrix. - * - * @param {number} col - * @returns {Float64Array} - */ - col(col) { - const result_col = new Float64Array(this._rows); - for (let row = 0; row < this._rows; ++row) { - result_col[row] = this.values[row * this._cols + col]; - } - return result_col; - } - - /** - * Returns the `col`th entry from the `row`th row of the Matrix. - * - * @param {number} row - * @param {number} col - * @returns {number} - */ - entry(row, col) { - return this.values[row * this._cols + col]; - } - - /** - * Sets the {@link col}th entry from the {@link row}th row of the Matrix to the given - * {@link value}. - * - * @param {number} row - * @param {number} col - * @param {number} value - * @returns {Matrix} - */ - set_entry(row, col, value) { - this.values[row * this._cols + col] = value; - return this; - } - - /** - * Adds a given {@link value} to the {@link col}th entry from the {@link row}th row of the - * Matrix. - * - * @param {number} row - * @param {number} col - * @param {number} value - * @returns {Matrix} - */ - add_entry(row, col, value) { - this.values[row * this._cols + col] += value; - return this; - } - - /** - * Subtracts a given {@link value} from the {@link col}th entry from the {@link row}th row of the - * Matrix. - * - * @param {number} row - * @param {number} col - * @param {number} value - * @returns {Matrix} - */ - sub_entry(row, col, value) { - this.values[row * this._cols + col] -= value; - return this; - } - - /** - * Returns a new transposed Matrix. - * - * @returns {Matrix} - */ - transpose() { - const B = new Matrix(this._cols, this._rows, (row, col) => this.entry(col, row)); - return B; - } - - /** - * Returns a new transposed Matrix. Short-form of `transpose`. - * - * @returns {Matrix} - */ - get T() { - return this.transpose(); - } - - /** - * Returns the inverse of the Matrix. - * - * @returns {Matrix} - */ - inverse() { - const rows = this._rows; - const cols = this._cols; - const A = this.clone(); - const B = new Matrix(rows, cols, "I"); - - // foreach column - for (let col = 0; col < cols; ++col) { - // Search for maximum in this column (pivot) - let max_idx = col; - let max_val = Math.abs(A.entry(col, col)); - for (let row = col + 1; row < rows; ++row) { - const val = Math.abs(A.entry(row, col)); - if (max_val < val) { - max_idx = row; - max_val = val; - } - } - if (max_val === 0) { - throw new Error("Cannot compute inverse of Matrix, determinant is zero"); - } - // Swap maximum row with current row - if (max_idx !== col) { - A.swap_rows(col, max_idx); - B.swap_rows(col, max_idx); - } - - // eliminate non-zero values on the other rows at column c - const A_col = A.row(col); - const B_col = B.row(col); - for (let row = 0; row < rows; ++row) { - if (row !== col) { - // eliminate value at column c and row r - const A_row = A.row(row); - const B_row = B.row(row); - if (A_row[col] !== 0) { - const f = A_row[col] / A_col[col]; - // sub (f * row c) from row r to eliminate the value at column c - for (let s = col; s < cols; ++s) { - A_row[s] -= f * A_col[s]; - } - for (let s = 0; s < cols; ++s) { - B_row[s] -= f * B_col[s]; - } - } - } else { - // normalize value at Acc to 1 (diagonal): - // divide each value of row r=c by the value at Acc - const f = A_col[col]; - for (let s = col; s < cols; ++s) { - A_col[s] /= f; - } - for (let s = 0; s < cols; ++s) { - B_col[s] /= f; - } - } - } - } - return B; - } - - /** - * Returns the dot product. If `B` is an Array or Float64Array then an Array gets returned. If `B` is a Matrix then - * a Matrix gets returned. - * - * @param {Matrix | number[] | Float64Array} B The right side - * @returns {Matrix} - */ - dot(B) { - if (B instanceof Matrix) { - const [rows_A, cols_A] = this.shape; - const [rows_B, cols_B] = B.shape; - if (cols_A !== rows_B) { - throw new Error(`A.dot(B): A is a ${this.shape.join(" ⨯ ")}-Matrix, B is a ${B.shape.join(" ⨯ ")}-Matrix: - A has ${cols_A} cols and B ${rows_B} rows. - Must be equal!`); - } - const C = new Matrix(rows_A, cols_B, 0); - const A_val = this.values; - const B_val = B.values; - const C_val = C.values; - - for (let i = 0; i < rows_A; ++i) { - const i_cols_A = i * cols_A; - const i_cols_B = i * cols_B; - for (let k = 0; k < cols_A; ++k) { - const aik = A_val[i_cols_A + k]; - if (aik === 0) continue; - const k_cols_B = k * cols_B; - for (let j = 0; j < cols_B; ++j) { - C_val[i_cols_B + j] += aik * B_val[k_cols_B + j]; - } - } - } - return C; - } else if (Matrix.isArray(B)) { - // TODO: create Matrix directly - const rows = this._rows; - if (B.length !== rows) { - throw new Error(`A.dot(B): A has ${rows} cols and B has ${B.length} rows. Must be equal!`); - } - const C = new Array(rows); - for (let row = 0; row < rows; ++row) { - C[row] = neumair_sum(this.row(row).map((e) => e * B[row])); - } - return Matrix.from(C); - } else { - throw new Error(`B must be Matrix or Array`); - } - } - - /** - * Transposes the current matrix and returns the dot product with `B`. If `B` is an Array or Float64Array then an - * Array gets returned. If `B` is a Matrix then a Matrix gets returned. - * - * @param {Matrix | number[] | Float64Array} B The right side - * @returns {Matrix} - */ - transDot(B) { - if (B instanceof Matrix) { - const [cols_A, rows_A] = this.shape; // transpose matrix - const [rows_B, cols_B] = B.shape; - if (cols_A !== rows_B) { - throw new Error(`A.dot(B): A is a ${[rows_A, cols_A].join(" ⨯ ")}-Matrix, B is a ${B.shape.join(" ⨯ ")}-Matrix: - A has ${cols_A} cols and B ${rows_B} rows, which must be equal!`); - } - // let B = new Matrix(this._cols, this._rows, (row, col) => this.entry(col, row)); - // this.values[row * this._cols + col]; - const C = new Matrix(rows_A, cols_B, 0); - const A_val = this.values; // A is rows_B x rows_A (transposed) - const B_val = B.values; - const C_val = C.values; - - for (let k = 0; k < cols_A; ++k) { - // cols_A is rows_B - const k_rows_A = k * rows_A; - const k_cols_B = k * cols_B; - for (let i = 0; i < rows_A; ++i) { - const aki = A_val[k_rows_A + i]; - if (aki === 0) continue; - for (let j = 0; j < cols_B; ++j) { - C_val[i * cols_B + j] += aki * B_val[k_cols_B + j]; - } - } - } - return C; - } else if (Matrix.isArray(B)) { - // TODO: create Matrix directly - const rows = this._cols; - if (B.length !== rows) { - throw new Error(`A.dot(B): A has ${rows} cols and B has ${B.length} rows. Must be equal!`); - } - const C = new Array(rows); - for (let row = 0; row < rows; ++row) { - C[row] = neumair_sum(this.col(row).map((e) => e * B[row])); - } - return Matrix.from(C); - } else { - throw new Error(`B must be Matrix or Array`); - } - } - - /** - * Returns the dot product with the transposed version of `B`. If `B` is an Array or Float64Array then an Array gets - * returned. If `B` is a Matrix then a Matrix gets returned. - * - * @param {Matrix | number[] | Float64Array} B The right side - * @returns {Matrix} - */ - dotTrans(B) { - if (B instanceof Matrix) { - const [rows_A, cols_A] = this.shape; - const [cols_B, rows_B] = B.shape; - if (cols_A !== rows_B) { - throw new Error(`A.dot(B): A is a ${this.shape.join(" ⨯ ")}-Matrix, B is a ${[rows_B, cols_B].join(" ⨯ ")}-Matrix: - A has ${cols_A} cols and B ${rows_B} rows, which must be equal!`); - } - const C = new Matrix(rows_A, cols_B, (row, col) => { - const A_i = this.row(row); - const B_i = B.row(col); - let sum = 0; - for (let i = 0; i < cols_A; ++i) { - sum += A_i[i] * B_i[i]; - } - return sum; - }); - return C; - } else if (Matrix.isArray(B)) { - // TODO: create Matrix directly - const rows = this._rows; - if (B.length !== rows) { - throw new Error(`A.dot(B): A has ${rows} cols and B has ${B.length} rows. Must be equal!`); - } - const C = new Array(rows); - for (let row = 0; row < rows; ++row) { - C[row] = neumair_sum(this.row(row).map((e) => e * B[row])); - } - return Matrix.from(C); - } else { - throw new Error(`B must be Matrix or Array`); - } - } - - /** - * Computes the outer product from `this` and `B`. - * - * @param {Matrix} B - * @returns {Matrix} - */ - outer(B) { - const l = this._data.length; - const r = B._data.length; - if (l !== r) throw new Error("Matrix A and B needs to be of the same length!"); - const C = new Matrix( - l, - l, - /** @type {Accessor} */ (i, j) => { - if (i <= j) { - return this._data[i] * B._data[j]; - } else { - return this.entry(j, i); - } - }, - ); - - return C; - } - - /** - * Appends matrix `B` to the matrix. - * - * @example let A = Matrix.from([ [1, 1], [1, 1], ]); // 2 by 2 matrix filled with ones. let B = Matrix.from([ [2, - * 2], [2, 2], ]); // 2 by 2 matrix filled with twos. - * - * A.concat(B, "horizontal"); // 2 by 4 matrix. [[1, 1, 2, 2], [1, 1, 2, 2]] - * A.concat(B, "vertical"); // 4 by 2 matrix. [[1, 1], [1, 1], [2, 2], [2, 2]] - * A.concat(B, "diag"); // 4 by 4 matrix. [[1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 2, 2], [0, 0, 2, 2]] - * - * @param {Matrix} B - Matrix to append. - * @param {"horizontal" | "vertical" | "diag"} [type="horizontal"] - Type of concatenation. Default is - * `"horizontal"` - * @returns {Matrix} - */ - concat(B, type = "horizontal") { - const [rows_A, cols_A] = this.shape; - const [rows_B, cols_B] = B.shape; - if (type === "horizontal") { - if (rows_A !== rows_B) { - throw new Error( - `A.concat(B, "horizontal"): A and B need same number of rows, A has ${rows_A} rows, B has ${rows_B} rows.`, - ); - } - const X = new Matrix(rows_A, cols_A + cols_B, "zeros"); - X.set_block(0, 0, this); - X.set_block(0, cols_A, B); - return X; - } else if (type === "vertical") { - if (cols_A !== cols_B) { - throw new Error( - `A.concat(B, "vertical"): A and B need same number of columns, A has ${cols_A} columns, B has ${cols_B} columns.`, - ); - } - const X = new Matrix(rows_A + rows_B, cols_A, "zeros"); - X.set_block(0, 0, this); - X.set_block(rows_A, 0, B); - return X; - } else if (type === "diag") { - const X = new Matrix(rows_A + rows_B, cols_A + cols_B, "zeros"); - X.set_block(0, 0, this); - X.set_block(rows_A, cols_A, B); - return X; - } else { - throw new Error(`type must be "horizontal" or "vertical", but type is ${type}!`); - } - } - - /** - * Writes the entries of B in A at an offset position given by `offset_row` and `offset_col`. - * - * @param {number} offset_row - * @param {number} offset_col - * @param {Matrix} B - * @returns {Matrix} - */ - set_block(offset_row, offset_col, B) { - const rows = Math.min(this._rows - offset_row, B.shape[0]); - const cols = Math.min(this._cols - offset_col, B.shape[1]); - for (let row = 0; row < rows; ++row) { - for (let col = 0; col < cols; ++col) { - this.set_entry(row + offset_row, col + offset_col, B.entry(row, col)); - } - } - return this; - } - - /** - * Extracts the entries from the `start_row`th row to the `end_row`th row, the - * `start_col`th column to the `end_col`th column of the matrix. If `end_row` or `end_col` is - * empty, the respective value is set to `this.rows` or `this.cols`. - * - * @example let A = Matrix.from([ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]); // a 3 by 3 matrix. - * - * A.get_block(1, 1); // [[5, 6], [8, 9]] - * A.get_block(0, 0, 1, 1); // [[1]] - * A.get_block(1, 1, 2, 2); // [[5]] - * A.get_block(0, 0, 2, 2); // [[1, 2], [4, 5]] - * - * @param {number} start_row - * @param {number} start_col - * @param {number | null} [end_row] - * @param {number | null} [end_col] - * @returns {Matrix} Returns a `end_row` - `start_row` times `end_col` - `start_col` matrix, with respective entries - * from the matrix. - */ - get_block(start_row, start_col, end_row, end_col) { - const [rows, cols] = this.shape; - end_row = end_row ?? rows; - end_col = end_col ?? cols; - if (end_row <= start_row || end_col <= start_col) { - throw new Error(` - end_row must be greater than start_row, and - end_col must be greater than start_col, but - end_row = ${end_row}, start_row = ${start_row}, end_col = ${end_col}, and start_col = ${start_col}!`); } - const X = new Matrix(end_row - start_row, end_col - start_col, "zeros"); - for (let row = start_row, new_row = 0; row < end_row; ++row, ++new_row) { - for (let col = start_col, new_col = 0; col < end_col; ++col, ++new_col) { - X.set_entry(new_row, new_col, this.entry(row, col)); - } - } - return X; - } - - /** - * Returns a new array gathering entries defined by the indices given by argument. - * - * @param {number[]} row_indices - Array consists of indices of rows for gathering entries of this matrix - * @param {number[]} col_indices - Array consists of indices of cols for gathering entries of this matrix - * @returns {Matrix} - */ - gather(row_indices, col_indices) { - const N = row_indices.length; - const D = col_indices.length; - - const R = new Matrix(N, D); - for (let i = 0; i < N; ++i) { - const row_index = row_indices[i]; - for (let j = 0; j < D; ++j) { - const col_index = col_indices[j]; - R.set_entry(i, j, this.entry(row_index, col_index)); - } - } - - return R; - } - - /** - * Applies a function to each entry of the matrix. - * - * @private - * @param {(d: number, v: number) => number} f Function takes 2 parameters, the value of the actual entry and a - * value given by the function `v`. The result of `f` gets writen to the Matrix. - * @param {Accessor} v Function takes 2 parameters for `row` and `col`, and returns a value witch should be applied - * to the `col`th entry of the `row`th row of the matrix. - * @returns {Matrix} - */ - _apply_array(f, v) { - const data = this.values; - const [rows, cols] = this.shape; - for (let i = 0, row = 0; row < rows; ++row) { - for (let col = 0; col < cols; ++col, ++i) { - data[i] = f(data[i], v(row, col)); - } - } - return this; - } - - /** - * @param {number[] | Float64Array} values - * @param {(d: number, v: number) => number} f - * @returns {Matrix} - */ - _apply_rowwise_array(values, f) { - return this._apply_array(f, (_, j) => values[j]); - } - /** - * @param {number[] | Float64Array} values - * @param {(d: number, v: number) => number} f - * @returns {Matrix} - */ - _apply_colwise_array(values, f) { - const data = this.values; - const [rows, cols] = this.shape; - for (let i = 0, row = 0; row < rows; ++row) { - const val = values[row]; - for (let col = 0; col < cols; ++col, ++i) { - data[i] = f(data[i], val); - } - } - return this; - } - - /** - * @param {Matrix | number[] | Float64Array | number} value - * @param {(d: number, v: number) => number} f - * @returns {Matrix} - */ - _apply(value, f) { - const data = this.values; - const [rows, cols] = this.shape; - if (value instanceof Matrix) { - const values = value.values; - const [value_rows, value_cols] = value.shape; - if (value_rows === 1) { - if (cols !== value_cols) { - throw new Error(`cols !== value_cols`); - } - for (let i = 0, row = 0; row < rows; ++row) { - for (let col = 0; col < cols; ++col, ++i) { - data[i] = f(data[i], values[col]); - } - } - } else if (value_cols === 1) { - if (rows !== value_rows) { - throw new Error(`rows !== value_rows`); + + /** + * Creates a Matrix out of `A`. + * @param {Matrix | Float64Array[] | number[][]} A - The matrix, array, or number, which should converted to a Matrix. + * @returns {Matrix} + * @example + * let A = Matrix.from([ [1, 0], [0, 1], ]); //creates a two by two identity matrix. + */ + static from(A) { + if (A instanceof Matrix) { + return A.clone(); } - for (let i = 0, row = 0; row < rows; ++row) { - const v = values[row]; - for (let col = 0; col < cols; ++col, ++i) { - data[i] = f(data[i], v); - } - } - } else if (rows === value_rows && cols === value_cols) { - for (let i = 0, n = rows * cols; i < n; ++i) { - data[i] = f(data[i], values[i]); - } - } else { - throw new Error(`error`); - } - } else if (Matrix.isArray(value)) { - if (value.length === rows) { - for (let i = 0, row = 0; row < rows; ++row) { - const v = value[row]; - for (let col = 0; col < cols; ++col, ++i) { - data[i] = f(data[i], v); - } + if (Matrix.is2dArray(A)) { + const m = A.length; + const n = A[0].length; + for (let row = 0; row < m; ++row) { + if (A[row].length !== n) { + throw new Error("various array lengths"); + } + } + return new Matrix(m, n, (i, j) => A[i][j]); } - } else if (value.length === cols) { - for (let i = 0, row = 0; row < rows; ++row) { - for (let col = 0; col < cols; ++col, ++i) { - data[i] = f(data[i], value[col]); - } + throw new Error("error"); + } + + /** + * Creates a Matrix with the diagonal being the values of `v`. + * + * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]] + * + * @param {number[] | Float64Array} v + * @returns {Matrix} + */ + static from_diag(v) { + const N = v.length; + return new Matrix(N, N, (i, j) => (i === j ? v[i] : 0)); + } + + /** + * Creates a Matrix with the diagonal being the values of `v`. + * + * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]] + * + * @param {number[] | Float64Array} v + * @param {"col" | "row"} type + * @returns {Matrix} + */ + static from_vector(v, type) { + const N = v.length; + if (type === "col") { + return new Matrix(N, 1, (i, _) => v[i]); + } else { + return new Matrix(1, N, (_, j) => v[j]); } - } else { - throw new Error(`error`); - } - } else { - // scalar value - for (let i = 0, n = rows * cols; i < n; ++i) { - data[i] = f(data[i], value); - } - } - return this; - } - - /** - * Clones the Matrix. - * - * @returns {Matrix} - */ - clone() { - const B = new Matrix(this._rows, this._cols); - //B._rows = this._rows; - //B._cols = this._cols; - if (this._data) { - B._data = this._data.slice(0); - } - return B; - } - - /** - * Entrywise multiplication with `value`. - * - * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; - * - * A.mult(2); // [[2, 4], [6, 8]]; - * A.mult(B); // [[1, 4], [9, 16]]; - * - * @param {Matrix | Float64Array | number[] | number} value - * @param {Object} [options] - * @param {boolean} [options.inline=false] - If true, applies multiplication to the element, otherwise it creates - * first a copy and applies the multiplication on the copy. Default is `false` - * @returns {Matrix} - */ - mult(value, { inline = false } = {}) { - const A = inline ? this : this.clone(); - return A._apply(value, (a, b) => a * b); - } - - /** - * Entrywise division with `value`. - * - * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; - * - * A.divide(2); // [[0.5, 1], [1.5, 2]]; - * A.divide(B); // [[1, 1], [1, 1]]; - * - * @param {Matrix | Float64Array | number[] | number} value - * @param {Object} [options] - * @param {Boolean} [options.inline=false] - If true, applies division to the element, otherwise it creates first a - * copy and applies the division on the copy. Default is `false` - * @returns {Matrix} - */ - divide(value, { inline = false } = {}) { - const A = inline ? this : this.clone(); - return A._apply(value, (a, b) => a / b); - } - - /** - * Entrywise addition with `value`. - * - * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; - * - * A.add(2); // [[3, 4], [5, 6]]; - * A.add(B); // [[2, 4], [6, 8]]; - * - * @param {Matrix | Float64Array | number[] | number} value - * @param {Object} [options] - * @param {boolean} [options.inline=false] - If true, applies addition to the element, otherwise it creates first a - * copy and applies the addition on the copy. Default is `false` - * @returns {Matrix} - */ - add(value, { inline = false } = {}) { - const A = inline ? this : this.clone(); - return A._apply(value, (a, b) => a + b); - } - - /** - * Entrywise subtraction with `value`. - * - * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; - * - * A.sub(2); // [[-1, 0], [1, 2]]; - * A.sub(B); // [[0, 0], [0, 0]]; - * - * @param {Matrix | Float64Array | number[] | number} value - * @param {Object} [options] - * @param {boolean} [options.inline=false] - If true, applies subtraction to the element, otherwise it creates first - * a copy and applies the subtraction on the copy. Default is `false` - * @returns {Matrix} - */ - sub(value, { inline = false } = {}) { - const A = inline ? this : this.clone(); - return A._apply(value, (a, b) => a - b); - } - - /** - * Returns the number of rows and columns of the Matrix. - * - * @returns {number[]} An Array in the form [rows, columns]. - */ - get shape() { - return [this._rows, this._cols]; - } - - /** - * Returns the matrix in the given shape with the given function which returns values for the entries of the matrix. - * - * @param {[number, number, Accessor]} parameter - Takes an Array in the form [rows, cols, value], where rows and - * cols are the number of rows and columns of the matrix, and value is a function which takes two parameters (row - * and col) which has to return a value for the colth entry of the rowth row. - * @returns {Matrix} - */ - set shape([rows, cols, value = () => 0]) { - this._rows = rows; - this._cols = cols; - this._data = new Float64Array(rows * cols); - for (let i = 0, row = 0; row < rows; ++row) { - for (let col = 0; col < cols; ++col, ++i) { - this._data[i] = value(row, col); - } - } - } - - /** - * Returns the Matrix as a Array of Float64Arrays. - * - * @returns {Float64Array[]} - */ - to2dArray() { - const result = []; - for (const row of this.iterate_rows()) { - result.push(row); } - return result; - } - - /** - * Returns the Matrix as a Array of Arrays. - * - * @returns {number[][]} - */ - asArray() { - const result = []; - for (const row of this.iterate_rows()) { - result.push(Array.from(row)); + + /** + * Returns the `row`th row from the Matrix. + * + * @param {number} row + * @returns {Float64Array} + */ + row(row) { + const data = this.values; + const cols = this._cols; + return data.subarray(row * cols, (row + 1) * cols); } - return result; - } - - /** - * Returns the diagonal of the Matrix. - * - * @returns {Float64Array} - */ - diag() { - const rows = this._rows; - const cols = this._cols; - const min_row_col = Math.min(rows, cols); - const result = new Float64Array(min_row_col); - for (let i = 0; i < min_row_col; ++i) { - result[i] = this.entry(i, i); + + /** + * Returns an generator yielding each row of the Matrix. + * + * @yields {Float64Array} + */ + *iterate_rows() { + const cols = this._cols; + const rows = this._rows; + const data = this.values; + for (let row = 0; row < rows; ++row) { + yield data.subarray(row * cols, (row + 1) * cols); + } } - return result; - } - - /** - * Returns the mean of all entries of the Matrix. - * - * @returns {number} - */ - mean() { - const sum = this.sum(); - const n = this._rows * this._cols; - return sum / n; - } - - /** - * Returns the sum oof all entries of the Matrix. - * - * @returns {number} - */ - sum() { - const data = this.values; - return neumair_sum(data); - } - - /** - * Returns the entries of the Matrix. - * - * @returns {Float64Array} - */ - get values() { - const data = this._data; - return data; - } - - /** - * Returns the mean of each row of the matrix. - * - * @returns {Float64Array} - */ - meanRows() { - const data = this.values; - const rows = this._rows; - const cols = this._cols; - const result = Float64Array.from({ length: rows }); - for (let i = 0, row = 0; row < rows; ++row) { - let sum = 0; - for (let col = 0; col < cols; ++col, ++i) { - sum += data[i]; - } - result[row] = sum / cols; + + /** + * Makes a `Matrix` object an iterable object. + * + * @yields {Float64Array} + */ + *[Symbol.iterator]() { + for (const row of this.iterate_rows()) { + yield row; + } } - return result; - } - - /** - * Returns the mean of each column of the matrix. - * - * @returns {Float64Array} - */ - meanCols() { - const data = this.values; - const rows = this._rows; - const cols = this._cols; - const result = Float64Array.from({ length: cols }); - for (let col = 0; col < cols; ++col) { - let sum = 0; - for (let i = col, row = 0; row < rows; ++row, i += cols) { - sum += data[i]; - } - result[col] = sum / rows; + + /** + * Sets the entries of `row`th row from the Matrix to the entries from `values`. + * + * @param {number} row + * @param {number[]} values + * @returns {Matrix} + */ + set_row(row, values) { + const cols = this._cols; + if (Matrix.isArray(values) && values.length === cols) { + const offset = row * cols; + for (let col = 0; col < cols; ++col) { + this.values[offset + col] = values[col]; + } + } else if (values instanceof Matrix && values.shape[1] === cols && values.shape[0] === 1) { + const offset = row * cols; + for (let col = 0; col < cols; ++col) { + this.values[offset + col] = values._data[col]; + } + } else { + throw new Error("Values not valid! Needs to be either an Array, a Float64Array, or a fitting Matrix!"); + } + return this; } - return result; - } - - /** - * Solves the equation `Ax = b` using the conjugate gradient method. Returns the result `x`. - * - * @param {Matrix} A - Matrix - * @param {Matrix} b - Matrix - * @param {Randomizer | null} [randomizer] - * @param {number} [tol=1e-3] Default is `1e-3` - * @returns {Matrix} - */ - static solve_CG(A, b, randomizer, tol = 1e-3) { - if (!randomizer) { - randomizer = new Randomizer(); + + /** + * Swaps the rows `row1` and `row2` of the Matrix. + * + * @param {number} row1 + * @param {number} row2 + * @returns {Matrix} + */ + swap_rows(row1, row2) { + const cols = this._cols; + const data = this.values; + for (let i = row1 * cols, j = row2 * cols, col = 0; col < cols; ++col, ++i, ++j) { + const t = data[i]; + data[i] = data[j]; + data[j] = t; + } + return this; } - const rows = A.shape[0]; - const cols = b.shape[1]; - let result = new Matrix(rows, 0); - for (let i = 0; i < cols; ++i) { - const b_i = Matrix.from_vector(b.col(i), "col"); - let x = new Matrix(rows, 1, () => randomizer.random); - let r = b_i.sub(A.dot(x)); - let d = r.clone(); - let iter = 0; - const max_iter = rows * 10; // Prevent infinite loops - do { - const z = A.dot(d); - const alpha = r.transDot(r).entry(0, 0) / d.transDot(z).entry(0, 0); - x = x.add(d.mult(alpha)); - const r_next = r.sub(z.mult(alpha)); - const beta = r_next.transDot(r_next).entry(0, 0) / r.transDot(r).entry(0, 0); - d = r_next.add(d.mult(beta)); - r = r_next; - iter++; - } while (Math.abs(r.mean()) > tol && iter < max_iter); - result = result.concat(x, "horizontal"); + + /** + * Returns the colth column from the Matrix. + * + * @param {number} col + * @returns {Float64Array} + */ + col(col) { + const result_col = new Float64Array(this._rows); + for (let row = 0; row < this._rows; ++row) { + result_col[row] = this.values[row * this._cols + col]; + } + return result_col; } - return result; - } - - /** - * Solves the equation `Ax = b`. Returns the result `x`. - * - * @param {Matrix | { L: Matrix; U: Matrix }} A - Matrix or LU Decomposition - * @param {Matrix} b - Matrix - * @returns {Matrix} - */ - static solve(A, b) { - const { L, U } = "L" in A && "U" in A ? A : Matrix.LU(A); - const rows = L.shape[0]; - const x = b.clone(); - - // forward - for (let row = 0; row < rows; ++row) { - for (let col = 0; col < row; ++col) { - x.sub_entry(0, row, L.entry(row, col) * x.entry(0, col)); - } - x.set_entry(0, row, x.entry(0, row) / L.entry(row, row)); + + /** + * Returns the `col`th entry from the `row`th row of the Matrix. + * + * @param {number} row + * @param {number} col + * @returns {number} + */ + entry(row, col) { + return this.values[row * this._cols + col]; } - // backward - for (let row = rows - 1; row >= 0; --row) { - for (let col = rows - 1; col > row; --col) { - x.sub_entry(0, row, U.entry(row, col) * x.entry(0, col)); - } - x.set_entry(0, row, x.entry(0, row) / U.entry(row, row)); + /** + * Sets the {@link col}th entry from the {@link row}th row of the Matrix to the given + * {@link value}. + * + * @param {number} row + * @param {number} col + * @param {number} value + * @returns {Matrix} + */ + set_entry(row, col, value) { + this.values[row * this._cols + col] = value; + return this; } - return x; - } - - /** - * `LU` decomposition of the Matrix `A`. Creates two matrices, so that the dot product `LU` equals `A`. - * - * @param {Matrix} A - * @returns {{ L: Matrix; U: Matrix }} The left triangle matrix `L` and the upper triangle matrix `U`. - */ - static LU(A) { - const rows = A.shape[0]; - const L = new Matrix(rows, rows, "zeros"); - const U = new Matrix(rows, rows, "identity"); - - for (let j = 0; j < rows; ++j) { - for (let i = j; i < rows; ++i) { - let sum = 0; - for (let k = 0; k < j; ++k) { - sum += L.entry(i, k) * U.entry(k, j); - } - L.set_entry(i, j, A.entry(i, j) - sum); - } - for (let i = j; i < rows; ++i) { - if (L.entry(j, j) === 0) { - throw new Error("L's diagonal not supposed to be 0!"); - } - let sum = 0; - for (let k = 0; k < j; ++k) { - sum += L.entry(j, k) * U.entry(k, i); - } - U.set_entry(j, i, (A.entry(j, i) - sum) / L.entry(j, j)); - } - } - - return { L, U }; - } - - /** - * Computes the determinante of `A`, by using the `LU` decomposition of `A`. - * - * @param {Matrix} A - * @returns {number} The determinate of the Matrix `A`. - */ - static det(A) { - const [rows, cols] = A.shape; + /** + * Adds a given {@link value} to the {@link col}th entry from the {@link row}th row of the + * Matrix. + * + * @param {number} row + * @param {number} col + * @param {number} value + * @returns {Matrix} + */ + add_entry(row, col, value) { + this.values[row * this._cols + col] += value; + return this; + } - if (rows === 2 && cols === 2) { - return A.entry(0, 0) * A.entry(1, 1) - A.entry(0, 1) * A.entry(1, 0); - } - if (rows === 3 && cols === 3) { - const a = A.entry(0, 0); - const b = A.entry(0, 1); - const c = A.entry(0, 2); - const d = A.entry(1, 0); - const e = A.entry(1, 1); - const f = A.entry(1, 2); - const g = A.entry(2, 0); - const h = A.entry(2, 1); - const i = A.entry(2, 2); - return a * (e * i - f * h) - b * (d * i - f * g) + c * (d * h - e * g); - } - - const { L, U } = Matrix.LU(A); - const L_diag = L.diag(); - const U_diag = U.diag(); - let det = L_diag[0] * U_diag[0]; - for (let row = 1; row < rows; ++row) { - det *= L_diag[row] * U_diag[row]; - } - return det; - } - - /** - * Computes the `k` components of the SVD decomposition of the matrix `M`. - * - * @param {Matrix} M - * @param {number} [k=2] Default is `2` - * @returns {{ U: Float64Array[]; Sigma: Float64Array; V: Float64Array[] }} - */ - static SVD(M, k = 2) { - const MtM = M.transDot(M); - const MMt = M.dotTrans(M); - const { eigenvectors: V, eigenvalues: Sigma } = simultaneous_poweriteration(MtM, k); - const { eigenvectors: U } = simultaneous_poweriteration(MMt, k); - return { U: U, Sigma: Sigma.map((sigma) => Math.sqrt(sigma)), V: V }; - - //Algorithm 1a: Householder reduction to bidiagonal form: - /* const [m, n] = A.shape; - let U = new Matrix(m, n, (i, j) => i == j ? 1 : 0); - console.log(U.to2dArray) - let V = new Matrix(n, m, (i, j) => i == j ? 1 : 0); - console.log(V.to2dArray) - let B = Matrix.bidiagonal(A.clone(), U, V); - console.log(U,V,B) - return { U: U, "Sigma": B, V: V }; */ - } - - /** - * @param {unknown} A - * @returns {A is unknown[]|number[]|Float64Array|Float32Array} - */ - static isArray(A) { - return Array.isArray(A) || A instanceof Float64Array || A instanceof Float32Array; - } - - /** - * @param {any[]} A - * @returns {A is number[][]|Float64Array[]} - */ - static is2dArray(A) { - if (!Array.isArray(A) || A.length === 0) { - return false; - } - const n = A[0].length; - for (let i = 0; i < A.length; ++i) { - if (!Array.isArray(A[i]) && !(A[i] instanceof Float64Array)) { - return false; - } - if (A[i].length !== n) { - return false; - } - } - return true; - } -} + /** + * Subtracts a given {@link value} from the {@link col}th entry from the {@link row}th row of the + * Matrix. + * + * @param {number} row + * @param {number} col + * @param {number} value + * @returns {Matrix} + */ + sub_entry(row, col, value) { + this.values[row * this._cols + col] -= value; + return this; + } -/** @import { Metric } from "../metrics/index.js" */ + /** + * Returns a new transposed Matrix. + * + * @returns {Matrix} + */ + transpose() { + const B = new Matrix(this._cols, this._rows, (row, col) => this.entry(col, row)); + return B; + } -/** - * Computes the norm of a vector, by computing its distance to **0**. - * - * @category Matrix - * @param {Matrix | number[] | Float64Array} v - Vector. - * @param {Metric} [metric=euclidean] - Which metric should be used to compute the norm. Default is `euclidean` - * @returns {number} - The norm of `v`. - */ -function norm(v, metric = euclidean) { - let vector = null; - if (v instanceof Matrix) { - const [rows, cols] = v.shape; - if (rows === 1) vector = v.row(0); - else if (cols === 1) vector = v.col(0); - else throw new Error("Matrix must be 1d!"); - } else { - vector = v; - } - const n = vector.length; - const zeros = new Float64Array(n); - return metric(vector, zeros); -} + /** + * Returns a new transposed Matrix. Short-form of `transpose`. + * + * @returns {Matrix} + */ + get T() { + return this.transpose(); + } -/** @import { Metric } from "../metrics/index.js" */ + /** + * Returns the inverse of the Matrix. + * + * @returns {Matrix} + */ + inverse() { + const rows = this._rows; + const cols = this._cols; + const A = this.clone(); + const B = new Matrix(rows, cols, "I"); + + // foreach column + for (let col = 0; col < cols; ++col) { + // Search for maximum in this column (pivot) + let max_idx = col; + let max_val = Math.abs(A.entry(col, col)); + for (let row = col + 1; row < rows; ++row) { + const val = Math.abs(A.entry(row, col)); + if (max_val < val) { + max_idx = row; + max_val = val; + } + } + if (max_val === 0) { + throw new Error("Cannot compute inverse of Matrix, determinant is zero"); + } + // Swap maximum row with current row + if (max_idx !== col) { + A.swap_rows(col, max_idx); + B.swap_rows(col, max_idx); + } -/** - * Normalizes Vector `v`. + // eliminate non-zero values on the other rows at column c + const A_col = A.row(col); + const B_col = B.row(col); + for (let row = 0; row < rows; ++row) { + if (row !== col) { + // eliminate value at column c and row r + const A_row = A.row(row); + const B_row = B.row(row); + if (A_row[col] !== 0) { + const f = A_row[col] / A_col[col]; + // sub (f * row c) from row r to eliminate the value at column c + for (let s = col; s < cols; ++s) { + A_row[s] -= f * A_col[s]; + } + for (let s = 0; s < cols; ++s) { + B_row[s] -= f * B_col[s]; + } + } + } else { + // normalize value at Acc to 1 (diagonal): + // divide each value of row r=c by the value at Acc + const f = A_col[col]; + for (let s = col; s < cols; ++s) { + A_col[s] /= f; + } + for (let s = 0; s < cols; ++s) { + B_col[s] /= f; + } + } + } + } + return B; + } + + /** + * Returns the dot product. If `B` is an Array or Float64Array then an Array gets returned. If `B` is a Matrix then + * a Matrix gets returned. + * + * @param {Matrix | number[] | Float64Array} B The right side + * @returns {Matrix} + */ + dot(B) { + if (B instanceof Matrix) { + const [rows_A, cols_A] = this.shape; + const [rows_B, cols_B] = B.shape; + if (cols_A !== rows_B) { + throw new Error(`A.dot(B): A is a ${this.shape.join(" ⨯ ")}-Matrix, B is a ${B.shape.join(" ⨯ ")}-Matrix: + A has ${cols_A} cols and B ${rows_B} rows. + Must be equal!`); + } + const C = new Matrix(rows_A, cols_B, 0); + const A_val = this.values; + const B_val = B.values; + const C_val = C.values; + + for (let i = 0; i < rows_A; ++i) { + const i_cols_A = i * cols_A; + const i_cols_B = i * cols_B; + for (let k = 0; k < cols_A; ++k) { + const aik = A_val[i_cols_A + k]; + if (aik === 0) continue; + const k_cols_B = k * cols_B; + for (let j = 0; j < cols_B; ++j) { + C_val[i_cols_B + j] += aik * B_val[k_cols_B + j]; + } + } + } + return C; + } else if (Matrix.isArray(B)) { + // TODO: create Matrix directly + const rows = this._rows; + if (B.length !== rows) { + throw new Error(`A.dot(B): A has ${rows} cols and B has ${B.length} rows. Must be equal!`); + } + const C = new Array(rows); + for (let row = 0; row < rows; ++row) { + C[row] = neumair_sum(this.row(row).map((e) => e * B[row])); + } + return Matrix.from(C); + } else { + throw new Error(`B must be Matrix or Array`); + } + } + + /** + * Transposes the current matrix and returns the dot product with `B`. If `B` is an Array or Float64Array then an + * Array gets returned. If `B` is a Matrix then a Matrix gets returned. + * + * @param {Matrix | number[] | Float64Array} B The right side + * @returns {Matrix} + */ + transDot(B) { + if (B instanceof Matrix) { + const [cols_A, rows_A] = this.shape; // transpose matrix + const [rows_B, cols_B] = B.shape; + if (cols_A !== rows_B) { + throw new Error(`A.dot(B): A is a ${[rows_A, cols_A].join(" ⨯ ")}-Matrix, B is a ${B.shape.join(" ⨯ ")}-Matrix: + A has ${cols_A} cols and B ${rows_B} rows, which must be equal!`); + } + // let B = new Matrix(this._cols, this._rows, (row, col) => this.entry(col, row)); + // this.values[row * this._cols + col]; + const C = new Matrix(rows_A, cols_B, 0); + const A_val = this.values; // A is rows_B x rows_A (transposed) + const B_val = B.values; + const C_val = C.values; + + for (let k = 0; k < cols_A; ++k) { + // cols_A is rows_B + const k_rows_A = k * rows_A; + const k_cols_B = k * cols_B; + for (let i = 0; i < rows_A; ++i) { + const aki = A_val[k_rows_A + i]; + if (aki === 0) continue; + for (let j = 0; j < cols_B; ++j) { + C_val[i * cols_B + j] += aki * B_val[k_cols_B + j]; + } + } + } + return C; + } else if (Matrix.isArray(B)) { + // TODO: create Matrix directly + const rows = this._cols; + if (B.length !== rows) { + throw new Error(`A.dot(B): A has ${rows} cols and B has ${B.length} rows. Must be equal!`); + } + const C = new Array(rows); + for (let row = 0; row < rows; ++row) { + C[row] = neumair_sum(this.col(row).map((e) => e * B[row])); + } + return Matrix.from(C); + } else { + throw new Error(`B must be Matrix or Array`); + } + } + + /** + * Returns the dot product with the transposed version of `B`. If `B` is an Array or Float64Array then an Array gets + * returned. If `B` is a Matrix then a Matrix gets returned. + * + * @param {Matrix | number[] | Float64Array} B The right side + * @returns {Matrix} + */ + dotTrans(B) { + if (B instanceof Matrix) { + const [rows_A, cols_A] = this.shape; + const [cols_B, rows_B] = B.shape; + if (cols_A !== rows_B) { + throw new Error(`A.dot(B): A is a ${this.shape.join(" ⨯ ")}-Matrix, B is a ${[rows_B, cols_B].join(" ⨯ ")}-Matrix: + A has ${cols_A} cols and B ${rows_B} rows, which must be equal!`); + } + const C = new Matrix(rows_A, cols_B, (row, col) => { + const A_i = this.row(row); + const B_i = B.row(col); + let sum = 0; + for (let i = 0; i < cols_A; ++i) { + sum += A_i[i] * B_i[i]; + } + return sum; + }); + return C; + } else if (Matrix.isArray(B)) { + // TODO: create Matrix directly + const rows = this._rows; + if (B.length !== rows) { + throw new Error(`A.dot(B): A has ${rows} cols and B has ${B.length} rows. Must be equal!`); + } + const C = new Array(rows); + for (let row = 0; row < rows; ++row) { + C[row] = neumair_sum(this.row(row).map((e) => e * B[row])); + } + return Matrix.from(C); + } else { + throw new Error(`B must be Matrix or Array`); + } + } + + /** + * Computes the outer product from `this` and `B`. + * + * @param {Matrix} B + * @returns {Matrix} + */ + outer(B) { + const l = this._data.length; + const r = B._data.length; + if (l !== r) throw new Error("Matrix A and B needs to be of the same length!"); + const C = new Matrix( + l, + l, + /** @type {Accessor} */ (i, j) => { + if (i <= j) { + return this._data[i] * B._data[j]; + } else { + return this.entry(j, i); + } + }, + ); + + return C; + } + + /** + * Appends matrix `B` to the matrix. + * + * @example let A = Matrix.from([ [1, 1], [1, 1], ]); // 2 by 2 matrix filled with ones. let B = Matrix.from([ [2, + * 2], [2, 2], ]); // 2 by 2 matrix filled with twos. + * + * A.concat(B, "horizontal"); // 2 by 4 matrix. [[1, 1, 2, 2], [1, 1, 2, 2]] + * A.concat(B, "vertical"); // 4 by 2 matrix. [[1, 1], [1, 1], [2, 2], [2, 2]] + * A.concat(B, "diag"); // 4 by 4 matrix. [[1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 2, 2], [0, 0, 2, 2]] + * + * @param {Matrix} B - Matrix to append. + * @param {"horizontal" | "vertical" | "diag"} [type="horizontal"] - Type of concatenation. Default is + * `"horizontal"` + * @returns {Matrix} + */ + concat(B, type = "horizontal") { + const [rows_A, cols_A] = this.shape; + const [rows_B, cols_B] = B.shape; + if (type === "horizontal") { + if (rows_A !== rows_B) { + throw new Error( + `A.concat(B, "horizontal"): A and B need same number of rows, A has ${rows_A} rows, B has ${rows_B} rows.`, + ); + } + const X = new Matrix(rows_A, cols_A + cols_B, "zeros"); + X.set_block(0, 0, this); + X.set_block(0, cols_A, B); + return X; + } else if (type === "vertical") { + if (cols_A !== cols_B) { + throw new Error( + `A.concat(B, "vertical"): A and B need same number of columns, A has ${cols_A} columns, B has ${cols_B} columns.`, + ); + } + const X = new Matrix(rows_A + rows_B, cols_A, "zeros"); + X.set_block(0, 0, this); + X.set_block(rows_A, 0, B); + return X; + } else if (type === "diag") { + const X = new Matrix(rows_A + rows_B, cols_A + cols_B, "zeros"); + X.set_block(0, 0, this); + X.set_block(rows_A, cols_A, B); + return X; + } else { + throw new Error(`type must be "horizontal" or "vertical", but type is ${type}!`); + } + } + + /** + * Writes the entries of B in A at an offset position given by `offset_row` and `offset_col`. + * + * @param {number} offset_row + * @param {number} offset_col + * @param {Matrix} B + * @returns {Matrix} + */ + set_block(offset_row, offset_col, B) { + const rows = Math.min(this._rows - offset_row, B.shape[0]); + const cols = Math.min(this._cols - offset_col, B.shape[1]); + for (let row = 0; row < rows; ++row) { + for (let col = 0; col < cols; ++col) { + this.set_entry(row + offset_row, col + offset_col, B.entry(row, col)); + } + } + return this; + } + + /** + * Extracts the entries from the `start_row`th row to the `end_row`th row, the + * `start_col`th column to the `end_col`th column of the matrix. If `end_row` or `end_col` is + * empty, the respective value is set to `this.rows` or `this.cols`. + * + * @example let A = Matrix.from([ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]); // a 3 by 3 matrix. + * + * A.get_block(1, 1); // [[5, 6], [8, 9]] + * A.get_block(0, 0, 1, 1); // [[1]] + * A.get_block(1, 1, 2, 2); // [[5]] + * A.get_block(0, 0, 2, 2); // [[1, 2], [4, 5]] + * + * @param {number} start_row + * @param {number} start_col + * @param {number | null} [end_row] + * @param {number | null} [end_col] + * @returns {Matrix} Returns a `end_row` - `start_row` times `end_col` - `start_col` matrix, with respective entries + * from the matrix. + */ + get_block(start_row, start_col, end_row, end_col) { + const [rows, cols] = this.shape; + end_row = end_row ?? rows; + end_col = end_col ?? cols; + if (end_row <= start_row || end_col <= start_col) { + throw new Error(` + end_row must be greater than start_row, and + end_col must be greater than start_col, but + end_row = ${end_row}, start_row = ${start_row}, end_col = ${end_col}, and start_col = ${start_col}!`); + } + const X = new Matrix(end_row - start_row, end_col - start_col, "zeros"); + for (let row = start_row, new_row = 0; row < end_row; ++row, ++new_row) { + for (let col = start_col, new_col = 0; col < end_col; ++col, ++new_col) { + X.set_entry(new_row, new_col, this.entry(row, col)); + } + } + return X; + } + + /** + * Returns a new array gathering entries defined by the indices given by argument. + * + * @param {number[]} row_indices - Array consists of indices of rows for gathering entries of this matrix + * @param {number[]} col_indices - Array consists of indices of cols for gathering entries of this matrix + * @returns {Matrix} + */ + gather(row_indices, col_indices) { + const N = row_indices.length; + const D = col_indices.length; + + const R = new Matrix(N, D); + for (let i = 0; i < N; ++i) { + const row_index = row_indices[i]; + for (let j = 0; j < D; ++j) { + const col_index = col_indices[j]; + R.set_entry(i, j, this.entry(row_index, col_index)); + } + } + + return R; + } + + /** + * Applies a function to each entry of the matrix. + * + * @private + * @param {(d: number, v: number) => number} f Function takes 2 parameters, the value of the actual entry and a + * value given by the function `v`. The result of `f` gets writen to the Matrix. + * @param {Accessor} v Function takes 2 parameters for `row` and `col`, and returns a value witch should be applied + * to the `col`th entry of the `row`th row of the matrix. + * @returns {Matrix} + */ + _apply_array(f, v) { + const data = this.values; + const [rows, cols] = this.shape; + for (let i = 0, row = 0; row < rows; ++row) { + for (let col = 0; col < cols; ++col, ++i) { + data[i] = f(data[i], v(row, col)); + } + } + return this; + } + + /** + * @param {number[] | Float64Array} values + * @param {(d: number, v: number) => number} f + * @returns {Matrix} + */ + _apply_rowwise_array(values, f) { + return this._apply_array(f, (_, j) => values[j]); + } + /** + * @param {number[] | Float64Array} values + * @param {(d: number, v: number) => number} f + * @returns {Matrix} + */ + _apply_colwise_array(values, f) { + const data = this.values; + const [rows, cols] = this.shape; + for (let i = 0, row = 0; row < rows; ++row) { + const val = values[row]; + for (let col = 0; col < cols; ++col, ++i) { + data[i] = f(data[i], val); + } + } + return this; + } + + /** + * @param {Matrix | number[] | Float64Array | number} value + * @param {(d: number, v: number) => number} f + * @returns {Matrix} + */ + _apply(value, f) { + const data = this.values; + const [rows, cols] = this.shape; + if (value instanceof Matrix) { + const values = value.values; + const [value_rows, value_cols] = value.shape; + if (value_rows === 1) { + if (cols !== value_cols) { + throw new Error(`cols !== value_cols`); + } + for (let i = 0, row = 0; row < rows; ++row) { + for (let col = 0; col < cols; ++col, ++i) { + data[i] = f(data[i], values[col]); + } + } + } else if (value_cols === 1) { + if (rows !== value_rows) { + throw new Error(`rows !== value_rows`); + } + for (let i = 0, row = 0; row < rows; ++row) { + const v = values[row]; + for (let col = 0; col < cols; ++col, ++i) { + data[i] = f(data[i], v); + } + } + } else if (rows === value_rows && cols === value_cols) { + for (let i = 0, n = rows * cols; i < n; ++i) { + data[i] = f(data[i], values[i]); + } + } else { + throw new Error(`error`); + } + } else if (Matrix.isArray(value)) { + if (value.length === rows) { + for (let i = 0, row = 0; row < rows; ++row) { + const v = value[row]; + for (let col = 0; col < cols; ++col, ++i) { + data[i] = f(data[i], v); + } + } + } else if (value.length === cols) { + for (let i = 0, row = 0; row < rows; ++row) { + for (let col = 0; col < cols; ++col, ++i) { + data[i] = f(data[i], value[col]); + } + } + } else { + throw new Error(`error`); + } + } else { + // scalar value + for (let i = 0, n = rows * cols; i < n; ++i) { + data[i] = f(data[i], value); + } + } + return this; + } + + /** + * Clones the Matrix. + * + * @returns {Matrix} + */ + clone() { + const B = new Matrix(this._rows, this._cols); + //B._rows = this._rows; + //B._cols = this._cols; + if (this._data) { + B._data = this._data.slice(0); + } + return B; + } + + /** + * Entrywise multiplication with `value`. + * + * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; + * + * A.mult(2); // [[2, 4], [6, 8]]; + * A.mult(B); // [[1, 4], [9, 16]]; + * + * @param {Matrix | Float64Array | number[] | number} value + * @param {Object} [options] + * @param {boolean} [options.inline=false] - If true, applies multiplication to the element, otherwise it creates + * first a copy and applies the multiplication on the copy. Default is `false` + * @returns {Matrix} + */ + mult(value, { inline = false } = {}) { + const A = inline ? this : this.clone(); + return A._apply(value, (a, b) => a * b); + } + + /** + * Entrywise division with `value`. + * + * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; + * + * A.divide(2); // [[0.5, 1], [1.5, 2]]; + * A.divide(B); // [[1, 1], [1, 1]]; + * + * @param {Matrix | Float64Array | number[] | number} value + * @param {Object} [options] + * @param {Boolean} [options.inline=false] - If true, applies division to the element, otherwise it creates first a + * copy and applies the division on the copy. Default is `false` + * @returns {Matrix} + */ + divide(value, { inline = false } = {}) { + const A = inline ? this : this.clone(); + return A._apply(value, (a, b) => a / b); + } + + /** + * Entrywise addition with `value`. + * + * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; + * + * A.add(2); // [[3, 4], [5, 6]]; + * A.add(B); // [[2, 4], [6, 8]]; + * + * @param {Matrix | Float64Array | number[] | number} value + * @param {Object} [options] + * @param {boolean} [options.inline=false] - If true, applies addition to the element, otherwise it creates first a + * copy and applies the addition on the copy. Default is `false` + * @returns {Matrix} + */ + add(value, { inline = false } = {}) { + const A = inline ? this : this.clone(); + return A._apply(value, (a, b) => a + b); + } + + /** + * Entrywise subtraction with `value`. + * + * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; + * + * A.sub(2); // [[-1, 0], [1, 2]]; + * A.sub(B); // [[0, 0], [0, 0]]; + * + * @param {Matrix | Float64Array | number[] | number} value + * @param {Object} [options] + * @param {boolean} [options.inline=false] - If true, applies subtraction to the element, otherwise it creates first + * a copy and applies the subtraction on the copy. Default is `false` + * @returns {Matrix} + */ + sub(value, { inline = false } = {}) { + const A = inline ? this : this.clone(); + return A._apply(value, (a, b) => a - b); + } + + /** + * Returns the number of rows and columns of the Matrix. + * + * @returns {number[]} An Array in the form [rows, columns]. + */ + get shape() { + return [this._rows, this._cols]; + } + + /** + * Returns the matrix in the given shape with the given function which returns values for the entries of the matrix. + * + * @param {[number, number, Accessor]} parameter - Takes an Array in the form [rows, cols, value], where rows and + * cols are the number of rows and columns of the matrix, and value is a function which takes two parameters (row + * and col) which has to return a value for the colth entry of the rowth row. + * @returns {Matrix} + */ + set shape([rows, cols, value = () => 0]) { + this._rows = rows; + this._cols = cols; + this._data = new Float64Array(rows * cols); + for (let i = 0, row = 0; row < rows; ++row) { + for (let col = 0; col < cols; ++col, ++i) { + this._data[i] = value(row, col); + } + } + } + + /** + * Returns the Matrix as a Array of Float64Arrays. + * + * @returns {Float64Array[]} + */ + to2dArray() { + const result = []; + for (const row of this.iterate_rows()) { + result.push(row); + } + return result; + } + + /** + * Returns the Matrix as a Array of Arrays. + * + * @returns {number[][]} + */ + asArray() { + const result = []; + for (const row of this.iterate_rows()) { + result.push(Array.from(row)); + } + return result; + } + + /** + * Returns the diagonal of the Matrix. + * + * @returns {Float64Array} + */ + diag() { + const rows = this._rows; + const cols = this._cols; + const min_row_col = Math.min(rows, cols); + const result = new Float64Array(min_row_col); + for (let i = 0; i < min_row_col; ++i) { + result[i] = this.entry(i, i); + } + return result; + } + + /** + * Returns the mean of all entries of the Matrix. + * + * @returns {number} + */ + mean() { + const sum = this.sum(); + const n = this._rows * this._cols; + return sum / n; + } + + /** + * Returns the sum oof all entries of the Matrix. + * + * @returns {number} + */ + sum() { + const data = this.values; + return neumair_sum(data); + } + + /** + * Returns the entries of the Matrix. + * + * @returns {Float64Array} + */ + get values() { + const data = this._data; + return data; + } + + /** + * Returns the mean of each row of the matrix. + * + * @returns {Float64Array} + */ + meanRows() { + const data = this.values; + const rows = this._rows; + const cols = this._cols; + const result = Float64Array.from({ length: rows }); + for (let i = 0, row = 0; row < rows; ++row) { + let sum = 0; + for (let col = 0; col < cols; ++col, ++i) { + sum += data[i]; + } + result[row] = sum / cols; + } + return result; + } + + /** + * Returns the mean of each column of the matrix. + * + * @returns {Float64Array} + */ + meanCols() { + const data = this.values; + const rows = this._rows; + const cols = this._cols; + const result = Float64Array.from({ length: cols }); + for (let col = 0; col < cols; ++col) { + let sum = 0; + for (let i = col, row = 0; row < rows; ++row, i += cols) { + sum += data[i]; + } + result[col] = sum / rows; + } + return result; + } + + /** + * Solves the equation `Ax = b` using the conjugate gradient method. Returns the result `x`. + * + * @param {Matrix} A - Matrix + * @param {Matrix} b - Matrix + * @param {Randomizer | null} [randomizer] + * @param {number} [tol=1e-3] Default is `1e-3` + * @returns {Matrix} + */ + static solve_CG(A, b, randomizer, tol = 1e-3) { + if (!randomizer) { + randomizer = new Randomizer(); + } + const rows = A.shape[0]; + const cols = b.shape[1]; + let result = new Matrix(rows, 0); + for (let i = 0; i < cols; ++i) { + const b_i = Matrix.from_vector(b.col(i), "col"); + let x = new Matrix(rows, 1, () => randomizer.random); + let r = b_i.sub(A.dot(x)); + let d = r.clone(); + let iter = 0; + const max_iter = rows * 10; // Prevent infinite loops + do { + const z = A.dot(d); + const alpha = r.transDot(r).entry(0, 0) / d.transDot(z).entry(0, 0); + x = x.add(d.mult(alpha)); + const r_next = r.sub(z.mult(alpha)); + const beta = r_next.transDot(r_next).entry(0, 0) / r.transDot(r).entry(0, 0); + d = r_next.add(d.mult(beta)); + r = r_next; + iter++; + } while (Math.abs(r.mean()) > tol && iter < max_iter); + result = result.concat(x, "horizontal"); + } + return result; + } + + /** + * Solves the equation `Ax = b`. Returns the result `x`. + * + * @param {Matrix | { L: Matrix; U: Matrix }} A - Matrix or LU Decomposition + * @param {Matrix} b - Matrix + * @returns {Matrix} + */ + static solve(A, b) { + const { L, U } = "L" in A && "U" in A ? A : Matrix.LU(A); + const rows = L.shape[0]; + const x = b.clone(); + + // forward + for (let row = 0; row < rows; ++row) { + for (let col = 0; col < row; ++col) { + x.sub_entry(0, row, L.entry(row, col) * x.entry(0, col)); + } + x.set_entry(0, row, x.entry(0, row) / L.entry(row, row)); + } + + // backward + for (let row = rows - 1; row >= 0; --row) { + for (let col = rows - 1; col > row; --col) { + x.sub_entry(0, row, U.entry(row, col) * x.entry(0, col)); + } + x.set_entry(0, row, x.entry(0, row) / U.entry(row, row)); + } + + return x; + } + + /** + * `LU` decomposition of the Matrix `A`. Creates two matrices, so that the dot product `LU` equals `A`. + * + * @param {Matrix} A + * @returns {{ L: Matrix; U: Matrix }} The left triangle matrix `L` and the upper triangle matrix `U`. + */ + static LU(A) { + const rows = A.shape[0]; + const L = new Matrix(rows, rows, "zeros"); + const U = new Matrix(rows, rows, "identity"); + + for (let j = 0; j < rows; ++j) { + for (let i = j; i < rows; ++i) { + let sum = 0; + for (let k = 0; k < j; ++k) { + sum += L.entry(i, k) * U.entry(k, j); + } + L.set_entry(i, j, A.entry(i, j) - sum); + } + for (let i = j; i < rows; ++i) { + if (L.entry(j, j) === 0) { + throw new Error("L's diagonal not supposed to be 0!"); + } + let sum = 0; + for (let k = 0; k < j; ++k) { + sum += L.entry(j, k) * U.entry(k, i); + } + U.set_entry(j, i, (A.entry(j, i) - sum) / L.entry(j, j)); + } + } + + return { L, U }; + } + + /** + * Computes the determinante of `A`, by using the `LU` decomposition of `A`. + * + * @param {Matrix} A + * @returns {number} The determinate of the Matrix `A`. + */ + static det(A) { + const [rows, cols] = A.shape; + + if (rows === 2 && cols === 2) { + return A.entry(0, 0) * A.entry(1, 1) - A.entry(0, 1) * A.entry(1, 0); + } + if (rows === 3 && cols === 3) { + const a = A.entry(0, 0); + const b = A.entry(0, 1); + const c = A.entry(0, 2); + const d = A.entry(1, 0); + const e = A.entry(1, 1); + const f = A.entry(1, 2); + const g = A.entry(2, 0); + const h = A.entry(2, 1); + const i = A.entry(2, 2); + return a * (e * i - f * h) - b * (d * i - f * g) + c * (d * h - e * g); + } + + const { L, U } = Matrix.LU(A); + const L_diag = L.diag(); + const U_diag = U.diag(); + let det = L_diag[0] * U_diag[0]; + for (let row = 1; row < rows; ++row) { + det *= L_diag[row] * U_diag[row]; + } + return det; + } + + /** + * Computes the `k` components of the SVD decomposition of the matrix `M`. + * + * @param {Matrix} M + * @param {number} [k=2] Default is `2` + * @returns {{ U: Float64Array[]; Sigma: Float64Array; V: Float64Array[] }} + */ + static SVD(M, k = 2) { + const MtM = M.transDot(M); + const MMt = M.dotTrans(M); + const { eigenvectors: V, eigenvalues: Sigma } = simultaneous_poweriteration(MtM, k); + const { eigenvectors: U } = simultaneous_poweriteration(MMt, k); + return { U: U, Sigma: Sigma.map((sigma) => Math.sqrt(sigma)), V: V }; + + //Algorithm 1a: Householder reduction to bidiagonal form: + /* const [m, n] = A.shape; + let U = new Matrix(m, n, (i, j) => i == j ? 1 : 0); + console.log(U.to2dArray) + let V = new Matrix(n, m, (i, j) => i == j ? 1 : 0); + console.log(V.to2dArray) + let B = Matrix.bidiagonal(A.clone(), U, V); + console.log(U,V,B) + return { U: U, "Sigma": B, V: V }; */ + } + + /** + * @param {unknown} A + * @returns {A is unknown[]|number[]|Float64Array|Float32Array} + */ + static isArray(A) { + return Array.isArray(A) || A instanceof Float64Array || A instanceof Float32Array; + } + + /** + * @param {any[]} A + * @returns {A is number[][]|Float64Array[]} + */ + static is2dArray(A) { + if (!Array.isArray(A) || A.length === 0) { + return false; + } + const n = A[0].length; + for (let i = 0; i < A.length; ++i) { + if (!Array.isArray(A[i]) && !(A[i] instanceof Float64Array)) { + return false; + } + if (A[i].length !== n) { + return false; + } + } + return true; + } +} + +/** @import { Metric } from "../metrics/index.js" */ + +/** + * Computes the norm of a vector, by computing its distance to **0**. + * + * @category Matrix + * @param {Matrix | number[] | Float64Array} v - Vector. + * @param {Metric} [metric=euclidean] - Which metric should be used to compute the norm. Default is `euclidean` + * @returns {number} - The norm of `v`. + */ +function norm(v, metric = euclidean) { + let vector = null; + if (v instanceof Matrix) { + const [rows, cols] = v.shape; + if (rows === 1) vector = v.row(0); + else if (cols === 1) vector = v.col(0); + else throw new Error("Matrix must be 1d!"); + } else { + vector = v; + } + const n = vector.length; + const zeros = new Float64Array(n); + return metric(vector, zeros); +} + +/** @import { Metric } from "../metrics/index.js" */ + +/** + * Normalizes Vector `v`. + * + * @category Matrix + * @param {number[] | Float64Array} v - Vector + * @param {Metric} metric + * @returns {number[] | Float64Array} - The normalized vector with length 1. + */ +function normalize(v, metric = euclidean) { + const v_norm = norm(v, metric); + return v.map((value) => value / v_norm); +} + +/** @import {InputType} from "../index.js" */ + +/** + * Base class for all clustering algorithms. + * @template Para + */ +class Clustering { + /** @type {InputType} */ + _points; + /** @type {Para} */ + _parameters; + /** @type {Matrix} */ + _matrix; + /** @type {number} */ + _N; + /** @type {number} */ + _D; + + /** + * Compute the respective Clustering with given parameters + * @param {InputType} points + * @param {Para} parameters + */ + constructor(points, parameters) { + this._points = points; + this._parameters = parameters; + + this._matrix = points instanceof Matrix ? points : Matrix.from(points); + const [N, D] = this._matrix.shape; + this._N = N; + this._D = D; + } + + /** + * @abstract + * @param {...unknown} args + * @returns {number[][]} An array with the indices of the clusters. + */ + get_clusters(...args) { + throw new Error("The function get_clusters must be implemented!"); + } + + /** + * @abstract + * @param {...unknown} args + * @returns {number[]} An array with the clusters id's for each point. + */ + get_cluster_list(...args) { + throw new Error("The function get_cluster_list must be implemented!"); + } +} + +/** @import { InputType } from "../index.js" */ +/** @import { ParametersCURE } from "./index.js" */ + +/** + * CURE (Clustering Using REpresentatives) + * + * An efficient clustering algorithm for large databases that is robust to outliers + * and identifies clusters with non-spherical shapes and wide variances in size. + * + * @class + * @extends Clustering + * @category Clustering + */ +class CURE extends Clustering { + /** @type {number} */ + _K; + /** @type {number} */ + _num_representatives; + /** @type {number} */ + _shrink_factor; + /** + * @private + * @type {CURECluster[]} + */ + _clusters = []; + /** @type {number[]} */ + _cluster_ids = []; + + /** + * @param {InputType} points + * @param {Partial} parameters + */ + constructor(points, parameters = {}) { + super( + points, + /** @type {ParametersCURE} */ ( + Object.assign( + { K: 2, num_representatives: 5, shrink_factor: 0.5, metric: euclidean, seed: 1212 }, + parameters, + ) + ), + ); + + this._K = this._parameters.K ?? 2; + this._num_representatives = this._parameters.num_representatives ?? 5; + this._shrink_factor = this._parameters.shrink_factor ?? 0.5; + + // Initialize clusters + this._initialize_clusters(); + // Run CURE algorithm + this._cure(); + } + + /** + * Initialize each point as its own cluster + * @private + */ + _initialize_clusters() { + const N = this._N; + //const D = this._D; + this._clusters = []; + + for (let i = 0; i < N; ++i) { + const point = this._matrix.row(i); + const centroid = new Float64Array(point); + // For single point, representative is the point itself + const representatives = [new Float64Array(point)]; + + this._clusters.push(new CURECluster([i], centroid, representatives)); + } + } + + /** + * Compute distance between two clusters using representative points + * @private + * @param {CURECluster} cluster1 + * @param {CURECluster} cluster2 + * @returns {number} + */ + _cluster_distance(cluster1, cluster2) { + const reps1 = cluster1.representatives; + const reps2 = cluster2.representatives; + const metric = this._parameters.metric; + + let min_dist = Infinity; + for (const r1 of reps1) { + for (const r2 of reps2) { + const dist = metric(r1, r2); + if (dist < min_dist) { + min_dist = dist; + } + } + } + return min_dist; + } + + /** + * Find the closest pair of clusters + * @private + * @returns {[number, number, number]} [index1, index2, distance] + */ + _find_closest_clusters() { + let min_dist = Infinity; + let min_i = 0; + let min_j = 1; + + for (let i = 0; i < this._clusters.length; ++i) { + for (let j = i + 1; j < this._clusters.length; ++j) { + const dist = this._cluster_distance(this._clusters[i], this._clusters[j]); + if (dist < min_dist) { + min_dist = dist; + min_i = i; + min_j = j; + } + } + } + + return [min_i, min_j, min_dist]; + } + + /** + * Merge two clusters + * @private + * @param {CURECluster} cluster1 + * @param {CURECluster} cluster2 + * @returns {CURECluster} + */ + _merge_clusters(cluster1, cluster2) { + // Merge indices + const merged_indices = [...cluster1.indices, ...cluster2.indices]; + + // Calculate new centroid + const size1 = cluster1.indices.length; + const size2 = cluster2.indices.length; + const total_size = size1 + size2; + const D = this._D; + const new_centroid = new Float64Array(D); + + for (let d = 0; d < D; ++d) { + new_centroid[d] = (size1 * cluster1.centroid[d] + size2 * cluster2.centroid[d]) / total_size; + } + + // Collect all points from both clusters + /** @type {{index: number, point: Float64Array}[]} */ + const all_points = []; + for (const idx of cluster1.indices) { + all_points.push({ index: idx, point: this._matrix.row(idx) }); + } + for (const idx of cluster2.indices) { + all_points.push({ index: idx, point: this._matrix.row(idx) }); + } + + // Select representative points - pick points farthest from centroid + const num_reps = Math.min(this._num_representatives, all_points.length); + const metric = this._parameters.metric; + + // Calculate distances from centroid for all points + const distances = all_points.map(({ point }) => metric(point, new_centroid)); + + // Select num_reps points with maximum distance (farthest from centroid) + const selected_indices = []; + const used = new Set(); + + for (let r = 0; r < num_reps; ++r) { + let max_dist = -1; + let max_idx = -1; + + for (let i = 0; i < distances.length; ++i) { + if (!used.has(i) && distances[i] > max_dist) { + max_dist = distances[i]; + max_idx = i; + } + } + + if (max_idx >= 0) { + used.add(max_idx); + selected_indices.push(max_idx); + } + } + + // Shrink representative points toward centroid + const new_representatives = selected_indices.map((idx) => { + const point = all_points[idx].point; + const shrunk = new Float64Array(D); + const alpha = this._shrink_factor; + + for (let d = 0; d < D; ++d) { + shrunk[d] = point[d] + alpha * (new_centroid[d] - point[d]); + } + + return shrunk; + }); + + return new CURECluster(merged_indices, new_centroid, new_representatives); + } + + /** + * Run CURE clustering algorithm + * @private + */ + _cure() { + // Merge clusters until we have K clusters + while (this._clusters.length > this._K) { + const [i, j] = this._find_closest_clusters(); + + // Merge clusters i and j + const merged = this._merge_clusters(this._clusters[i], this._clusters[j]); + + // Remove the old clusters and add the merged one + // Remove larger index first to maintain correct indices + // min_i < min_j is always true from _find_closest_clusters + this._clusters.splice(j, 1); + this._clusters.splice(i, 1); + + this._clusters.push(merged); + } + + // Build cluster list for get_cluster_list + this._build_cluster_ids(); + } + + /** + * Build the cluster list (point -> cluster assignment) + * @private + */ + _build_cluster_ids() { + const N = this._N; + this._cluster_ids = new Array(N).fill(-1); + + for (let c = 0; c < this._clusters.length; ++c) { + for (const idx of this._clusters[c].indices) { + this._cluster_ids[idx] = c; + } + } + } + + /** + * @returns {number[][]} + */ + get_clusters() { + return this._clusters.map((cluster) => cluster.indices); + } + + /** + * @returns {number[]} + */ + get_cluster_list() { + return this._cluster_ids; + } +} + +/** + * @private + * Represents a cluster in CURE algorithm + */ +class CURECluster { + /** + * @param {number[]} indices - Indices of points in the cluster + * @param {Float64Array} centroid - Centroid of the cluster + * @param {Float64Array[]} representatives - Representative points (shrunk toward centroid) + */ + constructor(indices, centroid, representatives) { + /** @type {number[]} */ + this.indices = indices; + /** @type {Float64Array} */ + this.centroid = centroid; + /** @type {Float64Array[]} */ + this.representatives = representatives; + } +} + +/** @import { InputType } from "../index.js" */ +/** @import { ParametersHierarchicalClustering } from "./index.js" */ + +/** + * Hierarchical Clustering + * + * A bottom-up approach (agglomerative) to clustering that builds a tree of clusters (dendrogram). + * Supports different linkage criteria: single, complete, and average. + * + * @class + * @extends Clustering + * @category Clustering + */ +class HierarchicalClustering extends Clustering { + /** @type {Cluster | null} */ + root = null; + + /** + * @param {InputType} points - Data or distance matrix if metric is 'precomputed' + * @param {Partial} parameters + */ + constructor(points, parameters = {}) { + super( + points, + /** @type {ParametersHierarchicalClustering} */ ( + Object.assign({ linkage: "complete", metric: euclidean }, parameters) + ), + ); + this._id = 0; + if (this._parameters.metric === "precomputed" && this._matrix.shape[0] !== this._matrix.shape[1]) { + throw new Error("If metric is 'precomputed', then matrix has to be square!"); + } + + const metric = this._parameters.metric; + const A = this._matrix; + const N = this._N; + this._d_min = new Float64Array(N); + const d_min = this._d_min; + let distance_matrix; + if (metric !== "precomputed") { + distance_matrix = new Matrix(N, N, Infinity); + for (let i = 0; i < N; ++i) { + distance_matrix.set_entry(i, i, 0); + d_min[i] = i; // temporary + const Ai = A.row(i); + for (let j = i + 1; j < N; ++j) { + const dist = metric(Ai, A.row(j)); + distance_matrix.set_entry(i, j, dist); + distance_matrix.set_entry(j, i, dist); + } + } + for (let i = 0; i < N; i++) { + let min_j = 0; + let min_d = Infinity; + for (let j = 0; j < N; j++) { + if (i === j) continue; + const d = distance_matrix.entry(i, j); + if (d < min_d) { + min_d = d; + min_j = j; + } + } + d_min[i] = min_j; + } + } else { + distance_matrix = this._matrix.clone(); + for (let i = 0; i < N; ++i) { + distance_matrix.set_entry(i, i, 0); + d_min[i] = i === 0 ? 1 : 0; + for (let j = 0; j < N; ++j) { + if (i === j) continue; + if (distance_matrix.entry(i, d_min[i]) > distance_matrix.entry(i, j)) { + d_min[i] = j; + } + } + } + } + this._distance_matrix = distance_matrix; + this._clusters = new Array(N); + const clusters = this._clusters; + this._c_size = new Uint16Array(N); + const c_size = this._c_size; + for (let i = 0; i < N; ++i) { + clusters[i] = []; + clusters[i][0] = new Cluster(this._id++, null, null, 0, A.row(i), i, 1, 0); + c_size[i] = 1; + } + const D = this._distance_matrix; + const linkage = this._parameters.linkage; + const p_max = N - 1; + for (let p = 0; p < p_max; ++p) { + let c1 = -1; + let min_dist = Infinity; + for (let i = 0; i < N; ++i) { + if (D.entry(i, i) === Infinity) continue; + const dist = D.entry(i, d_min[i]); + if (dist < min_dist) { + min_dist = dist; + c1 = i; + } + } + if (c1 === -1) break; + + const c2 = d_min[c1]; + const c1_cluster = clusters[c1][0]; + const c2_cluster = clusters[c2][0]; + const c1_cluster_indices = c1_cluster.isLeaf ? [c1_cluster.index] : c1_cluster.index; + const c2_cluster_indices = c2_cluster.isLeaf ? [c2_cluster.index] : c2_cluster.index; + const indices = c1_cluster_indices.concat(c2_cluster_indices); + const new_cluster = new Cluster(this._id++, c1_cluster, c2_cluster, D.entry(c1, c2), null, indices); + c1_cluster.parent = new_cluster; + c2_cluster.parent = new_cluster; + clusters[c1].unshift(new_cluster); + + const size1 = c_size[c1]; + const size2 = c_size[c2]; + c_size[c1] += size2; + + for (let j = 0; j < N; ++j) { + if (j === c1 || j === c2 || D.entry(j, j) === Infinity) continue; + const D_c1_j = D.entry(c1, j); + const D_c2_j = D.entry(c2, j); + let value; + switch (linkage) { + case "single": + value = Math.min(D_c1_j, D_c2_j); + break; + case "complete": + value = Math.max(D_c1_j, D_c2_j); + break; + case "average": + value = (size1 * D_c1_j + size2 * D_c2_j) / (size1 + size2); + break; + } + D.set_entry(j, c1, value); + D.set_entry(c1, j, value); + } + + D.set_entry(c2, c2, Infinity); + for (let i = 0; i < N; ++i) { + D.set_entry(i, c2, Infinity); + D.set_entry(c2, i, Infinity); + } + + // Update d_min for all rows + for (let i = 0; i < N; i++) { + if (D.entry(i, i) === Infinity) continue; + if (d_min[i] === c1 || d_min[i] === c2 || i === c1) { + let min_j = 0; + let min_d = Infinity; + for (let j = 0; j < N; j++) { + if (i === j || D.entry(j, j) === Infinity) continue; + const d = D.entry(i, j); + if (d < min_d) { + min_d = d; + min_j = j; + } + } + d_min[i] = min_j; + } else { + if (D.entry(i, c1) < D.entry(i, d_min[i])) { + d_min[i] = c1; + } + } + } + + this.root = new_cluster; + } + } + + /** + * @param {number} value - Value where to cut the tree. + * @param {"distance" | "depth"} [type="distance"] - Type of value. Default is `"distance"` + * @returns {Cluster[][]} - Array of clusters with the indices of the rows in given points. + */ + get_clusters_raw(value, type = "distance") { + /** @type {Cluster[][]} */ + const clusters = []; + /** @type {(d: {dist: number, depth: number}) => number} */ + let accessor; + switch (type) { + case "distance": + accessor = (d) => d.dist; + break; + case "depth": + accessor = (d) => d.depth; + break; + default: + throw new Error("invalid type"); + } + this._traverse(/** @type {Cluster} */ (this.root), accessor, value, clusters); + return clusters; + } + + /** + * @param {number} value - Value where to cut the tree. + * @param {"distance" | "depth"} [type="distance"] - Type of value. Default is `"distance"` + * @returns {number[][]} - Array of clusters with the indices of the rows in given points. + */ + get_clusters(value, type = "distance") { + /** @type {Cluster[][]} */ + const clusters = []; + /** @type {(d: {dist: number, depth: number}) => number} */ + let accessor; + switch (type) { + case "distance": + accessor = (d) => d.dist; + break; + case "depth": + accessor = (d) => d.depth; + break; + default: + throw new Error("invalid type"); + } + if (this.root) this._traverse(this.root, accessor, value, clusters); + return clusters.map((cluster) => cluster.map((d) => d.index)); + } + + /** + * @param {number} value - Value where to cut the tree. + * @param {"distance" | "depth"} [type="distance"] - Type of value. Default is `"distance"` + * @returns {number[]} - Array of clusters with the indices of the rows in given points. + */ + get_cluster_list(value, type = "distance") { + const clusters = this.get_clusters(value, type); + /** @type {number[]} */ + const list = new Array(this._N).fill(0); + for (let i = 0; i < clusters.length; ++i) { + const cluster = clusters[i]; + for (let j = 0; j < cluster.length; ++j) { + const index = cluster[j]; + list[index] = i; + } + } + return list; + } + + /** + * @private + * @param {Cluster} node + * @param {(d: {dist: number, depth: number}) => number} f + * @param {number} value + * @param {Cluster[][]} result + */ + _traverse(node, f, value, result) { + if (f(node) <= value) { + result.push(node.leaves()); + } else { + if (node.left) this._traverse(node.left, f, value, result); + if (node.right) this._traverse(node.right, f, value, result); + } + } +} + +/** @private */ +class Cluster { + /**@type {number} */ + size; + /**@type {number} */ + depth; + /**@type {Cluster | null} */ + parent; + + /** + * + * @param {number} id + * @param {Cluster?} left + * @param {Cluster?} right + * @param {number} dist + * @param {Float64Array?} centroid + * @param {number} index + * @param {number} [size] + * @param {number} [depth] + */ + constructor(id, left, right, dist, centroid, index, size, depth) { + this.id = id; + this.left = left; + this.right = right; + this.dist = dist; + this.index = index; + if (size) { + this.size = size; + } else { + if (!left || !right) throw new Error("If size is not given, left & right cannot be null!"); + this.size = left.size + right.size; + } + + if (depth !== undefined) { + this.depth = depth; + } else { + if (!left || !right) throw new Error("If depth is not given, left & right cannot be null!"); + this.depth = Math.max(left.depth, right.depth) + 1; + } + + if (centroid !== undefined && centroid !== null) { + this.centroid = centroid; + } else { + if (!left || !right) throw new Error("If centroid is not given, left & right cannot be null!"); + + this.centroid = this._calculate_centroid(left, right); + } + + this.parent = null; + } + + /** + * + * @param {Cluster} left + * @param {Cluster} right + * @returns {Float64Array} + */ + _calculate_centroid(left, right) { + const l_size = left.size; + const r_size = right.size; + const l_centroid = left.centroid; + const r_centroid = right.centroid; + const size = this.size; + const n = left.centroid.length; + const new_centroid = new Float64Array(n); + for (let i = 0; i < n; ++i) { + new_centroid[i] = (l_size * l_centroid[i] + r_size * r_centroid[i]) / size; + } + return new_centroid; + } + + get isLeaf() { + return this.depth === 0; + } + + /** + * + * @returns {Cluster[]} + */ + leaves() { + if (this.isLeaf) return [this]; + const left = this.left; + const right = this.right; + return (left ? (left.isLeaf ? [left] : left.leaves()) : []).concat( + right ? (right.isLeaf ? [right] : right.leaves()) : [], + ); + } + + /** + * + * @returns {Cluster[]} + */ + descendants() { + if (this.isLeaf) return [this]; + const left_descendants = this.left ? this.left.descendants() : []; + const right_descendants = this.right ? this.right.descendants() : []; + return left_descendants.concat(right_descendants).concat([this]); + } +} + +/** + * @template T + * @typedef {Object} DisjointSetPayload + * @property {T} parent + * @property {Set} children + * @property {number} size + */ + +/** + * @template T + * @class + * @category Data Structures + * @see {@link https://en.wikipedia.org/wiki/Disjoint-set_data_structure} + */ +class DisjointSet { + /** + * @param {T[]?} elements + */ + constructor(elements = null) { + /** + * @private + * @type {Map>} + */ + this._list = new Map(); + if (elements) { + for (const e of elements) { + this.make_set(e); + } + } + } + + /** + * @private + * @param {T} x + * @returns {DisjointSet} + */ + make_set(x) { + const list = this._list; + if (!list.has(x)) { + list.set(x, { parent: x, children: new Set([x]), size: 1 }); + } + return this; + } + + /** + * @param {T} x + * @returns + */ + find(x) { + const list = this._list; + const disjoint_set = list.get(x); + if (disjoint_set) { + if (disjoint_set.parent !== x) { + disjoint_set.children.add(x); + const new_parent = this.find(disjoint_set.parent); + if (!new_parent) throw new Error("should not happen!"); + disjoint_set.parent = new_parent; + return disjoint_set.parent; + } else { + return x; + } + } else { + return null; + } + } + + /** + * @param {T} x + * @param {T} y + * @returns + */ + union(x, y) { + let node_x = this.find(x); + let node_y = this.find(y); + + if (!node_x || !node_y) throw new Error("x or y not found!"); + + let disjoint_set_x = this._list.get(node_x); + let disjoint_set_y = this._list.get(node_y); + + if (!disjoint_set_x || !disjoint_set_y) throw new Error("should not happen!"); + + if (node_x === node_y) return this; + if (disjoint_set_x.size < disjoint_set_y.size) { + [node_x, node_y] = [node_y, node_x]; + [disjoint_set_x, disjoint_set_y] = [disjoint_set_y, disjoint_set_x]; + } + + disjoint_set_y.parent = node_x; + // keep track of children + disjoint_set_y.children.forEach(disjoint_set_x.children.add, disjoint_set_x.children); + disjoint_set_x.size += disjoint_set_y.size; + + return this; + } + + /** @param {T} x */ + get_children(x) { + const node = this._list.get(x); + if (node) { + return node.children; + } else { + return null; + } + } +} + +/** @import { Comparator } from "./index.js" */ + +/** + * @template T + * @class + * @category Data Structures + */ +class Heap { + /** @type {{ element: T; value: number }[]} */ + _container; + + /** @type {Comparator} */ + _comparator; + + /** + * A heap is a datastructure holding its elements in a specific way, so that the top element would be the first + * entry of an ordered list. + * + * @param {T[]?} elements - Contains the elements for the Heap. `elements` can be null. + * @param {(d: T) => number} accessor - Function returns the value of the element. + * @param {"min" | "max" | Comparator} [comparator="min"] - Function returning true or false + * defining the wished order of the Heap, or String for predefined function. ("min" for a Min-Heap, "max" for a + * Max_heap). Default is `"min"` + * @see {@link https://en.wikipedia.org/wiki/Binary_heap} + */ + constructor(elements = null, accessor, comparator = "min") { + /** @type {(d: T) => number} */ + this._accessor = accessor; + this._container = []; + if (comparator === "min") { + this._comparator = (a, b) => a < b; + } else if (comparator === "max") { + this._comparator = (a, b) => a > b; + } else { + this._comparator = comparator; + } + if (elements) { + this._container = []; + for (const e of elements) { + this._container.push({ + element: e, + value: accessor(e), + }); + } + for (let i = Math.floor(elements.length / 2 - 1); i >= 0; --i) { + this._heapify_down(i); + } + } + } + + /** + * Creates a Heap from an Array + * + * @template T + * @param {T[]} elements - Contains the elements for the Heap. + * @param {(d: T) => number} accessor - Function returns the value of the element. + * @param {"min" | "max" | Comparator} [comparator="min"] - Function returning true or false + * defining the wished order of the Heap, or String for predefined function. ("min" for a Min-Heap, "max" for a + * Max_heap). Default is `"min"` + * @returns {Heap} + */ + static heapify(elements, accessor, comparator = "min") { + const heap = new Heap(null, accessor, comparator); + const container = heap._container; + for (const e of elements) { + container.push({ + element: e, + value: accessor(e), + }); + } + for (let i = Math.floor(elements.length / 2 - 1); i >= 0; --i) { + heap._heapify_down(i); + } + return heap; + } + + /** + * Swaps elements of container array. + * + * @private + * @param {number} index_a + * @param {number} index_b + */ + _swap(index_a, index_b) { + const container = this._container; + [container[index_b], container[index_a]] = [container[index_a], container[index_b]]; + return; + } + + /** @private */ + _heapify_up() { + const container = this._container; + let index = container.length - 1; + while (index > 0) { + const parentIndex = Math.floor((index - 1) / 2); + if (!this._comparator(container[index].value, container[parentIndex].value)) { + break; + } else { + this._swap(parentIndex, index); + index = parentIndex; + } + } + } + + /** + * Pushes the element to the heap. + * + * @param {T} element + * @returns {Heap} + */ + push(element) { + const value = this._accessor(element); + //const node = new Node(element, value); + const node = { element: element, value: value }; + this._container.push(node); + this._heapify_up(); + return this; + } + + /** + * @private + * @param {Number} [start_index=0] Default is `0` + */ + _heapify_down(start_index = 0) { + const container = this._container; + const comparator = this._comparator; + const length = container.length; + const left = 2 * start_index + 1; + const right = 2 * start_index + 2; + let index = start_index; + if (index >= length) throw "index higher than length"; + if (left < length && comparator(container[left].value, container[index].value)) { + index = left; + } + if (right < length && comparator(container[right].value, container[index].value)) { + index = right; + } + if (index !== start_index) { + this._swap(start_index, index); + this._heapify_down(index); + } + } + + /** + * Removes and returns the top entry of the heap. + * + * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by + * `accessor`}). + */ + pop() { + const container = this._container; + if (container.length === 0) { + return null; + } else if (container.length === 1) { + const item = container.pop(); + if (!item) throw new Error("Cannot happen!"); + return item; + } + this._swap(0, container.length - 1); + const item = container.pop(); + this._heapify_down(); + return item ?? null; + } + + /** + * Returns the top entry of the heap without removing it. + * + * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by + * `accessor`). + */ + get first() { + return this._container.length > 0 ? this._container[0] : null; + } + + /** + * Yields the raw data + * + * @yields {T} Object consists of the element and its value (computed by `accessor`}). + */ + *iterate() { + for (let i = 0, n = this._container.length; i < n; ++i) { + yield this._container[i].element; + } + } + + /** + * Returns the heap as ordered array. + * + * @returns {T[]} Array consisting the elements ordered by `comparator`. + */ + toArray() { + return this._container.sort((a, b) => (this._comparator(a.value, b.value) ? -1 : 1)).map((d) => d.element); + } + + /** + * Returns elements of container array. + * + * @returns {T[]} Array consisting the elements. + */ + data() { + return this._container.map((d) => d.element); + } + + /** + * Returns the container array. + * + * @returns {{ element: T; value: number }[]} The container array. + */ + raw_data() { + return this._container; + } + + /** + * The size of the heap. + * + * @returns {number} + */ + get length() { + return this._container.length; + } + + /** + * Returns false if the the heap has entries, true if the heap has no entries. + * + * @returns {boolean} + */ + get empty() { + return this.length === 0; + } +} + +/** @import { InputType } from "../index.js" */ +/** @import { ParametersKMeans } from "./index.js" */ +/** + * K-Means Clustering + * + * A popular clustering algorithm that partitions data into K clusters where each point + * belongs to the cluster with the nearest mean (centroid). + * + * @class + * @extends Clustering + * @category Clustering + * @see {@link KMedoids} for a more robust alternative + * + * @example + * import * as druid from "@saehrimnir/druidjs"; + * + * const points = [[1, 1], [1.5, 1.5], [5, 5], [5.5, 5.5]]; + * const kmeans = new druid.KMeans(points, { K: 2 }); + * + * const clusters = kmeans.get_cluster_list(); // [0, 0, 1, 1] + * const centroids = kmeans.centroids; // center points + */ +class KMeans extends Clustering { + /** + * @param {InputType} points + * @param {Partial} parameters + */ + constructor(points, parameters = {}) { + super( + points, + /** @type {ParametersKMeans} */ (Object.assign({ K: 4, metric: euclidean, seed: 1212 }, parameters)), + ); + + const K = this._parameters.K; + const seed = parameters.seed; + + // Convert points to Matrix if needed + if (points instanceof Matrix) { + this._matrix = points; + } else { + this._matrix = Matrix.from(points); + } + + const [N, D] = this._matrix.shape; + this._N = N; + this._D = D; + + this._K = K > N ? N : K; + this._randomizer = new Randomizer(seed); + + /** @type {number[]} */ + this._clusters = new Array(N).fill(0); + + this._cluster_centroids = parameters.initial_centroids + ? parameters.initial_centroids.map((c) => new Float64Array(c)) + : this._get_random_centroids(this._K); + let cluster_centroids = this._cluster_centroids; + let iterations = 0; + const max_iterations = 300; + let clusters_changed = true; + + while (clusters_changed && iterations < max_iterations) { + const iteration_result = this._iteration(cluster_centroids); + cluster_centroids = iteration_result.cluster_centroids; + clusters_changed = iteration_result.clusters_changed; + iterations++; + } + + this._cluster_centroids = cluster_centroids; + } + + /** @returns {number} The number of clusters */ + get k() { + return this._K; + } + + /** @returns {Float64Array[]} The cluster centroids */ + get centroids() { + return this._cluster_centroids; + } + + /** @returns {number[]} The cluster list */ + get_cluster_list() { + return this._clusters; + } + + /** @returns {number[][]} An Array of clusters with the indices of the points. */ + get_clusters() { + const K = this._K; + const clusters = this._clusters; + /** @type {number[][]} */ + const result = new Array(K).fill(0).map(() => []); + clusters.forEach((c, i) => { + if (c >= 0 && c < K) { + result[c].push(i); + } + }); + return result; + } + + /** + * @private + * @param {number[]} point_indices + * @param {number[]} candidates + * @returns {number} + */ + _furthest_point(point_indices, candidates) { + const A = this._matrix; + const metric = this._parameters.metric; + + if (point_indices.length === 0 || candidates.length === 0) { + return candidates[0] ?? 0; + } + + const H = Heap.heapify( + candidates, + (d) => { + const Ad = A.row(d); + let sum = 0; + for (let j = 0; j < point_indices.length; ++j) { + sum += metric(Ad, A.row(point_indices[j])); + } + return sum; + }, + "max", + ); + + const furthest = H.pop(); + if (!furthest) throw new Error("Should not happen!"); + + return furthest.element; + } + + /** + * @private + * @param {number} K + * @returns {Float64Array[]} + */ + _get_random_centroids(K) { + const N = this._N; + const randomizer = this._randomizer; + const A = this._matrix; + /** @type {Float64Array[]} */ + const cluster_centroids = new Array(K); + const indices = linspace(0, N - 1); + + // First centroid: random selection + const random_point = randomizer.random_int % N; + cluster_centroids[0] = A.row(random_point); + const init_points = [random_point]; + + const sample_size = Math.max(1, Math.floor((N - K) / K)); + + for (let i = 1; i < K; ++i) { + const remaining = indices.filter((d) => !init_points.includes(d)); + if (remaining.length === 0) break; + + const sample = randomizer.choice(remaining, Math.min(sample_size, remaining.length)); + const furthest_point = this._furthest_point(init_points, sample); + + init_points.push(furthest_point); + cluster_centroids[i] = A.row(furthest_point); + } + + return cluster_centroids; + } + + /** + * @private + * @param {Float64Array[]} cluster_centroids + * @returns {{ clusters_changed: boolean; cluster_centroids: Float64Array[] }} + */ + _iteration(cluster_centroids) { + const K = cluster_centroids.length; + const N = this._N; + const metric = this._parameters.metric; + const A = this._matrix; + const clusters = this._clusters; + let clusters_changed = false; + + // Find nearest cluster centroid for each point + for (let i = 0; i < N; ++i) { + const Ai = A.row(i); + let min_dist = Infinity; + let min_cluster = 0; + + for (let j = 0; j < K; ++j) { + const d = metric(cluster_centroids[j], Ai); + if (d < min_dist) { + min_dist = d; + min_cluster = j; + } + } + + if (clusters[i] !== min_cluster) { + clusters_changed = true; + clusters[i] = min_cluster; + } + } + + // Update cluster centroids + const new_centroids = this._compute_centroid(K); + + return { + clusters_changed: clusters_changed, + cluster_centroids: new_centroids, + }; + } + + /** + * @private + * @param {number} K + * @returns {Float64Array[]} + */ + _compute_centroid(K) { + const N = this._N; + const D = this._D; + const A = this._matrix; + const clusters = this._clusters; + + // Initialize new centroids and counters + /** @type {Float64Array[]} */ + const new_centroids = new Array(K); + const cluster_counter = new Array(K).fill(0); + + for (let i = 0; i < K; ++i) { + new_centroids[i] = new Float64Array(D); + } + + // Sum up all points in each cluster + for (let i = 0; i < N; ++i) { + const Ai = A.row(i); + const ci = clusters[i]; + if (ci >= 0 && ci < K) { + cluster_counter[ci]++; + const centroid = new_centroids[ci]; + for (let j = 0; j < D; ++j) { + centroid[j] += Ai[j]; + } + } + } + + // Divide by count to get mean + for (let i = 0; i < K; ++i) { + const n = cluster_counter[i]; + if (n > 0) { + const centroid = new_centroids[i]; + for (let j = 0; j < D; ++j) { + centroid[j] /= n; + } + } + } + + return new_centroids; + } +} + +/** @import {InputType} from "../index.js" */ +/** @import { ParametersKMedoids } from "./index.js" */ + +/** + * K-Medoids (PAM - Partitioning Around Medoids) + * + * A robust clustering algorithm similar to K-Means, but uses actual data points (medoids) + * as cluster centers and can work with any distance metric. + * + * @class + * @extends Clustering + * @category Clustering + * @see {@link KMeans} for a faster but less robust alternative + */ +class KMedoids extends Clustering { + /** + * @param {InputType} points - Data matrix + * @param {Partial} parameters + * @see {@link https://link.springer.com/chapter/10.1007/978-3-030-32047-8_16} Faster k-Medoids Clustering: Improving the PAM, CLARA, and CLARANS Algorithms + */ + constructor(points, parameters = {}) { + super(points, Object.assign({ K: 4, max_iter: null, metric: euclidean, seed: 1212 }, parameters)); + this._A = this._matrix.to2dArray(); + let K = this._parameters.K; + const N = this._N; + this._max_iter = this._parameters.max_iter ?? 10 * Math.log10(N); + this._distance_matrix = new Matrix(N, N, "zeros"); + + if (K > N) { + this._parameters.K = K = N; + } + this._randomizer = new Randomizer(this._parameters.seed); + this._clusters = new Array(N).fill(-1); + this._cluster_medoids = this._get_random_medoids(K); + this._is_initialized = false; + } + + /** @returns {number[]} The cluster list */ + get_cluster_list() { + if (!this._is_initialized) { + this.get_clusters(); + } + return this._clusters; + } + + /** @returns {number[][]} - Array of clusters with the indices of the rows in given points. */ + get_clusters() { + const K = this._parameters.K; + const A = this._A; + const N = this._N; + if (!this._is_initialized) { + this.init(K, this._cluster_medoids); + } + /** @type {number[][]} */ + const result = new Array(K).fill(0).map(() => []); + for (let j = 0; j < N; j++) { + const nearest = this._nearest_medoid(A[j], j); + const cluster_idx = nearest.index_nearest; + result[cluster_idx].push(j); + this._clusters[j] = cluster_idx; + } + return result; + } + + /** @returns {number} */ + get k() { + return this._parameters.K; + } + + /** @returns {number[]} */ + get medoids() { + return this.get_medoids(); + } + + /** @returns {number[]} */ + get_medoids() { + const K = this._parameters.K; + if (!this._is_initialized) { + this.init(K, this._cluster_medoids); + } + return this._cluster_medoids; + } + + async *generator() { + const max_iter = this._max_iter; + if (!this._is_initialized) { + this.get_clusters(); + } + yield this.get_clusters(); + let i = 0; + while (i < max_iter) { + const finish = this._iteration(); + this._update_clusters(); + yield this.get_clusters(); + if (finish) break; + i++; + } + } + + /** Algorithm 1. FastPAM1: Improved SWAP algorithm */ + /* _iteration_1() { + const A = this._A; + const N = this._N; + const K = this._K; + const medoids = this._cluster_medoids; + let DeltaTD = 0; + let m0 = null; + let x0 = null; + A.forEach((x_j, j) => { + if (medoids.findIndex(m => m === j) < 0) { + const nearest_medoid = this._nearest_medoid(x_j, j); + const d_j = nearest_medoid.distance_nearest; // distance to current medoid + const deltaTD = new Array(K).fill(-d_j); // change if making j a medoid + A.forEach((x_o, o) => { + // disance to new medoid + const d_oj = this._get_distance(o, j, x_o, x_j); + const { + "index_nearest": n, + "distance_nearest": d_n, + "distance_second": d_s, + } = this._nearest_medoid(x_o, o); + this._clusters[o] = n; // cached values + deltaTD[n] += Math.min(d_oj, d_s) - d_n; // loss change + if (d_oj < d_n) { // reassignment check + deltaTD.forEach((d_i, i) => { + if (n !== i) { + deltaTD[i] = d_i + d_oj - d_n; // update loss change + } + }); + } + }); + // choose best medoid i; + const i = deltaTD + .map((d, i) => [d, i]) + .sort((d1, d2) => d1[0] - d2[0])[0][1]; + const deltaTD_i = deltaTD[i]; + // store + if (deltaTD_i < DeltaTD) { + DeltaTD = deltaTD_i; + m0 = i; + x0 = j; + } + } + }); + + if (DeltaTD >= 0) { + return true // break loop if DeltaTD >= 0 + } + // swap roles of medoid m and non-medoid x; + medoids[m0] = x0; + this._cluster_medoids = medoids; + return false + } */ + + /** + * FastPAM1: One best swap per iteration + * @private + * @returns {boolean} + */ + _iteration() { + const A = this._A; + const K = this._parameters.K; + const medoids = this._cluster_medoids; + const N = this._N; + + // Precompute nearest and second nearest medoid for all points + const cache = new Array(N); + for (let i = 0; i < N; i++) { + cache[i] = this._nearest_medoid(A[i], i); + } + + let best_delta = 0; + let best_swap = null; // { m_idx: index in medoids, x_idx: index in A } + + // For each non-medoid point j, evaluate swapping it with each medoid i + const medoid_set = new Set(medoids); + for (let j = 0; j < N; j++) { + if (medoid_set.has(j)) continue; + + const x_j = A[j]; + const d_j = cache[j].distance_nearest; + + // deltaTD[i] will store the change in total distance if we swap medoid[i] with j + const deltaTD = new Array(K).fill(-d_j); + + for (let o = 0; o < N; o++) { + if (o === j) continue; + const dist_o_j = this._get_distance(o, j, A[o], x_j); + const { index_nearest: n, distance_nearest: d_n, distance_second: d_s } = cache[o]; + + // If o is assigned to the current medoid being swapped out (n) + deltaTD[n] += Math.min(dist_o_j, d_s) - d_n; + + // For all other medoids i != n, if j is closer to o than its current medoid + if (dist_o_j < d_n) { + for (let i = 0; i < K; i++) { + if (i !== n) { + deltaTD[i] += dist_o_j - d_n; + } + } + } + } + + // Find best medoid to swap with j + for (let i = 0; i < K; i++) { + if (deltaTD[i] < best_delta) { + best_delta = deltaTD[i]; + best_swap = { m_idx: i, x_idx: j }; + } + } + } + + if (best_swap && best_delta < 0) { + medoids[best_swap.m_idx] = best_swap.x_idx; + this._cluster_medoids = medoids; + return false; // not finished + } + + return true; // finished + } + + /** + * @private + * Get distance between two points + * @param {number} i + * @param {number} j + * @param {Float64Array?} x_i + * @param {Float64Array?} x_j + * @returns {number} + */ + _get_distance(i, j, x_i = null, x_j = null) { + if (i === j) return 0; + const D = this._distance_matrix; + const A = this._A; + const metric = this._parameters.metric; + let d_ij = D.entry(i, j); + if (d_ij === 0) { + d_ij = metric(x_i || A[i], x_j || A[j]); + D.set_entry(i, j, d_ij); + D.set_entry(j, i, d_ij); + } + return d_ij; + } + + /** + * @private + * @param {Float64Array} x_j + * @param {number} j + * @returns + */ + _nearest_medoid(x_j, j) { + const medoids = this._cluster_medoids; + const A = this._A; + if (medoids.length === 0) { + throw new Error("No medoids available. Initialization failed."); + } + + let d_n = Infinity; + let n = -1; + let d_s = Infinity; + let s = -1; + + for (let i = 0; i < medoids.length; i++) { + const m = medoids[i]; + const d = this._get_distance(j, m, x_j, A[m]); + if (d < d_n) { + d_s = d_n; + s = n; + d_n = d; + n = i; + } else if (d < d_s) { + d_s = d; + s = i; + } + } + + if (s === -1) s = n; + + return { + distance_nearest: d_n, + index_nearest: n, + distance_second: d_s, + index_second: s, + }; + } + + /** + * @private + */ + _update_clusters() { + const N = this._N; + const A = this._A; + for (let j = 0; j < N; j++) { + const nearest = this._nearest_medoid(A[j], j); + this._clusters[j] = nearest.index_nearest; + } + } + + /** + * Computes `K` clusters out of the `matrix`. + * @param {number} K - Number of clusters. + * @param {number[]} cluster_medoids + */ + init(K, cluster_medoids) { + if (!K) K = this._parameters.K; + if (!cluster_medoids) cluster_medoids = this._get_random_medoids(K); + this._cluster_medoids = cluster_medoids; + const max_iter = this._max_iter; + let finish = false; + let i = 0; + do { + finish = this._iteration(); + } while (!finish && ++i < max_iter); + this._update_clusters(); + this._is_initialized = true; + return this; + } + + /** + * Algorithm 3. FastPAM LAB: Linear Approximate BUILD initialization. + * @private + * @param {number} K - Number of clusters + * @returns {number[]} + */ + _get_random_medoids(K) { + const N = this._N; + const A = this._A; + const indices = linspace(0, N - 1); + const randomizer = this._randomizer; + const n = Math.min(N, 10 + Math.ceil(Math.sqrt(N))); + + // Handle case where K >= N + if (K >= N) { + return indices.slice(0, N); + } + + /** @type {number[]} */ + const medoids = []; + + // first medoid: select from a random sample of size n + let best_j = -1; + let min_td = Infinity; + let S = randomizer.choice(indices, n); + for (let j = 0; j < S.length; ++j) { + let td = 0; + const S_j = S[j]; + const x_j = A[S_j]; + for (let o = 0; o < S.length; ++o) { + if (o === j) continue; + td += this._get_distance(S_j, S[o], x_j, A[S[o]]); + } + if (td < min_td) { + min_td = td; + best_j = S_j; + } + } + medoids.push(best_j); + + // other medoids: greedy additive selection (Algorithm LAB) + for (let i = 1; i < K; ++i) { + let best_idx = -1; + let best_delta = Infinity; + + const remainingIndices = indices.filter((idx) => !medoids.includes(idx)); + if (remainingIndices.length === 0) break; + + S = randomizer.choice(remainingIndices, Math.min(n, remainingIndices.length)); + for (let j = 0; j < S.length; ++j) { + let deltaTD = 0; + const S_j = S[j]; + const x_j = A[S_j]; + + // Estimate TD reduction on the sample S + for (let o = 0; o < S.length; ++o) { + if (o === j) continue; + const S_o = S[o]; + const x_o = A[S_o]; + + // Closest distance to current medoids + let min_d_existing = Infinity; + for (let m = 0; m < medoids.length; m++) { + const d = this._get_distance(S_o, medoids[m], x_o, A[medoids[m]]); + if (d < min_d_existing) min_d_existing = d; + } + + const delta = this._get_distance(S_j, S_o, x_j, x_o) - min_d_existing; + if (delta < 0) { + deltaTD += delta; + } + } + + if (deltaTD < best_delta) { + best_delta = deltaTD; + best_idx = S_j; + } + } + if (best_idx !== -1) { + medoids.push(best_idx); + } + } + return medoids; + } +} + +/** @import { ParametersMeanShift } from "./index.js" */ +/** @import { InputType } from "../index.js" */ + +/** + * Mean Shift Clustering + * + * A non-parametric clustering technique that does not require prior knowledge of the + * number of clusters. It identifies centers of density in the data. + * + * @class + * @extends Clustering + * @category Clustering + */ +class MeanShift extends Clustering { + /** + * @private + * @type {number} + */ + _bandwidth; + /** + * @private + * @type {number} + */ + _max_iter; + /** + * @private + * @type {number} + */ + _tolerance; + /** + * @private + * @type {(dist: number) => number} + */ + _kernel; + /** + * @type {Matrix} + */ + _points; + /** + * @private + * @type {number[] | undefined} + */ + _clusters; + /** + * @private + * @type {number[][] | undefined} + */ + _cluster_list; + + /** + * + * @param {InputType} points + * @param {Partial} parameters + */ + constructor(points, parameters = {}) { + super( + points, + /** @type {ParametersMeanShift} */ ( + Object.assign({ seed: 1212, metric: euclidean, bandwidth: 0, kernel: "gaussian" }, parameters) + ), + ); + + // Ensure bandwidth is positive + this._bandwidth = parameters.bandwidth ?? this._compute_bandwidth(this._matrix); + this._max_iter = parameters.max_iter ?? Math.max(10, Math.floor(10 * Math.log10(this._N))); + this._tolerance = parameters.tolerance ?? 1e-3; + const kernel_param = parameters.kernel ?? "gaussian"; + // If kernel is a string, map to function + if (typeof kernel_param === "string") { + if (kernel_param === "flat") { + this._kernel = (dist) => (dist <= this._bandwidth ? 1 : 0); + } else { + // gaussian (default) + this._kernel = (dist) => Math.exp(-(dist * dist) / (2 * this._bandwidth * this._bandwidth)); + } + } else { + // custom function + this._kernel = kernel_param; + } + + // Copy points to a mutable matrix + this._points = this._matrix.clone(); + + this._mean_shift(); + this._assign_clusters(); + } + + /** + * Helper to compute bandwidth if not provided + * @private + * @param {Matrix} matrix + * @returns {number} + */ + _compute_bandwidth(matrix) { + const N = matrix.shape[0]; + //const D = matrix.shape[1]; + // Compute average pairwise distance + let totalDist = 0; + for (let i = 0; i < N; ++i) { + const row_i = matrix.row(i); + for (let j = i + 1; j < N; ++j) { + const row_j = matrix.row(j); + const dist = this._parameters.metric(row_i, row_j); + totalDist += dist; + } + } + const avgDist = totalDist / ((N * (N - 1)) / 2); + // Use a fraction of avgDist as bandwidth + return avgDist / 2; + } + + /** + * Compute kernel weight + * @private + * @param {number} dist + * @returns {number} + */ + _kernel_weight(dist) { + return this._kernel(dist); + } + + /** + * Perform mean shift iterations + * @private + */ + _mean_shift() { + const N = this._N; + const D = this._D; + const points = this._points; + const metric = this._parameters.metric; + //const bandwidth = this._bandwidth; + const kernel = this._kernel_weight.bind(this); + const tolerance = this._tolerance; + + for (let iter = 0; iter < this._max_iter; ++iter) { + let max_shift = 0; + // For each point compute shift + for (let i = 0; i < N; ++i) { + const row_i = points.row(i); + let sum_weights = 0; + const weighted_sum = new Float64Array(D); + for (let j = 0; j < N; ++j) { + const row_j = points.row(j); + const dist = metric(row_i, row_j); + const weight = kernel(dist); + sum_weights += weight; + for (let d = 0; d < D; ++d) { + weighted_sum[d] += weight * row_j[d]; + } + } + if (sum_weights === 0) { + // No neighbors within kernel, shift is zero + //const shift = new Float64Array(D); + // Compute shift magnitude + const shift_norm = Math.sqrt(weighted_sum.reduce((acc, v) => acc + v * v, 0)); + max_shift = Math.max(max_shift, shift_norm); + } else { + const shift = new Float64Array(D); + for (let d = 0; d < D; ++d) { + shift[d] = weighted_sum[d] / sum_weights - row_i[d]; + } + const shift_norm = Math.sqrt(shift.reduce((acc, v) => acc + v * v, 0)); + max_shift = Math.max(max_shift, shift_norm); + // Update point + for (let d = 0; d < D; ++d) { + row_i[d] += shift[d]; + } + } + } + if (max_shift < tolerance) { + // Converged + break; + } + } + } + + /** + * After convergence, assign clusters based on nearest mode + * @private + */ + _assign_clusters() { + const N = this._N; + const metric = this._parameters.metric; + const bandwidth = this._bandwidth; + + // Group points that converged to the same mode + // Two points are in the same mode if they're within bandwidth/2 of each other + const mode_threshold = bandwidth * 0.5; + /** @type {number[][]} */ + const modes = []; // Each mode contains indices of points in that mode + const point_to_mode = new Array(N).fill(-1); + + for (let i = 0; i < N; ++i) { + if (point_to_mode[i] !== -1) continue; // Already assigned to a mode + + const row_i = this._points.row(i); + const mode = [i]; + point_to_mode[i] = modes.length; + + // Find all points close to this mode + for (let j = i + 1; j < N; ++j) { + if (point_to_mode[j] !== -1) continue; + + const row_j = this._points.row(j); + const dist = metric(row_i, row_j); + + if (dist < mode_threshold) { + mode.push(j); + point_to_mode[j] = modes.length; + } + } + + modes.push(mode); + } + + // Build final clusters - each mode becomes a cluster + /** @type {number[][]} */ + const clusters = []; + const cluster_ids = new Array(N).fill(-1); + + for (let mode_idx = 0; mode_idx < modes.length; ++mode_idx) { + const mode = modes[mode_idx]; + clusters.push([...mode]); + for (const point_idx of mode) { + cluster_ids[point_idx] = mode_idx; + } + } + + this._clusters = cluster_ids; + this._cluster_list = clusters; + } + + /** + * @returns {number[][]} + */ + get_clusters() { + // Ensure algorithm has been run + if (!this._cluster_list) { + this._mean_shift(); + this._assign_clusters(); + } + return /** @type {number[][]} */ (this._cluster_list); + } + + /** + * + * @returns {number[]} + */ + get_cluster_list() { + if (!this._clusters) { + this._mean_shift(); + this._assign_clusters(); + } + return /** @type {number[]} */ (this._clusters); + } +} + +/** @import { InputType } from "../index.js" */ +/** @import { ParametersOptics } from "./index.js" */ + +/** @typedef {Object} DBEntry + * @property {Float64Array} element + * @property {number} index + * @property {number} [reachability_distance] + * @property {boolean} processed + * @property {DBEntry[]} [neighbors] + */ + +/** + * OPTICS (Ordering Points To Identify the Clustering Structure) + * + * A density-based clustering algorithm that extends DBSCAN. It handles clusters of varying + * densities and produces a reachability plot that can be used to extract clusters. + * + * @class + * @extends Clustering + * @category Clustering + */ +class OPTICS extends Clustering { + /** + * **O**rdering **P**oints **T**o **I**dentify the **C**lustering **S**tructure. + * + * @param {InputType} points - The data. + * @param {Partial} [parameters={}] + * @see {@link https://www.dbs.ifi.lmu.de/Publikationen/Papers/OPTICS.pdf} + * @see {@link https://en.wikipedia.org/wiki/OPTICS_algorithm} + */ + constructor(points, parameters = {}) { + super( + points, + /** @type {ParametersOptics} */ ( + Object.assign({ epsilon: 1, min_points: 4, metric: euclidean }, parameters) + ), + ); + const matrix = this._matrix; + /** + * @private + * @type {DBEntry[]} + */ + this._ordered_list = []; + const ordered_list = this._ordered_list; + /** @type {number[][]} */ + this._clusters = []; + const clusters = this._clusters; + + const N = this._N; + + /** + * @private + * @type {DBEntry[]} + */ + this._DB = new Array(N).fill(0).map((_, i) => { + return { + element: matrix.row(i), + index: i, + reachability_distance: undefined, + processed: false, + }; + }); + const DB = this._DB; + + this._cluster_index = 0; + let cluster_index = this._cluster_index; + + for (const p of DB) { + if (p.processed) continue; + p.neighbors = this._get_neighbors(p); + p.processed = true; + clusters.push([p.index]); + cluster_index = clusters.length - 1; + ordered_list.push(p); + if (this._core_distance(p) !== undefined) { + const seeds = new Heap(null, (d) => d.reachability_distance, "min"); + this._update(p, seeds); + this._expand_cluster(seeds, clusters[cluster_index]); + } + } + } + + /** + * @private + * @param {DBEntry} p - A point of the data. + * @returns {DBEntry[]} An array consisting of the `epsilon`-neighborhood of `p`. + */ + _get_neighbors(p) { + if (p?.neighbors) return p.neighbors; + const DB = this._DB; + const metric = this._parameters.metric; + const epsilon = this._parameters.epsilon; + const neighbors = []; + for (const q of DB) { + if (q.index === p.index) continue; + if (metric(p.element, q.element) <= epsilon) { + neighbors.push(q); + } + } + return neighbors; + } + + /** + * @private + * @param {DBEntry} p - A point of `matrix`. + * @returns {number|undefined} The distance to the `min_points`-th nearest point of `p`, or undefined if the + * `epsilon`-neighborhood has fewer elements than `min_points`. + */ + _core_distance(p) { + const min_points = this._parameters.min_points; + const metric = this._parameters.metric; + // Need min_points - 1 other points plus the point itself + if (!p.neighbors || p.neighbors.length < min_points - 1) { + return undefined; + } + // Sort neighbors by distance to find the MinPts-th closest + const sortedNeighbors = p.neighbors.toSorted( + (a, b) => metric(p.element, a.element) - metric(p.element, b.element), + ); + // MinPts-th closest is at index min_points - 2 (0-indexed, excluding p itself) + return metric(p.element, sortedNeighbors[min_points - 2].element); + } + + /** + * Updates the reachability distance of the points. + * + * @private + * @param {DBEntry} p + * @param {Heap} seeds + */ + _update(p, seeds) { + const metric = this._parameters.metric; + const core_distance = this._core_distance(p); + // If p is not a core point, don't update seeds + if (core_distance === undefined) { + return; + } + const neighbors = this._get_neighbors(p); //p.neighbors; + for (const q of neighbors) { + if (q.processed) continue; + const new_reachability_distance = Math.max(core_distance, metric(p.element, q.element)); + //if (q.reachability_distance == undefined) { // q is not in seeds + if (seeds.raw_data().findIndex((d) => d.element === q) < 0) { + q.reachability_distance = new_reachability_distance; + seeds.push(q); + } else { + // q is in seeds + if (new_reachability_distance < (q.reachability_distance ?? Infinity)) { + q.reachability_distance = new_reachability_distance; + seeds = Heap.heapify(seeds.data(), (d) => d.reachability_distance ?? Infinity, "min"); // seeds change key =/ + } + } + } + } + + /** + * Expands the `cluster` with points in `seeds`. + * + * @private + * @param {Heap} seeds + * @param {number[]} cluster + */ + _expand_cluster(seeds, cluster) { + const ordered_list = this._ordered_list; + while (!seeds.empty) { + const q = /** @type {{ element: DBEntry, value: number}} */ (seeds.pop()).element; + q.neighbors = this._get_neighbors(q); + q.processed = true; + cluster.push(q.index); + ordered_list.push(q); + if (this._core_distance(q) !== undefined) { + this._update(q, seeds); + // Recursive call removed - while loop handles iteration correctly + } + } + } + + /** + * Returns an array of clusters. + * + * @returns {number[][]} Array of clusters with the indices of the rows in given `matrix`. + */ + get_clusters() { + const clusters = []; + const outliers = []; + const min_points = this._parameters.min_points; + for (const cluster of this._clusters) { + if (cluster.length < min_points) { + outliers.push(...cluster); + } else { + clusters.push(cluster); + } + } + clusters.push(outliers); + return clusters; + } + + /** + * @returns {number[]} Returns an array, where the ith entry defines the cluster affirmation of the ith point of + * given data. (-1 stands for outlier) + */ + get_cluster_list() { + const N = this._matrix.shape[0]; + /** @type {number[]} */ + const result = new Array(N).fill(0); + const clusters = this.get_clusters(); + for (let i = 0, n = clusters.length; i < n; ++i) { + const cluster = clusters[i]; + for (const index of cluster) { + result[index] = i < n - 1 ? i : -1; + } + } + return result; + } +} + +/** @import { InputType } from "../index.js" */ +/** @import { ParametersXMeans } from "./index.js" */ + +/** + * @typedef SplitResult + * @property {number} index - Index of the cluster being split + * @property {number} bic_parent - BIC score of the parent cluster + * @property {number} bic_children - BIC score of the split children + * @property {number[][]} child_clusters - Clusters after splitting + * @property {Float64Array[]} child_centroids - Centroids of child clusters + */ + +/** + * @typedef CandidateResult + * @property {KMeans} kmeans - The KMeans instance for this K + * @property {number} score - BIC score + */ + +/** + * X-Means Clustering + * + * An extension of K-Means that automatically determines the number of clusters (K) + * using the Bayesian Information Criterion (BIC). + * + * @class + * @extends Clustering + * @category Clustering + */ +class XMeans extends Clustering { + /** + * XMeans clustering algorithm that automatically determines the optimal number of clusters. + * + * X-Means extends K-Means by starting with a minimum number of clusters and iteratively + * splitting clusters to improve the Bayesian Information Criterion (BIC). + * + * Algorithm: + * 1. Start with K_min clusters using KMeans + * 2. For each cluster, try splitting it into 2 sub-clusters + * 3. If BIC improves after splitting, keep the split + * 4. Run KMeans again with all (old + new) centroids + * 5. Repeat until K_max is reached or no more improvements + * + * @param {InputType} points - The data points to cluster + * @param {Partial} [parameters={}] - Configuration parameters + * @see {@link https://www.cs.cmu.edu/~dpelleg/download/xmeans.pdf} + * @see {@link https://github.com/annoviko/pyclustering/blob/master/pyclustering/cluster/xmeans.py} + * @see {@link https://github.com/haifengl/smile/blob/master/core/src/main/java/smile/clustering/XMeans.java} + */ + constructor(points, parameters = {}) { + const defaults = { + K_max: 10, + K_min: 2, + metric: euclidean, + seed: 1212, + min_cluster_size: 35, + tolerance: 0.001, + }; + super(points, /** @type {ParametersXMeans} */ (Object.assign(defaults, parameters))); + this._randomizer = new Randomizer(this._parameters.seed); + + /** @type {KMeans | null} */ + this._best_kmeans = null; + + // Run XMeans algorithm + this._run(); + } + + /** + * Run the XMeans algorithm + * + * @private + */ + _run() { + /** @type {Map} */ + const candidates = new Map(); + const A = this._matrix; + + // Initialize with K_min clusters + let current_kmeans = new KMeans(this._points, { + K: this._parameters.K_min, + metric: this._parameters.metric, + seed: this._parameters.seed, + }); + + let K = this._parameters.K_min; + + candidates.set(K, { + kmeans: current_kmeans, + score: -Infinity, + }); + + // Iteratively improve clustering + while (K < this._parameters.K_max) { + const clusters = current_kmeans.get_clusters(); + const centroids = current_kmeans.centroids; + + // Try splitting each cluster + /** @type {SplitResult[]} */ + const split_results = []; + + for (let j = 0; j < clusters.length; ++j) { + const cluster = clusters[j]; + + // Skip small clusters - need enough points for reliable BIC + if (cluster.length < this._parameters.min_cluster_size) { + continue; + } + + // Get subset data for this cluster + /** @type {number[][]} */ + const subset_points = cluster.map((idx) => { + const row = A.row(idx); + return Array.from(row); + }); + + // Calculate BIC for parent (single cluster) + const parent_bic = this._bic([cluster], [centroids[j]]); + + // Run KMeans with K=2 on subset + const subset_kmeans = new KMeans(subset_points, { + K: 2, + metric: this._parameters.metric, + seed: this._randomizer.seed, + }); + + const child_clusters_local = subset_kmeans.get_clusters(); + const child_centroids = subset_kmeans.centroids; + + // Map local indices back to global indices + /** @type {number[][]} */ + const child_clusters_global = child_clusters_local.map((local_cluster) => + local_cluster.map((local_idx) => cluster[local_idx]), + ); + + // Calculate BIC for children (split into 2 clusters) + const children_bic = this._bic(child_clusters_global, child_centroids); + + split_results.push({ + index: j, + bic_parent: parent_bic, + bic_children: children_bic, + child_clusters: child_clusters_global, + child_centroids: child_centroids, + }); + } + + // Keep all splits that improve BIC (BIC_children > BIC_parent) + /** @type {SplitResult[]} */ + const accepted_splits = split_results.filter((result) => result.bic_children > result.bic_parent); + + // If no splits improve BIC, we're done + if (accepted_splits.length === 0) { + break; + } + + // Build new centroids array: keep non-split centroids + add split centroids + /** @type {Float64Array[]} */ + const new_centroids = []; + const split_indices = new Set(); + + // Sort accepted splits by improvement (descending) + accepted_splits.sort((a, b) => b.bic_children - b.bic_parent - (a.bic_children - a.bic_parent)); + + for (const split of accepted_splits) { + if (centroids.length + split_indices.size + 1 <= this._parameters.K_max) { + split_indices.add(split.index); + } else { + break; + } + } + + for (let i = 0; i < centroids.length; ++i) { + if (split_indices.has(i)) { + // This cluster was split - add both child centroids + const split_result = accepted_splits.find((s) => s.index === i); + if (split_result) { + new_centroids.push(...split_result.child_centroids); + } + } else { + // This cluster wasn't split - keep its centroid + new_centroids.push(centroids[i]); + } + } + + // Run KMeans on full dataset with new centroids as initialization + // This is crucial - we need to reassign all points to all clusters + const newK = new_centroids.length; + + // Create a new KMeans instance with K set to new number of clusters + current_kmeans = new KMeans(this._matrix, { + K: newK, + metric: this._parameters.metric, + seed: this._randomizer.seed, + initial_centroids: new_centroids, + }); + + // Store the candidate with the BIC of the FULL dataset + candidates.set(newK, { + kmeans: current_kmeans, + score: this._bic(current_kmeans.get_clusters(), current_kmeans.centroids), + }); + + K = newK; + } + + // Select best candidate based on BIC score + this._best_kmeans = this._select_best_candidate(candidates); + } + + /** + * Select the best candidate based on BIC score + * + * @private + * @param {Map} candidates + * @returns {KMeans} + */ + _select_best_candidate(candidates) { + if (candidates.size === 0) { + throw new Error("No candidates found"); + } + + const first_candidate = candidates.get(this._parameters.K_min); + if (!first_candidate) { + throw new Error("Missing initial candidate"); + } + + let best_score = first_candidate.score; + /** @type {KMeans} */ + let best_kmeans = first_candidate.kmeans; + + for (const candidate of candidates.values()) { + if (candidate.score > best_score) { + best_score = candidate.score; + best_kmeans = candidate.kmeans; + } + } + + return best_kmeans; + } + + /** + * Calculate Bayesian Information Criterion for a set of clusters. + * + * Uses Kass's formula for BIC calculation: + * BIC(θ) = L(D) - 0.5 * p * ln(N) + * + * Where: + * - L(D) is the log-likelihood of the data + * - p is the number of free parameters: (K-1) + D*K + 1 + * - N is the total number of points + * + * @private + * @param {number[][]} clusters - Array of clusters with point indices + * @param {Float64Array[]} centroids - Array of centroids + * @returns {number} BIC score (higher is better) + */ + _bic(clusters, centroids) { + const A = this._matrix; + const D = this._D; + const K = centroids.length; + + let total_variance = 0; + let N = 0; + + // Calculate total variance (sum of squared distances) + for (let i = 0; i < K; ++i) { + const cluster = clusters[i]; + const centroid = centroids[i]; + N += cluster.length; + + for (let j = 0; j < cluster.length; ++j) { + const point_idx = cluster[j]; + const point = A.row(point_idx); + // Sum of squared distances (variance term) + total_variance += euclidean_squared(centroid, point); + } + } + + // Not enough points for meaningful BIC + if (N <= K) { + return -Infinity; + } + + // Estimate variance (ML estimate) + const variance = total_variance / (N - K); + + // Handle case of zero variance (all points identical) + if (variance <= 0) { + return -Infinity; + } + + // Number of free parameters: (K-1) cluster weights + K*D centroid coordinates + 1 variance + const p = K - 1 + D * K + 1; + + // Calculate log-likelihood + let log_likelihood = 0; + const log_2pi = Math.log(2 * Math.PI); + + for (let i = 0; i < K; ++i) { + const n = clusters[i].length; + if (n <= 1) continue; + + // Log-likelihood for cluster i + const cluster_log_likelihood = + n * Math.log(n / N) - 0.5 * n * log_2pi - 0.5 * n * D * Math.log(variance) - 0.5 * (n - 1); + + log_likelihood += cluster_log_likelihood; + } + + // BIC = log_likelihood - 0.5 * p * ln(N) + return log_likelihood - 0.5 * p * Math.log(N); + } + + /** + * Get the computed clusters + * + * @returns {number[][]} Array of clusters, each containing indices of points + */ + get_clusters() { + if (!this._best_kmeans) { + throw new Error("XMeans has not been run"); + } + return this._best_kmeans.get_clusters(); + } + + /** @returns {number[]} The cluster list */ + get_cluster_list() { + if (!this._best_kmeans) { + throw new Error("XMeans has not been run"); + } + return this._best_kmeans.get_cluster_list(); + } + + /** + * Get the final centroids + * + * @returns {Float64Array[]} Array of centroids + */ + get centroids() { + if (!this._best_kmeans) { + throw new Error("XMeans has not been run"); + } + return this._best_kmeans.centroids; + } + + /** + * Get the optimal number of clusters found + * + * @returns {number} The number of clusters + */ + get k() { + if (!this._best_kmeans) { + throw new Error("XMeans has not been run"); + } + return this._best_kmeans.k; + } +} + +/** @import {InputType} from "../index.js" */ + +/** + * @abstract + * @template {InputType} T + * @template {{ seed?: number }} Para + * + * Base class for all Dimensionality Reduction (DR) algorithms. + * + * Provides a common interface for parameters management, data initialization, + * and transformation (both synchronous and asynchronous). + * + * @class + */ +class DR { + /** @type {number} */ + _D; + /** @type {number} */ + _N; + /** @type {Randomizer} */ + _randomizer; + /** @type {boolean} */ + _is_initialized; + + /** + * Takes the default parameters and seals them, remembers the type of input `X`, and initializes the random number + * generator. + * + * @param {T} X - The high-dimensional data. + * @param {Para} default_parameters - Object containing default parameterization of the DR method. + * @param {Partial} parameters - Object containing parameterization of the DR method to override defaults. + */ + constructor(X, default_parameters, parameters = {}) { + /** @type {T} */ + this.__input = X; + + /** @type {Para} */ + this._parameters = /** @type {Para} */ Object.seal({ + ...default_parameters, + ...parameters, + }); + /** @type {"array" | "matrix" | "typed"} */ + this._type; + /** @type {Matrix} */ + this.X; + /** @type {Matrix} */ + this.Y; + + if (Array.isArray(X)) { + if (X[0] instanceof Float64Array) { + this._type = "typed"; + } else { + this._type = "array"; + } + this.X = Matrix.from(X); + } else if (X instanceof Matrix) { + this._type = "matrix"; + this.X = X; + } else { + throw new Error("No valid type for X!"); + } + const [N, D] = this.X.shape; + this._N = N; + this._D = D; + this._randomizer = new Randomizer(this._parameters.seed); + this._is_initialized = false; + } + + /** + * Get all Parameters. + * @overload + * @returns {Para} + */ + /** + * Get value of given parameter. + * @template {keyof Para} K + * @overload + * @param {K} name - Name of the parameter. + * @returns {Para[K]} + */ + /** + * Set value of given parameter. + * @template {keyof Para} K + * @overload + * @param {K} name - Name of the parameter. + * @param {Para[K]} value - Value of the parameter to set. + * @returns {this} + */ + /** + * @param {keyof Para} [name] - Name of the parameter. If null, returns all parameters as an Object. + * @param {Para[keyof Para]} [value] - Value of the parameter to set. If name is set and value is not given, returns the + * current value. + * @returns {Para | Para[keyof Para] | this} On setting a parameter, returns the DR object. If name is set and value is not + * given, returns the parameter value. If name is null, returns all parameters. On setting a parameter, this + * function returns the DR object. If `name` is set and `value == null` then return actual parameter value. If + * `name` is not given, then returns all parameters as an Object. + * @example + * ```js + * const DR = new druid.TSNE(X, {d: 3}); // creates a new DR object, with parameter for `d = 3`. + * DR.parameter("d"); // returns 3 + * DR.parameter("d", 2); // sets parameter `d` to 2 and returns `DR`. + * ``` + * + */ + parameter(name, value) { + if (name === undefined && value === undefined) { + return Object.assign({}, this._parameters); + } + if (name && !Object.hasOwn(this._parameters, name)) { + throw new Error(`${String(name)} is not a valid parameter!`); + } + if (name && value !== undefined) { + this._parameters[name] = value; + this._is_initialized = false; + return this; + } else if (name) { + return this._parameters[name]; + } + throw new Error("Should not happen!"); + } + + /** + * Computes the projection. + * + * @abstract + * @param {...unknown} args + * @returns {T} The projection. + */ + transform(...args) { + this.check_init(); + return this.projection; + } + + /** + * Computes the projection. + * + * @template {InputType} T + * @template {{ seed?: number }} Para + * @param {T} X + * @param {Para} parameters + * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method. + * @returns {T} The dimensionality reduced dataset. + */ + static transform(X, parameters, ...args) { + const dr = new DR(X, parameters, parameters); + return /** @type {T} */ (dr.transform()); + } + + /** + * Computes the projection. + * + * @abstract + * @param {...unknown} args + * @returns {Generator} The intermediate steps of the projection. + */ + *generator(...args) { + const R = this.transform(...args); + yield R; + return R; + } + + /** + * Computes the projection. + * + * @template {{ seed?: number }} Para + * @param {InputType} X + * @param {Para} parameters + * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method. + * @returns {Generator} A generator yielding the intermediate steps of the dimensionality + * reduction method. + */ + static *generator(X, parameters, ...args) { + const dr = new DR(X, parameters, parameters); + const generator = dr.generator(...args); + let result; + do { + result = generator.next(); + yield result.value; + } while (!result.done); + + return result.value; + } + + /** + * @abstract + * @param {...unknown} args + */ + init(...args) { + } + + /** + * If the respective DR method has an `init` function, call it before `transform`. + * + * @returns {DR} + */ + check_init() { + if (!this._is_initialized && typeof this.init === "function") { + this.init(); + this._is_initialized = true; + } + return this; + } + + /** @returns {T} The projection in the type of input `X`. */ + get projection() { + if (Object.hasOwn(this, "Y")) { + this.check_init(); + //return this._type === "matrix" ? this.Y : this.Y.to2dArray(); + if (this._type === "matrix") { + return /** @type {T} */ (/** @type {any} */ (this.Y)); + } else if (this._type === "typed") { + return /** @type {T} */ (/** @type {any} */ (this.Y.to2dArray())); + } else { + return /** @type {T} */ (/** @type {any} */ (this.Y.asArray())); + } + } else { + throw new Error("The dataset is not transformed yet!"); + } + } + + /** + * Computes the projection. + * + * @param {...unknown} args - Arguments the transform method of the respective DR method takes. + * @returns {Promise} The dimensionality reduced dataset. + */ + async transform_async(...args) { + return this.transform(...args); + } + + /** + * Computes the projection. + * + * @template {{ seed?: number }} Para + * @param {InputType} X + * @param {Para} parameters + * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method. + * @returns {Promise} A promise yielding the dimensionality reduced dataset. + */ + static async transform_async(X, parameters, ...args) { + return DR.transform(X, parameters, ...args); + } +} + +/** @import { InputType } from "../index.js" */ +/** @import { ParametersFASTMAP } from "./index.js"; */ + +/** + * FastMap algorithm for dimensionality reduction. + * + * A very fast algorithm for projecting high-dimensional data into a lower-dimensional + * space while preserving pairwise distances. It works similarly to PCA but uses + * only a subset of the data to find projection axes. + * + * @class + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction + */ +class FASTMAP extends DR { + /** + * FastMap: a fast algorithm for indexing, data-mining and visualization of traditional and multimedia datasets. + * @param {T} X - The high-dimensional data. + * @param {Partial} parameters - Object containing parameterization of the DR method. + * @see {@link https://doi.org/10.1145/223784.223812} + */ + constructor(X, parameters) { + super(X, { d: 2, metric: euclidean, seed: 1212 }, parameters); + } + + /** + * Chooses two points which are the most distant in the actual projection. + * + * @private + * @param {(a: number, b: number) => number} dist + * @returns {[number, number, number]} An array consisting of first index, second index, and distance between the + * two points. + */ + _choose_distant_objects(dist) { + const X = this.X; + const N = X.shape[0]; + let a_index = this._randomizer.random_int % N; + /** @type {number | null} */ + let b_index = null; + let max_dist = -Infinity; + for (let i = 0; i < N; ++i) { + const d_ai = dist(a_index, i); + if (d_ai > max_dist) { + max_dist = d_ai; + b_index = i; + } + } + if (b_index === null) throw new Error("should not happen!"); + max_dist = -Infinity; + for (let i = 0; i < N; ++i) { + const d_bi = dist(b_index, i); + if (d_bi > max_dist) { + max_dist = d_bi; + a_index = i; + } + } + return [a_index, b_index, max_dist]; + } + + /** + * Computes the projection. + * + * @returns {T} The `d`-dimensional projection of the data matrix `X`. + */ + transform() { + const X = this.X; + const N = X.shape[0]; + const d = /** @type {number} */ (this._parameters.d); + const metric = /** @type {typeof euclidean} */ (this._parameters.metric); + const Y = new Matrix(N, d, 0); + /** @type {(a: number, b: number) => number} */ + let dist = (a, b) => metric(X.row(a), X.row(b)); + + for (let _col = 0; _col < d; ++_col) { + const old_dist = dist; + // choose pivot objects + const [a_index, b_index, d_ab] = this._choose_distant_objects(dist); + if (d_ab !== 0) { + // project the objects on the line (O_a, O_b) + for (let i = 0; i < N; ++i) { + const d_ai = dist(a_index, i); + const d_bi = dist(b_index, i); + const y_i = (d_ai ** 2 + d_ab ** 2 - d_bi ** 2) / (2 * d_ab); + Y.set_entry(i, _col, y_i); + } + // consider the projections of the objects on a + // hyperplane perpendicluar to the line (a, b); + // the distance function D'() between two + // projections is given by Eq.4 + dist = (a, b) => Math.sqrt(old_dist(a, b) ** 2 - (Y.entry(a, _col) - Y.entry(b, _col)) ** 2); + } + } + // return embedding. + this.Y = Y; + return this.projection; + } + + *generator() { + yield this.transform(); + return this.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {T} + */ + static transform(X, parameters) { + const dr = new FASTMAP(X, parameters); + return dr.transform(); + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new FASTMAP(X, parameters); + yield* dr.generator(); + return dr.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new FASTMAP(X, parameters); + return dr.transform_async(); + } +} + +/** + * Base class for all K-Nearest Neighbors (KNN) search algorithms. + * + * Provides a common interface for elements management and search operations. + * + * @abstract + * @category KNN + * @template {number[] | Float64Array} T - Type of elements + * @template {Object} Para - Type of parameters + * @class + */ +class KNN { + /** @type {T[]} */ + _elements; + /** @type {Para} */ + _parameters; + /** @type {"typed" | "array"} */ + _type; + + /** + * @param {T[]} elements + * @param {Para} parameters + */ + constructor(elements, parameters) { + if (elements.length === 0) throw new Error("Elements needs to contain at least one element!"); + if (elements[0] instanceof Float64Array) { + this._type = "typed"; + } else { + this._type = "array"; + } + this._parameters = parameters; + this._elements = elements; + } + + /** + * @abstract + * @param {T} t + * @param {number} k + * @returns {{ element: T; index: number; distance: number }[]} + */ + search(t, k) { + throw new Error("The function search must be implemented!"); + } + + /** + * @abstract + * @param {number} i + * @param {number} k + * @returns {{ element: T; index: number; distance: number }[]} + */ + search_by_index(i, k) { + throw new Error("The function search_by_index must be implemented!"); + } +} + +/** @import { Metric } from "../metrics/index.js" */ +/** @import { ParametersAnnoy } from "./index.js" */ + +/** + * @template {number[] | Float64Array} T + * @typedef {Object} AnnoyNode + * @property {boolean} isLeaf - Whether this is a leaf node + * @property {number[]} indices - Indices of points in this node (leaf) or children (internal) + * @property {number[]} normal - Hyperplane normal vector (internal nodes only) + * @property {number} offset - Hyperplane offset (internal nodes only) + * @property {AnnoyNode | null} left - Left child (internal nodes only) + * @property {AnnoyNode | null} right - Right child (internal nodes only) + */ + +/** + * Annoy-style (Approximate Nearest Neighbors Oh Yeah) implementation using Random Projection Trees. + * + * This implementation builds multiple random projection trees where each tree randomly selects + * two points and splits the space based on a hyperplane equidistant between them. + * + * Key features: + * - Multiple random projection trees for better recall + * - Each tree uses random hyperplanes for splitting + * - Priority queue search for better recall + * - Combines results from all trees + * + * Best suited for: + * - High-dimensional data + * - Approximate nearest neighbor search + * - Large datasets + * - When high recall is needed with approximate methods + * + * @class + * @category KNN + * @template {number[] | Float64Array} T + * @extends KNN + * @see {@link https://github.com/spotify/annoy} + * @see {@link https://erikbern.com/2015/09/24/nearest-neighbors-and-vector-models-epilogue-curse-of-dimensionality.html} + */ +class Annoy extends KNN { + /** + * Creates a new Annoy-style index with random projection trees. + * + * @param {T[]} elements - Elements to index + * @param {ParametersAnnoy} [parameters={}] - Configuration parameters + */ + constructor( + elements, + parameters = { + metric: euclidean, + numTrees: 10, + maxPointsPerLeaf: 10, + seed: 1212, + }, + ) { + // Handle empty initialization - use dummy element + const hasElements = elements && elements.length > 0; + const firstElement = /** @type {T} */ (hasElements ? elements[0] : new Float64Array([0])); + + super([firstElement], parameters); + + this._metric = this._parameters.metric ?? euclidean; + this._numTrees = this._parameters.numTrees ?? 10; + this._maxPointsPerLeaf = this._parameters.maxPointsPerLeaf ?? 10; + this._seed = this._parameters.seed ?? 1212; + this._randomizer = new Randomizer(this._seed); + + /** + * @private + * @type {AnnoyNode[]} + */ + this._trees = []; + + // Build trees + if (hasElements) { + // Reset elements and rebuild properly + /** @type {T[]} */ + this._elements = []; + this._trees = []; + this.add(elements); + } + } + + /** + * Get the number of trees in the index. + * @returns {number} + */ + get num_trees() { + return this._trees.length; + } + + /** + * Get the total number of nodes in all trees. + * @returns {number} + */ + get num_nodes() { + let total = 0; + for (const tree of this._trees) { + total += this._countNodes(tree); + } + return total; + } + + /** + * @private + * @param {any} node + * @returns {number} + */ + _countNodes(node) { + if (!node) return 0; + return 1 + this._countNodes(node.left) + this._countNodes(node.right); + } + + /** + * Add elements to the Annoy index. + * @param {T[]} elements + * @returns {this} + */ + add(elements) { + // Extend elements array + this._elements = this._elements.concat(elements); + + // Rebuild all trees with new elements + this._trees = []; + this._buildTrees(); + + return this; + } + + /** + * Build all random projection trees. + * @private + */ + _buildTrees() { + const elements = this._elements; + const n = elements.length; + + for (let t = 0; t < this._numTrees; t++) { + // Create index array for this tree + const indices = Array.from({ length: n }, (_, i) => i); + const tree = this._buildTreeRecursive(indices); + this._trees.push(tree); + } + } + + /** + * Recursively build a random projection tree. + * @private + * @param {number[]} indices - Indices of elements to include + * @returns {AnnoyNode} + */ + _buildTreeRecursive(indices) { + const elements = this._elements; + + // Base case: small enough to be a leaf + if (indices.length <= this._maxPointsPerLeaf) { + return { + isLeaf: true, + indices: indices, + normal: [], + offset: 0, + left: null, + right: null, + }; + } + + // Select two random points to define the splitting hyperplane + const idx1 = indices[Math.floor(this._randomizer.random * indices.length)]; + const idx2 = indices[Math.floor(this._randomizer.random * indices.length)]; + + const point1 = elements[idx1]; + const point2 = elements[idx2]; + + // Compute normal vector (point2 - point1) + const dim = point1.length; + /** @type {number[]} */ + const normal = new Array(dim); + for (let i = 0; i < dim; i++) { + normal[i] = point2[i] - point1[i]; + } + + // Normalize + let norm = 0; + for (let i = 0; i < dim; i++) { + norm += normal[i] * normal[i]; + } + norm = Math.sqrt(norm); + + if (norm > 1e-10) { + for (let i = 0; i < dim; i++) { + normal[i] /= norm; + } + } + + // Compute midpoint and offset + /** @type {number[]} */ + const midpoint = new Array(dim); + for (let i = 0; i < dim; i++) { + midpoint[i] = (point1[i] + point2[i]) / 2; + } + + // Compute offset: dot(normal, midpoint) + let offset = 0; + for (let i = 0; i < dim; i++) { + offset += normal[i] * midpoint[i]; + } + + // Split points based on which side of hyperplane they fall + const leftIndices = []; + const rightIndices = []; + + for (const idx of indices) { + const point = elements[idx]; + let dot = 0; + for (let i = 0; i < dim; i++) { + dot += normal[i] * point[i]; + } + + if (dot < offset) { + leftIndices.push(idx); + } else { + rightIndices.push(idx); + } + } + + // Handle edge case where all points fall on one side + if (leftIndices.length === 0 || rightIndices.length === 0) { + return { + isLeaf: true, + indices: indices, + normal: [], + offset: 0, + left: null, + right: null, + }; + } + + // Recursively build subtrees + const left = this._buildTreeRecursive(leftIndices); + const right = this._buildTreeRecursive(rightIndices); + + return { + isLeaf: false, + indices: [], + normal: normal, + offset: offset, + left: left, + right: right, + }; + } + + /** + * Compute distance from point to hyperplane. + * @private + * @param {T} point + * @param {number[]} normal + * @param {number} offset + * @returns {number} Signed distance (positive = right side, negative = left side) + */ + _distanceToHyperplane(point, normal, offset) { + let dot = 0; + for (let i = 0; i < point.length; i++) { + dot += normal[i] * point[i]; + } + return dot - offset; + } + + /** + * Search for k approximate nearest neighbors. + * @param {T} query + * @param {number} [k=5] + * @returns {{ element: T; index: number; distance: number }[]} + */ + search(query, k = 5) { + const metric = this._metric; + const elements = this._elements; + + if (elements.length === 0) return []; + + // Collect candidates from all trees using priority queue + const candidates = new Set(); + + // Collect more candidates for better recall + // Search at least k * numTrees * 2 candidates + const minCandidates = Math.min(k * this._numTrees * 3, elements.length); + + for (const tree of this._trees) { + this._searchTreePriority(tree, query, candidates, minCandidates); + } + + // Compute exact distances for all candidates + /** @type {Heap<{ index: number; distance: number }>} */ + const best = new Heap(null, (d) => d.distance, "max"); + + for (const idx of candidates) { + const element = elements[idx]; + if (!element || element.length !== query.length) continue; + + const dist = metric(query, element); + + if (best.length < k) { + best.push({ index: idx, distance: dist }); + } else if (dist < (best.first?.value ?? Infinity)) { + best.pop(); + best.push({ index: idx, distance: dist }); + } + } + + // If we still don't have enough candidates, do a linear scan fallback + if (best.length < k) { + for (let i = 0; i < elements.length && best.length < k; i++) { + if (candidates.has(i)) continue; + + const element = elements[i]; + if (!element || element.length !== query.length) continue; + + const dist = metric(query, element); + best.push({ index: i, distance: dist }); + } + } + + // Convert to result format + /** @type {{ element: T; index: number; distance: number }[]} */ + const result = []; + while (best.length > 0) { + const item = /** @type {{ element: { index: number; distance: number }; value: number }} */ (best.pop()); + result.push({ + element: elements[item.element.index], + index: item.element.index, + distance: item.value, + }); + } + + return result.reverse(); + } + + /** + * Search tree using priority queue for better recall. + * Explores nodes in order of distance to hyperplane. + * @private + * @param {AnnoyNode} node + * @param {T} query + * @param {Set} candidates + * @param {number} maxCandidates + */ + _searchTreePriority(node, query, candidates, maxCandidates) { + if (!node) return; + + // Priority queue entry: { node, distance } + /** @type {Heap<{ node: AnnoyNode; dist: number }>} */ + const pq = new Heap(null, (d) => d.dist, "min"); + pq.push({ node: node, dist: 0 }); + + while (!pq.empty && candidates.size < maxCandidates) { + const entry = pq.pop(); + if (!entry) continue; + + const currentNode = entry.element.node; + + // Leaf node: add all points + if (currentNode.isLeaf) { + for (const idx of currentNode.indices) { + candidates.add(idx); + if (candidates.size >= maxCandidates) return; + } + continue; + } + + // Internal node: compute distance to hyperplane + const dist = this._distanceToHyperplane(query, currentNode.normal, currentNode.offset); + + // Determine which side is closer + const closerSide = dist < 0 ? currentNode.left : currentNode.right; + const fartherSide = dist < 0 ? currentNode.right : currentNode.left; + + // Add closer side with priority 0 (explore first) + if (closerSide) { + pq.push({ node: closerSide, dist: 0 }); + } + + // Add farther side with priority = |dist| (explore later if needed) + if (fartherSide && candidates.size < maxCandidates) { + pq.push({ node: fartherSide, dist: Math.abs(dist) }); + } + } + } + + /** + * @param {number} i + * @param {number} [k=5] + * @returns {{ element: T; index: number; distance: number }[]} + */ + search_by_index(i, k = 5) { + if (i < 0 || i >= this._elements.length) return []; + return this.search(this._elements[i], k); + } + + /** + * Alias for search_by_index for backward compatibility. + * + * @param {number} i - Index of the query element + * @param {number} [k=5] - Number of nearest neighbors to return + * @returns {{ element: T; index: number; distance: number }[]} + */ + search_index(i, k = 5) { + return this.search_by_index(i, k); + } +} + +/** @import { Metric } from "../metrics/index.js" */ +/** @import { ParametersBallTree } from "./index.js" */ + +/** + * @template {number[] | Float64Array} T + * @typedef {Object} ElementWithIndex + * @property {number} index + * @property {T} element + */ + +/** + * Ball Tree for efficient nearest neighbor search. + * + * A Ball Tree is a metric tree that partitions points into a nested set of + * hyperspheres (balls). It is particularly effective for high-dimensional + * data and supports any valid metric. + * + * @class + * @category KNN + * @template {number[] | Float64Array} T + * @extends KNN + */ +class BallTree extends KNN { + /** + * Generates a BallTree with given `elements`. + * + * @param {T[]} elements - Elements which should be added to the BallTree + * @param {ParametersBallTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}` + * @see {@link https://en.wikipedia.org/wiki/Ball_tree} + * @see {@link https://github.com/invisal/noobjs/blob/master/src/tree/BallTree.js} + */ + constructor(elements, parameters = { metric: euclidean, seed: 1212 }) { + super(elements, Object.assign({ seed: 1212 }, parameters)); + /** + * @private + * @type {BallTreeNode | BallTreeLeaf} + */ + this._root = this._construct(elements.map((element, index) => ({ index, element }))); + } + + /** @returns {Metric} */ + get _metric() { + return this._parameters.metric; + } + + /** + * @private + * @param {ElementWithIndex[]} elements + * @returns {BallTreeNode | BallTreeLeaf} Root of balltree. + */ + _construct(elements) { + if (elements.length === 1) { + return new BallTreeLeaf(elements); + } else { + const c = this._greatest_spread(elements); + const sorted_elements = elements.sort((a, b) => a.element[c] - b.element[c]); + const n = sorted_elements.length; + const p_index = Math.floor(n / 2); + const p = sorted_elements[p_index]; + const L = sorted_elements.slice(0, p_index); + const R = sorted_elements.slice(p_index, n); + const radius = Math.max(...elements.map((d) => this._metric(p.element, d.element))); + let B; + if (L.length > 0 && R.length > 0) { + B = new BallTreeNode(p, this._construct(L), this._construct(R), radius); + } else { + B = new BallTreeLeaf(elements); + } + return B; + } + } + + /** + * @private + * @param {ElementWithIndex[]} B + * @returns {number} + */ + _greatest_spread(B) { + const d = B[0].element.length; + const start = new Array(d); + + for (let i = 0; i < d; ++i) { + start[i] = [Infinity, -Infinity]; + } + + let spread = B.reduce((acc, current) => { + for (let i = 0; i < d; ++i) { + acc[i][0] = Math.min(acc[i][0], current.element[i]); + acc[i][1] = Math.max(acc[i][1], current.element[i]); + } + return acc; + }, start); + spread = spread.map((d) => d[1] - d[0]); + + let c = 0; + for (let i = 0; i < d; ++i) { + c = spread[i] > spread[c] ? i : c; + } + return c; + } + + /** + * @param {number} i + * @param {number} k + */ + search_by_index(i, k = 5) { + return this.search(this._elements[i], k); + } + + /** + * @param {T} t - Query element. + * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5` + * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors. + */ + search(t, k = 5) { + /** @type {Heap>} */ + const heap = new Heap(null, (d) => this._metric(d.element, t), "max"); + this._search(t, k, heap, this._root); + + // Convert heap to result array + /** @type {{ element: T; index: number; distance: number }[]} */ + const result = []; + while (heap.length > 0) { + const item = /** @type {{ element: ElementWithIndex; value: number }} */ (heap.pop()); + result.push({ + element: item.element.element, + index: item.element.index, + distance: item.value, + }); + } + return result.reverse(); // Reverse to get closest first + } + + /** + * @private + * @param {T} t - Query element. + * @param {number} k - Number of nearest neighbors to return. + * @param {Heap>} Q - Heap consists of the currently found `k` nearest neighbors. + * @param {BallTreeNode | BallTreeLeaf} B + */ + _search(t, k, Q, B) { + if (!B) return; + + if (B instanceof BallTreeNode) { + const dist_to_pivot = this._metric(t, B.pivot.element); + if (Q.length >= k && dist_to_pivot - B.radius >= (Q.first?.value ?? -Infinity)) { + return; + } + + const c1 = B.child1; + const c2 = B.child2; + + let d1 = Infinity; + let d2 = Infinity; + + if (c1 instanceof BallTreeNode) d1 = this._metric(t, c1.pivot.element); + else if (c1 instanceof BallTreeLeaf) d1 = this._metric(t, c1.points[0].element); + + if (c2 instanceof BallTreeNode) d2 = this._metric(t, c2.pivot.element); + else if (c2 instanceof BallTreeLeaf) d2 = this._metric(t, c2.points[0].element); + + if (d1 < d2) { + if (c1) this._search(t, k, Q, c1); + if (c2) this._search(t, k, Q, c2); + } else { + if (c2) this._search(t, k, Q, c2); + if (c1) this._search(t, k, Q, c1); + } + } else if (B instanceof BallTreeLeaf) { + for (let i = 0, n = B.points.length; i < n; ++i) { + const p = B.points[i]; + const dist = this._metric(p.element, t); + if (Q.length < k) { + Q.push(p); + } else if (dist < (Q.first?.value ?? Infinity)) { + Q.pop(); + Q.push(p); + } + } + } + } +} + +/** + * @private + * @template {number[] | Float64Array} T + */ +class BallTreeNode { + /** + * @param {ElementWithIndex} pivot + * @param {BallTreeNode | BallTreeLeaf | null} child1 + * @param {BallTreeNode | BallTreeLeaf | null} child2 + * @param {number} radius + */ + constructor(pivot, child1 = null, child2 = null, radius = 0) { + this.pivot = pivot; + this.child1 = child1; + this.child2 = child2; + this.radius = radius; + } +} + +/** + * @private + * @template {number[] | Float64Array} T + */ +class BallTreeLeaf { + /** @param {ElementWithIndex[]} points */ + constructor(points) { + this.points = points; + } +} + +/** @import { Metric } from "../metrics/index.js" */ +/** @import { ParametersHNSW } from "./index.js" */ + +/** + * @typedef {Object} Layer + * @property {number} l_c - Layer number + * @property {number[]} point_indices - Global indices of points in this layer + * @property {Map} edges - Global index -> array of connected global indices + */ + +/** + * @template {number[] | Float64Array} T + * @typedef {Object} Candidate + * @property {T} element - The actual data point + * @property {number} index - Global index in the dataset + * @property {number} distance - Distance from query + */ + +/** + * Hierarchical Navigable Small World (HNSW) graph for approximate nearest neighbor search. + * + * HNSW builds a multi-layer graph structure where each layer is a navigable small world graph. + * The top layers serve as "highways" for fast traversal, while lower layers provide accuracy. + * Each element is assigned to a random level, allowing logarithmic search complexity. + * + * Key parameters: + * - `m`: Controls the number of connections per element (affects accuracy/memory) + * - `ef_construction`: Controls the quality of the graph during construction (higher = better but slower) + * - `ef`: Controls the quality of search (higher = better recall but slower) + * + * Based on: + * - "Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs" + * by Malkov & Yashunin (2016) + * - "Approximate Nearest Neighbor Search on High Dimensional Data" + * by Li et al. (2019) + * + * @class + * @category KNN + * @template {number[] | Float64Array} T + * @extends KNN + * + * @example + * import * as druid from "@saehrimnir/druidjs"; + * + * const points = [[1, 2], [3, 4], [5, 6], [7, 8]]; + * const hnsw = new druid.HNSW(points, { + * metric: druid.euclidean, + * m: 16, + * ef_construction: 200 + * }); + * + * const query = [2, 3]; + * const neighbors = hnsw.search(query, 2); + * // [{ element: [1, 2], index: 0, distance: 1.41 }, ...] + */ +class HNSW extends KNN { + /** + * Creates a new HNSW index. + * + * @param {T[]} points - Initial points to add to the index + * @param {ParametersHNSW} [parameters={}] - Configuration parameters + */ + constructor( + points, + parameters = { + metric: euclidean, + heuristic: true, + m: 16, + ef_construction: 200, + m0: null, + mL: null, + seed: 1212, + ef: 50, + }, + ) { + // Handle empty initialization - use dummy element + const hasElements = points && points.length > 0; + let firstElement = /** @type {T} */ (hasElements ? points[0] : new Float64Array([0])); + + // Validate all points have consistent dimensions + if (hasElements) { + const expected_dim = firstElement.length; + for (let i = 1; i < points.length; i++) { + if (!points[i] || points[i].length !== expected_dim) { + console.warn( + `HNSW: Point ${i} has inconsistent dimensions (expected ${expected_dim}, got ${points[i]?.length})`, + ); + // Remove invalid points + points = points.filter((_, idx) => idx === 0 || points[idx]?.length === expected_dim); + firstElement = points[0]; + } + } + } + + super([firstElement], parameters); + + // Store reference to elements before clearing + const elementsToAdd = hasElements ? [...points] : []; + /** @type {T[]} */ + this._elements = []; + + /** @type {Metric} */ + this._metric = this._parameters.metric || euclidean; + + /** @type {Function} */ + this._select = this._parameters.heuristic ? this._select_heuristic.bind(this) : this._select_simple.bind(this); + + /** + * @private + * @type {Map} + */ + this._graph = new Map(); + + /** @type {number} */ + this._next_index = 0; + + // Validate and set parameters + const m_param = this._parameters.m ?? 16; + if (m_param <= 0 || !Number.isInteger(m_param)) { + throw new Error("HNSW: parameter 'm' must be a positive integer"); + } + /** @type {number} */ + this._m = Math.max(2, m_param); + + const ef_construction_param = this._parameters.ef_construction ?? 200; + if (ef_construction_param <= 0 || !Number.isInteger(ef_construction_param)) { + throw new Error("HNSW: parameter 'ef_construction' must be a positive integer"); + } + /** @type {number} */ + this._ef_construction = ef_construction_param; + + const ef_param = this._parameters.ef ?? 50; + if (ef_param <= 0 || !Number.isInteger(ef_param)) { + throw new Error("HNSW: parameter 'ef' must be a positive integer"); + } + /** @type {number} */ + this._ef = ef_param; + + const m0_param = this._parameters.m0 ?? 2 * this._m; + if (m0_param <= 0 || !Number.isInteger(m0_param)) { + throw new Error("HNSW: parameter 'm0' must be a positive integer"); + } + /** @type {number} */ + this._m0 = m0_param; + + /** @type {number} */ + this._mL = this._parameters.mL ?? 1 / Math.log(this._m); + + /** @type {Randomizer} */ + this._randomizer = new Randomizer(this._parameters.seed); + + /** @type {number} - Current maximum layer in the graph */ + this._L = -1; + + /** @type {number[] | null} - Entry point indices for search */ + this._ep = null; + + // Add initial points + if (elementsToAdd && elementsToAdd.length > 0) { + this.add(elementsToAdd); + } + } + + /** + * Add a single element to the index. + * + * @param {T} element - Element to add + * @returns {HNSW} This instance for chaining + */ + addOne(element) { + return this.add([element]); + } + + /** + * Add multiple elements to the index. + * + * @param {T[]} new_elements - Elements to add + * @returns {HNSW} This instance for chaining + */ + add(new_elements) { + // Handle empty array + if (!new_elements || new_elements.length === 0) { + return this; + } + + const m = this._m; + const ef_construction = this._ef_construction; + const m0 = this._m0; + const mL = this._mL; + const randomizer = this._randomizer; + const graph = this._graph; + + // Ensure _elements is a proper array that supports push + if (!Array.isArray(this._elements)) { + this._elements = Array.from(this._elements); + } + const elements = this._elements; + + // Get expected dimension from first existing element or first new element + const expected_dim = elements.length > 0 ? elements[0].length : new_elements[0]?.length; + + for (const element of new_elements) { + // Validate element + if (!element || (!Array.isArray(element) && !(element instanceof Float64Array))) { + console.warn("HNSW: Skipping invalid element (null, undefined, or not an array)"); + continue; + } + + // Validate dimensions + if (element.length !== expected_dim) { + console.warn( + `HNSW: Skipping element with wrong dimensions (expected ${expected_dim}, got ${element.length})`, + ); + continue; + } + + elements.push(element); + const global_index = elements.length - 1; + + // Assign random level to the element + // Level is drawn from exponential distribution: l = floor(-ln(uniform(0,1)) * mL) + const rand = Math.max(randomizer.random, 1e-10); // Avoid log(0) + const l = Math.min(31, Math.floor(-Math.log(rand) * mL)); + + let ep_indices = this._ep ? [...this._ep] : null; + const L = this._L; + + if (L >= 0) { + // Search from top layer down to min(L, l) + 1 + // These are the layers where element will NOT be inserted + for (let l_c = L; l_c > l; --l_c) { + const search_result = this._search_layer(element, ep_indices, 1, l_c); + if (search_result.length > 0) { + ep_indices = [search_result[0].index]; + } + } + + // Insert element into layers l down to 0 + for (let l_c = Math.min(L, l); l_c >= 0; --l_c) { + const layer = graph.get(l_c); + if (!layer) continue; + + layer.point_indices.push(global_index); + + // Search for ef_construction nearest neighbors + let W = this._search_layer(element, ep_indices, ef_construction, l_c); + + // If graph search returns no results (e.g., graph is empty or disconnected), + // fall back to linear search over all existing elements + if (W.length === 0 && elements.length > 1) { + const fallbackCandidates = []; + for (let i = 0; i < elements.length - 1; i++) { + const elem = elements[i]; + if (elem && elem.length === element.length) { + fallbackCandidates.push({ + element: elem, + index: i, + distance: this._metric(element, elem), + }); + } + } + fallbackCandidates.sort((a, b) => a.distance - b.distance); + W = fallbackCandidates.slice(0, ef_construction); + // Update ep_indices for next layer based on fallback results + if (l_c === Math.min(L, l)) { + ep_indices = W.map((c) => c.index); + } + } + + // Select neighbors using heuristic or simple approach (respect heuristic setting on all layers) + const neighbor_indices = this._select(element, W, l_c === 0 ? m0 : m, l_c); + + // Add bidirectional connections + for (const neighbor_idx of neighbor_indices) { + if (neighbor_idx === global_index) continue; + + // Add connection from element to neighbor + if (!layer.edges.has(global_index)) { + layer.edges.set(global_index, []); + } + layer.edges.get(global_index)?.push(neighbor_idx); + + // Add connection from neighbor to element + if (!layer.edges.has(neighbor_idx)) { + layer.edges.set(neighbor_idx, []); + } + const neighbor_edge_list = layer.edges.get(neighbor_idx); + if (neighbor_edge_list && !neighbor_edge_list.includes(global_index)) { + neighbor_edge_list.push(global_index); + } + + // Prune connections if too many + const max_conn = l_c === 0 ? m0 : m; + const neighbor_edges = layer.edges.get(neighbor_idx); + if (neighbor_edges && neighbor_edges.length > max_conn) { + const neighbor_element = elements[neighbor_idx]; + // Filter out self-connections before pruning + const valid_neighbor_edges = neighbor_edges.filter((idx) => idx !== neighbor_idx); + const neighbor_candidates = valid_neighbor_edges.map((idx) => ({ + element: elements[idx], + index: idx, + distance: this._metric(neighbor_element, elements[idx]), + })); + const pruned = + l_c === 0 + ? this._select_simple(neighbor_element, neighbor_candidates, max_conn) + : this._select(neighbor_element, neighbor_candidates, max_conn, l_c); + layer.edges.set(neighbor_idx, pruned); + } + } + + // Use closest neighbor as entry point for next layer (following HNSW paper) + if (W.length > 0) { + ep_indices = [W[0].index]; + } + } + } + + // If element's level is higher than current max, create new layers + if (l > L) { + for (let i = L + 1; i <= l; ++i) { + graph.set(i, { + l_c: i, + point_indices: [global_index], + edges: new Map(), + }); + } + // Element becomes the new entry point + this._ep = [global_index]; + this._L = l; + } + + // Special case: if this is the first element (L was -1), + // we need to ensure layer 0 has proper structure for future insertions + if (L === -1) { + if (!graph.has(0)) { + graph.set(0, { + l_c: 0, + point_indices: [global_index], + edges: new Map(), + }); + } + const layer0 = graph.get(0); + if (layer0 && !layer0.edges.has(global_index)) { + layer0.edges.set(global_index, []); + } + } + } + + return this; + } + + /** + * Select neighbors using the heuristic approach. + * + * The heuristic extends candidates with their neighbors and selects + * points that are closer to the query than to already selected points. + * This maintains graph connectivity better than simple selection. + * + * @private + * @param {T} q - Query element + * @param {Candidate[]} candidates - Candidate elements with distances + * @param {number} M - Maximum number of neighbors to return + * @param {number} l_c - Layer number + * @param {boolean} [extend_candidates=true] - Whether to extend candidates with their neighbors + * @param {boolean} [keep_pruned_connections=true] - Whether to add pruned connections back if needed + * @returns {number[]} Selected neighbor indices + */ + _select_heuristic(q, candidates, M, l_c, extend_candidates = true, keep_pruned_connections = true) { + if (l_c > this._L) { + return candidates.map((c) => c.index); + } + + const metric = this._metric; + const layer = this._graph.get(l_c); + const elements = this._elements; + + // Extend candidate set with neighbors of candidates + const W_set = new Set(candidates.map((c) => c.index)); + if (extend_candidates) { + for (const c of candidates) { + const edges = layer?.edges.get(c.index); + if (edges) { + for (const neighbor_idx of edges) { + W_set.add(neighbor_idx); + } + } + } + } + + // Create extended candidates with distances + const W = [...W_set] + .map((idx) => ({ + element: elements[idx], + index: idx, + distance: metric(elements[idx], q), + })) + .sort((a, b) => a.distance - b.distance); + + const R = []; + const W_discarded = []; + + // Select neighbors: prefer points closer to query than to already selected points + for (const e of W) { + if (R.length >= M) break; + + let should_add = true; + + // Check if e is closer to query than to any already selected point + for (const r of R) { + const dist_er = metric(e.element, r.element); + if (dist_er < e.distance) { + should_add = false; + break; + } + } + + if (should_add) { + R.push(e); + } else { + W_discarded.push(e); + } + } + + // Add discarded connections if we need more + if (keep_pruned_connections && R.length < M) { + for (const e of W_discarded) { + if (R.length >= M) break; + R.push(e); + } + } + + return R.map((c) => c.index); + } + + /** + * Select neighbors using simple distance-based selection. + * + * Simply returns the M closest candidates to the query. + * + * @private + * @param {T} q - Query element + * @param {Candidate[]} C - Candidate elements with distances + * @param {number} M - Maximum number of neighbors to return + * @returns {number[]} M nearest candidate indices + */ + _select_simple(q, C, M) { + if (C.length <= M) return C.map((c) => c.index); + + // Candidates already have distance computed, use it directly + return C.slice() + .sort((a, b) => a.distance - b.distance) + .slice(0, M) + .map((c) => c.index); + } + + /** + * Search a single layer for nearest neighbors. + * + * Implements the greedy search algorithm: start from entry points, + * always expand the closest unvisited candidate, maintain a list + * of the ef closest found neighbors. + * + * @private + * @param {T} q - Query element + * @param {number[] | null} ep_indices - Entry point indices + * @param {number} ef - Number of nearest neighbors to find + * @param {number} l_c - Layer number to search + * @returns {Candidate[]} ef nearest neighbors found with their distances + */ + _search_layer(q, ep_indices, ef, l_c) { + const metric = this._metric; + const layer = this._graph.get(l_c); + const elements = this._elements; + + if (!layer || layer.edges.size === 0 || !ep_indices || ep_indices.length === 0) { + return []; + } + + // Filter out invalid indices + const valid_ep_indices = ep_indices.filter((idx) => elements[idx] !== undefined); + if (valid_ep_indices.length === 0) { + return []; + } + + // Visited set to avoid cycles + const visited = new Set(valid_ep_indices); + + // Candidate set (min-heap): closest unvisited candidates to expand + const C = new Heap( + valid_ep_indices.map((idx) => ({ + element: elements[idx], + index: idx, + distance: metric(elements[idx], q), + })), + (item) => item.distance, + "min", + ); + + // Result set (max-heap): ef closest found neighbors + const W = new Heap( + valid_ep_indices.map((idx) => ({ + element: elements[idx], + index: idx, + distance: metric(elements[idx], q), + })), + (item) => item.distance, + "max", + ); + + // Algorithm 2 stops when the distance from query to the next candidate is greater + // than the distance to the furthest element in the result set W. + while (!C.empty) { + const c = C.pop(); + if (!c) break; + const furthest_dist = W.first?.value ?? Infinity; + + // Stop if current candidate is farther than furthest result + if (c.value > furthest_dist) { + break; + } + + const edges = layer.edges.get(c.element.index); + if (!edges) continue; + + for (const neighbor_idx of edges) { + if (!visited.has(neighbor_idx)) { + const neighbor_element = elements[neighbor_idx]; + // Skip invalid elements or elements with different dimensions + if (!neighbor_element || neighbor_element.length !== q.length) continue; + + // Skip self-connections + if (neighbor_idx === c.element.index) continue; + + visited.add(neighbor_idx); + const dist_e = metric(neighbor_element, q); + + const current_furthest = W.first?.value ?? Infinity; + if (dist_e < current_furthest || W.length < ef) { + C.push({ + element: neighbor_element, + index: neighbor_idx, + distance: dist_e, + }); + W.push({ + element: neighbor_element, + index: neighbor_idx, + distance: dist_e, + }); + + if (W.length > ef) { + W.pop(); + } + } + } + } + } + + // Return sorted results for consistent entry point selection + return W.data().sort((a, b) => a.distance - b.distance); + } + + /** + * Searches for the K nearest neighbors to a query element in the HNSW graph. + * + * Performs a multi-layer search starting from the entry point and traversing + * each layer as entry points for the next. + * + * @param {T} q - Query element + * @param {number} K - Number of nearest neighbors to return + * @returns {Candidate[]} K nearest neighbors with their distances + */ + search(q, K) { + // Validate K + if (!Number.isInteger(K) || K <= 0) { + throw new Error("HNSW: parameter 'K' must be a positive integer"); + } + + // Validate query dimensions + if (!q || (!Array.isArray(q) && !(q instanceof Float64Array))) { + throw new Error("HNSW: query must be an array"); + } + + const search_ef = this._ef; + + // Fallback to linear search if graph is not properly initialized + if (this._L < 0 || !this._ep || this._elements.length === 0) { + return this._linear_search(q, K); + } + + let ep_indices = [...this._ep]; + + // Search from top layer down to layer 1 + for (let l_c = this._L; l_c > 0; --l_c) { + const result = this._search_layer(q, ep_indices, 1, l_c); + if (result.length > 0) { + ep_indices = [result[0].index]; + } + } + + // Search layer 0 with ef candidates + const result = this._search_layer(q, ep_indices, Math.max(search_ef, K), 0); + + // If graph search returns no results, fallback to linear search + if (result.length === 0) { + return this._linear_search(q, K); + } + + // Return K closest + return result.slice(0, K); + } + + /** + * Fallback linear search when graph search fails + * @private + * @param {T} q - Query element + * @param {number} K - Number of nearest neighbors to return + * @returns {Candidate[]} + */ + _linear_search(q, K) { + const metric = this._metric; + const elements = this._elements; + const N = elements.length; + + if (N === 0) return []; + + /** @type {Candidate[]} */ + const candidates = []; + for (let i = 0; i < N; i++) { + const element = elements[i]; + // Skip elements with different dimensions (can happen with inconsistent data) + if (!element || element.length !== q.length) continue; + + candidates.push({ + element: element, + index: i, + distance: metric(q, element), + }); + } + + candidates.sort((a, b) => a.distance - b.distance); + return candidates.slice(0, K); + } + + /** + * Iterator for searching the HNSW graph layer by layer. + * + * Yields intermediate results at each layer for debugging or visualization. + * + * @param {T} q - Query element + * @param {number} K - Number of nearest neighbors to return + * @param {number?} [ef] - Size of dynamic candidate list + * @yields {{layer: number, candidates: Candidate[]}} + */ + *search_iter(q, K, ef = null) { + const search_ef = ef ?? this._ef; + + if (this._L < 0 || !this._ep) { + return; + } + + let ep_indices = [...this._ep]; + + // Yield entry points at top layer instead of query itself + const top_layer = this._graph.get(this._L); + if (top_layer && this._ep && this._ep.length > 0) { + const entry_candidates = this._ep + .filter((idx) => this._elements[idx] !== undefined) + .map((idx) => ({ + element: this._elements[idx], + index: idx, + distance: this._metric(this._elements[idx], q), + })); + yield { + layer: this._L, + candidates: entry_candidates, + }; + } + + for (let l_c = this._L; l_c > 0; --l_c) { + const result = this._search_layer(q, ep_indices, 1, l_c); + yield { layer: l_c, candidates: result }; + // Use closest candidate as entry point for next layer (following HNSW paper) + ep_indices = result.length > 0 ? [result[0].index] : ep_indices; + } + + const result = this._search_layer(q, ep_indices, Math.max(search_ef, K), 0); + yield { layer: 0, candidates: result }; + } + + /** + * Get the number of elements in the index. + * + * @returns {number} Number of elements + */ + get size() { + return this._elements?.length ?? 0; + } + + /** + * Get the number of layers in the graph. + * + * @returns {number} Number of layers + */ + get num_layers() { + return this._L + 1; + } + + /** + * Get an element by its index. + * + * @param {number} index - Element index + * @returns {T} The element at the given index + */ + get_element(index) { + return this._elements[index]; + } + + /** + * Search for nearest neighbors using an element index as the query. + * + * @param {number} i - Index of the query element + * @param {number} [K=5] - Number of nearest neighbors to return + * @returns {Candidate[]} K nearest neighbors + */ + search_by_index(i, K = 5) { + const elements = this._elements; + if (i < 0 || i >= elements.length) return []; + + const element = elements[i]; + if (!element) return []; + + return this.search(element, K); + } +} + +/** @import { Metric } from "../metrics/index.js" */ +/** @import { ParametersKDTree } from "./index.js" */ + +/** + * @template {number[] | Float64Array} T + * @typedef {Object} ElementWithIndex + * @property {number} index + * @property {T} element + */ + +/** + * KD-Tree (K-dimensional Tree) for efficient nearest neighbor search. + * + * KD-Trees partition k-dimensional space by recursively splitting along coordinate axes. + * At each level, the tree splits points based on the median of the coordinate with the largest spread. + * This creates a balanced binary tree structure that enables efficient O(log n) search on average. + * + * Best suited for: + * - Low to moderate dimensional data (d < 20-30) + * - When exact nearest neighbors are needed + * - When dimensionality is not too high + * + * Performance degrades in high dimensions (curse of dimensionality) where approximate + * methods like HNSW or LSH become more effective. + * + * @class + * @category KNN + * @template {number[] | Float64Array} T + * @extends KNN + * @see {@link https://en.wikipedia.org/wiki/K-d_tree} + */ +class KDTree extends KNN { + /** + * Generates a KD-Tree with given `elements`. + * + * @param {T[]} elements - Elements which should be added to the KD-Tree + * @param {ParametersKDTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}` + */ + constructor(elements, parameters = { metric: euclidean, seed: 1212 }) { + super(elements, Object.assign({ seed: 1212 }, parameters)); + /** + * @private + * @type {KDTreeNode | KDTreeLeaf | null} + */ + this._root = this._construct( + elements.map((element, index) => ({ index, element })), + 0, + ); + } + + /** @returns {Metric} */ + get _metric() { + return this._parameters.metric; + } + + /** + * @private + * @param {ElementWithIndex[]} elements + * @param {number} depth - Current depth in the tree (determines splitting axis) + * @returns {KDTreeNode | KDTreeLeaf | null} Root of KD-Tree. + */ + _construct(elements, depth) { + if (elements.length === 0) { + return null; + } + + if (elements.length === 1) { + return new KDTreeLeaf(elements[0]); + } + + const k = elements[0].element.length; + const axis = depth % k; + + // Sort by the splitting axis and find median + elements.sort((a, b) => a.element[axis] - b.element[axis]); + const medianIndex = Math.floor(elements.length / 2); + const medianPoint = elements[medianIndex]; + + // Recursively build left and right subtrees + const leftElements = elements.slice(0, medianIndex); + const rightElements = elements.slice(medianIndex + 1); + + const left = this._construct(leftElements, depth + 1); + const right = this._construct(rightElements, depth + 1); + + return new KDTreeNode(medianPoint, axis, left, right); + } + + /** + * @param {number} i + * @param {number} k + */ + search_by_index(i, k = 5) { + return this.search(this._elements[i], k); + } + + /** + * @param {T} t - Query element. + * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5` + * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors. + */ + search(t, k = 5) { + /** @type {Heap<{ point: ElementWithIndex; distance: number }>} */ + const best = new Heap(null, (d) => d.distance, "max"); + + this._search_recursive(t, k, this._root, best); + + // Convert heap to result array (closest first) + /** @type {{ element: T; index: number; distance: number }[]} */ + const result = []; + while (best.length > 0) { + const item = /** @type {{ element: { point: ElementWithIndex; distance: number }; value: number }} */ ( + best.pop() + ); + result.push({ + element: item.element.point.element, + index: item.element.point.index, + distance: item.value, + }); + } + return result.reverse(); + } + + /** + * @private + * @param {T} target - Query element. + * @param {number} k - Number of nearest neighbors to return. + * @param {KDTreeNode | KDTreeLeaf | null} node - Current node. + * @param {Heap<{ point: ElementWithIndex; distance: number }>} best - Heap of k best found so far. + */ + _search_recursive(target, k, node, best) { + if (node === null) return; + + if (node instanceof KDTreeLeaf) { + const dist = this._metric(target, node.point.element); + if (best.length < k) { + best.push({ point: node.point, distance: dist }); + } else if (dist < (best.first?.value ?? Infinity)) { + best.pop(); + best.push({ point: node.point, distance: dist }); + } + return; + } + + // Node is an internal node + const axis = node.axis; + const point = node.point; + const pointValue = point.element[axis]; + const targetValue = target[axis]; + + // Determine which subtree to search first + const firstSubtree = targetValue < pointValue ? node.left : node.right; + const secondSubtree = targetValue < pointValue ? node.right : node.left; + + // Search the nearer subtree + this._search_recursive(target, k, firstSubtree, best); + + // Check if we need to search the other subtree + // The hyperplane could contain closer points + const distToHyperplane = Math.abs(targetValue - pointValue); + const currentMaxDist = best.first?.value ?? Infinity; + + // Calculate distance to current point + const distToPoint = this._metric(target, point.element); + if (best.length < k) { + best.push({ point: point, distance: distToPoint }); + } else if (distToPoint < currentMaxDist) { + best.pop(); + best.push({ point: point, distance: distToPoint }); + } + + // Check if we need to explore the other side of the hyperplane + if (best.length < k || distToHyperplane < (best.first?.value ?? Infinity)) { + this._search_recursive(target, k, secondSubtree, best); + } + } +} + +/** + * @private + * @template {number[] | Float64Array} T + */ +class KDTreeNode { + /** + * @param {ElementWithIndex} point + * @param {number} axis - The splitting axis + * @param {KDTreeNode | KDTreeLeaf | null} left + * @param {KDTreeNode | KDTreeLeaf | null} right + */ + constructor(point, axis, left = null, right = null) { + this.point = point; + this.axis = axis; + this.left = left; + this.right = right; + } +} + +/** + * @private + * @template {number[] | Float64Array} T + */ +class KDTreeLeaf { + /** + * @param {ElementWithIndex} point + */ + constructor(point) { + this.point = point; + } +} + +/** @import { Metric } from "../metrics/index.js" */ +/** @import { ParametersLSH } from "./index.js" */ + +/** + * Locality Sensitive Hashing (LSH) for approximate nearest neighbor search. + * + * LSH uses hash functions that map similar items to the same buckets with high probability. + * This implementation uses Random Projection hashing (SimHash-style) which works well for + * cosine similarity and Euclidean distance. + * + * Key concepts: + * - Multiple hash tables increase recall probability + * - Each hash function projects data onto random hyperplanes + * - Points on the same side of hyperplanes are hashed together + * - Combines results from all tables for better accuracy + * + * Best suited for: + * - High-dimensional data where exact methods fail + * - Approximate nearest neighbor needs + * - Large datasets where linear scan is too slow + * - When some false positives/negatives are acceptable + * + * @class + * @category KNN + * @template {number[] | Float64Array} T + * @extends KNN + * @see {@link https://en.wikipedia.org/wiki/Locality-sensitive_hashing} + */ +class LSH extends KNN { + /** + * Creates a new LSH index. + * + * @param {T[]} elements - Elements to index + * @param {ParametersLSH} [parameters={}] - Configuration parameters + */ + constructor( + elements, + parameters = { + metric: euclidean, + numHashTables: 10, + numHashFunctions: 10, + seed: 1212, + }, + ) { + // Handle empty initialization - use dummy element + const hasElements = elements && elements.length > 0; + const firstElement = /** @type {T} */ (hasElements ? elements[0] : new Float64Array([0])); + + super([firstElement], parameters); + + this._metric = this._parameters.metric ?? euclidean; + this._numHashTables = this._parameters.numHashTables ?? 10; + this._numHashFunctions = this._parameters.numHashFunctions ?? 10; + this._seed = this._parameters.seed ?? 1212; + this._randomizer = new Randomizer(this._seed); + + // Hash tables: array of Maps where key is hash bucket, value is array of element indices + /** @type {Map[]} */ + this._hashTables = []; + + // Random projection vectors for each hash table and hash function + /** @type {Float64Array[][]} */ + this._projections = []; + + // Random offsets for each hash table and hash function (for quantization) + /** @type {number[][]} */ + this._offsets = []; + + // Store dimensionality for later + /** @type {number} */ + this._dim = firstElement.length; + + // Initialize hash functions + this._initializeHashFunctions(); + + // Reset elements if we were initialized with dummy + if (!hasElements) { + /** @type {T[]} */ + this._elements = []; + } else { + // Clear and re-add elements properly + /** @type {T[]} */ + this._elements = []; + this._hashTables = []; + this._projections = []; + this._offsets = []; + this._initializeHashFunctions(); + this.add(elements); + } + } + + /** + * Initialize random projection vectors for all hash tables. + * @private + */ + _initializeHashFunctions() { + const dim = this._elements[0]?.length ?? 0; + + for (let t = 0; t < this._numHashTables; t++) { + const tableProjections = []; + const tableOffsets = []; + + for (let h = 0; h < this._numHashFunctions; h++) { + // Generate random projection vector (normalized) + const projection = new Float64Array(dim); + let norm = 0; + for (let i = 0; i < dim; i++) { + // Box-Muller transform for normal distribution + const u1 = this._randomizer.random; + const u2 = this._randomizer.random; + const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2); + projection[i] = z; + norm += z * z; + } + // Normalize + norm = Math.sqrt(norm); + for (let i = 0; i < dim; i++) { + projection[i] /= norm; + } + + tableProjections.push(projection); + // Random offset for quantization buckets + tableOffsets.push(this._randomizer.random); + } + + this._projections.push(tableProjections); + this._offsets.push(tableOffsets); + this._hashTables.push(new Map()); + } + } + + /** + * Compute hash signature for an element using random projections. + * @private + * @param {T} element + * @param {number} tableIndex + * @returns {string} Hash signature + */ + _computeHash(element, tableIndex) { + const projections = this._projections[tableIndex]; + const offsets = this._offsets[tableIndex]; + const bits = []; + + for (let i = 0; i < this._numHashFunctions; i++) { + // Compute dot product + let dot = 0; + const proj = projections[i]; + for (let j = 0; j < element.length; j++) { + dot += element[j] * proj[j]; + } + // Quantize with offset + const bucket = Math.floor(dot + offsets[i]); + bits.push(bucket); + } + + return bits.join(","); + } + + /** + * Add elements to the LSH index. + * @param {T[]} elements + * @returns {this} + */ + add(elements) { + // Extend elements array + const startIndex = this._elements.length; + this._elements = this._elements.concat(elements); + + // Hash each new element and add to tables + for (let i = 0; i < elements.length; i++) { + const globalIndex = startIndex + i; + const element = elements[i]; + + for (let t = 0; t < this._numHashTables; t++) { + const hash = this._computeHash(element, t); + const table = this._hashTables[t]; + + if (!table.has(hash)) { + table.set(hash, []); + } + const bucket = table.get(hash); + if (bucket) { + bucket.push(globalIndex); + } + } + } + + return this; + } + + /** + * Search for k approximate nearest neighbors. + * @param {T} query + * @param {number} [k=5] + * @returns {{ element: T; index: number; distance: number }[]} + */ + search(query, k = 5) { + const metric = this._metric; + const elements = this._elements; + + if (elements.length === 0) return []; + + // Collect candidate indices from all hash tables + const candidates = new Set(); + + for (let t = 0; t < this._numHashTables; t++) { + const hash = this._computeHash(query, t); + const table = this._hashTables[t]; + const bucket = table.get(hash); + + if (bucket) { + for (const idx of bucket) { + if (idx !== undefined) { + candidates.add(idx); + } + } + } + } + + // If insufficient candidates found, fall back to linear search + if (candidates.size < k) { + // Add more candidates from all buckets or entire dataset + //const needed = k - candidates.size; + + // First, try to add from neighboring buckets (different hashes) + for (let t = 0; t < this._numHashTables && candidates.size < k; t++) { + const table = this._hashTables[t]; + for (const [, bucket] of table) { + for (const idx of bucket) { + if (idx !== undefined) { + candidates.add(idx); + if (candidates.size >= k) break; + } + } + if (candidates.size >= k) break; + } + } + + // If still not enough, add from entire dataset + for (let i = 0; i < elements.length && candidates.size < k; i++) { + candidates.add(i); + } + } + + // Compute exact distances for candidates + /** @type {Heap<{ index: number; distance: number }>} */ + const best = new Heap(null, (d) => d.distance, "max"); + + for (const idx of candidates) { + const element = elements[idx]; + if (!element || element.length !== query.length) continue; + + const dist = metric(query, element); + + if (best.length < k) { + best.push({ index: idx, distance: dist }); + } else if (dist < (best.first?.value ?? Infinity)) { + best.pop(); + best.push({ index: idx, distance: dist }); + } + } + + // Convert to result format + /** @type {{ element: T; index: number; distance: number }[]} */ + const result = []; + while (best.length > 0) { + const item = /** @type {{ element: { index: number; distance: number }; value: number }} */ (best.pop()); + result.push({ + element: elements[item.element.index], + index: item.element.index, + distance: item.value, + }); + } + + return result.reverse(); + } + + /** + * @param {number} i + * @param {number} [k=5] + * @returns {{ element: T; index: number; distance: number }[]} + */ + search_by_index(i, k = 5) { + if (i < 0 || i >= this._elements.length) return []; + return this.search(this._elements[i], k); + } +} + +/** @import { ParametersNaiveKNN } from "./index.js" */ + +/** + * Naive KNN implementation using a distance matrix. + * + * This implementation pre-computes the entire distance matrix and performs + * an exhaustive search. Best suited for small datasets or when a distance + * matrix is already available. + * + * @template {number[] | Float64Array} T + * @category KNN + * @class + * @extends KNN + */ +class NaiveKNN extends KNN { + /** + * Generates a KNN list with given `elements`. + * + * @param {T[]} elements - Elements which should be added to the KNN list + * @param {ParametersNaiveKNN} parameters + */ + constructor(elements, parameters = {}) { + const params = Object.assign({ metric: euclidean, seed: 1212 }, parameters); + super(elements, params); + const N = + this._elements instanceof Matrix ? /** @type {any} */ (this._elements).shape[0] : this._elements.length; + if (this._parameters.metric === "precomputed") { + this._D = Matrix.from(/** @type {number[][] | Float64Array[]} */ (/** @type {any} */ (this._elements))); + } else { + this._D = distance_matrix( + /** @type {number[][] | Float64Array[]} */ (this._elements), + this._parameters.metric, + ); + } + + /** @type {Heap<{ value: number; index: number }>[]} */ + this.KNN = []; + for (let row = 0; row < N; ++row) { + const distances = this._D.row(row); + /** @type {Heap<{ value: number; index: number }>} */ + const H = new Heap(null, (d) => d.value, "min"); + for (let j = 0; j < N; ++j) { + H.push({ + value: distances[j], + index: j, + }); + } + this.KNN.push(H); + } + } + + /** + * @param {number} i + * @param {number} k + */ + search_by_index(i, k = 5) { + if (this._parameters.metric === "precomputed") { + const H = this.KNN[i]; + /** @type {{ element: T; index: number; distance: number }[]} */ + const result = []; + const data = H.toArray(); // Get array representation + const temp_heap = new Heap(data, (d) => d.value, "min"); + const N = + this._elements instanceof Matrix ? /** @type {any} */ (this._elements).shape[0] : this._elements.length; + for (let j = 0; j < Math.min(k, N); ++j) { + const node = temp_heap.pop(); + if (!node) break; + result.push({ + element: /** @type {T} */ ( + this._elements instanceof Matrix + ? /** @type {any} */ (this._elements).row(node.element.index) + : this._elements[node.element.index] + ), + index: /** @type {number} */ (node.element.index), + distance: /** @type {number} */ (node.value), + }); + } + return result; + } + return this.search( + /** @type {T} */ ( + this._elements instanceof Matrix ? /** @type {any} */ (this._elements).row(i) : this._elements[i] + ), + k, + ); + } + + /** + * @param {T} t - Query element. + * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5` + * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors. + */ + search(t, k = 5) { + if (this._parameters.metric === "precomputed") { + throw new Error("Search by query element is only possible when not using a precomputed distance matrix!"); + } + /** @type {import("../metrics/index.js").Metric} */ + const metric = /** @type {any} */ (this._parameters.metric); + + const isMatrix = this._elements instanceof Matrix; + const elementsAny = /** @type {any} */ (this._elements); + const N = isMatrix ? elementsAny.shape[0] : this._elements.length; + + // Compute distances from query to ALL points + const distances = []; + for (let i = 0; i < N; i++) { + const element = /** @type {T} */ (isMatrix ? elementsAny.row(i) : this._elements[i]); + distances.push({ + element: element, + index: i, + distance: metric(t, element), + }); + } + + // Sort by distance and return k nearest + distances.sort((a, b) => a.distance - b.distance); + return distances.slice(0, k); + } +} + +/** @import {ParametersNNDescent} from "./index.js" */ +/** * - * @category Matrix - * @param {number[] | Float64Array} v - Vector - * @param {Metric} metric - * @returns {number[] | Float64Array} - The normalized vector with length 1. + * @template {number[] | Float64Array} T + * @typedef {Object} NNDescentElement + * @property {T} value + * @property {number} index + * @property {boolean} flag */ -function normalize(v, metric = euclidean) { - const v_norm = norm(v, metric); - return v.map((value) => value / v_norm); + +/** + * @template {number[] | Float64Array} T + * @typedef {Object} NNDescentNeighbor + * @property {T} value + * @property {number} index + * @property {number} distance + * @property {boolean} [flag] + */ + +/** + * NN-Descent + * + * An efficient graph-based approximate nearest neighbor search algorithm. + * It works by iteratively improving a neighbor graph using the fact that + * "neighbors of neighbors are likely to be neighbors". + * + * @class + * @category KNN + * @template {number[] | Float64Array} T + * @extends KNN + * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf|NN-Descent Paper} + */ +class NNDescent extends KNN { + /** + * @private + * @type {KNNHeap[]} + */ + _B = []; + /** + * @private + * @type {NNDescentNeighbor[][]} + */ + nn = []; + + /** + * @param {T[]} elements - Called V in paper. + * @param {Partial} parameters + * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf} + */ + constructor(elements, parameters = {}) { + super( + elements, + /** @type {ParametersNNDescent} */ ( + Object.assign({ metric: euclidean, K: 10, rho: 1, delta: 1e-3, seed: 1212 }, parameters) + ), + ); + this._N = elements.length; + this._randomizer = new Randomizer(this._parameters.seed); + this._sample_size = this._parameters.samples * this._parameters.rho; + + this._nndescent_elements = elements.map((e, i) => { + return { + value: e, + index: i, + flag: true, + }; + }); + + if (elements) { + this.add(elements); + } + } + + /** + * Samples Array A with sample size. + * + * @private + * @template U + * @param {U[]} A + * @returns {U[]} + */ + _sample(A) { + const n = A.length; + const sample_size = this._sample_size; + if (sample_size > n) { + return A; + } else { + const randomizer = this._randomizer; + return randomizer.choice(A, sample_size); + } + } + + /** + * @private + * @param {KNNHeap} B + * @param {NNDescentNeighbor} u + * @returns {number} + */ + _update(B, u) { + if (B.set.has(u.index)) return 0; + + const worst = B.first; + if (worst && B.length >= this._parameters.samples) { + const dist = B._accessor(u); + const worst_dist = B._accessor(worst.element); + if (dist >= worst_dist) { + return 0; // u is worse than the worst neighbor + } + } + + B.push(u); + u.flag = true; + if (B.length > this._parameters.samples) { + B.pop(); + } + return 1; + } + + /** + * @private + * @param {(KNNHeap | null)[]} B + * @returns {NNDescentNeighbor[][]} + */ + _reverse(B) { + const N = this._N; + const R = new Array(N); + for (let i = 0; i < N; i++) { + R[i] = []; + } + for (let j = 0; j < N; j++) { + const Bi = B[j]; + if (Bi) { + const Bjdata = Bi.data(); + for (const neighbor of Bjdata) { + const v = neighbor.index; + R[v].push(neighbor); + } + } + } + return R; + } + + /** + * @param {T[]} elements + * @returns {this} + */ + add(elements) { + const randomizer = this._randomizer; + const metric = this._parameters.metric; + const K = this._parameters.samples; + const delta = this._parameters.delta; + const N = elements.length; + this._N = N; + /** @type {KNNHeap[]} */ + const B = []; + this._B = B; + for (let i = 0; i < N; i++) { + const e = elements[i]; + const sample = randomizer + .choice( + elements.map((el, idx) => ({ el, idx })), + K, + ) + .map((d) => { + return { index: d.idx, distance: metric(d.el, e), value: d.el }; + }); + const Bi = new KNNHeap(sample, (d) => d.distance, "max"); + B.push(Bi); + } + + let c = Infinity; + let old_c = -Infinity; + while (c > delta * N * K && c !== old_c) { + const old_ = new Array(N); + const new_ = new Array(N); + for (let i = 0; i < N; i++) { + const Bi = B[i].data(); + const falseBs = Bi.filter((d) => !d.flag); + const trueBs = this._sample(Bi.filter((d) => d.flag)); + for (const d of trueBs) { + d.flag = false; + } + old_[i] = new KNNHeap(falseBs, (d) => d.distance, "max"); + new_[i] = new KNNHeap(trueBs, (d) => d.distance, "max"); + } + const old_reverse = this._reverse(old_); + const new_reverse = this._reverse(new_); + old_c = c; + c = 0; + for (let i = 0; i < N; i++) { + for (const o of this._sample(old_reverse[i])) { + old_[i].push(o); + } + for (const n of this._sample(new_reverse[i])) { + new_[i].push(n); + } + + const new_i = new_[i].data(); + const old_i = old_[i].data(); + const n1 = new_i.length; + const n2 = old_i.length; + for (let j = 0; j < n1; j++) { + const u1 = new_i[j]; + const Bu1 = B[u1.index]; + for (let k = 0; k < n1; k++) { + const u2 = new_i[k]; + if (u1.index === u2.index) continue; + const Bu2 = B[u2.index]; + c += this._update(Bu2, u1); + c += this._update(Bu1, u2); + } + for (let k = 0; k < n2; k++) { + const u2 = old_i[k]; + if (u1.index === u2.index) continue; + const Bu2 = B[u2.index]; + c += this._update(Bu2, u1); + c += this._update(Bu1, u2); + } + } + } + } + this.nn = this._B.map((heap) => heap.data()); + return this; + } + + /** + * @param {T} x + * @param {number} [k=5] Default is `5` + * @returns {{ element: T, index: number; distance: number }[]} + */ + search(x, k = 5) { + const metric = this._parameters.metric; + const N = this._N; + const elements = this._elements; + + if (N === 0) return []; + const xLength = x.length; + + // Initialize candidate pool + const visited = new Set(); + /** @type {{index: number, dist: number, evaluated: boolean}[]} */ + let pool = []; + + // Randomly pick initial candidates + const randomizer = this._randomizer; + for (let i = 0; i < Math.min(N, Math.max(k * 10, 50)); i++) { + let rnd; + do { + rnd = randomizer.random_int % N; + } while (visited.has(rnd)); + visited.add(rnd); + + const element = elements[rnd]; + if (!element || element.length !== xLength) continue; + + pool.push({ + index: rnd, + dist: metric(x, element), + evaluated: false, + }); + } + + let searching = true; + while (searching) { + pool.sort((a, b) => a.dist - b.dist); + // keep the top subset for exploration + pool = pool.slice(0, Math.max(k * 5, 50)); + + searching = false; + for (let i = 0; i < pool.length; i++) { + const candidate = pool[i]; + if (candidate.evaluated) continue; + + candidate.evaluated = true; + searching = true; + + // get neighbors of this candidate from graph + const neighbors = this.nn[candidate.index]; + if (!neighbors) continue; + + for (const neighbor of neighbors) { + const n_idx = neighbor.index; + if (!visited.has(n_idx)) { + visited.add(n_idx); + const element = elements[n_idx]; + if (element && element.length === xLength) { + pool.push({ + index: n_idx, + dist: metric(x, element), + evaluated: false, + }); + } + } + } + // Don't break here! Look at more candidates per iteration for better convergence + // break; + } + } + + pool.sort((a, b) => a.dist - b.dist); + + /** @type {{ element: T, index: number; distance: number }[]} */ + const result = []; + for (let i = 0; i < Math.min(k, pool.length); i++) { + const item = pool[i]; + result.push({ + element: elements[item.index], + index: item.index, + distance: item.dist, + }); + } + return result; + } + + /** + * @param {number} i + * @param {number} [k=5] Default is `5` + * @returns {{ element: T; index: number; distance: number }[]} + */ + search_by_index(i, k = 5) { + // Use regular search with the element at index i + const elements = this._elements; + if (i < 0 || i >= elements.length) return []; + + const element = elements[i]; + if (!element) return []; + + return this.search(element, k); + } +} + +/** + * @template {number[] | Float64Array} U + * @typedef {Object} HeapEntry + * @property {NNDescentNeighbor} element + * @property {number} value + */ + +/** + * @template {number[] | Float64Array} U + * @extends {Heap>} + */ +class KNNHeap extends Heap { + /** @type {Set} */ + set; + + /** + * @param {NNDescentNeighbor[]} elements + * @param {(d: NNDescentNeighbor) => number} accessor + * @param {"max" | "min"} comparator + */ + constructor(elements, accessor, comparator) { + super(null, accessor, comparator); + this.set = new Set(); + if (elements) { + for (const element of elements) { + this.push(element); + } + } + } + + /** + * @param {NNDescentNeighbor} element + * @returns {KNNHeap} + */ + push(element) { + const set = this.set; + if (set.has(element.index)) { + return this; + } else { + set.add(element.index); + super.push(element); + return this; + } + } + + /** @returns {{ element: NNDescentNeighbor; value: number } | null} */ + pop() { + const result = super.pop(); + if (result?.element) { + this.set.delete(result.element.index); + return result; + } + return null; + } + + /** @returns {NNDescentNeighbor[]} */ + data() { + return this._container.map((d) => d.element); + } +} + +/** @import {InputType} from "../index.js" */ +/** @import {ParametersPCA} from "./index.js" */ +/** @import {EigenArgs} from "../linear_algebra/index.js" */ + +/** + * Principal Component Analysis (PCA) + * + * A linear dimensionality reduction technique that identifies the axes (principal components) + * along which the variance of the data is maximized. + * + * @class + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction + * @see {@link MDS} for another linear alternative + * + * @example + * import * as druid from "@saehrimnir/druidjs"; + * + * const X = [[1, 2], [3, 4], [5, 6]]; + * const pca = new druid.PCA(X, { d: 2 }); + * const Y = pca.transform(); + * // [[x1, y1], [x2, y2], [x3, y3]] + */ +class PCA extends DR { + /** + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + */ + constructor(X, parameters = {}) { + super(X, { d: 2, seed: 1212, eig_args: {} }, parameters); + const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); + if (!Object.hasOwn(eig_args, "seed")) { + eig_args.seed = this._randomizer; + } + } + + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + *generator() { + yield this.transform(); + return this.projection; + } + + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {T} - The projected data. + */ + transform() { + const V = this.principal_components(); + const X = this.X; + this.Y = X.dot(V); + return this.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {T} + */ + static transform(X, parameters) { + const dr = new PCA(X, parameters); + return dr.transform(); + } + + /** + * Computes the `d` principal components of Matrix `X`. + * + * @returns {Matrix} + */ + principal_components() { + if (this.V) { + return this.V; + } + const d = /** @type {number} */ (this.parameter("d")); + const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); + const X = this.X; + const X_cent = X.sub(X.meanCols()); + const C = X_cent.transDot(X_cent); + const { eigenvectors: V } = simultaneous_poweriteration(C, d, eig_args); + this.V = Matrix.from(V).transpose(); + return this.V; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Matrix} + */ + static principal_components(X, parameters) { + const dr = new PCA(X, parameters); + return dr.principal_components(); + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new PCA(X, parameters); + yield* dr.generator(); + return dr.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new PCA(X, parameters); + return dr.transform_async(); + } +} + +/** @import {InputType} from "../index.js" */ +/** @import {Metric} from "../metrics/index.js" */ +/** @import {ParametersPaCMAP} from "./index.js" */ + +/** + * Pairwise Controlled Manifold Approximation Projection (PaCMAP) + * + * A dimensionality reduction technique that uses three types of point pairs — + * nearest neighbor (NN), mid-near (MN), and further (FP) pairs — with a + * dynamic three-phase weight schedule and Adam optimization to preserve both + * local and global structure. + * + * @class + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction + * @see {@link https://arxiv.org/abs/2012.04456|PaCMAP Paper} + * @see {@link https://github.com/YingfanWang/PaCMAP|PaCMAP GitHub} + * @see {@link UMAP} for a related graph-based technique + * @see {@link LocalMAP} for the local-refinement variant + * + * @example + * import * as druid from "@saehrimnir/druidjs"; + * + * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]; + * const pacmap = new druid.PaCMAP(X, { + * n_neighbors: 10, + * MN_ratio: 0.5, + * FP_ratio: 2.0, + * seed: 42 + * }); + * + * const Y = pacmap.transform(); // 450 iterations (default) + * // [[x1, y1], [x2, y2], [x3, y3]] + */ +class PaCMAP extends DR { + /** + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + */ + constructor(X, parameters) { + super( + X, + { + n_neighbors: 10, + MN_ratio: 0.5, + FP_ratio: 2.0, + d: 2, + metric: euclidean, + lr: 1.0, + num_iters: [100, 100, 250], + seed: 1212, + }, + parameters, + ); + [this._N, this._D] = this.X.shape; + const n_neighbors = /** @type {number} */ (this.parameter("n_neighbors")); + if (n_neighbors >= this._N) { + throw new Error( + `Parameter n_neighbors (=${n_neighbors}) needs to be smaller than dataset size (N=${this._N})!`, + ); + } + this._iter = 0; + } + + /** + * Samples mid-near pairs for each point. + * For each point i, repeats n_MN times: samples 6 random non-neighbor + * candidates, picks the 2nd closest by high-dim distance. + * + * @protected + * @param {Set[]} nn_sets - Array of neighbor index sets per point + * @param {number} n_MN - Number of mid-near pairs per point + * @returns {Int32Array} Flat array of [i, j] pairs + */ + _sample_mn_pairs(nn_sets, n_MN) { + const N = this._N; + const X = this.X; + const randomizer = this._randomizer; + const pairs = new Int32Array(N * n_MN * 2); + let idx = 0; + + for (let i = 0; i < N; ++i) { + const nn_set = nn_sets[i]; + const x_i = X.row(i); + + for (let k = 0; k < n_MN; ++k) { + // Sample 6 random non-neighbor candidates + /** @type {{idx: number, dist: number}[]} */ + const candidates = []; + let attempts = 0; + while (candidates.length < 6 && attempts < N * 2) { + const j = randomizer.random_int % N; + attempts++; + if (j !== i && !nn_set.has(j)) { + candidates.push({ idx: j, dist: euclidean_squared(x_i, X.row(j)) }); + } + } + if (candidates.length < 2) { + // Fallback: use any available non-self point + const j = (i + 1) % N; + pairs[idx++] = i; + pairs[idx++] = j; + continue; + } + candidates.sort((a, b) => a.dist - b.dist); + // Pick the 2nd closest (index 1) + pairs[idx++] = i; + pairs[idx++] = candidates[1].idx; + } + } + return pairs.slice(0, idx); + } + + /** + * Samples further pairs for each point (random non-neighbors). + * + * @protected + * @param {Set[]} nn_sets - Array of neighbor index sets per point + * @param {number} n_FP - Number of further pairs per point + * @returns {Int32Array} Flat array of [i, j] pairs + */ + _sample_fp_pairs(nn_sets, n_FP) { + const N = this._N; + const randomizer = this._randomizer; + const pairs = new Int32Array(N * n_FP * 2); + let idx = 0; + + for (let i = 0; i < N; ++i) { + const nn_set = nn_sets[i]; + let count = 0; + let attempts = 0; + while (count < n_FP && attempts < N * 3) { + const j = randomizer.random_int % N; + attempts++; + if (j !== i && !nn_set.has(j)) { + pairs[idx++] = i; + pairs[idx++] = j; + count++; + } + } + } + return pairs.slice(0, idx); + } + + /** + * Computes gradient coefficients and updates the gradient matrix for one pair type. + * + * @protected + * @param {Float64Array} grad_flat - Flat N×d gradient accumulator (modified in place) + * @param {Int32Array} pairs - Flat [i, j, i, j, ...] pair array + * @param {number} w - Weight for this pair type + * @param {number} attr_num - Numerator constant for attractive (10 for NN, 10000 for MN); 0 for repulsive + * @param {boolean} repulsive - Whether this is a repulsive pair type + */ + _accumulate_gradients(grad_flat, pairs, w, attr_num, repulsive) { + if (w === 0) return; + const Y = this.Y; + const d = /** @type {number} */ (this.parameter("d")); + const n_pairs = pairs.length / 2; + + for (let p = 0; p < n_pairs; ++p) { + const i = pairs[p * 2]; + const j = pairs[p * 2 + 1]; + const y_i = Y.row(i); + const y_j = Y.row(j); + + // d_ij = 1 + ||y_i - y_j||² + let sq_dist = 0; + for (let k = 0; k < d; ++k) { + const diff = y_i[k] - y_j[k]; + sq_dist += diff * diff; + } + const d_ij = 1 + sq_dist; + + /** @type {number} */ + let coeff; + if (repulsive) { + // FP loss: 1/(1+d_ij), gradient: -2/(1+d_ij)² + coeff = (-w * 2) / (d_ij * d_ij); + } else { + // NN loss: d_ij/(attr_num+d_ij), gradient: 2*attr_num/(attr_num+d_ij)² + const denom = attr_num + d_ij; + coeff = (w * 2 * attr_num) / (denom * denom); + } + + const base_i = i * d; + const base_j = j * d; + for (let k = 0; k < d; ++k) { + const diff = y_i[k] - y_j[k]; + const g = coeff * diff; + grad_flat[base_i + k] += g; + grad_flat[base_j + k] -= g; + } + } + } + + /** + * Returns the weight schedule for the current iteration. + * + * @protected + * @param {number} iter - Current iteration (0-indexed) + * @returns {{ w_nn: number; w_mn: number; w_fp: number }} + */ + _get_weights(iter) { + const num_iters = /** @type {number[]} */ (this.parameter("num_iters")); + const [p1, p2] = num_iters; + if (iter < p1) { + // Phase 1: MN weight linearly decays from 1000 to 3 + const t = iter / p1; + return { w_nn: 2.0, w_mn: 1000.0 * (1 - t) + 3.0 * t, w_fp: 1.0 }; + } else if (iter < p1 + p2) { + // Phase 2: fixed weights + return { w_nn: 3.0, w_mn: 3.0, w_fp: 1.0 }; + } else { + // Phase 3: MN disabled + return { w_nn: 1.0, w_mn: 0.0, w_fp: 1.0 }; + } + } + + /** + * Applies Adam optimizer update to Y using accumulated gradients. + * + * @protected + * @param {Float64Array} grad_flat - Flat N×d gradient + */ + _adam_update(grad_flat) { + const lr = /** @type {number} */ (this.parameter("lr")); + const N = this._N; + const d = /** @type {number} */ (this.parameter("d")); + const beta1 = 0.9; + const beta2 = 0.999; + const eps = 1e-7; + this._adam_t = (this._adam_t ?? 0) + 1; + const t = /** @type {number} */ (this._adam_t); + const bc1 = 1 - beta1 ** t; + const bc2 = 1 - beta2 ** t; + const Y = this.Y; + const m = /** @type {Float64Array} */ (this._adam_m); + const v = /** @type {Float64Array} */ (this._adam_v); + + for (let i = 0; i < N; ++i) { + const base = i * d; + const y_i = Y.row(i); + for (let k = 0; k < d; ++k) { + const g = grad_flat[base + k]; + m[base + k] = beta1 * m[base + k] + (1 - beta1) * g; + v[base + k] = beta2 * v[base + k] + (1 - beta2) * g * g; + const m_hat = m[base + k] / bc1; + const v_hat = v[base + k] / bc2; + y_i[k] -= lr * (m_hat / (Math.sqrt(v_hat) + eps)); + } + } + } + + /** + * Initializes PaCMAP: PCA embedding, KNN pairs, MN pairs, FP pairs, Adam state. + * + * @returns {PaCMAP} + */ + init() { + const X = this.X; + const N = this._N; + const d = /** @type {number} */ (this.parameter("d")); + const seed = /** @type {number} */ (this.parameter("seed")); + const metric = /** @type {Metric} */ (this.parameter("metric")); + const n_neighbors = /** @type {number} */ (this.parameter("n_neighbors")); + const MN_ratio = /** @type {number} */ (this.parameter("MN_ratio")); + const FP_ratio = /** @type {number} */ (this.parameter("FP_ratio")); + + // 1. PCA initialization scaled by 0.01 (X is always Matrix here) + const pca_init = /** @type {Matrix} */ (PCA.transform(X, { d, seed })); + this.Y = new Matrix(N, d, (i, j) => pca_init.entry(i, j) * 0.01); + + // 2. Build KNN graph for NN pairs + const knn = new BallTree(X.to2dArray(), { metric, seed }); + const n_MN = Math.max(1, Math.round(n_neighbors * MN_ratio)); + const n_FP = Math.max(1, Math.round(n_neighbors * FP_ratio)); + /** @type {Set[]} */ + const nn_sets = []; + // NN pairs: flat [i, j] pairs + const nn_pairs = new Int32Array(N * n_neighbors * 2); + let nn_idx = 0; + + for (let i = 0; i < N; ++i) { + const neighbors = knn.search(X.row(i), n_neighbors + 1); + /** @type {number[]} */ + const idxs = []; + for (const nb of neighbors) { + if (nb.index !== i) idxs.push(nb.index); + if (idxs.length >= n_neighbors) break; + } + nn_sets[i] = new Set(idxs); + for (const j of idxs) { + nn_pairs[nn_idx++] = i; + nn_pairs[nn_idx++] = j; + } + } + this._nn_pairs = nn_pairs.slice(0, nn_idx); + + // 3. MN pairs (mid-near sampling) + this._mn_pairs = this._sample_mn_pairs(nn_sets, n_MN); + + // 4. FP pairs (random non-neighbors) + this._fp_pairs = this._sample_fp_pairs(nn_sets, n_FP); + + // 5. Adam optimizer state + this._adam_m = new Float64Array(N * d); + this._adam_v = new Float64Array(N * d); + this._adam_t = 0; + + this._iter = 0; + return this; + } + + /** + * Performs one optimization step. + * + * @returns {Matrix} + */ + next() { + if (!this._nn_pairs) throw new Error("Call init() first!"); + const N = this._N; + const d = /** @type {number} */ (this.parameter("d")); + const { w_nn, w_mn, w_fp } = this._get_weights(this._iter); + + const grad_flat = new Float64Array(N * d); + this._accumulate_gradients(grad_flat, /** @type {Int32Array} */ (this._nn_pairs), w_nn, 10, false); + this._accumulate_gradients(grad_flat, /** @type {Int32Array} */ (this._mn_pairs), w_mn, 10000, false); + this._accumulate_gradients(grad_flat, /** @type {Int32Array} */ (this._fp_pairs), w_fp, 0, true); + this._adam_update(grad_flat); + + this._iter++; + return this.Y; + } + + /** + * @param {number} [iterations] - Total number of iterations. Defaults to sum of `num_iters`. + * @returns {T} + */ + transform(iterations) { + const num_iters = /** @type {number[]} */ (this.parameter("num_iters")); + const total = iterations ?? num_iters.reduce((a, b) => a + b, 0); + this.check_init(); + for (let i = 0; i < total; ++i) { + this.next(); + } + return this.projection; + } + + /** + * @param {number} [iterations] - Total number of iterations. Defaults to sum of `num_iters`. + * @returns {Generator} + */ + *generator(iterations) { + const num_iters = /** @type {number[]} */ (this.parameter("num_iters")); + const total = iterations ?? num_iters.reduce((a, b) => a + b, 0); + this.check_init(); + for (let i = 0; i < total; ++i) { + this.next(); + yield this.projection; + } + return this.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X, parameters) { + const dr = new PaCMAP(X, parameters); + return dr.transform(); + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new PaCMAP(X, parameters); + yield* dr.generator(); + return dr.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new PaCMAP(X, parameters); + return dr.transform_async(); + } } /** @import {InputType} from "../index.js" */ +/** @import {ParametersLocalMAP} from "./index.js" */ /** - * Base class for all clustering algorithms. - * @template Para + * LocalMAP + * + * A variant of PaCMAP that improves local cluster separation by dynamically + * resampling further pairs (FP) in phase 3 using nearby points in the current + * low-dimensional embedding space, rather than randomly sampled non-neighbors. + * + * @class + * @template {InputType} T + * @extends PaCMAP + * @category Dimensionality Reduction + * @see {@link https://arxiv.org/abs/2012.04456|PaCMAP Paper} + * @see {@link PaCMAP} for the base algorithm + * + * @example + * import * as druid from "@saehrimnir/druidjs"; + * + * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]; + * const localmap = new druid.LocalMAP(X, { + * n_neighbors: 10, + * low_dist_thres: 10, + * seed: 42 + * }); + * + * const Y = localmap.transform(); // 450 iterations (default) + * // [[x1, y1], [x2, y2], [x3, y3]] */ -class Clustering { - /** @type {InputType} */ - _points; - /** @type {Para} */ - _parameters; - /** @type {Matrix} */ - _matrix; - /** @type {number} */ - _N; - /** @type {number} */ - _D; - - /** - * Compute the respective Clustering with given parameters - * @param {InputType} points - * @param {Para} parameters - */ - constructor(points, parameters) { - this._points = points; - this._parameters = parameters; - - this._matrix = points instanceof Matrix ? points : Matrix.from(points); - const [N, D] = this._matrix.shape; - this._N = N; - this._D = D; - } - - /** - * @abstract - * @param {...unknown} args - * @returns {number[][]} An array with the indices of the clusters. - */ - get_clusters(...args) { - throw new Error("The function get_clusters must be implemented!"); - } - - /** - * @abstract - * @param {...unknown} args - * @returns {number[]} An array with the clusters id's for each point. - */ - get_cluster_list(...args) { - throw new Error("The function get_cluster_list must be implemented!"); - } +class LocalMAP extends PaCMAP { + /** + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + */ + constructor(X, parameters = {}) { + // Merge low_dist_thres into parameters before the seal in DR constructor. + // DR.constructor does Object.seal({ ...defaults, ...parameters }), so + // passing low_dist_thres here ensures it lands in the sealed object. + super(X, { low_dist_thres: 10, ...parameters }); + } + + /** + * Performs one optimization step. + * In phase 3, resamples FP pairs from the current embedding space + * and applies distance-based weight scaling. + * + * @returns {import("../matrix/index.js").Matrix} + */ + next() { + if (!this._nn_pairs) throw new Error("Call init() first!"); + const num_iters = /** @type {number[]} */ (this.parameter("num_iters")); + const phase3_start = num_iters[0] + num_iters[1]; + + if (this._iter < phase3_start) { + // Phases 1 and 2: identical to PaCMAP + return super.next(); + } + + // Phase 3: resample FP pairs from embedding neighbors + const N = this._N; + const d = /** @type {number} */ (this.parameter("d")); + const low_dist_thres = /** @type {number} */ (this._low_dist_thres ?? 10); + const low_dist_thres_sq = low_dist_thres * low_dist_thres; + const { w_nn, w_mn, w_fp } = this._get_weights(this._iter); + const Y = this.Y; + + // Build a KNN structure on the current embedding to find nearby pairs + const y_array = Y.to2dArray(); + const seed = /** @type {number} */ (this.parameter("seed")); + const emb_knn = new BallTree(y_array, { metric: euclidean_squared, seed }); + const n_FP = /** @type {number} */ (this.parameter("FP_ratio")) * + /** @type {number} */ (this.parameter("n_neighbors")); + const n_FP_int = Math.max(1, Math.round(n_FP)); + + // Build local FP pairs by finding nearby embedding neighbors + // (these are not NN neighbors in high-dim space but nearby in low-dim) + const nn_sets = this._nn_sets_cache; + /** @type {Int32Array} */ + let local_fp_pairs; + + if (nn_sets) { + const pair_buf = new Int32Array(N * n_FP_int * 2); + let idx = 0; + for (let i = 0; i < N; ++i) { + const nn_set = nn_sets[i]; + // Search for nearby points in embedding space + const neighbors = emb_knn.search(y_array[i], Math.min(n_FP_int * 3 + 1, N)); + let count = 0; + for (const nb of neighbors) { + if (nb.index === i || (nn_set && nn_set.has(nb.index))) continue; + pair_buf[idx++] = i; + pair_buf[idx++] = nb.index; + count++; + if (count >= n_FP_int) break; + } + } + local_fp_pairs = pair_buf.slice(0, idx); + } else { + local_fp_pairs = /** @type {Int32Array} */ (this._fp_pairs); + } + + // Accumulate gradients with local weight scaling for FP pairs + const grad_flat = new Float64Array(N * d); + this._accumulate_gradients(grad_flat, /** @type {Int32Array} */ (this._nn_pairs), w_nn, 10, false); + this._accumulate_gradients(grad_flat, /** @type {Int32Array} */ (this._mn_pairs), w_mn, 10000, false); + + // FP pairs with local distance-based weight scaling + this._accumulate_gradients_local_fp( + grad_flat, + local_fp_pairs, + w_fp, + low_dist_thres, + low_dist_thres_sq, + ); + + this._adam_update(grad_flat); + this._iter++; + return this.Y; + } + + /** + * Accumulates FP gradients with LocalMAP's distance-based weight scaling. + * For pairs within low_dist_thres, scales w_fp by low_dist_thres / (2 * sqrt(d_ij)). + * + * @private + * @param {Float64Array} grad_flat - Flat N×d gradient accumulator (modified in place) + * @param {Int32Array} pairs - Flat [i, j, i, j, ...] pair array + * @param {number} w_fp - Base FP weight + * @param {number} low_dist_thres - Distance threshold + * @param {number} low_dist_thres_sq - Squared distance threshold + */ + _accumulate_gradients_local_fp(grad_flat, pairs, w_fp, low_dist_thres, low_dist_thres_sq) { + if (w_fp === 0) return; + const Y = this.Y; + const d = /** @type {number} */ (this.parameter("d")); + const n_pairs = pairs.length / 2; + + for (let p = 0; p < n_pairs; ++p) { + const i = pairs[p * 2]; + const j = pairs[p * 2 + 1]; + const y_i = Y.row(i); + const y_j = Y.row(j); + + let sq_dist = 0; + for (let k = 0; k < d; ++k) { + const diff = y_i[k] - y_j[k]; + sq_dist += diff * diff; + } + const d_ij = 1 + sq_dist; + + // Apply local weight scaling when pair is within distance threshold + let w = w_fp; + if (sq_dist < low_dist_thres_sq) { + w *= low_dist_thres / (2 * Math.sqrt(d_ij)); + } + + // FP loss: 1/(1+d_ij), gradient: -2/(1+d_ij)² + const coeff = (-w * 2) / (d_ij * d_ij); + + const base_i = i * d; + const base_j = j * d; + for (let k = 0; k < d; ++k) { + const diff = y_i[k] - y_j[k]; + const g = coeff * diff; + grad_flat[base_i + k] += g; + grad_flat[base_j + k] -= g; + } + } + } + + /** + * Initializes LocalMAP (same as PaCMAP, but caches nn_sets for phase 3 resampling). + * + * @returns {LocalMAP} + */ + init() { + super.init(); + // Cache low_dist_thres from sealed parameters (avoids type indexing issues) + this._low_dist_thres = /** @type {number} */ (/** @type {any} */ (this._parameters)["low_dist_thres"] ?? 10); + // Cache nn_sets for use in phase 3 FP resampling + // We rebuild them from _nn_pairs + const N = this._N; + const nn_pairs = this._nn_pairs; + if (!nn_pairs) return this; + /** @type {Set[]} */ + const nn_sets = Array.from({ length: N }, () => new Set()); + for (let p = 0; p < nn_pairs.length; p += 2) { + nn_sets[nn_pairs[p]].add(nn_pairs[p + 1]); + } + this._nn_sets_cache = nn_sets; + return this; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X, parameters) { + const dr = new LocalMAP(X, parameters); + return dr.transform(); + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new LocalMAP(X, parameters); + yield* dr.generator(); + return dr.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new LocalMAP(X, parameters); + return dr.transform_async(); + } } -/** @import { InputType } from "../index.js" */ -/** @import { ParametersCURE } from "./index.js" */ +/** @import {InputType} from "../index.js" */ +/** @import {ParametersSMACOF} from "./index.js" */ /** - * CURE (Clustering Using REpresentatives) + * Metric Multidimensional Scaling (MDS) via SMACOF. * - * An efficient clustering algorithm for large databases that is robust to outliers - * and identifies clusters with non-spherical shapes and wide variances in size. + * SMACOF (Scaling by Majorizing a Complicated Function) is an iterative majorization + * algorithm for solving metric multidimensional scaling problems, which aims to + * minimize the stress function. * * @class - * @extends Clustering - * @category Clustering + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction + * @see {@link MDS} for the classical approach. */ -class CURE extends Clustering { - /** @type {number} */ - _K; - /** @type {number} */ - _num_representatives; - /** @type {number} */ - _shrink_factor; - /** - * @private - * @type {CURECluster[]} - */ - _clusters = []; - /** @type {number[]} */ - _cluster_ids = []; - - /** - * @param {InputType} points - * @param {Partial} parameters - */ - constructor(points, parameters = {}) { - super( - points, - /** @type {ParametersCURE} */ ( - Object.assign( - { K: 2, num_representatives: 5, shrink_factor: 0.5, metric: euclidean, seed: 1212 }, - parameters, - ) - ), - ); - - this._K = this._parameters.K ?? 2; - this._num_representatives = this._parameters.num_representatives ?? 5; - this._shrink_factor = this._parameters.shrink_factor ?? 0.5; - - // Initialize clusters - this._initialize_clusters(); - // Run CURE algorithm - this._cure(); - } - - /** - * Initialize each point as its own cluster - * @private - */ - _initialize_clusters() { - const N = this._N; - //const D = this._D; - this._clusters = []; +class SMACOF extends DR { + /** + * SMACOF for MDS. + * + * @param {T} X - The high-dimensional data or precomputed distance matrix. + * @param {Partial} [parameters] - Object containing parameterization. + */ + constructor(X, parameters = {}) { + super(X, { d: 2, metric: euclidean, seed: 1212, iterations: 300, epsilon: 1e-4 }, parameters); + } - for (let i = 0; i < N; ++i) { - const point = this._matrix.row(i); - const centroid = new Float64Array(point); - // For single point, representative is the point itself - const representatives = [new Float64Array(point)]; - - this._clusters.push(new CURECluster([i], centroid, representatives)); - } - } - - /** - * Compute distance between two clusters using representative points - * @private - * @param {CURECluster} cluster1 - * @param {CURECluster} cluster2 - * @returns {number} - */ - _cluster_distance(cluster1, cluster2) { - const reps1 = cluster1.representatives; - const reps2 = cluster2.representatives; - const metric = this._parameters.metric; - - let min_dist = Infinity; - for (const r1 of reps1) { - for (const r2 of reps2) { - const dist = metric(r1, r2); - if (dist < min_dist) { - min_dist = dist; - } - } - } - return min_dist; - } - - /** - * Find the closest pair of clusters - * @private - * @returns {[number, number, number]} [index1, index2, distance] - */ - _find_closest_clusters() { - let min_dist = Infinity; - let min_i = 0; - let min_j = 1; - - for (let i = 0; i < this._clusters.length; ++i) { - for (let j = i + 1; j < this._clusters.length; ++j) { - const dist = this._cluster_distance(this._clusters[i], this._clusters[j]); - if (dist < min_dist) { - min_dist = dist; - min_i = i; - min_j = j; - } - } - } - - return [min_i, min_j, min_dist]; - } - - /** - * Merge two clusters - * @private - * @param {CURECluster} cluster1 - * @param {CURECluster} cluster2 - * @returns {CURECluster} - */ - _merge_clusters(cluster1, cluster2) { - // Merge indices - const merged_indices = [...cluster1.indices, ...cluster2.indices]; - - // Calculate new centroid - const size1 = cluster1.indices.length; - const size2 = cluster2.indices.length; - const total_size = size1 + size2; - const D = this._D; - const new_centroid = new Float64Array(D); - - for (let d = 0; d < D; ++d) { - new_centroid[d] = (size1 * cluster1.centroid[d] + size2 * cluster2.centroid[d]) / total_size; - } - - // Collect all points from both clusters - /** @type {{index: number, point: Float64Array}[]} */ - const all_points = []; - for (const idx of cluster1.indices) { - all_points.push({ index: idx, point: this._matrix.row(idx) }); - } - for (const idx of cluster2.indices) { - all_points.push({ index: idx, point: this._matrix.row(idx) }); - } - - // Select representative points - pick points farthest from centroid - const num_reps = Math.min(this._num_representatives, all_points.length); - const metric = this._parameters.metric; - - // Calculate distances from centroid for all points - const distances = all_points.map(({ point }) => metric(point, new_centroid)); - - // Select num_reps points with maximum distance (farthest from centroid) - const selected_indices = []; - const used = new Set(); - - for (let r = 0; r < num_reps; ++r) { - let max_dist = -1; - let max_idx = -1; - - for (let i = 0; i < distances.length; ++i) { - if (!used.has(i) && distances[i] > max_dist) { - max_dist = distances[i]; - max_idx = i; - } - } - - if (max_idx >= 0) { - used.add(max_idx); - selected_indices.push(max_idx); - } - } - - // Shrink representative points toward centroid - const new_representatives = selected_indices.map((idx) => { - const point = all_points[idx].point; - const shrunk = new Float64Array(D); - const alpha = this._shrink_factor; - - for (let d = 0; d < D; ++d) { - shrunk[d] = point[d] + alpha * (new_centroid[d] - point[d]); - } - - return shrunk; - }); - - return new CURECluster(merged_indices, new_centroid, new_representatives); - } - - /** - * Run CURE clustering algorithm - * @private - */ - _cure() { - // Merge clusters until we have K clusters - while (this._clusters.length > this._K) { - const [i, j] = this._find_closest_clusters(); - - // Merge clusters i and j - const merged = this._merge_clusters(this._clusters[i], this._clusters[j]); - - // Remove the old clusters and add the merged one - // Remove larger index first to maintain correct indices - // min_i < min_j is always true from _find_closest_clusters - this._clusters.splice(j, 1); - this._clusters.splice(i, 1); - - this._clusters.push(merged); - } - - // Build cluster list for get_cluster_list - this._build_cluster_ids(); - } - - /** - * Build the cluster list (point -> cluster assignment) - * @private - */ - _build_cluster_ids() { - const N = this._N; - this._cluster_ids = new Array(N).fill(-1); - - for (let c = 0; c < this._clusters.length; ++c) { - for (const idx of this._clusters[c].indices) { - this._cluster_ids[idx] = c; - } - } - } + /** + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + *generator() { + this.check_init(); + const X = this.X; + const rows = this._N; + const d = /** @type {number} */ (this.parameter("d")); + const metric = /** @type {typeof euclidean | "precomputed"} */ (this.parameter("metric")); + const iterations = /** @type {number} */ (this.parameter("iterations")); + const epsilon = /** @type {number} */ (this.parameter("epsilon")); + + const target_distances = metric === "precomputed" ? X : distance_matrix(X, metric); + + let Z = new Matrix(rows, d, () => (this._randomizer.random - 0.5) * 2); + + // Center Z + for (let j = 0; j < d; ++j) { + const col = Z.col(j); + const mean = col.reduce((a, b) => a + b, 0) / rows; + for (let i = 0; i < rows; ++i) { + Z.sub_entry(i, j, mean); + } + } - /** - * @returns {number[][]} - */ - get_clusters() { - return this._clusters.map((cluster) => cluster.indices); - } - - /** - * @returns {number[]} - */ - get_cluster_list() { - return this._cluster_ids; - } -} + this.Y = /** @type {Matrix} */ (Z); // Initial state -/** - * @private - * Represents a cluster in CURE algorithm - */ -class CURECluster { - /** - * @param {number[]} indices - Indices of points in the cluster - * @param {Float64Array} centroid - Centroid of the cluster - * @param {Float64Array[]} representatives - Representative points (shrunk toward centroid) - */ - constructor(indices, centroid, representatives) { - /** @type {number[]} */ - this.indices = indices; - /** @type {Float64Array} */ - this.centroid = centroid; - /** @type {Float64Array[]} */ - this.representatives = representatives; - } + let prev_stress = Infinity; + + if (!(iterations > 0)) { + yield this.projection; + return this.projection; + } + + for (let iter = 0; iter < iterations; ++iter) { + const B = new Matrix(rows, rows, 0); + + for (let i = 0; i < rows; ++i) { + let bii = 0; + const z_i = Z.row(i); + for (let j = 0; j < rows; ++j) { + if (i === j) continue; + const z_j = Z.row(j); + const dist_Z = euclidean(z_i, z_j); + const dist_target = target_distances.entry(i, j); + + let bij = 0; + if (dist_Z > 1e-12) { + bij = -dist_target / dist_Z; + } + B.set_entry(i, j, bij); + bii -= bij; + } + B.set_entry(i, i, bii); + } + + // Z_new = 1/N * B(Z) * Z + const Z_new = B.dot(Z)._apply(rows, (val, n) => val / n); + + this.Y = /** @type {Matrix} */ (Z_new); + Z = /** @type {Matrix} */ (Z_new); + + // Calculate stress + let stress_num = 0; + let stress_den = 0; + for (let i = 0; i < rows; ++i) { + const z_i = Z.row(i); + for (let j = i + 1; j < rows; ++j) { + const z_j = Z.row(j); + const dist_Y = euclidean(z_i, z_j); + const diff = target_distances.entry(i, j) - dist_Y; + stress_num += diff * diff; + stress_den += target_distances.entry(i, j) ** 2; + } + } + const current_stress = Math.sqrt(stress_num / Math.max(stress_den, 1e-12)); + + yield this.projection; + + if (Math.abs(prev_stress - current_stress) < epsilon) { + break; + } + prev_stress = current_stress; + } + return this.projection; + } + + /** + * @returns {T} + */ + transform() { + const gen = this.generator(); + let res = /** @type {T} */ (this.X); + for (const step of gen) { + res = step; + } + return res; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X, parameters) { + const dr = new SMACOF(X, parameters); + return dr.transform(); + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new SMACOF(X, parameters); + yield* dr.generator(); + return dr.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new SMACOF(X, parameters); + return dr.transform_async(); + } } -/** @import { InputType } from "../index.js" */ -/** @import { ParametersHierarchicalClustering } from "./index.js" */ +/** @import {InputType} from "../index.js" */ +/** @import {ParametersISOMAP} from "./index.js" */ +/** @import {EigenArgs} from "../linear_algebra/index.js" */ /** - * Hierarchical Clustering + * Isomap (Isometric Mapping) * - * A bottom-up approach (agglomerative) to clustering that builds a tree of clusters (dendrogram). - * Supports different linkage criteria: single, complete, and average. + * A nonlinear dimensionality reduction algorithm that uses geodesic distances + * between points on a manifold to perform embedding. It builds a neighborhood + * graph and uses MDS on the shortest-path distances. * * @class - * @extends Clustering - * @category Clustering + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction + * @see {@link LLE} for another nonlinear alternative */ -class HierarchicalClustering extends Clustering { - /** @type {Cluster | null} */ - root = null; - - /** - * @param {InputType} points - Data or distance matrix if metric is 'precomputed' - * @param {Partial} parameters - */ - constructor(points, parameters = {}) { - super( - points, - /** @type {ParametersHierarchicalClustering} */ ( - Object.assign({ linkage: "complete", metric: euclidean }, parameters) - ), - ); - this._id = 0; - if ( - this._parameters.metric === "precomputed" && - this._matrix.shape[0] !== this._matrix.shape[1] - ) { - throw new Error("If metric is 'precomputed', then matrix has to be square!"); - } - - const metric = this._parameters.metric; - const A = this._matrix; - const N = this._N; - this._d_min = new Float64Array(N); - const d_min = this._d_min; - let distance_matrix; - if (metric !== "precomputed") { - distance_matrix = new Matrix(N, N, Infinity); - for (let i = 0; i < N; ++i) { - distance_matrix.set_entry(i, i, 0); - d_min[i] = i; // temporary - const Ai = A.row(i); - for (let j = i + 1; j < N; ++j) { - const dist = metric(Ai, A.row(j)); - distance_matrix.set_entry(i, j, dist); - distance_matrix.set_entry(j, i, dist); - } - } - for (let i = 0; i < N; i++) { - let min_j = 0; - let min_d = Infinity; - for (let j = 0; j < N; j++) { - if (i === j) continue; - const d = distance_matrix.entry(i, j); - if (d < min_d) { - min_d = d; - min_j = j; - } - } - d_min[i] = min_j; - } - } else { - distance_matrix = this._matrix.clone(); - for (let i = 0; i < N; ++i) { - distance_matrix.set_entry(i, i, 0); - d_min[i] = i === 0 ? 1 : 0; - for (let j = 0; j < N; ++j) { - if (i === j) continue; - if (distance_matrix.entry(i, d_min[i]) > distance_matrix.entry(i, j)) { - d_min[i] = j; - } - } - } - } - this._distance_matrix = distance_matrix; - this._clusters = new Array(N); - const clusters = this._clusters; - this._c_size = new Uint16Array(N); - const c_size = this._c_size; - for (let i = 0; i < N; ++i) { - clusters[i] = []; - clusters[i][0] = new Cluster(this._id++, null, null, 0, A.row(i), i, 1, 0); - c_size[i] = 1; - } - const D = this._distance_matrix; - const linkage = this._parameters.linkage; - const p_max = N - 1; - for (let p = 0; p < p_max; ++p) { - let c1 = -1; - let min_dist = Infinity; - for (let i = 0; i < N; ++i) { - if (D.entry(i, i) === Infinity) continue; - const dist = D.entry(i, d_min[i]); - if (dist < min_dist) { - min_dist = dist; - c1 = i; - } - } - if (c1 === -1) break; - - const c2 = d_min[c1]; - const c1_cluster = clusters[c1][0]; - const c2_cluster = clusters[c2][0]; - const c1_cluster_indices = c1_cluster.isLeaf ? [c1_cluster.index] : c1_cluster.index; - const c2_cluster_indices = c2_cluster.isLeaf ? [c2_cluster.index] : c2_cluster.index; - const indices = c1_cluster_indices.concat(c2_cluster_indices); - const new_cluster = new Cluster( - this._id++, - c1_cluster, - c2_cluster, - D.entry(c1, c2), - null, - indices, - ); - c1_cluster.parent = new_cluster; - c2_cluster.parent = new_cluster; - clusters[c1].unshift(new_cluster); - - const size1 = c_size[c1]; - const size2 = c_size[c2]; - c_size[c1] += size2; - - for (let j = 0; j < N; ++j) { - if (j === c1 || j === c2 || D.entry(j, j) === Infinity) continue; - const D_c1_j = D.entry(c1, j); - const D_c2_j = D.entry(c2, j); - let value; - switch (linkage) { - case "single": - value = Math.min(D_c1_j, D_c2_j); - break; - case "complete": - value = Math.max(D_c1_j, D_c2_j); - break; - case "average": - value = (size1 * D_c1_j + size2 * D_c2_j) / (size1 + size2); - break; +class ISOMAP extends DR { + /** + * Isometric feature mapping (ISOMAP). + * + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + * @see {@link https://doi.org/10.1126/science.290.5500.2319} + */ + constructor(X, parameters = {}) { + /** @type {ParametersISOMAP} */ + const defaults = { + neighbors: -Infinity, + d: 2, + metric: euclidean, + seed: 1212, + project: "MDS", + eig_args: {}, + }; + super(X, defaults, parameters); + + this.defaults = defaults; + + if (this._parameters.neighbors === -Infinity) { + this.parameter("neighbors", Math.min(Math.max(Math.floor(this.X.shape[0] / 10), 2), this._N - 1)); } - D.set_entry(j, c1, value); - D.set_entry(c1, j, value); - } - - D.set_entry(c2, c2, Infinity); - for (let i = 0; i < N; ++i) { - D.set_entry(i, c2, Infinity); - D.set_entry(c2, i, Infinity); - } - - // Update d_min for all rows - for (let i = 0; i < N; i++) { - if (D.entry(i, i) === Infinity) continue; - if (d_min[i] === c1 || d_min[i] === c2 || i === c1) { - let min_j = 0; - let min_d = Infinity; - for (let j = 0; j < N; j++) { - if (i === j || D.entry(j, j) === Infinity) continue; - const d = D.entry(i, j); - if (d < min_d) { - min_d = d; - min_j = j; - } - } - d_min[i] = min_j; - } else { - if (D.entry(i, c1) < D.entry(i, d_min[i])) { - d_min[i] = c1; - } - } - } - - this.root = new_cluster; - } - } - - /** - * @param {number} value - Value where to cut the tree. - * @param {"distance" | "depth"} [type="distance"] - Type of value. Default is `"distance"` - * @returns {Cluster[][]} - Array of clusters with the indices of the rows in given points. - */ - get_clusters_raw(value, type = "distance") { - /** @type {Cluster[][]} */ - const clusters = []; - /** @type {(d: {dist: number, depth: number}) => number} */ - let accessor; - switch (type) { - case "distance": - accessor = (d) => d.dist; - break; - case "depth": - accessor = (d) => d.depth; - break; - default: - throw new Error("invalid type"); - } - this._traverse(/** @type {Cluster} */ (this.root), accessor, value, clusters); - return clusters; - } - - /** - * @param {number} value - Value where to cut the tree. - * @param {"distance" | "depth"} [type="distance"] - Type of value. Default is `"distance"` - * @returns {number[][]} - Array of clusters with the indices of the rows in given points. - */ - get_clusters(value, type = "distance") { - /** @type {Cluster[][]} */ - const clusters = []; - /** @type {(d: {dist: number, depth: number}) => number} */ - let accessor; - switch (type) { - case "distance": - accessor = (d) => d.dist; - break; - case "depth": - accessor = (d) => d.depth; - break; - default: - throw new Error("invalid type"); - } - if (this.root) this._traverse(this.root, accessor, value, clusters); - return clusters.map((cluster) => cluster.map((d) => d.index)); - } - - /** - * @param {number} value - Value where to cut the tree. - * @param {"distance" | "depth"} [type="distance"] - Type of value. Default is `"distance"` - * @returns {number[]} - Array of clusters with the indices of the rows in given points. - */ - get_cluster_list(value, type = "distance") { - const clusters = this.get_clusters(value, type); - /** @type {number[]} */ - const list = new Array(this._N).fill(0); - for (let i = 0; i < clusters.length; ++i) { - const cluster = clusters[i]; - for (let j = 0; j < cluster.length; ++j) { - const index = cluster[j]; - list[index] = i; - } - } - return list; - } - - /** - * @private - * @param {Cluster} node - * @param {(d: {dist: number, depth: number}) => number} f - * @param {number} value - * @param {Cluster[][]} result - */ - _traverse(node, f, value, result) { - if (f(node) <= value) { - result.push(node.leaves()); - } else { - if (node.left) this._traverse(node.left, f, value, result); - if (node.right) this._traverse(node.right, f, value, result); - } - } -} -/** @private */ -class Cluster { - /**@type {number} */ - size; - /**@type {number} */ - depth; - /**@type {Cluster | null} */ - parent; - - /** - * - * @param {number} id - * @param {Cluster?} left - * @param {Cluster?} right - * @param {number} dist - * @param {Float64Array?} centroid - * @param {number} index - * @param {number} [size] - * @param {number} [depth] - */ - constructor(id, left, right, dist, centroid, index, size, depth) { - this.id = id; - this.left = left; - this.right = right; - this.dist = dist; - this.index = index; - if (size) { - this.size = size; - } else { - if (!left || !right) throw new Error("If size is not given, left & right cannot be null!"); - this.size = left.size + right.size; + const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); + if (!Object.hasOwn(eig_args, "seed")) { + eig_args.seed = this._randomizer; + } } - if (depth !== undefined) { - this.depth = depth; - } else { - if (!left || !right) throw new Error("If depth is not given, left & right cannot be null!"); - this.depth = Math.max(left.depth, right.depth) + 1; + /** + * Computes the projection. + * + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + *generator() { + yield this.transform(); + return this.projection; } - if (centroid !== undefined && centroid !== null) { - this.centroid = centroid; - } else { - if (!left || !right) - throw new Error("If centroid is not given, left & right cannot be null!"); - - this.centroid = this._calculate_centroid(left, right); - } - - this.parent = null; - } - - /** - * - * @param {Cluster} left - * @param {Cluster} right - * @returns {Float64Array} - */ - _calculate_centroid(left, right) { - const l_size = left.size; - const r_size = right.size; - const l_centroid = left.centroid; - const r_centroid = right.centroid; - const size = this.size; - const n = left.centroid.length; - const new_centroid = new Float64Array(n); - for (let i = 0; i < n; ++i) { - new_centroid[i] = (l_size * l_centroid[i] + r_size * r_centroid[i]) / size; - } - return new_centroid; - } - - get isLeaf() { - return this.depth === 0; - } - - /** - * - * @returns {Cluster[]} - */ - leaves() { - if (this.isLeaf) return [this]; - const left = this.left; - const right = this.right; - return (left ? (left.isLeaf ? [left] : left.leaves()) : []).concat( - right ? (right.isLeaf ? [right] : right.leaves()) : [], - ); - } - - /** - * - * @returns {Cluster[]} - */ - descendants() { - if (this.isLeaf) return [this]; - const left_descendants = this.left ? this.left.descendants() : []; - const right_descendants = this.right ? this.right.descendants() : []; - return left_descendants.concat(right_descendants).concat([this]); - } -} + /** + * @returns {T} + */ + transform() { + this.check_init(); + const X = this.X; + const rows = this._N; + const d = /** @type {number} */ (this.parameter("d")); + const metric = /** @type {typeof euclidean} */ (this.parameter("metric")); + const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); + const neighbors = /** @type {number} */ (this.parameter("neighbors")); + // TODO: make knn extern and parameter for constructor or transform? + const D = new Matrix(rows, rows, 0); + D.shape = [rows, rows, (i, j) => (i <= j ? metric(X.row(i), X.row(j)) : D.entry(j, i))]; + + /** @type {{ index: number; distance: number }[][]} */ + const kNearestNeighbors = []; + const tree = new BallTree(X.to2dArray(), { + metric, + seed: /** @type {number} */ (this.parameter("seed")), + }); + for (let i = 0; i < rows; ++i) { + // BallTree search returns elements including the queried point itself (at distance 0). + // Request neighbors + 1 and slice off the first one (which should be the query point). + const neighborsList = tree.search_by_index(i, neighbors + 1); + kNearestNeighbors.push( + neighborsList.slice(1).map((n) => ({ + index: n.index, + distance: n.distance, + })), + ); + } -/** - * @template T - * @typedef {Object} DisjointSetPayload - * @property {T} parent - * @property {Set} children - * @property {number} size - */ + // ISOMAP requires an undirected/symmetric nearest neighbor graph. + // If i is a nearest neighbor of j, then j should be connected to i as well. + for (let i = 0; i < rows; ++i) { + for (const neighbor of kNearestNeighbors[i]) { + const j = neighbor.index; + const d = neighbor.distance; + const reciprocal_edge = kNearestNeighbors[j].find((n) => n.index === i); + if (!reciprocal_edge) { + kNearestNeighbors[j].push({ index: i, distance: d }); + } + } + } -/** - * @template T - * @class - * @category Data Structures - * @see {@link https://en.wikipedia.org/wiki/Disjoint-set_data_structure} - */ -class DisjointSet { - /** - * @param {T[]?} elements - */ - constructor(elements = null) { - /** - * @private - * @type {Map>} - */ - this._list = new Map(); - if (elements) { - for (const e of elements) { - this.make_set(e); - } - } - } - - /** - * @private - * @param {T} x - * @returns {DisjointSet} - */ - make_set(x) { - const list = this._list; - if (!list.has(x)) { - list.set(x, { parent: x, children: new Set([x]), size: 1 }); - } - return this; - } - - /** - * @param {T} x - * @returns - */ - find(x) { - const list = this._list; - const disjoint_set = list.get(x); - if (disjoint_set) { - if (disjoint_set.parent !== x) { - disjoint_set.children.add(x); - const new_parent = this.find(disjoint_set.parent); - if (!new_parent) throw new Error("should not happen!"); - disjoint_set.parent = new_parent; - return disjoint_set.parent; - } else { - return x; - } - } else { - return null; - } - } + /*D = dijkstra(kNearestNeighbors);*/ + // compute shortest paths using Dijkstra's algorithm + // TODO: make extern + const G = new Matrix(rows, rows, Infinity); - /** - * @param {T} x - * @param {T} y - * @returns - */ - union(x, y) { - let node_x = this.find(x); - let node_y = this.find(y); + for (let i = 0; i < rows; ++i) { + G.set_entry(i, i, 0); + const H = new Heap([{ index: i, distance: 0 }], (d) => d.distance, "min"); - if (!node_x || !node_y) throw new Error("x or y not found!"); + while (!H.empty) { + const item = H.pop(); + if (!item) break; - let disjoint_set_x = this._list.get(node_x); - let disjoint_set_y = this._list.get(node_y); + const u = item.element.index; + const dist_u = item.element.distance; - if (!disjoint_set_x || !disjoint_set_y) throw new Error("should not happen!"); + if (dist_u > G.entry(i, u)) continue; - if (node_x === node_y) return this; - if (disjoint_set_x.size < disjoint_set_y.size) { - [node_x, node_y] = [node_y, node_x]; - [disjoint_set_x, disjoint_set_y] = [disjoint_set_y, disjoint_set_x]; - } + for (const neighbor of kNearestNeighbors[u]) { + const v = neighbor.index; + const alt = dist_u + neighbor.distance; + if (alt < G.entry(i, v)) { + G.set_entry(i, v, alt); + H.push({ index: v, distance: alt }); + } + } + } + } - disjoint_set_y.parent = node_x; - // keep track of children - disjoint_set_y.children.forEach(disjoint_set_x.children.add, disjoint_set_x.children); - disjoint_set_x.size += disjoint_set_y.size; + let max_val = 0; + for (let i = 0; i < rows; i++) { + for (let j = 0; j < rows; j++) { + const val = G.entry(i, j); + if (val !== Infinity && val > max_val) max_val = val; + } + } + const big_val = max_val * 10; - return this; - } + const project = /** @type {"MDS" | "SMACOF"} */ (this.parameter("project")); - /** @param {T} x */ - get_children(x) { - const node = this._list.get(x); - if (node) { - return node.children; - } else { - return null; + if (project === "SMACOF") { + // Apply SMACOF metric MDS to the distance matrix directly + const D_matrix = new Matrix(rows, rows, (i, j) => { + const val = G.entry(i, j); + return val === Infinity ? big_val : val; + }); + const smacof = new SMACOF(D_matrix, { + metric: "precomputed", + d, + seed: this.parameter("seed"), + }); + smacof.transform(); + this.Y = smacof.Y; + } else { + // "MDS" (Classical MDS) via Eigendecomposition of double-centered squared distance matrix + const D_sq = new Matrix(rows, rows, (i, j) => { + let val = G.entry(i, j); + if (val === Infinity) val = big_val; + return val * val; + }); + + const ai_ = D_sq.meanCols(); + const a_j = D_sq.meanRows(); + const a__ = D_sq.mean(); + const B = new Matrix(rows, rows, (i, j) => -0.5 * (D_sq.entry(i, j) - ai_[i] - a_j[j] + a__)); + + // compute d eigenvectors + const { eigenvectors: V } = simultaneous_poweriteration(B, d, eig_args); + this.Y = Matrix.from(V).transpose(); + } + // return embedding + return this.projection; } - } -} -/** @import { Comparator } from "./index.js" */ + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X, parameters) { + const dr = new ISOMAP(X, parameters); + return dr.transform(); + } -/** - * @template T - * @class - * @category Data Structures - */ -class Heap { - /** @type {{ element: T; value: number }[]} */ - _container; - - /** @type {Comparator} */ - _comparator; - - /** - * A heap is a datastructure holding its elements in a specific way, so that the top element would be the first - * entry of an ordered list. - * - * @param {T[]?} elements - Contains the elements for the Heap. `elements` can be null. - * @param {(d: T) => number} accessor - Function returns the value of the element. - * @param {"min" | "max" | Comparator} [comparator="min"] - Function returning true or false - * defining the wished order of the Heap, or String for predefined function. ("min" for a Min-Heap, "max" for a - * Max_heap). Default is `"min"` - * @see {@link https://en.wikipedia.org/wiki/Binary_heap} - */ - constructor(elements = null, accessor, comparator = "min") { - /** @type {(d: T) => number} */ - this._accessor = accessor; - this._container = []; - if (comparator === "min") { - this._comparator = (a, b) => a < b; - } else if (comparator === "max") { - this._comparator = (a, b) => a > b; - } else { - this._comparator = comparator; - } - if (elements) { - this._container = []; - for (const e of elements) { - this._container.push({ - element: e, - value: accessor(e), - }); - } - for (let i = Math.floor(elements.length / 2 - 1); i >= 0; --i) { - this._heapify_down(i); - } - } - } - - /** - * Creates a Heap from an Array - * - * @template T - * @param {T[]} elements - Contains the elements for the Heap. - * @param {(d: T) => number} accessor - Function returns the value of the element. - * @param {"min" | "max" | Comparator} [comparator="min"] - Function returning true or false - * defining the wished order of the Heap, or String for predefined function. ("min" for a Min-Heap, "max" for a - * Max_heap). Default is `"min"` - * @returns {Heap} - */ - static heapify(elements, accessor, comparator = "min") { - const heap = new Heap(null, accessor, comparator); - const container = heap._container; - for (const e of elements) { - container.push({ - element: e, - value: accessor(e), - }); - } - for (let i = Math.floor(elements.length / 2 - 1); i >= 0; --i) { - heap._heapify_down(i); - } - return heap; - } - - /** - * Swaps elements of container array. - * - * @private - * @param {number} index_a - * @param {number} index_b - */ - _swap(index_a, index_b) { - const container = this._container; - [container[index_b], container[index_a]] = [container[index_a], container[index_b]]; - return; - } - - /** @private */ - _heapify_up() { - const container = this._container; - let index = container.length - 1; - while (index > 0) { - const parentIndex = Math.floor((index - 1) / 2); - if (!this._comparator(container[index].value, container[parentIndex].value)) { - break; - } else { - this._swap(parentIndex, index); - index = parentIndex; - } - } - } - - /** - * Pushes the element to the heap. - * - * @param {T} element - * @returns {Heap} - */ - push(element) { - const value = this._accessor(element); - //const node = new Node(element, value); - const node = { element: element, value: value }; - this._container.push(node); - this._heapify_up(); - return this; - } - - /** - * @private - * @param {Number} [start_index=0] Default is `0` - */ - _heapify_down(start_index = 0) { - const container = this._container; - const comparator = this._comparator; - const length = container.length; - const left = 2 * start_index + 1; - const right = 2 * start_index + 2; - let index = start_index; - if (index >= length) throw "index higher than length"; - if (left < length && comparator(container[left].value, container[index].value)) { - index = left; - } - if (right < length && comparator(container[right].value, container[index].value)) { - index = right; - } - if (index !== start_index) { - this._swap(start_index, index); - this._heapify_down(index); - } - } - - /** - * Removes and returns the top entry of the heap. - * - * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by - * `accessor`}). - */ - pop() { - const container = this._container; - if (container.length === 0) { - return null; - } else if (container.length === 1) { - const item = container.pop(); - if (!item) throw new Error("Cannot happen!"); - return item; - } - this._swap(0, container.length - 1); - const item = container.pop(); - this._heapify_down(); - return item ?? null; - } - - /** - * Returns the top entry of the heap without removing it. - * - * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by - * `accessor`). - */ - get first() { - return this._container.length > 0 ? this._container[0] : null; - } - - /** - * Yields the raw data - * - * @yields {T} Object consists of the element and its value (computed by `accessor`}). - */ - *iterate() { - for (let i = 0, n = this._container.length; i < n; ++i) { - yield this._container[i].element; - } - } - - /** - * Returns the heap as ordered array. - * - * @returns {T[]} Array consisting the elements ordered by `comparator`. - */ - toArray() { - return this._container - .sort((a, b) => (this._comparator(a.value, b.value) ? -1 : 1)) - .map((d) => d.element); - } - - /** - * Returns elements of container array. - * - * @returns {T[]} Array consisting the elements. - */ - data() { - return this._container.map((d) => d.element); - } - - /** - * Returns the container array. - * - * @returns {{ element: T; value: number }[]} The container array. - */ - raw_data() { - return this._container; - } - - /** - * The size of the heap. - * - * @returns {number} - */ - get length() { - return this._container.length; - } - - /** - * Returns false if the the heap has entries, true if the heap has no entries. - * - * @returns {boolean} - */ - get empty() { - return this.length === 0; - } + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new ISOMAP(X, parameters); + yield* dr.generator(); + return dr.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new ISOMAP(X, parameters); + return dr.transform_async(); + } } -/** @import { InputType } from "../index.js" */ -/** @import { ParametersKMeans } from "./index.js" */ +/** @import {InputType} from "../index.js" */ +/** @import {ParametersLDA} from "./index.js" */ +/** @import {EigenArgs} from "../linear_algebra/index.js" */ + /** - * K-Means Clustering + * Linear Discriminant Analysis (LDA) * - * A popular clustering algorithm that partitions data into K clusters where each point - * belongs to the cluster with the nearest mean (centroid). + * A supervised dimensionality reduction technique that finds the axes that + * maximize the separation between multiple classes. * * @class - * @extends Clustering - * @category Clustering - * @see {@link KMedoids} for a more robust alternative - * - * @example - * import * as druid from "@saehrimnir/druidjs"; - * - * const points = [[1, 1], [1.5, 1.5], [5, 5], [5.5, 5.5]]; - * const kmeans = new druid.KMeans(points, { K: 2 }); - * - * const clusters = kmeans.get_cluster_list(); // [0, 0, 1, 1] - * const centroids = kmeans.centroids; // center points + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction */ -class KMeans extends Clustering { - /** - * @param {InputType} points - * @param {Partial} parameters - */ - constructor(points, parameters = {}) { - super( - points, - /** @type {ParametersKMeans} */ ( - Object.assign({ K: 4, metric: euclidean, seed: 1212 }, parameters) - ), - ); - - const K = this._parameters.K; - const seed = parameters.seed; - - // Convert points to Matrix if needed - if (points instanceof Matrix) { - this._matrix = points; - } else { - this._matrix = Matrix.from(points); +class LDA extends DR { + /** + * Linear Discriminant Analysis. + * + * @param {T} X - The high-dimensional data. + * @param {Partial & { labels: any[] | Float64Array }} parameters - Object containing parameterization of the DR method. + * @see {@link https://onlinelibrary.wiley.com/doi/10.1111/j.1469-1809.1936.tb02137.x} + */ + constructor(X, parameters) { + super(X, { labels: parameters.labels, d: 2, seed: 1212, eig_args: {} }, parameters); + const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); + if (!Object.hasOwn(eig_args, "seed")) { + eig_args.seed = this._randomizer; + } } - const [N, D] = this._matrix.shape; - this._N = N; - this._D = D; + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + *generator() { + yield this.transform(); + return this.projection; + } - this._K = K > N ? N : K; - this._randomizer = new Randomizer(seed); + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {T} - The projected data. + */ + transform() { + const X = this.X; + const [rows, cols] = X.shape; + const { d, labels, eig_args } = this._parameters; + if (labels === null || labels.length !== rows) { + throw new Error("LDA needs parameter label to every datapoint to work!"); + } - /** @type {number[]} */ - this._clusters = new Array(N).fill(0); - - this._cluster_centroids = parameters.initial_centroids - ? parameters.initial_centroids.map((c) => new Float64Array(c)) - : this._get_random_centroids(this._K); - let cluster_centroids = this._cluster_centroids; - let iterations = 0; - const max_iterations = 300; - let clusters_changed = true; - - while (clusters_changed && iterations < max_iterations) { - const iteration_result = this._iteration(cluster_centroids); - cluster_centroids = iteration_result.cluster_centroids; - clusters_changed = iteration_result.clusters_changed; - iterations++; - } - - this._cluster_centroids = cluster_centroids; - } - - /** @returns {number} The number of clusters */ - get k() { - return this._K; - } - - /** @returns {Float64Array[]} The cluster centroids */ - get centroids() { - return this._cluster_centroids; - } - - /** @returns {number[]} The cluster list */ - get_cluster_list() { - return this._clusters; - } - - /** @returns {number[][]} An Array of clusters with the indices of the points. */ - get_clusters() { - const K = this._K; - const clusters = this._clusters; - /** @type {number[][]} */ - const result = new Array(K).fill(0).map(() => []); - clusters.forEach((c, i) => { - if (c >= 0 && c < K) { - result[c].push(i); - } - }); - return result; - } - - /** - * @private - * @param {number[]} point_indices - * @param {number[]} candidates - * @returns {number} - */ - _furthest_point(point_indices, candidates) { - const A = this._matrix; - const metric = this._parameters.metric; - - if (point_indices.length === 0 || candidates.length === 0) { - return candidates[0] ?? 0; - } - - const H = Heap.heapify( - candidates, - (d) => { - const Ad = A.row(d); - let sum = 0; - for (let j = 0; j < point_indices.length; ++j) { - sum += metric(Ad, A.row(point_indices[j])); - } - return sum; - }, - "max", - ); - - const furthest = H.pop(); - if (!furthest) throw new Error("Should not happen!"); - - return furthest.element; - } - - /** - * @private - * @param {number} K - * @returns {Float64Array[]} - */ - _get_random_centroids(K) { - const N = this._N; - const randomizer = this._randomizer; - const A = this._matrix; - /** @type {Float64Array[]} */ - const cluster_centroids = new Array(K); - const indices = linspace(0, N - 1); - - // First centroid: random selection - const random_point = randomizer.random_int % N; - cluster_centroids[0] = A.row(random_point); - const init_points = [random_point]; - - const sample_size = Math.max(1, Math.floor((N - K) / K)); - - for (let i = 1; i < K; ++i) { - const remaining = indices.filter((d) => !init_points.includes(d)); - if (remaining.length === 0) break; - - const sample = randomizer.choice(remaining, Math.min(sample_size, remaining.length)); - const furthest_point = this._furthest_point(init_points, sample); - - init_points.push(furthest_point); - cluster_centroids[i] = A.row(furthest_point); - } - - return cluster_centroids; - } - - /** - * @private - * @param {Float64Array[]} cluster_centroids - * @returns {{ clusters_changed: boolean; cluster_centroids: Float64Array[] }} - */ - _iteration(cluster_centroids) { - const K = cluster_centroids.length; - const N = this._N; - const metric = this._parameters.metric; - const A = this._matrix; - const clusters = this._clusters; - let clusters_changed = false; - - // Find nearest cluster centroid for each point - for (let i = 0; i < N; ++i) { - const Ai = A.row(i); - let min_dist = Infinity; - let min_cluster = 0; - - for (let j = 0; j < K; ++j) { - const d = metric(cluster_centroids[j], Ai); - if (d < min_dist) { - min_dist = d; - min_cluster = j; - } - } - - if (clusters[i] !== min_cluster) { - clusters_changed = true; - clusters[i] = min_cluster; - } - } - - // Update cluster centroids - const new_centroids = this._compute_centroid(K); - - return { - clusters_changed: clusters_changed, - cluster_centroids: new_centroids, - }; - } - - /** - * @private - * @param {number} K - * @returns {Float64Array[]} - */ - _compute_centroid(K) { - const N = this._N; - const D = this._D; - const A = this._matrix; - const clusters = this._clusters; - - // Initialize new centroids and counters - /** @type {Float64Array[]} */ - const new_centroids = new Array(K); - const cluster_counter = new Array(K).fill(0); - - for (let i = 0; i < K; ++i) { - new_centroids[i] = new Float64Array(D); - } - - // Sum up all points in each cluster - for (let i = 0; i < N; ++i) { - const Ai = A.row(i); - const ci = clusters[i]; - if (ci >= 0 && ci < K) { - cluster_counter[ci]++; - const centroid = new_centroids[ci]; - for (let j = 0; j < D; ++j) { - centroid[j] += Ai[j]; + /** @type {Record} */ + const unique_labels = {}; + let label_id = 0; + labels.forEach((l, i) => { + if (l in unique_labels) { + unique_labels[l].count++; + unique_labels[l].rows.push(X.row(i)); + } else { + unique_labels[l] = { + id: label_id++, + count: 1, + rows: [X.row(i)], + }; + } + }); + + // create X_mean and vector means; + const X_mean = X.meanCols(); + const V_mean = new Matrix(label_id, cols); + for (const label in unique_labels) { + const V = Matrix.from(unique_labels[label].rows); + const v_mean = V.meanCols(); + for (let j = 0; j < cols; ++j) { + V_mean.set_entry(unique_labels[label].id, j, v_mean[j]); + } + } + // scatter_between + let S_b = new Matrix(cols, cols); + for (const label in unique_labels) { + const v = V_mean.row(unique_labels[label].id); + const m = Matrix.from([v]).sub(Matrix.from([X_mean])); + const N = unique_labels[label].count; + S_b = S_b.add(m.transDot(m).mult(N)); } - } - } - // Divide by count to get mean - for (let i = 0; i < K; ++i) { - const n = cluster_counter[i]; - if (n > 0) { - const centroid = new_centroids[i]; - for (let j = 0; j < D; ++j) { - centroid[j] /= n; + // scatter_within + let S_w = new Matrix(cols, cols); + for (const label in unique_labels) { + const v = V_mean.row(unique_labels[label].id); + const R = unique_labels[label].rows; + for (let i = 0, n = unique_labels[label].count; i < n; ++i) { + const row_v = Matrix.from([R[i]]).sub(Matrix.from([v])); + S_w = S_w.add(row_v.transDot(row_v)); + } } - } + + const { eigenvectors: EV } = simultaneous_poweriteration( + S_w.inverse().dot(S_b), + d || Math.min(cols, label_id - 1), + eig_args, + ); + const V = Matrix.from(EV).transpose(); + this.Y = X.dot(V); + + // return embedding + return this.projection; + } + + /** + * @template {InputType} T + * @template {{ seed?: number }} Para + * @param {T} X + * @param {Para} parameters + * @returns {T} + */ + static transform(X, parameters) { + // @ts-expect-error: LDA requires labels, but DR static transform doesn't + const dr = new LDA(X, parameters); + return dr.transform(); + } + + /** + * @template {InputType} T + * @template {{ seed?: number }} Para + * @param {T} X + * @param {Para} parameters + * @returns {Generator} + */ + static *generator(X, parameters) { + // @ts-expect-error: LDA requires labels, but DR static generator doesn't + const dr = new LDA(X, parameters); + yield* dr.generator(); + return dr.projection; } - return new_centroids; - } + /** + * @template {InputType} T + * @template {{ seed?: number }} Para + * @param {T} X + * @param {Para} parameters + * @returns {Promise} + */ + static async transform_async(X, parameters) { + // @ts-expect-error: LDA requires labels, but DR static transform doesn't + const dr = new LDA(X, parameters); + return dr.transform_async(); + } } /** @import {InputType} from "../index.js" */ -/** @import { ParametersKMedoids } from "./index.js" */ +/** @import {ParametersLLE} from "./index.js" */ +/** @import {EigenArgs} from "../linear_algebra/index.js" */ /** - * K-Medoids (PAM - Partitioning Around Medoids) + * Locally Linear Embedding (LLE) * - * A robust clustering algorithm similar to K-Means, but uses actual data points (medoids) - * as cluster centers and can work with any distance metric. + * A nonlinear dimensionality reduction technique that preserves local + * linear relationships between points. It represents each point as a linear + * combination of its neighbors. * * @class - * @extends Clustering - * @category Clustering - * @see {@link KMeans} for a faster but less robust alternative + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction + * @see {@link ISOMAP} for another nonlinear alternative */ -class KMedoids extends Clustering { - /** - * @param {InputType} points - Data matrix - * @param {Partial} parameters - * @see {@link https://link.springer.com/chapter/10.1007/978-3-030-32047-8_16} Faster k-Medoids Clustering: Improving the PAM, CLARA, and CLARANS Algorithms - */ - constructor(points, parameters = {}) { - super( - points, - Object.assign({ K: 4, max_iter: null, metric: euclidean, seed: 1212 }, parameters), - ); - this._A = this._matrix.to2dArray(); - let K = this._parameters.K; - const N = this._N; - this._max_iter = this._parameters.max_iter ?? 10 * Math.log10(N); - this._distance_matrix = new Matrix(N, N, "zeros"); - - if (K > N) { - this._parameters.K = K = N; - } - this._randomizer = new Randomizer(this._parameters.seed); - this._clusters = new Array(N).fill(-1); - this._cluster_medoids = this._get_random_medoids(K); - this._is_initialized = false; - } - - /** @returns {number[]} The cluster list */ - get_cluster_list() { - if (!this._is_initialized) { - this.get_clusters(); - } - return this._clusters; - } - - /** @returns {number[][]} - Array of clusters with the indices of the rows in given points. */ - get_clusters() { - const K = this._parameters.K; - const A = this._A; - const N = this._N; - if (!this._is_initialized) { - this.init(K, this._cluster_medoids); - } - /** @type {number[][]} */ - const result = new Array(K).fill(0).map(() => []); - for (let j = 0; j < N; j++) { - const nearest = this._nearest_medoid(A[j], j); - const cluster_idx = nearest.index_nearest; - result[cluster_idx].push(j); - this._clusters[j] = cluster_idx; +class LLE extends DR { + /** + * Locally Linear Embedding. + * + * @param {T} X - The high-dimensional data. + * @param {Partial} parameters - Object containing parameterization of the DR method. + * @see {@link https://doi.org/10.1126/science.290.5500.2323} + */ + constructor(X, parameters) { + super( + X, + { + neighbors: -Infinity, + d: 2, + metric: euclidean, + seed: 1212, + eig_args: {}, + }, + parameters, + ); + if (this._parameters.neighbors === -Infinity) { + this.parameter("neighbors", Math.min(Math.max(Math.floor(this._N / 10), 2), this._N - 1)); + } + + const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); + if (!Object.hasOwn(eig_args, "seed")) { + eig_args.seed = this._randomizer; + } } - return result; - } - - /** @returns {number} */ - get k() { - return this._parameters.K; - } - - /** @returns {number[]} */ - get medoids() { - return this.get_medoids(); - } - - /** @returns {number[]} */ - get_medoids() { - const K = this._parameters.K; - if (!this._is_initialized) { - this.init(K, this._cluster_medoids); - } - return this._cluster_medoids; - } - - async *generator() { - const max_iter = this._max_iter; - if (!this._is_initialized) { - this.get_clusters(); - } - yield this.get_clusters(); - let i = 0; - while (i < max_iter) { - const finish = this._iteration(); - this._update_clusters(); - yield this.get_clusters(); - if (finish) break; - i++; - } - } - - /** Algorithm 1. FastPAM1: Improved SWAP algorithm */ - /* _iteration_1() { - const A = this._A; - const N = this._N; - const K = this._K; - const medoids = this._cluster_medoids; - let DeltaTD = 0; - let m0 = null; - let x0 = null; - A.forEach((x_j, j) => { - if (medoids.findIndex(m => m === j) < 0) { - const nearest_medoid = this._nearest_medoid(x_j, j); - const d_j = nearest_medoid.distance_nearest; // distance to current medoid - const deltaTD = new Array(K).fill(-d_j); // change if making j a medoid - A.forEach((x_o, o) => { - // disance to new medoid - const d_oj = this._get_distance(o, j, x_o, x_j); - const { - "index_nearest": n, - "distance_nearest": d_n, - "distance_second": d_s, - } = this._nearest_medoid(x_o, o); - this._clusters[o] = n; // cached values - deltaTD[n] += Math.min(d_oj, d_s) - d_n; // loss change - if (d_oj < d_n) { // reassignment check - deltaTD.forEach((d_i, i) => { - if (n !== i) { - deltaTD[i] = d_i + d_oj - d_n; // update loss change - } - }); - } - }); - // choose best medoid i; - const i = deltaTD - .map((d, i) => [d, i]) - .sort((d1, d2) => d1[0] - d2[0])[0][1]; - const deltaTD_i = deltaTD[i]; - // store - if (deltaTD_i < DeltaTD) { - DeltaTD = deltaTD_i; - m0 = i; - x0 = j; + + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + *generator() { + yield this.transform(); + return this.projection; + } + + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {T} + */ + transform() { + const X = this.X; + const rows = this._N; + const cols = this._D; + const neighbors = /** @type {number} */ (this.parameter("neighbors")); + const d = /** @type {number} */ (this.parameter("d")); + const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); + const metric = /** @type {typeof euclidean} */ (this.parameter("metric")); + const nN = k_nearest_neighbors(X, neighbors, metric); + const O = new Matrix(neighbors, 1, 1); + const W = new Matrix(rows, rows); + + for (let row = 0; row < rows; ++row) { + const nN_row = nN[row]; + const Z = new Matrix(neighbors, cols, (i, j) => X.entry(nN_row[i].j, j) - X.entry(row, j)); + const C = Z.dotTrans(Z); + if (neighbors > cols) { + const C_trace = neumair_sum(C.diag()) / 1000; + for (let j = 0; j < neighbors; ++j) { + C.add_entry(j, j, C_trace); } } - }); - - if (DeltaTD >= 0) { - return true // break loop if DeltaTD >= 0 + // reconstruct; + let w = Matrix.solve_CG(C, O, this._randomizer); + w = w.divide(w.sum()); + for (let j = 0; j < neighbors; ++j) { + W.set_entry(row, nN_row[j].j, w.entry(j, 0)); + } } - // swap roles of medoid m and non-medoid x; - medoids[m0] = x0; - this._cluster_medoids = medoids; - return false - } */ + // comp embedding + const I = new Matrix(rows, rows, "identity"); + const IW = I.sub(W); + const M = IW.transDot(IW); + + // M is symmetric positive semi-definite. Smallest eigenvalue is 0 (ones vector). + // To find smallest eigenvalues of M, we can find largest of (C*I - M) + // Upper bound for max eigenvalue: Frobenius norm or sum of absolute values + const C = M.mean() * rows * 2; // Safe upper bound for a sparse-ish M in LLE + const CI_M = new Matrix(rows, rows, (i, j) => (i === j ? C : 0) - M.entry(i, j)); - /** FastPAM1: One best swap per iteration */ - _iteration() { - const A = this._A; - const K = this._parameters.K; - const medoids = this._cluster_medoids; - const N = this._N; - - // Precompute nearest and second nearest medoid for all points - const cache = new Array(N); - for (let i = 0; i < N; i++) { - cache[i] = this._nearest_medoid(A[i], i); - } - - let best_delta = 0; - let best_swap = null; // { m_idx: index in medoids, x_idx: index in A } - - // For each non-medoid point j, evaluate swapping it with each medoid i - const medoid_set = new Set(medoids); - for (let j = 0; j < N; j++) { - if (medoid_set.has(j)) continue; - - const x_j = A[j]; - const d_j = cache[j].distance_nearest; - - // deltaTD[i] will store the change in total distance if we swap medoid[i] with j - const deltaTD = new Array(K).fill(-d_j); - - for (let o = 0; o < N; o++) { - if (o === j) continue; - const dist_o_j = this._get_distance(o, j, A[o], x_j); - const { index_nearest: n, distance_nearest: d_n, distance_second: d_s } = cache[o]; - - // If o is assigned to the current medoid being swapped out (n) - deltaTD[n] += Math.min(dist_o_j, d_s) - d_n; - - // For all other medoids i != n, if j is closer to o than its current medoid - if (dist_o_j < d_n) { - for (let i = 0; i < K; i++) { - if (i !== n) { - deltaTD[i] += dist_o_j - d_n; - } - } - } - } - - // Find best medoid to swap with j - for (let i = 0; i < K; i++) { - if (deltaTD[i] < best_delta) { - best_delta = deltaTD[i]; - best_swap = { m_idx: i, x_idx: j }; - } - } - } - - if (best_swap && best_delta < 0) { - medoids[best_swap.m_idx] = best_swap.x_idx; - this._cluster_medoids = medoids; - return false; // not finished - } - - return true; // finished - } - - /** - * - * @param {number} i - * @param {number} j - * @param {Float64Array?} x_i - * @param {Float64Array?} x_j - * @returns - */ - _get_distance(i, j, x_i = null, x_j = null) { - if (i === j) return 0; - const D = this._distance_matrix; - const A = this._A; - const metric = this._parameters.metric; - let d_ij = D.entry(i, j); - if (d_ij === 0) { - d_ij = metric(x_i || A[i], x_j || A[j]); - D.set_entry(i, j, d_ij); - D.set_entry(j, i, d_ij); - } - return d_ij; - } - - /** - * - * @param {Float64Array} x_j - * @param {number} j - * @returns - */ - _nearest_medoid(x_j, j) { - const medoids = this._cluster_medoids; - const A = this._A; - if (medoids.length === 0) { - throw new Error("No medoids available. Initialization failed."); - } - - let d_n = Infinity; - let n = -1; - let d_s = Infinity; - let s = -1; - - for (let i = 0; i < medoids.length; i++) { - const m = medoids[i]; - const d = this._get_distance(j, m, x_j, A[m]); - if (d < d_n) { - d_s = d_n; - s = n; - d_n = d; - n = i; - } else if (d < d_s) { - d_s = d; - s = i; - } - } - - if (s === -1) s = n; - - return { - distance_nearest: d_n, - index_nearest: n, - distance_second: d_s, - index_second: s, - }; - } - - _update_clusters() { - const N = this._N; - const A = this._A; - for (let j = 0; j < N; j++) { - const nearest = this._nearest_medoid(A[j], j); - this._clusters[j] = nearest.index_nearest; - } - } - - /** - * Computes `K` clusters out of the `matrix`. - * @param {number} K - Number of clusters. - * @param {number[]} cluster_medoids - */ - init(K, cluster_medoids) { - if (!K) K = this._parameters.K; - if (!cluster_medoids) cluster_medoids = this._get_random_medoids(K); - this._cluster_medoids = cluster_medoids; - const max_iter = this._max_iter; - let finish = false; - let i = 0; - do { - finish = this._iteration(); - } while (!finish && ++i < max_iter); - this._update_clusters(); - this._is_initialized = true; - return this; - } - - /** - * Algorithm 3. FastPAM LAB: Linear Approximate BUILD initialization. - * - * @param {number} K - Number of clusters - * @returns {number[]} - */ - _get_random_medoids(K) { - const N = this._N; - const A = this._A; - const indices = linspace(0, N - 1); - const randomizer = this._randomizer; - const n = Math.min(N, 10 + Math.ceil(Math.sqrt(N))); - - // Handle case where K >= N - if (K >= N) { - return indices.slice(0, N); + const { eigenvectors: V } = simultaneous_poweriteration(CI_M, d + 1, eig_args); + // Skip the first eigenvector (the ones vector corresponding to eigenvalue C) + this.Y = Matrix.from(V.slice(1, 1 + d)).T; + + // return embedding + return this.projection; } - /** @type {number[]} */ - const medoids = []; - - // first medoid: select from a random sample of size n - let best_j = -1; - let min_td = Infinity; - let S = randomizer.choice(indices, n); - for (let j = 0; j < S.length; ++j) { - let td = 0; - const S_j = S[j]; - const x_j = A[S_j]; - for (let o = 0; o < S.length; ++o) { - if (o === j) continue; - td += this._get_distance(S_j, S[o], x_j, A[S[o]]); - } - if (td < min_td) { - min_td = td; - best_j = S_j; - } - } - medoids.push(best_j); - - // other medoids: greedy additive selection (Algorithm LAB) - for (let i = 1; i < K; ++i) { - let best_idx = -1; - let best_delta = Infinity; - - const remainingIndices = indices.filter((idx) => !medoids.includes(idx)); - if (remainingIndices.length === 0) break; - - S = randomizer.choice(remainingIndices, Math.min(n, remainingIndices.length)); - for (let j = 0; j < S.length; ++j) { - let deltaTD = 0; - const S_j = S[j]; - const x_j = A[S_j]; - - // Estimate TD reduction on the sample S - for (let o = 0; o < S.length; ++o) { - if (o === j) continue; - const S_o = S[o]; - const x_o = A[S_o]; - - // Closest distance to current medoids - let min_d_existing = Infinity; - for (let m = 0; m < medoids.length; m++) { - const d = this._get_distance(S_o, medoids[m], x_o, A[medoids[m]]); - if (d < min_d_existing) min_d_existing = d; - } - - const delta = this._get_distance(S_j, S_o, x_j, x_o) - min_d_existing; - if (delta < 0) { - deltaTD += delta; - } - } - - if (deltaTD < best_delta) { - best_delta = deltaTD; - best_idx = S_j; - } - } - if (best_idx !== -1) { - medoids.push(best_idx); - } - } - return medoids; - } + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {T} + */ + static transform(X, parameters) { + const dr = new LLE(X, parameters); + return dr.transform(); + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new LLE(X, parameters); + yield* dr.generator(); + return dr.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new LLE(X, parameters); + return dr.transform_async(); + } } -/** @import { ParametersMeanShift } from "./index.js" */ -/** @import { InputType } from "../index.js" */ +/** @import {InputType} from "../index.js" */ +/** @import {ParametersMDS} from "./index.js" */ +/** @import {EigenArgs} from "../linear_algebra/index.js" */ /** - * Mean Shift Clustering + * Classical Multidimensional Scaling (MDS) * - * A non-parametric clustering technique that does not require prior knowledge of the - * number of clusters. It identifies centers of density in the data. + * A linear dimensionality reduction technique that seeks to preserve the + * pairwise distances between points as much as possible in the lower-dimensional + * space. * * @class - * @extends Clustering - * @category Clustering - */ -class MeanShift extends Clustering { - /** @type {number} */ - _bandwidth; - /** @type {number} */ - _max_iter; - /** @type {number} */ - _tolerance; - /** @type {(dist: number) => number} */ - _kernel; - /** @type {Matrix} */ - _points; - /** @type {number[] | undefined} */ - _clusters; - /** @type {number[][] | undefined} */ - _cluster_list; - /** - * - * @param {InputType} points - * @param {Partial} parameters - */ - constructor(points, parameters = {}) { - super( - points, - /** @type {ParametersMeanShift} */ ( - Object.assign( - { seed: 1212, metric: euclidean, bandwidth: 0, kernel: "gaussian" }, - parameters, - ) - ), - ); - - // Ensure bandwidth is positive - this._bandwidth = parameters.bandwidth ?? this._compute_bandwidth(this._matrix); - this._max_iter = parameters.max_iter ?? Math.max(10, Math.floor(10 * Math.log10(this._N))); - this._tolerance = parameters.tolerance ?? 1e-3; - const kernel_param = parameters.kernel ?? "gaussian"; - // If kernel is a string, map to function - if (typeof kernel_param === "string") { - if (kernel_param === "flat") { - this._kernel = (dist) => (dist <= this._bandwidth ? 1 : 0); - } else { - // gaussian (default) - this._kernel = (dist) => Math.exp(-(dist * dist) / (2 * this._bandwidth * this._bandwidth)); - } - } else { - // custom function - this._kernel = kernel_param; - } - - // Copy points to a mutable matrix - this._points = this._matrix.clone(); - - this._mean_shift(); - this._assign_clusters(); - } - - // Helper to compute bandwidth if not provided - /** - * @param {Matrix} matrix - * @returns {number} - */ - _compute_bandwidth(matrix) { - const N = matrix.shape[0]; - //const D = matrix.shape[1]; - // Compute average pairwise distance - let totalDist = 0; - for (let i = 0; i < N; ++i) { - const row_i = matrix.row(i); - for (let j = i + 1; j < N; ++j) { - const row_j = matrix.row(j); - const dist = this._parameters.metric(row_i, row_j); - totalDist += dist; - } - } - const avgDist = totalDist / ((N * (N - 1)) / 2); - // Use a fraction of avgDist as bandwidth - return avgDist / 2; - } - - // Compute kernel weight - /** - * @param {number} dist - * @returns {number} - */ - _kernel_weight(dist) { - return this._kernel(dist); - } - - // Perform mean shift iterations - _mean_shift() { - const N = this._N; - const D = this._D; - const points = this._points; - const metric = this._parameters.metric; - //const bandwidth = this._bandwidth; - const kernel = this._kernel_weight.bind(this); - const tolerance = this._tolerance; - - for (let iter = 0; iter < this._max_iter; ++iter) { - let max_shift = 0; - // For each point compute shift - for (let i = 0; i < N; ++i) { - const row_i = points.row(i); - let sum_weights = 0; - const weighted_sum = new Float64Array(D); - for (let j = 0; j < N; ++j) { - const row_j = points.row(j); - const dist = metric(row_i, row_j); - const weight = kernel(dist); - sum_weights += weight; - for (let d = 0; d < D; ++d) { - weighted_sum[d] += weight * row_j[d]; - } - } - if (sum_weights === 0) { - // No neighbors within kernel, shift is zero - //const shift = new Float64Array(D); - // Compute shift magnitude - const shift_norm = Math.sqrt(weighted_sum.reduce((acc, v) => acc + v * v, 0)); - max_shift = Math.max(max_shift, shift_norm); - } else { - const shift = new Float64Array(D); - for (let d = 0; d < D; ++d) { - shift[d] = weighted_sum[d] / sum_weights - row_i[d]; - } - const shift_norm = Math.sqrt(shift.reduce((acc, v) => acc + v * v, 0)); - max_shift = Math.max(max_shift, shift_norm); - // Update point - for (let d = 0; d < D; ++d) { - row_i[d] += shift[d]; - } - } - } - if (max_shift < tolerance) { - // Converged - break; - } - } - } - - // After convergence, assign clusters based on nearest mode - _assign_clusters() { - const N = this._N; - const metric = this._parameters.metric; - const bandwidth = this._bandwidth; - - // Group points that converged to the same mode - // Two points are in the same mode if they're within bandwidth/2 of each other - const mode_threshold = bandwidth * 0.5; - /** @type {number[][]} */ - const modes = []; // Each mode contains indices of points in that mode - const point_to_mode = new Array(N).fill(-1); + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction + * @see {@link PCA} for another linear alternative + */ +class MDS extends DR { + /** + * Classical MDS. + * + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + */ + constructor(X, parameters = {}) { + super(X, { d: 2, metric: euclidean, seed: 1212, eig_args: {} }, parameters); + const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); + if (!Object.hasOwn(eig_args, "seed")) { + eig_args.seed = this._randomizer; + } + } - for (let i = 0; i < N; ++i) { - if (point_to_mode[i] !== -1) continue; // Already assigned to a mode + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + *generator() { + yield this.transform(); + return this.projection; + } - const row_i = this._points.row(i); - const mode = [i]; - point_to_mode[i] = modes.length; + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {T} + */ + transform() { + const X = this.X; + const rows = X.shape[0]; + const d = /** @type {number} */ (this.parameter("d")); + const metric = /** @type {typeof euclidean | "precomputed"} */ (this.parameter("metric")); + const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); + const A = metric === "precomputed" ? X : distance_matrix(X, metric); + + const D_sq = new Matrix(rows, rows, (i, j) => { + const val = A.entry(i, j); + return val * val; + }); - // Find all points close to this mode - for (let j = i + 1; j < N; ++j) { - if (point_to_mode[j] !== -1) continue; + const ai_ = D_sq.meanCols(); + const a_j = D_sq.meanRows(); + const a__ = D_sq.mean(); - const row_j = this._points.row(j); - const dist = metric(row_i, row_j); + this._d_X = A; + const B = new Matrix(rows, rows, (i, j) => -0.5 * (D_sq.entry(i, j) - ai_[i] - a_j[j] + a__)); - if (dist < mode_threshold) { - mode.push(j); - point_to_mode[j] = modes.length; - } - } + const { eigenvectors: V } = simultaneous_poweriteration(B, d, eig_args); + this.Y = Matrix.from(V).transpose(); - modes.push(mode); + return this.projection; } - // Build final clusters - each mode becomes a cluster - /** @type {number[][]} */ - const clusters = []; - const cluster_ids = new Array(N).fill(-1); + /** @returns {number} - The stress of the projection. */ + stress() { + const N = this.X.shape[0]; + const Y = this.Y; + const d_X = this._d_X; + if (!d_X) throw new Error("First transform!"); - for (let mode_idx = 0; mode_idx < modes.length; ++mode_idx) { - const mode = modes[mode_idx]; - clusters.push([...mode]); - for (const point_idx of mode) { - cluster_ids[point_idx] = mode_idx; - } + const d_Y = new Matrix(N, N, 0); + d_Y.shape = [ + N, + N, + (i, j) => { + return i < j ? euclidean(Y.row(i), Y.row(j)) : d_Y.entry(j, i); + }, + ]; + let top_sum = 0; + let bottom_sum = 0; + for (let i = 0; i < N; ++i) { + for (let j = i + 1; j < N; ++j) { + top_sum += (d_X.entry(i, j) - d_Y.entry(i, j)) ** 2; + bottom_sum += d_X.entry(i, j) ** 2; + } + } + return Math.sqrt(top_sum / bottom_sum); } - this._clusters = cluster_ids; - this._cluster_list = clusters; - } + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X, parameters) { + const dr = new MDS(X, parameters); + return dr.transform(); + } - /** - * @returns {number[][]} - */ - get_clusters() { - // Ensure algorithm has been run - if (!this._cluster_list) { - this._mean_shift(); - this._assign_clusters(); + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new MDS(X, parameters); + yield* dr.generator(); + return dr.projection; } - return /** @type {number[][]} */ (this._cluster_list); - } - /** - * - * @returns {number[]} - */ - get_cluster_list() { - if (!this._clusters) { - this._mean_shift(); - this._assign_clusters(); + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new MDS(X, parameters); + return dr.transform_async(); } - return /** @type {number[]} */ (this._clusters); - } } -/** @import { InputType } from "../index.js" */ -/** @import { ParametersOptics } from "./index.js" */ - -/** @typedef {Object} DBEntry - * @property {Float64Array} element - * @property {number} index - * @property {number} [reachability_distance] - * @property {boolean} processed - * @property {DBEntry[]} [neighbors] - */ +/** @import {InputType} from "../index.js" */ +/** @import {ParametersLSP} from "./index.js" */ /** - * OPTICS (Ordering Points To Identify the Clustering Structure) + * Least Square Projection (LSP) * - * A density-based clustering algorithm that extends DBSCAN. It handles clusters of varying - * densities and produces a reachability plot that can be used to extract clusters. + * A dimensionality reduction technique that uses a small set of control points + * (projected with MDS) to define the projection for the rest of the data + * using a Laplacian-based optimization. * * @class - * @extends Clustering - * @category Clustering + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction */ -class OPTICS extends Clustering { - /** - * **O**rdering **P**oints **T**o **I**dentify the **C**lustering **S**tructure. - * - * @param {InputType} points - The data. - * @param {Partial} [parameters={}] - * @see {@link https://www.dbs.ifi.lmu.de/Publikationen/Papers/OPTICS.pdf} - * @see {@link https://en.wikipedia.org/wiki/OPTICS_algorithm} - */ - constructor(points, parameters = {}) { - super( - points, - /** @type {ParametersOptics} */ ( - Object.assign({ epsilon: 1, min_points: 4, metric: euclidean }, parameters) - ), - ); - const matrix = this._matrix; +class LSP extends DR { /** - * @private - * @type {DBEntry[]} + * Least Squares Projection. + * + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + * @see {@link https://ieeexplore.ieee.org/document/4378370} + */ + constructor(X, parameters) { + super( + X, + { + neighbors: -Infinity, + control_points: -Infinity, + d: 2, + metric: euclidean, + seed: 1212, + }, + parameters, + ); + if (this.parameter("neighbors") === -Infinity) { + this.parameter("neighbors", Math.min(Math.max(Math.floor(this._N / 10), 2), this._N - 1)); + } + if (this.parameter("control_points") === -Infinity) { + this.parameter("control_points", Math.min(Math.ceil(Math.sqrt(this._N)), this._N - 1)); + } + this._is_initialized = false; + } + + /** + * @returns {LSP} + */ + // init(DR = MDS, DR_parameters = {}, KNN = BallTree) { + init() { + const DR = MDS; + let DR_parameters = {}; + const KNN = BallTree; + if (this._is_initialized) return this; + const X = this.X; + const N = this._N; + const K = /** @type {number} */ (this.parameter("neighbors")); + const d = /** @type {number} */ (this.parameter("d")); + const seed = /** @type {number} */ (this.parameter("seed")); + const metric = /** @type {typeof euclidean} */ (this.parameter("metric")); + DR_parameters = Object.assign({ d, metric, seed }, DR_parameters); + const nc = /** @type {number} */ (this.parameter("control_points")); + const control_points = new KMedoids(X, { K: nc, metric }).get_medoids(); + const C = new Matrix(nc, N, "zeros"); + control_points.forEach((c_i, i) => { + C.set_entry(i, c_i, 1); + }); + + const control_points_matrix = Matrix.from(control_points.map((c_i) => X.row(c_i))); + const Y_C = new DR(control_points_matrix, DR_parameters).transform(); + + const XA = X.to2dArray(); + const knn = new KNN(XA, { metric, seed }); + const L = new Matrix(N, N, "I"); + const alpha = -1 / K; + XA.forEach((x_i, i) => { + for (const { index: j } of knn.search(x_i, K)) { + if (i === j) continue; + L.set_entry(i, j, alpha); + } + }); + const A = L.concat(C, "vertical"); + + const z = new Matrix(N, d, "zeros"); + const b = z.concat(Y_C, "vertical"); + + this._A = A; + this._b = b; + this._is_initialized = true; + return this; + } + + /** + * Computes the projection. + * + * @returns {T} Returns the projection. */ - this._ordered_list = []; - const ordered_list = this._ordered_list; - /** @type {number[][]} */ - this._clusters = []; - const clusters = this._clusters; + transform() { + this.check_init(); + const A = this._A; + const b = this._b; - const N = this._N; + if (!A || !b) throw new Error("Call init() first!"); + const ATA = A.transDot(A); + const ATb = A.transDot(b); + this.Y = Matrix.solve_CG(ATA, ATb, this._randomizer); + return this.projection; + } /** - * @private - * @type {DBEntry[]} - */ - this._DB = new Array(N).fill(0).map((_, i) => { - return { - element: matrix.row(i), - index: i, - reachability_distance: undefined, - processed: false, - }; - }); - const DB = this._DB; - - this._cluster_index = 0; - let cluster_index = this._cluster_index; - - for (const p of DB) { - if (p.processed) continue; - p.neighbors = this._get_neighbors(p); - p.processed = true; - clusters.push([p.index]); - cluster_index = clusters.length - 1; - ordered_list.push(p); - if (this._core_distance(p) !== undefined) { - const seeds = new Heap(null, (d) => d.reachability_distance, "min"); - this._update(p, seeds); - this._expand_cluster(seeds, clusters[cluster_index]); - } - } - } - - /** - * @private - * @param {DBEntry} p - A point of the data. - * @returns {DBEntry[]} An array consisting of the `epsilon`-neighborhood of `p`. - */ - _get_neighbors(p) { - if (p?.neighbors) return p.neighbors; - const DB = this._DB; - const metric = this._parameters.metric; - const epsilon = this._parameters.epsilon; - const neighbors = []; - for (const q of DB) { - if (q.index === p.index) continue; - if (metric(p.element, q.element) <= epsilon) { - neighbors.push(q); - } - } - return neighbors; - } - - /** - * @private - * @param {DBEntry} p - A point of `matrix`. - * @returns {number|undefined} The distance to the `min_points`-th nearest point of `p`, or undefined if the - * `epsilon`-neighborhood has fewer elements than `min_points`. - */ - _core_distance(p) { - const min_points = this._parameters.min_points; - const metric = this._parameters.metric; - // Need min_points - 1 other points plus the point itself - if (!p.neighbors || p.neighbors.length < min_points - 1) { - return undefined; - } - // Sort neighbors by distance to find the MinPts-th closest - const sortedNeighbors = p.neighbors.toSorted( - (a, b) => metric(p.element, a.element) - metric(p.element, b.element), - ); - // MinPts-th closest is at index min_points - 2 (0-indexed, excluding p itself) - return metric(p.element, sortedNeighbors[min_points - 2].element); - } - - /** - * Updates the reachability distance of the points. - * - * @private - * @param {DBEntry} p - * @param {Heap} seeds - */ - _update(p, seeds) { - const metric = this._parameters.metric; - const core_distance = this._core_distance(p); - // If p is not a core point, don't update seeds - if (core_distance === undefined) { - return; - } - const neighbors = this._get_neighbors(p); //p.neighbors; - for (const q of neighbors) { - if (q.processed) continue; - const new_reachability_distance = Math.max(core_distance, metric(p.element, q.element)); - //if (q.reachability_distance == undefined) { // q is not in seeds - if (seeds.raw_data().findIndex((d) => d.element === q) < 0) { - q.reachability_distance = new_reachability_distance; - seeds.push(q); - } else { - // q is in seeds - if (new_reachability_distance < (q.reachability_distance ?? Infinity)) { - q.reachability_distance = new_reachability_distance; - seeds = Heap.heapify(seeds.data(), (d) => d.reachability_distance ?? Infinity, "min"); // seeds change key =/ - } - } - } - } - - /** - * Expands the `cluster` with points in `seeds`. - * - * @private - * @param {Heap} seeds - * @param {number[]} cluster - */ - _expand_cluster(seeds, cluster) { - const ordered_list = this._ordered_list; - while (!seeds.empty) { - const q = /** @type {{ element: DBEntry, value: number}} */ (seeds.pop()).element; - q.neighbors = this._get_neighbors(q); - q.processed = true; - cluster.push(q.index); - ordered_list.push(q); - if (this._core_distance(q) !== undefined) { - this._update(q, seeds); - // Recursive call removed - while loop handles iteration correctly - } - } - } - - /** - * Returns an array of clusters. - * - * @returns {number[][]} Array of clusters with the indices of the rows in given `matrix`. - */ - get_clusters() { - const clusters = []; - const outliers = []; - const min_points = this._parameters.min_points; - for (const cluster of this._clusters) { - if (cluster.length < min_points) { - outliers.push(...cluster); - } else { - clusters.push(cluster); - } - } - clusters.push(outliers); - return clusters; - } - - /** - * @returns {number[]} Returns an array, where the ith entry defines the cluster affirmation of the ith point of - * given data. (-1 stands for outlier) - */ - get_cluster_list() { - const N = this._matrix.shape[0]; - /** @type {number[]} */ - const result = new Array(N).fill(0); - const clusters = this.get_clusters(); - for (let i = 0, n = clusters.length; i < n; ++i) { - const cluster = clusters[i]; - for (const index of cluster) { - result[index] = i < n - 1 ? i : -1; - } + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X, parameters) { + const dr = new LSP(X, parameters); + return dr.transform(); } - return result; - } -} -/** @import { InputType } from "../index.js" */ -/** @import { ParametersXMeans } from "./index.js" */ + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new LSP(X, parameters); + yield* dr.generator(); + return dr.projection; + } -/** - * @typedef SplitResult - * @property {number} index - Index of the cluster being split - * @property {number} bic_parent - BIC score of the parent cluster - * @property {number} bic_children - BIC score of the split children - * @property {number[][]} child_clusters - Clusters after splitting - * @property {Float64Array[]} child_centroids - Centroids of child clusters - */ + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new LSP(X, parameters); + return dr.transform_async(); + } +} -/** - * @typedef CandidateResult - * @property {KMeans} kmeans - The KMeans instance for this K - * @property {number} score - BIC score - */ +/** @import {InputType} from "../index.js" */ +/** @import {ParametersLTSA} from "./index.js" */ +/** @import {EigenArgs} from "../linear_algebra/index.js" */ /** - * X-Means Clustering + * Local Tangent Space Alignment (LTSA) * - * An extension of K-Means that automatically determines the number of clusters (K) - * using the Bayesian Information Criterion (BIC). + * A nonlinear dimensionality reduction algorithm that represents the local + * geometry of the manifold by tangent spaces and then aligns them to reveal + * the global structure. * * @class - * @extends Clustering - * @category Clustering + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction */ -class XMeans extends Clustering { - /** - * XMeans clustering algorithm that automatically determines the optimal number of clusters. - * - * X-Means extends K-Means by starting with a minimum number of clusters and iteratively - * splitting clusters to improve the Bayesian Information Criterion (BIC). - * - * Algorithm: - * 1. Start with K_min clusters using KMeans - * 2. For each cluster, try splitting it into 2 sub-clusters - * 3. If BIC improves after splitting, keep the split - * 4. Run KMeans again with all (old + new) centroids - * 5. Repeat until K_max is reached or no more improvements - * - * @param {InputType} points - The data points to cluster - * @param {Partial} [parameters={}] - Configuration parameters - * @see {@link https://www.cs.cmu.edu/~dpelleg/download/xmeans.pdf} - * @see {@link https://github.com/annoviko/pyclustering/blob/master/pyclustering/cluster/xmeans.py} - * @see {@link https://github.com/haifengl/smile/blob/master/core/src/main/java/smile/clustering/XMeans.java} - */ - constructor(points, parameters = {}) { - const defaults = { - K_max: 10, - K_min: 2, - metric: euclidean, - seed: 1212, - min_cluster_size: 35, - tolerance: 0.001, - }; - super(points, /** @type {ParametersXMeans} */ (Object.assign(defaults, parameters))); - this._randomizer = new Randomizer(this._parameters.seed); - - /** @type {KMeans | null} */ - this._best_kmeans = null; - - // Run XMeans algorithm - this._run(); - } - - /** - * Run the XMeans algorithm - * - * @private - */ - _run() { - /** @type {Map} */ - const candidates = new Map(); - const A = this._matrix; - - // Initialize with K_min clusters - let current_kmeans = new KMeans(this._points, { - K: this._parameters.K_min, - metric: this._parameters.metric, - seed: this._parameters.seed, - }); - - let K = this._parameters.K_min; - - candidates.set(K, { - kmeans: current_kmeans, - score: -Infinity, - }); - - // Iteratively improve clustering - while (K < this._parameters.K_max) { - const clusters = current_kmeans.get_clusters(); - const centroids = current_kmeans.centroids; - - // Try splitting each cluster - /** @type {SplitResult[]} */ - const split_results = []; - - for (let j = 0; j < clusters.length; ++j) { - const cluster = clusters[j]; - - // Skip small clusters - need enough points for reliable BIC - if (cluster.length < this._parameters.min_cluster_size) { - continue; - } - - // Get subset data for this cluster - /** @type {number[][]} */ - const subset_points = cluster.map((idx) => { - const row = A.row(idx); - return Array.from(row); - }); - - // Calculate BIC for parent (single cluster) - const parent_bic = this._bic([cluster], [centroids[j]]); - - // Run KMeans with K=2 on subset - const subset_kmeans = new KMeans(subset_points, { - K: 2, - metric: this._parameters.metric, - seed: this._randomizer.seed, - }); +class LTSA extends DR { + /** + * Local Tangent Space Alignment + * + * @param {T} X - The high-dimensional data. + * @param {Partial} parameters - Object containing parameterization of the DR method. + * @see {@link https://epubs.siam.org/doi/abs/10.1137/S1064827502419154} + */ + constructor(X, parameters) { + super( + X, + { + neighbors: -Infinity, + d: 2, + metric: euclidean, + seed: 1212, + eig_args: {}, + }, + parameters, + ); + if (this.parameter("neighbors") === -Infinity) { + this.parameter("neighbors", Math.min(Math.max(Math.floor(this._N / 10), 2), this._N - 1)); + } + const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); + if (!Object.hasOwn(eig_args, "seed")) { + eig_args.seed = this._randomizer; + } - const child_clusters_local = subset_kmeans.get_clusters(); - const child_centroids = subset_kmeans.centroids; + const d = /** @type {number} */ (this.parameter("d")); + if (this._D <= d) { + throw new Error( + `Dimensionality of X (D = ${this._D}) must be greater than the required dimensionality of the result (d = ${d})!`, + ); + } + } - // Map local indices back to global indices - /** @type {number[][]} */ - const child_clusters_global = child_clusters_local.map((local_cluster) => - local_cluster.map((local_idx) => cluster[local_idx]), - ); + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + *generator() { + yield this.transform(); + return this.projection; + } - // Calculate BIC for children (split into 2 clusters) - const children_bic = this._bic(child_clusters_global, child_centroids); + /** + * Transforms the inputdata `X` to dimenionality `d`. + * + * @returns {T} + */ + transform() { + const X = this.X; + const [rows, D] = X.shape; + const neighbors = /** @type {number} */ (this.parameter("neighbors")); + const d = /** @type {number} */ (this.parameter("d")); + const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); + const metric = /** @type {typeof euclidean} */ (this.parameter("metric")); + // 1.1 determine k nearest neighbors + const nN = k_nearest_neighbors(X, neighbors, metric); + // center matrix + const O = new Matrix(D, D, "center"); + const B = new Matrix(rows, rows, 0); - split_results.push({ - index: j, - bic_parent: parent_bic, - bic_children: children_bic, - child_clusters: child_clusters_global, - child_centroids: child_centroids, - }); - } - - // Keep all splits that improve BIC (BIC_children > BIC_parent) - /** @type {SplitResult[]} */ - const accepted_splits = split_results.filter( - (result) => result.bic_children > result.bic_parent, - ); - - // If no splits improve BIC, we're done - if (accepted_splits.length === 0) { - break; - } - - // Build new centroids array: keep non-split centroids + add split centroids - /** @type {Float64Array[]} */ - const new_centroids = []; - const split_indices = new Set(); - - // Sort accepted splits by improvement (descending) - accepted_splits.sort( - (a, b) => b.bic_children - b.bic_parent - (a.bic_children - a.bic_parent), - ); - - for (const split of accepted_splits) { - if (centroids.length + split_indices.size + 1 <= this._parameters.K_max) { - split_indices.add(split.index); - } else { - break; + for (let row = 0; row < rows; ++row) { + // 1.2 compute the d largest eigenvectors of the correlation matrix + const I_i = [row, ...nN[row].map((n) => n.j)]; + let X_i = Matrix.from(I_i.map((n) => X.row(n))); + // center X_i + X_i = X_i.dot(O); + // correlation matrix + const C = X_i.dotTrans(X_i); + const { eigenvectors: g } = simultaneous_poweriteration(C, d, eig_args); + //g.push(linspace(0, k).map(_ => 1 / Math.sqrt(k + 1))); + const G_i_t = Matrix.from(g); + // 2. Constructing alignment matrix + const W_i = G_i_t.transDot(G_i_t).add(1 / Math.sqrt(neighbors + 1)); + for (let i = 0; i < neighbors + 1; ++i) { + for (let j = 0; j < neighbors + 1; ++j) { + B.add_entry(I_i[i], I_i[j], W_i.entry(i, j) - (i === j ? 1 : 0)); + } + } } - } - for (let i = 0; i < centroids.length; ++i) { - if (split_indices.has(i)) { - // This cluster was split - add both child centroids - const split_result = accepted_splits.find((s) => s.index === i); - if (split_result) { - new_centroids.push(...split_result.child_centroids); - } - } else { - // This cluster wasn't split - keep its centroid - new_centroids.push(centroids[i]); - } - } - - // Run KMeans on full dataset with new centroids as initialization - // This is crucial - we need to reassign all points to all clusters - const newK = new_centroids.length; - - // Create a new KMeans instance with K set to new number of clusters - current_kmeans = new KMeans(this._matrix, { - K: newK, - metric: this._parameters.metric, - seed: this._randomizer.seed, - initial_centroids: new_centroids, - }); - - // Store the candidate with the BIC of the FULL dataset - candidates.set(newK, { - kmeans: current_kmeans, - score: this._bic(current_kmeans.get_clusters(), current_kmeans.centroids), - }); - - K = newK; - } - - // Select best candidate based on BIC score - this._best_kmeans = this._select_best_candidate(candidates); - } + // 3. Aligning global coordinates + const { eigenvectors: Y } = simultaneous_poweriteration(B, d + 1, eig_args); + this.Y = Matrix.from(Y.slice(1)).transpose(); - /** - * Select the best candidate based on BIC score - * - * @private - * @param {Map} candidates - * @returns {KMeans} - */ - _select_best_candidate(candidates) { - if (candidates.size === 0) { - throw new Error("No candidates found"); - } - - const first_candidate = candidates.get(this._parameters.K_min); - if (!first_candidate) { - throw new Error("Missing initial candidate"); - } - - let best_score = first_candidate.score; - /** @type {KMeans} */ - let best_kmeans = first_candidate.kmeans; - - for (const candidate of candidates.values()) { - if (candidate.score > best_score) { - best_score = candidate.score; - best_kmeans = candidate.kmeans; - } - } - - return best_kmeans; - } - - /** - * Calculate Bayesian Information Criterion for a set of clusters. - * - * Uses Kass's formula for BIC calculation: - * BIC(θ) = L(D) - 0.5 * p * ln(N) - * - * Where: - * - L(D) is the log-likelihood of the data - * - p is the number of free parameters: (K-1) + D*K + 1 - * - N is the total number of points - * - * @private - * @param {number[][]} clusters - Array of clusters with point indices - * @param {Float64Array[]} centroids - Array of centroids - * @returns {number} BIC score (higher is better) - */ - _bic(clusters, centroids) { - const A = this._matrix; - const D = this._D; - const K = centroids.length; - - let total_variance = 0; - let N = 0; - - // Calculate total variance (sum of squared distances) - for (let i = 0; i < K; ++i) { - const cluster = clusters[i]; - const centroid = centroids[i]; - N += cluster.length; - - for (let j = 0; j < cluster.length; ++j) { - const point_idx = cluster[j]; - const point = A.row(point_idx); - // Sum of squared distances (variance term) - total_variance += euclidean_squared(centroid, point); - } - } - - // Not enough points for meaningful BIC - if (N <= K) { - return -Infinity; - } - - // Estimate variance (ML estimate) - const variance = total_variance / (N - K); - - // Handle case of zero variance (all points identical) - if (variance <= 0) { - return -Infinity; - } - - // Number of free parameters: (K-1) cluster weights + K*D centroid coordinates + 1 variance - const p = K - 1 + D * K + 1; - - // Calculate log-likelihood - let log_likelihood = 0; - const log_2pi = Math.log(2 * Math.PI); - - for (let i = 0; i < K; ++i) { - const n = clusters[i].length; - if (n <= 1) continue; - - // Log-likelihood for cluster i - const cluster_log_likelihood = - n * Math.log(n / N) - 0.5 * n * log_2pi - 0.5 * n * D * Math.log(variance) - 0.5 * (n - 1); - - log_likelihood += cluster_log_likelihood; - } - - // BIC = log_likelihood - 0.5 * p * ln(N) - return log_likelihood - 0.5 * p * Math.log(N); - } - - /** - * Get the computed clusters - * - * @returns {number[][]} Array of clusters, each containing indices of points - */ - get_clusters() { - if (!this._best_kmeans) { - throw new Error("XMeans has not been run"); - } - return this._best_kmeans.get_clusters(); - } - - /** @returns {number[]} The cluster list */ - get_cluster_list() { - if (!this._best_kmeans) { - throw new Error("XMeans has not been run"); - } - return this._best_kmeans.get_cluster_list(); - } - - /** - * Get the final centroids - * - * @returns {Float64Array[]} Array of centroids - */ - get centroids() { - if (!this._best_kmeans) { - throw new Error("XMeans has not been run"); - } - return this._best_kmeans.centroids; - } - - /** - * Get the optimal number of clusters found - * - * @returns {number} The number of clusters - */ - get k() { - if (!this._best_kmeans) { - throw new Error("XMeans has not been run"); - } - return this._best_kmeans.k; - } -} + // return embedding + return this.projection; + } -/** @import {InputType} from "../index.js" */ + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {T} + */ + static transform(X, parameters) { + const dr = new LTSA(X, parameters); + return dr.transform(); + } -/** - * @abstract - * @template {InputType} T - * @template {{ seed?: number }} Para - * - * Base class for all Dimensionality Reduction (DR) algorithms. - * - * Provides a common interface for parameters management, data initialization, - * and transformation (both synchronous and asynchronous). - * - * @class - */ -class DR { - /** @type {number} */ - _D; - /** @type {number} */ - _N; - /** @type {Randomizer} */ - _randomizer; - /** @type {boolean} */ - _is_initialized; - - /** - * Takes the default parameters and seals them, remembers the type of input `X`, and initializes the random number - * generator. - * - * @param {T} X - The high-dimensional data. - * @param {Para} default_parameters - Object containing default parameterization of the DR method. - * @param {Partial} parameters - Object containing parameterization of the DR method to override defaults. - */ - constructor(X, default_parameters, parameters = {}) { - /** @type {T} */ - this.__input = X; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new LTSA(X, parameters); + yield* dr.generator(); + return dr.projection; + } - /** @type {Para} */ - this._parameters = /** @type {Para} */ Object.seal({ - ...default_parameters, - ...parameters, - }); - /** @type {"array" | "matrix" | "typed"} */ - this._type; - /** @type {Matrix} */ - this.X; - /** @type {Matrix} */ - this.Y; - - if (Array.isArray(X)) { - if (X[0] instanceof Float64Array) { - this._type = "typed"; - } else { - this._type = "array"; - } - this.X = Matrix.from(X); - } else if (X instanceof Matrix) { - this._type = "matrix"; - this.X = X; - } else { - throw new Error("No valid type for X!"); - } - const [N, D] = this.X.shape; - this._N = N; - this._D = D; - this._randomizer = new Randomizer(this._parameters.seed); - this._is_initialized = false; - } - - /** - * Get all Parameters. - * @overload - * @returns {Para} - */ - /** - * Get value of given parameter. - * @template {keyof Para} K - * @overload - * @param {K} name - Name of the parameter. - * @returns {Para[K]} - */ - /** - * Set value of given parameter. - * @template {keyof Para} K - * @overload - * @param {K} name - Name of the parameter. - * @param {Para[K]} value - Value of the parameter to set. - * @returns {this} - */ - /** - * @param {keyof Para} [name] - Name of the parameter. If null, returns all parameters as an Object. - * @param {Para[keyof Para]} [value] - Value of the parameter to set. If name is set and value is not given, returns the - * current value. - * @returns {Para | Para[keyof Para] | this} On setting a parameter, returns the DR object. If name is set and value is not - * given, returns the parameter value. If name is null, returns all parameters. On setting a parameter, this - * function returns the DR object. If `name` is set and `value == null` then return actual parameter value. If - * `name` is not given, then returns all parameters as an Object. - * @example - * ```js - * const DR = new druid.TSNE(X, {d: 3}); // creates a new DR object, with parameter for `d = 3`. - * DR.parameter("d"); // returns 3 - * DR.parameter("d", 2); // sets parameter `d` to 2 and returns `DR`. - * ``` - * - */ - parameter(name, value) { - if (name === undefined && value === undefined) { - return Object.assign({}, this._parameters); - } - if (name && !Object.hasOwn(this._parameters, name)) { - throw new Error(`${String(name)} is not a valid parameter!`); - } - if (name && value !== undefined) { - this._parameters[name] = value; - this._is_initialized = false; - return this; - } else if (name) { - return this._parameters[name]; - } - throw new Error("Should not happen!"); - } - - /** - * Computes the projection. - * - * @abstract - * @param {...unknown} args - * @returns {T} The projection. - */ - transform(...args) { - this.check_init(); - return this.projection; - } - - /** - * Computes the projection. - * - * @template {InputType} T - * @template {{ seed?: number }} Para - * @param {T} X - * @param {Para} parameters - * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method. - * @returns {T} The dimensionality reduced dataset. - */ - static transform(X, parameters, ...args) { - const dr = new DR(X, parameters, parameters); - return /** @type {T} */ (dr.transform()); - } - - /** - * Computes the projection. - * - * @abstract - * @param {...unknown} args - * @returns {Generator} The intermediate steps of the projection. - */ - *generator(...args) { - const R = this.transform(...args); - yield R; - return R; - } - - /** - * Computes the projection. - * - * @template {{ seed?: number }} Para - * @param {InputType} X - * @param {Para} parameters - * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method. - * @returns {Generator} A generator yielding the intermediate steps of the dimensionality - * reduction method. - */ - static *generator(X, parameters, ...args) { - const dr = new DR(X, parameters, parameters); - const generator = dr.generator(...args); - let result; - do { - result = generator.next(); - yield result.value; - } while (!result.done); - - return result.value; - } - - /** - * @abstract - * @param {...unknown} args - */ - init(...args) {} - - /** - * If the respective DR method has an `init` function, call it before `transform`. - * - * @returns {DR} - */ - check_init() { - if (!this._is_initialized && typeof this.init === "function") { - this.init(); - this._is_initialized = true; - } - return this; - } - - /** @returns {T} The projection in the type of input `X`. */ - get projection() { - if (Object.hasOwn(this, "Y")) { - this.check_init(); - //return this._type === "matrix" ? this.Y : this.Y.to2dArray(); - if (this._type === "matrix") { - return /** @type {T} */ (/** @type {any} */ (this.Y)); - } else if (this._type === "typed") { - return /** @type {T} */ (/** @type {any} */ (this.Y.to2dArray())); - } else { - return /** @type {T} */ (/** @type {any} */ (this.Y.asArray())); - } - } else { - throw new Error("The dataset is not transformed yet!"); - } - } - - /** - * Computes the projection. - * - * @param {...unknown} args - Arguments the transform method of the respective DR method takes. - * @returns {Promise} The dimensionality reduced dataset. - */ - async transform_async(...args) { - return this.transform(...args); - } - - /** - * Computes the projection. - * - * @template {{ seed?: number }} Para - * @param {InputType} X - * @param {Para} parameters - * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method. - * @returns {Promise} A promise yielding the dimensionality reduced dataset. - */ - static async transform_async(X, parameters, ...args) { - return DR.transform(X, parameters, ...args); - } + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new LTSA(X, parameters); + return dr.transform_async(); + } } -/** @import { InputType } from "../index.js" */ -/** @import { ParametersFASTMAP } from "./index.js"; */ +/** @import {InputType} from "../index.js" */ +/** @import {ParametersPCA, ParametersMDS, ParametersSAMMON} from "./index.js" */ +/** @typedef {"PCA" | "MDS" | "random"} AvailableInit */ + +/** @typedef {{ PCA: ParametersPCA; MDS: ParametersMDS; random: {} }} ChooseDR */ /** - * FastMap algorithm for dimensionality reduction. + * Sammon's Mapping * - * A very fast algorithm for projecting high-dimensional data into a lower-dimensional - * space while preserving pairwise distances. It works similarly to PCA but uses - * only a subset of the data to find projection axes. + * A nonlinear dimensionality reduction technique that minimizes a stress + * function based on the ratio of pairwise distances in high and low dimensional spaces. * * @class * @template {InputType} T - * @extends DR + * @extends DR> * @category Dimensionality Reduction */ -class FASTMAP extends DR { - /** - * FastMap: a fast algorithm for indexing, data-mining and visualization of traditional and multimedia datasets. - * @param {T} X - The high-dimensional data. - * @param {Partial} parameters - Object containing parameterization of the DR method. - * @see {@link https://doi.org/10.1145/223784.223812} - */ - constructor(X, parameters) { - super(X, { d: 2, metric: euclidean, seed: 1212 }, parameters); - } - - /** - * Chooses two points which are the most distant in the actual projection. - * - * @private - * @param {(a: number, b: number) => number} dist - * @returns {[number, number, number]} An array consisting of first index, second index, and distance between the - * two points. - */ - _choose_distant_objects(dist) { - const X = this.X; - const N = X.shape[0]; - let a_index = this._randomizer.random_int % N; - /** @type {number | null} */ - let b_index = null; - let max_dist = -Infinity; - for (let i = 0; i < N; ++i) { - const d_ai = dist(a_index, i); - if (d_ai > max_dist) { - max_dist = d_ai; - b_index = i; - } - } - if (b_index === null) throw new Error("should not happen!"); - max_dist = -Infinity; - for (let i = 0; i < N; ++i) { - const d_bi = dist(b_index, i); - if (d_bi > max_dist) { - max_dist = d_bi; - a_index = i; - } - } - return [a_index, b_index, max_dist]; - } - - /** - * Computes the projection. - * - * @returns {T} The `d`-dimensional projection of the data matrix `X`. - */ - transform() { - const X = this.X; - const N = X.shape[0]; - const d = /** @type {number} */ (this._parameters.d); - const metric = /** @type {typeof euclidean} */ (this._parameters.metric); - const Y = new Matrix(N, d, 0); - /** @type {(a: number, b: number) => number} */ - let dist = (a, b) => metric(X.row(a), X.row(b)); - - for (let _col = 0; _col < d; ++_col) { - const old_dist = dist; - // choose pivot objects - const [a_index, b_index, d_ab] = this._choose_distant_objects(dist); - if (d_ab !== 0) { - // project the objects on the line (O_a, O_b) - for (let i = 0; i < N; ++i) { - const d_ai = dist(a_index, i); - const d_bi = dist(b_index, i); - const y_i = (d_ai ** 2 + d_ab ** 2 - d_bi ** 2) / (2 * d_ab); - Y.set_entry(i, _col, y_i); - } - // consider the projections of the objects on a - // hyperplane perpendicluar to the line (a, b); - // the distance function D'() between two - // projections is given by Eq.4 - dist = (a, b) => - Math.sqrt(old_dist(a, b) ** 2 - (Y.entry(a, _col) - Y.entry(b, _col)) ** 2); - } - } - // return embedding. - this.Y = Y; - return this.projection; - } - - *generator() { - yield this.transform(); - return this.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {T} - */ - static transform(X, parameters) { - const dr = new FASTMAP(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new FASTMAP(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new FASTMAP(X, parameters); - return dr.transform_async(); - } -} - -/** - * Base class for all K-Nearest Neighbors (KNN) search algorithms. - * - * Provides a common interface for elements management and search operations. - * - * @abstract - * @category KNN - * @template {number[] | Float64Array} T - Type of elements - * @template {Object} Para - Type of parameters - * @class - */ -class KNN { - /** @type {T[]} */ - _elements; - /** @type {Para} */ - _parameters; - /** @type {"typed" | "array"} */ - _type; - - /** - * @param {T[]} elements - * @param {Para} parameters - */ - constructor(elements, parameters) { - if (elements.length === 0) throw new Error("Elements needs to contain at least one element!"); - if (elements[0] instanceof Float64Array) { - this._type = "typed"; - } else { - this._type = "array"; - } - this._parameters = parameters; - this._elements = elements; - } - - /** - * @abstract - * @param {T} t - * @param {number} k - * @returns {{ element: T; index: number; distance: number }[]} - */ - search(t, k) { - throw new Error("The function search must be implemented!"); - } - - /** - * @abstract - * @param {number} i - * @param {number} k - * @returns {{ element: T; index: number; distance: number }[]} - */ - search_by_index(i, k) { - throw new Error("The function search_by_index must be implemented!"); - } -} - -/** @import { Metric } from "../metrics/index.js" */ -/** @import { ParametersAnnoy } from "./index.js" */ +class SAMMON extends DR { + /** @type {Matrix | undefined} */ + distance_matrix; -/** - * @template {number[] | Float64Array} T - * @typedef {Object} AnnoyNode - * @property {boolean} isLeaf - Whether this is a leaf node - * @property {number[]} indices - Indices of points in this node (leaf) or children (internal) - * @property {number[]} normal - Hyperplane normal vector (internal nodes only) - * @property {number} offset - Hyperplane offset (internal nodes only) - * @property {AnnoyNode | null} left - Left child (internal nodes only) - * @property {AnnoyNode | null} right - Right child (internal nodes only) - */ + /** + * SAMMON's Mapping + * + * @param {T} X - The high-dimensional data. + * @param {Partial>} [parameters] - Object containing parameterization of the DR + * method. + * @see {@link https://arxiv.org/pdf/2009.01512.pdf} + */ + constructor(X, parameters) { + super( + X, + { + magic: 0.1, + d: 2, + metric: euclidean, + seed: 1212, + init_DR: "random", + init_parameters: {}, + }, + parameters, + ); + } -/** - * Annoy-style (Approximate Nearest Neighbors Oh Yeah) implementation using Random Projection Trees. - * - * This implementation builds multiple random projection trees where each tree randomly selects - * two points and splits the space based on a hyperplane equidistant between them. - * - * Key features: - * - Multiple random projection trees for better recall - * - Each tree uses random hyperplanes for splitting - * - Priority queue search for better recall - * - Combines results from all trees - * - * Best suited for: - * - High-dimensional data - * - Approximate nearest neighbor search - * - Large datasets - * - When high recall is needed with approximate methods - * - * @class - * @category KNN - * @template {number[] | Float64Array} T - * @extends KNN - * @see {@link https://github.com/spotify/annoy} - * @see {@link https://erikbern.com/2015/09/24/nearest-neighbors-and-vector-models-epilogue-curse-of-dimensionality.html} - */ -class Annoy extends KNN { - /** - * Creates a new Annoy-style index with random projection trees. - * - * @param {T[]} elements - Elements to index - * @param {ParametersAnnoy} [parameters={}] - Configuration parameters - */ - constructor( - elements, - parameters = { - metric: euclidean, - numTrees: 10, - maxPointsPerLeaf: 10, - seed: 1212, - }, - ) { - // Handle empty initialization - use dummy element - const hasElements = elements && elements.length > 0; - const firstElement = /** @type {T} */ (hasElements ? elements[0] : new Float64Array([0])); - - super([firstElement], parameters); - - this._metric = this._parameters.metric ?? euclidean; - this._numTrees = this._parameters.numTrees ?? 10; - this._maxPointsPerLeaf = this._parameters.maxPointsPerLeaf ?? 10; - this._seed = this._parameters.seed ?? 1212; - this._randomizer = new Randomizer(this._seed); + /** + * Initializes the projection. + * + * @param {Matrix | undefined} D + * @returns {asserts D is Matrix} + */ + init(D) { + const N = this.X.shape[0]; + const d = /** @type {number} */ (this.parameter("d")); + const metric = /** @type {typeof euclidean | "precomputed"} */ (this.parameter("metric")); + const init_DR = /** @type {AvailableInit} */ (this.parameter("init_DR")); + const DR_parameters = this.parameter("init_parameters"); + if (init_DR === "random") { + const randomizer = this._randomizer; + this.Y = new Matrix(N, d, () => randomizer.random); + } else if (init_DR === "PCA") { + this.Y = Matrix.from(PCA.transform(this.X, /** @type {ParametersPCA} */ (DR_parameters))); + } else if (init_DR === "MDS") { + this.Y = Matrix.from(MDS.transform(this.X, /** @type {ParametersMDS} */ (DR_parameters))); + } else { + throw new Error('init_DR needs to be either "random" or a DR method!'); + } + D = metric === "precomputed" ? Matrix.from(this.X) : distance_matrix(this.X, metric); + this.distance_matrix = D; + } /** - * @private - * @type {AnnoyNode[]} - */ - this._trees = []; - - // Build trees - if (hasElements) { - // Reset elements and rebuild properly - /** @type {T[]} */ - this._elements = []; - this._trees = []; - this.add(elements); - } - } - - /** - * Get the number of trees in the index. - * @returns {number} - */ - get num_trees() { - return this._trees.length; - } - - /** - * Get the total number of nodes in all trees. - * @returns {number} - */ - get num_nodes() { - let total = 0; - for (const tree of this._trees) { - total += this._countNodes(tree); - } - return total; - } - - /** - * @private - * @param {any} node - * @returns {number} - */ - _countNodes(node) { - if (!node) return 0; - return 1 + this._countNodes(node.left) + this._countNodes(node.right); - } - - /** - * Add elements to the Annoy index. - * @param {T[]} elements - * @returns {this} - */ - add(elements) { - // Extend elements array - this._elements = this._elements.concat(elements); - - // Rebuild all trees with new elements - this._trees = []; - this._buildTrees(); - - return this; - } - - /** - * Build all random projection trees. - * @private - */ - _buildTrees() { - const elements = this._elements; - const n = elements.length; - - for (let t = 0; t < this._numTrees; t++) { - // Create index array for this tree - const indices = Array.from({ length: n }, (_, i) => i); - const tree = this._buildTreeRecursive(indices); - this._trees.push(tree); - } - } - - /** - * Recursively build a random projection tree. - * @private - * @param {number[]} indices - Indices of elements to include - * @returns {AnnoyNode} - */ - _buildTreeRecursive(indices) { - const elements = this._elements; - - // Base case: small enough to be a leaf - if (indices.length <= this._maxPointsPerLeaf) { - return { - isLeaf: true, - indices: indices, - normal: [], - offset: 0, - left: null, - right: null, - }; - } - - // Select two random points to define the splitting hyperplane - const idx1 = indices[Math.floor(this._randomizer.random * indices.length)]; - const idx2 = indices[Math.floor(this._randomizer.random * indices.length)]; - - const point1 = elements[idx1]; - const point2 = elements[idx2]; - - // Compute normal vector (point2 - point1) - const dim = point1.length; - /** @type {number[]} */ - const normal = new Array(dim); - for (let i = 0; i < dim; i++) { - normal[i] = point2[i] - point1[i]; + * Transforms the inputdata `X` to dimensionality 2. + * + * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200` + * @returns {T} The projection of `X`. + */ + transform(max_iter = 200) { + this.check_init(); + if (!this.distance_matrix) this.init(this.distance_matrix); + for (let j = 0; j < max_iter; ++j) { + this._step(); + } + return this.projection; } - // Normalize - let norm = 0; - for (let i = 0; i < dim; i++) { - norm += normal[i] * normal[i]; - } - norm = Math.sqrt(norm); + /** + * Transforms the inputdata `X` to dimenionality 2. + * + * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200` + * @returns {Generator} A generator yielding the intermediate steps of the projection of + * `X`. + */ + *generator(max_iter = 200) { + this.check_init(); + if (!this.distance_matrix) this.init(this.distance_matrix); + + for (let j = 0; j < max_iter; ++j) { + this._step(); + yield this.projection; + } - if (norm > 1e-10) { - for (let i = 0; i < dim; i++) { - normal[i] /= norm; - } + return this.projection; } - // Compute midpoint and offset - /** @type {number[]} */ - const midpoint = new Array(dim); - for (let i = 0; i < dim; i++) { - midpoint[i] = (point1[i] + point2[i]) / 2; - } - - // Compute offset: dot(normal, midpoint) - let offset = 0; - for (let i = 0; i < dim; i++) { - offset += normal[i] * midpoint[i]; - } - - // Split points based on which side of hyperplane they fall - const leftIndices = []; - const rightIndices = []; - - for (const idx of indices) { - const point = elements[idx]; - let dot = 0; - for (let i = 0; i < dim; i++) { - dot += normal[i] * point[i]; - } - - if (dot < offset) { - leftIndices.push(idx); - } else { - rightIndices.push(idx); - } - } - - // Handle edge case where all points fall on one side - if (leftIndices.length === 0 || rightIndices.length === 0) { - return { - isLeaf: true, - indices: indices, - normal: [], - offset: 0, - left: null, - right: null, - }; - } - - // Recursively build subtrees - const left = this._buildTreeRecursive(leftIndices); - const right = this._buildTreeRecursive(rightIndices); - - return { - isLeaf: false, - indices: [], - normal: normal, - offset: offset, - left: left, - right: right, - }; - } - - /** - * Compute distance from point to hyperplane. - * @private - * @param {T} point - * @param {number[]} normal - * @param {number} offset - * @returns {number} Signed distance (positive = right side, negative = left side) - */ - _distanceToHyperplane(point, normal, offset) { - let dot = 0; - for (let i = 0; i < point.length; i++) { - dot += normal[i] * point[i]; - } - return dot - offset; - } - - /** - * Search for k approximate nearest neighbors. - * @param {T} query - * @param {number} [k=5] - * @returns {{ element: T; index: number; distance: number }[]} - */ - search(query, k = 5) { - const metric = this._metric; - const elements = this._elements; - - if (elements.length === 0) return []; - - // Collect candidates from all trees using priority queue - const candidates = new Set(); - - // Collect more candidates for better recall - // Search at least k * numTrees * 2 candidates - const minCandidates = Math.min(k * this._numTrees * 3, elements.length); - - for (const tree of this._trees) { - this._searchTreePriority(tree, query, candidates, minCandidates); - } - - // Compute exact distances for all candidates - /** @type {Heap<{ index: number; distance: number }>} */ - const best = new Heap(null, (d) => d.distance, "max"); - - for (const idx of candidates) { - const element = elements[idx]; - if (!element || element.length !== query.length) continue; - - const dist = metric(query, element); - - if (best.length < k) { - best.push({ index: idx, distance: dist }); - } else if (dist < (best.first?.value ?? Infinity)) { - best.pop(); - best.push({ index: idx, distance: dist }); - } - } - - // If we still don't have enough candidates, do a linear scan fallback - if (best.length < k) { - for (let i = 0; i < elements.length && best.length < k; i++) { - if (candidates.has(i)) continue; + _step() { + if (!this.distance_matrix) this.init(this.distance_matrix); + const MAGIC = /** @type {number} */ (this.parameter("magic")); + const D = /** @type {Matrix} */ (this.distance_matrix); + const N = this.X.shape[0]; + const d = /** @type {number} */ (this.parameter("d")); + const Y = this.Y; - const element = elements[i]; - if (!element || element.length !== query.length) continue; - - const dist = metric(query, element); - best.push({ index: i, distance: dist }); - } - } - - // Convert to result format - /** @type {{ element: T; index: number; distance: number }[]} */ - const result = []; - while (best.length > 0) { - const item = /** @type {{ element: { index: number; distance: number }; value: number }} */ ( - best.pop() - ); - result.push({ - element: elements[item.element.index], - index: item.element.index, - distance: item.value, - }); - } - - return result.reverse(); - } - - /** - * Search tree using priority queue for better recall. - * Explores nodes in order of distance to hyperplane. - * @private - * @param {AnnoyNode} node - * @param {T} query - * @param {Set} candidates - * @param {number} maxCandidates - */ - _searchTreePriority(node, query, candidates, maxCandidates) { - if (!node) return; - - // Priority queue entry: { node, distance } - /** @type {Heap<{ node: AnnoyNode; dist: number }>} */ - const pq = new Heap(null, (d) => d.dist, "min"); - pq.push({ node: node, dist: 0 }); - - while (!pq.empty && candidates.size < maxCandidates) { - const entry = pq.pop(); - if (!entry) continue; - - const currentNode = entry.element.node; - - // Leaf node: add all points - if (currentNode.isLeaf) { - for (const idx of currentNode.indices) { - candidates.add(idx); - if (candidates.size >= maxCandidates) return; - } - continue; - } - - // Internal node: compute distance to hyperplane - const dist = this._distanceToHyperplane(query, currentNode.normal, currentNode.offset); - - // Determine which side is closer - const closerSide = dist < 0 ? currentNode.left : currentNode.right; - const fartherSide = dist < 0 ? currentNode.right : currentNode.left; - - // Add closer side with priority 0 (explore first) - if (closerSide) { - pq.push({ node: closerSide, dist: 0 }); - } - - // Add farther side with priority = |dist| (explore later if needed) - if (fartherSide && candidates.size < maxCandidates) { - pq.push({ node: fartherSide, dist: Math.abs(dist) }); - } - } - } - - /** - * @param {number} i - * @param {number} [k=5] - * @returns {{ element: T; index: number; distance: number }[]} - */ - search_by_index(i, k = 5) { - if (i < 0 || i >= this._elements.length) return []; - return this.search(this._elements[i], k); - } - - /** - * Alias for search_by_index for backward compatibility. - * - * @param {number} i - Index of the query element - * @param {number} [k=5] - Number of nearest neighbors to return - * @returns {{ element: T; index: number; distance: number }[]} - */ - search_index(i, k = 5) { - return this.search_by_index(i, k); - } -} + const G = new Matrix(N, d, 0); -/** @import { Metric } from "../metrics/index.js" */ -/** @import { ParametersBallTree } from "./index.js" */ + const sum = new Float64Array(d); + for (let i = 0; i < N; ++i) { + const e1 = new Float64Array(d); + const e2 = new Float64Array(d); + const Yi = Y.row(i); + for (let j = 0; j < N; ++j) { + if (i === j) continue; + const dX = D.entry(i, j); + if (dX === 0) continue; // Skip identical points in high-dim + + const Yj = Y.row(j); + const delta = new Float64Array(d); + for (let k = 0; k < d; ++k) { + delta[k] = Yi[k] - Yj[k]; + } + const dY = Math.max(euclidean(Yi, Yj), 1e-6); + const dq = dX - dY; + const dr = dX * dY; + for (let k = 0; k < d; ++k) { + e1[k] += (delta[k] * dq) / dr; + e2[k] += (dq - (delta[k] ** 2 * (1 + dq / dY)) / dY) / dr; + } + } + for (let k = 0; k < d; ++k) { + const val = Y.entry(i, k) + ((MAGIC * e1[k]) / Math.abs(e2[k]) || 0); + G.set_entry(i, k, val); + sum[k] += val; + } + } + for (let k = 0; k < d; ++k) { + sum[k] /= N; + } -/** - * @template {number[] | Float64Array} T - * @typedef {Object} ElementWithIndex - * @property {number} index - * @property {T} element - */ + for (let i = 0; i < N; ++i) { + for (let k = 0; k < d; ++k) { + Y.set_entry(i, k, G.entry(i, k) - sum[k]); + } + } + return Y; + } -/** - * Ball Tree for efficient nearest neighbor search. - * - * A Ball Tree is a metric tree that partitions points into a nested set of - * hyperspheres (balls). It is particularly effective for high-dimensional - * data and supports any valid metric. - * - * @class - * @category KNN - * @template {number[] | Float64Array} T - * @extends KNN - */ -class BallTree extends KNN { - /** - * Generates a BallTree with given `elements`. - * - * @param {T[]} elements - Elements which should be added to the BallTree - * @param {ParametersBallTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}` - * @see {@link https://en.wikipedia.org/wiki/Ball_tree} - * @see {@link https://github.com/invisal/noobjs/blob/master/src/tree/BallTree.js} - */ - constructor(elements, parameters = { metric: euclidean, seed: 1212 }) { - super(elements, Object.assign({ seed: 1212 }, parameters)); /** - * @private - * @type {BallTreeNode | BallTreeLeaf} - */ - this._root = this._construct(elements.map((element, index) => ({ index, element }))); - } - - /** @returns {Metric} */ - get _metric() { - return this._parameters.metric; - } - - /** - * @private - * @param {ElementWithIndex[]} elements - * @returns {BallTreeNode | BallTreeLeaf} Root of balltree. - */ - _construct(elements) { - if (elements.length === 1) { - return new BallTreeLeaf(elements); - } else { - const c = this._greatest_spread(elements); - const sorted_elements = elements.sort((a, b) => a.element[c] - b.element[c]); - const n = sorted_elements.length; - const p_index = Math.floor(n / 2); - const p = sorted_elements[p_index]; - const L = sorted_elements.slice(0, p_index); - const R = sorted_elements.slice(p_index, n); - const radius = Math.max(...elements.map((d) => this._metric(p.element, d.element))); - let B; - if (L.length > 0 && R.length > 0) { - B = new BallTreeNode(p, this._construct(L), this._construct(R), radius); - } else { - B = new BallTreeLeaf(elements); - } - return B; - } - } - - /** - * @private - * @param {ElementWithIndex[]} B - * @returns {number} - */ - _greatest_spread(B) { - const d = B[0].element.length; - const start = new Array(d); - - for (let i = 0; i < d; ++i) { - start[i] = [Infinity, -Infinity]; - } - - let spread = B.reduce((acc, current) => { - for (let i = 0; i < d; ++i) { - acc[i][0] = Math.min(acc[i][0], current.element[i]); - acc[i][1] = Math.max(acc[i][1], current.element[i]); - } - return acc; - }, start); - spread = spread.map((d) => d[1] - d[0]); - - let c = 0; - for (let i = 0; i < d; ++i) { - c = spread[i] > spread[c] ? i : c; + * @template {InputType} T + * @param {T} X + * @param {Partial>} [parameters] + * @returns {T} + */ + static transform(X, parameters) { + const dr = new SAMMON(X, parameters); + return dr.transform(); } - return c; - } - - /** - * @param {number} i - * @param {number} k - */ - search_by_index(i, k = 5) { - return this.search(this._elements[i], k); - } - - /** - * @param {T} t - Query element. - * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5` - * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors. - */ - search(t, k = 5) { - /** @type {Heap>} */ - const heap = new Heap(null, (d) => this._metric(d.element, t), "max"); - this._search(t, k, heap, this._root); - - // Convert heap to result array - /** @type {{ element: T; index: number; distance: number }[]} */ - const result = []; - while (heap.length > 0) { - const item = /** @type {{ element: ElementWithIndex; value: number }} */ (heap.pop()); - result.push({ - element: item.element.element, - index: item.element.index, - distance: item.value, - }); - } - return result.reverse(); // Reverse to get closest first - } - - /** - * @private - * @param {T} t - Query element. - * @param {number} k - Number of nearest neighbors to return. - * @param {Heap>} Q - Heap consists of the currently found `k` nearest neighbors. - * @param {BallTreeNode | BallTreeLeaf} B - */ - _search(t, k, Q, B) { - if (!B) return; - - if (B instanceof BallTreeNode) { - const dist_to_pivot = this._metric(t, B.pivot.element); - if (Q.length >= k && dist_to_pivot - B.radius >= (Q.first?.value ?? -Infinity)) { - return; - } - - const c1 = B.child1; - const c2 = B.child2; - - let d1 = Infinity; - let d2 = Infinity; - - if (c1 instanceof BallTreeNode) d1 = this._metric(t, c1.pivot.element); - else if (c1 instanceof BallTreeLeaf) d1 = this._metric(t, c1.points[0].element); - - if (c2 instanceof BallTreeNode) d2 = this._metric(t, c2.pivot.element); - else if (c2 instanceof BallTreeLeaf) d2 = this._metric(t, c2.points[0].element); - - if (d1 < d2) { - if (c1) this._search(t, k, Q, c1); - if (c2) this._search(t, k, Q, c2); - } else { - if (c2) this._search(t, k, Q, c2); - if (c1) this._search(t, k, Q, c1); - } - } else if (B instanceof BallTreeLeaf) { - for (let i = 0, n = B.points.length; i < n; ++i) { - const p = B.points[i]; - const dist = this._metric(p.element, t); - if (Q.length < k) { - Q.push(p); - } else if (dist < (Q.first?.value ?? Infinity)) { - Q.pop(); - Q.push(p); - } - } - } - } -} -/** - * @private - * @template {number[] | Float64Array} T - */ -class BallTreeNode { - /** - * @param {ElementWithIndex} pivot - * @param {BallTreeNode | BallTreeLeaf | null} child1 - * @param {BallTreeNode | BallTreeLeaf | null} child2 - * @param {number} radius - */ - constructor(pivot, child1 = null, child2 = null, radius = 0) { - this.pivot = pivot; - this.child1 = child1; - this.child2 = child2; - this.radius = radius; - } -} + /** + * @template {InputType} T + * @param {T} X + * @param {Partial>} [parameters] + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new SAMMON(X, parameters); + yield* dr.generator(); + return dr.projection; + } -/** - * @private - * @template {number[] | Float64Array} T - */ -class BallTreeLeaf { - /** @param {ElementWithIndex[]} points */ - constructor(points) { - this.points = points; - } + /** + * @template {InputType} T + * @param {T} X + * @param {Partial>} [parameters] + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new SAMMON(X, parameters); + return dr.transform_async(); + } } -/** @import { Metric } from "../metrics/index.js" */ -/** @import { ParametersHNSW } from "./index.js" */ - -/** - * @typedef {Object} Layer - * @property {number} l_c - Layer number - * @property {number[]} point_indices - Global indices of points in this layer - * @property {Map} edges - Global index -> array of connected global indices - */ - -/** - * @template {number[] | Float64Array} T - * @typedef {Object} Candidate - * @property {T} element - The actual data point - * @property {number} index - Global index in the dataset - * @property {number} distance - Distance from query - */ +/** @import {InputType} from "../index.js" */ +/** @import {Metric} from "../metrics/index.js" */ +/** @import {ParametersSQDMDS} from "./index.js" */ /** - * Hierarchical Navigable Small World (HNSW) graph for approximate nearest neighbor search. - * - * HNSW builds a multi-layer graph structure where each layer is a navigable small world graph. - * The top layers serve as "highways" for fast traversal, while lower layers provide accuracy. - * Each element is assigned to a random level, allowing logarithmic search complexity. - * - * Key parameters: - * - `m`: Controls the number of connections per element (affects accuracy/memory) - * - `ef_construction`: Controls the quality of the graph during construction (higher = better but slower) - * - `ef`: Controls the quality of search (higher = better recall but slower) + * SQuadMDS (Stochastic Quartet MDS) * - * Based on: - * - "Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs" - * by Malkov & Yashunin (2016) - * - "Approximate Nearest Neighbor Search on High Dimensional Data" - * by Li et al. (2019) + * A lean Stochastic Quartet MDS improving global structure preservation in + * neighbor embedding like t-SNE and UMAP. * * @class - * @category KNN - * @template {number[] | Float64Array} T - * @extends KNN - * - * @example - * import * as druid from "@saehrimnir/druidjs"; - * - * const points = [[1, 2], [3, 4], [5, 6], [7, 8]]; - * const hnsw = new druid.HNSW(points, { - * metric: druid.euclidean, - * m: 16, - * ef_construction: 200 - * }); - * - * const query = [2, 3]; - * const neighbors = hnsw.search(query, 2); - * // [{ element: [1, 2], index: 0, distance: 1.41 }, ...] + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction */ -class HNSW extends KNN { - /** - * Creates a new HNSW index. - * - * @param {T[]} points - Initial points to add to the index - * @param {ParametersHNSW} [parameters={}] - Configuration parameters - */ - constructor( - points, - parameters = { - metric: euclidean, - heuristic: true, - m: 16, - ef_construction: 200, - m0: null, - mL: null, - seed: 1212, - ef: 50, - }, - ) { - // Handle empty initialization - use dummy element - const hasElements = points && points.length > 0; - let firstElement = /** @type {T} */ (hasElements ? points[0] : new Float64Array([0])); - - // Validate all points have consistent dimensions - if (hasElements) { - const expected_dim = firstElement.length; - for (let i = 1; i < points.length; i++) { - if (!points[i] || points[i].length !== expected_dim) { - console.warn( - `HNSW: Point ${i} has inconsistent dimensions (expected ${expected_dim}, got ${points[i]?.length})`, - ); - // Remove invalid points - points = points.filter((_, idx) => idx === 0 || points[idx]?.length === expected_dim); - firstElement = points[0]; - } - } - } - - super([firstElement], parameters); - - // Store reference to elements before clearing - const elementsToAdd = hasElements ? [...points] : []; - /** @type {T[]} */ - this._elements = []; +class SQDMDS extends DR { + /** + * SQuadMDS: a lean Stochastic Quartet MDS improving global structure preservation in neighbor embedding like t-SNE + * and UMAP. + * + * @param {T} X + * @param {Partial} [parameters] + * @see {@link https://arxiv.org/pdf/2202.12087.pdf} + */ + constructor(X, parameters) { + super( + X, + { + d: 2, + metric: euclidean, + seed: 1212, + decay_start: 0.1, + decay_cte: 0.34, // 0.34 + }, + parameters, + ); - /** @type {Metric} */ - this._metric = this._parameters.metric || euclidean; + this.init(); + if (this.parameter("metric") === "precomputed" && this.X.shape[0] !== this.X.shape[1]) { + throw new Error("SQDMDS input data must be a square Matrix"); + } + } - /** @type {Function} */ - this._select = this._parameters.heuristic - ? this._select_heuristic.bind(this) - : this._select_simple.bind(this); + init() { + const N = this._N; + const d = /** @type {number} */ (this.parameter("d")); + + // initialize helpers. + this._add = this.__add(d); + this._sub_div = this.__sub_div(d); + this._minus = this.__minus(d); + this._mult = this.__mult(d); + this._LR_init = Math.max(2, 0.005 * N); + this._LR = this._LR_init; + const decay_cte = /** @type {number} */ (this.parameter("decay_cte")); + this._offset = -Math.exp(-1 / decay_cte); + this._momentums = new Matrix(N, d, 0); + this._grads = new Matrix(N, d, 0); + this._indices = linspace(0, N - 1); + // initialize projection. + const R = this._randomizer; + this.Y = new Matrix(N, d, () => R.random - 0.5); + + // preparing metric for optimization. + const this_metric = /** @type {Metric | "precomputed"} */ (this.parameter("metric")); + if (this_metric === "precomputed") { + /** @type {(i: number, j: number, X: Matrix) => number} */ + this._HD_metric = (i, j, X) => X.entry(i, j); + /** @type {(i: number, j: number, X: Matrix) => number} */ + this._HD_metric_exaggeration = (i, j, X) => X.entry(i, j) ** 2; + } else { + this._HD_metric = (i, j, X) => this_metric(X.row(i), X.row(j)); + if (this_metric === euclidean) { + this._HD_metric_exaggeration = (i, j, X) => euclidean_squared(X.row(i), X.row(j)); + } else { + this._HD_metric_exaggeration = (i, j, X) => this_metric(X.row(i), X.row(j)) ** 2; + } + } + return; + } /** - * @private - * @type {Map} + * Computes the projection. + * + * @param {number} [iterations=500] - Number of iterations. Default is `500` + * @returns {T} The projection. */ - this._graph = new Map(); + transform(iterations = 500) { + this.check_init(); + const decay_start = /** @type {number} */ (this.parameter("decay_start")); + this._decay_start = Math.round(decay_start * iterations); + for (let i = 0; i < iterations; ++i) { + this._step(i, iterations); + } + return this.projection; + } - /** @type {number} */ - this._next_index = 0; + /** + * Computes the projection. + * + * @param {number} [iterations=500] - Number of iterations. Default is `500` + * @returns {Generator} The intermediate steps of the projection. + */ + *generator(iterations = 500) { + this.check_init(); + const decay_start = /** @type {number} */ (this.parameter("decay_start")); + this._decay_start = Math.round(decay_start * iterations); + for (let i = 0; i < iterations; ++i) { + this._step(i, iterations); + yield this.projection; + } - // Validate and set parameters - const m_param = this._parameters.m ?? 16; - if (m_param <= 0 || !Number.isInteger(m_param)) { - throw new Error("HNSW: parameter 'm' must be a positive integer"); + return this.projection; } - /** @type {number} */ - this._m = Math.max(2, m_param); - const ef_construction_param = this._parameters.ef_construction ?? 200; - if (ef_construction_param <= 0 || !Number.isInteger(ef_construction_param)) { - throw new Error("HNSW: parameter 'ef_construction' must be a positive integer"); + /** + * Performs an optimization step. + * + * @private + * @param {number} i - Acutal iteration. + * @param {number} iterations - Number of iterations. + */ + _step(i, iterations) { + if (this._LR_init === undefined || this._offset === undefined) throw new Error("Call init() first!"); + + const decay_start = /** @type {number} */ (this.parameter("decay_start")); + if (i > decay_start) { + const decay_cte = /** @type {number} */ (this.parameter("decay_cte")); + const offset = this._offset; + const ratio = (i - decay_start) / (iterations - decay_start); + this._LR = this._LR_init * (Math.exp(-(ratio * ratio) / decay_cte) + offset); + this._distance_exaggeration = false; + } else { + this._distance_exaggeration = true; + } + this._nestrov_iteration(this._distance_exaggeration); } - /** @type {number} */ - this._ef_construction = ef_construction_param; - const ef_param = this._parameters.ef ?? 50; - if (ef_param <= 0 || !Number.isInteger(ef_param)) { - throw new Error("HNSW: parameter 'ef' must be a positive integer"); + /** + * Creates quartets of non overlapping indices. + * + * @private + * @returns {Uint32Array[]} + */ + __quartets() { + if (!this._indices) throw new Error("Call init() first!"); + if (this._offset === undefined) throw new Error("Call init() first!"); + const N = this._N; + const max_N = N - (N % 4); + const R = this._randomizer; + const shuffled_indices = R.choice(this._indices, max_N); + const result = []; + for (let i = 0; i < max_N; i += 4) { + result.push( + Uint32Array.of( + shuffled_indices[i], + shuffled_indices[i + 1], + shuffled_indices[i + 2], + shuffled_indices[i + 3], + ), + ); + } + return result; } - /** @type {number} */ - this._ef = ef_param; - const m0_param = this._parameters.m0 ?? 2 * this._m; - if (m0_param <= 0 || !Number.isInteger(m0_param)) { - throw new Error("HNSW: parameter 'm0' must be a positive integer"); + /** + * Computes and applies gradients, and updates momentum. + * + * @private + * @param {boolean} distance_exaggeration + */ + _nestrov_iteration(distance_exaggeration) { + if (!this._momentums || !this._grads || this._LR === undefined) throw new Error("Call init() first!"); + const momentums = this._momentums.mult(0.99, { inline: true }); + const LR = this._LR; + const grads = this._fill_MDS_grads(this.Y.add(momentums), this._grads, distance_exaggeration); + const [n, d] = momentums.shape; + for (let i = 0; i < n; ++i) { + const g_i = grads.row(i); + const g_i_norm = norm(g_i); + if (g_i_norm === 0) continue; + const mul = LR / g_i_norm; + const m_i = momentums.row(i); + for (let j = 0; j < d; ++j) { + m_i[j] -= mul * g_i[j]; + } + } // momentums -= (LR / norm) * grads + this.Y.add(momentums, { inline: true }); } - /** @type {number} */ - this._m0 = m0_param; - /** @type {number} */ - this._mL = this._parameters.mL ?? 1 / Math.log(this._m); + /** + * Computes the gradients. + * + * @param {Matrix} Y - The Projection. + * @param {Matrix} grads - The gradients. + * @param {boolean} [exaggeration=false] - Whether or not to use early exaggeration. Default is `false` + * @param {boolean} [zero_grad=true] - Whether or not to reset the gradient in the beginning. Default is `true` + * @returns {Matrix} The gradients. + */ + _fill_MDS_grads(Y, grads, exaggeration = false, zero_grad = true) { + if (!this._HD_metric || !this._HD_metric_exaggeration || !this._add) throw new Error("Call init() first!"); + if (zero_grad) { + // compute new gradients + grads.values.fill(0); + } + const add = this._add; + const X = this.X; + let HD_metric; + if (exaggeration === true) { + HD_metric = this._HD_metric_exaggeration; + } else { + HD_metric = this._HD_metric; + } - /** @type {Randomizer} */ - this._randomizer = new Randomizer(this._parameters.seed); - - /** @type {number} - Current maximum layer in the graph */ - this._L = -1; - - /** @type {number[] | null} - Entry point indices for search */ - this._ep = null; - - // Add initial points - if (elementsToAdd && elementsToAdd.length > 0) { - this.add(elementsToAdd); - } - } - - /** - * Add a single element to the index. - * - * @param {T} element - Element to add - * @returns {HNSW} This instance for chaining - */ - addOne(element) { - return this.add([element]); - } - - /** - * Add multiple elements to the index. - * - * @param {T[]} new_elements - Elements to add - * @returns {HNSW} This instance for chaining - */ - add(new_elements) { - // Handle empty array - if (!new_elements || new_elements.length === 0) { - return this; - } - - const m = this._m; - const ef_construction = this._ef_construction; - const m0 = this._m0; - const mL = this._mL; - const randomizer = this._randomizer; - const graph = this._graph; - - // Ensure _elements is a proper array that supports push - if (!Array.isArray(this._elements)) { - this._elements = Array.from(this._elements); - } - const elements = this._elements; - - // Get expected dimension from first existing element or first new element - const expected_dim = elements.length > 0 ? elements[0].length : new_elements[0]?.length; - - for (const element of new_elements) { - // Validate element - if (!element || (!Array.isArray(element) && !(element instanceof Float64Array))) { - console.warn("HNSW: Skipping invalid element (null, undefined, or not an array)"); - continue; - } - - // Validate dimensions - if (element.length !== expected_dim) { - console.warn( - `HNSW: Skipping element with wrong dimensions (expected ${expected_dim}, got ${element.length})`, - ); - continue; - } - - elements.push(element); - const global_index = elements.length - 1; - - // Assign random level to the element - // Level is drawn from exponential distribution: l = floor(-ln(uniform(0,1)) * mL) - const rand = Math.max(randomizer.random, 1e-10); // Avoid log(0) - const l = Math.min(31, Math.floor(-Math.log(rand) * mL)); - - let ep_indices = this._ep ? [...this._ep] : null; - const L = this._L; - - if (L >= 0) { - // Search from top layer down to min(L, l) + 1 - // These are the layers where element will NOT be inserted - for (let l_c = L; l_c > l; --l_c) { - const search_result = this._search_layer(element, ep_indices, 1, l_c); - if (search_result.length > 0) { - ep_indices = [search_result[0].index]; - } - } - - // Insert element into layers l down to 0 - for (let l_c = Math.min(L, l); l_c >= 0; --l_c) { - const layer = graph.get(l_c); - if (!layer) continue; - - layer.point_indices.push(global_index); - - // Search for ef_construction nearest neighbors - let W = this._search_layer(element, ep_indices, ef_construction, l_c); - - // If graph search returns no results (e.g., graph is empty or disconnected), - // fall back to linear search over all existing elements - if (W.length === 0 && elements.length > 1) { - const fallbackCandidates = []; - for (let i = 0; i < elements.length - 1; i++) { - const elem = elements[i]; - if (elem && elem.length === element.length) { - fallbackCandidates.push({ - element: elem, - index: i, - distance: this._metric(element, elem), - }); - } - } - fallbackCandidates.sort((a, b) => a.distance - b.distance); - W = fallbackCandidates.slice(0, ef_construction); - // Update ep_indices for next layer based on fallback results - if (l_c === Math.min(L, l)) { - ep_indices = W.map((c) => c.index); + const D_quartet = new Float64Array(6); + const quartets = this.__quartets(); + for (const [i, j, k, l] of quartets) { + // compute quartet's HD distances. + D_quartet[0] = HD_metric(i, j, X); + D_quartet[1] = HD_metric(i, k, X); + D_quartet[2] = HD_metric(i, l, X); + D_quartet[3] = HD_metric(j, k, X); + D_quartet[4] = HD_metric(j, l, X); + D_quartet[5] = HD_metric(k, l, X); + + const D_quartet_sum = neumair_sum(D_quartet); + + if (D_quartet_sum > 0) { + for (let i = 0; i < 6; ++i) { + D_quartet[i] /= D_quartet_sum; + D_quartet[i] += 1e-11; + } } - } + const [gi, gj, gk, gl] = this._compute_quartet_grads(Y, [i, j, k, l], D_quartet); - // Select neighbors using heuristic or simple approach (respect heuristic setting on all layers) - const neighbor_indices = this._select(element, W, l_c === 0 ? m0 : m, l_c); + // add is inline, row acces the matrix + add(grads.row(i), gi); + add(grads.row(j), gj); + add(grads.row(k), gk); + add(grads.row(l), gl); + } + return grads; + } - // Add bidirectional connections - for (const neighbor_idx of neighbor_indices) { - if (neighbor_idx === global_index) continue; + /** + * Quartet gradients for a projection. + * + * @private + * @param {Matrix} Y - The acutal projection. + * @param {number[]} quartet - The indices of the quartet. + * @param {Float64Array} D_hd - The high-dimensional distances of the quartet. + * @returns {Float64Array[]} The gradients for the quartet. + */ + _compute_quartet_grads(Y, quartet, [p_ab, p_ac, p_ad, p_bc, p_bd, p_cd]) { + const [a, b, c, d] = quartet.map((index) => Y.row(index)); + // LD distances, add a small number just in case + const d_ab = euclidean(a, b) + 1e-12; + const d_ac = euclidean(a, c) + 1e-12; + const d_ad = euclidean(a, d) + 1e-12; + const d_bc = euclidean(b, c) + 1e-12; + const d_bd = euclidean(b, d) + 1e-12; + const d_cd = euclidean(c, d) + 1e-12; + const sum_LD_dist = neumair_sum([d_ab, d_ac, d_ad, d_bc, d_bd, d_cd]); + + // for each element of the sum: use the same gradient function and just permute the points given in input. + const [gA1, gB1, gC1, gD1] = this._ABCD_grads( + a, + b, + c, + d, + d_ab, + d_ac, + d_ad, + d_bc, + d_bd, + d_cd, + p_ab, + sum_LD_dist, + ); + const [gA2, gC2, gB2, gD2] = this._ABCD_grads( + a, + c, + b, + d, + d_ac, + d_ab, + d_ad, + d_bc, + d_cd, + d_bd, + p_ac, + sum_LD_dist, + ); + const [gA3, gD3, gC3, gB3] = this._ABCD_grads( + a, + d, + c, + b, + d_ad, + d_ac, + d_ab, + d_cd, + d_bd, + d_bc, + p_ad, + sum_LD_dist, + ); + const [gB4, gC4, gA4, gD4] = this._ABCD_grads( + b, + c, + a, + d, + d_bc, + d_ab, + d_bd, + d_ac, + d_cd, + d_ad, + p_bc, + sum_LD_dist, + ); + const [gB5, gD5, gA5, gC5] = this._ABCD_grads( + b, + d, + a, + c, + d_bd, + d_ab, + d_bc, + d_ad, + d_cd, + d_ac, + p_bd, + sum_LD_dist, + ); + const [gC6, gD6, gA6, gB6] = this._ABCD_grads( + c, + d, + a, + b, + d_cd, + d_ac, + d_bc, + d_ad, + d_bd, + d_ab, + p_cd, + sum_LD_dist, + ); - // Add connection from element to neighbor - if (!layer.edges.has(global_index)) { - layer.edges.set(global_index, []); - } - layer.edges.get(global_index)?.push(neighbor_idx); + if (!this._add) throw new Error("Call init() first!"); + const add = this._add; + const gA = add(gA1, gA2, gA3, gA4, gA5, gA6); + const gB = add(gB1, gB2, gB3, gB4, gB5, gB6); + const gC = add(gC1, gC2, gC3, gC4, gC5, gC6); + const gD = add(gD1, gD2, gD3, gD4, gD5, gD6); - // Add connection from neighbor to element - if (!layer.edges.has(neighbor_idx)) { - layer.edges.set(neighbor_idx, []); - } - const neighbor_edge_list = layer.edges.get(neighbor_idx); - if (neighbor_edge_list && !neighbor_edge_list.includes(global_index)) { - neighbor_edge_list.push(global_index); - } + return [gA, gB, gC, gD]; + } - // Prune connections if too many - const max_conn = l_c === 0 ? m0 : m; - const neighbor_edges = layer.edges.get(neighbor_idx); - if (neighbor_edges && neighbor_edges.length > max_conn) { - const neighbor_element = elements[neighbor_idx]; - // Filter out self-connections before pruning - const valid_neighbor_edges = neighbor_edges.filter((idx) => idx !== neighbor_idx); - const neighbor_candidates = valid_neighbor_edges.map((idx) => ({ - element: elements[idx], - index: idx, - distance: this._metric(neighbor_element, elements[idx]), - })); - const pruned = - l_c === 0 - ? this._select_simple(neighbor_element, neighbor_candidates, max_conn) - : this._select(neighbor_element, neighbor_candidates, max_conn, l_c); - layer.edges.set(neighbor_idx, pruned); - } - } - - // Use closest neighbor as entry point for next layer (following HNSW paper) - if (W.length > 0) { - ep_indices = [W[0].index]; - } - } - } - - // If element's level is higher than current max, create new layers - if (l > L) { - for (let i = L + 1; i <= l; ++i) { - graph.set(i, { - l_c: i, - point_indices: [global_index], - edges: new Map(), - }); - } - // Element becomes the new entry point - this._ep = [global_index]; - this._L = l; - } - - // Special case: if this is the first element (L was -1), - // we need to ensure layer 0 has proper structure for future insertions - if (L === -1) { - if (!graph.has(0)) { - graph.set(0, { - l_c: 0, - point_indices: [global_index], - edges: new Map(), - }); - } - const layer0 = graph.get(0); - if (layer0 && !layer0.edges.has(global_index)) { - layer0.edges.set(global_index, []); - } - } - } - - return this; - } - - /** - * Select neighbors using the heuristic approach. - * - * The heuristic extends candidates with their neighbors and selects - * points that are closer to the query than to already selected points. - * This maintains graph connectivity better than simple selection. - * - * @private - * @param {T} q - Query element - * @param {Candidate[]} candidates - Candidate elements with distances - * @param {number} M - Maximum number of neighbors to return - * @param {number} l_c - Layer number - * @param {boolean} [extend_candidates=true] - Whether to extend candidates with their neighbors - * @param {boolean} [keep_pruned_connections=true] - Whether to add pruned connections back if needed - * @returns {number[]} Selected neighbor indices - */ - _select_heuristic( - q, - candidates, - M, - l_c, - extend_candidates = true, - keep_pruned_connections = true, - ) { - if (l_c > this._L) { - return candidates.map((c) => c.index); - } - - const metric = this._metric; - const layer = this._graph.get(l_c); - const elements = this._elements; - - // Extend candidate set with neighbors of candidates - const W_set = new Set(candidates.map((c) => c.index)); - if (extend_candidates) { - for (const c of candidates) { - const edges = layer?.edges.get(c.index); - if (edges) { - for (const neighbor_idx of edges) { - W_set.add(neighbor_idx); - } - } - } - } - - // Create extended candidates with distances - const W = [...W_set] - .map((idx) => ({ - element: elements[idx], - index: idx, - distance: metric(elements[idx], q), - })) - .sort((a, b) => a.distance - b.distance); - - const R = []; - const W_discarded = []; - - // Select neighbors: prefer points closer to query than to already selected points - for (const e of W) { - if (R.length >= M) break; - - let should_add = true; - - // Check if e is closer to query than to any already selected point - for (const r of R) { - const dist_er = metric(e.element, r.element); - if (dist_er < e.distance) { - should_add = false; - break; - } - } - - if (should_add) { - R.push(e); - } else { - W_discarded.push(e); - } - } - - // Add discarded connections if we need more - if (keep_pruned_connections && R.length < M) { - for (const e of W_discarded) { - if (R.length >= M) break; - R.push(e); - } - } - - return R.map((c) => c.index); - } - - /** - * Select neighbors using simple distance-based selection. - * - * Simply returns the M closest candidates to the query. - * - * @private - * @param {T} q - Query element - * @param {Candidate[]} C - Candidate elements with distances - * @param {number} M - Maximum number of neighbors to return - * @returns {number[]} M nearest candidate indices - */ - _select_simple(q, C, M) { - if (C.length <= M) return C.map((c) => c.index); - - // Candidates already have distance computed, use it directly - return C.slice() - .sort((a, b) => a.distance - b.distance) - .slice(0, M) - .map((c) => c.index); - } - - /** - * Search a single layer for nearest neighbors. - * - * Implements the greedy search algorithm: start from entry points, - * always expand the closest unvisited candidate, maintain a list - * of the ef closest found neighbors. - * - * @private - * @param {T} q - Query element - * @param {number[] | null} ep_indices - Entry point indices - * @param {number} ef - Number of nearest neighbors to find - * @param {number} l_c - Layer number to search - * @returns {Candidate[]} ef nearest neighbors found with their distances - */ - _search_layer(q, ep_indices, ef, l_c) { - const metric = this._metric; - const layer = this._graph.get(l_c); - const elements = this._elements; - - if (!layer || layer.edges.size === 0 || !ep_indices || ep_indices.length === 0) { - return []; - } - - // Filter out invalid indices - const valid_ep_indices = ep_indices.filter((idx) => elements[idx] !== undefined); - if (valid_ep_indices.length === 0) { - return []; - } - - // Visited set to avoid cycles - const visited = new Set(valid_ep_indices); - - // Candidate set (min-heap): closest unvisited candidates to expand - const C = new Heap( - valid_ep_indices.map((idx) => ({ - element: elements[idx], - index: idx, - distance: metric(elements[idx], q), - })), - (item) => item.distance, - "min", - ); - - // Result set (max-heap): ef closest found neighbors - const W = new Heap( - valid_ep_indices.map((idx) => ({ - element: elements[idx], - index: idx, - distance: metric(elements[idx], q), - })), - (item) => item.distance, - "max", - ); - - // Algorithm 2 stops when the distance from query to the next candidate is greater - // than the distance to the furthest element in the result set W. - while (!C.empty) { - const c = C.pop(); - if (!c) break; - const furthest_dist = W.first?.value ?? Infinity; - - // Stop if current candidate is farther than furthest result - if (c.value > furthest_dist) { - break; - } - - const edges = layer.edges.get(c.element.index); - if (!edges) continue; - - for (const neighbor_idx of edges) { - if (!visited.has(neighbor_idx)) { - const neighbor_element = elements[neighbor_idx]; - // Skip invalid elements or elements with different dimensions - if (!neighbor_element || neighbor_element.length !== q.length) continue; - - // Skip self-connections - if (neighbor_idx === c.element.index) continue; - - visited.add(neighbor_idx); - const dist_e = metric(neighbor_element, q); - - const current_furthest = W.first?.value ?? Infinity; - if (dist_e < current_furthest || W.length < ef) { - C.push({ - element: neighbor_element, - index: neighbor_idx, - distance: dist_e, - }); - W.push({ - element: neighbor_element, - index: neighbor_idx, - distance: dist_e, - }); + /** + * Gradients for one element of the loss function's sum. + * + * @private + * @param {Float64Array} a + * @param {Float64Array} b + * @param {Float64Array} c + * @param {Float64Array} d + * @param {number} d_ab + * @param {number} d_ac + * @param {number} d_ad + * @param {number} d_bc + * @param {number} d_bd + * @param {number} d_cd + * @param {number} p_ab + * @param {number} sum_LD_dist + * @returns {Float64Array[]} + */ + _ABCD_grads(a, b, c, d, d_ab, d_ac, d_ad, d_bc, d_bd, d_cd, p_ab, sum_LD_dist) { + if (!this._minus || !this._add || !this._mult || !this._sub_div) throw new Error("Call init() first!"); + const ratio = d_ab / sum_LD_dist; + const twice_ratio = 2 * ((p_ab - ratio) / sum_LD_dist); + const minus = this._minus; + const add = this._add; + const mult = this._mult; + const sub_div = this._sub_div; + // no side effects because sub_div creates new arrays, and the inline functions work on this new created arrays. + const gA = mult( + minus(mult(add(sub_div(a, b, d_ab), sub_div(a, c, d_ac), sub_div(a, d, d_ad)), ratio), sub_div(a, b, d_ab)), + twice_ratio, + ); + const gB = mult( + minus(mult(add(sub_div(b, a, d_ab), sub_div(b, c, d_bc), sub_div(b, d, d_bd)), ratio), sub_div(b, a, d_ab)), + twice_ratio, + ); + const gC = mult(add(sub_div(c, a, d_ac), sub_div(c, b, d_bc), sub_div(c, d, d_cd)), ratio * twice_ratio); + const gD = mult(add(sub_div(d, a, d_ad), sub_div(d, b, d_bd), sub_div(d, c, d_cd)), ratio * twice_ratio); + return [gA, gB, gC, gD]; + } - if (W.length > ef) { - W.pop(); + /** + * Inline! + * + * @param {number} d + */ + __minus(d) { + return /** @type {(a: Float64Array, b: Float64Array) => Float64Array} */ (a, b) => { + for (let i = 0; i < d; ++i) { + a[i] -= b[i]; } - } - } - } + return a; + }; } - // Return sorted results for consistent entry point selection - return W.data().sort((a, b) => a.distance - b.distance); - } - - /** - * Searches for the K nearest neighbors to a query element in the HNSW graph. - * - * Performs a multi-layer search starting from the entry point and traversing - * each layer as entry points for the next. - * - * @param {T} q - Query element - * @param {number} K - Number of nearest neighbors to return - * @returns {Candidate[]} K nearest neighbors with their distances - */ - search(q, K) { - // Validate K - if (!Number.isInteger(K) || K <= 0) { - throw new Error("HNSW: parameter 'K' must be a positive integer"); - } - - // Validate query dimensions - if (!q || (!Array.isArray(q) && !(q instanceof Float64Array))) { - throw new Error("HNSW: query must be an array"); - } - - const search_ef = this._ef; - - // Fallback to linear search if graph is not properly initialized - if (this._L < 0 || !this._ep || this._elements.length === 0) { - return this._linear_search(q, K); - } - - let ep_indices = [...this._ep]; - - // Search from top layer down to layer 1 - for (let l_c = this._L; l_c > 0; --l_c) { - const result = this._search_layer(q, ep_indices, 1, l_c); - if (result.length > 0) { - ep_indices = [result[0].index]; - } - } - - // Search layer 0 with ef candidates - const result = this._search_layer(q, ep_indices, Math.max(search_ef, K), 0); - - // If graph search returns no results, fallback to linear search - if (result.length === 0) { - return this._linear_search(q, K); - } - - // Return K closest - return result.slice(0, K); - } - - /** - * Fallback linear search when graph search fails - * @private - * @param {T} q - Query element - * @param {number} K - Number of nearest neighbors to return - * @returns {Candidate[]} - */ - _linear_search(q, K) { - const metric = this._metric; - const elements = this._elements; - const N = elements.length; - - if (N === 0) return []; - - /** @type {Candidate[]} */ - const candidates = []; - for (let i = 0; i < N; i++) { - const element = elements[i]; - // Skip elements with different dimensions (can happen with inconsistent data) - if (!element || element.length !== q.length) continue; - - candidates.push({ - element: element, - index: i, - distance: metric(q, element), - }); - } - - candidates.sort((a, b) => a.distance - b.distance); - return candidates.slice(0, K); - } - - /** - * Iterator for searching the HNSW graph layer by layer. - * - * Yields intermediate results at each layer for debugging or visualization. - * - * @param {T} q - Query element - * @param {number} K - Number of nearest neighbors to return - * @param {number?} [ef] - Size of dynamic candidate list - * @yields {{layer: number, candidates: Candidate[]}} - */ - *search_iter(q, K, ef = null) { - const search_ef = ef ?? this._ef; - - if (this._L < 0 || !this._ep) { - return; - } - - let ep_indices = [...this._ep]; - - // Yield entry points at top layer instead of query itself - const top_layer = this._graph.get(this._L); - if (top_layer && this._ep && this._ep.length > 0) { - const entry_candidates = this._ep - .filter((idx) => this._elements[idx] !== undefined) - .map((idx) => ({ - element: this._elements[idx], - index: idx, - distance: this._metric(this._elements[idx], q), - })); - yield { - layer: this._L, - candidates: entry_candidates, - }; - } - - for (let l_c = this._L; l_c > 0; --l_c) { - const result = this._search_layer(q, ep_indices, 1, l_c); - yield { layer: l_c, candidates: result }; - // Use closest candidate as entry point for next layer (following HNSW paper) - ep_indices = result.length > 0 ? [result[0].index] : ep_indices; - } - - const result = this._search_layer(q, ep_indices, Math.max(search_ef, K), 0); - yield { layer: 0, candidates: result }; - } - - /** - * Get the number of elements in the index. - * - * @returns {number} Number of elements - */ - get size() { - return this._elements?.length ?? 0; - } - - /** - * Get the number of layers in the graph. - * - * @returns {number} Number of layers - */ - get num_layers() { - return this._L + 1; - } - - /** - * Get an element by its index. - * - * @param {number} index - Element index - * @returns {T} The element at the given index - */ - get_element(index) { - return this._elements[index]; - } - - /** - * Search for nearest neighbors using an element index as the query. - * - * @param {number} i - Index of the query element - * @param {number} [K=5] - Number of nearest neighbors to return - * @returns {Candidate[]} K nearest neighbors - */ - search_by_index(i, K = 5) { - const elements = this._elements; - if (i < 0 || i >= elements.length) return []; - - const element = elements[i]; - if (!element) return []; - - return this.search(element, K); - } -} + /** + * Inline! + * + * @param {number} d + */ + __add(d) { + return /** @type {(...summands: Float64Array[]) => Float64Array} */ (...summands) => { + const n = summands.length; + const s1 = summands[0]; + for (let j = 1; j < n; ++j) { + const summand = summands[j]; + for (let i = 0; i < d; ++i) { + s1[i] += summand[i]; + } + } + return s1; + }; + } -/** @import { Metric } from "../metrics/index.js" */ -/** @import { ParametersKDTree } from "./index.js" */ + /** + * Inline! + * + * @param {number} d + */ + __mult(d) { + return /** @type {(a: Float64Array, v: number) => Float64Array} */ (a, v) => { + for (let i = 0; i < d; ++i) { + a[i] *= v; + } + return a; + }; + } -/** - * @template {number[] | Float64Array} T - * @typedef {Object} ElementWithIndex - * @property {number} index - * @property {T} element - */ + /** + * Creates a new array `(x - y) / div`. + * + * @param {number} d + */ + __sub_div(d) { + return /** @type {(x: Float64Array, y: Float64Array, div: number) => Float64Array} */ (x, y, div) => { + return Float64Array.from({ length: d }, (_, i) => (x[i] - y[i]) / div); + }; + } -/** - * KD-Tree (K-dimensional Tree) for efficient nearest neighbor search. - * - * KD-Trees partition k-dimensional space by recursively splitting along coordinate axes. - * At each level, the tree splits points based on the median of the coordinate with the largest spread. - * This creates a balanced binary tree structure that enables efficient O(log n) search on average. - * - * Best suited for: - * - Low to moderate dimensional data (d < 20-30) - * - When exact nearest neighbors are needed - * - When dimensionality is not too high - * - * Performance degrades in high dimensions (curse of dimensionality) where approximate - * methods like HNSW or LSH become more effective. - * - * @class - * @category KNN - * @template {number[] | Float64Array} T - * @extends KNN - * @see {@link https://en.wikipedia.org/wiki/K-d_tree} - */ -class KDTree extends KNN { - /** - * Generates a KD-Tree with given `elements`. - * - * @param {T[]} elements - Elements which should be added to the KD-Tree - * @param {ParametersKDTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}` - */ - constructor(elements, parameters = { metric: euclidean, seed: 1212 }) { - super(elements, Object.assign({ seed: 1212 }, parameters)); /** - * @private - * @type {KDTreeNode | KDTreeLeaf | null} - */ - this._root = this._construct( - elements.map((element, index) => ({ index, element })), - 0, - ); - } - - /** @returns {Metric} */ - get _metric() { - return this._parameters.metric; - } - - /** - * @private - * @param {ElementWithIndex[]} elements - * @param {number} depth - Current depth in the tree (determines splitting axis) - * @returns {KDTreeNode | KDTreeLeaf | null} Root of KD-Tree. - */ - _construct(elements, depth) { - if (elements.length === 0) { - return null; - } - - if (elements.length === 1) { - return new KDTreeLeaf(elements[0]); - } - - const k = elements[0].element.length; - const axis = depth % k; - - // Sort by the splitting axis and find median - elements.sort((a, b) => a.element[axis] - b.element[axis]); - const medianIndex = Math.floor(elements.length / 2); - const medianPoint = elements[medianIndex]; - - // Recursively build left and right subtrees - const leftElements = elements.slice(0, medianIndex); - const rightElements = elements.slice(medianIndex + 1); - - const left = this._construct(leftElements, depth + 1); - const right = this._construct(rightElements, depth + 1); - - return new KDTreeNode(medianPoint, axis, left, right); - } - - /** - * @param {number} i - * @param {number} k - */ - search_by_index(i, k = 5) { - return this.search(this._elements[i], k); - } - - /** - * @param {T} t - Query element. - * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5` - * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors. - */ - search(t, k = 5) { - /** @type {Heap<{ point: ElementWithIndex; distance: number }>} */ - const best = new Heap(null, (d) => d.distance, "max"); - - this._search_recursive(t, k, this._root, best); - - // Convert heap to result array (closest first) - /** @type {{ element: T; index: number; distance: number }[]} */ - const result = []; - while (best.length > 0) { - const item = - /** @type {{ element: { point: ElementWithIndex; distance: number }; value: number }} */ ( - best.pop() - ); - result.push({ - element: item.element.point.element, - index: item.element.point.index, - distance: item.value, - }); - } - return result.reverse(); - } - - /** - * @private - * @param {T} target - Query element. - * @param {number} k - Number of nearest neighbors to return. - * @param {KDTreeNode | KDTreeLeaf | null} node - Current node. - * @param {Heap<{ point: ElementWithIndex; distance: number }>} best - Heap of k best found so far. - */ - _search_recursive(target, k, node, best) { - if (node === null) return; - - if (node instanceof KDTreeLeaf) { - const dist = this._metric(target, node.point.element); - if (best.length < k) { - best.push({ point: node.point, distance: dist }); - } else if (dist < (best.first?.value ?? Infinity)) { - best.pop(); - best.push({ point: node.point, distance: dist }); - } - return; - } - - // Node is an internal node - const axis = node.axis; - const point = node.point; - const pointValue = point.element[axis]; - const targetValue = target[axis]; - - // Determine which subtree to search first - const firstSubtree = targetValue < pointValue ? node.left : node.right; - const secondSubtree = targetValue < pointValue ? node.right : node.left; - - // Search the nearer subtree - this._search_recursive(target, k, firstSubtree, best); - - // Check if we need to search the other subtree - // The hyperplane could contain closer points - const distToHyperplane = Math.abs(targetValue - pointValue); - const currentMaxDist = best.first?.value ?? Infinity; - - // Calculate distance to current point - const distToPoint = this._metric(target, point.element); - if (best.length < k) { - best.push({ point: point, distance: distToPoint }); - } else if (distToPoint < currentMaxDist) { - best.pop(); - best.push({ point: point, distance: distToPoint }); - } - - // Check if we need to explore the other side of the hyperplane - if (best.length < k || distToHyperplane < (best.first?.value ?? Infinity)) { - this._search_recursive(target, k, secondSubtree, best); - } - } -} + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X, parameters) { + const dr = new SQDMDS(X, parameters); + return dr.transform(); + } -/** - * @private - * @template {number[] | Float64Array} T - */ -class KDTreeNode { - /** - * @param {ElementWithIndex} point - * @param {number} axis - The splitting axis - * @param {KDTreeNode | KDTreeLeaf | null} left - * @param {KDTreeNode | KDTreeLeaf | null} right - */ - constructor(point, axis, left = null, right = null) { - this.point = point; - this.axis = axis; - this.left = left; - this.right = right; - } -} + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new SQDMDS(X, parameters); + yield* dr.generator(); + return dr.projection; + } -/** - * @private - * @template {number[] | Float64Array} T - */ -class KDTreeLeaf { - /** - * @param {ElementWithIndex} point - */ - constructor(point) { - this.point = point; - } + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new SQDMDS(X, parameters); + return dr.transform_async(); + } } -/** @import { Metric } from "../metrics/index.js" */ -/** @import { ParametersLSH } from "./index.js" */ +/** @import {InputType} from "../index.js" */ +/** @import {ParametersTopoMap} from "./index.js" */ /** - * Locality Sensitive Hashing (LSH) for approximate nearest neighbor search. - * - * LSH uses hash functions that map similar items to the same buckets with high probability. - * This implementation uses Random Projection hashing (SimHash-style) which works well for - * cosine similarity and Euclidean distance. - * - * Key concepts: - * - Multiple hash tables increase recall probability - * - Each hash function projects data onto random hyperplanes - * - Points on the same side of hyperplanes are hashed together - * - Combines results from all tables for better accuracy + * TopoMap * - * Best suited for: - * - High-dimensional data where exact methods fail - * - Approximate nearest neighbor needs - * - Large datasets where linear scan is too slow - * - When some false positives/negatives are acceptable + * A 0-dimensional Homology Preserving Projection of High-Dimensional Data. + * It aims to preserve the topological structure of the data by maintaining + * the connectivity of a minimum spanning tree. * * @class - * @category KNN - * @template {number[] | Float64Array} T - * @extends KNN - * @see {@link https://en.wikipedia.org/wiki/Locality-sensitive_hashing} + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction */ -class LSH extends KNN { - /** - * Creates a new LSH index. - * - * @param {T[]} elements - Elements to index - * @param {ParametersLSH} [parameters={}] - Configuration parameters - */ - constructor( - elements, - parameters = { - metric: euclidean, - numHashTables: 10, - numHashFunctions: 10, - seed: 1212, - }, - ) { - // Handle empty initialization - use dummy element - const hasElements = elements && elements.length > 0; - const firstElement = /** @type {T} */ (hasElements ? elements[0] : new Float64Array([0])); - - super([firstElement], parameters); - - this._metric = this._parameters.metric ?? euclidean; - this._numHashTables = this._parameters.numHashTables ?? 10; - this._numHashFunctions = this._parameters.numHashFunctions ?? 10; - this._seed = this._parameters.seed ?? 1212; - this._randomizer = new Randomizer(this._seed); - - // Hash tables: array of Maps where key is hash bucket, value is array of element indices - /** @type {Map[]} */ - this._hashTables = []; - - // Random projection vectors for each hash table and hash function - /** @type {Float64Array[][]} */ - this._projections = []; - - // Random offsets for each hash table and hash function (for quantization) - /** @type {number[][]} */ - this._offsets = []; - - // Store dimensionality for later - /** @type {number} */ - this._dim = firstElement.length; +class TopoMap extends DR { + /** + * TopoMap: A 0-dimensional Homology Preserving Projection of High-Dimensional Data. + * + * @param {T} X - The high-dimensional data. + * @param {Partial} parameters - Object containing parameterization of the DR method. + * @see {@link https://arxiv.org/pdf/2009.01512.pdf} + */ + constructor(X, parameters) { + super(X, { metric: euclidean, seed: 1212 }, parameters); + [this._N, this._D] = this.X.shape; + this._distance_matrix = new Matrix(this._N, this._N, -1); + } + + /** + * @private + * @param {number} i + * @param {number} j + * @param {import("../metrics/index.js").Metric} metric + * @returns {number} + */ + __lazy_distance_matrix(i, j, metric) { + const D = this._distance_matrix; + const X = this.X; + const D_ij = D.entry(i, j); + if (D_ij === -1 && i !== j) { + const dist = metric(X.row(i), X.row(j)); + D.set_entry(i, j, dist); + D.set_entry(j, i, dist); + return dist; + } + return i === j ? 0 : D_ij; + } - // Initialize hash functions - this._initializeHashFunctions(); + /** + * Computes the minimum spanning tree, using a given metric + * + * @private + * @param {import("../metrics/index.js").Metric} metric + * @see {@link https://en.wikipedia.org/wiki/Kruskal%27s_algorithm} + */ + _make_minimum_spanning_tree(metric = euclidean) { + const N = this._N; + const X = [...this.X]; - // Reset elements if we were initialized with dummy - if (!hasElements) { - /** @type {T[]} */ - this._elements = []; - } else { - // Clear and re-add elements properly - /** @type {T[]} */ - this._elements = []; - this._hashTables = []; - this._projections = []; - this._offsets = []; - this._initializeHashFunctions(); - this.add(elements); - } - } - - /** - * Initialize random projection vectors for all hash tables. - * @private - */ - _initializeHashFunctions() { - const dim = this._elements[0]?.length ?? 0; - - for (let t = 0; t < this._numHashTables; t++) { - const tableProjections = []; - const tableOffsets = []; - - for (let h = 0; h < this._numHashFunctions; h++) { - // Generate random projection vector (normalized) - const projection = new Float64Array(dim); - let norm = 0; - for (let i = 0; i < dim; i++) { - // Box-Muller transform for normal distribution - const u1 = this._randomizer.random; - const u2 = this._randomizer.random; - const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2); - projection[i] = z; - norm += z * z; + this._disjoint_set = new DisjointSet(X); + const disjoint_set = this._disjoint_set; + const F = []; + let E = []; + for (let i = 0; i < N; ++i) { + for (let j = i + 1; j < N; ++j) { + E.push([i, j, this.__lazy_distance_matrix(i, j, metric)]); + } + } + E = E.sort((a, b) => a[2] - b[2]); + + for (const [u, v, w] of E) { + const set_u = disjoint_set.find(X[u]); + const set_v = disjoint_set.find(X[v]); + if (!set_u || !set_v) throw new Error("Should not happen!"); + if (set_u !== set_v) { + F.push([u, v, w]); + disjoint_set.union(set_u, set_v); + } } - // Normalize - norm = Math.sqrt(norm); - for (let i = 0; i < dim; i++) { - projection[i] /= norm; - } - - tableProjections.push(projection); - // Random offset for quantization buckets - tableOffsets.push(this._randomizer.random); - } - - this._projections.push(tableProjections); - this._offsets.push(tableOffsets); - this._hashTables.push(new Map()); - } - } - - /** - * Compute hash signature for an element using random projections. - * @private - * @param {T} element - * @param {number} tableIndex - * @returns {string} Hash signature - */ - _computeHash(element, tableIndex) { - const projections = this._projections[tableIndex]; - const offsets = this._offsets[tableIndex]; - const bits = []; - - for (let i = 0; i < this._numHashFunctions; i++) { - // Compute dot product - let dot = 0; - const proj = projections[i]; - for (let j = 0; j < element.length; j++) { - dot += element[j] * proj[j]; - } - // Quantize with offset - const bucket = Math.floor(dot + offsets[i]); - bits.push(bucket); - } - - return bits.join(","); - } - - /** - * Add elements to the LSH index. - * @param {T[]} elements - * @returns {this} - */ - add(elements) { - // Extend elements array - const startIndex = this._elements.length; - this._elements = this._elements.concat(elements); - - // Hash each new element and add to tables - for (let i = 0; i < elements.length; i++) { - const globalIndex = startIndex + i; - const element = elements[i]; - - for (let t = 0; t < this._numHashTables; t++) { - const hash = this._computeHash(element, t); - const table = this._hashTables[t]; - - if (!table.has(hash)) { - table.set(hash, []); - } - const bucket = table.get(hash); - if (bucket) { - bucket.push(globalIndex); - } - } - } - - return this; - } - - /** - * Search for k approximate nearest neighbors. - * @param {T} query - * @param {number} [k=5] - * @returns {{ element: T; index: number; distance: number }[]} - */ - search(query, k = 5) { - const metric = this._metric; - const elements = this._elements; - - if (elements.length === 0) return []; - - // Collect candidate indices from all hash tables - const candidates = new Set(); - - for (let t = 0; t < this._numHashTables; t++) { - const hash = this._computeHash(query, t); - const table = this._hashTables[t]; - const bucket = table.get(hash); - - if (bucket) { - for (const idx of bucket) { - if (idx !== undefined) { - candidates.add(idx); - } - } - } - } - - // If insufficient candidates found, fall back to linear search - if (candidates.size < k) { - // Add more candidates from all buckets or entire dataset - //const needed = k - candidates.size; - - // First, try to add from neighboring buckets (different hashes) - for (let t = 0; t < this._numHashTables && candidates.size < k; t++) { - const table = this._hashTables[t]; - for (const [, bucket] of table) { - for (const idx of bucket) { - if (idx !== undefined) { - candidates.add(idx); - if (candidates.size >= k) break; - } - } - if (candidates.size >= k) break; - } - } - - // If still not enough, add from entire dataset - for (let i = 0; i < elements.length && candidates.size < k; i++) { - candidates.add(i); - } - } - - // Compute exact distances for candidates - /** @type {Heap<{ index: number; distance: number }>} */ - const best = new Heap(null, (d) => d.distance, "max"); - - for (const idx of candidates) { - const element = elements[idx]; - if (!element || element.length !== query.length) continue; - - const dist = metric(query, element); - - if (best.length < k) { - best.push({ index: idx, distance: dist }); - } else if (dist < (best.first?.value ?? Infinity)) { - best.pop(); - best.push({ index: idx, distance: dist }); - } - } - - // Convert to result format - /** @type {{ element: T; index: number; distance: number }[]} */ - const result = []; - while (best.length > 0) { - const item = /** @type {{ element: { index: number; distance: number }; value: number }} */ ( - best.pop() - ); - result.push({ - element: elements[item.element.index], - index: item.element.index, - distance: item.value, - }); - } - - return result.reverse(); - } - - /** - * @param {number} i - * @param {number} [k=5] - * @returns {{ element: T; index: number; distance: number }[]} - */ - search_by_index(i, k = 5) { - if (i < 0 || i >= this._elements.length) return []; - return this.search(this._elements[i], k); - } -} -/** @import { ParametersNaiveKNN } from "./index.js" */ + return F.sort((a, b) => a[2] - b[2]); + } -/** - * Naive KNN implementation using a distance matrix. - * - * This implementation pre-computes the entire distance matrix and performs - * an exhaustive search. Best suited for small datasets or when a distance - * matrix is already available. - * - * @template {number[] | Float64Array} T - * @category KNN - * @class - * @extends KNN - */ -class NaiveKNN extends KNN { - /** - * Generates a KNN list with given `elements`. - * - * @param {T[]} elements - Elements which should be added to the KNN list - * @param {ParametersNaiveKNN} parameters - */ - constructor(elements, parameters = {}) { - const params = Object.assign({ metric: euclidean, seed: 1212 }, parameters); - super(elements, params); - const N = - this._elements instanceof Matrix - ? /** @type {any} */ (this._elements).shape[0] - : this._elements.length; - if (this._parameters.metric === "precomputed") { - this._D = Matrix.from( - /** @type {number[][] | Float64Array[]} */ (/** @type {any} */ (this._elements)), - ); - } else { - this._D = distance_matrix( - /** @type {number[][] | Float64Array[]} */ (this._elements), - this._parameters.metric, - ); - } - - /** @type {Heap<{ value: number; index: number }>[]} */ - this.KNN = []; - for (let row = 0; row < N; ++row) { - const distances = this._D.row(row); - /** @type {Heap<{ value: number; index: number }>} */ - const H = new Heap(null, (d) => d.value, "min"); - for (let j = 0; j < N; ++j) { - H.push({ - value: distances[j], - index: j, - }); - } - this.KNN.push(H); - } - } - - /** - * @param {number} i - * @param {number} k - */ - search_by_index(i, k = 5) { - if (this._parameters.metric === "precomputed") { - const H = this.KNN[i]; - /** @type {{ element: T; index: number; distance: number }[]} */ - const result = []; - const data = H.toArray(); // Get array representation - const temp_heap = new Heap(data, (d) => d.value, "min"); - const N = - this._elements instanceof Matrix - ? /** @type {any} */ (this._elements).shape[0] - : this._elements.length; - for (let j = 0; j < Math.min(k, N); ++j) { - const node = temp_heap.pop(); - if (!node) break; - result.push({ - element: /** @type {T} */ ( - this._elements instanceof Matrix - ? /** @type {any} */ (this._elements).row(node.element.index) - : this._elements[node.element.index] - ), - index: /** @type {number} */ (node.element.index), - distance: /** @type {number} */ (node.value), - }); - } - return result; - } - return this.search( - /** @type {T} */ ( - this._elements instanceof Matrix - ? /** @type {any} */ (this._elements).row(i) - : this._elements[i] - ), - k, - ); - } - - /** - * @param {T} t - Query element. - * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5` - * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors. - */ - search(t, k = 5) { - if (this._parameters.metric === "precomputed") { - throw new Error( - "Search by query element is only possible when not using a precomputed distance matrix!", - ); - } - /** @type {import("../metrics/index.js").Metric} */ - const metric = /** @type {any} */ (this._parameters.metric); - - const isMatrix = this._elements instanceof Matrix; - const elementsAny = /** @type {any} */ (this._elements); - const N = isMatrix ? elementsAny.shape[0] : this._elements.length; - - // Compute distances from query to ALL points - const distances = []; - for (let i = 0; i < N; i++) { - const element = /** @type {T} */ (isMatrix ? elementsAny.row(i) : this._elements[i]); - distances.push({ - element: element, - index: i, - distance: metric(t, element), - }); - } - - // Sort by distance and return k nearest - distances.sort((a, b) => a.distance - b.distance); - return distances.slice(0, k); - } -} + /** Initializes TopoMap. Sets all projcted points to zero, and computes a minimum spanning tree. */ + init() { + const { metric } = this._parameters; + this.Y = new Matrix(this._N, 2, 0); + this._Emst = this._make_minimum_spanning_tree(metric); + this._is_initialized = true; + return this; + } -/** @import {ParametersNNDescent} from "./index.js" */ -/** - * - * @template {number[] | Float64Array} T - * @typedef {Object} NNDescentElement - * @property {T} value - * @property {number} index - * @property {boolean} flag - */ + /** + * Returns true if Point C is left of line AB. + * + * @private + * @param {Float64Array} PointA - Point A of line AB + * @param {Float64Array} PointB - Point B of line AB + * @param {Float64Array} PointC - Point C + * @returns {boolean} + */ + __hull_cross([ax, ay], [bx, by], [sx, sy]) { + return (bx - ax) * (sy - ay) - (by - ay) * (sx - ax) <= 0; + } -/** - * @template {number[] | Float64Array} T - * @typedef {Object} NNDescentNeighbor - * @property {T} value - * @property {number} index - * @property {number} distance - * @property {boolean} [flag] - */ + /** + * Computes the convex hull of the set of Points S + * + * @private + * @param {Float64Array[]} S - Set of Points. + * @returns {Float64Array[]} Convex hull of S. Starts at the bottom-most point and continues counter-clockwise. + * @see {@link https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain#JavaScript} + */ + __hull(S) { + const points = S.sort(([x1, y1], [x2, y2]) => y1 - y2 || x1 - x2); + const N = points.length; + if (N <= 2) return points; -/** - * NN-Descent - * - * An efficient graph-based approximate nearest neighbor search algorithm. - * It works by iteratively improving a neighbor graph using the fact that - * "neighbors of neighbors are likely to be neighbors". - * - * @class - * @category KNN - * @template {number[] | Float64Array} T - * @extends KNN - * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf|NN-Descent Paper} - */ -class NNDescent extends KNN { - /** - * @private - * @type {KNNHeap[]} - */ - _B = []; - /** - * @private - * @type {NNDescentNeighbor[][]} - */ - nn = []; - - /** - * @param {T[]} elements - Called V in paper. - * @param {Partial} parameters - * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf} - */ - constructor(elements, parameters = {}) { - super( - elements, - /** @type {ParametersNNDescent} */ ( - Object.assign({ metric: euclidean, K: 10, rho: 1, delta: 1e-3, seed: 1212 }, parameters) - ), - ); - this._N = elements.length; - this._randomizer = new Randomizer(this._parameters.seed); - this._sample_size = this._parameters.samples * this._parameters.rho; - - this._nndescent_elements = elements.map((e, i) => { - return { - value: e, - index: i, - flag: true, - }; - }); - - if (elements) { - this.add(elements); - } - } - - /** - * Samples Array A with sample size. - * - * @private - * @template U - * @param {U[]} A - * @returns {U[]} - */ - _sample(A) { - const n = A.length; - const sample_size = this._sample_size; - if (sample_size > n) { - return A; - } else { - const randomizer = this._randomizer; - return randomizer.choice(A, sample_size); - } - } - - /** - * @private - * @param {KNNHeap} B - * @param {NNDescentNeighbor} u - * @returns {number} - */ - _update(B, u) { - if (B.set.has(u.index)) return 0; - - const worst = B.first; - if (worst && B.length >= this._parameters.samples) { - const dist = B._accessor(u); - const worst_dist = B._accessor(worst.element); - if (dist >= worst_dist) { - return 0; // u is worse than the worst neighbor - } - } - - B.push(u); - u.flag = true; - if (B.length > this._parameters.samples) { - B.pop(); - } - return 1; - } - - /** - * @private - * @param {(KNNHeap | null)[]} B - * @returns {NNDescentNeighbor[][]} - */ - _reverse(B) { - const N = this._N; - const R = new Array(N); - for (let i = 0; i < N; i++) { - R[i] = []; - } - for (let j = 0; j < N; j++) { - const Bi = B[j]; - if (Bi) { - const Bjdata = Bi.data(); - for (const neighbor of Bjdata) { - const v = neighbor.index; - R[v].push(neighbor); - } - } - } - return R; - } - - /** - * @param {T[]} elements - * @returns {this} - */ - add(elements) { - const randomizer = this._randomizer; - const metric = this._parameters.metric; - const K = this._parameters.samples; - const delta = this._parameters.delta; - const N = elements.length; - this._N = N; - /** @type {KNNHeap[]} */ - const B = []; - this._B = B; - for (let i = 0; i < N; i++) { - const e = elements[i]; - const sample = randomizer - .choice( - elements.map((el, idx) => ({ el, idx })), - K, - ) - .map((d) => { - return { index: d.idx, distance: metric(d.el, e), value: d.el }; - }); - const Bi = new KNNHeap(sample, (d) => d.distance, "max"); - B.push(Bi); - } - - let c = Infinity; - let old_c = -Infinity; - while (c > delta * N * K && c !== old_c) { - const old_ = new Array(N); - const new_ = new Array(N); - for (let i = 0; i < N; i++) { - const Bi = B[i].data(); - const falseBs = Bi.filter((d) => !d.flag); - const trueBs = this._sample(Bi.filter((d) => d.flag)); - for (const d of trueBs) { - d.flag = false; - } - old_[i] = new KNNHeap(falseBs, (d) => d.distance, "max"); - new_[i] = new KNNHeap(trueBs, (d) => d.distance, "max"); - } - const old_reverse = this._reverse(old_); - const new_reverse = this._reverse(new_); - old_c = c; - c = 0; - for (let i = 0; i < N; i++) { - for (const o of this._sample(old_reverse[i])) { - old_[i].push(o); - } - for (const n of this._sample(new_reverse[i])) { - new_[i].push(n); - } - - const new_i = new_[i].data(); - const old_i = old_[i].data(); - const n1 = new_i.length; - const n2 = old_i.length; - for (let j = 0; j < n1; j++) { - const u1 = new_i[j]; - const Bu1 = B[u1.index]; - for (let k = 0; k < n1; k++) { - const u2 = new_i[k]; - if (u1.index === u2.index) continue; - const Bu2 = B[u2.index]; - c += this._update(Bu2, u1); - c += this._update(Bu1, u2); - } - for (let k = 0; k < n2; k++) { - const u2 = old_i[k]; - if (u1.index === u2.index) continue; - const Bu2 = B[u2.index]; - c += this._update(Bu2, u1); - c += this._update(Bu1, u2); - } - } - } - } - this.nn = this._B.map((heap) => heap.data()); - return this; - } - - /** - * @param {T} x - * @param {number} [k=5] Default is `5` - * @returns {{ element: T, index: number; distance: number }[]} - */ - search(x, k = 5) { - const metric = this._parameters.metric; - const N = this._N; - const elements = this._elements; - - if (N === 0) return []; - const xLength = x.length; - - // Initialize candidate pool - const visited = new Set(); - /** @type {{index: number, dist: number, evaluated: boolean}[]} */ - let pool = []; - - // Randomly pick initial candidates - const randomizer = this._randomizer; - for (let i = 0; i < Math.min(N, Math.max(k * 10, 50)); i++) { - let rnd; - do { - rnd = randomizer.random_int % N; - } while (visited.has(rnd)); - visited.add(rnd); - - const element = elements[rnd]; - if (!element || element.length !== xLength) continue; - - pool.push({ - index: rnd, - dist: metric(x, element), - evaluated: false, - }); - } - - let searching = true; - while (searching) { - pool.sort((a, b) => a.dist - b.dist); - // keep the top subset for exploration - pool = pool.slice(0, Math.max(k * 5, 50)); - - searching = false; - for (let i = 0; i < pool.length; i++) { - const candidate = pool[i]; - if (candidate.evaluated) continue; - - candidate.evaluated = true; - searching = true; - - // get neighbors of this candidate from graph - const neighbors = this.nn[candidate.index]; - if (!neighbors) continue; - - for (const neighbor of neighbors) { - const n_idx = neighbor.index; - if (!visited.has(n_idx)) { - visited.add(n_idx); - const element = elements[n_idx]; - if (element && element.length === xLength) { - pool.push({ - index: n_idx, - dist: metric(x, element), - evaluated: false, - }); + const lower = []; + for (let i = 0; i < N; ++i) { + while ( + lower.length >= 2 && + this.__hull_cross(lower[lower.length - 2], lower[lower.length - 1], points[i]) + ) { + lower.pop(); + } + lower.push(points[i]); + } + const upper = []; + for (let i = N - 1; i >= 0; --i) { + while ( + upper.length >= 2 && + this.__hull_cross(upper[upper.length - 2], upper[upper.length - 1], points[i]) + ) { + upper.pop(); } - } + upper.push(points[i]); } - // Don't break here! Look at more candidates per iteration for better convergence - // break; - } + upper.pop(); + lower.pop(); + return lower.concat(upper); } - pool.sort((a, b) => a.dist - b.dist); - - /** @type {{ element: T, index: number; distance: number }[]} */ - const result = []; - for (let i = 0; i < Math.min(k, pool.length); i++) { - const item = pool[i]; - result.push({ - element: elements[item.index], - index: item.index, - distance: item.dist, - }); + /** + * Finds the angle to rotate Point A and B to lie on a line parallel to the x-axis. + * + * @private + * @param {Float64Array} PointA + * @param {Float64Array} PointB + * @returns {{ sin: number; cos: number }} Object containing the sinus- and cosinus-values for a rotation. + */ + __findAngle([p1x, p1y], [p2x, p2y]) { + const n = euclidean([p1x, p1y], [p2x, p2y]); + if (n === 0) + return { + sin: 0, + cos: 1, + }; + const vec = [(p2x - p1x) / n, (p2y - p1y) / n]; + const cos = vec[0]; + let sin = Math.sqrt(1 - cos * cos); + sin = vec[1] >= 0 ? -sin : sin; + return { + sin: sin, + cos: cos, + }; } - return result; - } - - /** - * @param {number} i - * @param {number} [k=5] Default is `5` - * @returns {{ element: T; index: number; distance: number }[]} - */ - search_by_index(i, k = 5) { - // Use regular search with the element at index i - const elements = this._elements; - if (i < 0 || i >= elements.length) return []; - - const element = elements[i]; - if (!element) return []; - - return this.search(element, k); - } -} -/** - * @template {number[] | Float64Array} U - * @typedef {Object} HeapEntry - * @property {NNDescentNeighbor} element - * @property {number} value - */ + /** + * @private + * @param {Float64Array[]} hull + * @param {Float64Array} p + * @param {boolean} topEdge + * @returns {{ sin: number; cos: number; tx: number; ty: number }} + */ + __align_hull(hull, p, topEdge) { + let v = -1; + /** @type {number} */ + let d2 = -Infinity; + for (let i = 0; i < hull.length; ++i) { + const d = euclidean(hull[i], p); + if (v === -1) { + d2 = d; + v = i; + } else { + if (d2 > d) { + d2 = d; + v = i; + } + } + } -/** - * @template {number[] | Float64Array} U - * @extends {Heap>} - */ -class KNNHeap extends Heap { - /** @type {Set} */ - set; - - /** - * @param {NNDescentNeighbor[]} elements - * @param {(d: NNDescentNeighbor) => number} accessor - * @param {"max" | "min"} comparator - */ - constructor(elements, accessor, comparator) { - super(null, accessor, comparator); - this.set = new Set(); - if (elements) { - for (const element of elements) { - this.push(element); - } - } - } - - /** - * @param {NNDescentNeighbor} element - * @returns {KNNHeap} - */ - push(element) { - const set = this.set; - if (set.has(element.index)) { - return this; - } else { - set.add(element.index); - super.push(element); - return this; - } - } - - /** @returns {{ element: NNDescentNeighbor; value: number } | null} */ - pop() { - const result = super.pop(); - if (result?.element) { - this.set.delete(result.element.index); - return result; - } - return null; - } - - /** @returns {NNDescentNeighbor[]} */ - data() { - return this._container.map((d) => d.element); - } -} + const v1 = hull[v]; + let v2; + if (topEdge) { + v2 = hull[(v + 1) % hull.length]; + } else { + v2 = hull[(v - 1 + hull.length) % hull.length]; + } -/** @import {InputType} from "../index.js" */ -/** @import {ParametersSMACOF} from "./index.js" */ + /** @type {{ sin?: number; cos?: number; tx: number; ty: number }} */ + const transformation = { + tx: -v1[0], + ty: -v1[1], + }; -/** - * Metric Multidimensional Scaling (MDS) via SMACOF. - * - * SMACOF (Scaling by Majorizing a Complicated Function) is an iterative majorization - * algorithm for solving metric multidimensional scaling problems, which aims to - * minimize the stress function. - * - * @class - * @template {InputType} T - * @extends DR - * @category Dimensionality Reduction - * @see {@link MDS} for the classical approach. - */ -class SMACOF extends DR { - /** - * SMACOF for MDS. - * - * @param {T} X - The high-dimensional data or precomputed distance matrix. - * @param {Partial} [parameters] - Object containing parameterization. - */ - constructor(X, parameters = {}) { - super(X, { d: 2, metric: euclidean, seed: 1212, iterations: 300, epsilon: 1e-4 }, parameters); - } - - /** - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - *generator() { - this.check_init(); - const X = this.X; - const rows = this._N; - const d = /** @type {number} */ (this.parameter("d")); - const metric = /** @type {typeof euclidean | "precomputed"} */ (this.parameter("metric")); - const iterations = /** @type {number} */ (this.parameter("iterations")); - const epsilon = /** @type {number} */ (this.parameter("epsilon")); - - const target_distances = metric === "precomputed" ? X : distance_matrix(X, metric); - - let Z = new Matrix(rows, d, () => (this._randomizer.random - 0.5) * 2); - - // Center Z - for (let j = 0; j < d; ++j) { - const col = Z.col(j); - const mean = col.reduce((a, b) => a + b, 0) / rows; - for (let i = 0; i < rows; ++i) { - Z.sub_entry(i, j, mean); - } - } - - this.Y = /** @type {Matrix} */ (Z); // Initial state - - let prev_stress = Infinity; - - if (!(iterations > 0)) { - yield this.projection; - return this.projection; - } - - for (let iter = 0; iter < iterations; ++iter) { - const B = new Matrix(rows, rows, 0); - - for (let i = 0; i < rows; ++i) { - let bii = 0; - const z_i = Z.row(i); - for (let j = 0; j < rows; ++j) { - if (i === j) continue; - const z_j = Z.row(j); - const dist_Z = euclidean(z_i, z_j); - const dist_target = target_distances.entry(i, j); - - let bij = 0; - if (dist_Z > 1e-12) { - bij = -dist_target / dist_Z; - } - B.set_entry(i, j, bij); - bii -= bij; - } - B.set_entry(i, i, bii); - } - - // Z_new = 1/N * B(Z) * Z - const Z_new = B.dot(Z)._apply(rows, (val, n) => val / n); - - this.Y = /** @type {Matrix} */ (Z_new); - Z = /** @type {Matrix} */ (Z_new); - - // Calculate stress - let stress_num = 0; - let stress_den = 0; - for (let i = 0; i < rows; ++i) { - const z_i = Z.row(i); - for (let j = i + 1; j < rows; ++j) { - const z_j = Z.row(j); - const dist_Y = euclidean(z_i, z_j); - const diff = target_distances.entry(i, j) - dist_Y; - stress_num += diff * diff; - stress_den += target_distances.entry(i, j) ** 2; - } - } - const current_stress = Math.sqrt(stress_num / Math.max(stress_den, 1e-12)); - - yield this.projection; - - if (Math.abs(prev_stress - current_stress) < epsilon) { - break; - } - prev_stress = current_stress; - } - return this.projection; - } - - /** - * @returns {T} - */ - transform() { - const gen = this.generator(); - let res = /** @type {T} */ (this.X); - for (const step of gen) { - res = step; - } - return res; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X, parameters) { - const dr = new SMACOF(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new SMACOF(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new SMACOF(X, parameters); - return dr.transform_async(); - } -} + if (hull.length >= 2) { + const { sin, cos } = this.__findAngle(v1, v2); + transformation.sin = sin; + transformation.cos = cos; + } else { + transformation.sin = 0; + transformation.cos = 1; + } -/** @import {InputType} from "../index.js" */ -/** @import {ParametersISOMAP} from "./index.js" */ -/** @import {EigenArgs} from "../linear_algebra/index.js" */ + return /** @type {{ sin: number; cos: number; tx: number; ty: number }} */ (transformation); + } -/** - * Isomap (Isometric Mapping) - * - * A nonlinear dimensionality reduction algorithm that uses geodesic distances - * between points on a manifold to perform embedding. It builds a neighborhood - * graph and uses MDS on the shortest-path distances. - * - * @class - * @template {InputType} T - * @extends DR - * @category Dimensionality Reduction - * @see {@link LLE} for another nonlinear alternative - */ -class ISOMAP extends DR { - /** - * Isometric feature mapping (ISOMAP). - * - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - * @see {@link https://doi.org/10.1126/science.290.5500.2319} - */ - constructor(X, parameters = {}) { - /** @type {ParametersISOMAP} */ - const defaults = { - neighbors: -Infinity, - d: 2, - metric: euclidean, - seed: 1212, - project: "MDS", - eig_args: {}, - }; - super(X, defaults, parameters); - - this.defaults = defaults; - - if (this._parameters.neighbors === -Infinity) { - this.parameter( - "neighbors", - Math.min(Math.max(Math.floor(this.X.shape[0] / 10), 2), this._N - 1), - ); - } - - const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); - if (!Object.hasOwn(eig_args, "seed")) { - eig_args.seed = this._randomizer; - } - } - - /** - * Computes the projection. - * - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - *generator() { - yield this.transform(); - return this.projection; - } - - /** - * @returns {T} - */ - transform() { - this.check_init(); - const X = this.X; - const rows = this._N; - const d = /** @type {number} */ (this.parameter("d")); - const metric = /** @type {typeof euclidean} */ (this.parameter("metric")); - const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); - const neighbors = /** @type {number} */ (this.parameter("neighbors")); - // TODO: make knn extern and parameter for constructor or transform? - const D = new Matrix(rows, rows, 0); - D.shape = [rows, rows, (i, j) => (i <= j ? metric(X.row(i), X.row(j)) : D.entry(j, i))]; - - /** @type {{ index: number; distance: number }[][]} */ - const kNearestNeighbors = []; - const tree = new BallTree(X.to2dArray(), { - metric, - seed: /** @type {number} */ (this.parameter("seed")), - }); - for (let i = 0; i < rows; ++i) { - // BallTree search returns elements including the queried point itself (at distance 0). - // Request neighbors + 1 and slice off the first one (which should be the query point). - const neighborsList = tree.search_by_index(i, neighbors + 1); - kNearestNeighbors.push( - neighborsList.slice(1).map((n) => ({ - index: n.index, - distance: n.distance, - })), - ); - } - - // ISOMAP requires an undirected/symmetric nearest neighbor graph. - // If i is a nearest neighbor of j, then j should be connected to i as well. - for (let i = 0; i < rows; ++i) { - for (const neighbor of kNearestNeighbors[i]) { - const j = neighbor.index; - const d = neighbor.distance; - const reciprocal_edge = kNearestNeighbors[j].find((n) => n.index === i); - if (!reciprocal_edge) { - kNearestNeighbors[j].push({ index: i, distance: d }); - } - } - } - - /*D = dijkstra(kNearestNeighbors);*/ - // compute shortest paths using Dijkstra's algorithm - // TODO: make extern - const G = new Matrix(rows, rows, Infinity); - - for (let i = 0; i < rows; ++i) { - G.set_entry(i, i, 0); - const H = new Heap([{ index: i, distance: 0 }], (d) => d.distance, "min"); - - while (!H.empty) { - const item = H.pop(); - if (!item) break; - - const u = item.element.index; - const dist_u = item.element.distance; - - if (dist_u > G.entry(i, u)) continue; - - for (const neighbor of kNearestNeighbors[u]) { - const v = neighbor.index; - const alt = dist_u + neighbor.distance; - if (alt < G.entry(i, v)) { - G.set_entry(i, v, alt); - H.push({ index: v, distance: alt }); - } - } - } - } - - let max_val = 0; - for (let i = 0; i < rows; i++) { - for (let j = 0; j < rows; j++) { - const val = G.entry(i, j); - if (val !== Infinity && val > max_val) max_val = val; - } - } - const big_val = max_val * 10; - - const project = /** @type {"MDS" | "SMACOF"} */ (this.parameter("project")); - - if (project === "SMACOF") { - // Apply SMACOF metric MDS to the distance matrix directly - const D_matrix = new Matrix(rows, rows, (i, j) => { - const val = G.entry(i, j); - return val === Infinity ? big_val : val; - }); - const smacof = new SMACOF(D_matrix, { - metric: "precomputed", - d, - seed: this.parameter("seed"), - }); - smacof.transform(); - this.Y = smacof.Y; - } else { - // "MDS" (Classical MDS) via Eigendecomposition of double-centered squared distance matrix - const D_sq = new Matrix(rows, rows, (i, j) => { - let val = G.entry(i, j); - if (val === Infinity) val = big_val; - return val * val; - }); - - const ai_ = D_sq.meanCols(); - const a_j = D_sq.meanRows(); - const a__ = D_sq.mean(); - const B = new Matrix(rows, rows, (i, j) => -0.5 * (D_sq.entry(i, j) - ai_[i] - a_j[j] + a__)); - - // compute d eigenvectors - const { eigenvectors: V } = simultaneous_poweriteration(B, d, eig_args); - this.Y = Matrix.from(V).transpose(); - } - // return embedding - return this.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X, parameters) { - const dr = new ISOMAP(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new ISOMAP(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new ISOMAP(X, parameters); - return dr.transform_async(); - } -} + /** + * @private + * @param {Float64Array} Point - The point which should get transformed. + * @param {{ sin: number; cos: number; tx: number; ty: number }} Transformation - Contains the values for + * translation and rotation. + */ + __transform([px, py], { tx, ty, sin, cos }) { + const x = px + tx; + const y = py + ty; + const xx = x * cos - y * sin; + const yy = x * sin + y * cos; + return [xx, yy]; + } -/** @import {InputType} from "../index.js" */ -/** @import {ParametersLDA} from "./index.js" */ -/** @import {EigenArgs} from "../linear_algebra/index.js" */ + /** + * Calls `__transform` for each point in Set C + * + * @private + * @param {Float64Array[]} C - Set of points. + * @param {{ sin: number; cos: number; tx: number; ty: number }} t - Transform object. + * @param {number} yOffset - Value to offset set C. + */ + __transform_component(C, t, yOffset) { + const N = C.length; + for (let i = 0; i < N; ++i) { + const c = C[i]; + const [cx, cy] = this.__transform(c, t); + c[0] = cx; + c[1] = cy + yOffset; + } + } -/** - * Linear Discriminant Analysis (LDA) - * - * A supervised dimensionality reduction technique that finds the axes that - * maximize the separation between multiple classes. - * - * @class - * @template {InputType} T - * @extends DR - * @category Dimensionality Reduction - */ -class LDA extends DR { - /** - * Linear Discriminant Analysis. - * - * @param {T} X - The high-dimensional data. - * @param {Partial & { labels: any[] | Float64Array }} parameters - Object containing parameterization of the DR method. - * @see {@link https://onlinelibrary.wiley.com/doi/10.1111/j.1469-1809.1936.tb02137.x} - */ - constructor(X, parameters) { - super(X, { labels: parameters.labels, d: 2, seed: 1212, eig_args: {} }, parameters); - const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); - if (!Object.hasOwn(eig_args, "seed")) { - eig_args.seed = this._randomizer; - } - } - - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - *generator() { - yield this.transform(); - return this.projection; - } - - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {T} - The projected data. - */ - transform() { - const X = this.X; - const [rows, cols] = X.shape; - const { d, labels, eig_args } = this._parameters; - if (labels === null || labels.length !== rows) { - throw new Error("LDA needs parameter label to every datapoint to work!"); - } - - /** @type {Record} */ - const unique_labels = {}; - let label_id = 0; - labels.forEach((l, i) => { - if (l in unique_labels) { - unique_labels[l].count++; - unique_labels[l].rows.push(X.row(i)); - } else { - unique_labels[l] = { - id: label_id++, - count: 1, - rows: [X.row(i)], - }; - } - }); - - // create X_mean and vector means; - const X_mean = X.meanCols(); - const V_mean = new Matrix(label_id, cols); - for (const label in unique_labels) { - const V = Matrix.from(unique_labels[label].rows); - const v_mean = V.meanCols(); - for (let j = 0; j < cols; ++j) { - V_mean.set_entry(unique_labels[label].id, j, v_mean[j]); - } - } - // scatter_between - let S_b = new Matrix(cols, cols); - for (const label in unique_labels) { - const v = V_mean.row(unique_labels[label].id); - const m = Matrix.from([v]).sub(Matrix.from([X_mean])); - const N = unique_labels[label].count; - S_b = S_b.add(m.transDot(m).mult(N)); - } - - // scatter_within - let S_w = new Matrix(cols, cols); - for (const label in unique_labels) { - const v = V_mean.row(unique_labels[label].id); - const R = unique_labels[label].rows; - for (let i = 0, n = unique_labels[label].count; i < n; ++i) { - const row_v = Matrix.from([R[i]]).sub(Matrix.from([v])); - S_w = S_w.add(row_v.transDot(row_v)); - } - } - - const { eigenvectors: EV } = simultaneous_poweriteration( - S_w.inverse().dot(S_b), - d || Math.min(cols, label_id - 1), - eig_args, - ); - const V = Matrix.from(EV).transpose(); - this.Y = X.dot(V); - - // return embedding - return this.projection; - } - - /** - * @template {InputType} T - * @template {{ seed?: number }} Para - * @param {T} X - * @param {Para} parameters - * @returns {T} - */ - static transform(X, parameters) { - // @ts-expect-error: LDA requires labels, but DR static transform doesn't - const dr = new LDA(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @template {{ seed?: number }} Para - * @param {T} X - * @param {Para} parameters - * @returns {Generator} - */ - static *generator(X, parameters) { - // @ts-expect-error: LDA requires labels, but DR static generator doesn't - const dr = new LDA(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @template {{ seed?: number }} Para - * @param {T} X - * @param {Para} parameters - * @returns {Promise} - */ - static async transform_async(X, parameters) { - // @ts-expect-error: LDA requires labels, but DR static transform doesn't - const dr = new LDA(X, parameters); - return dr.transform_async(); - } -} + /** + * @private + * @param {Float64Array} root_u - Root of component u + * @param {Float64Array} root_v - Root of component v + * @param {Float64Array} p_u - Point u + * @param {Float64Array} p_v - Point v + * @param {number} w - Edge weight w + * @param {DisjointSet} components - The disjoint set containing the components + */ + __align_components(root_u, root_v, p_u, p_v, w, components) { + if (!components) throw new Error("components not provided!"); + const u_children = components.get_children(root_u); + const v_children = components.get_children(root_v); + if (!u_children || !v_children) throw new Error("should not happen!"); -/** @import {InputType} from "../index.js" */ -/** @import {ParametersLLE} from "./index.js" */ -/** @import {EigenArgs} from "../linear_algebra/index.js" */ + const points_u = [...u_children]; + const points_v = [...v_children]; + + const hull_u = this.__hull(points_u); + const hull_v = this.__hull(points_v); + + const t_u = this.__align_hull(hull_u, p_u, false); + const t_v = this.__align_hull(hull_v, p_v, true); + + this.__transform_component(points_u, t_u, 0); + this.__transform_component(points_v, t_v, w); + } + + /** + * Transforms the inputdata `X` to dimensionality 2. + * + * @returns {T} + */ + transform() { + if (!this._is_initialized) this.init(); + if (!this._Emst) throw new Error("Call init() first!"); + const Emst = this._Emst; + const Y = this.Y.to2dArray(); + /** @type {DisjointSet} */ + const components = new DisjointSet( + Y, + // Y.map((y, i) => { + // y.i = i; + // return y; + // }), + ); -/** - * Locally Linear Embedding (LLE) - * - * A nonlinear dimensionality reduction technique that preserves local - * linear relationships between points. It represents each point as a linear - * combination of its neighbors. - * - * @class - * @template {InputType} T - * @extends DR - * @category Dimensionality Reduction - * @see {@link ISOMAP} for another nonlinear alternative - */ -class LLE extends DR { - /** - * Locally Linear Embedding. - * - * @param {T} X - The high-dimensional data. - * @param {Partial} parameters - Object containing parameterization of the DR method. - * @see {@link https://doi.org/10.1126/science.290.5500.2323} - */ - constructor(X, parameters) { - super( - X, - { - neighbors: -Infinity, - d: 2, - metric: euclidean, - seed: 1212, - eig_args: {}, - }, - parameters, - ); - if (this._parameters.neighbors === -Infinity) { - this.parameter("neighbors", Math.min(Math.max(Math.floor(this._N / 10), 2), this._N - 1)); - } - - const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); - if (!Object.hasOwn(eig_args, "seed")) { - eig_args.seed = this._randomizer; - } - } - - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - *generator() { - yield this.transform(); - return this.projection; - } - - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {T} - */ - transform() { - const X = this.X; - const rows = this._N; - const cols = this._D; - const neighbors = /** @type {number} */ (this.parameter("neighbors")); - const d = /** @type {number} */ (this.parameter("d")); - const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); - const metric = /** @type {typeof euclidean} */ (this.parameter("metric")); - const nN = k_nearest_neighbors(X, neighbors, metric); - const O = new Matrix(neighbors, 1, 1); - const W = new Matrix(rows, rows); + for (const [u, v, w] of Emst) { + const p_u = Y[u]; + const p_v = Y[v]; + const component_u = components.find(p_u); + const component_v = components.find(p_v); + if (!component_u || !component_v) throw new Error("Should not happen!"); + if (component_u === component_v) continue; + this.__align_components(component_u, component_v, p_u, p_v, w, components); + components.union(component_u, component_v); + } + return this.projection; + } - for (let row = 0; row < rows; ++row) { - const nN_row = nN[row]; - const Z = new Matrix(neighbors, cols, (i, j) => X.entry(nN_row[i].j, j) - X.entry(row, j)); - const C = Z.dotTrans(Z); - if (neighbors > cols) { - const C_trace = neumair_sum(C.diag()) / 1000; - for (let j = 0; j < neighbors; ++j) { - C.add_entry(j, j, C_trace); - } - } - // reconstruct; - let w = Matrix.solve_CG(C, O, this._randomizer); - w = w.divide(w.sum()); - for (let j = 0; j < neighbors; ++j) { - W.set_entry(row, nN_row[j].j, w.entry(j, 0)); - } - } - // comp embedding - const I = new Matrix(rows, rows, "identity"); - const IW = I.sub(W); - const M = IW.transDot(IW); - - // M is symmetric positive semi-definite. Smallest eigenvalue is 0 (ones vector). - // To find smallest eigenvalues of M, we can find largest of (C*I - M) - // Upper bound for max eigenvalue: Frobenius norm or sum of absolute values - const C = M.mean() * rows * 2; // Safe upper bound for a sparse-ish M in LLE - const CI_M = new Matrix(rows, rows, (i, j) => (i === j ? C : 0) - M.entry(i, j)); - - const { eigenvectors: V } = simultaneous_poweriteration(CI_M, d + 1, eig_args); - // Skip the first eigenvector (the ones vector corresponding to eigenvalue C) - this.Y = Matrix.from(V.slice(1, 1 + d)).T; - - // return embedding - return this.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {T} - */ - static transform(X, parameters) { - const dr = new LLE(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new LLE(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new LLE(X, parameters); - return dr.transform_async(); - } -} + /** + * Transforms the inputdata `X` to dimensionality 2. + * + * @returns {Generator} + */ + *generator() { + if (!this._is_initialized) this.init(); + if (!this._Emst) throw new Error("call init() first!"); + const Emst = this._Emst; + const Y = this.Y.to2dArray(); + const components = new DisjointSet( + Y, + // Y.map((y, i) => { + // y.i = i; + // return y; + // }), + ); -/** @import {InputType} from "../index.js" */ -/** @import {ParametersMDS} from "./index.js" */ -/** @import {EigenArgs} from "../linear_algebra/index.js" */ + for (const [u, v, w] of Emst) { + const p_u = Y[u]; + const p_v = Y[v]; + const component_u = components.find(p_u); + const component_v = components.find(p_v); + if (!component_u || !component_v) throw new Error("should not happen!"); + if (component_u === component_v) continue; + this.__align_components(component_u, component_v, p_u, p_v, w, components); + components.union(component_u, component_v); + yield this.projection; + } + return this.projection; + } -/** - * Classical Multidimensional Scaling (MDS) - * - * A linear dimensionality reduction technique that seeks to preserve the - * pairwise distances between points as much as possible in the lower-dimensional - * space. - * - * @class - * @template {InputType} T - * @extends DR - * @category Dimensionality Reduction - * @see {@link PCA} for another linear alternative - */ -class MDS extends DR { - /** - * Classical MDS. - * - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - */ - constructor(X, parameters = {}) { - super(X, { d: 2, metric: euclidean, seed: 1212, eig_args: {} }, parameters); - const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); - if (!Object.hasOwn(eig_args, "seed")) { - eig_args.seed = this._randomizer; - } - } - - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - *generator() { - yield this.transform(); - return this.projection; - } - - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {T} - */ - transform() { - const X = this.X; - const rows = X.shape[0]; - const d = /** @type {number} */ (this.parameter("d")); - const metric = /** @type {typeof euclidean | "precomputed"} */ (this.parameter("metric")); - const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); - const A = metric === "precomputed" ? X : distance_matrix(X, metric); - - const D_sq = new Matrix(rows, rows, (i, j) => { - const val = A.entry(i, j); - return val * val; - }); - - const ai_ = D_sq.meanCols(); - const a_j = D_sq.meanRows(); - const a__ = D_sq.mean(); - - this._d_X = A; - const B = new Matrix(rows, rows, (i, j) => -0.5 * (D_sq.entry(i, j) - ai_[i] - a_j[j] + a__)); - - const { eigenvectors: V } = simultaneous_poweriteration(B, d, eig_args); - this.Y = Matrix.from(V).transpose(); - - return this.projection; - } - - /** @returns {number} - The stress of the projection. */ - stress() { - const N = this.X.shape[0]; - const Y = this.Y; - const d_X = this._d_X; - if (!d_X) throw new Error("First transform!"); - - const d_Y = new Matrix(N, N, 0); - d_Y.shape = [ - N, - N, - (i, j) => { - return i < j ? euclidean(Y.row(i), Y.row(j)) : d_Y.entry(j, i); - }, - ]; - let top_sum = 0; - let bottom_sum = 0; - for (let i = 0; i < N; ++i) { - for (let j = i + 1; j < N; ++j) { - top_sum += (d_X.entry(i, j) - d_Y.entry(i, j)) ** 2; - bottom_sum += d_X.entry(i, j) ** 2; - } - } - return Math.sqrt(top_sum / bottom_sum); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X, parameters) { - const dr = new MDS(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new MDS(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new MDS(X, parameters); - return dr.transform_async(); - } -} + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {T} + */ + static transform(X, parameters) { + const dr = new TopoMap(X, parameters); + return dr.transform(); + } -/** @import {InputType} from "../index.js" */ -/** @import {ParametersLSP} from "./index.js" */ + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new TopoMap(X, parameters); + yield* dr.generator(); + return dr.projection; + } -/** - * Least Square Projection (LSP) - * - * A dimensionality reduction technique that uses a small set of control points - * (projected with MDS) to define the projection for the rest of the data - * using a Laplacian-based optimization. - * - * @class - * @template {InputType} T - * @extends DR - * @category Dimensionality Reduction - */ -class LSP extends DR { - /** - * Least Squares Projection. - * - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - * @see {@link https://ieeexplore.ieee.org/document/4378370} - */ - constructor(X, parameters) { - super( - X, - { - neighbors: -Infinity, - control_points: -Infinity, - d: 2, - metric: euclidean, - seed: 1212, - }, - parameters, - ); - if (this.parameter("neighbors") === -Infinity) { - this.parameter("neighbors", Math.min(Math.max(Math.floor(this._N / 10), 2), this._N - 1)); - } - if (this.parameter("control_points") === -Infinity) { - this.parameter("control_points", Math.min(Math.ceil(Math.sqrt(this._N)), this._N - 1)); - } - this._is_initialized = false; - } - - /** - * @returns {LSP} - */ - // init(DR = MDS, DR_parameters = {}, KNN = BallTree) { - init() { - const DR = MDS; - let DR_parameters = {}; - const KNN = BallTree; - if (this._is_initialized) return this; - const X = this.X; - const N = this._N; - const K = /** @type {number} */ (this.parameter("neighbors")); - const d = /** @type {number} */ (this.parameter("d")); - const seed = /** @type {number} */ (this.parameter("seed")); - const metric = /** @type {typeof euclidean} */ (this.parameter("metric")); - DR_parameters = Object.assign({ d, metric, seed }, DR_parameters); - const nc = /** @type {number} */ (this.parameter("control_points")); - const control_points = new KMedoids(X, { K: nc, metric }).get_medoids(); - const C = new Matrix(nc, N, "zeros"); - control_points.forEach((c_i, i) => { - C.set_entry(i, c_i, 1); - }); - - const control_points_matrix = Matrix.from(control_points.map((c_i) => X.row(c_i))); - const Y_C = new DR(control_points_matrix, DR_parameters).transform(); - - const XA = X.to2dArray(); - const knn = new KNN(XA, { metric, seed }); - const L = new Matrix(N, N, "I"); - const alpha = -1 / K; - XA.forEach((x_i, i) => { - for (const { index: j } of knn.search(x_i, K)) { - if (i === j) continue; - L.set_entry(i, j, alpha); - } - }); - const A = L.concat(C, "vertical"); - - const z = new Matrix(N, d, "zeros"); - const b = z.concat(Y_C, "vertical"); - - this._A = A; - this._b = b; - this._is_initialized = true; - return this; - } - - /** - * Computes the projection. - * - * @returns {T} Returns the projection. - */ - transform() { - this.check_init(); - const A = this._A; - const b = this._b; - - if (!A || !b) throw new Error("Call init() first!"); - const ATA = A.transDot(A); - const ATb = A.transDot(b); - this.Y = Matrix.solve_CG(ATA, ATb, this._randomizer); - return this.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X, parameters) { - const dr = new LSP(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new LSP(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new LSP(X, parameters); - return dr.transform_async(); - } + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new TopoMap(X, parameters); + return dr.transform_async(); + } } /** @import {InputType} from "../index.js" */ -/** @import {ParametersLTSA} from "./index.js" */ -/** @import {EigenArgs} from "../linear_algebra/index.js" */ +/** @import {Metric} from "../metrics/index.js" */ +/** @import {ParametersTriMap} from "./index.js" */ +/** @import {KNN} from "../knn/KNN.js" */ /** - * Local Tangent Space Alignment (LTSA) + * TriMap * - * A nonlinear dimensionality reduction algorithm that represents the local - * geometry of the manifold by tangent spaces and then aligns them to reveal - * the global structure. + * A dimensionality reduction technique that preserves both local and global + * structure using triplets. It is designed to be a more robust alternative + * to t-SNE and UMAP. * * @class * @template {InputType} T - * @extends DR + * @extends DR * @category Dimensionality Reduction */ -class LTSA extends DR { - /** - * Local Tangent Space Alignment - * - * @param {T} X - The high-dimensional data. - * @param {Partial} parameters - Object containing parameterization of the DR method. - * @see {@link https://epubs.siam.org/doi/abs/10.1137/S1064827502419154} - */ - constructor(X, parameters) { - super( - X, - { - neighbors: -Infinity, - d: 2, - metric: euclidean, - seed: 1212, - eig_args: {}, - }, - parameters, - ); - if (this.parameter("neighbors") === -Infinity) { - this.parameter("neighbors", Math.min(Math.max(Math.floor(this._N / 10), 2), this._N - 1)); - } - const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); - if (!Object.hasOwn(eig_args, "seed")) { - eig_args.seed = this._randomizer; - } - - const d = /** @type {number} */ (this.parameter("d")); - if (this._D <= d) { - throw new Error( - `Dimensionality of X (D = ${this._D}) must be greater than the required dimensionality of the result (d = ${d})!`, - ); - } - } - - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - *generator() { - yield this.transform(); - return this.projection; - } - - /** - * Transforms the inputdata `X` to dimenionality `d`. - * - * @returns {T} - */ - transform() { - const X = this.X; - const [rows, D] = X.shape; - const neighbors = /** @type {number} */ (this.parameter("neighbors")); - const d = /** @type {number} */ (this.parameter("d")); - const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); - const metric = /** @type {typeof euclidean} */ (this.parameter("metric")); - // 1.1 determine k nearest neighbors - const nN = k_nearest_neighbors(X, neighbors, metric); - // center matrix - const O = new Matrix(D, D, "center"); - const B = new Matrix(rows, rows, 0); +class TriMap extends DR { + /** + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + * @see {@link https://arxiv.org/pdf/1910.00204v1.pdf} + * @see {@link https://github.com/eamid/trimap} + */ + constructor(X, parameters) { + super( + X, + { + weight_adj: 500, + n_inliers: 10, + n_outliers: 5, + n_random: 5, + d: 2, + metric: euclidean, + tol: 1e-8, + seed: 1212, + }, + parameters, + ); + } - for (let row = 0; row < rows; ++row) { - // 1.2 compute the d largest eigenvectors of the correlation matrix - const I_i = [row, ...nN[row].map((n) => n.j)]; - let X_i = Matrix.from(I_i.map((n) => X.row(n))); - // center X_i - X_i = X_i.dot(O); - // correlation matrix - const C = X_i.dotTrans(X_i); - const { eigenvectors: g } = simultaneous_poweriteration(C, d, eig_args); - //g.push(linspace(0, k).map(_ => 1 / Math.sqrt(k + 1))); - const G_i_t = Matrix.from(g); - // 2. Constructing alignment matrix - const W_i = G_i_t.transDot(G_i_t).add(1 / Math.sqrt(neighbors + 1)); - for (let i = 0; i < neighbors + 1; ++i) { - for (let j = 0; j < neighbors + 1; ++j) { - B.add_entry(I_i[i], I_i[j], W_i.entry(i, j) - (i === j ? 1 : 0)); - } - } - } - - // 3. Aligning global coordinates - const { eigenvectors: Y } = simultaneous_poweriteration(B, d + 1, eig_args); - this.Y = Matrix.from(Y.slice(1)).transpose(); - - // return embedding - return this.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {T} - */ - static transform(X, parameters) { - const dr = new LTSA(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new LTSA(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new LTSA(X, parameters); - return dr.transform_async(); - } -} + /** + * @param {Matrix | null} [pca=null] - Initial Embedding (if null then PCA gets used). Default is `null` + * @param {import("../knn/KNN.js").KNN | null} [knn=null] - KNN Object (if null then BallTree gets used). Default is `null` + */ + init(pca = null, knn = null) { + const X = this.X; + const N = X.shape[0]; + //const c = /** @type {number} */ (this._parameters.c); + const d = /** @type {number} */ (this._parameters.d); + const metric = /** @type {Metric} */ (this._parameters.metric); + const seed = /** @type {number} */ (this._parameters.seed); + this.n_inliers = /** @type {number} */ (this._parameters.n_inliers); + this.n_outliers = /** @type {number} */ (this._parameters.n_outliers); + this.n_random = /** @type {number} */ (this._parameters.n_random); + this.Y = pca ?? PCA.transform(X, { d, seed }); + this.knn = knn ?? new BallTree(X.to2dArray(), { metric, seed }); + const { triplets, weights } = this._generate_triplets(this.n_inliers, this.n_outliers, this.n_random); + this.triplets = triplets; + this.weights = weights; + this.lr = (1000 * N) / triplets.shape[0]; + this.C = Infinity; + this.vel = new Matrix(N, d, 0); + this.gain = new Matrix(N, d, 1); + return this; + } -/** @import {InputType} from "../index.js" */ -/** @import {ParametersPCA} from "./index.js" */ -/** @import {EigenArgs} from "../linear_algebra/index.js" */ + /** + * Generates {@link n_inliers} x {@link n_outliers} x {@link n_random} triplets. + * + * @param {number} n_inliers + * @param {number} n_outliers + * @param {number} n_random + */ + _generate_triplets(n_inliers, n_outliers, n_random) { + const metric = /** @type {Metric} */ (this._parameters.metric); + const weight_adj = /** @type {number} */ (this._parameters.weight_adj); + const X = this.X; + const N = X.shape[0]; + const knn = this.knn; + if (!knn) throw new Error("Call init() first!"); + const n_extra = Math.min(n_inliers + 20, N); + const nbrs = new Matrix(N, n_extra); + const knn_distances = new Matrix(N, n_extra); + for (let i = 0; i < N; ++i) { + const results = knn + .search(X.row(i), n_extra + 1) + .filter((d) => d.distance !== 0) + .sort((a, b) => a.distance - b.distance); + + results.forEach((d, j) => { + if (j < n_extra) { + nbrs.set_entry(i, j, d.index); + knn_distances.set_entry(i, j, d.distance); + } + }); + } + // scale parameter + const sig = new Float64Array(N); + for (let i = 0; i < N; ++i) { + sig[i] = Math.max( + (knn_distances.entry(i, 3) + knn_distances.entry(i, 4) + knn_distances.entry(i, 5)) / 3, + 1e-10, + ); + } -/** - * Principal Component Analysis (PCA) - * - * A linear dimensionality reduction technique that identifies the axes (principal components) - * along which the variance of the data is maximized. - * - * @class - * @template {InputType} T - * @extends DR - * @category Dimensionality Reduction - * @see {@link MDS} for another linear alternative - * - * @example - * import * as druid from "@saehrimnir/druidjs"; - * - * const X = [[1, 2], [3, 4], [5, 6]]; - * const pca = new druid.PCA(X, { d: 2 }); - * const Y = pca.transform(); - * // [[x1, y1], [x2, y2], [x3, y3]] - */ -class PCA extends DR { - /** - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - */ - constructor(X, parameters = {}) { - super(X, { d: 2, seed: 1212, eig_args: {} }, parameters); - const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); - if (!Object.hasOwn(eig_args, "seed")) { - eig_args.seed = this._randomizer; - } - } - - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - *generator() { - yield this.transform(); - return this.projection; - } - - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {T} - The projected data. - */ - transform() { - const V = this.principal_components(); - const X = this.X; - this.Y = X.dot(V); - return this.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {T} - */ - static transform(X, parameters) { - const dr = new PCA(X, parameters); - return dr.transform(); - } - - /** - * Computes the `d` principal components of Matrix `X`. - * - * @returns {Matrix} - */ - principal_components() { - if (this.V) { - return this.V; - } - const d = /** @type {number} */ (this.parameter("d")); - const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); - const X = this.X; - const X_cent = X.sub(X.meanCols()); - const C = X_cent.transDot(X_cent); - const { eigenvectors: V } = simultaneous_poweriteration(C, d, eig_args); - this.V = Matrix.from(V).transpose(); - return this.V; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Matrix} - */ - static principal_components(X, parameters) { - const dr = new PCA(X, parameters); - return dr.principal_components(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new PCA(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new PCA(X, parameters); - return dr.transform_async(); - } -} + const P = this._find_p(knn_distances, sig, nbrs); -/** @import {InputType} from "../index.js" */ -/** @import {ParametersPCA, ParametersMDS, ParametersSAMMON} from "./index.js" */ -/** @typedef {"PCA" | "MDS" | "random"} AvailableInit */ + let triplets = this._sample_knn_triplets(P, nbrs, n_inliers, n_outliers); + let n_triplets = triplets.shape[0]; + const outlier_distances = new Float64Array(n_triplets); + for (let i = 0; i < n_triplets; ++i) { + const j = triplets.entry(i, 0); + const k = triplets.entry(i, 2); + outlier_distances[i] = metric(X.row(j), X.row(k)); + } + let weights = this._find_weights(triplets, P, nbrs, outlier_distances, sig); -/** @typedef {{ PCA: ParametersPCA; MDS: ParametersMDS; random: {} }} ChooseDR */ + if (n_random > 0) { + const { random_triplets, random_weights } = this._sample_random_triplets(X, n_random, sig); + triplets = triplets.concat(random_triplets, "vertical"); + weights = Float64Array.from([...weights, ...random_weights]); + } + n_triplets = triplets.shape[0]; + let max_weight = -Infinity; + for (let i = 0; i < n_triplets; ++i) { + if (Number.isNaN(weights[i])) { + weights[i] = 0; + } + if (max_weight < weights[i]) max_weight = weights[i]; + } + let max_weight_2 = -Infinity; + for (let i = 0; i < n_triplets; ++i) { + weights[i] /= max_weight; + weights[i] += 0.0001; + weights[i] = Math.log(1 + weight_adj * weights[i]); + if (max_weight_2 < weights[i]) max_weight_2 = weights[i]; + } + for (let i = 0; i < n_triplets; ++i) { + weights[i] /= max_weight_2; + } + return { + triplets: triplets, + weights: weights, + }; + } -/** - * Sammon's Mapping - * - * A nonlinear dimensionality reduction technique that minimizes a stress - * function based on the ratio of pairwise distances in high and low dimensional spaces. - * - * @class - * @template {InputType} T - * @extends DR> - * @category Dimensionality Reduction - */ -class SAMMON extends DR { - /** @type {Matrix | undefined} */ - distance_matrix; - - /** - * SAMMON's Mapping - * - * @param {T} X - The high-dimensional data. - * @param {Partial>} [parameters] - Object containing parameterization of the DR - * method. - * @see {@link https://arxiv.org/pdf/2009.01512.pdf} - */ - constructor(X, parameters) { - super( - X, - { - magic: 0.1, - d: 2, - metric: euclidean, - seed: 1212, - init_DR: "random", - init_parameters: {}, - }, - parameters, - ); - } - - /** - * Initializes the projection. - * - * @param {Matrix | undefined} D - * @returns {asserts D is Matrix} - */ - init(D) { - const N = this.X.shape[0]; - const d = /** @type {number} */ (this.parameter("d")); - const metric = /** @type {typeof euclidean | "precomputed"} */ (this.parameter("metric")); - const init_DR = /** @type {AvailableInit} */ (this.parameter("init_DR")); - const DR_parameters = this.parameter("init_parameters"); - if (init_DR === "random") { - const randomizer = this._randomizer; - this.Y = new Matrix(N, d, () => randomizer.random); - } else if (init_DR === "PCA") { - this.Y = Matrix.from(PCA.transform(this.X, /** @type {ParametersPCA} */ (DR_parameters))); - } else if (init_DR === "MDS") { - this.Y = Matrix.from(MDS.transform(this.X, /** @type {ParametersMDS} */ (DR_parameters))); - } else { - throw new Error('init_DR needs to be either "random" or a DR method!'); - } - D = metric === "precomputed" ? Matrix.from(this.X) : distance_matrix(this.X, metric); - this.distance_matrix = D; - } - - /** - * Transforms the inputdata `X` to dimensionality 2. - * - * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200` - * @returns {T} The projection of `X`. - */ - transform(max_iter = 200) { - this.check_init(); - if (!this.distance_matrix) this.init(this.distance_matrix); - for (let j = 0; j < max_iter; ++j) { - this._step(); - } - return this.projection; - } - - /** - * Transforms the inputdata `X` to dimenionality 2. - * - * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200` - * @returns {Generator} A generator yielding the intermediate steps of the projection of - * `X`. - */ - *generator(max_iter = 200) { - this.check_init(); - if (!this.distance_matrix) this.init(this.distance_matrix); - - for (let j = 0; j < max_iter; ++j) { - this._step(); - yield this.projection; - } - - return this.projection; - } - - _step() { - if (!this.distance_matrix) this.init(this.distance_matrix); - const MAGIC = /** @type {number} */ (this.parameter("magic")); - const D = /** @type {Matrix} */ (this.distance_matrix); - const N = this.X.shape[0]; - const d = /** @type {number} */ (this.parameter("d")); - const Y = this.Y; - - const G = new Matrix(N, d, 0); - - const sum = new Float64Array(d); - for (let i = 0; i < N; ++i) { - const e1 = new Float64Array(d); - const e2 = new Float64Array(d); - const Yi = Y.row(i); - for (let j = 0; j < N; ++j) { - if (i === j) continue; - const dX = D.entry(i, j); - if (dX === 0) continue; // Skip identical points in high-dim - - const Yj = Y.row(j); - const delta = new Float64Array(d); - for (let k = 0; k < d; ++k) { - delta[k] = Yi[k] - Yj[k]; + /** + * Calculates the similarity matrix P + * + * @private + * @param {Matrix} knn_distances - Matrix of pairwise knn distances + * @param {Float64Array} sig - Scaling factor for the distances + * @param {Matrix} nbrs - Nearest neighbors + * @returns {Matrix} Pairwise similarity matrix + */ + _find_p(knn_distances, sig, nbrs) { + const [N, n_neighbors] = knn_distances.shape; + return new Matrix(N, n_neighbors, (i, j) => { + return Math.exp(-(knn_distances.entry(i, j) ** 2 / sig[i] / sig[nbrs.entry(i, j)])); + }); + } + + /** + * Sample nearest neighbors triplets based on the similarity values given in P. + * + * @private + * @param {Matrix} P - Matrix of pairwise similarities between each point and its neighbors given in matrix nbrs. + * @param {Matrix} nbrs - Nearest neighbors indices for each point. The similarity values are given in matrix + * {@link P}. Row i corresponds to the i-th point. + * @param {number} n_inliers - Number of inlier points. + * @param {number} n_outliers - Number of outlier points. + */ + _sample_knn_triplets(P, nbrs, n_inliers, n_outliers) { + const N = nbrs.shape[0]; + const triplets_list = []; + for (let i = 0; i < N; ++i) { + const sort_indices = this.__argsort(P.row(i)); + for (let j = 0; j < n_inliers; ++j) { + const sim = nbrs.entry(i, sort_indices[sort_indices[j] === i ? j + 1 : j]); + const rejects = [i, ...Array.from(sort_indices.slice(0, j + 2)).map((idx) => nbrs.entry(i, idx))]; + const samples = this._rejection_sample(n_outliers, N, rejects); + for (let k = 0; k < samples.length; ++k) { + const out = samples[k]; + triplets_list.push([i, sim, out]); + } + } } - const dY = Math.max(euclidean(Yi, Yj), 1e-6); - const dq = dX - dY; - const dr = dX * dY; - for (let k = 0; k < d; ++k) { - e1[k] += (delta[k] * dq) / dr; - e2[k] += (dq - (delta[k] ** 2 * (1 + dq / dY)) / dY) / dr; + const triplets = new Matrix(triplets_list.length, 3); + for (let t = 0; t < triplets_list.length; ++t) { + triplets.set_entry(t, 0, triplets_list[t][0]); + triplets.set_entry(t, 1, triplets_list[t][1]); + triplets.set_entry(t, 2, triplets_list[t][2]); } - } - for (let k = 0; k < d; ++k) { - const val = Y.entry(i, k) + ((MAGIC * e1[k]) / Math.abs(e2[k]) || 0); - G.set_entry(i, k, val); - sum[k] += val; - } + return triplets; } - for (let k = 0; k < d; ++k) { - sum[k] /= N; + + /** + * Should do the same as np.argsort() + * + * @private + * @param {Float64Array | number[]} A + */ + __argsort(A) { + return linspace(0, A.length - 1).sort((i, j) => A[j] - A[i]); } - for (let i = 0; i < N; ++i) { - for (let k = 0; k < d; ++k) { - Y.set_entry(i, k, G.entry(i, k) - sum[k]); - } - } - return Y; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial>} [parameters] - * @returns {T} - */ - static transform(X, parameters) { - const dr = new SAMMON(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial>} [parameters] - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new SAMMON(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial>} [parameters] - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new SAMMON(X, parameters); - return dr.transform_async(); - } -} + /** + * Samples {@link n_samples} integers from a given interval [0, {@link max_int}] while rejection the values that are + * in the {@link rejects}. + * + * @private + * @param {number} n_samples + * @param {number} max_int + * @param {number[]} rejects + */ + _rejection_sample(n_samples, max_int, rejects) { + const randomizer = this._randomizer; + const interval = linspace(0, max_int - 1).filter((d) => rejects.indexOf(d) < 0); + return randomizer.choice(interval, Math.min(n_samples, interval.length)); + } -/** @import {InputType} from "../index.js" */ -/** @import {Metric} from "../metrics/index.js" */ -/** @import {ParametersSQDMDS} from "./index.js" */ + /** + * Calculates the weights for the sampled nearest neighbors triplets + * + * @private + * @param {Matrix} triplets - Sampled Triplets. + * @param {Matrix} P - Pairwise similarity matrix. + * @param {Matrix} nbrs - Nearest Neighbors + * @param {Float64Array} outlier_distances - Matrix of pairwise outlier distances + * @param {Float64Array} sig - Scaling factor for the distances. + */ + _find_weights(triplets, P, nbrs, outlier_distances, sig) { + const n_triplets = triplets.shape[0]; + const weights = new Float64Array(n_triplets); + for (let t = 0; t < n_triplets; ++t) { + const i = triplets.entry(t, 0); + const sim = nbrs.row(i).indexOf(triplets.entry(t, 1)); + const p_sim = P.entry(i, sim); + let p_out = Math.exp(-(outlier_distances[t] ** 2 / (sig[i] * sig[triplets.entry(t, 2)]))); + if (p_out < 1e-20) p_out = 1e-20; + weights[t] = p_sim / p_out; + } + return weights; + } -/** - * SQuadMDS (Stochastic Quartet MDS) - * - * A lean Stochastic Quartet MDS improving global structure preservation in - * neighbor embedding like t-SNE and UMAP. - * - * @class - * @template {InputType} T - * @extends DR - * @category Dimensionality Reduction - */ -class SQDMDS extends DR { - /** - * SQuadMDS: a lean Stochastic Quartet MDS improving global structure preservation in neighbor embedding like t-SNE - * and UMAP. - * - * @param {T} X - * @param {Partial} [parameters] - * @see {@link https://arxiv.org/pdf/2202.12087.pdf} - */ - constructor(X, parameters) { - super( - X, - { - d: 2, - metric: euclidean, - seed: 1212, - decay_start: 0.1, - decay_cte: 0.34, // 0.34 - }, - parameters, - ); - - this.init(); - if (this.parameter("metric") === "precomputed" && this.X.shape[0] !== this.X.shape[1]) { - throw new Error("SQDMDS input data must be a square Matrix"); - } - } - - init() { - const N = this._N; - const d = /** @type {number} */ (this.parameter("d")); - - // initialize helpers. - this._add = this.__add(d); - this._sub_div = this.__sub_div(d); - this._minus = this.__minus(d); - this._mult = this.__mult(d); - this._LR_init = Math.max(2, 0.005 * N); - this._LR = this._LR_init; - const decay_cte = /** @type {number} */ (this.parameter("decay_cte")); - this._offset = -Math.exp(-1 / decay_cte); - this._momentums = new Matrix(N, d, 0); - this._grads = new Matrix(N, d, 0); - this._indices = linspace(0, N - 1); - // initialize projection. - const R = this._randomizer; - this.Y = new Matrix(N, d, () => R.random - 0.5); - - // preparing metric for optimization. - const this_metric = /** @type {Metric | "precomputed"} */ (this.parameter("metric")); - if (this_metric === "precomputed") { - /** @type {(i: number, j: number, X: Matrix) => number} */ - this._HD_metric = (i, j, X) => X.entry(i, j); - /** @type {(i: number, j: number, X: Matrix) => number} */ - this._HD_metric_exaggeration = (i, j, X) => X.entry(i, j) ** 2; - } else { - this._HD_metric = (i, j, X) => this_metric(X.row(i), X.row(j)); - if (this_metric === euclidean) { - this._HD_metric_exaggeration = (i, j, X) => euclidean_squared(X.row(i), X.row(j)); - } else { - this._HD_metric_exaggeration = (i, j, X) => this_metric(X.row(i), X.row(j)) ** 2; - } - } - return; - } - - /** - * Computes the projection. - * - * @param {number} [iterations=500] - Number of iterations. Default is `500` - * @returns {T} The projection. - */ - transform(iterations = 500) { - this.check_init(); - const decay_start = /** @type {number} */ (this.parameter("decay_start")); - this._decay_start = Math.round(decay_start * iterations); - for (let i = 0; i < iterations; ++i) { - this._step(i, iterations); - } - return this.projection; - } - - /** - * Computes the projection. - * - * @param {number} [iterations=500] - Number of iterations. Default is `500` - * @returns {Generator} The intermediate steps of the projection. - */ - *generator(iterations = 500) { - this.check_init(); - const decay_start = /** @type {number} */ (this.parameter("decay_start")); - this._decay_start = Math.round(decay_start * iterations); - for (let i = 0; i < iterations; ++i) { - this._step(i, iterations); - yield this.projection; - } - - return this.projection; - } - - /** - * Performs an optimization step. - * - * @private - * @param {number} i - Acutal iteration. - * @param {number} iterations - Number of iterations. - */ - _step(i, iterations) { - if (this._LR_init === undefined || this._offset === undefined) - throw new Error("Call init() first!"); - - const decay_start = /** @type {number} */ (this.parameter("decay_start")); - if (i > decay_start) { - const decay_cte = /** @type {number} */ (this.parameter("decay_cte")); - const offset = this._offset; - const ratio = (i - decay_start) / (iterations - decay_start); - this._LR = this._LR_init * (Math.exp(-(ratio * ratio) / decay_cte) + offset); - this._distance_exaggeration = false; - } else { - this._distance_exaggeration = true; - } - this._nestrov_iteration(this._distance_exaggeration); - } - - /** - * Creates quartets of non overlapping indices. - * - * @private - * @returns {Uint32Array[]} - */ - __quartets() { - if (!this._indices) throw new Error("Call init() first!"); - if (this._offset === undefined) throw new Error("Call init() first!"); - const N = this._N; - const max_N = N - (N % 4); - const R = this._randomizer; - const shuffled_indices = R.choice(this._indices, max_N); - const result = []; - for (let i = 0; i < max_N; i += 4) { - result.push( - Uint32Array.of( - shuffled_indices[i], - shuffled_indices[i + 1], - shuffled_indices[i + 2], - shuffled_indices[i + 3], - ), - ); + /** + * Sample uniformly ranom triplets + * + * @private + * @param {Matrix} X - Data matrix. + * @param {number} n_random - Number of random triplets per point + * @param {Float64Array} sig - Scaling factor for the distances + */ + _sample_random_triplets(X, n_random, sig) { + const metric = /** @type {Metric} */ (this.parameter("metric")); + const randomizer = this._randomizer; + const N = X.shape[0]; + const random_triplets = new Matrix(N * n_random, 3); + const random_weights = new Float64Array(N * n_random); + for (let i = 0; i < N; ++i) { + const n_i = i * n_random; + const indices = Array.from({ length: N }, (_, idx) => idx).filter((idx) => idx !== i); + for (let j = 0; j < n_random; ++j) { + let [sim, out] = randomizer.choice(indices, 2); + let p_sim = Math.exp(-(metric(X.row(i), X.row(sim)) ** 2 / (sig[i] * sig[sim]))); + if (p_sim < 1e-20) p_sim = 1e-20; + let p_out = Math.exp(-(metric(X.row(i), X.row(out)) ** 2 / (sig[i] * sig[out]))); + if (p_out < 1e-20) p_out = 1e-20; + + if (p_sim < p_out) { + [sim, out] = [out, sim]; + [p_sim, p_out] = [p_out, p_sim]; + } + const index = n_i + j; + random_triplets.set_entry(index, 0, i); + random_triplets.set_entry(index, 1, sim); + random_triplets.set_entry(index, 2, out); + random_weights[index] = 0.1 * (p_sim / p_out); + } + } + return { + random_triplets: random_triplets, + random_weights: random_weights, + }; } - return result; - } - - /** - * Computes and applies gradients, and updates momentum. - * - * @private - * @param {boolean} distance_exaggeration - */ - _nestrov_iteration(distance_exaggeration) { - if (!this._momentums || !this._grads || this._LR === undefined) - throw new Error("Call init() first!"); - const momentums = this._momentums.mult(0.99, { inline: true }); - const LR = this._LR; - const grads = this._fill_MDS_grads(this.Y.add(momentums), this._grads, distance_exaggeration); - const [n, d] = momentums.shape; - for (let i = 0; i < n; ++i) { - const g_i = grads.row(i); - const g_i_norm = norm(g_i); - if (g_i_norm === 0) continue; - const mul = LR / g_i_norm; - const m_i = momentums.row(i); - for (let j = 0; j < d; ++j) { - m_i[j] -= mul * g_i[j]; - } - } // momentums -= (LR / norm) * grads - this.Y.add(momentums, { inline: true }); - } - - /** - * Computes the gradients. - * - * @param {Matrix} Y - The Projection. - * @param {Matrix} grads - The gradients. - * @param {boolean} [exaggeration=false] - Whether or not to use early exaggeration. Default is `false` - * @param {boolean} [zero_grad=true] - Whether or not to reset the gradient in the beginning. Default is `true` - * @returns {Matrix} The gradients. - */ - _fill_MDS_grads(Y, grads, exaggeration = false, zero_grad = true) { - if (!this._HD_metric || !this._HD_metric_exaggeration || !this._add) - throw new Error("Call init() first!"); - if (zero_grad) { - // compute new gradients - grads.values.fill(0); - } - const add = this._add; - const X = this.X; - let HD_metric; - if (exaggeration === true) { - HD_metric = this._HD_metric_exaggeration; - } else { - HD_metric = this._HD_metric; - } - - const D_quartet = new Float64Array(6); - const quartets = this.__quartets(); - for (const [i, j, k, l] of quartets) { - // compute quartet's HD distances. - D_quartet[0] = HD_metric(i, j, X); - D_quartet[1] = HD_metric(i, k, X); - D_quartet[2] = HD_metric(i, l, X); - D_quartet[3] = HD_metric(j, k, X); - D_quartet[4] = HD_metric(j, l, X); - D_quartet[5] = HD_metric(k, l, X); - - const D_quartet_sum = neumair_sum(D_quartet); - - if (D_quartet_sum > 0) { - for (let i = 0; i < 6; ++i) { - D_quartet[i] /= D_quartet_sum; - D_quartet[i] += 1e-11; - } - } - const [gi, gj, gk, gl] = this._compute_quartet_grads(Y, [i, j, k, l], D_quartet); - - // add is inline, row acces the matrix - add(grads.row(i), gi); - add(grads.row(j), gj); - add(grads.row(k), gk); - add(grads.row(l), gl); - } - return grads; - } - - /** - * Quartet gradients for a projection. - * - * @private - * @param {Matrix} Y - The acutal projection. - * @param {number[]} quartet - The indices of the quartet. - * @param {Float64Array} D_hd - The high-dimensional distances of the quartet. - * @returns {Float64Array[]} The gradients for the quartet. - */ - _compute_quartet_grads(Y, quartet, [p_ab, p_ac, p_ad, p_bc, p_bd, p_cd]) { - const [a, b, c, d] = quartet.map((index) => Y.row(index)); - // LD distances, add a small number just in case - const d_ab = euclidean(a, b) + 1e-12; - const d_ac = euclidean(a, c) + 1e-12; - const d_ad = euclidean(a, d) + 1e-12; - const d_bc = euclidean(b, c) + 1e-12; - const d_bd = euclidean(b, d) + 1e-12; - const d_cd = euclidean(c, d) + 1e-12; - const sum_LD_dist = neumair_sum([d_ab, d_ac, d_ad, d_bc, d_bd, d_cd]); - - // for each element of the sum: use the same gradient function and just permute the points given in input. - const [gA1, gB1, gC1, gD1] = this._ABCD_grads( - a, - b, - c, - d, - d_ab, - d_ac, - d_ad, - d_bc, - d_bd, - d_cd, - p_ab, - sum_LD_dist, - ); - const [gA2, gC2, gB2, gD2] = this._ABCD_grads( - a, - c, - b, - d, - d_ac, - d_ab, - d_ad, - d_bc, - d_cd, - d_bd, - p_ac, - sum_LD_dist, - ); - const [gA3, gD3, gC3, gB3] = this._ABCD_grads( - a, - d, - c, - b, - d_ad, - d_ac, - d_ab, - d_cd, - d_bd, - d_bc, - p_ad, - sum_LD_dist, - ); - const [gB4, gC4, gA4, gD4] = this._ABCD_grads( - b, - c, - a, - d, - d_bc, - d_ab, - d_bd, - d_ac, - d_cd, - d_ad, - p_bc, - sum_LD_dist, - ); - const [gB5, gD5, gA5, gC5] = this._ABCD_grads( - b, - d, - a, - c, - d_bd, - d_ab, - d_bc, - d_ad, - d_cd, - d_ac, - p_bd, - sum_LD_dist, - ); - const [gC6, gD6, gA6, gB6] = this._ABCD_grads( - c, - d, - a, - b, - d_cd, - d_ac, - d_bc, - d_ad, - d_bd, - d_ab, - p_cd, - sum_LD_dist, - ); - - if (!this._add) throw new Error("Call init() first!"); - const add = this._add; - const gA = add(gA1, gA2, gA3, gA4, gA5, gA6); - const gB = add(gB1, gB2, gB3, gB4, gB5, gB6); - const gC = add(gC1, gC2, gC3, gC4, gC5, gC6); - const gD = add(gD1, gD2, gD3, gD4, gD5, gD6); - - return [gA, gB, gC, gD]; - } - - /** - * Gradients for one element of the loss function's sum. - * - * @private - * @param {Float64Array} a - * @param {Float64Array} b - * @param {Float64Array} c - * @param {Float64Array} d - * @param {number} d_ab - * @param {number} d_ac - * @param {number} d_ad - * @param {number} d_bc - * @param {number} d_bd - * @param {number} d_cd - * @param {number} p_ab - * @param {number} sum_LD_dist - * @returns {Float64Array[]} - */ - _ABCD_grads(a, b, c, d, d_ab, d_ac, d_ad, d_bc, d_bd, d_cd, p_ab, sum_LD_dist) { - if (!this._minus || !this._add || !this._mult || !this._sub_div) - throw new Error("Call init() first!"); - const ratio = d_ab / sum_LD_dist; - const twice_ratio = 2 * ((p_ab - ratio) / sum_LD_dist); - const minus = this._minus; - const add = this._add; - const mult = this._mult; - const sub_div = this._sub_div; - // no side effects because sub_div creates new arrays, and the inline functions work on this new created arrays. - const gA = mult( - minus( - mult(add(sub_div(a, b, d_ab), sub_div(a, c, d_ac), sub_div(a, d, d_ad)), ratio), - sub_div(a, b, d_ab), - ), - twice_ratio, - ); - const gB = mult( - minus( - mult(add(sub_div(b, a, d_ab), sub_div(b, c, d_bc), sub_div(b, d, d_bd)), ratio), - sub_div(b, a, d_ab), - ), - twice_ratio, - ); - const gC = mult( - add(sub_div(c, a, d_ac), sub_div(c, b, d_bc), sub_div(c, d, d_cd)), - ratio * twice_ratio, - ); - const gD = mult( - add(sub_div(d, a, d_ad), sub_div(d, b, d_bd), sub_div(d, c, d_cd)), - ratio * twice_ratio, - ); - return [gA, gB, gC, gD]; - } - - /** - * Inline! - * - * @param {number} d - */ - __minus(d) { - return /** @type {(a: Float64Array, b: Float64Array) => Float64Array} */ (a, b) => { - for (let i = 0; i < d; ++i) { - a[i] -= b[i]; - } - return a; - }; - } - - /** - * Inline! - * - * @param {number} d - */ - __add(d) { - return /** @type {(...summands: Float64Array[]) => Float64Array} */ (...summands) => { - const n = summands.length; - const s1 = summands[0]; - for (let j = 1; j < n; ++j) { - const summand = summands[j]; - for (let i = 0; i < d; ++i) { - s1[i] += summand[i]; - } - } - return s1; - }; - } - - /** - * Inline! - * - * @param {number} d - */ - __mult(d) { - return /** @type {(a: Float64Array, v: number) => Float64Array} */ (a, v) => { - for (let i = 0; i < d; ++i) { - a[i] *= v; - } - return a; - }; - } - - /** - * Creates a new array `(x - y) / div`. - * - * @param {number} d - */ - __sub_div(d) { - return /** @type {(x: Float64Array, y: Float64Array, div: number) => Float64Array} */ ( - x, - y, - div, - ) => { - return Float64Array.from({ length: d }, (_, i) => (x[i] - y[i]) / div); - }; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X, parameters) { - const dr = new SQDMDS(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new SQDMDS(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new SQDMDS(X, parameters); - return dr.transform_async(); - } -} -/** @import {InputType} from "../index.js" */ -/** @import {ParametersTopoMap} from "./index.js" */ + /** + * Computes the gradient for updating the embedding. + * + * @param {Matrix} Y - The embedding + */ + _grad(Y) { + const n_inliers = this.n_inliers; + const n_outliers = this.n_outliers; + const triplets = this.triplets; + const weights = this.weights; + if (!triplets || n_inliers === undefined || n_outliers === undefined || !weights) + throw new Error("Call init() first!"); + const [N, dim] = Y.shape; + const n_triplets = triplets.shape[0]; + const grad = new Matrix(N, dim, 0); + const y_ij = new Float64Array(dim); + const y_ik = new Float64Array(dim); + let d_ij = 1; + let d_ik = 1; + let n_viol = 0; + let loss = 0; + const n_knn_triplets = N * n_inliers * n_outliers; + + for (let t = 0; t < n_triplets; ++t) { + const [i, j, k] = triplets.row(t); + // update y_ij, y_ik, d_ij, d_ik + if (t % n_outliers === 0 || t >= n_knn_triplets) { + d_ij = 1; + d_ik = 1; + for (let d = 0; d < dim; ++d) { + const Y_id = Y.entry(i, d); + const Y_jd = Y.entry(j, d); + const Y_kd = Y.entry(k, d); + y_ij[d] = Y_id - Y_jd; + y_ik[d] = Y_id - Y_kd; + d_ij += y_ij[d] ** 2; + d_ik += y_ik[d] ** 2; + } + // update y_ik and d_ik only + } else { + d_ik = 1; + for (let d = 0; d < dim; ++d) { + const Y_id = Y.entry(i, d); + const Y_kd = Y.entry(k, d); + y_ik[d] = Y_id - Y_kd; + d_ik += y_ik[d] ** 2; + } + } -/** - * TopoMap - * - * A 0-dimensional Homology Preserving Projection of High-Dimensional Data. - * It aims to preserve the topological structure of the data by maintaining - * the connectivity of a minimum spanning tree. - * - * @class - * @template {InputType} T - * @extends DR - * @category Dimensionality Reduction - */ -class TopoMap extends DR { - /** - * TopoMap: A 0-dimensional Homology Preserving Projection of High-Dimensional Data. - * - * @param {T} X - The high-dimensional data. - * @param {Partial} parameters - Object containing parameterization of the DR method. - * @see {@link https://arxiv.org/pdf/2009.01512.pdf} - */ - constructor(X, parameters) { - super(X, { metric: euclidean, seed: 1212 }, parameters); - [this._N, this._D] = this.X.shape; - this._distance_matrix = new Matrix(this._N, this._N, -1); - } - - /** - * @private - * @param {number} i - * @param {number} j - * @param {import("../metrics/index.js").Metric} metric - * @returns {number} - */ - __lazy_distance_matrix(i, j, metric) { - const D = this._distance_matrix; - const X = this.X; - const D_ij = D.entry(i, j); - if (D_ij === -1 && i !== j) { - const dist = metric(X.row(i), X.row(j)); - D.set_entry(i, j, dist); - D.set_entry(j, i, dist); - return dist; - } - return i === j ? 0 : D_ij; - } - - /** - * Computes the minimum spanning tree, using a given metric - * - * @private - * @param {import("../metrics/index.js").Metric} metric - * @see {@link https://en.wikipedia.org/wiki/Kruskal%27s_algorithm} - */ - _make_minimum_spanning_tree(metric = euclidean) { - const N = this._N; - const X = [...this.X]; - - this._disjoint_set = new DisjointSet(X); - const disjoint_set = this._disjoint_set; - const F = []; - let E = []; - for (let i = 0; i < N; ++i) { - for (let j = i + 1; j < N; ++j) { - E.push([i, j, this.__lazy_distance_matrix(i, j, metric)]); - } - } - E = E.sort((a, b) => a[2] - b[2]); - - for (const [u, v, w] of E) { - const set_u = disjoint_set.find(X[u]); - const set_v = disjoint_set.find(X[v]); - if (!set_u || !set_v) throw new Error("Should not happen!"); - if (set_u !== set_v) { - F.push([u, v, w]); - disjoint_set.union(set_u, set_v); - } - } - - return F.sort((a, b) => a[2] - b[2]); - } - - /** Initializes TopoMap. Sets all projcted points to zero, and computes a minimum spanning tree. */ - init() { - const { metric } = this._parameters; - this.Y = new Matrix(this._N, 2, 0); - this._Emst = this._make_minimum_spanning_tree(metric); - this._is_initialized = true; - return this; - } - - /** - * Returns true if Point C is left of line AB. - * - * @private - * @param {Float64Array} PointA - Point A of line AB - * @param {Float64Array} PointB - Point B of line AB - * @param {Float64Array} PointC - Point C - * @returns {boolean} - */ - __hull_cross([ax, ay], [bx, by], [sx, sy]) { - return (bx - ax) * (sy - ay) - (by - ay) * (sx - ax) <= 0; - } - - /** - * Computes the convex hull of the set of Points S - * - * @private - * @param {Float64Array[]} S - Set of Points. - * @returns {Float64Array[]} Convex hull of S. Starts at the bottom-most point and continues counter-clockwise. - * @see {@link https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain#JavaScript} - */ - __hull(S) { - const points = S.sort(([x1, y1], [x2, y2]) => y1 - y2 || x1 - x2); - const N = points.length; - if (N <= 2) return points; - - const lower = []; - for (let i = 0; i < N; ++i) { - while ( - lower.length >= 2 && - this.__hull_cross(lower[lower.length - 2], lower[lower.length - 1], points[i]) - ) { - lower.pop(); - } - lower.push(points[i]); - } - const upper = []; - for (let i = N - 1; i >= 0; --i) { - while ( - upper.length >= 2 && - this.__hull_cross(upper[upper.length - 2], upper[upper.length - 1], points[i]) - ) { - upper.pop(); - } - upper.push(points[i]); - } - upper.pop(); - lower.pop(); - return lower.concat(upper); - } - - /** - * Finds the angle to rotate Point A and B to lie on a line parallel to the x-axis. - * - * @private - * @param {Float64Array} PointA - * @param {Float64Array} PointB - * @returns {{ sin: number; cos: number }} Object containing the sinus- and cosinus-values for a rotation. - */ - __findAngle([p1x, p1y], [p2x, p2y]) { - const n = euclidean([p1x, p1y], [p2x, p2y]); - if (n === 0) - return { - sin: 0, - cos: 1, - }; - const vec = [(p2x - p1x) / n, (p2y - p1y) / n]; - const cos = vec[0]; - let sin = Math.sqrt(1 - cos * cos); - sin = vec[1] >= 0 ? -sin : sin; - return { - sin: sin, - cos: cos, - }; - } - - /** - * @private - * @param {Float64Array[]} hull - * @param {Float64Array} p - * @param {boolean} topEdge - * @returns {{ sin: number; cos: number; tx: number; ty: number }} - */ - __align_hull(hull, p, topEdge) { - let v = -1; - /** @type {number} */ - let d2 = -Infinity; - for (let i = 0; i < hull.length; ++i) { - const d = euclidean(hull[i], p); - if (v === -1) { - d2 = d; - v = i; - } else { - if (d2 > d) { - d2 = d; - v = i; - } - } - } - - const v1 = hull[v]; - let v2; - if (topEdge) { - v2 = hull[(v + 1) % hull.length]; - } else { - v2 = hull[(v - 1 + hull.length) % hull.length]; + if (d_ij > d_ik) ++n_viol; + loss += weights[t] / (1 + d_ik / d_ij); + const w = weights[t] / (d_ij + d_ik) ** 2; + for (let d = 0; d < dim; ++d) { + const gs = y_ij[d] * d_ik * w; + const go = y_ik[d] * d_ij * w; + grad.add_entry(i, d, gs - go); + grad.sub_entry(j, d, gs); + grad.add_entry(k, d, go); + } + } + return { grad, loss, n_viol }; + } + + /** + * @param {number} max_iteration + * @returns {T} + */ + transform(max_iteration = 800) { + this.check_init(); + for (let iter = 0; iter < max_iteration; ++iter) { + this._next(iter); + } + return this.projection; + } + + /** + * @param {number} max_iteration + * @returns {Generator} + */ + *generator(max_iteration = 800) { + this.check_init(); + for (let iter = 0; iter < max_iteration; ++iter) { + this._next(iter); + yield this.projection; + } + return this.projection; + } + + /** + * Does the iteration step. + * + * @private + * @param {number} iter + */ + _next(iter) { + const gamma = iter > 250 ? 0.5 : 0.3; + const old_C = this.C; + const vel = this.vel; + if (!vel || old_C === undefined || this.lr === undefined) throw new Error("Call init() first!"); + const Y = this.Y.add(vel.mult(gamma)); + const { grad, loss } = this._grad(Y); + this.C = loss; + this.Y = this._update_embedding(Y, iter, grad); + const tol = /** @type {number} */ (this.parameter("tol")); + this.lr *= old_C > loss + tol ? 1.01 : 0.9; + return this.Y; } - /** @type {{ sin?: number; cos?: number; tx: number; ty: number }} */ - const transformation = { - tx: -v1[0], - ty: -v1[1], - }; - - if (hull.length >= 2) { - const { sin, cos } = this.__findAngle(v1, v2); - transformation.sin = sin; - transformation.cos = cos; - } else { - transformation.sin = 0; - transformation.cos = 1; - } - - return /** @type {{ sin: number; cos: number; tx: number; ty: number }} */ (transformation); - } - - /** - * @private - * @param {Float64Array} Point - The point which should get transformed. - * @param {{ sin: number; cos: number; tx: number; ty: number }} Transformation - Contains the values for - * translation and rotation. - */ - __transform([px, py], { tx, ty, sin, cos }) { - const x = px + tx; - const y = py + ty; - const xx = x * cos - y * sin; - const yy = x * sin + y * cos; - return [xx, yy]; - } - - /** - * Calls `__transform` for each point in Set C - * - * @private - * @param {Float64Array[]} C - Set of points. - * @param {{ sin: number; cos: number; tx: number; ty: number }} t - Transform object. - * @param {number} yOffset - Value to offset set C. - */ - __transform_component(C, t, yOffset) { - const N = C.length; - for (let i = 0; i < N; ++i) { - const c = C[i]; - const [cx, cy] = this.__transform(c, t); - c[0] = cx; - c[1] = cy + yOffset; - } - } - - /** - * @private - * @param {Float64Array} root_u - Root of component u - * @param {Float64Array} root_v - Root of component v - * @param {Float64Array} p_u - Point u - * @param {Float64Array} p_v - Point v - * @param {number} w - Edge weight w - * @param {DisjointSet} components - The disjoint set containing the components - */ - __align_components(root_u, root_v, p_u, p_v, w, components) { - if (!components) throw new Error("components not provided!"); - const u_children = components.get_children(root_u); - const v_children = components.get_children(root_v); - if (!u_children || !v_children) throw new Error("should not happen!"); - - const points_u = [...u_children]; - const points_v = [...v_children]; - - const hull_u = this.__hull(points_u); - const hull_v = this.__hull(points_v); - - const t_u = this.__align_hull(hull_u, p_u, false); - const t_v = this.__align_hull(hull_v, p_v, true); - - this.__transform_component(points_u, t_u, 0); - this.__transform_component(points_v, t_v, w); - } - - /** - * Transforms the inputdata `X` to dimensionality 2. - * - * @returns {T} - */ - transform() { - if (!this._is_initialized) this.init(); - if (!this._Emst) throw new Error("Call init() first!"); - const Emst = this._Emst; - const Y = this.Y.to2dArray(); - /** @type {DisjointSet} */ - const components = new DisjointSet( - Y, - // Y.map((y, i) => { - // y.i = i; - // return y; - // }), - ); - - for (const [u, v, w] of Emst) { - const p_u = Y[u]; - const p_v = Y[v]; - const component_u = components.find(p_u); - const component_v = components.find(p_v); - if (!component_u || !component_v) throw new Error("Should not happen!"); - if (component_u === component_v) continue; - this.__align_components(component_u, component_v, p_u, p_v, w, components); - components.union(component_u, component_v); - } - return this.projection; - } - - /** - * Transforms the inputdata `X` to dimensionality 2. - * - * @returns {Generator} - */ - *generator() { - if (!this._is_initialized) this.init(); - if (!this._Emst) throw new Error("call init() first!"); - const Emst = this._Emst; - const Y = this.Y.to2dArray(); - const components = new DisjointSet( - Y, - // Y.map((y, i) => { - // y.i = i; - // return y; - // }), - ); - - for (const [u, v, w] of Emst) { - const p_u = Y[u]; - const p_v = Y[v]; - const component_u = components.find(p_u); - const component_v = components.find(p_v); - if (!component_u || !component_v) throw new Error("should not happen!"); - if (component_u === component_v) continue; - this.__align_components(component_u, component_v, p_u, p_v, w, components); - components.union(component_u, component_v); - yield this.projection; - } - return this.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {T} - */ - static transform(X, parameters) { - const dr = new TopoMap(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new TopoMap(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new TopoMap(X, parameters); - return dr.transform_async(); - } -} + /** + * Updates the embedding. + * + * @private + * @param {Matrix} Y + * @param {number} iter + * @param {Matrix} grad + */ + _update_embedding(Y, iter, grad) { + const [N, dim] = Y.shape; + const gamma = iter > 250 ? 0.8 : 0.5; // moment parameter + const min_gain = 0.01; + const gain = this.gain; + const vel = this.vel; + const lr = this.lr; + if (!vel || !gain || lr === undefined) throw new Error("Call init() first!"); + for (let i = 0; i < N; ++i) { + for (let d = 0; d < dim; ++d) { + const new_gain = + Math.sign(vel.entry(i, d)) !== Math.sign(grad.entry(i, d)) + ? gain.entry(i, d) + 0.2 + : Math.max(gain.entry(i, d) * 0.8, min_gain); + gain.set_entry(i, d, new_gain); + vel.set_entry(i, d, gamma * vel.entry(i, d) - lr * gain.entry(i, d) * grad.entry(i, d)); + Y.set_entry(i, d, Y.entry(i, d) + vel.entry(i, d)); + } + } + return Y; + } -/** @import {InputType} from "../index.js" */ -/** @import {Metric} from "../metrics/index.js" */ -/** @import {ParametersTriMap} from "./index.js" */ -/** @import {KNN} from "../knn/KNN.js" */ + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X, parameters) { + const dr = new TriMap(X, parameters); + return dr.transform(); + } -/** - * TriMap - * - * A dimensionality reduction technique that preserves both local and global - * structure using triplets. It is designed to be a more robust alternative - * to t-SNE and UMAP. - * - * @class - * @template {InputType} T - * @extends DR - * @category Dimensionality Reduction - */ -class TriMap extends DR { - /** - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - * @see {@link https://arxiv.org/pdf/1910.00204v1.pdf} - * @see {@link https://github.com/eamid/trimap} - */ - constructor(X, parameters) { - super( - X, - { - weight_adj: 500, - n_inliers: 10, - n_outliers: 5, - n_random: 5, - d: 2, - metric: euclidean, - tol: 1e-8, - seed: 1212, - }, - parameters, - ); - } - - /** - * @param {Matrix | null} [pca=null] - Initial Embedding (if null then PCA gets used). Default is `null` - * @param {import("../knn/KNN.js").KNN | null} [knn=null] - KNN Object (if null then BallTree gets used). Default is `null` - */ - init(pca = null, knn = null) { - const X = this.X; - const N = X.shape[0]; - //const c = /** @type {number} */ (this._parameters.c); - const d = /** @type {number} */ (this._parameters.d); - const metric = /** @type {Metric} */ (this._parameters.metric); - const seed = /** @type {number} */ (this._parameters.seed); - this.n_inliers = /** @type {number} */ (this._parameters.n_inliers); - this.n_outliers = /** @type {number} */ (this._parameters.n_outliers); - this.n_random = /** @type {number} */ (this._parameters.n_random); - this.Y = pca ?? PCA.transform(X, { d, seed }); - this.knn = knn ?? new BallTree(X.to2dArray(), { metric, seed }); - const { triplets, weights } = this._generate_triplets( - this.n_inliers, - this.n_outliers, - this.n_random, - ); - this.triplets = triplets; - this.weights = weights; - this.lr = (1000 * N) / triplets.shape[0]; - this.C = Infinity; - this.vel = new Matrix(N, d, 0); - this.gain = new Matrix(N, d, 1); - return this; - } - - /** - * Generates {@link n_inliers} x {@link n_outliers} x {@link n_random} triplets. - * - * @param {number} n_inliers - * @param {number} n_outliers - * @param {number} n_random - */ - _generate_triplets(n_inliers, n_outliers, n_random) { - const metric = /** @type {Metric} */ (this._parameters.metric); - const weight_adj = /** @type {number} */ (this._parameters.weight_adj); - const X = this.X; - const N = X.shape[0]; - const knn = this.knn; - if (!knn) throw new Error("Call init() first!"); - const n_extra = Math.min(n_inliers + 20, N); - const nbrs = new Matrix(N, n_extra); - const knn_distances = new Matrix(N, n_extra); - for (let i = 0; i < N; ++i) { - const results = knn - .search(X.row(i), n_extra + 1) - .filter((d) => d.distance !== 0) - .sort((a, b) => a.distance - b.distance); + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new TriMap(X, parameters); + yield* dr.generator(); + return dr.projection; + } - results.forEach((d, j) => { - if (j < n_extra) { - nbrs.set_entry(i, j, d.index); - knn_distances.set_entry(i, j, d.distance); - } - }); + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new TriMap(X, parameters); + return dr.transform_async(); } - // scale parameter - const sig = new Float64Array(N); - for (let i = 0; i < N; ++i) { - sig[i] = Math.max( - (knn_distances.entry(i, 3) + knn_distances.entry(i, 4) + knn_distances.entry(i, 5)) / 3, - 1e-10, - ); - } - - const P = this._find_p(knn_distances, sig, nbrs); - - let triplets = this._sample_knn_triplets(P, nbrs, n_inliers, n_outliers); - let n_triplets = triplets.shape[0]; - const outlier_distances = new Float64Array(n_triplets); - for (let i = 0; i < n_triplets; ++i) { - const j = triplets.entry(i, 0); - const k = triplets.entry(i, 2); - outlier_distances[i] = metric(X.row(j), X.row(k)); - } - let weights = this._find_weights(triplets, P, nbrs, outlier_distances, sig); - - if (n_random > 0) { - const { random_triplets, random_weights } = this._sample_random_triplets(X, n_random, sig); - triplets = triplets.concat(random_triplets, "vertical"); - weights = Float64Array.from([...weights, ...random_weights]); - } - n_triplets = triplets.shape[0]; - let max_weight = -Infinity; - for (let i = 0; i < n_triplets; ++i) { - if (Number.isNaN(weights[i])) { - weights[i] = 0; - } - if (max_weight < weights[i]) max_weight = weights[i]; - } - let max_weight_2 = -Infinity; - for (let i = 0; i < n_triplets; ++i) { - weights[i] /= max_weight; - weights[i] += 0.0001; - weights[i] = Math.log(1 + weight_adj * weights[i]); - if (max_weight_2 < weights[i]) max_weight_2 = weights[i]; - } - for (let i = 0; i < n_triplets; ++i) { - weights[i] /= max_weight_2; - } - return { - triplets: triplets, - weights: weights, - }; - } - - /** - * Calculates the similarity matrix P - * - * @private - * @param {Matrix} knn_distances - Matrix of pairwise knn distances - * @param {Float64Array} sig - Scaling factor for the distances - * @param {Matrix} nbrs - Nearest neighbors - * @returns {Matrix} Pairwise similarity matrix - */ - _find_p(knn_distances, sig, nbrs) { - const [N, n_neighbors] = knn_distances.shape; - return new Matrix(N, n_neighbors, (i, j) => { - return Math.exp(-(knn_distances.entry(i, j) ** 2 / sig[i] / sig[nbrs.entry(i, j)])); - }); - } - - /** - * Sample nearest neighbors triplets based on the similarity values given in P. - * - * @private - * @param {Matrix} P - Matrix of pairwise similarities between each point and its neighbors given in matrix nbrs. - * @param {Matrix} nbrs - Nearest neighbors indices for each point. The similarity values are given in matrix - * {@link P}. Row i corresponds to the i-th point. - * @param {number} n_inliers - Number of inlier points. - * @param {number} n_outliers - Number of outlier points. - */ - _sample_knn_triplets(P, nbrs, n_inliers, n_outliers) { - const N = nbrs.shape[0]; - const triplets_list = []; - for (let i = 0; i < N; ++i) { - const sort_indices = this.__argsort(P.row(i)); - for (let j = 0; j < n_inliers; ++j) { - const sim = nbrs.entry(i, sort_indices[sort_indices[j] === i ? j + 1 : j]); - const rejects = [ - i, - ...Array.from(sort_indices.slice(0, j + 2)).map((idx) => nbrs.entry(i, idx)), - ]; - const samples = this._rejection_sample(n_outliers, N, rejects); - for (let k = 0; k < samples.length; ++k) { - const out = samples[k]; - triplets_list.push([i, sim, out]); - } - } - } - const triplets = new Matrix(triplets_list.length, 3); - for (let t = 0; t < triplets_list.length; ++t) { - triplets.set_entry(t, 0, triplets_list[t][0]); - triplets.set_entry(t, 1, triplets_list[t][1]); - triplets.set_entry(t, 2, triplets_list[t][2]); - } - return triplets; - } - - /** - * Should do the same as np.argsort() - * - * @private - * @param {Float64Array | number[]} A - */ - __argsort(A) { - return linspace(0, A.length - 1).sort((i, j) => A[j] - A[i]); - } - - /** - * Samples {@link n_samples} integers from a given interval [0, {@link max_int}] while rejection the values that are - * in the {@link rejects}. - * - * @private - * @param {number} n_samples - * @param {number} max_int - * @param {number[]} rejects - */ - _rejection_sample(n_samples, max_int, rejects) { - const randomizer = this._randomizer; - const interval = linspace(0, max_int - 1).filter((d) => rejects.indexOf(d) < 0); - return randomizer.choice(interval, Math.min(n_samples, interval.length)); - } - - /** - * Calculates the weights for the sampled nearest neighbors triplets - * - * @private - * @param {Matrix} triplets - Sampled Triplets. - * @param {Matrix} P - Pairwise similarity matrix. - * @param {Matrix} nbrs - Nearest Neighbors - * @param {Float64Array} outlier_distances - Matrix of pairwise outlier distances - * @param {Float64Array} sig - Scaling factor for the distances. - */ - _find_weights(triplets, P, nbrs, outlier_distances, sig) { - const n_triplets = triplets.shape[0]; - const weights = new Float64Array(n_triplets); - for (let t = 0; t < n_triplets; ++t) { - const i = triplets.entry(t, 0); - const sim = nbrs.row(i).indexOf(triplets.entry(t, 1)); - const p_sim = P.entry(i, sim); - let p_out = Math.exp(-(outlier_distances[t] ** 2 / (sig[i] * sig[triplets.entry(t, 2)]))); - if (p_out < 1e-20) p_out = 1e-20; - weights[t] = p_sim / p_out; - } - return weights; - } - - /** - * Sample uniformly ranom triplets - * - * @private - * @param {Matrix} X - Data matrix. - * @param {number} n_random - Number of random triplets per point - * @param {Float64Array} sig - Scaling factor for the distances - */ - _sample_random_triplets(X, n_random, sig) { - const metric = /** @type {Metric} */ (this.parameter("metric")); - const randomizer = this._randomizer; - const N = X.shape[0]; - const random_triplets = new Matrix(N * n_random, 3); - const random_weights = new Float64Array(N * n_random); - for (let i = 0; i < N; ++i) { - const n_i = i * n_random; - const indices = Array.from({ length: N }, (_, idx) => idx).filter((idx) => idx !== i); - for (let j = 0; j < n_random; ++j) { - let [sim, out] = randomizer.choice(indices, 2); - let p_sim = Math.exp(-(metric(X.row(i), X.row(sim)) ** 2 / (sig[i] * sig[sim]))); - if (p_sim < 1e-20) p_sim = 1e-20; - let p_out = Math.exp(-(metric(X.row(i), X.row(out)) ** 2 / (sig[i] * sig[out]))); - if (p_out < 1e-20) p_out = 1e-20; - - if (p_sim < p_out) { - [sim, out] = [out, sim]; - [p_sim, p_out] = [p_out, p_sim]; - } - const index = n_i + j; - random_triplets.set_entry(index, 0, i); - random_triplets.set_entry(index, 1, sim); - random_triplets.set_entry(index, 2, out); - random_weights[index] = 0.1 * (p_sim / p_out); - } - } - return { - random_triplets: random_triplets, - random_weights: random_weights, - }; - } - - /** - * Computes the gradient for updating the embedding. - * - * @param {Matrix} Y - The embedding - */ - _grad(Y) { - const n_inliers = this.n_inliers; - const n_outliers = this.n_outliers; - const triplets = this.triplets; - const weights = this.weights; - if (!triplets || n_inliers === undefined || n_outliers === undefined || !weights) - throw new Error("Call init() first!"); - const [N, dim] = Y.shape; - const n_triplets = triplets.shape[0]; - const grad = new Matrix(N, dim, 0); - const y_ij = new Float64Array(dim); - const y_ik = new Float64Array(dim); - let d_ij = 1; - let d_ik = 1; - let n_viol = 0; - let loss = 0; - const n_knn_triplets = N * n_inliers * n_outliers; - - for (let t = 0; t < n_triplets; ++t) { - const [i, j, k] = triplets.row(t); - // update y_ij, y_ik, d_ij, d_ik - if (t % n_outliers === 0 || t >= n_knn_triplets) { - d_ij = 1; - d_ik = 1; - for (let d = 0; d < dim; ++d) { - const Y_id = Y.entry(i, d); - const Y_jd = Y.entry(j, d); - const Y_kd = Y.entry(k, d); - y_ij[d] = Y_id - Y_jd; - y_ik[d] = Y_id - Y_kd; - d_ij += y_ij[d] ** 2; - d_ik += y_ik[d] ** 2; - } - // update y_ik and d_ik only - } else { - d_ik = 1; - for (let d = 0; d < dim; ++d) { - const Y_id = Y.entry(i, d); - const Y_kd = Y.entry(k, d); - y_ik[d] = Y_id - Y_kd; - d_ik += y_ik[d] ** 2; - } - } - - if (d_ij > d_ik) ++n_viol; - loss += weights[t] / (1 + d_ik / d_ij); - const w = weights[t] / (d_ij + d_ik) ** 2; - for (let d = 0; d < dim; ++d) { - const gs = y_ij[d] * d_ik * w; - const go = y_ik[d] * d_ij * w; - grad.add_entry(i, d, gs - go); - grad.sub_entry(j, d, gs); - grad.add_entry(k, d, go); - } - } - return { grad, loss, n_viol }; - } - - /** - * @param {number} max_iteration - * @returns {T} - */ - transform(max_iteration = 800) { - this.check_init(); - for (let iter = 0; iter < max_iteration; ++iter) { - this._next(iter); - } - return this.projection; - } - - /** - * @param {number} max_iteration - * @returns {Generator} - */ - *generator(max_iteration = 800) { - this.check_init(); - for (let iter = 0; iter < max_iteration; ++iter) { - this._next(iter); - yield this.projection; - } - return this.projection; - } - - /** - * Does the iteration step. - * - * @private - * @param {number} iter - */ - _next(iter) { - const gamma = iter > 250 ? 0.5 : 0.3; - const old_C = this.C; - const vel = this.vel; - if (!vel || old_C === undefined || this.lr === undefined) throw new Error("Call init() first!"); - const Y = this.Y.add(vel.mult(gamma)); - const { grad, loss } = this._grad(Y); - this.C = loss; - this.Y = this._update_embedding(Y, iter, grad); - const tol = /** @type {number} */ (this.parameter("tol")); - this.lr *= old_C > loss + tol ? 1.01 : 0.9; - return this.Y; - } - - /** - * Updates the embedding. - * - * @private - * @param {Matrix} Y - * @param {number} iter - * @param {Matrix} grad - */ - _update_embedding(Y, iter, grad) { - const [N, dim] = Y.shape; - const gamma = iter > 250 ? 0.8 : 0.5; // moment parameter - const min_gain = 0.01; - const gain = this.gain; - const vel = this.vel; - const lr = this.lr; - if (!vel || !gain || lr === undefined) throw new Error("Call init() first!"); - for (let i = 0; i < N; ++i) { - for (let d = 0; d < dim; ++d) { - const new_gain = - Math.sign(vel.entry(i, d)) !== Math.sign(grad.entry(i, d)) - ? gain.entry(i, d) + 0.2 - : Math.max(gain.entry(i, d) * 0.8, min_gain); - gain.set_entry(i, d, new_gain); - vel.set_entry(i, d, gamma * vel.entry(i, d) - lr * gain.entry(i, d) * grad.entry(i, d)); - Y.set_entry(i, d, Y.entry(i, d) + vel.entry(i, d)); - } - } - return Y; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X, parameters) { - const dr = new TriMap(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new TriMap(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new TriMap(X, parameters); - return dr.transform_async(); - } } /** @import {InputType} from "../index.js" */ @@ -10184,255 +10766,255 @@ class TriMap extends DR { * // [[x1, y1], [x2, y2], [x3, y3]] */ class TSNE extends DR { - /** - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - */ - constructor(X, parameters) { - super( - X, - { - perplexity: 50, - epsilon: 10, - d: 2, - metric: euclidean_squared, - seed: 1212, - }, - parameters, - ); - [this._N, this._D] = this.X.shape; - this._iter = 0; - const d = /** @type {number} */ (this.parameter("d")); - this.Y = new Matrix(this._N, d, () => this._randomizer.gauss_random() * 1e-4); - } - - init() { - // init - const perplexity = /** @type {number} */ (this.parameter("perplexity")); - const Htarget = Math.log(perplexity); - const N = this._N; - const D = this._D; - const metric = /** @type {Metric | "precomputed"} */ (this._parameters.metric); - const X = this.X; - let Delta; - if (metric === "precomputed") { - Delta = Matrix.from(X); - } else { - Delta = new Matrix(N, N); - for (let i = 0; i < N; ++i) { - const X_i = X.row(i); - for (let j = i + 1; j < N; ++j) { - const distance = metric(X_i, X.row(j)); - Delta.set_entry(i, j, distance); - Delta.set_entry(j, i, distance); - } - } + /** + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + */ + constructor(X, parameters) { + super( + X, + { + perplexity: 50, + epsilon: 10, + d: 2, + metric: euclidean_squared, + seed: 1212, + }, + parameters, + ); + [this._N, this._D] = this.X.shape; + this._iter = 0; + const d = /** @type {number} */ (this.parameter("d")); + this.Y = new Matrix(this._N, d, () => this._randomizer.gauss_random() * 1e-4); } - const P = new Matrix(N, N, 0); + init() { + // init + const perplexity = /** @type {number} */ (this.parameter("perplexity")); + const Htarget = Math.log(perplexity); + const N = this._N; + const D = this._D; + const metric = /** @type {Metric | "precomputed"} */ (this._parameters.metric); + const X = this.X; + let Delta; + if (metric === "precomputed") { + Delta = Matrix.from(X); + } else { + Delta = new Matrix(N, N); + for (let i = 0; i < N; ++i) { + const X_i = X.row(i); + for (let j = i + 1; j < N; ++j) { + const distance = metric(X_i, X.row(j)); + Delta.set_entry(i, j, distance); + Delta.set_entry(j, i, distance); + } + } + } + + const P = new Matrix(N, N, 0); - this._ystep = new Matrix(N, D, 0); - this._gains = new Matrix(N, D, 1); + this._ystep = new Matrix(N, D, 0); + this._gains = new Matrix(N, D, 1); - // search for fitting sigma - const tol = 1e-4; - const maxtries = 50; - for (let i = 0; i < N; ++i) { - const dist_i = Delta.row(i); - const prow = P.row(i); - let betamin = -Infinity; - let betamax = Infinity; - let beta = 1; - let cnt = maxtries; - let done = false; - let psum = 0; - - while (!done && cnt--) { - // compute entropy and kernel row with beta precision - psum = 0; - let dp_sum = 0; - for (let j = 0; j < N; ++j) { - const dist = dist_i[j]; - const pj = i !== j ? Math.exp(-dist * beta) : 0; - dp_sum += dist * pj; - prow[j] = pj; - psum += pj; - } - // compute entropy - const H = psum > 0 ? Math.log(psum) + (beta * dp_sum) / psum : 0; - if (H > Htarget) { - betamin = beta; - beta = betamax === Infinity ? beta * 2 : (beta + betamax) / 2; - } else { - betamax = beta; - beta = betamin === -Infinity ? beta / 2 : (beta + betamin) / 2; + // search for fitting sigma + const tol = 1e-4; + const maxtries = 50; + for (let i = 0; i < N; ++i) { + const dist_i = Delta.row(i); + const prow = P.row(i); + let betamin = -Infinity; + let betamax = Infinity; + let beta = 1; + let cnt = maxtries; + let done = false; + let psum = 0; + + while (!done && cnt--) { + // compute entropy and kernel row with beta precision + psum = 0; + let dp_sum = 0; + for (let j = 0; j < N; ++j) { + const dist = dist_i[j]; + const pj = i !== j ? Math.exp(-dist * beta) : 0; + dp_sum += dist * pj; + prow[j] = pj; + psum += pj; + } + // compute entropy + const H = psum > 0 ? Math.log(psum) + (beta * dp_sum) / psum : 0; + if (H > Htarget) { + betamin = beta; + beta = betamax === Infinity ? beta * 2 : (beta + betamax) / 2; + } else { + betamax = beta; + beta = betamin === -Infinity ? beta / 2 : (beta + betamin) / 2; + } + done = Math.abs(H - Htarget) < tol; + } + // normalize p + for (let j = 0; j < N; ++j) { + prow[j] /= psum; + } } - done = Math.abs(H - Htarget) < tol; - } - // normalize p - for (let j = 0; j < N; ++j) { - prow[j] /= psum; - } - } - // compute probabilities - const N2 = N * 2; - for (let i = 0; i < N; ++i) { - for (let j = i; j < N; ++j) { - const p = Math.max((P.entry(i, j) + P.entry(j, i)) / N2, 1e-100); - P.set_entry(i, j, p); - P.set_entry(j, i, p); - } - } - this._P = P; - return this; - } - - /** - * @param {number} [iterations=500] - Number of iterations. Default is `500` - * @returns {T} The projection. - */ - transform(iterations = 500) { - this.check_init(); - for (let i = 0; i < iterations; ++i) { - this.next(); - } - return this.projection; - } - - /** - * @param {number} [iterations=500] - Number of iterations. Default is `500` - * @returns {Generator} - The projection. - */ - *generator(iterations = 500) { - this.check_init(); - for (let i = 0; i < iterations; ++i) { - this.next(); - yield this.projection; - } - return this.projection; - } - - /** - * Performs a optimization step - * - * @private - * @returns {Matrix} - */ - next() { - const iter = ++this._iter; - if (!this._P || !this._ystep || !this._gains) throw new Error("Call init() first!"); - const P = this._P; - const ystep = this._ystep; - const gains = this._gains; - const N = this._N; - const dim = /** @type {number} */ (this._parameters.d); - const epsilon = /** @type {number} */ (this._parameters.epsilon); - const Y = this.Y; - - //calc cost gradient; - const pmul = iter < 100 ? 4 : 1; - - // compute Q dist (unnormalized) - const Qu = new Matrix(N, N, "zeros"); - let qsum = 0; - for (let i = 0; i < N; ++i) { - for (let j = i + 1; j < N; ++j) { - let dsum = 0; - for (let d = 0; d < dim; ++d) { - const dhere = Y.entry(i, d) - Y.entry(j, d); - dsum += dhere * dhere; + // compute probabilities + const N2 = N * 2; + for (let i = 0; i < N; ++i) { + for (let j = i; j < N; ++j) { + const p = Math.max((P.entry(i, j) + P.entry(j, i)) / N2, 1e-100); + P.set_entry(i, j, p); + P.set_entry(j, i, p); + } } - const qu = 1 / (1 + dsum); - Qu.set_entry(i, j, qu); - Qu.set_entry(j, i, qu); - qsum += 2 * qu; - } + this._P = P; + return this; } - // normalize Q dist - const Q = new Matrix(N, N, 0); - for (let i = 0; i < N; ++i) { - for (let j = i + 1; j < N; ++j) { - const val = Math.max(Qu.entry(i, j) / qsum, 1e-100); - Q.set_entry(i, j, val); - Q.set_entry(j, i, val); - } + /** + * @param {number} [iterations=500] - Number of iterations. Default is `500` + * @returns {T} The projection. + */ + transform(iterations = 500) { + this.check_init(); + for (let i = 0; i < iterations; ++i) { + this.next(); + } + return this.projection; } - const grad = new Matrix(N, dim, "zeros"); - for (let i = 0; i < N; ++i) { - for (let j = 0; j < N; ++j) { - const premult = 4 * (pmul * P.entry(i, j) - Q.entry(i, j)) * Qu.entry(i, j); - for (let d = 0; d < dim; ++d) { - grad.add_entry(i, d, premult * (Y.entry(i, d) - Y.entry(j, d))); + /** + * @param {number} [iterations=500] - Number of iterations. Default is `500` + * @returns {Generator} - The projection. + */ + *generator(iterations = 500) { + this.check_init(); + for (let i = 0; i < iterations; ++i) { + this.next(); + yield this.projection; } - } + return this.projection; } - // perform gradient step - const ymean = new Float64Array(dim); - for (let i = 0; i < N; ++i) { - for (let d = 0; d < dim; ++d) { - const gid = grad.entry(i, d); - const sid = ystep.entry(i, d); - const gainid = gains.entry(i, d); + /** + * Performs a optimization step + * + * @private + * @returns {Matrix} + */ + next() { + const iter = ++this._iter; + if (!this._P || !this._ystep || !this._gains) throw new Error("Call init() first!"); + const P = this._P; + const ystep = this._ystep; + const gains = this._gains; + const N = this._N; + const dim = /** @type {number} */ (this._parameters.d); + const epsilon = /** @type {number} */ (this._parameters.epsilon); + const Y = this.Y; + + //calc cost gradient; + const pmul = iter < 100 ? 4 : 1; + + // compute Q dist (unnormalized) + const Qu = new Matrix(N, N, "zeros"); + let qsum = 0; + for (let i = 0; i < N; ++i) { + for (let j = i + 1; j < N; ++j) { + let dsum = 0; + for (let d = 0; d < dim; ++d) { + const dhere = Y.entry(i, d) - Y.entry(j, d); + dsum += dhere * dhere; + } + const qu = 1 / (1 + dsum); + Qu.set_entry(i, j, qu); + Qu.set_entry(j, i, qu); + qsum += 2 * qu; + } + } + + // normalize Q dist + const Q = new Matrix(N, N, 0); + for (let i = 0; i < N; ++i) { + for (let j = i + 1; j < N; ++j) { + const val = Math.max(Qu.entry(i, j) / qsum, 1e-100); + Q.set_entry(i, j, val); + Q.set_entry(j, i, val); + } + } + + const grad = new Matrix(N, dim, "zeros"); + for (let i = 0; i < N; ++i) { + for (let j = 0; j < N; ++j) { + const premult = 4 * (pmul * P.entry(i, j) - Q.entry(i, j)) * Qu.entry(i, j); + for (let d = 0; d < dim; ++d) { + grad.add_entry(i, d, premult * (Y.entry(i, d) - Y.entry(j, d))); + } + } + } - let newgain = Math.sign(gid) === Math.sign(sid) ? gainid * 0.8 : gainid + 0.2; - if (newgain < 0.01) newgain = 0.01; - gains.set_entry(i, d, newgain); + // perform gradient step + const ymean = new Float64Array(dim); + for (let i = 0; i < N; ++i) { + for (let d = 0; d < dim; ++d) { + const gid = grad.entry(i, d); + const sid = ystep.entry(i, d); + const gainid = gains.entry(i, d); + + let newgain = Math.sign(gid) === Math.sign(sid) ? gainid * 0.8 : gainid + 0.2; + if (newgain < 0.01) newgain = 0.01; + gains.set_entry(i, d, newgain); + + const momval = iter < 250 ? 0.5 : 0.8; + const newsid = momval * sid - epsilon * newgain * gid; + ystep.set_entry(i, d, newsid); + + Y.add_entry(i, d, newsid); + ymean[d] += Y.entry(i, d); + } + } + + for (let i = 0; i < N; ++i) { + for (let d = 0; d < dim; ++d) { + Y.sub_entry(i, d, ymean[d] / N); + } + } - const momval = iter < 250 ? 0.5 : 0.8; - const newsid = momval * sid - epsilon * newgain * gid; - ystep.set_entry(i, d, newsid); + return this.Y; + } - Y.add_entry(i, d, newsid); - ymean[d] += Y.entry(i, d); - } + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X, parameters) { + const dr = new TSNE(X, parameters); + return dr.transform(); } - for (let i = 0; i < N; ++i) { - for (let d = 0; d < dim; ++d) { - Y.sub_entry(i, d, ymean[d] / N); - } - } - - return this.Y; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X, parameters) { - const dr = new TSNE(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new TSNE(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new TSNE(X, parameters); - return dr.transform_async(); - } + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new TSNE(X, parameters); + yield* dr.generator(); + return dr.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new TSNE(X, parameters); + return dr.transform_async(); + } } /** @@ -10445,31 +11027,31 @@ class TSNE extends DR { * @see http://optimization-js.github.io/optimization-js/optimization.js.html#line438 */ function powell(f, x0, max_iter = 300) { - const epsilon = 1e-2; - const n = x0.length; - let alpha = 1e-3; - let pfx = 10000; - const x = /** @type {T} */ (x0.slice()); - let fx = f(x); - let convergence = false; - - while (max_iter-- >= 0 && !convergence) { - convergence = true; - for (let i = 0; i < n; ++i) { - x[i] += 1e-6; - const fxi = f(x); - x[i] -= 1e-6; - const dx = (fxi - fx) / 1e-6; - if (Math.abs(dx) > epsilon) { - convergence = false; - } - x[i] -= alpha * dx; - fx = f(x); - } - alpha *= pfx >= fx ? 1.05 : 0.4; - pfx = fx; - } - return x; + const epsilon = 1e-2; + const n = x0.length; + let alpha = 1e-3; + let pfx = 10000; + const x = /** @type {T} */ (x0.slice()); + let fx = f(x); + let convergence = false; + + while (max_iter-- >= 0 && !convergence) { + convergence = true; + for (let i = 0; i < n; ++i) { + x[i] += 1e-6; + const fxi = f(x); + x[i] -= 1e-6; + const dx = (fxi - fx) / 1e-6; + if (Math.abs(dx) > epsilon) { + convergence = false; + } + x[i] -= alpha * dx; + fx = f(x); + } + alpha *= pfx >= fx ? 1.05 : 0.4; + pfx = fx; + } + return x; } /** @import {InputType} from "../index.js" */ @@ -10505,486 +11087,481 @@ function powell(f, x0, max_iter = 300) { * // [[x1, y1], [x2, y2], [x3, y3]] */ class UMAP extends DR { - /** - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - */ - constructor(X, parameters) { - super( - X, - { - n_neighbors: 15, - local_connectivity: 1, - min_dist: 1, - d: 2, - metric: euclidean, - seed: 1212, - _spread: 1, - _set_op_mix_ratio: 1, - _repulsion_strength: 1, - _negative_sample_rate: 5, - _n_epochs: 350, - _initial_alpha: 1, - }, - parameters, - ); - [this._N, this._D] = this.X.shape; - const n_neighbors = /** @type {number} */ (this.parameter("n_neighbors")); - const local_connectivity = /** @type {number} */ (this.parameter("local_connectivity")); - const d = /** @type {number} */ (this.parameter("d")); - /* let n_neighbors = Math.min(this._N - 1, parameters.n_neighbors); + /** + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + */ + constructor(X, parameters) { + super( + X, + { + n_neighbors: 15, + local_connectivity: 1, + min_dist: 1, + d: 2, + metric: euclidean, + seed: 1212, + _spread: 1, + _set_op_mix_ratio: 1, + _repulsion_strength: 1, + _negative_sample_rate: 5, + _n_epochs: 350, + _initial_alpha: 1, + }, + parameters, + ); + [this._N, this._D] = this.X.shape; + const n_neighbors = /** @type {number} */ (this.parameter("n_neighbors")); + const local_connectivity = /** @type {number} */ (this.parameter("local_connectivity")); + const d = /** @type {number} */ (this.parameter("d")); + /* let n_neighbors = Math.min(this._N - 1, parameters.n_neighbors); this.parameter("n_neighbors", n_neighbors); this.parameter("local_connectivity", Math.min(this.parameter("local_connectivity"), n_neighbors - 1)); */ - if (n_neighbors > this._N) { - throw new Error( - `Parameter n_neighbors (=${n_neighbors}) needs to be smaller than dataset size (N=${this._N})!`, - ); - } - if (local_connectivity > n_neighbors) { - throw new Error( - `Parameter local_connectivity (=${local_connectivity}) needs to be smaller than parameter n_neighbors (=${n_neighbors})`, - ); - } - this._iter = 0; - const randomizer = this._randomizer; - this.Y = new Matrix(this._N, d, () => randomizer.random); - } - - /** - * @private - * @param {number} spread - * @param {number} min_dist - * @returns {number[]} - */ - _find_ab_params(spread, min_dist) { - /** @type {(x: number, a: number, b: number) => number} */ - const curve = (x, a, b) => 1 / (1 + a * x ** (2 * b)); - const xv = linspace(0, spread * 3, 300); - const yv = linspace(0, spread * 3, 300); - - for (let i = 0, n = xv.length; i < n; ++i) { - const xv_i = xv[i]; - yv[i] = xv_i < min_dist ? 1 : Math.exp(-(xv_i - min_dist) / spread); - } - - /** @type {(p: [number, number]) => number} */ - const err = (p) => { - const error = linspace(1, 300).map((_, i) => yv[i] - curve(xv[i], p[0], p[1])); - return Math.sqrt(neumair_sum(error.map((e) => e * e))); - }; - - return powell(err, [1, 1]); - } - - /** - * @private - * @param {{ element: Float64Array; index: number; distance: number }[][]} distances - * @param {number[]} sigmas - * @param {number[]} rhos - * @returns {{ element: Float64Array; index: number; distance: number }[][]} - */ - _compute_membership_strengths(distances, sigmas, rhos) { - for (let i = 0, n = distances.length; i < n; ++i) { - const rho = rhos[i]; - const curr_dist = distances[i]; - for (let j = 0, m = curr_dist.length; j < m; ++j) { - const v = curr_dist[j].distance - rho; - curr_dist[j].distance = v > 0 ? Math.exp(-v / sigmas[i]) : 1.0; - } - } - return distances; - } - - /** - * @private - * @param {NaiveKNN | BallTree} knn - * @param {number} k - * @returns {{ - * distances: { element: Float64Array; index: number; distance: number }[][]; - * sigmas: number[]; - * rhos: number[]; - * }} - */ - _smooth_knn_dist(knn, k) { - const SMOOTH_K_TOLERANCE = 1e-5; - const MIN_K_DIST_SCALE = 1e-3; - const n_iter = 64; - const local_connectivity = /** @type {number} */ (this._parameters.local_connectivity); - const metric = /** @type {Metric | "precomputed"} */ (this._parameters.metric); - const target = Math.log2(k); - const rhos = []; - const sigmas = []; - const X = this.X; - const N = X.shape[0]; - //const distances = [...X].map(x_i => knn.search(x_i, k).raw_data().reverse()); - - /** @type {{ element: Float64Array; index: number; distance: number }[][]} */ - const distances = []; - if (metric === "precomputed" || knn instanceof NaiveKNN) { - for (let i = 0; i < N; ++i) { - distances.push(knn.search_by_index(i, k).reverse()); - } - } else { - for (const x_i of X) { - distances.push(knn.search(x_i, k).reverse()); - } + if (n_neighbors > this._N) { + throw new Error( + `Parameter n_neighbors (=${n_neighbors}) needs to be smaller than dataset size (N=${this._N})!`, + ); + } + if (local_connectivity > n_neighbors) { + throw new Error( + `Parameter local_connectivity (=${local_connectivity}) needs to be smaller than parameter n_neighbors (=${n_neighbors})`, + ); + } + this._iter = 0; + const randomizer = this._randomizer; + this.Y = new Matrix(this._N, d, () => randomizer.random); } - const index = Math.floor(local_connectivity); - const interpolation = local_connectivity - index; - for (let i = 0; i < N; ++i) { - let lo = 0; - let hi = Infinity; - let mid = 1; - let rho = 0; - - const search_result = distances[i]; - const non_zero_dist = search_result.filter((d) => d.distance > 0); - const non_zero_dist_length = non_zero_dist.length; - if (non_zero_dist_length >= local_connectivity) { - if (index > 0) { - rho = non_zero_dist[index - 1].distance; - if (interpolation > SMOOTH_K_TOLERANCE) { - rho += - interpolation * (non_zero_dist[index].distance - non_zero_dist[index - 1].distance); - } - } else { - rho = interpolation * non_zero_dist[0].distance; - } - } else if (non_zero_dist_length > 0) { - rho = non_zero_dist[non_zero_dist_length - 1].distance; - } - for (let x = 0; x < n_iter; ++x) { - let psum = 0; - for (let j = 0; j < k; ++j) { - const d = search_result[j].distance - rho; - psum += d > 0 ? Math.exp(-(d / mid)) : 1; - } - if (Math.abs(psum - target) < SMOOTH_K_TOLERANCE) { - break; - } - if (psum > target) { - [hi, mid] = [mid, (lo + hi) / 2]; + /** + * @private + * @param {number} spread + * @param {number} min_dist + * @returns {number[]} + */ + _find_ab_params(spread, min_dist) { + /** @type {(x: number, a: number, b: number) => number} */ + const curve = (x, a, b) => 1 / (1 + a * x ** (2 * b)); + const xv = linspace(0, spread * 3, 300); + const yv = linspace(0, spread * 3, 300); + + for (let i = 0, n = xv.length; i < n; ++i) { + const xv_i = xv[i]; + yv[i] = xv_i < min_dist ? 1 : Math.exp(-(xv_i - min_dist) / spread); + } + + /** @type {(p: [number, number]) => number} */ + const err = (p) => { + const error = linspace(1, 300).map((_, i) => yv[i] - curve(xv[i], p[0], p[1])); + return Math.sqrt(neumair_sum(error.map((e) => e * e))); + }; + + return powell(err, [1, 1]); + } + + /** + * @private + * @param {{ element: Float64Array; index: number; distance: number }[][]} distances + * @param {number[]} sigmas + * @param {number[]} rhos + * @returns {{ element: Float64Array; index: number; distance: number }[][]} + */ + _compute_membership_strengths(distances, sigmas, rhos) { + for (let i = 0, n = distances.length; i < n; ++i) { + const rho = rhos[i]; + const curr_dist = distances[i]; + for (let j = 0, m = curr_dist.length; j < m; ++j) { + const v = curr_dist[j].distance - rho; + curr_dist[j].distance = v > 0 ? Math.exp(-v / sigmas[i]) : 1.0; + } + } + return distances; + } + + /** + * @private + * @param {NaiveKNN | BallTree} knn + * @param {number} k + * @returns {{ + * distances: { element: Float64Array; index: number; distance: number }[][]; + * sigmas: number[]; + * rhos: number[]; + * }} + */ + _smooth_knn_dist(knn, k) { + const SMOOTH_K_TOLERANCE = 1e-5; + const MIN_K_DIST_SCALE = 1e-3; + const n_iter = 64; + const local_connectivity = /** @type {number} */ (this._parameters.local_connectivity); + const metric = /** @type {Metric | "precomputed"} */ (this._parameters.metric); + const target = Math.log2(k); + const rhos = []; + const sigmas = []; + const X = this.X; + const N = X.shape[0]; + //const distances = [...X].map(x_i => knn.search(x_i, k).raw_data().reverse()); + + /** @type {{ element: Float64Array; index: number; distance: number }[][]} */ + const distances = []; + if (metric === "precomputed" || knn instanceof NaiveKNN) { + for (let i = 0; i < N; ++i) { + distances.push(knn.search_by_index(i, k).reverse()); + } } else { - if (hi === Infinity) { - [lo, mid] = [mid, mid * 2]; - } else { - [lo, mid] = [mid, (lo + hi) / 2]; - } - } - } - - //let mean_d = null; - if (rho > 0) { - const mean_ithd = search_result.reduce((a, b) => a + b.distance, 0) / search_result.length; - if (mid < MIN_K_DIST_SCALE * mean_ithd) { - mid = MIN_K_DIST_SCALE * mean_ithd; - } - } else { - const mean_d = distances.reduce( - (acc, res) => acc + res.reduce((a, b) => a + b.distance, 0) / res.length, - 0, - ); - if (mid < MIN_K_DIST_SCALE * mean_d) { - mid = MIN_K_DIST_SCALE * mean_d; - } - } - rhos[i] = rho; - sigmas[i] = mid; - } - return { - distances: distances, - sigmas: sigmas, - rhos: rhos, - }; - } - - /** - * @private - * @param {Matrix} X - * @param {number} n_neighbors - * @returns {Matrix} - */ - _fuzzy_simplicial_set(X, n_neighbors) { - const N = X.shape[0]; - const metric = /** @type {Metric | "precomputed"} */ (this._parameters.metric); - const _set_op_mix_ratio = /** @type {number} */ (this._parameters._set_op_mix_ratio); - - const knn = - metric === "precomputed" - ? new NaiveKNN(X.to2dArray(), { - metric: "precomputed", - seed: /** @type {number} */ (this._parameters.seed), - }) - : new BallTree(X.to2dArray(), { - metric, - seed: /** @type {number} */ (this._parameters.seed), - }); - let { distances, sigmas, rhos } = this._smooth_knn_dist(knn, n_neighbors); - distances = this._compute_membership_strengths(distances, sigmas, rhos); - const result = new Matrix(N, N, "zeros"); - for (let i = 0; i < N; ++i) { - const distances_i = distances[i]; - for (let j = 0; j < distances_i.length; ++j) { - result.set_entry(i, distances_i[j].index, distances_i[j].distance); - } - } - - const transposed_result = result.T; - const prod_matrix = result.mult(transposed_result); - return result - .add(transposed_result) - .sub(prod_matrix) - .mult(_set_op_mix_ratio) - .add(prod_matrix.mult(1 - _set_op_mix_ratio)); - } - - /** - * @private - * @param {number} n_epochs - * @returns {Float32Array} - */ - _make_epochs_per_sample(n_epochs) { - if (!this._weights) throw new Error("Call init() first!"); - const weights = this._weights; - const result = new Float32Array(weights.length).fill(-1); - const weight_scl = n_epochs / max(weights); - weights.forEach((w, i) => { - const sample = w * weight_scl; - if (sample > 0) result[i] = Math.round(n_epochs / sample); - }); - return result; - } - - /** - * @private - * @param {Matrix} graph - * @returns {{ rows: number[]; cols: number[]; data: number[] }} - */ - _tocoo(graph) { - const rows = []; - const cols = []; - const data = []; - const [rows_n, cols_n] = graph.shape; - for (let row = 0; row < rows_n; ++row) { - for (let col = 0; col < cols_n; ++col) { - const entry = graph.entry(row, col); - if (entry !== 0) { - rows.push(row); - cols.push(col); - data.push(entry); - } - } - } - return { - rows: rows, - cols: cols, - data: data, - }; - } - - /** - * Computes all necessary - * - * @returns {UMAP} - */ - init() { - const _spread = /** @type {number} */ (this._parameters._spread); - const min_dist = /** @type {number} */ (this._parameters.min_dist); - const n_neighbors = /** @type {number} */ (this._parameters.n_neighbors); - const _n_epochs = /** @type {number} */ (this._parameters._n_epochs); - const _negative_sample_rate = /** @type {number} */ (this._parameters._negative_sample_rate); - const [a, b] = this._find_ab_params(_spread, min_dist); - this._a = a; - this._b = b; - this._graph = this._fuzzy_simplicial_set(this.X, n_neighbors); - const { rows, cols, data: weights } = this._tocoo(this._graph); - this._head = rows; - this._tail = cols; - this._weights = weights; - this._epochs_per_sample = this._make_epochs_per_sample(_n_epochs); - this._epochs_per_negative_sample = this._epochs_per_sample.map( - (d) => d * _negative_sample_rate, - ); - this._epoch_of_next_sample = this._epochs_per_sample.slice(); - this._epoch_of_next_negative_sample = this._epochs_per_negative_sample.slice(); - return this; - } - - graph() { - this.check_init(); - return { cols: this._head, rows: this._tail, weights: this._weights }; - } - - /** - * @param {number} [iterations=350] - Number of iterations. Default is `350` - * @returns {T} - */ - transform(iterations = 350) { - if (this.parameter("_n_epochs") !== iterations) { - this.parameter("_n_epochs", iterations); - this.init(); - } - this.check_init(); - for (let i = 0; i < iterations; ++i) { - this.next(); - } - return this.projection; - } - - /** - * @param {number} [iterations=350] - Number of iterations. Default is `350` - * @returns {Generator} - */ - *generator(iterations = 350) { - if (this.parameter("_n_epochs") !== iterations) { - this.parameter("_n_epochs", iterations); - this.init(); - } - this.check_init(); - for (let i = 0; i < iterations; ++i) { - this.next(); - yield this.projection; - } - return this.projection; - } - - /** - * @private - * @param {number} x - * @returns {number} - */ - _clip(x) { - if (x > 4) return 4; - if (x < -4) return -4; - return x; - } - - /** - * Performs the optimization step. - * - * @private - * @param {Matrix} head_embedding - * @param {Matrix} tail_embedding - * @param {number[]} head - * @param {number[]} tail - * @returns {Matrix} - */ - _optimize_layout(head_embedding, tail_embedding, head, tail) { - const randomizer = this._randomizer; - const _repulsion_strength = /** @type {number} */ (this.parameter("_repulsion_strength")); - const dim = /** @type {number} */ (this.parameter("d")); - const { - _alpha: alpha, - _a: a, - _b: b, - _epochs_per_sample: epochs_per_sample, - _epochs_per_negative_sample: epochs_per_negative_sample, - _epoch_of_next_negative_sample: epoch_of_next_negative_sample, - _epoch_of_next_sample: epoch_of_next_sample, - _clip: clip, - } = this; - if ( - alpha === undefined || - a === undefined || - b === undefined || - epochs_per_sample === undefined || - epochs_per_negative_sample === undefined || - epoch_of_next_negative_sample === undefined || - epoch_of_next_sample === undefined || - clip === undefined - ) { - throw new Error("call init() first!"); - } - const tail_length = tail.length; - - for (let i = 0, n = epochs_per_sample.length; i < n; ++i) { - if (epoch_of_next_sample[i] <= this._iter) { - const j = head[i]; - const k = tail[i]; - const current = head_embedding.row(j); - const other = tail_embedding.row(k); - const dist = euclidean_squared(current, other); - if (dist > 0) { - const grad_coeff = (-2 * a * b * dist ** (b - 1)) / (a * dist ** b + 1); - for (let d = 0; d < dim; ++d) { - const grad_d = clip(grad_coeff * (current[d] - other[d])) * alpha; - current[d] += grad_d; - other[d] -= grad_d; - } - } - epoch_of_next_sample[i] += epochs_per_sample[i]; - const n_neg_samples = - (this._iter - epoch_of_next_negative_sample[i]) / epochs_per_negative_sample[i]; - for (let p = 0; p < n_neg_samples; ++p) { - const k = randomizer.random_int % tail_length; - const other = tail_embedding.row(tail[k]); - const dist = euclidean_squared(current, other); - if (dist > 0) { - const grad_coeff = - (2 * _repulsion_strength * b) / ((0.01 + dist) * (a * dist ** b + 1)); - for (let d = 0; d < dim; ++d) { - const grad_d = clip(grad_coeff * (current[d] - other[d])) * alpha; - current[d] += grad_d; - other[d] -= grad_d; - } - } - } - epoch_of_next_negative_sample[i] += n_neg_samples * epochs_per_negative_sample[i]; - } - } - return head_embedding; - } - - /** - * @private - * @returns {Matrix} - */ - next() { - if (!this._head || !this._tail) throw new Error("Call init() first!"); - const iter = ++this._iter; - const Y = this.Y; - const _initial_alpha = /** @type {number} */ (this._parameters._initial_alpha); - const _n_epochs = /** @type {number} */ (this._parameters._n_epochs); - this._alpha = _initial_alpha * (1 - iter / _n_epochs); - this.Y = this._optimize_layout(Y, Y, this._head, this._tail); - - return this.Y; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X, parameters) { - const dr = new UMAP(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new UMAP(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new UMAP(X, parameters); - return dr.transform_async(); - } + for (const x_i of X) { + distances.push(knn.search(x_i, k).reverse()); + } + } + + const index = Math.floor(local_connectivity); + const interpolation = local_connectivity - index; + for (let i = 0; i < N; ++i) { + let lo = 0; + let hi = Infinity; + let mid = 1; + let rho = 0; + + const search_result = distances[i]; + const non_zero_dist = search_result.filter((d) => d.distance > 0); + const non_zero_dist_length = non_zero_dist.length; + if (non_zero_dist_length >= local_connectivity) { + if (index > 0) { + rho = non_zero_dist[index - 1].distance; + if (interpolation > SMOOTH_K_TOLERANCE) { + rho += interpolation * (non_zero_dist[index].distance - non_zero_dist[index - 1].distance); + } + } else { + rho = interpolation * non_zero_dist[0].distance; + } + } else if (non_zero_dist_length > 0) { + rho = non_zero_dist[non_zero_dist_length - 1].distance; + } + for (let x = 0; x < n_iter; ++x) { + let psum = 0; + for (let j = 0; j < k; ++j) { + const d = search_result[j].distance - rho; + psum += d > 0 ? Math.exp(-(d / mid)) : 1; + } + if (Math.abs(psum - target) < SMOOTH_K_TOLERANCE) { + break; + } + if (psum > target) { + [hi, mid] = [mid, (lo + hi) / 2]; + } else { + if (hi === Infinity) { + [lo, mid] = [mid, mid * 2]; + } else { + [lo, mid] = [mid, (lo + hi) / 2]; + } + } + } + + //let mean_d = null; + if (rho > 0) { + const mean_ithd = search_result.reduce((a, b) => a + b.distance, 0) / search_result.length; + if (mid < MIN_K_DIST_SCALE * mean_ithd) { + mid = MIN_K_DIST_SCALE * mean_ithd; + } + } else { + const mean_d = distances.reduce( + (acc, res) => acc + res.reduce((a, b) => a + b.distance, 0) / res.length, + 0, + ); + if (mid < MIN_K_DIST_SCALE * mean_d) { + mid = MIN_K_DIST_SCALE * mean_d; + } + } + rhos[i] = rho; + sigmas[i] = mid; + } + return { + distances: distances, + sigmas: sigmas, + rhos: rhos, + }; + } + + /** + * @private + * @param {Matrix} X + * @param {number} n_neighbors + * @returns {Matrix} + */ + _fuzzy_simplicial_set(X, n_neighbors) { + const N = X.shape[0]; + const metric = /** @type {Metric | "precomputed"} */ (this._parameters.metric); + const _set_op_mix_ratio = /** @type {number} */ (this._parameters._set_op_mix_ratio); + + const knn = + metric === "precomputed" + ? new NaiveKNN(X.to2dArray(), { + metric: "precomputed", + seed: /** @type {number} */ (this._parameters.seed), + }) + : new BallTree(X.to2dArray(), { + metric, + seed: /** @type {number} */ (this._parameters.seed), + }); + let { distances, sigmas, rhos } = this._smooth_knn_dist(knn, n_neighbors); + distances = this._compute_membership_strengths(distances, sigmas, rhos); + const result = new Matrix(N, N, "zeros"); + for (let i = 0; i < N; ++i) { + const distances_i = distances[i]; + for (let j = 0; j < distances_i.length; ++j) { + result.set_entry(i, distances_i[j].index, distances_i[j].distance); + } + } + + const transposed_result = result.T; + const prod_matrix = result.mult(transposed_result); + return result + .add(transposed_result) + .sub(prod_matrix) + .mult(_set_op_mix_ratio) + .add(prod_matrix.mult(1 - _set_op_mix_ratio)); + } + + /** + * @private + * @param {number} n_epochs + * @returns {Float32Array} + */ + _make_epochs_per_sample(n_epochs) { + if (!this._weights) throw new Error("Call init() first!"); + const weights = this._weights; + const result = new Float32Array(weights.length).fill(-1); + const weight_scl = n_epochs / max(weights); + weights.forEach((w, i) => { + const sample = w * weight_scl; + if (sample > 0) result[i] = Math.round(n_epochs / sample); + }); + return result; + } + + /** + * @private + * @param {Matrix} graph + * @returns {{ rows: number[]; cols: number[]; data: number[] }} + */ + _tocoo(graph) { + const rows = []; + const cols = []; + const data = []; + const [rows_n, cols_n] = graph.shape; + for (let row = 0; row < rows_n; ++row) { + for (let col = 0; col < cols_n; ++col) { + const entry = graph.entry(row, col); + if (entry !== 0) { + rows.push(row); + cols.push(col); + data.push(entry); + } + } + } + return { + rows: rows, + cols: cols, + data: data, + }; + } + + /** + * Computes all necessary + * + * @returns {UMAP} + */ + init() { + const _spread = /** @type {number} */ (this._parameters._spread); + const min_dist = /** @type {number} */ (this._parameters.min_dist); + const n_neighbors = /** @type {number} */ (this._parameters.n_neighbors); + const _n_epochs = /** @type {number} */ (this._parameters._n_epochs); + const _negative_sample_rate = /** @type {number} */ (this._parameters._negative_sample_rate); + const [a, b] = this._find_ab_params(_spread, min_dist); + this._a = a; + this._b = b; + this._graph = this._fuzzy_simplicial_set(this.X, n_neighbors); + const { rows, cols, data: weights } = this._tocoo(this._graph); + this._head = rows; + this._tail = cols; + this._weights = weights; + this._epochs_per_sample = this._make_epochs_per_sample(_n_epochs); + this._epochs_per_negative_sample = this._epochs_per_sample.map((d) => d * _negative_sample_rate); + this._epoch_of_next_sample = this._epochs_per_sample.slice(); + this._epoch_of_next_negative_sample = this._epochs_per_negative_sample.slice(); + return this; + } + + graph() { + this.check_init(); + return { cols: this._head, rows: this._tail, weights: this._weights }; + } + + /** + * @param {number} [iterations=350] - Number of iterations. Default is `350` + * @returns {T} + */ + transform(iterations = 350) { + if (this.parameter("_n_epochs") !== iterations) { + this.parameter("_n_epochs", iterations); + this.init(); + } + this.check_init(); + for (let i = 0; i < iterations; ++i) { + this.next(); + } + return this.projection; + } + + /** + * @param {number} [iterations=350] - Number of iterations. Default is `350` + * @returns {Generator} + */ + *generator(iterations = 350) { + if (this.parameter("_n_epochs") !== iterations) { + this.parameter("_n_epochs", iterations); + this.init(); + } + this.check_init(); + for (let i = 0; i < iterations; ++i) { + this.next(); + yield this.projection; + } + return this.projection; + } + + /** + * @private + * @param {number} x + * @returns {number} + */ + _clip(x) { + if (x > 4) return 4; + if (x < -4) return -4; + return x; + } + + /** + * Performs the optimization step. + * + * @private + * @param {Matrix} head_embedding + * @param {Matrix} tail_embedding + * @param {number[]} head + * @param {number[]} tail + * @returns {Matrix} + */ + _optimize_layout(head_embedding, tail_embedding, head, tail) { + const randomizer = this._randomizer; + const _repulsion_strength = /** @type {number} */ (this.parameter("_repulsion_strength")); + const dim = /** @type {number} */ (this.parameter("d")); + const { + _alpha: alpha, + _a: a, + _b: b, + _epochs_per_sample: epochs_per_sample, + _epochs_per_negative_sample: epochs_per_negative_sample, + _epoch_of_next_negative_sample: epoch_of_next_negative_sample, + _epoch_of_next_sample: epoch_of_next_sample, + _clip: clip, + } = this; + if ( + alpha === undefined || + a === undefined || + b === undefined || + epochs_per_sample === undefined || + epochs_per_negative_sample === undefined || + epoch_of_next_negative_sample === undefined || + epoch_of_next_sample === undefined || + clip === undefined + ) { + throw new Error("call init() first!"); + } + const tail_length = tail.length; + + for (let i = 0, n = epochs_per_sample.length; i < n; ++i) { + if (epoch_of_next_sample[i] <= this._iter) { + const j = head[i]; + const k = tail[i]; + const current = head_embedding.row(j); + const other = tail_embedding.row(k); + const dist = euclidean_squared(current, other); + if (dist > 0) { + const grad_coeff = (-2 * a * b * dist ** (b - 1)) / (a * dist ** b + 1); + for (let d = 0; d < dim; ++d) { + const grad_d = clip(grad_coeff * (current[d] - other[d])) * alpha; + current[d] += grad_d; + other[d] -= grad_d; + } + } + epoch_of_next_sample[i] += epochs_per_sample[i]; + const n_neg_samples = (this._iter - epoch_of_next_negative_sample[i]) / epochs_per_negative_sample[i]; + for (let p = 0; p < n_neg_samples; ++p) { + const k = randomizer.random_int % tail_length; + const other = tail_embedding.row(tail[k]); + const dist = euclidean_squared(current, other); + if (dist > 0) { + const grad_coeff = (2 * _repulsion_strength * b) / ((0.01 + dist) * (a * dist ** b + 1)); + for (let d = 0; d < dim; ++d) { + const grad_d = clip(grad_coeff * (current[d] - other[d])) * alpha; + current[d] += grad_d; + other[d] -= grad_d; + } + } + } + epoch_of_next_negative_sample[i] += n_neg_samples * epochs_per_negative_sample[i]; + } + } + return head_embedding; + } + + /** + * @private + * @returns {Matrix} + */ + next() { + if (!this._head || !this._tail) throw new Error("Call init() first!"); + const iter = ++this._iter; + const Y = this.Y; + const _initial_alpha = /** @type {number} */ (this._parameters._initial_alpha); + const _n_epochs = /** @type {number} */ (this._parameters._n_epochs); + this._alpha = _initial_alpha * (1 - iter / _n_epochs); + this.Y = this._optimize_layout(Y, Y, this._head, this._tail); + + return this.Y; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X, parameters) { + const dr = new UMAP(X, parameters); + return dr.transform(); + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new UMAP(X, parameters); + yield* dr.generator(); + return dr.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new UMAP(X, parameters); + return dr.transform_async(); + } } const version = pkg.version; @@ -11006,6 +11583,7 @@ exports.LLE = LLE; exports.LSH = LSH; exports.LSP = LSP; exports.LTSA = LTSA; +exports.LocalMAP = LocalMAP; exports.MDS = MDS; exports.Matrix = Matrix; exports.MeanShift = MeanShift; @@ -11013,6 +11591,7 @@ exports.NNDescent = NNDescent; exports.NaiveKNN = NaiveKNN; exports.OPTICS = OPTICS; exports.PCA = PCA; +exports.PaCMAP = PaCMAP; exports.Randomizer = Randomizer; exports.SAMMON = SAMMON; exports.SMACOF = SMACOF; diff --git a/dist/druid.cjs.map b/dist/druid.cjs.map index abba69a..f4528f3 100644 --- a/dist/druid.cjs.map +++ b/dist/druid.cjs.map @@ -1 +1 @@ -{"version":3,"file":"druid.cjs","sources":["../src/metrics/bray_curtis.js","../src/metrics/canberra.js","../src/metrics/chebyshev.js","../src/metrics/cosine.js","../src/metrics/euclidean_squared.js","../src/metrics/euclidean.js","../src/metrics/goodman_kruskal.js","../src/metrics/hamming.js","../src/metrics/haversine.js","../src/metrics/jaccard.js","../src/metrics/manhattan.js","../src/metrics/sokal_michener.js","../src/metrics/wasserstein.js","../src/metrics/yule.js","../src/matrix/distance_matrix.js","../src/matrix/k_nearest_neighbors.js","../src/matrix/linspace.js","../src/linear_algebra/inner_product.js","../src/numerical/kahan_sum.js","../src/numerical/neumair_sum.js","../src/linear_algebra/qr.js","../src/linear_algebra/qr_householder.js","../src/util/max.js","../src/util/min.js","../src/util/randomizer.js","../src/linear_algebra/simultaneous_poweriteration.js","../src/matrix/Matrix.js","../src/matrix/norm.js","../src/matrix/normalize.js","../src/clustering/Clustering.js","../src/clustering/CURE.js","../src/clustering/Hierarchical_Clustering.js","../src/datastructure/DisjointSet.js","../src/datastructure/Heap.js","../src/clustering/KMeans.js","../src/clustering/KMedoids.js","../src/clustering/MeanShift.js","../src/clustering/OPTICS.js","../src/clustering/XMeans.js","../src/dimred/DR.js","../src/dimred/FASTMAP.js","../src/knn/KNN.js","../src/knn/Annoy.js","../src/knn/BallTree.js","../src/knn/HNSW.js","../src/knn/KDTree.js","../src/knn/LSH.js","../src/knn/NaiveKNN.js","../src/knn/NNDescent.js","../src/dimred/SMACOF.js","../src/dimred/ISOMAP.js","../src/dimred/LDA.js","../src/dimred/LLE.js","../src/dimred/MDS.js","../src/dimred/LSP.js","../src/dimred/LTSA.js","../src/dimred/PCA.js","../src/dimred/SAMMON.js","../src/dimred/SQDMDS.js","../src/dimred/TopoMap.js","../src/dimred/TriMap.js","../src/dimred/TSNE.js","../src/optimization/powell.js","../src/dimred/UMAP.js","../src/index.js"],"sourcesContent":["/**\n * Computes the Bray-Curtis distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The Bray-Curtis distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Bray%E2%80%93Curtis_dissimilarity}\n */\nexport function bray_curtis(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n let sum_abs_diff = 0;\n let sum_ab = 0;\n for (let i = 0; i < a.length; ++i) {\n sum_abs_diff += Math.abs(a[i] - b[i]);\n sum_ab += a[i] + b[i];\n }\n return sum_abs_diff / sum_ab;\n}\n","/**\n * Computes the canberra distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The canberra distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Canberra_distance}\n */\nexport function canberra(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let sum = 0;\n for (let i = 0; i < n; ++i) {\n sum += Math.abs(a[i] - b[i]) / (Math.abs(a[i]) + Math.abs(b[i]));\n }\n return sum;\n}\n","/**\n * Computes the chebyshev distance (L) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The chebyshev distance between `a` and `b`.\n */\nexport function chebyshev(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n const res = [];\n for (let i = 0; i < n; ++i) {\n res.push(Math.abs(a[i] - b[i]));\n }\n return Math.max(...res);\n}\n","/**\n * Computes the cosine distance (not similarity) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The cosine distance between `a` and `b`.\n * @example\n * import { cosine } from \"@saehrimnir/druidjs\";\n * const a = [1, 2, 3];\n * const b = [4, 5, 6];\n * const distance = cosine(a, b); // 0.9746318461970762\n */\nexport function cosine(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let sum = 0;\n let sum_a = 0;\n let sum_b = 0;\n for (let i = 0; i < n; ++i) {\n sum += a[i] * b[i];\n sum_a += a[i] * a[i];\n sum_b += b[i] * b[i];\n }\n return Math.acos(sum / (Math.sqrt(sum_a) * Math.sqrt(sum_b)));\n}\n","/**\n * Computes the squared euclidean distance (l_2^2) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The squared euclidean distance between `a` and `b`.\n\n */\nexport function euclidean_squared(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let sum = 0;\n for (let i = 0; i < n; ++i) {\n const a_b = a[i] - b[i];\n sum += a_b * a_b;\n }\n return sum;\n}\n","import { euclidean_squared } from \"../metrics/euclidean_squared.js\";\n\n/**\n * Computes the euclidean distance (`l_2`) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The euclidean distance between `a` and `b`.\n */\nexport function euclidean(a, b) {\n return Math.sqrt(euclidean_squared(a, b));\n}\n","/**\n * Computes the Goodman-Kruskal gamma coefficient for ordinal association.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a - First categorical/ordinal variable\n * @param {number[] | Float64Array} b - Second categorical/ordinal variable\n * @returns {number} The Goodman-Kruskal gamma coefficient between `a` and `b` (-1 to 1).\n * @see {@link https://en.wikipedia.org/wiki/Goodman_and_Kruskal%27s_gamma}\n */\nexport function goodman_kruskal(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n if (n < 2) return 0;\n\n let concordant = 0;\n let discordant = 0;\n let tie_a = 0;\n let tie_b = 0;\n\n for (let i = 0; i < n; ++i) {\n for (let j = i + 1; j < n; ++j) {\n const a_diff = a[i] - a[j];\n const b_diff = b[i] - b[j];\n const a_tied = a_diff === 0;\n const b_tied = b_diff === 0;\n\n if (a_tied && b_tied) {\n } else if (a_tied) {\n tie_a++;\n } else if (b_tied) {\n tie_b++;\n } else if (a_diff * b_diff > 0) {\n concordant++;\n } else {\n discordant++;\n }\n }\n }\n\n const denominator = concordant + discordant + tie_a + tie_b;\n if (denominator === 0) return 0;\n\n const numerator = concordant + discordant;\n if (numerator === 0) return 0;\n\n return (concordant - discordant) / numerator;\n}\n","/**\n * Computes the hamming distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The hamming distance between `a` and `b`.\n */\nexport function hamming(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let disagree = 0;\n for (let i = 0; i < n; ++i) {\n const x = a[i];\n const y = b[i];\n disagree += x !== y ? 1 : 0;\n }\n return disagree / n;\n}\n","/**\n * Computes the Haversine distance between two points on a sphere of unit length 1. Multiply the result with the radius of the sphere. (For instance Earth's radius is 6371km)\n *\n * @category Metrics\n * @param {number[] | Float64Array} a - Point [lat1, lon1] in radians\n * @param {number[] | Float64Array} b - Point [lat2, lon2] in radians\n * @returns {number} The Haversine distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Haversine_formula}\n */\nexport function haversine(a, b) {\n if (a.length !== 2 || b.length !== 2)\n throw new Error(\"Haversine distance requires exactly 2 coordinates [lat, lon] for each point!\");\n const lat1 = a[0];\n const lon1 = a[1];\n const lat2 = b[0];\n const lon2 = b[1];\n\n const dlat = lat2 - lat1;\n const dlon = lon2 - lon1;\n\n const sin_dlat2 = Math.sin(dlat / 2);\n const sin_dlon2 = Math.sin(dlon / 2);\n\n const x = sin_dlat2 * sin_dlat2 + Math.cos(lat1) * Math.cos(lat2) * sin_dlon2 * sin_dlon2;\n const c = 2 * Math.atan2(Math.sqrt(x), Math.sqrt(1 - x));\n\n return c;\n}\n","/**\n * Computes the jaccard distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The jaccard distance between `a` and `b`.\n */\nexport function jaccard(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let num_non_zero = 0;\n let num_equal = 0;\n for (let i = 0; i < n; ++i) {\n const x = a[i] !== 0;\n const y = b[i] !== 0;\n num_non_zero += x || y ? 1 : 0;\n num_equal += x && y ? 1 : 0;\n }\n return (num_non_zero - num_equal) / num_non_zero;\n}\n","/**\n * Computes the manhattan distance (`l_1`) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The manhattan distance between `a` and `b`.\n */\nexport function manhattan(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let sum = 0;\n for (let i = 0; i < n; ++i) {\n sum += Math.abs(a[i] - b[i]);\n }\n return sum;\n}\n","/**\n * Computes the Sokal-Michener distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The Sokal-Michener distance between `a` and `b`.\n\n */\nexport function sokal_michener(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let num_not_equal = 0;\n for (let i = 0; i < n; ++i) {\n const x = a[i] !== 0;\n const y = b[i] !== 0;\n num_not_equal += x !== y ? 1 : 0;\n }\n return (2 * num_not_equal) / (n + num_not_equal);\n}\n","/**\n * Computes the 1D Wasserstein distance (Earth Mover's Distance) between two distributions.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a - First distribution (histogram or probability mass)\n * @param {number[] | Float64Array} b - Second distribution (histogram or probability mass)\n * @returns {number} The Wasserstein/EMD distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Wasserstein_metric}\n */\nexport function wasserstein(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let sumA = 0;\n let sumB = 0;\n for (let i = 0; i < n; i++) {\n sumA += a[i];\n sumB += b[i];\n }\n\n // Fallback if sums are 0\n if (sumA === 0 && sumB === 0) return 0;\n if (sumA === 0 || sumB === 0) return Infinity;\n\n let distance = 0;\n let cumA = 0;\n let cumB = 0;\n for (let i = 0; i < n; i++) {\n cumA += a[i] / sumA;\n cumB += b[i] / sumB;\n distance += Math.abs(cumA - cumB);\n }\n return distance;\n}\n","/**\n * Computes the yule distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The yule distance between `a` and `b`.\n */\nexport function yule(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let num_true_true = 0;\n let num_true_false = 0;\n let num_false_true = 0;\n for (let i = 0; i < n; ++i) {\n const x = a[i] !== 0;\n const y = b[i] !== 0;\n num_true_true += x && y ? 1 : 0;\n num_true_false += x && !y ? 1 : 0;\n num_false_true += !x && y ? 1 : 0;\n }\n const num_false_false = n - num_true_true - num_true_false - num_false_true;\n return num_true_false === 0 || num_false_true === 0\n ? 0\n : (2 * num_true_false * num_false_true) / (num_true_true * num_false_false + num_true_false * num_false_true);\n}\n","import { euclidean } from \"../metrics/index.js\";\nimport { Matrix } from \"./index.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n\n/**\n * @param {Matrix | Float64Array[] | number[][]} A\n * @returns {A is Matrix}\n */\nfunction isMatrix(A) {\n return A instanceof Matrix;\n}\n\n/**\n * Computes the distance matrix of datamatrix `A`.\n *\n * @category Matrix\n * @param {Matrix | Float64Array[] | number[][]} A - Matrix.\n * @param {Metric} [metric=euclidean] - The diistance metric. Default is `euclidean`\n * @returns {Matrix} The distance matrix of `A`.\n */\nexport function distance_matrix(A, metric = euclidean) {\n /** @type {number} */\n const n = isMatrix(A) ? A.shape[0] : A.length;\n const D = new Matrix(n, n);\n for (let i = 0; i < n; ++i) {\n const A_i = isMatrix(A) ? A.row(i) : A[i];\n for (let j = i + 1; j < n; ++j) {\n const dist = metric(A_i, isMatrix(A) ? A.row(j) : A[j]);\n D.set_entry(i, j, dist);\n D.set_entry(j, i, dist);\n }\n }\n return D;\n}\n","//@ts-check\n\nimport { distance_matrix, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n\n/**\n * Computes the k-nearest neighbors of each row of `A`.\n *\n * @category Matrix\n * @param {Matrix} A - Either the data matrix, or a distance matrix.\n * @param {number} k - The number of neighbors to compute.\n * @param {Metric | \"precomputed\"} [metric=euclidean] Default is `euclidean`\n * @returns {{ i: number; j: number; distance: number }[][]} The kNN graph.\n */\nexport function k_nearest_neighbors(A, k, metric = euclidean) {\n A = A instanceof Matrix ? A : Matrix.from(A);\n const rows = A.shape[0];\n const D = metric === \"precomputed\" ? A : distance_matrix(A, metric);\n /** @type {{ i: number; j: number; distance: number }[][]} */\n const nN = [];\n for (let row = 0; row < rows; ++row) {\n const res = Array.from(D.row(row))\n .map((distance, col) => {\n return {\n i: row,\n j: col,\n distance: distance,\n };\n })\n .sort((a, b) => a.distance - b.distance)\n .slice(1, k + 1);\n nN.push(res);\n }\n return nN;\n}\n","/**\n * Creates an Array containing `number` numbers from `start` to `end`. If `number = null`.\n *\n * @category Matrix\n * @param {number} start - Start value.\n * @param {number} end - End value.\n * @param {number} [number] - Number of number between `start` and `end`.\n * @returns {number[]} An array with `number` entries, beginning at `start` ending at `end`.\n */\nexport function linspace(start, end, number) {\n if (number === undefined || number === null) {\n number = Math.max(Math.round(end - start) + 1, 1);\n }\n if (number < 2) {\n return number === 1 ? [start] : [];\n }\n const result = new Array(number);\n number -= 1;\n for (let i = number; i >= 0; --i) {\n result[i] = (i * end + (number - i) * start) / number;\n }\n return result;\n}\n","/**\n * Computes the inner product between two arrays of the same length.\n *\n * @category Linear Algebra\n * @param {number[] | Float64Array} a - Array a.\n * @param {number[] | Float64Array} b - Array b.\n * @returns The inner product between `a` and `b`.\n */\nexport function inner_product(a, b) {\n const N = a.length;\n if (N !== b.length) {\n throw new Error(\"Array a and b must have the same length!\");\n }\n let sum = 0;\n for (let i = 0; i < N; ++i) {\n sum += a[i] * b[i];\n }\n return sum;\n}\n","/**\n * Numerical stable summation with the Kahan summation algorithm.\n *\n * @category Numerical\n * @param {number[] | Float64Array} summands - Array of values to sum up.\n * @returns {number} The sum.\n * @see {@link https://en.wikipedia.org/wiki/Kahan_summation_algorithm}\n */\nexport function kahan_sum(summands) {\n const n = summands.length;\n let sum = 0;\n let compensation = 0;\n let y, t;\n\n for (let i = 0; i < n; ++i) {\n y = summands[i] - compensation;\n t = sum + y;\n compensation = t - sum - y;\n sum = t;\n }\n return sum;\n}\n","/**\n * Numerical stable summation with the Neumair summation algorithm.\n *\n * @category Numerical\n * @param {number[] | Float64Array} summands - Array of values to sum up.\n * @returns {number} The sum.\n * @see {@link https://en.wikipedia.org/wiki/Kahan_summation_algorithm#Further_enhancements}\n */\nexport function neumair_sum(summands) {\n const n = summands.length;\n let sum = 0;\n let compensation = 0;\n\n for (let i = 0; i < n; ++i) {\n const summand = summands[i];\n const t = sum + summand;\n if (Math.abs(sum) >= Math.abs(summand)) {\n compensation += sum - t + summand;\n } else {\n compensation += summand - t + sum;\n }\n sum = t;\n }\n return sum + compensation;\n}\n","import { Matrix, norm } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { neumair_sum } from \"../numerical/index.js\";\n\n/**\n * Computes the QR Decomposition of the Matrix `A` using Gram-Schmidt process.\n *\n * @category Linear Algebra\n * @param {Matrix} A\n * @returns {{ R: Matrix; Q: Matrix }}\n * @see {@link https://en.wikipedia.org/wiki/QR_decomposition#Using_the_Gram%E2%80%93Schmidt_process}\n */\nexport function qr(A) {\n const [rows, cols] = A.shape;\n const Q = new Matrix(rows, cols, \"identity\");\n const R = new Matrix(cols, cols, 0);\n\n for (let j = 0; j < cols; ++j) {\n const v = A.col(j);\n for (let i = 0; i < j; ++i) {\n const q = Q.col(i);\n const q_dot_v = neumair_sum(q.map((q_, k) => q_ * v[k]));\n for (let k = 0; k < rows; ++k) {\n v[k] -= q_dot_v * q[k];\n }\n R.set_entry(i, j, q_dot_v);\n }\n const v_norm = norm(v, euclidean);\n for (let k = 0; k < rows; ++k) {\n Q.set_entry(k, j, v[k] / v_norm);\n }\n R.set_entry(j, j, v_norm);\n }\n return { R, Q };\n}\n","import { Matrix, norm } from \"../matrix/index.js\";\n\n/**\n * Computes the QR Decomposition of the Matrix `A` with householder transformations.\n *\n * @category Linear Algebra\n * @param {Matrix} A\n * @returns {{ R: Matrix; Q: Matrix }}\n * @see {@link https://en.wikipedia.org/wiki/QR_decomposition#Using_Householder_reflections}\n * @see {@link http://mlwiki.org/index.php/Householder_Transformation}\n */\nexport function qr_householder(A) {\n const [rows, cols] = A.shape;\n const Q = new Matrix(rows, rows, \"I\");\n const R = A.clone();\n\n for (let j = 0; j < cols; ++j) {\n const x = Matrix.from_vector(R.col(j).slice(j), \"row\");\n const x_norm = norm(x);\n const x0 = x.entry(0, 0);\n const rho = -Math.sign(x0);\n const u1 = x0 - rho * x_norm;\n const u = x.divide(u1).set_entry(0, 0, 1);\n const beta = (-rho * u1) / x_norm;\n\n const u_outer_u = u.outer(u);\n const R_block = R.get_block(j, 0);\n const new_R = R_block.sub(u_outer_u.dot(R_block).mult(beta));\n const Q_block = Q.get_block(0, j);\n const new_Q = Q_block.sub(Q_block.dot(u_outer_u).mult(beta));\n R.set_block(j, 0, new_R);\n Q.set_block(0, j, new_Q);\n }\n return { R, Q };\n}\n","/**\n * Returns maximum in Array `values`.\n *\n * @category Utils\n * @param {Iterable} values\n * @returns {number}\n */\nexport function max(values) {\n let max = -Infinity;\n for (const value of values) {\n if (value !== null && max < value) {\n max = value;\n }\n }\n return max;\n}\n","/**\n * Returns maximum in Array `values`.\n *\n * @category Utils\n * @param {Iterable} values\n * @returns {number}\n */\nexport function min(values) {\n let min = Infinity;\n for (const value of values) {\n if (value !== null && min > value) {\n min = value;\n }\n }\n return min;\n}\n","import { linspace } from \"../matrix/index.js\";\n\n/**\n * @category Utils\n * @class\n */\nexport class Randomizer {\n _N = 624;\n _M = 397;\n _MATRIX_A = 0x9908b0df;\n _UPPER_MASK = 0x80000000;\n _LOWER_MASK = 0x7fffffff;\n\n /** @type {number[]} */\n _mt;\n /** @type {number} */\n _mti;\n /** @type {number} */\n _seed;\n\n /**\n * Mersenne Twister random number generator.\n *\n * @param {number} [_seed=new Date().getTime()] - The seed for the random number generator. If `_seed == null` then\n * the actual time gets used as seed. Default is `new Date().getTime()`\n * @see https://github.com/bmurray7/mersenne-twister-examples/blob/master/javascript-mersenne-twister.js\n */\n constructor(_seed) {\n this._mt = new Array(this._N);\n this._mti = this._N + 1;\n this._seed = _seed ?? Date.now();\n this.seed = this._seed;\n }\n\n /** @type {number} seed */\n set seed(_seed) {\n this._seed = _seed;\n const mt = this._mt;\n\n mt[0] = _seed >>> 0;\n for (this._mti = 1; this._mti < this._N; this._mti += 1) {\n const mti = this._mti;\n const s = mt[mti - 1] ^ (mt[mti - 1] >>> 30);\n mt[mti] = ((((s & 0xffff0000) >>> 16) * 1812433253) << 16) + (s & 0x0000ffff) * 1812433253 + mti;\n mt[mti] >>>= 0;\n }\n }\n\n /**\n * Returns the seed of the random number generator.\n *\n * @returns {number} - The seed.\n */\n get seed() {\n return this._seed;\n }\n\n /**\n * Returns a float between 0 and 1.\n *\n * @returns {number} - A random number between [0, 1]\n */\n get random() {\n return this.random_int * (1.0 / 4294967296.0);\n }\n\n /**\n * Returns an integer between 0 and MAX_INTEGER.\n *\n * @returns {number} - A random integer.\n */\n get random_int() {\n let y,\n mag01 = [0x0, this._MATRIX_A];\n if (this._mti >= this._N) {\n let kk;\n\n /* if (this._mti == this._N + 1) {\n this.seed = 5489;\n } */\n\n const N_M = this._N - this._M;\n const M_N = this._M - this._N;\n\n for (kk = 0; kk < N_M; ++kk) {\n y = (this._mt[kk] & this._UPPER_MASK) | (this._mt[kk + 1] & this._LOWER_MASK);\n this._mt[kk] = this._mt[kk + this._M] ^ (y >>> 1) ^ mag01[y & 0x1];\n }\n for (; kk < this._N - 1; ++kk) {\n y = (this._mt[kk] & this._UPPER_MASK) | (this._mt[kk + 1] & this._LOWER_MASK);\n this._mt[kk] = this._mt[kk + M_N] ^ (y >>> 1) ^ mag01[y & 0x1];\n }\n\n y = (this._mt[this._N - 1] & this._UPPER_MASK) | (this._mt[0] & this._LOWER_MASK);\n this._mt[this._N - 1] = this._mt[this._M - 1] ^ (y >>> 1) ^ mag01[y & 0x1];\n\n this._mti = 0;\n }\n this._mti += 1;\n y = this._mt[this._mti];\n y ^= y >>> 11;\n y ^= (y << 7) & 0x9d2c5680;\n y ^= (y << 15) & 0xefc60000;\n y ^= y >>> 18;\n\n return y >>> 0;\n }\n\n gauss_random() {\n let x, y, r;\n if (this._val != null) {\n x = this._val;\n this._val = null;\n return x;\n } else\n do {\n x = 2 * this.random - 1;\n y = 2 * this.random - 1;\n r = x * x + y * y;\n } while (!r || r > 1);\n const c = Math.sqrt((-2 * Math.log(r)) / r);\n this._val = y * c; // cache this for next function call for efficiency\n return x * c;\n }\n\n /**\n * @template T Returns samples from an input Matrix or Array.\n * @param {T[]} A - The input Matrix or Array.\n * @param {number} n - The number of samples.\n * @returns {T[]} A random selection form `A` of `n` samples.\n */\n choice(A, n) {\n if (!Array.isArray(A)) throw new Error(\"A must be an Array!\");\n // if (A instanceof Matrix) {\n // let rows = A.shape[0];\n // if (n > rows) {\n // throw new Error(\"n bigger than A!\");\n // }\n // /** @type {number[]} */\n // let sample = new Array(n);\n // let index_list = linspace(0, rows - 1);\n // for (let i = 0, l = index_list.length; i < n; ++i, --l) {\n // let random_index = this.random_int % l;\n // sample[i] = index_list.splice(random_index, 1)[0];\n // }\n // return sample.map((d) => A.row(d));\n // } else if (Array.isArray(A) || A instanceof Float64Array) {\n const rows = A.length;\n if (n > rows) {\n throw new Error(\"n bigger than A!\");\n }\n const sample = new Array(n);\n const index_list = linspace(0, rows - 1);\n for (let i = 0, l = index_list.length; i < n; ++i, --l) {\n const random_index = this.random_int % l;\n sample[i] = index_list.splice(random_index, 1)[0];\n }\n return sample.map((d) => A[d]);\n //} else {\n //throw new Error(\"A must be of type Matrix or Float64Array or number[]!\");\n // }\n }\n\n /**\n * @template T Returns samples from an input Matrix or Array.\n * @param {T[]} A - The input Matrix or Array.\n * @param {number} n - The number of samples.\n * @param {number} seed - The seed for the random number generator.\n * @returns {T[]} - A random selection form `A` of `n` samples.\n */\n static choice(A, n, seed = 1212) {\n const R = new Randomizer(seed);\n return R.choice(A, n);\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { euclidean_squared } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { qr as qr_gramschmidt } from \"./index.js\";\n\n/** @import { EigenArgs } from \"./index.js\" */\n\n/**\n * Computes the `k` biggest Eigenvectors and Eigenvalues from Matrix `A` with the QR-Algorithm.\n *\n * @category Linear Algebra\n * @param {Matrix} A - The Matrix\n * @param {number} k - The number of eigenvectors and eigenvalues to compute.\n * @param {EigenArgs} parameters - Object containing parameterization of the simultanious\n * poweriteration method.\n * @returns {{ eigenvalues: Float64Array; eigenvectors: Float64Array[] }} The `k` biggest eigenvectors and eigenvalues\n * of Matrix `A`.\n */\nexport function simultaneous_poweriteration(\n A,\n k = 2,\n { seed = 1212, max_iterations = 100, qr = qr_gramschmidt, tol = 1e-8 } = {},\n) {\n const randomizer = seed instanceof Randomizer ? seed : new Randomizer(seed);\n if (!(A instanceof Matrix)) A = Matrix.from(A);\n const n = A.shape[0];\n let { Q, R } = qr(new Matrix(n, k, () => (randomizer.random - 0.5) * 2));\n while (max_iterations--) {\n const oldQ = Q;\n const Z = A.dot(Q);\n const QR = qr(Z);\n Q = QR.Q;\n R = QR.R;\n const error = euclidean_squared(Q.values, oldQ.values);\n if (error < tol) {\n break;\n }\n }\n\n const eigenvalues = R.diag();\n const eigenvectors = Q.transpose().to2dArray();\n return { eigenvalues, eigenvectors };\n}\n","import { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { neumair_sum } from \"../numerical/index.js\";\nimport { Randomizer } from \"../util/index.js\";\n\n/** @typedef {(i: number, j: number) => number} Accessor */\n\n/**\n * @class\n * @category Matrix\n */\nexport class Matrix {\n /**\n * Creates a new Matrix. Entries are stored in a Float64Array.\n *\n * @example let A = new Matrix(10, 10, () => Math.random()); //creates a 10 times 10 random matrix. let B = new\n * Matrix(3, 3, \"I\"); // creates a 3 times 3 identity matrix.\n *\n * @param {number} rows - The amount of rows of the matrix.\n * @param {number} cols - The amount of columns of the matrix.\n * @param {Accessor | string | number} value - Can be a function with row and col as parameters, a number, or\n * \"zeros\", \"identity\" or \"I\", or \"center\".\n *\n * - **function**: for each entry the function gets called with the parameters for the actual row and column.\n * - **string**: allowed are\n *\n * - \"zero\", creates a zero matrix.\n * - \"identity\" or \"I\", creates an identity matrix.\n * - \"center\", creates an center matrix.\n * - **number**: create a matrix filled with the given value.\n */\n constructor(rows, cols, value = 0) {\n /** @type {number} */ this._rows = rows;\n /** @type {number} */ this._cols = cols;\n /** @type {Float64Array} */ this._data;\n\n if (rows && cols) {\n if (!value) {\n this._data = new Float64Array(rows * cols);\n }\n if (typeof value === \"function\") {\n this._data = new Float64Array(rows * cols);\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col) {\n this._data[row * cols + col] = value(row, col);\n }\n }\n }\n if (typeof value === \"string\") {\n if (value === \"zeros\") {\n this._data = new Float64Array(rows * cols);\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col) {\n this._data[row * cols + col] = 0;\n }\n }\n }\n if (value === \"identity\" || value === \"I\") {\n this._data = new Float64Array(rows * cols);\n for (let row = 0; row < rows; ++row) {\n this._data[row * cols + row] = 1;\n }\n }\n if (value === \"center\" && rows === cols) {\n this._data = new Float64Array(rows * cols);\n value = (i, j) => (i === j ? 1 : 0) - 1 / rows;\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col) {\n this._data[row * cols + col] = value(row, col);\n }\n }\n }\n }\n if (typeof value === \"number\") {\n this._data = new Float64Array(rows * cols);\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col) {\n this._data[row * cols + col] = value;\n }\n }\n }\n if (Array.isArray(value)) {\n this._data = new Float64Array(rows * cols);\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col) {\n this._data[row * cols + col] = value[row][col];\n }\n }\n }\n }\n }\n\n /**\n * Creates a Matrix out of `A`.\n * @param {Matrix | Float64Array[] | number[][]} A - The matrix, array, or number, which should converted to a Matrix.\n * @returns {Matrix}\n * @example\n * let A = Matrix.from([ [1, 0], [0, 1], ]); //creates a two by two identity matrix.\n */\n static from(A) {\n if (A instanceof Matrix) {\n return A.clone();\n }\n if (Matrix.is2dArray(A)) {\n const m = A.length;\n const n = A[0].length;\n for (let row = 0; row < m; ++row) {\n if (A[row].length !== n) {\n throw new Error(\"various array lengths\");\n }\n }\n return new Matrix(m, n, (i, j) => A[i][j]);\n }\n throw new Error(\"error\");\n }\n\n /**\n * Creates a Matrix with the diagonal being the values of `v`.\n *\n * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]]\n *\n * @param {number[] | Float64Array} v\n * @returns {Matrix}\n */\n static from_diag(v) {\n const N = v.length;\n return new Matrix(N, N, (i, j) => (i === j ? v[i] : 0));\n }\n\n /**\n * Creates a Matrix with the diagonal being the values of `v`.\n *\n * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]]\n *\n * @param {number[] | Float64Array} v\n * @param {\"col\" | \"row\"} type\n * @returns {Matrix}\n */\n static from_vector(v, type) {\n const N = v.length;\n if (type === \"col\") {\n return new Matrix(N, 1, (i, _) => v[i]);\n } else {\n return new Matrix(1, N, (_, j) => v[j]);\n }\n }\n\n /**\n * Returns the `row`th row from the Matrix.\n *\n * @param {number} row\n * @returns {Float64Array}\n */\n row(row) {\n const data = this.values;\n const cols = this._cols;\n return data.subarray(row * cols, (row + 1) * cols);\n }\n\n /**\n * Returns an generator yielding each row of the Matrix.\n *\n * @yields {Float64Array}\n */\n *iterate_rows() {\n const cols = this._cols;\n const rows = this._rows;\n const data = this.values;\n for (let row = 0; row < rows; ++row) {\n yield data.subarray(row * cols, (row + 1) * cols);\n }\n }\n\n /**\n * Makes a `Matrix` object an iterable object.\n *\n * @yields {Float64Array}\n */\n *[Symbol.iterator]() {\n for (const row of this.iterate_rows()) {\n yield row;\n }\n }\n\n /**\n * Sets the entries of `row`th row from the Matrix to the entries from `values`.\n *\n * @param {number} row\n * @param {number[]} values\n * @returns {Matrix}\n */\n set_row(row, values) {\n const cols = this._cols;\n if (Matrix.isArray(values) && values.length === cols) {\n const offset = row * cols;\n for (let col = 0; col < cols; ++col) {\n this.values[offset + col] = values[col];\n }\n } else if (values instanceof Matrix && values.shape[1] === cols && values.shape[0] === 1) {\n const offset = row * cols;\n for (let col = 0; col < cols; ++col) {\n this.values[offset + col] = values._data[col];\n }\n } else {\n throw new Error(\"Values not valid! Needs to be either an Array, a Float64Array, or a fitting Matrix!\");\n }\n return this;\n }\n\n /**\n * Swaps the rows `row1` and `row2` of the Matrix.\n *\n * @param {number} row1\n * @param {number} row2\n * @returns {Matrix}\n */\n swap_rows(row1, row2) {\n const cols = this._cols;\n const data = this.values;\n for (let i = row1 * cols, j = row2 * cols, col = 0; col < cols; ++col, ++i, ++j) {\n const t = data[i];\n data[i] = data[j];\n data[j] = t;\n }\n return this;\n }\n\n /**\n * Returns the colth column from the Matrix.\n *\n * @param {number} col\n * @returns {Float64Array}\n */\n col(col) {\n const result_col = new Float64Array(this._rows);\n for (let row = 0; row < this._rows; ++row) {\n result_col[row] = this.values[row * this._cols + col];\n }\n return result_col;\n }\n\n /**\n * Returns the `col`th entry from the `row`th row of the Matrix.\n *\n * @param {number} row\n * @param {number} col\n * @returns {number}\n */\n entry(row, col) {\n return this.values[row * this._cols + col];\n }\n\n /**\n * Sets the {@link col}th entry from the {@link row}th row of the Matrix to the given\n * {@link value}.\n *\n * @param {number} row\n * @param {number} col\n * @param {number} value\n * @returns {Matrix}\n */\n set_entry(row, col, value) {\n this.values[row * this._cols + col] = value;\n return this;\n }\n\n /**\n * Adds a given {@link value} to the {@link col}th entry from the {@link row}th row of the\n * Matrix.\n *\n * @param {number} row\n * @param {number} col\n * @param {number} value\n * @returns {Matrix}\n */\n add_entry(row, col, value) {\n this.values[row * this._cols + col] += value;\n return this;\n }\n\n /**\n * Subtracts a given {@link value} from the {@link col}th entry from the {@link row}th row of the\n * Matrix.\n *\n * @param {number} row\n * @param {number} col\n * @param {number} value\n * @returns {Matrix}\n */\n sub_entry(row, col, value) {\n this.values[row * this._cols + col] -= value;\n return this;\n }\n\n /**\n * Returns a new transposed Matrix.\n *\n * @returns {Matrix}\n */\n transpose() {\n const B = new Matrix(this._cols, this._rows, (row, col) => this.entry(col, row));\n return B;\n }\n\n /**\n * Returns a new transposed Matrix. Short-form of `transpose`.\n *\n * @returns {Matrix}\n */\n get T() {\n return this.transpose();\n }\n\n /**\n * Returns the inverse of the Matrix.\n *\n * @returns {Matrix}\n */\n inverse() {\n const rows = this._rows;\n const cols = this._cols;\n const A = this.clone();\n const B = new Matrix(rows, cols, \"I\");\n\n // foreach column\n for (let col = 0; col < cols; ++col) {\n // Search for maximum in this column (pivot)\n let max_idx = col;\n let max_val = Math.abs(A.entry(col, col));\n for (let row = col + 1; row < rows; ++row) {\n const val = Math.abs(A.entry(row, col));\n if (max_val < val) {\n max_idx = row;\n max_val = val;\n }\n }\n if (max_val === 0) {\n throw new Error(\"Cannot compute inverse of Matrix, determinant is zero\");\n }\n // Swap maximum row with current row\n if (max_idx !== col) {\n A.swap_rows(col, max_idx);\n B.swap_rows(col, max_idx);\n }\n\n // eliminate non-zero values on the other rows at column c\n const A_col = A.row(col);\n const B_col = B.row(col);\n for (let row = 0; row < rows; ++row) {\n if (row !== col) {\n // eliminate value at column c and row r\n const A_row = A.row(row);\n const B_row = B.row(row);\n if (A_row[col] !== 0) {\n const f = A_row[col] / A_col[col];\n // sub (f * row c) from row r to eliminate the value at column c\n for (let s = col; s < cols; ++s) {\n A_row[s] -= f * A_col[s];\n }\n for (let s = 0; s < cols; ++s) {\n B_row[s] -= f * B_col[s];\n }\n }\n } else {\n // normalize value at Acc to 1 (diagonal):\n // divide each value of row r=c by the value at Acc\n const f = A_col[col];\n for (let s = col; s < cols; ++s) {\n A_col[s] /= f;\n }\n for (let s = 0; s < cols; ++s) {\n B_col[s] /= f;\n }\n }\n }\n }\n return B;\n }\n\n /**\n * Returns the dot product. If `B` is an Array or Float64Array then an Array gets returned. If `B` is a Matrix then\n * a Matrix gets returned.\n *\n * @param {Matrix | number[] | Float64Array} B The right side\n * @returns {Matrix}\n */\n dot(B) {\n if (B instanceof Matrix) {\n const [rows_A, cols_A] = this.shape;\n const [rows_B, cols_B] = B.shape;\n if (cols_A !== rows_B) {\n throw new Error(`A.dot(B): A is a ${this.shape.join(\" ⨯ \")}-Matrix, B is a ${B.shape.join(\" ⨯ \")}-Matrix:\n A has ${cols_A} cols and B ${rows_B} rows.\n Must be equal!`);\n }\n const C = new Matrix(rows_A, cols_B, 0);\n const A_val = this.values;\n const B_val = B.values;\n const C_val = C.values;\n\n for (let i = 0; i < rows_A; ++i) {\n const i_cols_A = i * cols_A;\n const i_cols_B = i * cols_B;\n for (let k = 0; k < cols_A; ++k) {\n const aik = A_val[i_cols_A + k];\n if (aik === 0) continue;\n const k_cols_B = k * cols_B;\n for (let j = 0; j < cols_B; ++j) {\n C_val[i_cols_B + j] += aik * B_val[k_cols_B + j];\n }\n }\n }\n return C;\n } else if (Matrix.isArray(B)) {\n // TODO: create Matrix directly\n const rows = this._rows;\n if (B.length !== rows) {\n throw new Error(`A.dot(B): A has ${rows} cols and B has ${B.length} rows. Must be equal!`);\n }\n const C = new Array(rows);\n for (let row = 0; row < rows; ++row) {\n C[row] = neumair_sum(this.row(row).map((e) => e * B[row]));\n }\n return Matrix.from(C);\n } else {\n throw new Error(`B must be Matrix or Array`);\n }\n }\n\n /**\n * Transposes the current matrix and returns the dot product with `B`. If `B` is an Array or Float64Array then an\n * Array gets returned. If `B` is a Matrix then a Matrix gets returned.\n *\n * @param {Matrix | number[] | Float64Array} B The right side\n * @returns {Matrix}\n */\n transDot(B) {\n if (B instanceof Matrix) {\n const [cols_A, rows_A] = this.shape; // transpose matrix\n const [rows_B, cols_B] = B.shape;\n if (cols_A !== rows_B) {\n throw new Error(`A.dot(B): A is a ${[rows_A, cols_A].join(\" ⨯ \")}-Matrix, B is a ${B.shape.join(\" ⨯ \")}-Matrix:\n A has ${cols_A} cols and B ${rows_B} rows, which must be equal!`);\n }\n // let B = new Matrix(this._cols, this._rows, (row, col) => this.entry(col, row));\n // this.values[row * this._cols + col];\n const C = new Matrix(rows_A, cols_B, 0);\n const A_val = this.values; // A is rows_B x rows_A (transposed)\n const B_val = B.values;\n const C_val = C.values;\n\n for (let k = 0; k < cols_A; ++k) {\n // cols_A is rows_B\n const k_rows_A = k * rows_A;\n const k_cols_B = k * cols_B;\n for (let i = 0; i < rows_A; ++i) {\n const aki = A_val[k_rows_A + i];\n if (aki === 0) continue;\n for (let j = 0; j < cols_B; ++j) {\n C_val[i * cols_B + j] += aki * B_val[k_cols_B + j];\n }\n }\n }\n return C;\n } else if (Matrix.isArray(B)) {\n // TODO: create Matrix directly\n const rows = this._cols;\n if (B.length !== rows) {\n throw new Error(`A.dot(B): A has ${rows} cols and B has ${B.length} rows. Must be equal!`);\n }\n const C = new Array(rows);\n for (let row = 0; row < rows; ++row) {\n C[row] = neumair_sum(this.col(row).map((e) => e * B[row]));\n }\n return Matrix.from(C);\n } else {\n throw new Error(`B must be Matrix or Array`);\n }\n }\n\n /**\n * Returns the dot product with the transposed version of `B`. If `B` is an Array or Float64Array then an Array gets\n * returned. If `B` is a Matrix then a Matrix gets returned.\n *\n * @param {Matrix | number[] | Float64Array} B The right side\n * @returns {Matrix}\n */\n dotTrans(B) {\n if (B instanceof Matrix) {\n const [rows_A, cols_A] = this.shape;\n const [cols_B, rows_B] = B.shape;\n if (cols_A !== rows_B) {\n throw new Error(`A.dot(B): A is a ${this.shape.join(\" ⨯ \")}-Matrix, B is a ${[rows_B, cols_B].join(\" ⨯ \")}-Matrix:\n A has ${cols_A} cols and B ${rows_B} rows, which must be equal!`);\n }\n const C = new Matrix(rows_A, cols_B, (row, col) => {\n const A_i = this.row(row);\n const B_i = B.row(col);\n let sum = 0;\n for (let i = 0; i < cols_A; ++i) {\n sum += A_i[i] * B_i[i];\n }\n return sum;\n });\n return C;\n } else if (Matrix.isArray(B)) {\n // TODO: create Matrix directly\n const rows = this._rows;\n if (B.length !== rows) {\n throw new Error(`A.dot(B): A has ${rows} cols and B has ${B.length} rows. Must be equal!`);\n }\n const C = new Array(rows);\n for (let row = 0; row < rows; ++row) {\n C[row] = neumair_sum(this.row(row).map((e) => e * B[row]));\n }\n return Matrix.from(C);\n } else {\n throw new Error(`B must be Matrix or Array`);\n }\n }\n\n /**\n * Computes the outer product from `this` and `B`.\n *\n * @param {Matrix} B\n * @returns {Matrix}\n */\n outer(B) {\n const l = this._data.length;\n const r = B._data.length;\n if (l !== r) throw new Error(\"Matrix A and B needs to be of the same length!\");\n const C = new Matrix(\n l,\n l,\n /** @type {Accessor} */ (i, j) => {\n if (i <= j) {\n return this._data[i] * B._data[j];\n } else {\n return this.entry(j, i);\n }\n },\n );\n\n return C;\n }\n\n /**\n * Appends matrix `B` to the matrix.\n *\n * @example let A = Matrix.from([ [1, 1], [1, 1], ]); // 2 by 2 matrix filled with ones. let B = Matrix.from([ [2,\n * 2], [2, 2], ]); // 2 by 2 matrix filled with twos.\n *\n * A.concat(B, \"horizontal\"); // 2 by 4 matrix. [[1, 1, 2, 2], [1, 1, 2, 2]]\n * A.concat(B, \"vertical\"); // 4 by 2 matrix. [[1, 1], [1, 1], [2, 2], [2, 2]]\n * A.concat(B, \"diag\"); // 4 by 4 matrix. [[1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 2, 2], [0, 0, 2, 2]]\n *\n * @param {Matrix} B - Matrix to append.\n * @param {\"horizontal\" | \"vertical\" | \"diag\"} [type=\"horizontal\"] - Type of concatenation. Default is\n * `\"horizontal\"`\n * @returns {Matrix}\n */\n concat(B, type = \"horizontal\") {\n const [rows_A, cols_A] = this.shape;\n const [rows_B, cols_B] = B.shape;\n if (type === \"horizontal\") {\n if (rows_A !== rows_B) {\n throw new Error(\n `A.concat(B, \"horizontal\"): A and B need same number of rows, A has ${rows_A} rows, B has ${rows_B} rows.`,\n );\n }\n const X = new Matrix(rows_A, cols_A + cols_B, \"zeros\");\n X.set_block(0, 0, this);\n X.set_block(0, cols_A, B);\n return X;\n } else if (type === \"vertical\") {\n if (cols_A !== cols_B) {\n throw new Error(\n `A.concat(B, \"vertical\"): A and B need same number of columns, A has ${cols_A} columns, B has ${cols_B} columns.`,\n );\n }\n const X = new Matrix(rows_A + rows_B, cols_A, \"zeros\");\n X.set_block(0, 0, this);\n X.set_block(rows_A, 0, B);\n return X;\n } else if (type === \"diag\") {\n const X = new Matrix(rows_A + rows_B, cols_A + cols_B, \"zeros\");\n X.set_block(0, 0, this);\n X.set_block(rows_A, cols_A, B);\n return X;\n } else {\n throw new Error(`type must be \"horizontal\" or \"vertical\", but type is ${type}!`);\n }\n }\n\n /**\n * Writes the entries of B in A at an offset position given by `offset_row` and `offset_col`.\n *\n * @param {number} offset_row\n * @param {number} offset_col\n * @param {Matrix} B\n * @returns {Matrix}\n */\n set_block(offset_row, offset_col, B) {\n const rows = Math.min(this._rows - offset_row, B.shape[0]);\n const cols = Math.min(this._cols - offset_col, B.shape[1]);\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col) {\n this.set_entry(row + offset_row, col + offset_col, B.entry(row, col));\n }\n }\n return this;\n }\n\n /**\n * Extracts the entries from the `start_row`th row to the `end_row`th row, the\n * `start_col`th column to the `end_col`th column of the matrix. If `end_row` or `end_col` is\n * empty, the respective value is set to `this.rows` or `this.cols`.\n *\n * @example let A = Matrix.from([ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]); // a 3 by 3 matrix.\n *\n * A.get_block(1, 1); // [[5, 6], [8, 9]]\n * A.get_block(0, 0, 1, 1); // [[1]]\n * A.get_block(1, 1, 2, 2); // [[5]]\n * A.get_block(0, 0, 2, 2); // [[1, 2], [4, 5]]\n *\n * @param {number} start_row\n * @param {number} start_col\n * @param {number | null} [end_row]\n * @param {number | null} [end_col]\n * @returns {Matrix} Returns a `end_row` - `start_row` times `end_col` - `start_col` matrix, with respective entries\n * from the matrix.\n */\n get_block(start_row, start_col, end_row, end_col) {\n const [rows, cols] = this.shape;\n end_row = end_row ?? rows;\n end_col = end_col ?? cols;\n if (end_row <= start_row || end_col <= start_col) {\n throw new Error(`\n end_row must be greater than start_row, and\n end_col must be greater than start_col, but\n end_row = ${end_row}, start_row = ${start_row}, end_col = ${end_col}, and start_col = ${start_col}!`);\n }\n const X = new Matrix(end_row - start_row, end_col - start_col, \"zeros\");\n for (let row = start_row, new_row = 0; row < end_row; ++row, ++new_row) {\n for (let col = start_col, new_col = 0; col < end_col; ++col, ++new_col) {\n X.set_entry(new_row, new_col, this.entry(row, col));\n }\n }\n return X;\n }\n\n /**\n * Returns a new array gathering entries defined by the indices given by argument.\n *\n * @param {number[]} row_indices - Array consists of indices of rows for gathering entries of this matrix\n * @param {number[]} col_indices - Array consists of indices of cols for gathering entries of this matrix\n * @returns {Matrix}\n */\n gather(row_indices, col_indices) {\n const N = row_indices.length;\n const D = col_indices.length;\n\n const R = new Matrix(N, D);\n for (let i = 0; i < N; ++i) {\n const row_index = row_indices[i];\n for (let j = 0; j < D; ++j) {\n const col_index = col_indices[j];\n R.set_entry(i, j, this.entry(row_index, col_index));\n }\n }\n\n return R;\n }\n\n /**\n * Applies a function to each entry of the matrix.\n *\n * @private\n * @param {(d: number, v: number) => number} f Function takes 2 parameters, the value of the actual entry and a\n * value given by the function `v`. The result of `f` gets writen to the Matrix.\n * @param {Accessor} v Function takes 2 parameters for `row` and `col`, and returns a value witch should be applied\n * to the `col`th entry of the `row`th row of the matrix.\n * @returns {Matrix}\n */\n _apply_array(f, v) {\n const data = this.values;\n const [rows, cols] = this.shape;\n for (let i = 0, row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col, ++i) {\n data[i] = f(data[i], v(row, col));\n }\n }\n return this;\n }\n\n /**\n * @param {number[] | Float64Array} values\n * @param {(d: number, v: number) => number} f\n * @returns {Matrix}\n */\n _apply_rowwise_array(values, f) {\n return this._apply_array(f, (_, j) => values[j]);\n }\n /**\n * @param {number[] | Float64Array} values\n * @param {(d: number, v: number) => number} f\n * @returns {Matrix}\n */\n _apply_colwise_array(values, f) {\n const data = this.values;\n const [rows, cols] = this.shape;\n for (let i = 0, row = 0; row < rows; ++row) {\n const val = values[row];\n for (let col = 0; col < cols; ++col, ++i) {\n data[i] = f(data[i], val);\n }\n }\n return this;\n }\n\n /**\n * @param {Matrix | number[] | Float64Array | number} value\n * @param {(d: number, v: number) => number} f\n * @returns {Matrix}\n */\n _apply(value, f) {\n const data = this.values;\n const [rows, cols] = this.shape;\n if (value instanceof Matrix) {\n const values = value.values;\n const [value_rows, value_cols] = value.shape;\n if (value_rows === 1) {\n if (cols !== value_cols) {\n throw new Error(`cols !== value_cols`);\n }\n for (let i = 0, row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col, ++i) {\n data[i] = f(data[i], values[col]);\n }\n }\n } else if (value_cols === 1) {\n if (rows !== value_rows) {\n throw new Error(`rows !== value_rows`);\n }\n for (let i = 0, row = 0; row < rows; ++row) {\n const v = values[row];\n for (let col = 0; col < cols; ++col, ++i) {\n data[i] = f(data[i], v);\n }\n }\n } else if (rows === value_rows && cols === value_cols) {\n for (let i = 0, n = rows * cols; i < n; ++i) {\n data[i] = f(data[i], values[i]);\n }\n } else {\n throw new Error(`error`);\n }\n } else if (Matrix.isArray(value)) {\n if (value.length === rows) {\n for (let i = 0, row = 0; row < rows; ++row) {\n const v = value[row];\n for (let col = 0; col < cols; ++col, ++i) {\n data[i] = f(data[i], v);\n }\n }\n } else if (value.length === cols) {\n for (let i = 0, row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col, ++i) {\n data[i] = f(data[i], value[col]);\n }\n }\n } else {\n throw new Error(`error`);\n }\n } else {\n // scalar value\n for (let i = 0, n = rows * cols; i < n; ++i) {\n data[i] = f(data[i], value);\n }\n }\n return this;\n }\n\n /**\n * Clones the Matrix.\n *\n * @returns {Matrix}\n */\n clone() {\n const B = new Matrix(this._rows, this._cols);\n //B._rows = this._rows;\n //B._cols = this._cols;\n if (this._data) {\n B._data = this._data.slice(0);\n }\n return B;\n }\n\n /**\n * Entrywise multiplication with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.mult(2); // [[2, 4], [6, 8]];\n * A.mult(B); // [[1, 4], [9, 16]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {boolean} [options.inline=false] - If true, applies multiplication to the element, otherwise it creates\n * first a copy and applies the multiplication on the copy. Default is `false`\n * @returns {Matrix}\n */\n mult(value, { inline = false } = {}) {\n const A = inline ? this : this.clone();\n return A._apply(value, (a, b) => a * b);\n }\n\n /**\n * Entrywise division with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.divide(2); // [[0.5, 1], [1.5, 2]];\n * A.divide(B); // [[1, 1], [1, 1]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {Boolean} [options.inline=false] - If true, applies division to the element, otherwise it creates first a\n * copy and applies the division on the copy. Default is `false`\n * @returns {Matrix}\n */\n divide(value, { inline = false } = {}) {\n const A = inline ? this : this.clone();\n return A._apply(value, (a, b) => a / b);\n }\n\n /**\n * Entrywise addition with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.add(2); // [[3, 4], [5, 6]];\n * A.add(B); // [[2, 4], [6, 8]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {boolean} [options.inline=false] - If true, applies addition to the element, otherwise it creates first a\n * copy and applies the addition on the copy. Default is `false`\n * @returns {Matrix}\n */\n add(value, { inline = false } = {}) {\n const A = inline ? this : this.clone();\n return A._apply(value, (a, b) => a + b);\n }\n\n /**\n * Entrywise subtraction with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.sub(2); // [[-1, 0], [1, 2]];\n * A.sub(B); // [[0, 0], [0, 0]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {boolean} [options.inline=false] - If true, applies subtraction to the element, otherwise it creates first\n * a copy and applies the subtraction on the copy. Default is `false`\n * @returns {Matrix}\n */\n sub(value, { inline = false } = {}) {\n const A = inline ? this : this.clone();\n return A._apply(value, (a, b) => a - b);\n }\n\n /**\n * Returns the number of rows and columns of the Matrix.\n *\n * @returns {number[]} An Array in the form [rows, columns].\n */\n get shape() {\n return [this._rows, this._cols];\n }\n\n /**\n * Returns the matrix in the given shape with the given function which returns values for the entries of the matrix.\n *\n * @param {[number, number, Accessor]} parameter - Takes an Array in the form [rows, cols, value], where rows and\n * cols are the number of rows and columns of the matrix, and value is a function which takes two parameters (row\n * and col) which has to return a value for the colth entry of the rowth row.\n * @returns {Matrix}\n */\n set shape([rows, cols, value = () => 0]) {\n this._rows = rows;\n this._cols = cols;\n this._data = new Float64Array(rows * cols);\n for (let i = 0, row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col, ++i) {\n this._data[i] = value(row, col);\n }\n }\n }\n\n /**\n * Returns the Matrix as a Array of Float64Arrays.\n *\n * @returns {Float64Array[]}\n */\n to2dArray() {\n const result = [];\n for (const row of this.iterate_rows()) {\n result.push(row);\n }\n return result;\n }\n\n /**\n * Returns the Matrix as a Array of Arrays.\n *\n * @returns {number[][]}\n */\n asArray() {\n const result = [];\n for (const row of this.iterate_rows()) {\n result.push(Array.from(row));\n }\n return result;\n }\n\n /**\n * Returns the diagonal of the Matrix.\n *\n * @returns {Float64Array}\n */\n diag() {\n const rows = this._rows;\n const cols = this._cols;\n const min_row_col = Math.min(rows, cols);\n const result = new Float64Array(min_row_col);\n for (let i = 0; i < min_row_col; ++i) {\n result[i] = this.entry(i, i);\n }\n return result;\n }\n\n /**\n * Returns the mean of all entries of the Matrix.\n *\n * @returns {number}\n */\n mean() {\n const sum = this.sum();\n const n = this._rows * this._cols;\n return sum / n;\n }\n\n /**\n * Returns the sum oof all entries of the Matrix.\n *\n * @returns {number}\n */\n sum() {\n const data = this.values;\n return neumair_sum(data);\n }\n\n /**\n * Returns the entries of the Matrix.\n *\n * @returns {Float64Array}\n */\n get values() {\n const data = this._data;\n return data;\n }\n\n /**\n * Returns the mean of each row of the matrix.\n *\n * @returns {Float64Array}\n */\n meanRows() {\n const data = this.values;\n const rows = this._rows;\n const cols = this._cols;\n const result = Float64Array.from({ length: rows });\n for (let i = 0, row = 0; row < rows; ++row) {\n let sum = 0;\n for (let col = 0; col < cols; ++col, ++i) {\n sum += data[i];\n }\n result[row] = sum / cols;\n }\n return result;\n }\n\n /**\n * Returns the mean of each column of the matrix.\n *\n * @returns {Float64Array}\n */\n meanCols() {\n const data = this.values;\n const rows = this._rows;\n const cols = this._cols;\n const result = Float64Array.from({ length: cols });\n for (let col = 0; col < cols; ++col) {\n let sum = 0;\n for (let i = col, row = 0; row < rows; ++row, i += cols) {\n sum += data[i];\n }\n result[col] = sum / rows;\n }\n return result;\n }\n\n /**\n * Solves the equation `Ax = b` using the conjugate gradient method. Returns the result `x`.\n *\n * @param {Matrix} A - Matrix\n * @param {Matrix} b - Matrix\n * @param {Randomizer | null} [randomizer]\n * @param {number} [tol=1e-3] Default is `1e-3`\n * @returns {Matrix}\n */\n static solve_CG(A, b, randomizer, tol = 1e-3) {\n if (!randomizer) {\n randomizer = new Randomizer();\n }\n const rows = A.shape[0];\n const cols = b.shape[1];\n let result = new Matrix(rows, 0);\n for (let i = 0; i < cols; ++i) {\n const b_i = Matrix.from_vector(b.col(i), \"col\");\n let x = new Matrix(rows, 1, () => randomizer.random);\n let r = b_i.sub(A.dot(x));\n let d = r.clone();\n let iter = 0;\n const max_iter = rows * 10; // Prevent infinite loops\n do {\n const z = A.dot(d);\n const alpha = r.transDot(r).entry(0, 0) / d.transDot(z).entry(0, 0);\n x = x.add(d.mult(alpha));\n const r_next = r.sub(z.mult(alpha));\n const beta = r_next.transDot(r_next).entry(0, 0) / r.transDot(r).entry(0, 0);\n d = r_next.add(d.mult(beta));\n r = r_next;\n iter++;\n } while (Math.abs(r.mean()) > tol && iter < max_iter);\n result = result.concat(x, \"horizontal\");\n }\n return result;\n }\n\n /**\n * Solves the equation `Ax = b`. Returns the result `x`.\n *\n * @param {Matrix | { L: Matrix; U: Matrix }} A - Matrix or LU Decomposition\n * @param {Matrix} b - Matrix\n * @returns {Matrix}\n */\n static solve(A, b) {\n const { L, U } = \"L\" in A && \"U\" in A ? A : Matrix.LU(A);\n const rows = L.shape[0];\n const x = b.clone();\n\n // forward\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < row; ++col) {\n x.sub_entry(0, row, L.entry(row, col) * x.entry(0, col));\n }\n x.set_entry(0, row, x.entry(0, row) / L.entry(row, row));\n }\n\n // backward\n for (let row = rows - 1; row >= 0; --row) {\n for (let col = rows - 1; col > row; --col) {\n x.sub_entry(0, row, U.entry(row, col) * x.entry(0, col));\n }\n x.set_entry(0, row, x.entry(0, row) / U.entry(row, row));\n }\n\n return x;\n }\n\n /**\n * `LU` decomposition of the Matrix `A`. Creates two matrices, so that the dot product `LU` equals `A`.\n *\n * @param {Matrix} A\n * @returns {{ L: Matrix; U: Matrix }} The left triangle matrix `L` and the upper triangle matrix `U`.\n */\n static LU(A) {\n const rows = A.shape[0];\n const L = new Matrix(rows, rows, \"zeros\");\n const U = new Matrix(rows, rows, \"identity\");\n\n for (let j = 0; j < rows; ++j) {\n for (let i = j; i < rows; ++i) {\n let sum = 0;\n for (let k = 0; k < j; ++k) {\n sum += L.entry(i, k) * U.entry(k, j);\n }\n L.set_entry(i, j, A.entry(i, j) - sum);\n }\n for (let i = j; i < rows; ++i) {\n if (L.entry(j, j) === 0) {\n throw new Error(\"L's diagonal not supposed to be 0!\");\n }\n let sum = 0;\n for (let k = 0; k < j; ++k) {\n sum += L.entry(j, k) * U.entry(k, i);\n }\n U.set_entry(j, i, (A.entry(j, i) - sum) / L.entry(j, j));\n }\n }\n\n return { L, U };\n }\n\n /**\n * Computes the determinante of `A`, by using the `LU` decomposition of `A`.\n *\n * @param {Matrix} A\n * @returns {number} The determinate of the Matrix `A`.\n */\n static det(A) {\n const [rows, cols] = A.shape;\n\n if (rows === 2 && cols === 2) {\n return A.entry(0, 0) * A.entry(1, 1) - A.entry(0, 1) * A.entry(1, 0);\n }\n if (rows === 3 && cols === 3) {\n const a = A.entry(0, 0);\n const b = A.entry(0, 1);\n const c = A.entry(0, 2);\n const d = A.entry(1, 0);\n const e = A.entry(1, 1);\n const f = A.entry(1, 2);\n const g = A.entry(2, 0);\n const h = A.entry(2, 1);\n const i = A.entry(2, 2);\n return a * (e * i - f * h) - b * (d * i - f * g) + c * (d * h - e * g);\n }\n\n const { L, U } = Matrix.LU(A);\n const L_diag = L.diag();\n const U_diag = U.diag();\n let det = L_diag[0] * U_diag[0];\n for (let row = 1; row < rows; ++row) {\n det *= L_diag[row] * U_diag[row];\n }\n return det;\n }\n\n /**\n * Computes the `k` components of the SVD decomposition of the matrix `M`.\n *\n * @param {Matrix} M\n * @param {number} [k=2] Default is `2`\n * @returns {{ U: Float64Array[]; Sigma: Float64Array; V: Float64Array[] }}\n */\n static SVD(M, k = 2) {\n const MtM = M.transDot(M);\n const MMt = M.dotTrans(M);\n const { eigenvectors: V, eigenvalues: Sigma } = simultaneous_poweriteration(MtM, k);\n const { eigenvectors: U } = simultaneous_poweriteration(MMt, k);\n return { U: U, Sigma: Sigma.map((sigma) => Math.sqrt(sigma)), V: V };\n\n //Algorithm 1a: Householder reduction to bidiagonal form:\n /* const [m, n] = A.shape;\n let U = new Matrix(m, n, (i, j) => i == j ? 1 : 0);\n console.log(U.to2dArray)\n let V = new Matrix(n, m, (i, j) => i == j ? 1 : 0);\n console.log(V.to2dArray)\n let B = Matrix.bidiagonal(A.clone(), U, V);\n console.log(U,V,B)\n return { U: U, \"Sigma\": B, V: V }; */\n }\n\n /**\n * @param {unknown} A\n * @returns {A is unknown[]|number[]|Float64Array|Float32Array}\n */\n static isArray(A) {\n return Array.isArray(A) || A instanceof Float64Array || A instanceof Float32Array;\n }\n\n /**\n * @param {any[]} A\n * @returns {A is number[][]|Float64Array[]}\n */\n static is2dArray(A) {\n if (!Array.isArray(A) || A.length === 0) {\n return false;\n }\n const n = A[0].length;\n for (let i = 0; i < A.length; ++i) {\n if (!Array.isArray(A[i]) && !(A[i] instanceof Float64Array)) {\n return false;\n }\n if (A[i].length !== n) {\n return false;\n }\n }\n return true;\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n\n/**\n * Computes the norm of a vector, by computing its distance to **0**.\n *\n * @category Matrix\n * @param {Matrix | number[] | Float64Array} v - Vector.\n * @param {Metric} [metric=euclidean] - Which metric should be used to compute the norm. Default is `euclidean`\n * @returns {number} - The norm of `v`.\n */\nexport function norm(v, metric = euclidean) {\n let vector = null;\n if (v instanceof Matrix) {\n const [rows, cols] = v.shape;\n if (rows === 1) vector = v.row(0);\n else if (cols === 1) vector = v.col(0);\n else throw new Error(\"Matrix must be 1d!\");\n } else {\n vector = v;\n }\n const n = vector.length;\n const zeros = new Float64Array(n);\n return metric(vector, zeros);\n}\n","import { euclidean } from \"../metrics/index.js\";\nimport { norm } from \"./index.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n\n/**\n * Normalizes Vector `v`.\n *\n * @category Matrix\n * @param {number[] | Float64Array} v - Vector\n * @param {Metric} metric\n * @returns {number[] | Float64Array} - The normalized vector with length 1.\n */\nexport function normalize(v, metric = euclidean) {\n const v_norm = norm(v, metric);\n return v.map((value) => value / v_norm);\n}\n","import { Matrix } from \"../matrix/index.js\";\n\n/** @import {InputType} from \"../index.js\" */\n\n/**\n * Base class for all clustering algorithms.\n * @template Para\n */\nexport class Clustering {\n /** @type {InputType} */\n _points;\n /** @type {Para} */\n _parameters;\n /** @type {Matrix} */\n _matrix;\n /** @type {number} */\n _N;\n /** @type {number} */\n _D;\n\n /**\n * Compute the respective Clustering with given parameters\n * @param {InputType} points\n * @param {Para} parameters\n */\n constructor(points, parameters) {\n this._points = points;\n this._parameters = parameters;\n\n this._matrix = points instanceof Matrix ? points : Matrix.from(points);\n const [N, D] = this._matrix.shape;\n this._N = N;\n this._D = D;\n }\n\n /**\n * @abstract\n * @param {...unknown} args\n * @returns {number[][]} An array with the indices of the clusters.\n */\n get_clusters(...args) {\n args;\n throw new Error(\"The function get_clusters must be implemented!\");\n }\n\n /**\n * @abstract\n * @param {...unknown} args\n * @returns {number[]} An array with the clusters id's for each point.\n */\n get_cluster_list(...args) {\n args;\n throw new Error(\"The function get_cluster_list must be implemented!\");\n }\n}\n","import { euclidean } from \"../metrics/index.js\";\nimport { Clustering } from \"./Clustering.js\";\n\n/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersCURE } from \"./index.js\" */\n\n/**\n * CURE (Clustering Using REpresentatives)\n *\n * An efficient clustering algorithm for large databases that is robust to outliers\n * and identifies clusters with non-spherical shapes and wide variances in size.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class CURE extends Clustering {\n /** @type {number} */\n _K;\n /** @type {number} */\n _num_representatives;\n /** @type {number} */\n _shrink_factor;\n /**\n * @private\n * @type {CURECluster[]}\n */\n _clusters = [];\n /** @type {number[]} */\n _cluster_ids = [];\n\n /**\n * @param {InputType} points\n * @param {Partial} parameters\n */\n constructor(points, parameters = {}) {\n super(\n points,\n /** @type {ParametersCURE} */ (\n Object.assign(\n { K: 2, num_representatives: 5, shrink_factor: 0.5, metric: euclidean, seed: 1212 },\n parameters,\n )\n ),\n );\n\n this._K = this._parameters.K ?? 2;\n this._num_representatives = this._parameters.num_representatives ?? 5;\n this._shrink_factor = this._parameters.shrink_factor ?? 0.5;\n\n // Initialize clusters\n this._initialize_clusters();\n // Run CURE algorithm\n this._cure();\n }\n\n /**\n * Initialize each point as its own cluster\n * @private\n */\n _initialize_clusters() {\n const N = this._N;\n //const D = this._D;\n this._clusters = [];\n\n for (let i = 0; i < N; ++i) {\n const point = this._matrix.row(i);\n const centroid = new Float64Array(point);\n // For single point, representative is the point itself\n const representatives = [new Float64Array(point)];\n\n this._clusters.push(new CURECluster([i], centroid, representatives));\n }\n }\n\n /**\n * Compute distance between two clusters using representative points\n * @private\n * @param {CURECluster} cluster1\n * @param {CURECluster} cluster2\n * @returns {number}\n */\n _cluster_distance(cluster1, cluster2) {\n const reps1 = cluster1.representatives;\n const reps2 = cluster2.representatives;\n const metric = this._parameters.metric;\n\n let min_dist = Infinity;\n for (const r1 of reps1) {\n for (const r2 of reps2) {\n const dist = metric(r1, r2);\n if (dist < min_dist) {\n min_dist = dist;\n }\n }\n }\n return min_dist;\n }\n\n /**\n * Find the closest pair of clusters\n * @private\n * @returns {[number, number, number]} [index1, index2, distance]\n */\n _find_closest_clusters() {\n let min_dist = Infinity;\n let min_i = 0;\n let min_j = 1;\n\n for (let i = 0; i < this._clusters.length; ++i) {\n for (let j = i + 1; j < this._clusters.length; ++j) {\n const dist = this._cluster_distance(this._clusters[i], this._clusters[j]);\n if (dist < min_dist) {\n min_dist = dist;\n min_i = i;\n min_j = j;\n }\n }\n }\n\n return [min_i, min_j, min_dist];\n }\n\n /**\n * Merge two clusters\n * @private\n * @param {CURECluster} cluster1\n * @param {CURECluster} cluster2\n * @returns {CURECluster}\n */\n _merge_clusters(cluster1, cluster2) {\n // Merge indices\n const merged_indices = [...cluster1.indices, ...cluster2.indices];\n\n // Calculate new centroid\n const size1 = cluster1.indices.length;\n const size2 = cluster2.indices.length;\n const total_size = size1 + size2;\n const D = this._D;\n const new_centroid = new Float64Array(D);\n\n for (let d = 0; d < D; ++d) {\n new_centroid[d] = (size1 * cluster1.centroid[d] + size2 * cluster2.centroid[d]) / total_size;\n }\n\n // Collect all points from both clusters\n /** @type {{index: number, point: Float64Array}[]} */\n const all_points = [];\n for (const idx of cluster1.indices) {\n all_points.push({ index: idx, point: this._matrix.row(idx) });\n }\n for (const idx of cluster2.indices) {\n all_points.push({ index: idx, point: this._matrix.row(idx) });\n }\n\n // Select representative points - pick points farthest from centroid\n const num_reps = Math.min(this._num_representatives, all_points.length);\n const metric = this._parameters.metric;\n\n // Calculate distances from centroid for all points\n const distances = all_points.map(({ point }) => metric(point, new_centroid));\n\n // Select num_reps points with maximum distance (farthest from centroid)\n const selected_indices = [];\n const used = new Set();\n\n for (let r = 0; r < num_reps; ++r) {\n let max_dist = -1;\n let max_idx = -1;\n\n for (let i = 0; i < distances.length; ++i) {\n if (!used.has(i) && distances[i] > max_dist) {\n max_dist = distances[i];\n max_idx = i;\n }\n }\n\n if (max_idx >= 0) {\n used.add(max_idx);\n selected_indices.push(max_idx);\n }\n }\n\n // Shrink representative points toward centroid\n const new_representatives = selected_indices.map((idx) => {\n const point = all_points[idx].point;\n const shrunk = new Float64Array(D);\n const alpha = this._shrink_factor;\n\n for (let d = 0; d < D; ++d) {\n shrunk[d] = point[d] + alpha * (new_centroid[d] - point[d]);\n }\n\n return shrunk;\n });\n\n return new CURECluster(merged_indices, new_centroid, new_representatives);\n }\n\n /**\n * Run CURE clustering algorithm\n * @private\n */\n _cure() {\n // Merge clusters until we have K clusters\n while (this._clusters.length > this._K) {\n const [i, j] = this._find_closest_clusters();\n\n // Merge clusters i and j\n const merged = this._merge_clusters(this._clusters[i], this._clusters[j]);\n\n // Remove the old clusters and add the merged one\n // Remove larger index first to maintain correct indices\n // min_i < min_j is always true from _find_closest_clusters\n this._clusters.splice(j, 1);\n this._clusters.splice(i, 1);\n\n this._clusters.push(merged);\n }\n\n // Build cluster list for get_cluster_list\n this._build_cluster_ids();\n }\n\n /**\n * Build the cluster list (point -> cluster assignment)\n * @private\n */\n _build_cluster_ids() {\n const N = this._N;\n this._cluster_ids = new Array(N).fill(-1);\n\n for (let c = 0; c < this._clusters.length; ++c) {\n for (const idx of this._clusters[c].indices) {\n this._cluster_ids[idx] = c;\n }\n }\n }\n\n /**\n * @returns {number[][]}\n */\n get_clusters() {\n return this._clusters.map((cluster) => cluster.indices);\n }\n\n /**\n * @returns {number[]}\n */\n get_cluster_list() {\n return this._cluster_ids;\n }\n}\n\n/**\n * @private\n * Represents a cluster in CURE algorithm\n */\nclass CURECluster {\n /**\n * @param {number[]} indices - Indices of points in the cluster\n * @param {Float64Array} centroid - Centroid of the cluster\n * @param {Float64Array[]} representatives - Representative points (shrunk toward centroid)\n */\n constructor(indices, centroid, representatives) {\n /** @type {number[]} */\n this.indices = indices;\n /** @type {Float64Array} */\n this.centroid = centroid;\n /** @type {Float64Array[]} */\n this.representatives = representatives;\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Clustering } from \"./Clustering.js\";\n\n/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersHierarchicalClustering } from \"./index.js\" */\n\n/**\n * Hierarchical Clustering\n *\n * A bottom-up approach (agglomerative) to clustering that builds a tree of clusters (dendrogram).\n * Supports different linkage criteria: single, complete, and average.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class HierarchicalClustering extends Clustering {\n /** @type {Cluster | null} */\n root = null;\n\n /**\n * @param {InputType} points - Data or distance matrix if metric is 'precomputed'\n * @param {Partial} parameters\n */\n constructor(points, parameters = {}) {\n super(\n points,\n /** @type {ParametersHierarchicalClustering} */ (\n Object.assign({ linkage: \"complete\", metric: euclidean }, parameters)\n ),\n );\n this._id = 0;\n if (this._parameters.metric === \"precomputed\" && this._matrix.shape[0] !== this._matrix.shape[1]) {\n throw new Error(\"If metric is 'precomputed', then matrix has to be square!\");\n }\n\n const metric = this._parameters.metric;\n const A = this._matrix;\n const N = this._N;\n this._d_min = new Float64Array(N);\n const d_min = this._d_min;\n let distance_matrix;\n if (metric !== \"precomputed\") {\n distance_matrix = new Matrix(N, N, Infinity);\n for (let i = 0; i < N; ++i) {\n distance_matrix.set_entry(i, i, 0);\n d_min[i] = i; // temporary\n const Ai = A.row(i);\n for (let j = i + 1; j < N; ++j) {\n const dist = metric(Ai, A.row(j));\n distance_matrix.set_entry(i, j, dist);\n distance_matrix.set_entry(j, i, dist);\n }\n }\n for (let i = 0; i < N; i++) {\n let min_j = 0;\n let min_d = Infinity;\n for (let j = 0; j < N; j++) {\n if (i === j) continue;\n const d = distance_matrix.entry(i, j);\n if (d < min_d) {\n min_d = d;\n min_j = j;\n }\n }\n d_min[i] = min_j;\n }\n } else {\n distance_matrix = this._matrix.clone();\n for (let i = 0; i < N; ++i) {\n distance_matrix.set_entry(i, i, 0);\n d_min[i] = i === 0 ? 1 : 0;\n for (let j = 0; j < N; ++j) {\n if (i === j) continue;\n if (distance_matrix.entry(i, d_min[i]) > distance_matrix.entry(i, j)) {\n d_min[i] = j;\n }\n }\n }\n }\n this._distance_matrix = distance_matrix;\n this._clusters = new Array(N);\n const clusters = this._clusters;\n this._c_size = new Uint16Array(N);\n const c_size = this._c_size;\n for (let i = 0; i < N; ++i) {\n clusters[i] = [];\n clusters[i][0] = new Cluster(this._id++, null, null, 0, A.row(i), i, 1, 0);\n c_size[i] = 1;\n }\n const D = this._distance_matrix;\n const linkage = this._parameters.linkage;\n const p_max = N - 1;\n for (let p = 0; p < p_max; ++p) {\n let c1 = -1;\n let min_dist = Infinity;\n for (let i = 0; i < N; ++i) {\n if (D.entry(i, i) === Infinity) continue;\n const dist = D.entry(i, d_min[i]);\n if (dist < min_dist) {\n min_dist = dist;\n c1 = i;\n }\n }\n if (c1 === -1) break;\n\n const c2 = d_min[c1];\n const c1_cluster = clusters[c1][0];\n const c2_cluster = clusters[c2][0];\n const c1_cluster_indices = c1_cluster.isLeaf ? [c1_cluster.index] : c1_cluster.index;\n const c2_cluster_indices = c2_cluster.isLeaf ? [c2_cluster.index] : c2_cluster.index;\n const indices = c1_cluster_indices.concat(c2_cluster_indices);\n const new_cluster = new Cluster(this._id++, c1_cluster, c2_cluster, D.entry(c1, c2), null, indices);\n c1_cluster.parent = new_cluster;\n c2_cluster.parent = new_cluster;\n clusters[c1].unshift(new_cluster);\n\n const size1 = c_size[c1];\n const size2 = c_size[c2];\n c_size[c1] += size2;\n\n for (let j = 0; j < N; ++j) {\n if (j === c1 || j === c2 || D.entry(j, j) === Infinity) continue;\n const D_c1_j = D.entry(c1, j);\n const D_c2_j = D.entry(c2, j);\n let value;\n switch (linkage) {\n case \"single\":\n value = Math.min(D_c1_j, D_c2_j);\n break;\n case \"complete\":\n value = Math.max(D_c1_j, D_c2_j);\n break;\n case \"average\":\n value = (size1 * D_c1_j + size2 * D_c2_j) / (size1 + size2);\n break;\n }\n D.set_entry(j, c1, value);\n D.set_entry(c1, j, value);\n }\n\n D.set_entry(c2, c2, Infinity);\n for (let i = 0; i < N; ++i) {\n D.set_entry(i, c2, Infinity);\n D.set_entry(c2, i, Infinity);\n }\n\n // Update d_min for all rows\n for (let i = 0; i < N; i++) {\n if (D.entry(i, i) === Infinity) continue;\n if (d_min[i] === c1 || d_min[i] === c2 || i === c1) {\n let min_j = 0;\n let min_d = Infinity;\n for (let j = 0; j < N; j++) {\n if (i === j || D.entry(j, j) === Infinity) continue;\n const d = D.entry(i, j);\n if (d < min_d) {\n min_d = d;\n min_j = j;\n }\n }\n d_min[i] = min_j;\n } else {\n if (D.entry(i, c1) < D.entry(i, d_min[i])) {\n d_min[i] = c1;\n }\n }\n }\n\n this.root = new_cluster;\n }\n }\n\n /**\n * @param {number} value - Value where to cut the tree.\n * @param {\"distance\" | \"depth\"} [type=\"distance\"] - Type of value. Default is `\"distance\"`\n * @returns {Cluster[][]} - Array of clusters with the indices of the rows in given points.\n */\n get_clusters_raw(value, type = \"distance\") {\n /** @type {Cluster[][]} */\n const clusters = [];\n /** @type {(d: {dist: number, depth: number}) => number} */\n let accessor;\n switch (type) {\n case \"distance\":\n accessor = (d) => d.dist;\n break;\n case \"depth\":\n accessor = (d) => d.depth;\n break;\n default:\n throw new Error(\"invalid type\");\n }\n this._traverse(/** @type {Cluster} */ (this.root), accessor, value, clusters);\n return clusters;\n }\n\n /**\n * @param {number} value - Value where to cut the tree.\n * @param {\"distance\" | \"depth\"} [type=\"distance\"] - Type of value. Default is `\"distance\"`\n * @returns {number[][]} - Array of clusters with the indices of the rows in given points.\n */\n get_clusters(value, type = \"distance\") {\n /** @type {Cluster[][]} */\n const clusters = [];\n /** @type {(d: {dist: number, depth: number}) => number} */\n let accessor;\n switch (type) {\n case \"distance\":\n accessor = (d) => d.dist;\n break;\n case \"depth\":\n accessor = (d) => d.depth;\n break;\n default:\n throw new Error(\"invalid type\");\n }\n if (this.root) this._traverse(this.root, accessor, value, clusters);\n return clusters.map((cluster) => cluster.map((d) => d.index));\n }\n\n /**\n * @param {number} value - Value where to cut the tree.\n * @param {\"distance\" | \"depth\"} [type=\"distance\"] - Type of value. Default is `\"distance\"`\n * @returns {number[]} - Array of clusters with the indices of the rows in given points.\n */\n get_cluster_list(value, type = \"distance\") {\n const clusters = this.get_clusters(value, type);\n /** @type {number[]} */\n const list = new Array(this._N).fill(0);\n for (let i = 0; i < clusters.length; ++i) {\n const cluster = clusters[i];\n for (let j = 0; j < cluster.length; ++j) {\n const index = cluster[j];\n list[index] = i;\n }\n }\n return list;\n }\n\n /**\n * @private\n * @param {Cluster} node\n * @param {(d: {dist: number, depth: number}) => number} f\n * @param {number} value\n * @param {Cluster[][]} result\n */\n _traverse(node, f, value, result) {\n if (f(node) <= value) {\n result.push(node.leaves());\n } else {\n if (node.left) this._traverse(node.left, f, value, result);\n if (node.right) this._traverse(node.right, f, value, result);\n }\n }\n}\n\n/** @private */\nclass Cluster {\n /**@type {number} */\n size;\n /**@type {number} */\n depth;\n /**@type {Cluster | null} */\n parent;\n\n /**\n *\n * @param {number} id\n * @param {Cluster?} left\n * @param {Cluster?} right\n * @param {number} dist\n * @param {Float64Array?} centroid\n * @param {number} index\n * @param {number} [size]\n * @param {number} [depth]\n */\n constructor(id, left, right, dist, centroid, index, size, depth) {\n this.id = id;\n this.left = left;\n this.right = right;\n this.dist = dist;\n this.index = index;\n if (size) {\n this.size = size;\n } else {\n if (!left || !right) throw new Error(\"If size is not given, left & right cannot be null!\");\n this.size = left.size + right.size;\n }\n\n if (depth !== undefined) {\n this.depth = depth;\n } else {\n if (!left || !right) throw new Error(\"If depth is not given, left & right cannot be null!\");\n this.depth = Math.max(left.depth, right.depth) + 1;\n }\n\n if (centroid !== undefined && centroid !== null) {\n this.centroid = centroid;\n } else {\n if (!left || !right) throw new Error(\"If centroid is not given, left & right cannot be null!\");\n\n this.centroid = this._calculate_centroid(left, right);\n }\n\n this.parent = null;\n }\n\n /**\n *\n * @param {Cluster} left\n * @param {Cluster} right\n * @returns {Float64Array}\n */\n _calculate_centroid(left, right) {\n const l_size = left.size;\n const r_size = right.size;\n const l_centroid = left.centroid;\n const r_centroid = right.centroid;\n const size = this.size;\n const n = left.centroid.length;\n const new_centroid = new Float64Array(n);\n for (let i = 0; i < n; ++i) {\n new_centroid[i] = (l_size * l_centroid[i] + r_size * r_centroid[i]) / size;\n }\n return new_centroid;\n }\n\n get isLeaf() {\n return this.depth === 0;\n }\n\n /**\n *\n * @returns {Cluster[]}\n */\n leaves() {\n if (this.isLeaf) return [this];\n const left = this.left;\n const right = this.right;\n return (left ? (left.isLeaf ? [left] : left.leaves()) : []).concat(\n right ? (right.isLeaf ? [right] : right.leaves()) : [],\n );\n }\n\n /**\n *\n * @returns {Cluster[]}\n */\n descendants() {\n if (this.isLeaf) return [this];\n const left_descendants = this.left ? this.left.descendants() : [];\n const right_descendants = this.right ? this.right.descendants() : [];\n return left_descendants.concat(right_descendants).concat([this]);\n }\n}\n","/**\n * @template T\n * @typedef {Object} DisjointSetPayload\n * @property {T} parent\n * @property {Set} children\n * @property {number} size\n */\n\n/**\n * @template T\n * @class\n * @category Data Structures\n * @see {@link https://en.wikipedia.org/wiki/Disjoint-set_data_structure}\n */\nexport class DisjointSet {\n /**\n * @param {T[]?} elements\n */\n constructor(elements = null) {\n /**\n * @private\n * @type {Map>}\n */\n this._list = new Map();\n if (elements) {\n for (const e of elements) {\n this.make_set(e);\n }\n }\n }\n\n /**\n * @private\n * @param {T} x\n * @returns {DisjointSet}\n */\n make_set(x) {\n const list = this._list;\n if (!list.has(x)) {\n list.set(x, { parent: x, children: new Set([x]), size: 1 });\n }\n return this;\n }\n\n /**\n * @param {T} x\n * @returns\n */\n find(x) {\n const list = this._list;\n const disjoint_set = list.get(x);\n if (disjoint_set) {\n if (disjoint_set.parent !== x) {\n disjoint_set.children.add(x);\n const new_parent = this.find(disjoint_set.parent);\n if (!new_parent) throw new Error(\"should not happen!\");\n disjoint_set.parent = new_parent;\n return disjoint_set.parent;\n } else {\n return x;\n }\n } else {\n return null;\n }\n }\n\n /**\n * @param {T} x\n * @param {T} y\n * @returns\n */\n union(x, y) {\n let node_x = this.find(x);\n let node_y = this.find(y);\n\n if (!node_x || !node_y) throw new Error(\"x or y not found!\");\n\n let disjoint_set_x = this._list.get(node_x);\n let disjoint_set_y = this._list.get(node_y);\n\n if (!disjoint_set_x || !disjoint_set_y) throw new Error(\"should not happen!\");\n\n if (node_x === node_y) return this;\n if (disjoint_set_x.size < disjoint_set_y.size) {\n [node_x, node_y] = [node_y, node_x];\n [disjoint_set_x, disjoint_set_y] = [disjoint_set_y, disjoint_set_x];\n }\n\n disjoint_set_y.parent = node_x;\n // keep track of children\n disjoint_set_y.children.forEach(disjoint_set_x.children.add, disjoint_set_x.children);\n disjoint_set_x.size += disjoint_set_y.size;\n\n return this;\n }\n\n /** @param {T} x */\n get_children(x) {\n const node = this._list.get(x);\n if (node) {\n return node.children;\n } else {\n return null;\n }\n }\n}\n","/** @import { Comparator } from \"./index.js\" */\n\n/**\n * @template T\n * @class\n * @category Data Structures\n */\nexport class Heap {\n /** @type {{ element: T; value: number }[]} */\n _container;\n\n /** @type {Comparator} */\n _comparator;\n\n /**\n * A heap is a datastructure holding its elements in a specific way, so that the top element would be the first\n * entry of an ordered list.\n *\n * @param {T[]?} elements - Contains the elements for the Heap. `elements` can be null.\n * @param {(d: T) => number} accessor - Function returns the value of the element.\n * @param {\"min\" | \"max\" | Comparator} [comparator=\"min\"] - Function returning true or false\n * defining the wished order of the Heap, or String for predefined function. (\"min\" for a Min-Heap, \"max\" for a\n * Max_heap). Default is `\"min\"`\n * @see {@link https://en.wikipedia.org/wiki/Binary_heap}\n */\n constructor(elements = null, accessor, comparator = \"min\") {\n /** @type {(d: T) => number} */\n this._accessor = accessor;\n this._container = [];\n if (comparator === \"min\") {\n this._comparator = (a, b) => a < b;\n } else if (comparator === \"max\") {\n this._comparator = (a, b) => a > b;\n } else {\n this._comparator = comparator;\n }\n if (elements) {\n this._container = [];\n for (const e of elements) {\n this._container.push({\n element: e,\n value: accessor(e),\n });\n }\n for (let i = Math.floor(elements.length / 2 - 1); i >= 0; --i) {\n this._heapify_down(i);\n }\n }\n }\n\n /**\n * Creates a Heap from an Array\n *\n * @template T\n * @param {T[]} elements - Contains the elements for the Heap.\n * @param {(d: T) => number} accessor - Function returns the value of the element.\n * @param {\"min\" | \"max\" | Comparator} [comparator=\"min\"] - Function returning true or false\n * defining the wished order of the Heap, or String for predefined function. (\"min\" for a Min-Heap, \"max\" for a\n * Max_heap). Default is `\"min\"`\n * @returns {Heap}\n */\n static heapify(elements, accessor, comparator = \"min\") {\n const heap = new Heap(null, accessor, comparator);\n const container = heap._container;\n for (const e of elements) {\n container.push({\n element: e,\n value: accessor(e),\n });\n }\n for (let i = Math.floor(elements.length / 2 - 1); i >= 0; --i) {\n heap._heapify_down(i);\n }\n return heap;\n }\n\n /**\n * Swaps elements of container array.\n *\n * @private\n * @param {number} index_a\n * @param {number} index_b\n */\n _swap(index_a, index_b) {\n const container = this._container;\n [container[index_b], container[index_a]] = [container[index_a], container[index_b]];\n return;\n }\n\n /** @private */\n _heapify_up() {\n const container = this._container;\n let index = container.length - 1;\n while (index > 0) {\n const parentIndex = Math.floor((index - 1) / 2);\n if (!this._comparator(container[index].value, container[parentIndex].value)) {\n break;\n } else {\n this._swap(parentIndex, index);\n index = parentIndex;\n }\n }\n }\n\n /**\n * Pushes the element to the heap.\n *\n * @param {T} element\n * @returns {Heap}\n */\n push(element) {\n const value = this._accessor(element);\n //const node = new Node(element, value);\n const node = { element: element, value: value };\n this._container.push(node);\n this._heapify_up();\n return this;\n }\n\n /**\n * @private\n * @param {Number} [start_index=0] Default is `0`\n */\n _heapify_down(start_index = 0) {\n const container = this._container;\n const comparator = this._comparator;\n const length = container.length;\n const left = 2 * start_index + 1;\n const right = 2 * start_index + 2;\n let index = start_index;\n if (index >= length) throw \"index higher than length\";\n if (left < length && comparator(container[left].value, container[index].value)) {\n index = left;\n }\n if (right < length && comparator(container[right].value, container[index].value)) {\n index = right;\n }\n if (index !== start_index) {\n this._swap(start_index, index);\n this._heapify_down(index);\n }\n }\n\n /**\n * Removes and returns the top entry of the heap.\n *\n * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by\n * `accessor`}).\n */\n pop() {\n const container = this._container;\n if (container.length === 0) {\n return null;\n } else if (container.length === 1) {\n const item = container.pop();\n if (!item) throw new Error(\"Cannot happen!\");\n return item;\n }\n this._swap(0, container.length - 1);\n const item = container.pop();\n this._heapify_down();\n return item ?? null;\n }\n\n /**\n * Returns the top entry of the heap without removing it.\n *\n * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by\n * `accessor`).\n */\n get first() {\n return this._container.length > 0 ? this._container[0] : null;\n }\n\n /**\n * Yields the raw data\n *\n * @yields {T} Object consists of the element and its value (computed by `accessor`}).\n */\n *iterate() {\n for (let i = 0, n = this._container.length; i < n; ++i) {\n yield this._container[i].element;\n }\n }\n\n /**\n * Returns the heap as ordered array.\n *\n * @returns {T[]} Array consisting the elements ordered by `comparator`.\n */\n toArray() {\n return this._container.sort((a, b) => (this._comparator(a.value, b.value) ? -1 : 1)).map((d) => d.element);\n }\n\n /**\n * Returns elements of container array.\n *\n * @returns {T[]} Array consisting the elements.\n */\n data() {\n return this._container.map((d) => d.element);\n }\n\n /**\n * Returns the container array.\n *\n * @returns {{ element: T; value: number }[]} The container array.\n */\n raw_data() {\n return this._container;\n }\n\n /**\n * The size of the heap.\n *\n * @returns {number}\n */\n get length() {\n return this._container.length;\n }\n\n /**\n * Returns false if the the heap has entries, true if the heap has no entries.\n *\n * @returns {boolean}\n */\n get empty() {\n return this.length === 0;\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { linspace, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { Clustering } from \"./Clustering.js\";\n\n/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersKMeans } from \"./index.js\" */\n/**\n * K-Means Clustering\n *\n * A popular clustering algorithm that partitions data into K clusters where each point\n * belongs to the cluster with the nearest mean (centroid).\n *\n * @class\n * @extends Clustering\n * @category Clustering\n * @see {@link KMedoids} for a more robust alternative\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const points = [[1, 1], [1.5, 1.5], [5, 5], [5.5, 5.5]];\n * const kmeans = new druid.KMeans(points, { K: 2 });\n *\n * const clusters = kmeans.get_cluster_list(); // [0, 0, 1, 1]\n * const centroids = kmeans.centroids; // center points\n */\nexport class KMeans extends Clustering {\n /**\n * @param {InputType} points\n * @param {Partial} parameters\n */\n constructor(points, parameters = {}) {\n super(\n points,\n /** @type {ParametersKMeans} */ (Object.assign({ K: 4, metric: euclidean, seed: 1212 }, parameters)),\n );\n\n const K = this._parameters.K;\n const seed = parameters.seed;\n\n // Convert points to Matrix if needed\n if (points instanceof Matrix) {\n this._matrix = points;\n } else {\n this._matrix = Matrix.from(points);\n }\n\n const [N, D] = this._matrix.shape;\n this._N = N;\n this._D = D;\n\n this._K = K > N ? N : K;\n this._randomizer = new Randomizer(seed);\n\n /** @type {number[]} */\n this._clusters = new Array(N).fill(0);\n\n this._cluster_centroids = parameters.initial_centroids\n ? parameters.initial_centroids.map((c) => new Float64Array(c))\n : this._get_random_centroids(this._K);\n let cluster_centroids = this._cluster_centroids;\n let iterations = 0;\n const max_iterations = 300;\n let clusters_changed = true;\n\n while (clusters_changed && iterations < max_iterations) {\n const iteration_result = this._iteration(cluster_centroids);\n cluster_centroids = iteration_result.cluster_centroids;\n clusters_changed = iteration_result.clusters_changed;\n iterations++;\n }\n\n this._cluster_centroids = cluster_centroids;\n }\n\n /** @returns {number} The number of clusters */\n get k() {\n return this._K;\n }\n\n /** @returns {Float64Array[]} The cluster centroids */\n get centroids() {\n return this._cluster_centroids;\n }\n\n /** @returns {number[]} The cluster list */\n get_cluster_list() {\n return this._clusters;\n }\n\n /** @returns {number[][]} An Array of clusters with the indices of the points. */\n get_clusters() {\n const K = this._K;\n const clusters = this._clusters;\n /** @type {number[][]} */\n const result = new Array(K).fill(0).map(() => []);\n clusters.forEach((c, i) => {\n if (c >= 0 && c < K) {\n result[c].push(i);\n }\n });\n return result;\n }\n\n /**\n * @private\n * @param {number[]} point_indices\n * @param {number[]} candidates\n * @returns {number}\n */\n _furthest_point(point_indices, candidates) {\n const A = this._matrix;\n const metric = this._parameters.metric;\n\n if (point_indices.length === 0 || candidates.length === 0) {\n return candidates[0] ?? 0;\n }\n\n const H = Heap.heapify(\n candidates,\n (d) => {\n const Ad = A.row(d);\n let sum = 0;\n for (let j = 0; j < point_indices.length; ++j) {\n sum += metric(Ad, A.row(point_indices[j]));\n }\n return sum;\n },\n \"max\",\n );\n\n const furthest = H.pop();\n if (!furthest) throw new Error(\"Should not happen!\");\n\n return furthest.element;\n }\n\n /**\n * @private\n * @param {number} K\n * @returns {Float64Array[]}\n */\n _get_random_centroids(K) {\n const N = this._N;\n const randomizer = this._randomizer;\n const A = this._matrix;\n /** @type {Float64Array[]} */\n const cluster_centroids = new Array(K);\n const indices = linspace(0, N - 1);\n\n // First centroid: random selection\n const random_point = randomizer.random_int % N;\n cluster_centroids[0] = A.row(random_point);\n const init_points = [random_point];\n\n const sample_size = Math.max(1, Math.floor((N - K) / K));\n\n for (let i = 1; i < K; ++i) {\n const remaining = indices.filter((d) => !init_points.includes(d));\n if (remaining.length === 0) break;\n\n const sample = randomizer.choice(remaining, Math.min(sample_size, remaining.length));\n const furthest_point = this._furthest_point(init_points, sample);\n\n init_points.push(furthest_point);\n cluster_centroids[i] = A.row(furthest_point);\n }\n\n return cluster_centroids;\n }\n\n /**\n * @private\n * @param {Float64Array[]} cluster_centroids\n * @returns {{ clusters_changed: boolean; cluster_centroids: Float64Array[] }}\n */\n _iteration(cluster_centroids) {\n const K = cluster_centroids.length;\n const N = this._N;\n const metric = this._parameters.metric;\n const A = this._matrix;\n const clusters = this._clusters;\n let clusters_changed = false;\n\n // Find nearest cluster centroid for each point\n for (let i = 0; i < N; ++i) {\n const Ai = A.row(i);\n let min_dist = Infinity;\n let min_cluster = 0;\n\n for (let j = 0; j < K; ++j) {\n const d = metric(cluster_centroids[j], Ai);\n if (d < min_dist) {\n min_dist = d;\n min_cluster = j;\n }\n }\n\n if (clusters[i] !== min_cluster) {\n clusters_changed = true;\n clusters[i] = min_cluster;\n }\n }\n\n // Update cluster centroids\n const new_centroids = this._compute_centroid(K);\n\n return {\n clusters_changed: clusters_changed,\n cluster_centroids: new_centroids,\n };\n }\n\n /**\n * @private\n * @param {number} K\n * @returns {Float64Array[]}\n */\n _compute_centroid(K) {\n const N = this._N;\n const D = this._D;\n const A = this._matrix;\n const clusters = this._clusters;\n\n // Initialize new centroids and counters\n /** @type {Float64Array[]} */\n const new_centroids = new Array(K);\n const cluster_counter = new Array(K).fill(0);\n\n for (let i = 0; i < K; ++i) {\n new_centroids[i] = new Float64Array(D);\n }\n\n // Sum up all points in each cluster\n for (let i = 0; i < N; ++i) {\n const Ai = A.row(i);\n const ci = clusters[i];\n if (ci >= 0 && ci < K) {\n cluster_counter[ci]++;\n const centroid = new_centroids[ci];\n for (let j = 0; j < D; ++j) {\n centroid[j] += Ai[j];\n }\n }\n }\n\n // Divide by count to get mean\n for (let i = 0; i < K; ++i) {\n const n = cluster_counter[i];\n if (n > 0) {\n const centroid = new_centroids[i];\n for (let j = 0; j < D; ++j) {\n centroid[j] /= n;\n }\n }\n }\n\n return new_centroids;\n }\n}\n","import { linspace, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { Clustering } from \"./Clustering.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import { ParametersKMedoids } from \"./index.js\" */\n\n/**\n * K-Medoids (PAM - Partitioning Around Medoids)\n *\n * A robust clustering algorithm similar to K-Means, but uses actual data points (medoids)\n * as cluster centers and can work with any distance metric.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n * @see {@link KMeans} for a faster but less robust alternative\n */\nexport class KMedoids extends Clustering {\n /**\n * @param {InputType} points - Data matrix\n * @param {Partial} parameters\n * @see {@link https://link.springer.com/chapter/10.1007/978-3-030-32047-8_16} Faster k-Medoids Clustering: Improving the PAM, CLARA, and CLARANS Algorithms\n */\n constructor(points, parameters = {}) {\n super(points, Object.assign({ K: 4, max_iter: null, metric: euclidean, seed: 1212 }, parameters));\n this._A = this._matrix.to2dArray();\n let K = this._parameters.K;\n const N = this._N;\n this._max_iter = this._parameters.max_iter ?? 10 * Math.log10(N);\n this._distance_matrix = new Matrix(N, N, \"zeros\");\n\n if (K > N) {\n this._parameters.K = K = N;\n }\n this._randomizer = new Randomizer(this._parameters.seed);\n this._clusters = new Array(N).fill(-1);\n this._cluster_medoids = this._get_random_medoids(K);\n this._is_initialized = false;\n }\n\n /** @returns {number[]} The cluster list */\n get_cluster_list() {\n if (!this._is_initialized) {\n this.get_clusters();\n }\n return this._clusters;\n }\n\n /** @returns {number[][]} - Array of clusters with the indices of the rows in given points. */\n get_clusters() {\n const K = this._parameters.K;\n const A = this._A;\n const N = this._N;\n if (!this._is_initialized) {\n this.init(K, this._cluster_medoids);\n }\n /** @type {number[][]} */\n const result = new Array(K).fill(0).map(() => []);\n for (let j = 0; j < N; j++) {\n const nearest = this._nearest_medoid(A[j], j);\n const cluster_idx = nearest.index_nearest;\n result[cluster_idx].push(j);\n this._clusters[j] = cluster_idx;\n }\n return result;\n }\n\n /** @returns {number} */\n get k() {\n return this._parameters.K;\n }\n\n /** @returns {number[]} */\n get medoids() {\n return this.get_medoids();\n }\n\n /** @returns {number[]} */\n get_medoids() {\n const K = this._parameters.K;\n if (!this._is_initialized) {\n this.init(K, this._cluster_medoids);\n }\n return this._cluster_medoids;\n }\n\n async *generator() {\n const max_iter = this._max_iter;\n if (!this._is_initialized) {\n this.get_clusters();\n }\n yield this.get_clusters();\n let i = 0;\n while (i < max_iter) {\n const finish = this._iteration();\n this._update_clusters();\n yield this.get_clusters();\n if (finish) break;\n i++;\n }\n }\n\n /** Algorithm 1. FastPAM1: Improved SWAP algorithm */\n /* _iteration_1() {\n const A = this._A;\n const N = this._N;\n const K = this._K;\n const medoids = this._cluster_medoids;\n let DeltaTD = 0;\n let m0 = null;\n let x0 = null;\n A.forEach((x_j, j) => {\n if (medoids.findIndex(m => m === j) < 0) {\n const nearest_medoid = this._nearest_medoid(x_j, j);\n const d_j = nearest_medoid.distance_nearest; // distance to current medoid\n const deltaTD = new Array(K).fill(-d_j); // change if making j a medoid\n A.forEach((x_o, o) => {\n // disance to new medoid\n const d_oj = this._get_distance(o, j, x_o, x_j);\n const {\n \"index_nearest\": n,\n \"distance_nearest\": d_n,\n \"distance_second\": d_s,\n } = this._nearest_medoid(x_o, o);\n this._clusters[o] = n; // cached values\n deltaTD[n] += Math.min(d_oj, d_s) - d_n; // loss change\n if (d_oj < d_n) { // reassignment check\n deltaTD.forEach((d_i, i) => {\n if (n !== i) {\n deltaTD[i] = d_i + d_oj - d_n; // update loss change\n }\n });\n }\n });\n // choose best medoid i;\n const i = deltaTD\n .map((d, i) => [d, i])\n .sort((d1, d2) => d1[0] - d2[0])[0][1];\n const deltaTD_i = deltaTD[i];\n // store\n if (deltaTD_i < DeltaTD) {\n DeltaTD = deltaTD_i;\n m0 = i;\n x0 = j;\n }\n }\n });\n\n if (DeltaTD >= 0) {\n return true // break loop if DeltaTD >= 0\n }\n // swap roles of medoid m and non-medoid x;\n medoids[m0] = x0;\n this._cluster_medoids = medoids;\n return false\n } */\n\n /** FastPAM1: One best swap per iteration */\n _iteration() {\n const A = this._A;\n const K = this._parameters.K;\n const medoids = this._cluster_medoids;\n const N = this._N;\n\n // Precompute nearest and second nearest medoid for all points\n const cache = new Array(N);\n for (let i = 0; i < N; i++) {\n cache[i] = this._nearest_medoid(A[i], i);\n }\n\n let best_delta = 0;\n let best_swap = null; // { m_idx: index in medoids, x_idx: index in A }\n\n // For each non-medoid point j, evaluate swapping it with each medoid i\n const medoid_set = new Set(medoids);\n for (let j = 0; j < N; j++) {\n if (medoid_set.has(j)) continue;\n\n const x_j = A[j];\n const d_j = cache[j].distance_nearest;\n\n // deltaTD[i] will store the change in total distance if we swap medoid[i] with j\n const deltaTD = new Array(K).fill(-d_j);\n\n for (let o = 0; o < N; o++) {\n if (o === j) continue;\n const dist_o_j = this._get_distance(o, j, A[o], x_j);\n const { index_nearest: n, distance_nearest: d_n, distance_second: d_s } = cache[o];\n\n // If o is assigned to the current medoid being swapped out (n)\n deltaTD[n] += Math.min(dist_o_j, d_s) - d_n;\n\n // For all other medoids i != n, if j is closer to o than its current medoid\n if (dist_o_j < d_n) {\n for (let i = 0; i < K; i++) {\n if (i !== n) {\n deltaTD[i] += dist_o_j - d_n;\n }\n }\n }\n }\n\n // Find best medoid to swap with j\n for (let i = 0; i < K; i++) {\n if (deltaTD[i] < best_delta) {\n best_delta = deltaTD[i];\n best_swap = { m_idx: i, x_idx: j };\n }\n }\n }\n\n if (best_swap && best_delta < 0) {\n medoids[best_swap.m_idx] = best_swap.x_idx;\n this._cluster_medoids = medoids;\n return false; // not finished\n }\n\n return true; // finished\n }\n\n /**\n *\n * @param {number} i\n * @param {number} j\n * @param {Float64Array?} x_i\n * @param {Float64Array?} x_j\n * @returns\n */\n _get_distance(i, j, x_i = null, x_j = null) {\n if (i === j) return 0;\n const D = this._distance_matrix;\n const A = this._A;\n const metric = this._parameters.metric;\n let d_ij = D.entry(i, j);\n if (d_ij === 0) {\n d_ij = metric(x_i || A[i], x_j || A[j]);\n D.set_entry(i, j, d_ij);\n D.set_entry(j, i, d_ij);\n }\n return d_ij;\n }\n\n /**\n *\n * @param {Float64Array} x_j\n * @param {number} j\n * @returns\n */\n _nearest_medoid(x_j, j) {\n const medoids = this._cluster_medoids;\n const A = this._A;\n if (medoids.length === 0) {\n throw new Error(\"No medoids available. Initialization failed.\");\n }\n\n let d_n = Infinity;\n let n = -1;\n let d_s = Infinity;\n let s = -1;\n\n for (let i = 0; i < medoids.length; i++) {\n const m = medoids[i];\n const d = this._get_distance(j, m, x_j, A[m]);\n if (d < d_n) {\n d_s = d_n;\n s = n;\n d_n = d;\n n = i;\n } else if (d < d_s) {\n d_s = d;\n s = i;\n }\n }\n\n if (s === -1) s = n;\n\n return {\n distance_nearest: d_n,\n index_nearest: n,\n distance_second: d_s,\n index_second: s,\n };\n }\n\n _update_clusters() {\n const N = this._N;\n const A = this._A;\n for (let j = 0; j < N; j++) {\n const nearest = this._nearest_medoid(A[j], j);\n this._clusters[j] = nearest.index_nearest;\n }\n }\n\n /**\n * Computes `K` clusters out of the `matrix`.\n * @param {number} K - Number of clusters.\n * @param {number[]} cluster_medoids\n */\n init(K, cluster_medoids) {\n if (!K) K = this._parameters.K;\n if (!cluster_medoids) cluster_medoids = this._get_random_medoids(K);\n this._cluster_medoids = cluster_medoids;\n const max_iter = this._max_iter;\n let finish = false;\n let i = 0;\n do {\n finish = this._iteration();\n } while (!finish && ++i < max_iter);\n this._update_clusters();\n this._is_initialized = true;\n return this;\n }\n\n /**\n * Algorithm 3. FastPAM LAB: Linear Approximate BUILD initialization.\n *\n * @param {number} K - Number of clusters\n * @returns {number[]}\n */\n _get_random_medoids(K) {\n const N = this._N;\n const A = this._A;\n const indices = linspace(0, N - 1);\n const randomizer = this._randomizer;\n const n = Math.min(N, 10 + Math.ceil(Math.sqrt(N)));\n\n // Handle case where K >= N\n if (K >= N) {\n return indices.slice(0, N);\n }\n\n /** @type {number[]} */\n const medoids = [];\n\n // first medoid: select from a random sample of size n\n let best_j = -1;\n let min_td = Infinity;\n let S = randomizer.choice(indices, n);\n for (let j = 0; j < S.length; ++j) {\n let td = 0;\n const S_j = S[j];\n const x_j = A[S_j];\n for (let o = 0; o < S.length; ++o) {\n if (o === j) continue;\n td += this._get_distance(S_j, S[o], x_j, A[S[o]]);\n }\n if (td < min_td) {\n min_td = td;\n best_j = S_j;\n }\n }\n medoids.push(best_j);\n\n // other medoids: greedy additive selection (Algorithm LAB)\n for (let i = 1; i < K; ++i) {\n let best_idx = -1;\n let best_delta = Infinity;\n\n const remainingIndices = indices.filter((idx) => !medoids.includes(idx));\n if (remainingIndices.length === 0) break;\n\n S = randomizer.choice(remainingIndices, Math.min(n, remainingIndices.length));\n for (let j = 0; j < S.length; ++j) {\n let deltaTD = 0;\n const S_j = S[j];\n const x_j = A[S_j];\n\n // Estimate TD reduction on the sample S\n for (let o = 0; o < S.length; ++o) {\n if (o === j) continue;\n const S_o = S[o];\n const x_o = A[S_o];\n\n // Closest distance to current medoids\n let min_d_existing = Infinity;\n for (let m = 0; m < medoids.length; m++) {\n const d = this._get_distance(S_o, medoids[m], x_o, A[medoids[m]]);\n if (d < min_d_existing) min_d_existing = d;\n }\n\n const delta = this._get_distance(S_j, S_o, x_j, x_o) - min_d_existing;\n if (delta < 0) {\n deltaTD += delta;\n }\n }\n\n if (deltaTD < best_delta) {\n best_delta = deltaTD;\n best_idx = S_j;\n }\n }\n if (best_idx !== -1) {\n medoids.push(best_idx);\n }\n }\n return medoids;\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Clustering } from \"./Clustering.js\";\n\n/** @import { ParametersMeanShift } from \"./index.js\" */\n/** @import { InputType } from \"../index.js\" */\n\n/**\n * Mean Shift Clustering\n *\n * A non-parametric clustering technique that does not require prior knowledge of the\n * number of clusters. It identifies centers of density in the data.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class MeanShift extends Clustering {\n /** @type {number} */\n _bandwidth;\n /** @type {number} */\n _max_iter;\n /** @type {number} */\n _tolerance;\n /** @type {(dist: number) => number} */\n _kernel;\n /** @type {Matrix} */\n _points;\n /** @type {number[] | undefined} */\n _clusters;\n /** @type {number[][] | undefined} */\n _cluster_list;\n /**\n *\n * @param {InputType} points\n * @param {Partial} parameters\n */\n constructor(points, parameters = {}) {\n super(\n points,\n /** @type {ParametersMeanShift} */ (\n Object.assign({ seed: 1212, metric: euclidean, bandwidth: 0, kernel: \"gaussian\" }, parameters)\n ),\n );\n\n // Ensure bandwidth is positive\n this._bandwidth = parameters.bandwidth ?? this._compute_bandwidth(this._matrix);\n this._max_iter = parameters.max_iter ?? Math.max(10, Math.floor(10 * Math.log10(this._N)));\n this._tolerance = parameters.tolerance ?? 1e-3;\n const kernel_param = parameters.kernel ?? \"gaussian\";\n // If kernel is a string, map to function\n if (typeof kernel_param === \"string\") {\n if (kernel_param === \"flat\") {\n this._kernel = (dist) => (dist <= this._bandwidth ? 1 : 0);\n } else {\n // gaussian (default)\n this._kernel = (dist) => Math.exp(-(dist * dist) / (2 * this._bandwidth * this._bandwidth));\n }\n } else {\n // custom function\n this._kernel = kernel_param;\n }\n\n // Copy points to a mutable matrix\n this._points = this._matrix.clone();\n\n this._mean_shift();\n this._assign_clusters();\n }\n\n // Helper to compute bandwidth if not provided\n /**\n * @param {Matrix} matrix\n * @returns {number}\n */\n _compute_bandwidth(matrix) {\n const N = matrix.shape[0];\n //const D = matrix.shape[1];\n // Compute average pairwise distance\n let totalDist = 0;\n for (let i = 0; i < N; ++i) {\n const row_i = matrix.row(i);\n for (let j = i + 1; j < N; ++j) {\n const row_j = matrix.row(j);\n const dist = this._parameters.metric(row_i, row_j);\n totalDist += dist;\n }\n }\n const avgDist = totalDist / ((N * (N - 1)) / 2);\n // Use a fraction of avgDist as bandwidth\n return avgDist / 2;\n }\n\n // Compute kernel weight\n /**\n * @param {number} dist\n * @returns {number}\n */\n _kernel_weight(dist) {\n return this._kernel(dist);\n }\n\n // Perform mean shift iterations\n _mean_shift() {\n const N = this._N;\n const D = this._D;\n const points = this._points;\n const metric = this._parameters.metric;\n //const bandwidth = this._bandwidth;\n const kernel = this._kernel_weight.bind(this);\n const tolerance = this._tolerance;\n\n for (let iter = 0; iter < this._max_iter; ++iter) {\n let max_shift = 0;\n // For each point compute shift\n for (let i = 0; i < N; ++i) {\n const row_i = points.row(i);\n let sum_weights = 0;\n const weighted_sum = new Float64Array(D);\n for (let j = 0; j < N; ++j) {\n const row_j = points.row(j);\n const dist = metric(row_i, row_j);\n const weight = kernel(dist);\n sum_weights += weight;\n for (let d = 0; d < D; ++d) {\n weighted_sum[d] += weight * row_j[d];\n }\n }\n if (sum_weights === 0) {\n // No neighbors within kernel, shift is zero\n //const shift = new Float64Array(D);\n // Compute shift magnitude\n const shift_norm = Math.sqrt(weighted_sum.reduce((acc, v) => acc + v * v, 0));\n max_shift = Math.max(max_shift, shift_norm);\n } else {\n const shift = new Float64Array(D);\n for (let d = 0; d < D; ++d) {\n shift[d] = weighted_sum[d] / sum_weights - row_i[d];\n }\n const shift_norm = Math.sqrt(shift.reduce((acc, v) => acc + v * v, 0));\n max_shift = Math.max(max_shift, shift_norm);\n // Update point\n for (let d = 0; d < D; ++d) {\n row_i[d] += shift[d];\n }\n }\n }\n if (max_shift < tolerance) {\n // Converged\n break;\n }\n }\n }\n\n // After convergence, assign clusters based on nearest mode\n _assign_clusters() {\n const N = this._N;\n const metric = this._parameters.metric;\n const bandwidth = this._bandwidth;\n\n // Group points that converged to the same mode\n // Two points are in the same mode if they're within bandwidth/2 of each other\n const mode_threshold = bandwidth * 0.5;\n /** @type {number[][]} */\n const modes = []; // Each mode contains indices of points in that mode\n const point_to_mode = new Array(N).fill(-1);\n\n for (let i = 0; i < N; ++i) {\n if (point_to_mode[i] !== -1) continue; // Already assigned to a mode\n\n const row_i = this._points.row(i);\n const mode = [i];\n point_to_mode[i] = modes.length;\n\n // Find all points close to this mode\n for (let j = i + 1; j < N; ++j) {\n if (point_to_mode[j] !== -1) continue;\n\n const row_j = this._points.row(j);\n const dist = metric(row_i, row_j);\n\n if (dist < mode_threshold) {\n mode.push(j);\n point_to_mode[j] = modes.length;\n }\n }\n\n modes.push(mode);\n }\n\n // Build final clusters - each mode becomes a cluster\n /** @type {number[][]} */\n const clusters = [];\n const cluster_ids = new Array(N).fill(-1);\n\n for (let mode_idx = 0; mode_idx < modes.length; ++mode_idx) {\n const mode = modes[mode_idx];\n clusters.push([...mode]);\n for (const point_idx of mode) {\n cluster_ids[point_idx] = mode_idx;\n }\n }\n\n this._clusters = cluster_ids;\n this._cluster_list = clusters;\n }\n\n /**\n * @returns {number[][]}\n */\n get_clusters() {\n // Ensure algorithm has been run\n if (!this._cluster_list) {\n this._mean_shift();\n this._assign_clusters();\n }\n return /** @type {number[][]} */ (this._cluster_list);\n }\n\n /**\n *\n * @returns {number[]}\n */\n get_cluster_list() {\n if (!this._clusters) {\n this._mean_shift();\n this._assign_clusters();\n }\n return /** @type {number[]} */ (this._clusters);\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Clustering } from \"./Clustering.js\";\n\n/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersOptics } from \"./index.js\" */\n\n/** @typedef {Object} DBEntry\n * @property {Float64Array} element\n * @property {number} index\n * @property {number} [reachability_distance]\n * @property {boolean} processed\n * @property {DBEntry[]} [neighbors]\n */\n\n/**\n * OPTICS (Ordering Points To Identify the Clustering Structure)\n *\n * A density-based clustering algorithm that extends DBSCAN. It handles clusters of varying\n * densities and produces a reachability plot that can be used to extract clusters.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class OPTICS extends Clustering {\n /**\n * **O**rdering **P**oints **T**o **I**dentify the **C**lustering **S**tructure.\n *\n * @param {InputType} points - The data.\n * @param {Partial} [parameters={}]\n * @see {@link https://www.dbs.ifi.lmu.de/Publikationen/Papers/OPTICS.pdf}\n * @see {@link https://en.wikipedia.org/wiki/OPTICS_algorithm}\n */\n constructor(points, parameters = {}) {\n super(\n points,\n /** @type {ParametersOptics} */ (\n Object.assign({ epsilon: 1, min_points: 4, metric: euclidean }, parameters)\n ),\n );\n const matrix = this._matrix;\n /**\n * @private\n * @type {DBEntry[]}\n */\n this._ordered_list = [];\n const ordered_list = this._ordered_list;\n /** @type {number[][]} */\n this._clusters = [];\n const clusters = this._clusters;\n\n const N = this._N;\n\n /**\n * @private\n * @type {DBEntry[]}\n */\n this._DB = new Array(N).fill(0).map((_, i) => {\n return {\n element: matrix.row(i),\n index: i,\n reachability_distance: undefined,\n processed: false,\n };\n });\n const DB = this._DB;\n\n this._cluster_index = 0;\n let cluster_index = this._cluster_index;\n\n for (const p of DB) {\n if (p.processed) continue;\n p.neighbors = this._get_neighbors(p);\n p.processed = true;\n clusters.push([p.index]);\n cluster_index = clusters.length - 1;\n ordered_list.push(p);\n if (this._core_distance(p) !== undefined) {\n const seeds = new Heap(null, (d) => d.reachability_distance, \"min\");\n this._update(p, seeds);\n this._expand_cluster(seeds, clusters[cluster_index]);\n }\n }\n }\n\n /**\n * @private\n * @param {DBEntry} p - A point of the data.\n * @returns {DBEntry[]} An array consisting of the `epsilon`-neighborhood of `p`.\n */\n _get_neighbors(p) {\n if (p?.neighbors) return p.neighbors;\n const DB = this._DB;\n const metric = this._parameters.metric;\n const epsilon = this._parameters.epsilon;\n const neighbors = [];\n for (const q of DB) {\n if (q.index === p.index) continue;\n if (metric(p.element, q.element) <= epsilon) {\n neighbors.push(q);\n }\n }\n return neighbors;\n }\n\n /**\n * @private\n * @param {DBEntry} p - A point of `matrix`.\n * @returns {number|undefined} The distance to the `min_points`-th nearest point of `p`, or undefined if the\n * `epsilon`-neighborhood has fewer elements than `min_points`.\n */\n _core_distance(p) {\n const min_points = this._parameters.min_points;\n const metric = this._parameters.metric;\n // Need min_points - 1 other points plus the point itself\n if (!p.neighbors || p.neighbors.length < min_points - 1) {\n return undefined;\n }\n // Sort neighbors by distance to find the MinPts-th closest\n const sortedNeighbors = p.neighbors.toSorted(\n (a, b) => metric(p.element, a.element) - metric(p.element, b.element),\n );\n // MinPts-th closest is at index min_points - 2 (0-indexed, excluding p itself)\n return metric(p.element, sortedNeighbors[min_points - 2].element);\n }\n\n /**\n * Updates the reachability distance of the points.\n *\n * @private\n * @param {DBEntry} p\n * @param {Heap} seeds\n */\n _update(p, seeds) {\n const metric = this._parameters.metric;\n const core_distance = this._core_distance(p);\n // If p is not a core point, don't update seeds\n if (core_distance === undefined) {\n return;\n }\n const neighbors = this._get_neighbors(p); //p.neighbors;\n for (const q of neighbors) {\n if (q.processed) continue;\n const new_reachability_distance = Math.max(core_distance, metric(p.element, q.element));\n //if (q.reachability_distance == undefined) { // q is not in seeds\n if (seeds.raw_data().findIndex((d) => d.element === q) < 0) {\n q.reachability_distance = new_reachability_distance;\n seeds.push(q);\n } else {\n // q is in seeds\n if (new_reachability_distance < (q.reachability_distance ?? Infinity)) {\n q.reachability_distance = new_reachability_distance;\n seeds = Heap.heapify(seeds.data(), (d) => d.reachability_distance ?? Infinity, \"min\"); // seeds change key =/\n }\n }\n }\n }\n\n /**\n * Expands the `cluster` with points in `seeds`.\n *\n * @private\n * @param {Heap} seeds\n * @param {number[]} cluster\n */\n _expand_cluster(seeds, cluster) {\n const ordered_list = this._ordered_list;\n while (!seeds.empty) {\n const q = /** @type {{ element: DBEntry, value: number}} */ (seeds.pop()).element;\n q.neighbors = this._get_neighbors(q);\n q.processed = true;\n cluster.push(q.index);\n ordered_list.push(q);\n if (this._core_distance(q) !== undefined) {\n this._update(q, seeds);\n // Recursive call removed - while loop handles iteration correctly\n }\n }\n }\n\n /**\n * Returns an array of clusters.\n *\n * @returns {number[][]} Array of clusters with the indices of the rows in given `matrix`.\n */\n get_clusters() {\n const clusters = [];\n const outliers = [];\n const min_points = this._parameters.min_points;\n for (const cluster of this._clusters) {\n if (cluster.length < min_points) {\n outliers.push(...cluster);\n } else {\n clusters.push(cluster);\n }\n }\n clusters.push(outliers);\n return clusters;\n }\n\n /**\n * @returns {number[]} Returns an array, where the ith entry defines the cluster affirmation of the ith point of\n * given data. (-1 stands for outlier)\n */\n get_cluster_list() {\n const N = this._matrix.shape[0];\n /** @type {number[]} */\n const result = new Array(N).fill(0);\n const clusters = this.get_clusters();\n for (let i = 0, n = clusters.length; i < n; ++i) {\n const cluster = clusters[i];\n for (const index of cluster) {\n result[index] = i < n - 1 ? i : -1;\n }\n }\n return result;\n }\n}\n","import { euclidean, euclidean_squared } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport { KMeans } from \"./KMeans.js\";\n\n/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersXMeans } from \"./index.js\" */\n\n/**\n * @typedef SplitResult\n * @property {number} index - Index of the cluster being split\n * @property {number} bic_parent - BIC score of the parent cluster\n * @property {number} bic_children - BIC score of the split children\n * @property {number[][]} child_clusters - Clusters after splitting\n * @property {Float64Array[]} child_centroids - Centroids of child clusters\n */\n\n/**\n * @typedef CandidateResult\n * @property {KMeans} kmeans - The KMeans instance for this K\n * @property {number} score - BIC score\n */\n\n/**\n * X-Means Clustering\n *\n * An extension of K-Means that automatically determines the number of clusters (K)\n * using the Bayesian Information Criterion (BIC).\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class XMeans extends Clustering {\n /**\n * XMeans clustering algorithm that automatically determines the optimal number of clusters.\n *\n * X-Means extends K-Means by starting with a minimum number of clusters and iteratively\n * splitting clusters to improve the Bayesian Information Criterion (BIC).\n *\n * Algorithm:\n * 1. Start with K_min clusters using KMeans\n * 2. For each cluster, try splitting it into 2 sub-clusters\n * 3. If BIC improves after splitting, keep the split\n * 4. Run KMeans again with all (old + new) centroids\n * 5. Repeat until K_max is reached or no more improvements\n *\n * @param {InputType} points - The data points to cluster\n * @param {Partial} [parameters={}] - Configuration parameters\n * @see {@link https://www.cs.cmu.edu/~dpelleg/download/xmeans.pdf}\n * @see {@link https://github.com/annoviko/pyclustering/blob/master/pyclustering/cluster/xmeans.py}\n * @see {@link https://github.com/haifengl/smile/blob/master/core/src/main/java/smile/clustering/XMeans.java}\n */\n constructor(points, parameters = {}) {\n const defaults = {\n K_max: 10,\n K_min: 2,\n metric: euclidean,\n seed: 1212,\n min_cluster_size: 35,\n tolerance: 0.001,\n };\n super(points, /** @type {ParametersXMeans} */ (Object.assign(defaults, parameters)));\n this._randomizer = new Randomizer(this._parameters.seed);\n\n /** @type {KMeans | null} */\n this._best_kmeans = null;\n\n // Run XMeans algorithm\n this._run();\n }\n\n /**\n * Run the XMeans algorithm\n *\n * @private\n */\n _run() {\n /** @type {Map} */\n const candidates = new Map();\n const A = this._matrix;\n\n // Initialize with K_min clusters\n let current_kmeans = new KMeans(this._points, {\n K: this._parameters.K_min,\n metric: this._parameters.metric,\n seed: this._parameters.seed,\n });\n\n let K = this._parameters.K_min;\n\n candidates.set(K, {\n kmeans: current_kmeans,\n score: -Infinity,\n });\n\n // Iteratively improve clustering\n while (K < this._parameters.K_max) {\n const clusters = current_kmeans.get_clusters();\n const centroids = current_kmeans.centroids;\n\n // Try splitting each cluster\n /** @type {SplitResult[]} */\n const split_results = [];\n\n for (let j = 0; j < clusters.length; ++j) {\n const cluster = clusters[j];\n\n // Skip small clusters - need enough points for reliable BIC\n if (cluster.length < this._parameters.min_cluster_size) {\n continue;\n }\n\n // Get subset data for this cluster\n /** @type {number[][]} */\n const subset_points = cluster.map((idx) => {\n const row = A.row(idx);\n return Array.from(row);\n });\n\n // Calculate BIC for parent (single cluster)\n const parent_bic = this._bic([cluster], [centroids[j]]);\n\n // Run KMeans with K=2 on subset\n const subset_kmeans = new KMeans(subset_points, {\n K: 2,\n metric: this._parameters.metric,\n seed: this._randomizer.seed,\n });\n\n const child_clusters_local = subset_kmeans.get_clusters();\n const child_centroids = subset_kmeans.centroids;\n\n // Map local indices back to global indices\n /** @type {number[][]} */\n const child_clusters_global = child_clusters_local.map((local_cluster) =>\n local_cluster.map((local_idx) => cluster[local_idx]),\n );\n\n // Calculate BIC for children (split into 2 clusters)\n const children_bic = this._bic(child_clusters_global, child_centroids);\n\n split_results.push({\n index: j,\n bic_parent: parent_bic,\n bic_children: children_bic,\n child_clusters: child_clusters_global,\n child_centroids: child_centroids,\n });\n }\n\n // Keep all splits that improve BIC (BIC_children > BIC_parent)\n /** @type {SplitResult[]} */\n const accepted_splits = split_results.filter((result) => result.bic_children > result.bic_parent);\n\n // If no splits improve BIC, we're done\n if (accepted_splits.length === 0) {\n break;\n }\n\n // Build new centroids array: keep non-split centroids + add split centroids\n /** @type {Float64Array[]} */\n const new_centroids = [];\n const split_indices = new Set();\n\n // Sort accepted splits by improvement (descending)\n accepted_splits.sort((a, b) => b.bic_children - b.bic_parent - (a.bic_children - a.bic_parent));\n\n for (const split of accepted_splits) {\n if (centroids.length + split_indices.size + 1 <= this._parameters.K_max) {\n split_indices.add(split.index);\n } else {\n break;\n }\n }\n\n for (let i = 0; i < centroids.length; ++i) {\n if (split_indices.has(i)) {\n // This cluster was split - add both child centroids\n const split_result = accepted_splits.find((s) => s.index === i);\n if (split_result) {\n new_centroids.push(...split_result.child_centroids);\n }\n } else {\n // This cluster wasn't split - keep its centroid\n new_centroids.push(centroids[i]);\n }\n }\n\n // Run KMeans on full dataset with new centroids as initialization\n // This is crucial - we need to reassign all points to all clusters\n const newK = new_centroids.length;\n\n // Create a new KMeans instance with K set to new number of clusters\n current_kmeans = new KMeans(this._matrix, {\n K: newK,\n metric: this._parameters.metric,\n seed: this._randomizer.seed,\n initial_centroids: new_centroids,\n });\n\n // Store the candidate with the BIC of the FULL dataset\n candidates.set(newK, {\n kmeans: current_kmeans,\n score: this._bic(current_kmeans.get_clusters(), current_kmeans.centroids),\n });\n\n K = newK;\n }\n\n // Select best candidate based on BIC score\n this._best_kmeans = this._select_best_candidate(candidates);\n }\n\n /**\n * Select the best candidate based on BIC score\n *\n * @private\n * @param {Map} candidates\n * @returns {KMeans}\n */\n _select_best_candidate(candidates) {\n if (candidates.size === 0) {\n throw new Error(\"No candidates found\");\n }\n\n const first_candidate = candidates.get(this._parameters.K_min);\n if (!first_candidate) {\n throw new Error(\"Missing initial candidate\");\n }\n\n let best_score = first_candidate.score;\n /** @type {KMeans} */\n let best_kmeans = first_candidate.kmeans;\n\n for (const candidate of candidates.values()) {\n if (candidate.score > best_score) {\n best_score = candidate.score;\n best_kmeans = candidate.kmeans;\n }\n }\n\n return best_kmeans;\n }\n\n /**\n * Calculate Bayesian Information Criterion for a set of clusters.\n *\n * Uses Kass's formula for BIC calculation:\n * BIC(θ) = L(D) - 0.5 * p * ln(N)\n *\n * Where:\n * - L(D) is the log-likelihood of the data\n * - p is the number of free parameters: (K-1) + D*K + 1\n * - N is the total number of points\n *\n * @private\n * @param {number[][]} clusters - Array of clusters with point indices\n * @param {Float64Array[]} centroids - Array of centroids\n * @returns {number} BIC score (higher is better)\n */\n _bic(clusters, centroids) {\n const A = this._matrix;\n const D = this._D;\n const K = centroids.length;\n\n let total_variance = 0;\n let N = 0;\n\n // Calculate total variance (sum of squared distances)\n for (let i = 0; i < K; ++i) {\n const cluster = clusters[i];\n const centroid = centroids[i];\n N += cluster.length;\n\n for (let j = 0; j < cluster.length; ++j) {\n const point_idx = cluster[j];\n const point = A.row(point_idx);\n // Sum of squared distances (variance term)\n total_variance += euclidean_squared(centroid, point);\n }\n }\n\n // Not enough points for meaningful BIC\n if (N <= K) {\n return -Infinity;\n }\n\n // Estimate variance (ML estimate)\n const variance = total_variance / (N - K);\n\n // Handle case of zero variance (all points identical)\n if (variance <= 0) {\n return -Infinity;\n }\n\n // Number of free parameters: (K-1) cluster weights + K*D centroid coordinates + 1 variance\n const p = K - 1 + D * K + 1;\n\n // Calculate log-likelihood\n let log_likelihood = 0;\n const log_2pi = Math.log(2 * Math.PI);\n\n for (let i = 0; i < K; ++i) {\n const n = clusters[i].length;\n if (n <= 1) continue;\n\n // Log-likelihood for cluster i\n const cluster_log_likelihood =\n n * Math.log(n / N) - 0.5 * n * log_2pi - 0.5 * n * D * Math.log(variance) - 0.5 * (n - 1);\n\n log_likelihood += cluster_log_likelihood;\n }\n\n // BIC = log_likelihood - 0.5 * p * ln(N)\n return log_likelihood - 0.5 * p * Math.log(N);\n }\n\n /**\n * Get the computed clusters\n *\n * @returns {number[][]} Array of clusters, each containing indices of points\n */\n get_clusters() {\n if (!this._best_kmeans) {\n throw new Error(\"XMeans has not been run\");\n }\n return this._best_kmeans.get_clusters();\n }\n\n /** @returns {number[]} The cluster list */\n get_cluster_list() {\n if (!this._best_kmeans) {\n throw new Error(\"XMeans has not been run\");\n }\n return this._best_kmeans.get_cluster_list();\n }\n\n /**\n * Get the final centroids\n *\n * @returns {Float64Array[]} Array of centroids\n */\n get centroids() {\n if (!this._best_kmeans) {\n throw new Error(\"XMeans has not been run\");\n }\n return this._best_kmeans.centroids;\n }\n\n /**\n * Get the optimal number of clusters found\n *\n * @returns {number} The number of clusters\n */\n get k() {\n if (!this._best_kmeans) {\n throw new Error(\"XMeans has not been run\");\n }\n return this._best_kmeans.k;\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { Randomizer } from \"../util/index.js\";\n\n/** @import {InputType} from \"../index.js\" */\n\n/**\n * @abstract\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n *\n * Base class for all Dimensionality Reduction (DR) algorithms.\n *\n * Provides a common interface for parameters management, data initialization,\n * and transformation (both synchronous and asynchronous).\n *\n * @class\n */\nexport class DR {\n /** @type {number} */\n _D;\n /** @type {number} */\n _N;\n /** @type {Randomizer} */\n _randomizer;\n /** @type {boolean} */\n _is_initialized;\n\n /**\n * Takes the default parameters and seals them, remembers the type of input `X`, and initializes the random number\n * generator.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Para} default_parameters - Object containing default parameterization of the DR method.\n * @param {Partial} parameters - Object containing parameterization of the DR method to override defaults.\n */\n constructor(X, default_parameters, parameters = {}) {\n /** @type {T} */\n this.__input = X;\n\n /** @type {Para} */\n this._parameters = /** @type {Para} */ Object.seal({\n ...default_parameters,\n ...parameters,\n });\n /** @type {\"array\" | \"matrix\" | \"typed\"} */\n this._type;\n /** @type {Matrix} */\n this.X;\n /** @type {Matrix} */\n this.Y;\n\n if (Array.isArray(X)) {\n if (X[0] instanceof Float64Array) {\n this._type = \"typed\";\n } else {\n this._type = \"array\";\n }\n this.X = Matrix.from(X);\n } else if (X instanceof Matrix) {\n this._type = \"matrix\";\n this.X = X;\n } else {\n throw new Error(\"No valid type for X!\");\n }\n const [N, D] = this.X.shape;\n this._N = N;\n this._D = D;\n this._randomizer = new Randomizer(this._parameters.seed);\n this._is_initialized = false;\n }\n\n /**\n * Get all Parameters.\n * @overload\n * @returns {Para}\n */\n /**\n * Get value of given parameter.\n * @template {keyof Para} K\n * @overload\n * @param {K} name - Name of the parameter.\n * @returns {Para[K]}\n */\n /**\n * Set value of given parameter.\n * @template {keyof Para} K\n * @overload\n * @param {K} name - Name of the parameter.\n * @param {Para[K]} value - Value of the parameter to set.\n * @returns {this}\n */\n /**\n * @param {keyof Para} [name] - Name of the parameter. If null, returns all parameters as an Object.\n * @param {Para[keyof Para]} [value] - Value of the parameter to set. If name is set and value is not given, returns the\n * current value.\n * @returns {Para | Para[keyof Para] | this} On setting a parameter, returns the DR object. If name is set and value is not\n * given, returns the parameter value. If name is null, returns all parameters. On setting a parameter, this\n * function returns the DR object. If `name` is set and `value == null` then return actual parameter value. If\n * `name` is not given, then returns all parameters as an Object.\n * @example\n * ```js\n * const DR = new druid.TSNE(X, {d: 3}); // creates a new DR object, with parameter for `d = 3`.\n * DR.parameter(\"d\"); // returns 3\n * DR.parameter(\"d\", 2); // sets parameter `d` to 2 and returns `DR`.\n * ```\n *\n */\n parameter(name, value) {\n if (name === undefined && value === undefined) {\n return Object.assign({}, this._parameters);\n }\n if (name && !Object.hasOwn(this._parameters, name)) {\n throw new Error(`${String(name)} is not a valid parameter!`);\n }\n if (name && value !== undefined) {\n this._parameters[name] = value;\n this._is_initialized = false;\n return this;\n } else if (name) {\n return this._parameters[name];\n }\n throw new Error(\"Should not happen!\");\n }\n\n /**\n * Computes the projection.\n *\n * @abstract\n * @param {...unknown} args\n * @returns {T} The projection.\n */\n transform(...args) {\n args;\n this.check_init();\n return this.projection;\n }\n\n /**\n * Computes the projection.\n *\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.\n * @returns {T} The dimensionality reduced dataset.\n */\n static transform(X, parameters, ...args) {\n args;\n const dr = new DR(X, parameters, parameters);\n return /** @type {T} */ (dr.transform());\n }\n\n /**\n * Computes the projection.\n *\n * @abstract\n * @param {...unknown} args\n * @returns {Generator} The intermediate steps of the projection.\n */\n *generator(...args) {\n const R = this.transform(...args);\n yield R;\n return R;\n }\n\n /**\n * Computes the projection.\n *\n * @template {{ seed?: number }} Para\n * @param {InputType} X\n * @param {Para} parameters\n * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.\n * @returns {Generator} A generator yielding the intermediate steps of the dimensionality\n * reduction method.\n */\n static *generator(X, parameters, ...args) {\n const dr = new DR(X, parameters, parameters);\n const generator = dr.generator(...args);\n let result;\n do {\n result = generator.next();\n yield result.value;\n } while (!result.done);\n\n return result.value;\n }\n\n /**\n * @abstract\n * @param {...unknown} args\n */\n init(...args) {\n args;\n }\n\n /**\n * If the respective DR method has an `init` function, call it before `transform`.\n *\n * @returns {DR}\n */\n check_init() {\n if (!this._is_initialized && typeof this.init === \"function\") {\n this.init();\n this._is_initialized = true;\n }\n return this;\n }\n\n /** @returns {T} The projection in the type of input `X`. */\n get projection() {\n if (Object.hasOwn(this, \"Y\")) {\n this.check_init();\n //return this._type === \"matrix\" ? this.Y : this.Y.to2dArray();\n if (this._type === \"matrix\") {\n return /** @type {T} */ (/** @type {any} */ (this.Y));\n } else if (this._type === \"typed\") {\n return /** @type {T} */ (/** @type {any} */ (this.Y.to2dArray()));\n } else {\n return /** @type {T} */ (/** @type {any} */ (this.Y.asArray()));\n }\n } else {\n throw new Error(\"The dataset is not transformed yet!\");\n }\n }\n\n /**\n * Computes the projection.\n *\n * @param {...unknown} args - Arguments the transform method of the respective DR method takes.\n * @returns {Promise} The dimensionality reduced dataset.\n */\n async transform_async(...args) {\n return this.transform(...args);\n }\n\n /**\n * Computes the projection.\n *\n * @template {{ seed?: number }} Para\n * @param {InputType} X\n * @param {Para} parameters\n * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.\n * @returns {Promise} A promise yielding the dimensionality reduced dataset.\n */\n static async transform_async(X, parameters, ...args) {\n return DR.transform(X, parameters, ...args);\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersFASTMAP } from \"./index.js\"; */\n\n/**\n * FastMap algorithm for dimensionality reduction.\n *\n * A very fast algorithm for projecting high-dimensional data into a lower-dimensional\n * space while preserving pairwise distances. It works similarly to PCA but uses\n * only a subset of the data to find projection axes.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class FASTMAP extends DR {\n /**\n * FastMap: a fast algorithm for indexing, data-mining and visualization of traditional and multimedia datasets.\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://doi.org/10.1145/223784.223812}\n */\n constructor(X, parameters) {\n super(X, { d: 2, metric: euclidean, seed: 1212 }, parameters);\n }\n\n /**\n * Chooses two points which are the most distant in the actual projection.\n *\n * @private\n * @param {(a: number, b: number) => number} dist\n * @returns {[number, number, number]} An array consisting of first index, second index, and distance between the\n * two points.\n */\n _choose_distant_objects(dist) {\n const X = this.X;\n const N = X.shape[0];\n let a_index = this._randomizer.random_int % N;\n /** @type {number | null} */\n let b_index = null;\n let max_dist = -Infinity;\n for (let i = 0; i < N; ++i) {\n const d_ai = dist(a_index, i);\n if (d_ai > max_dist) {\n max_dist = d_ai;\n b_index = i;\n }\n }\n if (b_index === null) throw new Error(\"should not happen!\");\n max_dist = -Infinity;\n for (let i = 0; i < N; ++i) {\n const d_bi = dist(b_index, i);\n if (d_bi > max_dist) {\n max_dist = d_bi;\n a_index = i;\n }\n }\n return [a_index, b_index, max_dist];\n }\n\n /**\n * Computes the projection.\n *\n * @returns {T} The `d`-dimensional projection of the data matrix `X`.\n */\n transform() {\n const X = this.X;\n const N = X.shape[0];\n const d = /** @type {number} */ (this._parameters.d);\n const metric = /** @type {typeof euclidean} */ (this._parameters.metric);\n const Y = new Matrix(N, d, 0);\n /** @type {(a: number, b: number) => number} */\n let dist = (a, b) => metric(X.row(a), X.row(b));\n\n for (let _col = 0; _col < d; ++_col) {\n const old_dist = dist;\n // choose pivot objects\n const [a_index, b_index, d_ab] = this._choose_distant_objects(dist);\n if (d_ab !== 0) {\n // project the objects on the line (O_a, O_b)\n for (let i = 0; i < N; ++i) {\n const d_ai = dist(a_index, i);\n const d_bi = dist(b_index, i);\n const y_i = (d_ai ** 2 + d_ab ** 2 - d_bi ** 2) / (2 * d_ab);\n Y.set_entry(i, _col, y_i);\n }\n // consider the projections of the objects on a\n // hyperplane perpendicluar to the line (a, b);\n // the distance function D'() between two\n // projections is given by Eq.4\n dist = (a, b) => Math.sqrt(old_dist(a, b) ** 2 - (Y.entry(a, _col) - Y.entry(b, _col)) ** 2);\n }\n }\n // return embedding.\n this.Y = Y;\n return this.projection;\n }\n\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new FASTMAP(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new FASTMAP(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new FASTMAP(X, parameters);\n return dr.transform_async();\n }\n}\n","/**\n * Base class for all K-Nearest Neighbors (KNN) search algorithms.\n *\n * Provides a common interface for elements management and search operations.\n *\n * @abstract\n * @category KNN\n * @template {number[] | Float64Array} T - Type of elements\n * @template {Object} Para - Type of parameters\n * @class\n */\nexport class KNN {\n /** @type {T[]} */\n _elements;\n /** @type {Para} */\n _parameters;\n /** @type {\"typed\" | \"array\"} */\n _type;\n\n /**\n * @param {T[]} elements\n * @param {Para} parameters\n */\n constructor(elements, parameters) {\n if (elements.length === 0) throw new Error(\"Elements needs to contain at least one element!\");\n if (elements[0] instanceof Float64Array) {\n this._type = \"typed\";\n } else {\n this._type = \"array\";\n }\n this._parameters = parameters;\n this._elements = elements;\n }\n\n /**\n * @abstract\n * @param {T} t\n * @param {number} k\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search(t, k) {\n t;\n k;\n throw new Error(\"The function search must be implemented!\");\n }\n\n /**\n * @abstract\n * @param {number} i\n * @param {number} k\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i, k) {\n i;\n k;\n throw new Error(\"The function search_by_index must be implemented!\");\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersAnnoy } from \"./index.js\" */\n\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} AnnoyNode\n * @property {boolean} isLeaf - Whether this is a leaf node\n * @property {number[]} indices - Indices of points in this node (leaf) or children (internal)\n * @property {number[]} normal - Hyperplane normal vector (internal nodes only)\n * @property {number} offset - Hyperplane offset (internal nodes only)\n * @property {AnnoyNode | null} left - Left child (internal nodes only)\n * @property {AnnoyNode | null} right - Right child (internal nodes only)\n */\n\n/**\n * Annoy-style (Approximate Nearest Neighbors Oh Yeah) implementation using Random Projection Trees.\n *\n * This implementation builds multiple random projection trees where each tree randomly selects\n * two points and splits the space based on a hyperplane equidistant between them.\n *\n * Key features:\n * - Multiple random projection trees for better recall\n * - Each tree uses random hyperplanes for splitting\n * - Priority queue search for better recall\n * - Combines results from all trees\n *\n * Best suited for:\n * - High-dimensional data\n * - Approximate nearest neighbor search\n * - Large datasets\n * - When high recall is needed with approximate methods\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link https://github.com/spotify/annoy}\n * @see {@link https://erikbern.com/2015/09/24/nearest-neighbors-and-vector-models-epilogue-curse-of-dimensionality.html}\n */\nexport class Annoy extends KNN {\n /**\n * Creates a new Annoy-style index with random projection trees.\n *\n * @param {T[]} elements - Elements to index\n * @param {ParametersAnnoy} [parameters={}] - Configuration parameters\n */\n constructor(\n elements,\n parameters = {\n metric: euclidean,\n numTrees: 10,\n maxPointsPerLeaf: 10,\n seed: 1212,\n },\n ) {\n // Handle empty initialization - use dummy element\n const hasElements = elements && elements.length > 0;\n const firstElement = /** @type {T} */ (hasElements ? elements[0] : new Float64Array([0]));\n\n super([firstElement], parameters);\n\n this._metric = this._parameters.metric ?? euclidean;\n this._numTrees = this._parameters.numTrees ?? 10;\n this._maxPointsPerLeaf = this._parameters.maxPointsPerLeaf ?? 10;\n this._seed = this._parameters.seed ?? 1212;\n this._randomizer = new Randomizer(this._seed);\n\n /**\n * @private\n * @type {AnnoyNode[]}\n */\n this._trees = [];\n\n // Build trees\n if (hasElements) {\n // Reset elements and rebuild properly\n /** @type {T[]} */\n this._elements = [];\n this._trees = [];\n this.add(elements);\n }\n }\n\n /**\n * Get the number of trees in the index.\n * @returns {number}\n */\n get num_trees() {\n return this._trees.length;\n }\n\n /**\n * Get the total number of nodes in all trees.\n * @returns {number}\n */\n get num_nodes() {\n let total = 0;\n for (const tree of this._trees) {\n total += this._countNodes(tree);\n }\n return total;\n }\n\n /**\n * @private\n * @param {any} node\n * @returns {number}\n */\n _countNodes(node) {\n if (!node) return 0;\n return 1 + this._countNodes(node.left) + this._countNodes(node.right);\n }\n\n /**\n * Add elements to the Annoy index.\n * @param {T[]} elements\n * @returns {this}\n */\n add(elements) {\n // Extend elements array\n this._elements = this._elements.concat(elements);\n\n // Rebuild all trees with new elements\n this._trees = [];\n this._buildTrees();\n\n return this;\n }\n\n /**\n * Build all random projection trees.\n * @private\n */\n _buildTrees() {\n const elements = this._elements;\n const n = elements.length;\n\n for (let t = 0; t < this._numTrees; t++) {\n // Create index array for this tree\n const indices = Array.from({ length: n }, (_, i) => i);\n const tree = this._buildTreeRecursive(indices);\n this._trees.push(tree);\n }\n }\n\n /**\n * Recursively build a random projection tree.\n * @private\n * @param {number[]} indices - Indices of elements to include\n * @returns {AnnoyNode}\n */\n _buildTreeRecursive(indices) {\n const elements = this._elements;\n\n // Base case: small enough to be a leaf\n if (indices.length <= this._maxPointsPerLeaf) {\n return {\n isLeaf: true,\n indices: indices,\n normal: [],\n offset: 0,\n left: null,\n right: null,\n };\n }\n\n // Select two random points to define the splitting hyperplane\n const idx1 = indices[Math.floor(this._randomizer.random * indices.length)];\n const idx2 = indices[Math.floor(this._randomizer.random * indices.length)];\n\n const point1 = elements[idx1];\n const point2 = elements[idx2];\n\n // Compute normal vector (point2 - point1)\n const dim = point1.length;\n /** @type {number[]} */\n const normal = new Array(dim);\n for (let i = 0; i < dim; i++) {\n normal[i] = point2[i] - point1[i];\n }\n\n // Normalize\n let norm = 0;\n for (let i = 0; i < dim; i++) {\n norm += normal[i] * normal[i];\n }\n norm = Math.sqrt(norm);\n\n if (norm > 1e-10) {\n for (let i = 0; i < dim; i++) {\n normal[i] /= norm;\n }\n }\n\n // Compute midpoint and offset\n /** @type {number[]} */\n const midpoint = new Array(dim);\n for (let i = 0; i < dim; i++) {\n midpoint[i] = (point1[i] + point2[i]) / 2;\n }\n\n // Compute offset: dot(normal, midpoint)\n let offset = 0;\n for (let i = 0; i < dim; i++) {\n offset += normal[i] * midpoint[i];\n }\n\n // Split points based on which side of hyperplane they fall\n const leftIndices = [];\n const rightIndices = [];\n\n for (const idx of indices) {\n const point = elements[idx];\n let dot = 0;\n for (let i = 0; i < dim; i++) {\n dot += normal[i] * point[i];\n }\n\n if (dot < offset) {\n leftIndices.push(idx);\n } else {\n rightIndices.push(idx);\n }\n }\n\n // Handle edge case where all points fall on one side\n if (leftIndices.length === 0 || rightIndices.length === 0) {\n return {\n isLeaf: true,\n indices: indices,\n normal: [],\n offset: 0,\n left: null,\n right: null,\n };\n }\n\n // Recursively build subtrees\n const left = this._buildTreeRecursive(leftIndices);\n const right = this._buildTreeRecursive(rightIndices);\n\n return {\n isLeaf: false,\n indices: [],\n normal: normal,\n offset: offset,\n left: left,\n right: right,\n };\n }\n\n /**\n * Compute distance from point to hyperplane.\n * @private\n * @param {T} point\n * @param {number[]} normal\n * @param {number} offset\n * @returns {number} Signed distance (positive = right side, negative = left side)\n */\n _distanceToHyperplane(point, normal, offset) {\n let dot = 0;\n for (let i = 0; i < point.length; i++) {\n dot += normal[i] * point[i];\n }\n return dot - offset;\n }\n\n /**\n * Search for k approximate nearest neighbors.\n * @param {T} query\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search(query, k = 5) {\n const metric = this._metric;\n const elements = this._elements;\n\n if (elements.length === 0) return [];\n\n // Collect candidates from all trees using priority queue\n const candidates = new Set();\n\n // Collect more candidates for better recall\n // Search at least k * numTrees * 2 candidates\n const minCandidates = Math.min(k * this._numTrees * 3, elements.length);\n\n for (const tree of this._trees) {\n this._searchTreePriority(tree, query, candidates, minCandidates);\n }\n\n // Compute exact distances for all candidates\n /** @type {Heap<{ index: number; distance: number }>} */\n const best = new Heap(null, (d) => d.distance, \"max\");\n\n for (const idx of candidates) {\n const element = elements[idx];\n if (!element || element.length !== query.length) continue;\n\n const dist = metric(query, element);\n\n if (best.length < k) {\n best.push({ index: idx, distance: dist });\n } else if (dist < (best.first?.value ?? Infinity)) {\n best.pop();\n best.push({ index: idx, distance: dist });\n }\n }\n\n // If we still don't have enough candidates, do a linear scan fallback\n if (best.length < k) {\n for (let i = 0; i < elements.length && best.length < k; i++) {\n if (candidates.has(i)) continue;\n\n const element = elements[i];\n if (!element || element.length !== query.length) continue;\n\n const dist = metric(query, element);\n best.push({ index: i, distance: dist });\n }\n }\n\n // Convert to result format\n /** @type {{ element: T; index: number; distance: number }[]} */\n const result = [];\n while (best.length > 0) {\n const item = /** @type {{ element: { index: number; distance: number }; value: number }} */ (best.pop());\n result.push({\n element: elements[item.element.index],\n index: item.element.index,\n distance: item.value,\n });\n }\n\n return result.reverse();\n }\n\n /**\n * Search tree using priority queue for better recall.\n * Explores nodes in order of distance to hyperplane.\n * @private\n * @param {AnnoyNode} node\n * @param {T} query\n * @param {Set} candidates\n * @param {number} maxCandidates\n */\n _searchTreePriority(node, query, candidates, maxCandidates) {\n if (!node) return;\n\n // Priority queue entry: { node, distance }\n /** @type {Heap<{ node: AnnoyNode; dist: number }>} */\n const pq = new Heap(null, (d) => d.dist, \"min\");\n pq.push({ node: node, dist: 0 });\n\n while (!pq.empty && candidates.size < maxCandidates) {\n const entry = pq.pop();\n if (!entry) continue;\n\n const currentNode = entry.element.node;\n\n // Leaf node: add all points\n if (currentNode.isLeaf) {\n for (const idx of currentNode.indices) {\n candidates.add(idx);\n if (candidates.size >= maxCandidates) return;\n }\n continue;\n }\n\n // Internal node: compute distance to hyperplane\n const dist = this._distanceToHyperplane(query, currentNode.normal, currentNode.offset);\n\n // Determine which side is closer\n const closerSide = dist < 0 ? currentNode.left : currentNode.right;\n const fartherSide = dist < 0 ? currentNode.right : currentNode.left;\n\n // Add closer side with priority 0 (explore first)\n if (closerSide) {\n pq.push({ node: closerSide, dist: 0 });\n }\n\n // Add farther side with priority = |dist| (explore later if needed)\n if (fartherSide && candidates.size < maxCandidates) {\n pq.push({ node: fartherSide, dist: Math.abs(dist) });\n }\n }\n }\n\n /**\n * @param {number} i\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i, k = 5) {\n if (i < 0 || i >= this._elements.length) return [];\n return this.search(this._elements[i], k);\n }\n\n /**\n * Alias for search_by_index for backward compatibility.\n *\n * @param {number} i - Index of the query element\n * @param {number} [k=5] - Number of nearest neighbors to return\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_index(i, k = 5) {\n return this.search_by_index(i, k);\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersBallTree } from \"./index.js\" */\n\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} ElementWithIndex\n * @property {number} index\n * @property {T} element\n */\n\n/**\n * Ball Tree for efficient nearest neighbor search.\n *\n * A Ball Tree is a metric tree that partitions points into a nested set of\n * hyperspheres (balls). It is particularly effective for high-dimensional\n * data and supports any valid metric.\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n */\nexport class BallTree extends KNN {\n /**\n * Generates a BallTree with given `elements`.\n *\n * @param {T[]} elements - Elements which should be added to the BallTree\n * @param {ParametersBallTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}`\n * @see {@link https://en.wikipedia.org/wiki/Ball_tree}\n * @see {@link https://github.com/invisal/noobjs/blob/master/src/tree/BallTree.js}\n */\n constructor(elements, parameters = { metric: euclidean, seed: 1212 }) {\n super(elements, Object.assign({ seed: 1212 }, parameters));\n /**\n * @private\n * @type {BallTreeNode | BallTreeLeaf}\n */\n this._root = this._construct(elements.map((element, index) => ({ index, element })));\n }\n\n /** @returns {Metric} */\n get _metric() {\n return this._parameters.metric;\n }\n\n /**\n * @private\n * @param {ElementWithIndex[]} elements\n * @returns {BallTreeNode | BallTreeLeaf} Root of balltree.\n */\n _construct(elements) {\n if (elements.length === 1) {\n return new BallTreeLeaf(elements);\n } else {\n const c = this._greatest_spread(elements);\n const sorted_elements = elements.sort((a, b) => a.element[c] - b.element[c]);\n const n = sorted_elements.length;\n const p_index = Math.floor(n / 2);\n const p = sorted_elements[p_index];\n const L = sorted_elements.slice(0, p_index);\n const R = sorted_elements.slice(p_index, n);\n const radius = Math.max(...elements.map((d) => this._metric(p.element, d.element)));\n let B;\n if (L.length > 0 && R.length > 0) {\n B = new BallTreeNode(p, this._construct(L), this._construct(R), radius);\n } else {\n B = new BallTreeLeaf(elements);\n }\n return B;\n }\n }\n\n /**\n * @private\n * @param {ElementWithIndex[]} B\n * @returns {number}\n */\n _greatest_spread(B) {\n const d = B[0].element.length;\n const start = new Array(d);\n\n for (let i = 0; i < d; ++i) {\n start[i] = [Infinity, -Infinity];\n }\n\n let spread = B.reduce((acc, current) => {\n for (let i = 0; i < d; ++i) {\n acc[i][0] = Math.min(acc[i][0], current.element[i]);\n acc[i][1] = Math.max(acc[i][1], current.element[i]);\n }\n return acc;\n }, start);\n spread = spread.map((d) => d[1] - d[0]);\n\n let c = 0;\n for (let i = 0; i < d; ++i) {\n c = spread[i] > spread[c] ? i : c;\n }\n return c;\n }\n\n /**\n * @param {number} i\n * @param {number} k\n */\n search_by_index(i, k = 5) {\n return this.search(this._elements[i], k);\n }\n\n /**\n * @param {T} t - Query element.\n * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors.\n */\n search(t, k = 5) {\n /** @type {Heap>} */\n const heap = new Heap(null, (d) => this._metric(d.element, t), \"max\");\n this._search(t, k, heap, this._root);\n\n // Convert heap to result array\n /** @type {{ element: T; index: number; distance: number }[]} */\n const result = [];\n while (heap.length > 0) {\n const item = /** @type {{ element: ElementWithIndex; value: number }} */ (heap.pop());\n result.push({\n element: item.element.element,\n index: item.element.index,\n distance: item.value,\n });\n }\n return result.reverse(); // Reverse to get closest first\n }\n\n /**\n * @private\n * @param {T} t - Query element.\n * @param {number} k - Number of nearest neighbors to return.\n * @param {Heap>} Q - Heap consists of the currently found `k` nearest neighbors.\n * @param {BallTreeNode | BallTreeLeaf} B\n */\n _search(t, k, Q, B) {\n if (!B) return;\n\n if (B instanceof BallTreeNode) {\n const dist_to_pivot = this._metric(t, B.pivot.element);\n if (Q.length >= k && dist_to_pivot - B.radius >= (Q.first?.value ?? -Infinity)) {\n return;\n }\n\n const c1 = B.child1;\n const c2 = B.child2;\n\n let d1 = Infinity;\n let d2 = Infinity;\n\n if (c1 instanceof BallTreeNode) d1 = this._metric(t, c1.pivot.element);\n else if (c1 instanceof BallTreeLeaf) d1 = this._metric(t, c1.points[0].element);\n\n if (c2 instanceof BallTreeNode) d2 = this._metric(t, c2.pivot.element);\n else if (c2 instanceof BallTreeLeaf) d2 = this._metric(t, c2.points[0].element);\n\n if (d1 < d2) {\n if (c1) this._search(t, k, Q, c1);\n if (c2) this._search(t, k, Q, c2);\n } else {\n if (c2) this._search(t, k, Q, c2);\n if (c1) this._search(t, k, Q, c1);\n }\n } else if (B instanceof BallTreeLeaf) {\n for (let i = 0, n = B.points.length; i < n; ++i) {\n const p = B.points[i];\n const dist = this._metric(p.element, t);\n if (Q.length < k) {\n Q.push(p);\n } else if (dist < (Q.first?.value ?? Infinity)) {\n Q.pop();\n Q.push(p);\n }\n }\n }\n }\n}\n\n/**\n * @private\n * @template {number[] | Float64Array} T\n */\nclass BallTreeNode {\n /**\n * @param {ElementWithIndex} pivot\n * @param {BallTreeNode | BallTreeLeaf | null} child1\n * @param {BallTreeNode | BallTreeLeaf | null} child2\n * @param {number} radius\n */\n constructor(pivot, child1 = null, child2 = null, radius = 0) {\n this.pivot = pivot;\n this.child1 = child1;\n this.child2 = child2;\n this.radius = radius;\n }\n}\n\n/**\n * @private\n * @template {number[] | Float64Array} T\n */\nclass BallTreeLeaf {\n /** @param {ElementWithIndex[]} points */\n constructor(points) {\n this.points = points;\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersHNSW } from \"./index.js\" */\n\n/**\n * @typedef {Object} Layer\n * @property {number} l_c - Layer number\n * @property {number[]} point_indices - Global indices of points in this layer\n * @property {Map} edges - Global index -> array of connected global indices\n */\n\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} Candidate\n * @property {T} element - The actual data point\n * @property {number} index - Global index in the dataset\n * @property {number} distance - Distance from query\n */\n\n/**\n * Hierarchical Navigable Small World (HNSW) graph for approximate nearest neighbor search.\n *\n * HNSW builds a multi-layer graph structure where each layer is a navigable small world graph.\n * The top layers serve as \"highways\" for fast traversal, while lower layers provide accuracy.\n * Each element is assigned to a random level, allowing logarithmic search complexity.\n *\n * Key parameters:\n * - `m`: Controls the number of connections per element (affects accuracy/memory)\n * - `ef_construction`: Controls the quality of the graph during construction (higher = better but slower)\n * - `ef`: Controls the quality of search (higher = better recall but slower)\n *\n * Based on:\n * - \"Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs\"\n * by Malkov & Yashunin (2016)\n * - \"Approximate Nearest Neighbor Search on High Dimensional Data\"\n * by Li et al. (2019)\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const points = [[1, 2], [3, 4], [5, 6], [7, 8]];\n * const hnsw = new druid.HNSW(points, {\n * metric: druid.euclidean,\n * m: 16,\n * ef_construction: 200\n * });\n *\n * const query = [2, 3];\n * const neighbors = hnsw.search(query, 2);\n * // [{ element: [1, 2], index: 0, distance: 1.41 }, ...]\n */\nexport class HNSW extends KNN {\n /**\n * Creates a new HNSW index.\n *\n * @param {T[]} points - Initial points to add to the index\n * @param {ParametersHNSW} [parameters={}] - Configuration parameters\n */\n constructor(\n points,\n parameters = {\n metric: euclidean,\n heuristic: true,\n m: 16,\n ef_construction: 200,\n m0: null,\n mL: null,\n seed: 1212,\n ef: 50,\n },\n ) {\n // Handle empty initialization - use dummy element\n const hasElements = points && points.length > 0;\n let firstElement = /** @type {T} */ (hasElements ? points[0] : new Float64Array([0]));\n\n // Validate all points have consistent dimensions\n if (hasElements) {\n const expected_dim = firstElement.length;\n for (let i = 1; i < points.length; i++) {\n if (!points[i] || points[i].length !== expected_dim) {\n console.warn(\n `HNSW: Point ${i} has inconsistent dimensions (expected ${expected_dim}, got ${points[i]?.length})`,\n );\n // Remove invalid points\n points = points.filter((_, idx) => idx === 0 || points[idx]?.length === expected_dim);\n firstElement = points[0];\n }\n }\n }\n\n super([firstElement], parameters);\n\n // Store reference to elements before clearing\n const elementsToAdd = hasElements ? [...points] : [];\n /** @type {T[]} */\n this._elements = [];\n\n /** @type {Metric} */\n this._metric = this._parameters.metric || euclidean;\n\n /** @type {Function} */\n this._select = this._parameters.heuristic ? this._select_heuristic.bind(this) : this._select_simple.bind(this);\n\n /**\n * @private\n * @type {Map}\n */\n this._graph = new Map();\n\n /** @type {number} */\n this._next_index = 0;\n\n // Validate and set parameters\n const m_param = this._parameters.m ?? 16;\n if (m_param <= 0 || !Number.isInteger(m_param)) {\n throw new Error(\"HNSW: parameter 'm' must be a positive integer\");\n }\n /** @type {number} */\n this._m = Math.max(2, m_param);\n\n const ef_construction_param = this._parameters.ef_construction ?? 200;\n if (ef_construction_param <= 0 || !Number.isInteger(ef_construction_param)) {\n throw new Error(\"HNSW: parameter 'ef_construction' must be a positive integer\");\n }\n /** @type {number} */\n this._ef_construction = ef_construction_param;\n\n const ef_param = this._parameters.ef ?? 50;\n if (ef_param <= 0 || !Number.isInteger(ef_param)) {\n throw new Error(\"HNSW: parameter 'ef' must be a positive integer\");\n }\n /** @type {number} */\n this._ef = ef_param;\n\n const m0_param = this._parameters.m0 ?? 2 * this._m;\n if (m0_param <= 0 || !Number.isInteger(m0_param)) {\n throw new Error(\"HNSW: parameter 'm0' must be a positive integer\");\n }\n /** @type {number} */\n this._m0 = m0_param;\n\n /** @type {number} */\n this._mL = this._parameters.mL ?? 1 / Math.log(this._m);\n\n /** @type {Randomizer} */\n this._randomizer = new Randomizer(this._parameters.seed);\n\n /** @type {number} - Current maximum layer in the graph */\n this._L = -1;\n\n /** @type {number[] | null} - Entry point indices for search */\n this._ep = null;\n\n // Add initial points\n if (elementsToAdd && elementsToAdd.length > 0) {\n this.add(elementsToAdd);\n }\n }\n\n /**\n * Add a single element to the index.\n *\n * @param {T} element - Element to add\n * @returns {HNSW} This instance for chaining\n */\n addOne(element) {\n return this.add([element]);\n }\n\n /**\n * Add multiple elements to the index.\n *\n * @param {T[]} new_elements - Elements to add\n * @returns {HNSW} This instance for chaining\n */\n add(new_elements) {\n // Handle empty array\n if (!new_elements || new_elements.length === 0) {\n return this;\n }\n\n const m = this._m;\n const ef_construction = this._ef_construction;\n const m0 = this._m0;\n const mL = this._mL;\n const randomizer = this._randomizer;\n const graph = this._graph;\n\n // Ensure _elements is a proper array that supports push\n if (!Array.isArray(this._elements)) {\n this._elements = Array.from(this._elements);\n }\n const elements = this._elements;\n\n // Get expected dimension from first existing element or first new element\n const expected_dim = elements.length > 0 ? elements[0].length : new_elements[0]?.length;\n\n for (const element of new_elements) {\n // Validate element\n if (!element || (!Array.isArray(element) && !(element instanceof Float64Array))) {\n console.warn(\"HNSW: Skipping invalid element (null, undefined, or not an array)\");\n continue;\n }\n\n // Validate dimensions\n if (element.length !== expected_dim) {\n console.warn(\n `HNSW: Skipping element with wrong dimensions (expected ${expected_dim}, got ${element.length})`,\n );\n continue;\n }\n\n elements.push(element);\n const global_index = elements.length - 1;\n\n // Assign random level to the element\n // Level is drawn from exponential distribution: l = floor(-ln(uniform(0,1)) * mL)\n const rand = Math.max(randomizer.random, 1e-10); // Avoid log(0)\n const l = Math.min(31, Math.floor(-Math.log(rand) * mL));\n\n let ep_indices = this._ep ? [...this._ep] : null;\n const L = this._L;\n\n if (L >= 0) {\n // Search from top layer down to min(L, l) + 1\n // These are the layers where element will NOT be inserted\n for (let l_c = L; l_c > l; --l_c) {\n const search_result = this._search_layer(element, ep_indices, 1, l_c);\n if (search_result.length > 0) {\n ep_indices = [search_result[0].index];\n }\n }\n\n // Insert element into layers l down to 0\n for (let l_c = Math.min(L, l); l_c >= 0; --l_c) {\n const layer = graph.get(l_c);\n if (!layer) continue;\n\n layer.point_indices.push(global_index);\n\n // Search for ef_construction nearest neighbors\n let W = this._search_layer(element, ep_indices, ef_construction, l_c);\n\n // If graph search returns no results (e.g., graph is empty or disconnected),\n // fall back to linear search over all existing elements\n if (W.length === 0 && elements.length > 1) {\n const fallbackCandidates = [];\n for (let i = 0; i < elements.length - 1; i++) {\n const elem = elements[i];\n if (elem && elem.length === element.length) {\n fallbackCandidates.push({\n element: elem,\n index: i,\n distance: this._metric(element, elem),\n });\n }\n }\n fallbackCandidates.sort((a, b) => a.distance - b.distance);\n W = fallbackCandidates.slice(0, ef_construction);\n // Update ep_indices for next layer based on fallback results\n if (l_c === Math.min(L, l)) {\n ep_indices = W.map((c) => c.index);\n }\n }\n\n // Select neighbors using heuristic or simple approach (respect heuristic setting on all layers)\n const neighbor_indices = this._select(element, W, l_c === 0 ? m0 : m, l_c);\n\n // Add bidirectional connections\n for (const neighbor_idx of neighbor_indices) {\n if (neighbor_idx === global_index) continue;\n\n // Add connection from element to neighbor\n if (!layer.edges.has(global_index)) {\n layer.edges.set(global_index, []);\n }\n layer.edges.get(global_index)?.push(neighbor_idx);\n\n // Add connection from neighbor to element\n if (!layer.edges.has(neighbor_idx)) {\n layer.edges.set(neighbor_idx, []);\n }\n const neighbor_edge_list = layer.edges.get(neighbor_idx);\n if (neighbor_edge_list && !neighbor_edge_list.includes(global_index)) {\n neighbor_edge_list.push(global_index);\n }\n\n // Prune connections if too many\n const max_conn = l_c === 0 ? m0 : m;\n const neighbor_edges = layer.edges.get(neighbor_idx);\n if (neighbor_edges && neighbor_edges.length > max_conn) {\n const neighbor_element = elements[neighbor_idx];\n // Filter out self-connections before pruning\n const valid_neighbor_edges = neighbor_edges.filter((idx) => idx !== neighbor_idx);\n const neighbor_candidates = valid_neighbor_edges.map((idx) => ({\n element: elements[idx],\n index: idx,\n distance: this._metric(neighbor_element, elements[idx]),\n }));\n const pruned =\n l_c === 0\n ? this._select_simple(neighbor_element, neighbor_candidates, max_conn)\n : this._select(neighbor_element, neighbor_candidates, max_conn, l_c);\n layer.edges.set(neighbor_idx, pruned);\n }\n }\n\n // Use closest neighbor as entry point for next layer (following HNSW paper)\n if (W.length > 0) {\n ep_indices = [W[0].index];\n }\n }\n }\n\n // If element's level is higher than current max, create new layers\n if (l > L) {\n for (let i = L + 1; i <= l; ++i) {\n graph.set(i, {\n l_c: i,\n point_indices: [global_index],\n edges: new Map(),\n });\n }\n // Element becomes the new entry point\n this._ep = [global_index];\n this._L = l;\n }\n\n // Special case: if this is the first element (L was -1),\n // we need to ensure layer 0 has proper structure for future insertions\n if (L === -1) {\n if (!graph.has(0)) {\n graph.set(0, {\n l_c: 0,\n point_indices: [global_index],\n edges: new Map(),\n });\n }\n const layer0 = graph.get(0);\n if (layer0 && !layer0.edges.has(global_index)) {\n layer0.edges.set(global_index, []);\n }\n }\n }\n\n return this;\n }\n\n /**\n * Select neighbors using the heuristic approach.\n *\n * The heuristic extends candidates with their neighbors and selects\n * points that are closer to the query than to already selected points.\n * This maintains graph connectivity better than simple selection.\n *\n * @private\n * @param {T} q - Query element\n * @param {Candidate[]} candidates - Candidate elements with distances\n * @param {number} M - Maximum number of neighbors to return\n * @param {number} l_c - Layer number\n * @param {boolean} [extend_candidates=true] - Whether to extend candidates with their neighbors\n * @param {boolean} [keep_pruned_connections=true] - Whether to add pruned connections back if needed\n * @returns {number[]} Selected neighbor indices\n */\n _select_heuristic(q, candidates, M, l_c, extend_candidates = true, keep_pruned_connections = true) {\n if (l_c > this._L) {\n return candidates.map((c) => c.index);\n }\n\n const metric = this._metric;\n const layer = this._graph.get(l_c);\n const elements = this._elements;\n\n // Extend candidate set with neighbors of candidates\n const W_set = new Set(candidates.map((c) => c.index));\n if (extend_candidates) {\n for (const c of candidates) {\n const edges = layer?.edges.get(c.index);\n if (edges) {\n for (const neighbor_idx of edges) {\n W_set.add(neighbor_idx);\n }\n }\n }\n }\n\n // Create extended candidates with distances\n const W = [...W_set]\n .map((idx) => ({\n element: elements[idx],\n index: idx,\n distance: metric(elements[idx], q),\n }))\n .sort((a, b) => a.distance - b.distance);\n\n const R = [];\n const W_discarded = [];\n\n // Select neighbors: prefer points closer to query than to already selected points\n for (const e of W) {\n if (R.length >= M) break;\n\n let should_add = true;\n\n // Check if e is closer to query than to any already selected point\n for (const r of R) {\n const dist_er = metric(e.element, r.element);\n if (dist_er < e.distance) {\n should_add = false;\n break;\n }\n }\n\n if (should_add) {\n R.push(e);\n } else {\n W_discarded.push(e);\n }\n }\n\n // Add discarded connections if we need more\n if (keep_pruned_connections && R.length < M) {\n for (const e of W_discarded) {\n if (R.length >= M) break;\n R.push(e);\n }\n }\n\n return R.map((c) => c.index);\n }\n\n /**\n * Select neighbors using simple distance-based selection.\n *\n * Simply returns the M closest candidates to the query.\n *\n * @private\n * @param {T} q - Query element\n * @param {Candidate[]} C - Candidate elements with distances\n * @param {number} M - Maximum number of neighbors to return\n * @returns {number[]} M nearest candidate indices\n */\n _select_simple(q, C, M) {\n if (C.length <= M) return C.map((c) => c.index);\n\n // Candidates already have distance computed, use it directly\n return C.slice()\n .sort((a, b) => a.distance - b.distance)\n .slice(0, M)\n .map((c) => c.index);\n }\n\n /**\n * Search a single layer for nearest neighbors.\n *\n * Implements the greedy search algorithm: start from entry points,\n * always expand the closest unvisited candidate, maintain a list\n * of the ef closest found neighbors.\n *\n * @private\n * @param {T} q - Query element\n * @param {number[] | null} ep_indices - Entry point indices\n * @param {number} ef - Number of nearest neighbors to find\n * @param {number} l_c - Layer number to search\n * @returns {Candidate[]} ef nearest neighbors found with their distances\n */\n _search_layer(q, ep_indices, ef, l_c) {\n const metric = this._metric;\n const layer = this._graph.get(l_c);\n const elements = this._elements;\n\n if (!layer || layer.edges.size === 0 || !ep_indices || ep_indices.length === 0) {\n return [];\n }\n\n // Filter out invalid indices\n const valid_ep_indices = ep_indices.filter((idx) => elements[idx] !== undefined);\n if (valid_ep_indices.length === 0) {\n return [];\n }\n\n // Visited set to avoid cycles\n const visited = new Set(valid_ep_indices);\n\n // Candidate set (min-heap): closest unvisited candidates to expand\n const C = new Heap(\n valid_ep_indices.map((idx) => ({\n element: elements[idx],\n index: idx,\n distance: metric(elements[idx], q),\n })),\n (item) => item.distance,\n \"min\",\n );\n\n // Result set (max-heap): ef closest found neighbors\n const W = new Heap(\n valid_ep_indices.map((idx) => ({\n element: elements[idx],\n index: idx,\n distance: metric(elements[idx], q),\n })),\n (item) => item.distance,\n \"max\",\n );\n\n // Algorithm 2 stops when the distance from query to the next candidate is greater\n // than the distance to the furthest element in the result set W.\n while (!C.empty) {\n const c = C.pop();\n if (!c) break;\n const furthest_dist = W.first?.value ?? Infinity;\n\n // Stop if current candidate is farther than furthest result\n if (c.value > furthest_dist) {\n break;\n }\n\n const edges = layer.edges.get(c.element.index);\n if (!edges) continue;\n\n for (const neighbor_idx of edges) {\n if (!visited.has(neighbor_idx)) {\n const neighbor_element = elements[neighbor_idx];\n // Skip invalid elements or elements with different dimensions\n if (!neighbor_element || neighbor_element.length !== q.length) continue;\n\n // Skip self-connections\n if (neighbor_idx === c.element.index) continue;\n\n visited.add(neighbor_idx);\n const dist_e = metric(neighbor_element, q);\n\n const current_furthest = W.first?.value ?? Infinity;\n if (dist_e < current_furthest || W.length < ef) {\n C.push({\n element: neighbor_element,\n index: neighbor_idx,\n distance: dist_e,\n });\n W.push({\n element: neighbor_element,\n index: neighbor_idx,\n distance: dist_e,\n });\n\n if (W.length > ef) {\n W.pop();\n }\n }\n }\n }\n }\n\n // Return sorted results for consistent entry point selection\n return W.data().sort((a, b) => a.distance - b.distance);\n }\n\n /**\n * Searches for the K nearest neighbors to a query element in the HNSW graph.\n *\n * Performs a multi-layer search starting from the entry point and traversing\n * each layer as entry points for the next.\n *\n * @param {T} q - Query element\n * @param {number} K - Number of nearest neighbors to return\n * @returns {Candidate[]} K nearest neighbors with their distances\n */\n search(q, K) {\n // Validate K\n if (!Number.isInteger(K) || K <= 0) {\n throw new Error(\"HNSW: parameter 'K' must be a positive integer\");\n }\n\n // Validate query dimensions\n if (!q || (!Array.isArray(q) && !(q instanceof Float64Array))) {\n throw new Error(\"HNSW: query must be an array\");\n }\n\n const search_ef = this._ef;\n\n // Fallback to linear search if graph is not properly initialized\n if (this._L < 0 || !this._ep || this._elements.length === 0) {\n return this._linear_search(q, K);\n }\n\n let ep_indices = [...this._ep];\n\n // Search from top layer down to layer 1\n for (let l_c = this._L; l_c > 0; --l_c) {\n const result = this._search_layer(q, ep_indices, 1, l_c);\n if (result.length > 0) {\n ep_indices = [result[0].index];\n }\n }\n\n // Search layer 0 with ef candidates\n const result = this._search_layer(q, ep_indices, Math.max(search_ef, K), 0);\n\n // If graph search returns no results, fallback to linear search\n if (result.length === 0) {\n return this._linear_search(q, K);\n }\n\n // Return K closest\n return result.slice(0, K);\n }\n\n /**\n * Fallback linear search when graph search fails\n * @private\n * @param {T} q - Query element\n * @param {number} K - Number of nearest neighbors to return\n * @returns {Candidate[]}\n */\n _linear_search(q, K) {\n const metric = this._metric;\n const elements = this._elements;\n const N = elements.length;\n\n if (N === 0) return [];\n\n /** @type {Candidate[]} */\n const candidates = [];\n for (let i = 0; i < N; i++) {\n const element = elements[i];\n // Skip elements with different dimensions (can happen with inconsistent data)\n if (!element || element.length !== q.length) continue;\n\n candidates.push({\n element: element,\n index: i,\n distance: metric(q, element),\n });\n }\n\n candidates.sort((a, b) => a.distance - b.distance);\n return candidates.slice(0, K);\n }\n\n /**\n * Iterator for searching the HNSW graph layer by layer.\n *\n * Yields intermediate results at each layer for debugging or visualization.\n *\n * @param {T} q - Query element\n * @param {number} K - Number of nearest neighbors to return\n * @param {number?} [ef] - Size of dynamic candidate list\n * @yields {{layer: number, candidates: Candidate[]}}\n */\n *search_iter(q, K, ef = null) {\n const search_ef = ef ?? this._ef;\n\n if (this._L < 0 || !this._ep) {\n return;\n }\n\n let ep_indices = [...this._ep];\n\n // Yield entry points at top layer instead of query itself\n const top_layer = this._graph.get(this._L);\n if (top_layer && this._ep && this._ep.length > 0) {\n const entry_candidates = this._ep\n .filter((idx) => this._elements[idx] !== undefined)\n .map((idx) => ({\n element: this._elements[idx],\n index: idx,\n distance: this._metric(this._elements[idx], q),\n }));\n yield {\n layer: this._L,\n candidates: entry_candidates,\n };\n }\n\n for (let l_c = this._L; l_c > 0; --l_c) {\n const result = this._search_layer(q, ep_indices, 1, l_c);\n yield { layer: l_c, candidates: result };\n // Use closest candidate as entry point for next layer (following HNSW paper)\n ep_indices = result.length > 0 ? [result[0].index] : ep_indices;\n }\n\n const result = this._search_layer(q, ep_indices, Math.max(search_ef, K), 0);\n yield { layer: 0, candidates: result };\n }\n\n /**\n * Get the number of elements in the index.\n *\n * @returns {number} Number of elements\n */\n get size() {\n return this._elements?.length ?? 0;\n }\n\n /**\n * Get the number of layers in the graph.\n *\n * @returns {number} Number of layers\n */\n get num_layers() {\n return this._L + 1;\n }\n\n /**\n * Get an element by its index.\n *\n * @param {number} index - Element index\n * @returns {T} The element at the given index\n */\n get_element(index) {\n return this._elements[index];\n }\n\n /**\n * Search for nearest neighbors using an element index as the query.\n *\n * @param {number} i - Index of the query element\n * @param {number} [K=5] - Number of nearest neighbors to return\n * @returns {Candidate[]} K nearest neighbors\n */\n search_by_index(i, K = 5) {\n const elements = this._elements;\n if (i < 0 || i >= elements.length) return [];\n\n const element = elements[i];\n if (!element) return [];\n\n return this.search(element, K);\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersKDTree } from \"./index.js\" */\n\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} ElementWithIndex\n * @property {number} index\n * @property {T} element\n */\n\n/**\n * KD-Tree (K-dimensional Tree) for efficient nearest neighbor search.\n *\n * KD-Trees partition k-dimensional space by recursively splitting along coordinate axes.\n * At each level, the tree splits points based on the median of the coordinate with the largest spread.\n * This creates a balanced binary tree structure that enables efficient O(log n) search on average.\n *\n * Best suited for:\n * - Low to moderate dimensional data (d < 20-30)\n * - When exact nearest neighbors are needed\n * - When dimensionality is not too high\n *\n * Performance degrades in high dimensions (curse of dimensionality) where approximate\n * methods like HNSW or LSH become more effective.\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link https://en.wikipedia.org/wiki/K-d_tree}\n */\nexport class KDTree extends KNN {\n /**\n * Generates a KD-Tree with given `elements`.\n *\n * @param {T[]} elements - Elements which should be added to the KD-Tree\n * @param {ParametersKDTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}`\n */\n constructor(elements, parameters = { metric: euclidean, seed: 1212 }) {\n super(elements, Object.assign({ seed: 1212 }, parameters));\n /**\n * @private\n * @type {KDTreeNode | KDTreeLeaf | null}\n */\n this._root = this._construct(\n elements.map((element, index) => ({ index, element })),\n 0,\n );\n }\n\n /** @returns {Metric} */\n get _metric() {\n return this._parameters.metric;\n }\n\n /**\n * @private\n * @param {ElementWithIndex[]} elements\n * @param {number} depth - Current depth in the tree (determines splitting axis)\n * @returns {KDTreeNode | KDTreeLeaf | null} Root of KD-Tree.\n */\n _construct(elements, depth) {\n if (elements.length === 0) {\n return null;\n }\n\n if (elements.length === 1) {\n return new KDTreeLeaf(elements[0]);\n }\n\n const k = elements[0].element.length;\n const axis = depth % k;\n\n // Sort by the splitting axis and find median\n elements.sort((a, b) => a.element[axis] - b.element[axis]);\n const medianIndex = Math.floor(elements.length / 2);\n const medianPoint = elements[medianIndex];\n\n // Recursively build left and right subtrees\n const leftElements = elements.slice(0, medianIndex);\n const rightElements = elements.slice(medianIndex + 1);\n\n const left = this._construct(leftElements, depth + 1);\n const right = this._construct(rightElements, depth + 1);\n\n return new KDTreeNode(medianPoint, axis, left, right);\n }\n\n /**\n * @param {number} i\n * @param {number} k\n */\n search_by_index(i, k = 5) {\n return this.search(this._elements[i], k);\n }\n\n /**\n * @param {T} t - Query element.\n * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors.\n */\n search(t, k = 5) {\n /** @type {Heap<{ point: ElementWithIndex; distance: number }>} */\n const best = new Heap(null, (d) => d.distance, \"max\");\n\n this._search_recursive(t, k, this._root, best);\n\n // Convert heap to result array (closest first)\n /** @type {{ element: T; index: number; distance: number }[]} */\n const result = [];\n while (best.length > 0) {\n const item = /** @type {{ element: { point: ElementWithIndex; distance: number }; value: number }} */ (\n best.pop()\n );\n result.push({\n element: item.element.point.element,\n index: item.element.point.index,\n distance: item.value,\n });\n }\n return result.reverse();\n }\n\n /**\n * @private\n * @param {T} target - Query element.\n * @param {number} k - Number of nearest neighbors to return.\n * @param {KDTreeNode | KDTreeLeaf | null} node - Current node.\n * @param {Heap<{ point: ElementWithIndex; distance: number }>} best - Heap of k best found so far.\n */\n _search_recursive(target, k, node, best) {\n if (node === null) return;\n\n if (node instanceof KDTreeLeaf) {\n const dist = this._metric(target, node.point.element);\n if (best.length < k) {\n best.push({ point: node.point, distance: dist });\n } else if (dist < (best.first?.value ?? Infinity)) {\n best.pop();\n best.push({ point: node.point, distance: dist });\n }\n return;\n }\n\n // Node is an internal node\n const axis = node.axis;\n const point = node.point;\n const pointValue = point.element[axis];\n const targetValue = target[axis];\n\n // Determine which subtree to search first\n const firstSubtree = targetValue < pointValue ? node.left : node.right;\n const secondSubtree = targetValue < pointValue ? node.right : node.left;\n\n // Search the nearer subtree\n this._search_recursive(target, k, firstSubtree, best);\n\n // Check if we need to search the other subtree\n // The hyperplane could contain closer points\n const distToHyperplane = Math.abs(targetValue - pointValue);\n const currentMaxDist = best.first?.value ?? Infinity;\n\n // Calculate distance to current point\n const distToPoint = this._metric(target, point.element);\n if (best.length < k) {\n best.push({ point: point, distance: distToPoint });\n } else if (distToPoint < currentMaxDist) {\n best.pop();\n best.push({ point: point, distance: distToPoint });\n }\n\n // Check if we need to explore the other side of the hyperplane\n if (best.length < k || distToHyperplane < (best.first?.value ?? Infinity)) {\n this._search_recursive(target, k, secondSubtree, best);\n }\n }\n}\n\n/**\n * @private\n * @template {number[] | Float64Array} T\n */\nclass KDTreeNode {\n /**\n * @param {ElementWithIndex} point\n * @param {number} axis - The splitting axis\n * @param {KDTreeNode | KDTreeLeaf | null} left\n * @param {KDTreeNode | KDTreeLeaf | null} right\n */\n constructor(point, axis, left = null, right = null) {\n this.point = point;\n this.axis = axis;\n this.left = left;\n this.right = right;\n }\n}\n\n/**\n * @private\n * @template {number[] | Float64Array} T\n */\nclass KDTreeLeaf {\n /**\n * @param {ElementWithIndex} point\n */\n constructor(point) {\n this.point = point;\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersLSH } from \"./index.js\" */\n\n/**\n * Locality Sensitive Hashing (LSH) for approximate nearest neighbor search.\n *\n * LSH uses hash functions that map similar items to the same buckets with high probability.\n * This implementation uses Random Projection hashing (SimHash-style) which works well for\n * cosine similarity and Euclidean distance.\n *\n * Key concepts:\n * - Multiple hash tables increase recall probability\n * - Each hash function projects data onto random hyperplanes\n * - Points on the same side of hyperplanes are hashed together\n * - Combines results from all tables for better accuracy\n *\n * Best suited for:\n * - High-dimensional data where exact methods fail\n * - Approximate nearest neighbor needs\n * - Large datasets where linear scan is too slow\n * - When some false positives/negatives are acceptable\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link https://en.wikipedia.org/wiki/Locality-sensitive_hashing}\n */\nexport class LSH extends KNN {\n /**\n * Creates a new LSH index.\n *\n * @param {T[]} elements - Elements to index\n * @param {ParametersLSH} [parameters={}] - Configuration parameters\n */\n constructor(\n elements,\n parameters = {\n metric: euclidean,\n numHashTables: 10,\n numHashFunctions: 10,\n seed: 1212,\n },\n ) {\n // Handle empty initialization - use dummy element\n const hasElements = elements && elements.length > 0;\n const firstElement = /** @type {T} */ (hasElements ? elements[0] : new Float64Array([0]));\n\n super([firstElement], parameters);\n\n this._metric = this._parameters.metric ?? euclidean;\n this._numHashTables = this._parameters.numHashTables ?? 10;\n this._numHashFunctions = this._parameters.numHashFunctions ?? 10;\n this._seed = this._parameters.seed ?? 1212;\n this._randomizer = new Randomizer(this._seed);\n\n // Hash tables: array of Maps where key is hash bucket, value is array of element indices\n /** @type {Map[]} */\n this._hashTables = [];\n\n // Random projection vectors for each hash table and hash function\n /** @type {Float64Array[][]} */\n this._projections = [];\n\n // Random offsets for each hash table and hash function (for quantization)\n /** @type {number[][]} */\n this._offsets = [];\n\n // Store dimensionality for later\n /** @type {number} */\n this._dim = firstElement.length;\n\n // Initialize hash functions\n this._initializeHashFunctions();\n\n // Reset elements if we were initialized with dummy\n if (!hasElements) {\n /** @type {T[]} */\n this._elements = [];\n } else {\n // Clear and re-add elements properly\n /** @type {T[]} */\n this._elements = [];\n this._hashTables = [];\n this._projections = [];\n this._offsets = [];\n this._initializeHashFunctions();\n this.add(elements);\n }\n }\n\n /**\n * Initialize random projection vectors for all hash tables.\n * @private\n */\n _initializeHashFunctions() {\n const dim = this._elements[0]?.length ?? 0;\n\n for (let t = 0; t < this._numHashTables; t++) {\n const tableProjections = [];\n const tableOffsets = [];\n\n for (let h = 0; h < this._numHashFunctions; h++) {\n // Generate random projection vector (normalized)\n const projection = new Float64Array(dim);\n let norm = 0;\n for (let i = 0; i < dim; i++) {\n // Box-Muller transform for normal distribution\n const u1 = this._randomizer.random;\n const u2 = this._randomizer.random;\n const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);\n projection[i] = z;\n norm += z * z;\n }\n // Normalize\n norm = Math.sqrt(norm);\n for (let i = 0; i < dim; i++) {\n projection[i] /= norm;\n }\n\n tableProjections.push(projection);\n // Random offset for quantization buckets\n tableOffsets.push(this._randomizer.random);\n }\n\n this._projections.push(tableProjections);\n this._offsets.push(tableOffsets);\n this._hashTables.push(new Map());\n }\n }\n\n /**\n * Compute hash signature for an element using random projections.\n * @private\n * @param {T} element\n * @param {number} tableIndex\n * @returns {string} Hash signature\n */\n _computeHash(element, tableIndex) {\n const projections = this._projections[tableIndex];\n const offsets = this._offsets[tableIndex];\n const bits = [];\n\n for (let i = 0; i < this._numHashFunctions; i++) {\n // Compute dot product\n let dot = 0;\n const proj = projections[i];\n for (let j = 0; j < element.length; j++) {\n dot += element[j] * proj[j];\n }\n // Quantize with offset\n const bucket = Math.floor(dot + offsets[i]);\n bits.push(bucket);\n }\n\n return bits.join(\",\");\n }\n\n /**\n * Add elements to the LSH index.\n * @param {T[]} elements\n * @returns {this}\n */\n add(elements) {\n // Extend elements array\n const startIndex = this._elements.length;\n this._elements = this._elements.concat(elements);\n\n // Hash each new element and add to tables\n for (let i = 0; i < elements.length; i++) {\n const globalIndex = startIndex + i;\n const element = elements[i];\n\n for (let t = 0; t < this._numHashTables; t++) {\n const hash = this._computeHash(element, t);\n const table = this._hashTables[t];\n\n if (!table.has(hash)) {\n table.set(hash, []);\n }\n const bucket = table.get(hash);\n if (bucket) {\n bucket.push(globalIndex);\n }\n }\n }\n\n return this;\n }\n\n /**\n * Search for k approximate nearest neighbors.\n * @param {T} query\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search(query, k = 5) {\n const metric = this._metric;\n const elements = this._elements;\n\n if (elements.length === 0) return [];\n\n // Collect candidate indices from all hash tables\n const candidates = new Set();\n\n for (let t = 0; t < this._numHashTables; t++) {\n const hash = this._computeHash(query, t);\n const table = this._hashTables[t];\n const bucket = table.get(hash);\n\n if (bucket) {\n for (const idx of bucket) {\n if (idx !== undefined) {\n candidates.add(idx);\n }\n }\n }\n }\n\n // If insufficient candidates found, fall back to linear search\n if (candidates.size < k) {\n // Add more candidates from all buckets or entire dataset\n //const needed = k - candidates.size;\n\n // First, try to add from neighboring buckets (different hashes)\n for (let t = 0; t < this._numHashTables && candidates.size < k; t++) {\n const table = this._hashTables[t];\n for (const [, bucket] of table) {\n for (const idx of bucket) {\n if (idx !== undefined) {\n candidates.add(idx);\n if (candidates.size >= k) break;\n }\n }\n if (candidates.size >= k) break;\n }\n }\n\n // If still not enough, add from entire dataset\n for (let i = 0; i < elements.length && candidates.size < k; i++) {\n candidates.add(i);\n }\n }\n\n // Compute exact distances for candidates\n /** @type {Heap<{ index: number; distance: number }>} */\n const best = new Heap(null, (d) => d.distance, \"max\");\n\n for (const idx of candidates) {\n const element = elements[idx];\n if (!element || element.length !== query.length) continue;\n\n const dist = metric(query, element);\n\n if (best.length < k) {\n best.push({ index: idx, distance: dist });\n } else if (dist < (best.first?.value ?? Infinity)) {\n best.pop();\n best.push({ index: idx, distance: dist });\n }\n }\n\n // Convert to result format\n /** @type {{ element: T; index: number; distance: number }[]} */\n const result = [];\n while (best.length > 0) {\n const item = /** @type {{ element: { index: number; distance: number }; value: number }} */ (best.pop());\n result.push({\n element: elements[item.element.index],\n index: item.element.index,\n distance: item.value,\n });\n }\n\n return result.reverse();\n }\n\n /**\n * @param {number} i\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i, k = 5) {\n if (i < 0 || i >= this._elements.length) return [];\n return this.search(this._elements[i], k);\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { distance_matrix, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import { ParametersNaiveKNN } from \"./index.js\" */\n\n/**\n * Naive KNN implementation using a distance matrix.\n *\n * This implementation pre-computes the entire distance matrix and performs\n * an exhaustive search. Best suited for small datasets or when a distance\n * matrix is already available.\n *\n * @template {number[] | Float64Array} T\n * @category KNN\n * @class\n * @extends KNN\n */\nexport class NaiveKNN extends KNN {\n /**\n * Generates a KNN list with given `elements`.\n *\n * @param {T[]} elements - Elements which should be added to the KNN list\n * @param {ParametersNaiveKNN} parameters\n */\n constructor(elements, parameters = {}) {\n const params = Object.assign({ metric: euclidean, seed: 1212 }, parameters);\n super(elements, params);\n const N =\n this._elements instanceof Matrix ? /** @type {any} */ (this._elements).shape[0] : this._elements.length;\n if (this._parameters.metric === \"precomputed\") {\n this._D = Matrix.from(/** @type {number[][] | Float64Array[]} */ (/** @type {any} */ (this._elements)));\n } else {\n this._D = distance_matrix(\n /** @type {number[][] | Float64Array[]} */ (this._elements),\n this._parameters.metric,\n );\n }\n\n /** @type {Heap<{ value: number; index: number }>[]} */\n this.KNN = [];\n for (let row = 0; row < N; ++row) {\n const distances = this._D.row(row);\n /** @type {Heap<{ value: number; index: number }>} */\n const H = new Heap(null, (d) => d.value, \"min\");\n for (let j = 0; j < N; ++j) {\n H.push({\n value: distances[j],\n index: j,\n });\n }\n this.KNN.push(H);\n }\n }\n\n /**\n * @param {number} i\n * @param {number} k\n */\n search_by_index(i, k = 5) {\n if (this._parameters.metric === \"precomputed\") {\n const H = this.KNN[i];\n /** @type {{ element: T; index: number; distance: number }[]} */\n const result = [];\n const data = H.toArray(); // Get array representation\n const temp_heap = new Heap(data, (d) => d.value, \"min\");\n const N =\n this._elements instanceof Matrix ? /** @type {any} */ (this._elements).shape[0] : this._elements.length;\n for (let j = 0; j < Math.min(k, N); ++j) {\n const node = temp_heap.pop();\n if (!node) break;\n result.push({\n element: /** @type {T} */ (\n this._elements instanceof Matrix\n ? /** @type {any} */ (this._elements).row(node.element.index)\n : this._elements[node.element.index]\n ),\n index: /** @type {number} */ (node.element.index),\n distance: /** @type {number} */ (node.value),\n });\n }\n return result;\n }\n return this.search(\n /** @type {T} */ (\n this._elements instanceof Matrix ? /** @type {any} */ (this._elements).row(i) : this._elements[i]\n ),\n k,\n );\n }\n\n /**\n * @param {T} t - Query element.\n * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors.\n */\n search(t, k = 5) {\n if (this._parameters.metric === \"precomputed\") {\n throw new Error(\"Search by query element is only possible when not using a precomputed distance matrix!\");\n }\n /** @type {import(\"../metrics/index.js\").Metric} */\n const metric = /** @type {any} */ (this._parameters.metric);\n\n const isMatrix = this._elements instanceof Matrix;\n const elementsAny = /** @type {any} */ (this._elements);\n const N = isMatrix ? elementsAny.shape[0] : this._elements.length;\n\n // Compute distances from query to ALL points\n const distances = [];\n for (let i = 0; i < N; i++) {\n const element = /** @type {T} */ (isMatrix ? elementsAny.row(i) : this._elements[i]);\n distances.push({\n element: element,\n index: i,\n distance: metric(t, element),\n });\n }\n\n // Sort by distance and return k nearest\n distances.sort((a, b) => a.distance - b.distance);\n return distances.slice(0, k);\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import {ParametersNNDescent} from \"./index.js\" */\n/**\n *\n * @template {number[] | Float64Array} T\n * @typedef {Object} NNDescentElement\n * @property {T} value\n * @property {number} index\n * @property {boolean} flag\n */\n\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} NNDescentNeighbor\n * @property {T} value\n * @property {number} index\n * @property {number} distance\n * @property {boolean} [flag]\n */\n\n/**\n * NN-Descent\n *\n * An efficient graph-based approximate nearest neighbor search algorithm.\n * It works by iteratively improving a neighbor graph using the fact that\n * \"neighbors of neighbors are likely to be neighbors\".\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf|NN-Descent Paper}\n */\nexport class NNDescent extends KNN {\n /**\n * @private\n * @type {KNNHeap[]}\n */\n _B = [];\n /**\n * @private\n * @type {NNDescentNeighbor[][]}\n */\n nn = [];\n\n /**\n * @param {T[]} elements - Called V in paper.\n * @param {Partial} parameters\n * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf}\n */\n constructor(elements, parameters = {}) {\n super(\n elements,\n /** @type {ParametersNNDescent} */ (\n Object.assign({ metric: euclidean, K: 10, rho: 1, delta: 1e-3, seed: 1212 }, parameters)\n ),\n );\n this._N = elements.length;\n this._randomizer = new Randomizer(this._parameters.seed);\n this._sample_size = this._parameters.samples * this._parameters.rho;\n\n this._nndescent_elements = elements.map((e, i) => {\n return {\n value: e,\n index: i,\n flag: true,\n };\n });\n\n if (elements) {\n this.add(elements);\n }\n }\n\n /**\n * Samples Array A with sample size.\n *\n * @private\n * @template U\n * @param {U[]} A\n * @returns {U[]}\n */\n _sample(A) {\n const n = A.length;\n const sample_size = this._sample_size;\n if (sample_size > n) {\n return A;\n } else {\n const randomizer = this._randomizer;\n return randomizer.choice(A, sample_size);\n }\n }\n\n /**\n * @private\n * @param {KNNHeap} B\n * @param {NNDescentNeighbor} u\n * @returns {number}\n */\n _update(B, u) {\n if (B.set.has(u.index)) return 0;\n\n const worst = B.first;\n if (worst && B.length >= this._parameters.samples) {\n const dist = B._accessor(u);\n const worst_dist = B._accessor(worst.element);\n if (dist >= worst_dist) {\n return 0; // u is worse than the worst neighbor\n }\n }\n\n B.push(u);\n u.flag = true;\n if (B.length > this._parameters.samples) {\n B.pop();\n }\n return 1;\n }\n\n /**\n * @private\n * @param {(KNNHeap | null)[]} B\n * @returns {NNDescentNeighbor[][]}\n */\n _reverse(B) {\n const N = this._N;\n const R = new Array(N);\n for (let i = 0; i < N; i++) {\n R[i] = [];\n }\n for (let j = 0; j < N; j++) {\n const Bi = B[j];\n if (Bi) {\n const Bjdata = Bi.data();\n for (const neighbor of Bjdata) {\n const v = neighbor.index;\n R[v].push(neighbor);\n }\n }\n }\n return R;\n }\n\n /**\n * @param {T[]} elements\n * @returns {this}\n */\n add(elements) {\n const randomizer = this._randomizer;\n const metric = this._parameters.metric;\n const K = this._parameters.samples;\n const delta = this._parameters.delta;\n const N = elements.length;\n this._N = N;\n /** @type {KNNHeap[]} */\n const B = [];\n this._B = B;\n for (let i = 0; i < N; i++) {\n const e = elements[i];\n const sample = randomizer\n .choice(\n elements.map((el, idx) => ({ el, idx })),\n K,\n )\n .map((d) => {\n return { index: d.idx, distance: metric(d.el, e), value: d.el };\n });\n const Bi = new KNNHeap(sample, (d) => d.distance, \"max\");\n B.push(Bi);\n }\n\n let c = Infinity;\n let old_c = -Infinity;\n while (c > delta * N * K && c !== old_c) {\n const old_ = new Array(N);\n const new_ = new Array(N);\n for (let i = 0; i < N; i++) {\n const Bi = B[i].data();\n const falseBs = Bi.filter((d) => !d.flag);\n const trueBs = this._sample(Bi.filter((d) => d.flag));\n for (const d of trueBs) {\n d.flag = false;\n }\n old_[i] = new KNNHeap(falseBs, (d) => d.distance, \"max\");\n new_[i] = new KNNHeap(trueBs, (d) => d.distance, \"max\");\n }\n const old_reverse = this._reverse(old_);\n const new_reverse = this._reverse(new_);\n old_c = c;\n c = 0;\n for (let i = 0; i < N; i++) {\n for (const o of this._sample(old_reverse[i])) {\n old_[i].push(o);\n }\n for (const n of this._sample(new_reverse[i])) {\n new_[i].push(n);\n }\n\n const new_i = new_[i].data();\n const old_i = old_[i].data();\n const n1 = new_i.length;\n const n2 = old_i.length;\n for (let j = 0; j < n1; j++) {\n const u1 = new_i[j];\n const Bu1 = B[u1.index];\n for (let k = 0; k < n1; k++) {\n const u2 = new_i[k];\n if (u1.index === u2.index) continue;\n const Bu2 = B[u2.index];\n c += this._update(Bu2, u1);\n c += this._update(Bu1, u2);\n }\n for (let k = 0; k < n2; k++) {\n const u2 = old_i[k];\n if (u1.index === u2.index) continue;\n const Bu2 = B[u2.index];\n c += this._update(Bu2, u1);\n c += this._update(Bu1, u2);\n }\n }\n }\n }\n this.nn = this._B.map((heap) => heap.data());\n return this;\n }\n\n /**\n * @param {T} x\n * @param {number} [k=5] Default is `5`\n * @returns {{ element: T, index: number; distance: number }[]}\n */\n search(x, k = 5) {\n const metric = this._parameters.metric;\n const N = this._N;\n const elements = this._elements;\n\n if (N === 0) return [];\n const xLength = x.length;\n\n // Initialize candidate pool\n const visited = new Set();\n /** @type {{index: number, dist: number, evaluated: boolean}[]} */\n let pool = [];\n\n // Randomly pick initial candidates\n const randomizer = this._randomizer;\n for (let i = 0; i < Math.min(N, Math.max(k * 10, 50)); i++) {\n let rnd;\n do {\n rnd = randomizer.random_int % N;\n } while (visited.has(rnd));\n visited.add(rnd);\n\n const element = elements[rnd];\n if (!element || element.length !== xLength) continue;\n\n pool.push({\n index: rnd,\n dist: metric(x, element),\n evaluated: false,\n });\n }\n\n let searching = true;\n while (searching) {\n pool.sort((a, b) => a.dist - b.dist);\n // keep the top subset for exploration\n pool = pool.slice(0, Math.max(k * 5, 50));\n\n searching = false;\n for (let i = 0; i < pool.length; i++) {\n const candidate = pool[i];\n if (candidate.evaluated) continue;\n\n candidate.evaluated = true;\n searching = true;\n\n // get neighbors of this candidate from graph\n const neighbors = this.nn[candidate.index];\n if (!neighbors) continue;\n\n for (const neighbor of neighbors) {\n const n_idx = neighbor.index;\n if (!visited.has(n_idx)) {\n visited.add(n_idx);\n const element = elements[n_idx];\n if (element && element.length === xLength) {\n pool.push({\n index: n_idx,\n dist: metric(x, element),\n evaluated: false,\n });\n }\n }\n }\n // Don't break here! Look at more candidates per iteration for better convergence\n // break;\n }\n }\n\n pool.sort((a, b) => a.dist - b.dist);\n\n /** @type {{ element: T, index: number; distance: number }[]} */\n const result = [];\n for (let i = 0; i < Math.min(k, pool.length); i++) {\n const item = pool[i];\n result.push({\n element: elements[item.index],\n index: item.index,\n distance: item.dist,\n });\n }\n return result;\n }\n\n /**\n * @param {number} i\n * @param {number} [k=5] Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i, k = 5) {\n // Use regular search with the element at index i\n const elements = this._elements;\n if (i < 0 || i >= elements.length) return [];\n\n const element = elements[i];\n if (!element) return [];\n\n return this.search(element, k);\n }\n}\n\n/**\n * @template {number[] | Float64Array} U\n * @typedef {Object} HeapEntry\n * @property {NNDescentNeighbor} element\n * @property {number} value\n */\n\n/**\n * @template {number[] | Float64Array} U\n * @extends {Heap>}\n */\nclass KNNHeap extends Heap {\n /** @type {Set} */\n set;\n\n /**\n * @param {NNDescentNeighbor[]} elements\n * @param {(d: NNDescentNeighbor) => number} accessor\n * @param {\"max\" | \"min\"} comparator\n */\n constructor(elements, accessor, comparator) {\n super(null, accessor, comparator);\n this.set = new Set();\n if (elements) {\n for (const element of elements) {\n this.push(element);\n }\n }\n }\n\n /**\n * @param {NNDescentNeighbor} element\n * @returns {KNNHeap}\n */\n push(element) {\n const set = this.set;\n if (set.has(element.index)) {\n return this;\n } else {\n set.add(element.index);\n super.push(element);\n return this;\n }\n }\n\n /** @returns {{ element: NNDescentNeighbor; value: number } | null} */\n pop() {\n const result = super.pop();\n if (result?.element) {\n this.set.delete(result.element.index);\n return result;\n }\n return null;\n }\n\n /** @returns {NNDescentNeighbor[]} */\n data() {\n return this._container.map((d) => d.element);\n }\n}\n","import { distance_matrix, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersSMACOF} from \"./index.js\" */\n\n/**\n * Metric Multidimensional Scaling (MDS) via SMACOF.\n *\n * SMACOF (Scaling by Majorizing a Complicated Function) is an iterative majorization\n * algorithm for solving metric multidimensional scaling problems, which aims to\n * minimize the stress function.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link MDS} for the classical approach.\n */\nexport class SMACOF extends DR {\n /**\n * SMACOF for MDS.\n *\n * @param {T} X - The high-dimensional data or precomputed distance matrix.\n * @param {Partial} [parameters] - Object containing parameterization.\n */\n constructor(X, parameters = {}) {\n super(X, { d: 2, metric: euclidean, seed: 1212, iterations: 300, epsilon: 1e-4 }, parameters);\n }\n\n /**\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n this.check_init();\n const X = this.X;\n const rows = this._N;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const metric = /** @type {typeof euclidean | \"precomputed\"} */ (this.parameter(\"metric\"));\n const iterations = /** @type {number} */ (this.parameter(\"iterations\"));\n const epsilon = /** @type {number} */ (this.parameter(\"epsilon\"));\n\n const target_distances = metric === \"precomputed\" ? X : distance_matrix(X, metric);\n\n let Z = new Matrix(rows, d, () => (this._randomizer.random - 0.5) * 2);\n\n // Center Z\n for (let j = 0; j < d; ++j) {\n const col = Z.col(j);\n const mean = col.reduce((a, b) => a + b, 0) / rows;\n for (let i = 0; i < rows; ++i) {\n Z.sub_entry(i, j, mean);\n }\n }\n\n this.Y = /** @type {Matrix} */ (Z); // Initial state\n\n let prev_stress = Infinity;\n\n if (!(iterations > 0)) {\n yield this.projection;\n return this.projection;\n }\n\n for (let iter = 0; iter < iterations; ++iter) {\n const B = new Matrix(rows, rows, 0);\n\n for (let i = 0; i < rows; ++i) {\n let bii = 0;\n const z_i = Z.row(i);\n for (let j = 0; j < rows; ++j) {\n if (i === j) continue;\n const z_j = Z.row(j);\n const dist_Z = euclidean(z_i, z_j);\n const dist_target = target_distances.entry(i, j);\n\n let bij = 0;\n if (dist_Z > 1e-12) {\n bij = -dist_target / dist_Z;\n }\n B.set_entry(i, j, bij);\n bii -= bij;\n }\n B.set_entry(i, i, bii);\n }\n\n // Z_new = 1/N * B(Z) * Z\n const Z_new = B.dot(Z)._apply(rows, (val, n) => val / n);\n\n this.Y = /** @type {Matrix} */ (Z_new);\n Z = /** @type {Matrix} */ (Z_new);\n\n // Calculate stress\n let stress_num = 0;\n let stress_den = 0;\n for (let i = 0; i < rows; ++i) {\n const z_i = Z.row(i);\n for (let j = i + 1; j < rows; ++j) {\n const z_j = Z.row(j);\n const dist_Y = euclidean(z_i, z_j);\n const diff = target_distances.entry(i, j) - dist_Y;\n stress_num += diff * diff;\n stress_den += target_distances.entry(i, j) ** 2;\n }\n }\n const current_stress = Math.sqrt(stress_num / Math.max(stress_den, 1e-12));\n\n yield this.projection;\n\n if (Math.abs(prev_stress - current_stress) < epsilon) {\n break;\n }\n prev_stress = current_stress;\n }\n return this.projection;\n }\n\n /**\n * @returns {T}\n */\n transform() {\n const gen = this.generator();\n let res = /** @type {T} */ (this.X);\n for (const step of gen) {\n res = step;\n }\n return res;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new SMACOF(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new SMACOF(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new SMACOF(X, parameters);\n return dr.transform_async();\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { BallTree } from \"../knn/index.js\";\nimport { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\nimport { SMACOF } from \"./SMACOF.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersISOMAP} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n\n/**\n * Isomap (Isometric Mapping)\n *\n * A nonlinear dimensionality reduction algorithm that uses geodesic distances\n * between points on a manifold to perform embedding. It builds a neighborhood\n * graph and uses MDS on the shortest-path distances.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link LLE} for another nonlinear alternative\n */\nexport class ISOMAP extends DR {\n /**\n * Isometric feature mapping (ISOMAP).\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n * @see {@link https://doi.org/10.1126/science.290.5500.2319}\n */\n constructor(X, parameters = {}) {\n /** @type {ParametersISOMAP} */\n const defaults = {\n neighbors: -Infinity,\n d: 2,\n metric: euclidean,\n seed: 1212,\n project: \"MDS\",\n eig_args: {},\n };\n super(X, defaults, parameters);\n\n this.defaults = defaults;\n\n if (this._parameters.neighbors === -Infinity) {\n this.parameter(\"neighbors\", Math.min(Math.max(Math.floor(this.X.shape[0] / 10), 2), this._N - 1));\n }\n\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n if (!Object.hasOwn(eig_args, \"seed\")) {\n eig_args.seed = this._randomizer;\n }\n }\n\n /**\n * Computes the projection.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * @returns {T}\n */\n transform() {\n this.check_init();\n const X = this.X;\n const rows = this._N;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const metric = /** @type {typeof euclidean} */ (this.parameter(\"metric\"));\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n const neighbors = /** @type {number} */ (this.parameter(\"neighbors\"));\n // TODO: make knn extern and parameter for constructor or transform?\n const D = new Matrix(rows, rows, 0);\n D.shape = [rows, rows, (i, j) => (i <= j ? metric(X.row(i), X.row(j)) : D.entry(j, i))];\n\n /** @type {{ index: number; distance: number }[][]} */\n const kNearestNeighbors = [];\n const tree = new BallTree(X.to2dArray(), { metric, seed: /** @type {number} */ (this.parameter(\"seed\")) });\n for (let i = 0; i < rows; ++i) {\n // BallTree search returns elements including the queried point itself (at distance 0).\n // Request neighbors + 1 and slice off the first one (which should be the query point).\n const neighborsList = tree.search_by_index(i, neighbors + 1);\n kNearestNeighbors.push(\n neighborsList.slice(1).map((n) => ({\n index: n.index,\n distance: n.distance,\n })),\n );\n }\n\n // ISOMAP requires an undirected/symmetric nearest neighbor graph.\n // If i is a nearest neighbor of j, then j should be connected to i as well.\n for (let i = 0; i < rows; ++i) {\n for (const neighbor of kNearestNeighbors[i]) {\n const j = neighbor.index;\n const d = neighbor.distance;\n const reciprocal_edge = kNearestNeighbors[j].find((n) => n.index === i);\n if (!reciprocal_edge) {\n kNearestNeighbors[j].push({ index: i, distance: d });\n }\n }\n }\n\n /*D = dijkstra(kNearestNeighbors);*/\n // compute shortest paths using Dijkstra's algorithm\n // TODO: make extern\n const G = new Matrix(rows, rows, Infinity);\n\n for (let i = 0; i < rows; ++i) {\n G.set_entry(i, i, 0);\n const H = new Heap([{ index: i, distance: 0 }], (d) => d.distance, \"min\");\n\n while (!H.empty) {\n const item = H.pop();\n if (!item) break;\n\n const u = item.element.index;\n const dist_u = item.element.distance;\n\n if (dist_u > G.entry(i, u)) continue;\n\n for (const neighbor of kNearestNeighbors[u]) {\n const v = neighbor.index;\n const alt = dist_u + neighbor.distance;\n if (alt < G.entry(i, v)) {\n G.set_entry(i, v, alt);\n H.push({ index: v, distance: alt });\n }\n }\n }\n }\n\n let max_val = 0;\n for (let i = 0; i < rows; i++) {\n for (let j = 0; j < rows; j++) {\n const val = G.entry(i, j);\n if (val !== Infinity && val > max_val) max_val = val;\n }\n }\n const big_val = max_val * 10;\n\n const project = /** @type {\"MDS\" | \"SMACOF\"} */ (this.parameter(\"project\"));\n\n if (project === \"SMACOF\") {\n // Apply SMACOF metric MDS to the distance matrix directly\n const D_matrix = new Matrix(rows, rows, (i, j) => {\n const val = G.entry(i, j);\n return val === Infinity ? big_val : val;\n });\n const smacof = new SMACOF(D_matrix, { metric: \"precomputed\", d, seed: this.parameter(\"seed\") });\n smacof.transform();\n this.Y = smacof.Y;\n } else {\n // \"MDS\" (Classical MDS) via Eigendecomposition of double-centered squared distance matrix\n const D_sq = new Matrix(rows, rows, (i, j) => {\n let val = G.entry(i, j);\n if (val === Infinity) val = big_val;\n return val * val;\n });\n\n const ai_ = D_sq.meanCols();\n const a_j = D_sq.meanRows();\n const a__ = D_sq.mean();\n const B = new Matrix(rows, rows, (i, j) => -0.5 * (D_sq.entry(i, j) - ai_[i] - a_j[j] + a__));\n\n // compute d eigenvectors\n const { eigenvectors: V } = simultaneous_poweriteration(B, d, eig_args);\n this.Y = Matrix.from(V).transpose();\n }\n // return embedding\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new ISOMAP(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new ISOMAP(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new ISOMAP(X, parameters);\n return dr.transform_async();\n }\n}\n","import { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLDA} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n\n/**\n * Linear Discriminant Analysis (LDA)\n *\n * A supervised dimensionality reduction technique that finds the axes that\n * maximize the separation between multiple classes.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class LDA extends DR {\n /**\n * Linear Discriminant Analysis.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial & { labels: any[] | Float64Array }} parameters - Object containing parameterization of the DR method.\n * @see {@link https://onlinelibrary.wiley.com/doi/10.1111/j.1469-1809.1936.tb02137.x}\n */\n constructor(X, parameters) {\n super(X, { labels: parameters.labels, d: 2, seed: 1212, eig_args: {} }, parameters);\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n if (!Object.hasOwn(eig_args, \"seed\")) {\n eig_args.seed = this._randomizer;\n }\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T} - The projected data.\n */\n transform() {\n const X = this.X;\n const [rows, cols] = X.shape;\n const { d, labels, eig_args } = this._parameters;\n if (labels === null || labels.length !== rows) {\n throw new Error(\"LDA needs parameter label to every datapoint to work!\");\n }\n\n /** @type {Record} */\n const unique_labels = {};\n let label_id = 0;\n labels.forEach((l, i) => {\n if (l in unique_labels) {\n unique_labels[l].count++;\n unique_labels[l].rows.push(X.row(i));\n } else {\n unique_labels[l] = {\n id: label_id++,\n count: 1,\n rows: [X.row(i)],\n };\n }\n });\n\n // create X_mean and vector means;\n const X_mean = X.meanCols();\n const V_mean = new Matrix(label_id, cols);\n for (const label in unique_labels) {\n const V = Matrix.from(unique_labels[label].rows);\n const v_mean = V.meanCols();\n for (let j = 0; j < cols; ++j) {\n V_mean.set_entry(unique_labels[label].id, j, v_mean[j]);\n }\n }\n // scatter_between\n let S_b = new Matrix(cols, cols);\n for (const label in unique_labels) {\n const v = V_mean.row(unique_labels[label].id);\n const m = Matrix.from([v]).sub(Matrix.from([X_mean]));\n const N = unique_labels[label].count;\n S_b = S_b.add(m.transDot(m).mult(N));\n }\n\n // scatter_within\n let S_w = new Matrix(cols, cols);\n for (const label in unique_labels) {\n const v = V_mean.row(unique_labels[label].id);\n const R = unique_labels[label].rows;\n for (let i = 0, n = unique_labels[label].count; i < n; ++i) {\n const row_v = Matrix.from([R[i]]).sub(Matrix.from([v]));\n S_w = S_w.add(row_v.transDot(row_v));\n }\n }\n\n const { eigenvectors: EV } = simultaneous_poweriteration(\n S_w.inverse().dot(S_b),\n d || Math.min(cols, label_id - 1),\n eig_args,\n );\n const V = Matrix.from(EV).transpose();\n this.Y = X.dot(V);\n\n // return embedding\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @returns {T}\n */\n static transform(X, parameters) {\n // @ts-expect-error: LDA requires labels, but DR static transform doesn't\n const dr = new LDA(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n // @ts-expect-error: LDA requires labels, but DR static generator doesn't\n const dr = new LDA(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n // @ts-expect-error: LDA requires labels, but DR static transform doesn't\n const dr = new LDA(X, parameters);\n return dr.transform_async();\n }\n}\n","import { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { k_nearest_neighbors, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { neumair_sum } from \"../numerical/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLLE} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n\n/**\n * Locally Linear Embedding (LLE)\n *\n * A nonlinear dimensionality reduction technique that preserves local\n * linear relationships between points. It represents each point as a linear\n * combination of its neighbors.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link ISOMAP} for another nonlinear alternative\n */\nexport class LLE extends DR {\n /**\n * Locally Linear Embedding.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://doi.org/10.1126/science.290.5500.2323}\n */\n constructor(X, parameters) {\n super(\n X,\n {\n neighbors: -Infinity,\n d: 2,\n metric: euclidean,\n seed: 1212,\n eig_args: {},\n },\n parameters,\n );\n if (this._parameters.neighbors === -Infinity) {\n this.parameter(\"neighbors\", Math.min(Math.max(Math.floor(this._N / 10), 2), this._N - 1));\n }\n\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n if (!Object.hasOwn(eig_args, \"seed\")) {\n eig_args.seed = this._randomizer;\n }\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T}\n */\n transform() {\n const X = this.X;\n const rows = this._N;\n const cols = this._D;\n const neighbors = /** @type {number} */ (this.parameter(\"neighbors\"));\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n const metric = /** @type {typeof euclidean} */ (this.parameter(\"metric\"));\n const nN = k_nearest_neighbors(X, neighbors, metric);\n const O = new Matrix(neighbors, 1, 1);\n const W = new Matrix(rows, rows);\n\n for (let row = 0; row < rows; ++row) {\n const nN_row = nN[row];\n const Z = new Matrix(neighbors, cols, (i, j) => X.entry(nN_row[i].j, j) - X.entry(row, j));\n const C = Z.dotTrans(Z);\n if (neighbors > cols) {\n const C_trace = neumair_sum(C.diag()) / 1000;\n for (let j = 0; j < neighbors; ++j) {\n C.add_entry(j, j, C_trace);\n }\n }\n // reconstruct;\n let w = Matrix.solve_CG(C, O, this._randomizer);\n w = w.divide(w.sum());\n for (let j = 0; j < neighbors; ++j) {\n W.set_entry(row, nN_row[j].j, w.entry(j, 0));\n }\n }\n // comp embedding\n const I = new Matrix(rows, rows, \"identity\");\n const IW = I.sub(W);\n const M = IW.transDot(IW);\n\n // M is symmetric positive semi-definite. Smallest eigenvalue is 0 (ones vector).\n // To find smallest eigenvalues of M, we can find largest of (C*I - M)\n // Upper bound for max eigenvalue: Frobenius norm or sum of absolute values\n const C = M.mean() * rows * 2; // Safe upper bound for a sparse-ish M in LLE\n const CI_M = new Matrix(rows, rows, (i, j) => (i === j ? C : 0) - M.entry(i, j));\n\n const { eigenvectors: V } = simultaneous_poweriteration(CI_M, d + 1, eig_args);\n // Skip the first eigenvector (the ones vector corresponding to eigenvalue C)\n this.Y = Matrix.from(V.slice(1, 1 + d)).T;\n\n // return embedding\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new LLE(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new LLE(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new LLE(X, parameters);\n return dr.transform_async();\n }\n}\n","import { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { distance_matrix, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersMDS} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n\n/**\n * Classical Multidimensional Scaling (MDS)\n *\n * A linear dimensionality reduction technique that seeks to preserve the\n * pairwise distances between points as much as possible in the lower-dimensional\n * space.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link PCA} for another linear alternative\n */\nexport class MDS extends DR {\n /**\n * Classical MDS.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X, parameters = {}) {\n super(X, { d: 2, metric: euclidean, seed: 1212, eig_args: {} }, parameters);\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n if (!Object.hasOwn(eig_args, \"seed\")) {\n eig_args.seed = this._randomizer;\n }\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T}\n */\n transform() {\n const X = this.X;\n const rows = X.shape[0];\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const metric = /** @type {typeof euclidean | \"precomputed\"} */ (this.parameter(\"metric\"));\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n const A = metric === \"precomputed\" ? X : distance_matrix(X, metric);\n\n const D_sq = new Matrix(rows, rows, (i, j) => {\n const val = A.entry(i, j);\n return val * val;\n });\n\n const ai_ = D_sq.meanCols();\n const a_j = D_sq.meanRows();\n const a__ = D_sq.mean();\n\n this._d_X = A;\n const B = new Matrix(rows, rows, (i, j) => -0.5 * (D_sq.entry(i, j) - ai_[i] - a_j[j] + a__));\n\n const { eigenvectors: V } = simultaneous_poweriteration(B, d, eig_args);\n this.Y = Matrix.from(V).transpose();\n\n return this.projection;\n }\n\n /** @returns {number} - The stress of the projection. */\n stress() {\n const N = this.X.shape[0];\n const Y = this.Y;\n const d_X = this._d_X;\n if (!d_X) throw new Error(\"First transform!\");\n\n const d_Y = new Matrix(N, N, 0);\n d_Y.shape = [\n N,\n N,\n (i, j) => {\n return i < j ? euclidean(Y.row(i), Y.row(j)) : d_Y.entry(j, i);\n },\n ];\n let top_sum = 0;\n let bottom_sum = 0;\n for (let i = 0; i < N; ++i) {\n for (let j = i + 1; j < N; ++j) {\n top_sum += (d_X.entry(i, j) - d_Y.entry(i, j)) ** 2;\n bottom_sum += d_X.entry(i, j) ** 2;\n }\n }\n return Math.sqrt(top_sum / bottom_sum);\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new MDS(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new MDS(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new MDS(X, parameters);\n return dr.transform_async();\n }\n}\n","import { KMedoids } from \"../clustering/index.js\";\nimport { BallTree } from \"../knn/index.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\nimport { MDS } from \"./MDS.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLSP} from \"./index.js\" */\n\n/**\n * Least Square Projection (LSP)\n *\n * A dimensionality reduction technique that uses a small set of control points\n * (projected with MDS) to define the projection for the rest of the data\n * using a Laplacian-based optimization.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class LSP extends DR {\n /**\n * Least Squares Projection.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n * @see {@link https://ieeexplore.ieee.org/document/4378370}\n */\n constructor(X, parameters) {\n super(\n X,\n {\n neighbors: -Infinity,\n control_points: -Infinity,\n d: 2,\n metric: euclidean,\n seed: 1212,\n },\n parameters,\n );\n if (this.parameter(\"neighbors\") === -Infinity) {\n this.parameter(\"neighbors\", Math.min(Math.max(Math.floor(this._N / 10), 2), this._N - 1));\n }\n if (this.parameter(\"control_points\") === -Infinity) {\n this.parameter(\"control_points\", Math.min(Math.ceil(Math.sqrt(this._N)), this._N - 1));\n }\n this._is_initialized = false;\n }\n\n /**\n * @returns {LSP}\n */\n //\tinit(DR = MDS, DR_parameters = {}, KNN = BallTree) {\n init() {\n const DR = MDS;\n let DR_parameters = {};\n const KNN = BallTree;\n if (this._is_initialized) return this;\n const X = this.X;\n const N = this._N;\n const K = /** @type {number} */ (this.parameter(\"neighbors\"));\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const seed = /** @type {number} */ (this.parameter(\"seed\"));\n const metric = /** @type {typeof euclidean} */ (this.parameter(\"metric\"));\n DR_parameters = Object.assign({ d, metric, seed }, DR_parameters);\n const nc = /** @type {number} */ (this.parameter(\"control_points\"));\n const control_points = new KMedoids(X, { K: nc, metric }).get_medoids();\n const C = new Matrix(nc, N, \"zeros\");\n control_points.forEach((c_i, i) => {\n C.set_entry(i, c_i, 1);\n });\n\n const control_points_matrix = Matrix.from(control_points.map((c_i) => X.row(c_i)));\n const Y_C = new DR(control_points_matrix, DR_parameters).transform();\n\n const XA = X.to2dArray();\n const knn = new KNN(XA, { metric, seed });\n const L = new Matrix(N, N, \"I\");\n const alpha = -1 / K;\n XA.forEach((x_i, i) => {\n for (const { index: j } of knn.search(x_i, K)) {\n if (i === j) continue;\n L.set_entry(i, j, alpha);\n }\n });\n const A = L.concat(C, \"vertical\");\n\n const z = new Matrix(N, d, \"zeros\");\n const b = z.concat(Y_C, \"vertical\");\n\n this._A = A;\n this._b = b;\n this._is_initialized = true;\n return this;\n }\n\n /**\n * Computes the projection.\n *\n * @returns {T} Returns the projection.\n */\n transform() {\n this.check_init();\n const A = this._A;\n const b = this._b;\n\n if (!A || !b) throw new Error(\"Call init() first!\");\n const ATA = A.transDot(A);\n const ATb = A.transDot(b);\n this.Y = Matrix.solve_CG(ATA, ATb, this._randomizer);\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new LSP(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new LSP(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new LSP(X, parameters);\n return dr.transform_async();\n }\n}\n","import { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { k_nearest_neighbors, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLTSA} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n\n/**\n * Local Tangent Space Alignment (LTSA)\n *\n * A nonlinear dimensionality reduction algorithm that represents the local\n * geometry of the manifold by tangent spaces and then aligns them to reveal\n * the global structure.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class LTSA extends DR {\n /**\n * Local Tangent Space Alignment\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://epubs.siam.org/doi/abs/10.1137/S1064827502419154}\n */\n constructor(X, parameters) {\n super(\n X,\n {\n neighbors: -Infinity,\n d: 2,\n metric: euclidean,\n seed: 1212,\n eig_args: {},\n },\n parameters,\n );\n if (this.parameter(\"neighbors\") === -Infinity) {\n this.parameter(\"neighbors\", Math.min(Math.max(Math.floor(this._N / 10), 2), this._N - 1));\n }\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n if (!Object.hasOwn(eig_args, \"seed\")) {\n eig_args.seed = this._randomizer;\n }\n\n const d = /** @type {number} */ (this.parameter(\"d\"));\n if (this._D <= d) {\n throw new Error(\n `Dimensionality of X (D = ${this._D}) must be greater than the required dimensionality of the result (d = ${d})!`,\n );\n }\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimenionality `d`.\n *\n * @returns {T}\n */\n transform() {\n const X = this.X;\n const [rows, D] = X.shape;\n const neighbors = /** @type {number} */ (this.parameter(\"neighbors\"));\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n const metric = /** @type {typeof euclidean} */ (this.parameter(\"metric\"));\n // 1.1 determine k nearest neighbors\n const nN = k_nearest_neighbors(X, neighbors, metric);\n // center matrix\n const O = new Matrix(D, D, \"center\");\n const B = new Matrix(rows, rows, 0);\n\n for (let row = 0; row < rows; ++row) {\n // 1.2 compute the d largest eigenvectors of the correlation matrix\n const I_i = [row, ...nN[row].map((n) => n.j)];\n let X_i = Matrix.from(I_i.map((n) => X.row(n)));\n // center X_i\n X_i = X_i.dot(O);\n // correlation matrix\n const C = X_i.dotTrans(X_i);\n const { eigenvectors: g } = simultaneous_poweriteration(C, d, eig_args);\n //g.push(linspace(0, k).map(_ => 1 / Math.sqrt(k + 1)));\n const G_i_t = Matrix.from(g);\n // 2. Constructing alignment matrix\n const W_i = G_i_t.transDot(G_i_t).add(1 / Math.sqrt(neighbors + 1));\n for (let i = 0; i < neighbors + 1; ++i) {\n for (let j = 0; j < neighbors + 1; ++j) {\n B.add_entry(I_i[i], I_i[j], W_i.entry(i, j) - (i === j ? 1 : 0));\n }\n }\n }\n\n // 3. Aligning global coordinates\n const { eigenvectors: Y } = simultaneous_poweriteration(B, d + 1, eig_args);\n this.Y = Matrix.from(Y.slice(1)).transpose();\n\n // return embedding\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new LTSA(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new LTSA(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new LTSA(X, parameters);\n return dr.transform_async();\n }\n}\n","import { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersPCA} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n\n/**\n * Principal Component Analysis (PCA)\n *\n * A linear dimensionality reduction technique that identifies the axes (principal components)\n * along which the variance of the data is maximized.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link MDS} for another linear alternative\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2], [3, 4], [5, 6]];\n * const pca = new druid.PCA(X, { d: 2 });\n * const Y = pca.transform();\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class PCA extends DR {\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X, parameters = {}) {\n super(X, { d: 2, seed: 1212, eig_args: {} }, parameters);\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n if (!Object.hasOwn(eig_args, \"seed\")) {\n eig_args.seed = this._randomizer;\n }\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T} - The projected data.\n */\n transform() {\n const V = this.principal_components();\n const X = this.X;\n this.Y = X.dot(V);\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new PCA(X, parameters);\n return dr.transform();\n }\n\n /**\n * Computes the `d` principal components of Matrix `X`.\n *\n * @returns {Matrix}\n */\n principal_components() {\n if (this.V) {\n return this.V;\n }\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n const X = this.X;\n const X_cent = X.sub(X.meanCols());\n const C = X_cent.transDot(X_cent);\n const { eigenvectors: V } = simultaneous_poweriteration(C, d, eig_args);\n this.V = Matrix.from(V).transpose();\n return this.V;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Matrix}\n */\n static principal_components(X, parameters) {\n const dr = new PCA(X, parameters);\n return dr.principal_components();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new PCA(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new PCA(X, parameters);\n return dr.transform_async();\n }\n}\n","import { distance_matrix, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\nimport { MDS, PCA } from \"./index.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersPCA, ParametersMDS, ParametersSAMMON} from \"./index.js\" */\n/** @typedef {\"PCA\" | \"MDS\" | \"random\"} AvailableInit */\n\n/** @typedef {{ PCA: ParametersPCA; MDS: ParametersMDS; random: {} }} ChooseDR */\n\n/**\n * Sammon's Mapping\n *\n * A nonlinear dimensionality reduction technique that minimizes a stress\n * function based on the ratio of pairwise distances in high and low dimensional spaces.\n *\n * @class\n * @template {InputType} T\n * @extends DR>\n * @category Dimensionality Reduction\n */\nexport class SAMMON extends DR {\n /** @type {Matrix | undefined} */\n distance_matrix;\n\n /**\n * SAMMON's Mapping\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial>} [parameters] - Object containing parameterization of the DR\n * method.\n * @see {@link https://arxiv.org/pdf/2009.01512.pdf}\n */\n constructor(X, parameters) {\n super(\n X,\n {\n magic: 0.1,\n d: 2,\n metric: euclidean,\n seed: 1212,\n init_DR: \"random\",\n init_parameters: {},\n },\n parameters,\n );\n }\n\n /**\n * Initializes the projection.\n *\n * @param {Matrix | undefined} D\n * @returns {asserts D is Matrix}\n */\n init(D) {\n const N = this.X.shape[0];\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const metric = /** @type {typeof euclidean | \"precomputed\"} */ (this.parameter(\"metric\"));\n const init_DR = /** @type {AvailableInit} */ (this.parameter(\"init_DR\"));\n const DR_parameters = this.parameter(\"init_parameters\");\n if (init_DR === \"random\") {\n const randomizer = this._randomizer;\n this.Y = new Matrix(N, d, () => randomizer.random);\n } else if (init_DR === \"PCA\") {\n this.Y = Matrix.from(PCA.transform(this.X, /** @type {ParametersPCA} */ (DR_parameters)));\n } else if (init_DR === \"MDS\") {\n this.Y = Matrix.from(MDS.transform(this.X, /** @type {ParametersMDS} */ (DR_parameters)));\n } else {\n throw new Error('init_DR needs to be either \"random\" or a DR method!');\n }\n D = metric === \"precomputed\" ? Matrix.from(this.X) : distance_matrix(this.X, metric);\n this.distance_matrix = D;\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality 2.\n *\n * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200`\n * @returns {T} The projection of `X`.\n */\n transform(max_iter = 200) {\n this.check_init();\n if (!this.distance_matrix) this.init(this.distance_matrix);\n for (let j = 0; j < max_iter; ++j) {\n this._step();\n }\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimenionality 2.\n *\n * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200`\n * @returns {Generator} A generator yielding the intermediate steps of the projection of\n * `X`.\n */\n *generator(max_iter = 200) {\n this.check_init();\n if (!this.distance_matrix) this.init(this.distance_matrix);\n\n for (let j = 0; j < max_iter; ++j) {\n this._step();\n yield this.projection;\n }\n\n return this.projection;\n }\n\n _step() {\n if (!this.distance_matrix) this.init(this.distance_matrix);\n const MAGIC = /** @type {number} */ (this.parameter(\"magic\"));\n const D = /** @type {Matrix} */ (this.distance_matrix);\n const N = this.X.shape[0];\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const Y = this.Y;\n\n const G = new Matrix(N, d, 0);\n\n const sum = new Float64Array(d);\n for (let i = 0; i < N; ++i) {\n const e1 = new Float64Array(d);\n const e2 = new Float64Array(d);\n const Yi = Y.row(i);\n for (let j = 0; j < N; ++j) {\n if (i === j) continue;\n const dX = D.entry(i, j);\n if (dX === 0) continue; // Skip identical points in high-dim\n\n const Yj = Y.row(j);\n const delta = new Float64Array(d);\n for (let k = 0; k < d; ++k) {\n delta[k] = Yi[k] - Yj[k];\n }\n const dY = Math.max(euclidean(Yi, Yj), 1e-6);\n const dq = dX - dY;\n const dr = dX * dY;\n for (let k = 0; k < d; ++k) {\n e1[k] += (delta[k] * dq) / dr;\n e2[k] += (dq - (delta[k] ** 2 * (1 + dq / dY)) / dY) / dr;\n }\n }\n for (let k = 0; k < d; ++k) {\n const val = Y.entry(i, k) + ((MAGIC * e1[k]) / Math.abs(e2[k]) || 0);\n G.set_entry(i, k, val);\n sum[k] += val;\n }\n }\n for (let k = 0; k < d; ++k) {\n sum[k] /= N;\n }\n\n for (let i = 0; i < N; ++i) {\n for (let k = 0; k < d; ++k) {\n Y.set_entry(i, k, G.entry(i, k) - sum[k]);\n }\n }\n return Y;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial>} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new SAMMON(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial>} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new SAMMON(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial>} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new SAMMON(X, parameters);\n return dr.transform_async();\n }\n}\n","import { linspace, Matrix, norm } from \"../matrix/index.js\";\nimport { euclidean, euclidean_squared } from \"../metrics/index.js\";\nimport { neumair_sum } from \"../numerical/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersSQDMDS} from \"./index.js\" */\n\n/**\n * SQuadMDS (Stochastic Quartet MDS)\n *\n * A lean Stochastic Quartet MDS improving global structure preservation in\n * neighbor embedding like t-SNE and UMAP.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class SQDMDS extends DR {\n /**\n * SQuadMDS: a lean Stochastic Quartet MDS improving global structure preservation in neighbor embedding like t-SNE\n * and UMAP.\n *\n * @param {T} X\n * @param {Partial} [parameters]\n * @see {@link https://arxiv.org/pdf/2202.12087.pdf}\n */\n constructor(X, parameters) {\n super(\n X,\n {\n d: 2,\n metric: euclidean,\n seed: 1212,\n decay_start: 0.1,\n decay_cte: 0.34, // 0.34\n },\n parameters,\n );\n\n this.init();\n if (this.parameter(\"metric\") === \"precomputed\" && this.X.shape[0] !== this.X.shape[1]) {\n throw new Error(\"SQDMDS input data must be a square Matrix\");\n }\n }\n\n init() {\n const N = this._N;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n\n // initialize helpers.\n this._add = this.__add(d);\n this._sub_div = this.__sub_div(d);\n this._minus = this.__minus(d);\n this._mult = this.__mult(d);\n this._LR_init = Math.max(2, 0.005 * N);\n this._LR = this._LR_init;\n const decay_cte = /** @type {number} */ (this.parameter(\"decay_cte\"));\n this._offset = -Math.exp(-1 / decay_cte);\n this._momentums = new Matrix(N, d, 0);\n this._grads = new Matrix(N, d, 0);\n this._indices = linspace(0, N - 1);\n // initialize projection.\n const R = this._randomizer;\n this.Y = new Matrix(N, d, () => R.random - 0.5);\n\n // preparing metric for optimization.\n const this_metric = /** @type {Metric | \"precomputed\"} */ (this.parameter(\"metric\"));\n if (this_metric === \"precomputed\") {\n /** @type {(i: number, j: number, X: Matrix) => number} */\n this._HD_metric = (i, j, X) => X.entry(i, j);\n /** @type {(i: number, j: number, X: Matrix) => number} */\n this._HD_metric_exaggeration = (i, j, X) => X.entry(i, j) ** 2;\n } else {\n this._HD_metric = (i, j, X) => this_metric(X.row(i), X.row(j));\n if (this_metric === euclidean) {\n this._HD_metric_exaggeration = (i, j, X) => euclidean_squared(X.row(i), X.row(j));\n } else {\n this._HD_metric_exaggeration = (i, j, X) => this_metric(X.row(i), X.row(j)) ** 2;\n }\n }\n return;\n }\n\n /**\n * Computes the projection.\n *\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {T} The projection.\n */\n transform(iterations = 500) {\n this.check_init();\n const decay_start = /** @type {number} */ (this.parameter(\"decay_start\"));\n this._decay_start = Math.round(decay_start * iterations);\n for (let i = 0; i < iterations; ++i) {\n this._step(i, iterations);\n }\n return this.projection;\n }\n\n /**\n * Computes the projection.\n *\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {Generator} The intermediate steps of the projection.\n */\n *generator(iterations = 500) {\n this.check_init();\n const decay_start = /** @type {number} */ (this.parameter(\"decay_start\"));\n this._decay_start = Math.round(decay_start * iterations);\n for (let i = 0; i < iterations; ++i) {\n this._step(i, iterations);\n yield this.projection;\n }\n\n return this.projection;\n }\n\n /**\n * Performs an optimization step.\n *\n * @private\n * @param {number} i - Acutal iteration.\n * @param {number} iterations - Number of iterations.\n */\n _step(i, iterations) {\n if (this._LR_init === undefined || this._offset === undefined) throw new Error(\"Call init() first!\");\n\n const decay_start = /** @type {number} */ (this.parameter(\"decay_start\"));\n if (i > decay_start) {\n const decay_cte = /** @type {number} */ (this.parameter(\"decay_cte\"));\n const offset = this._offset;\n const ratio = (i - decay_start) / (iterations - decay_start);\n this._LR = this._LR_init * (Math.exp(-(ratio * ratio) / decay_cte) + offset);\n this._distance_exaggeration = false;\n } else {\n this._distance_exaggeration = true;\n }\n this._nestrov_iteration(this._distance_exaggeration);\n }\n\n /**\n * Creates quartets of non overlapping indices.\n *\n * @private\n * @returns {Uint32Array[]}\n */\n __quartets() {\n if (!this._indices) throw new Error(\"Call init() first!\");\n if (this._offset === undefined) throw new Error(\"Call init() first!\");\n const N = this._N;\n const max_N = N - (N % 4);\n const R = this._randomizer;\n const shuffled_indices = R.choice(this._indices, max_N);\n const result = [];\n for (let i = 0; i < max_N; i += 4) {\n result.push(\n Uint32Array.of(\n shuffled_indices[i],\n shuffled_indices[i + 1],\n shuffled_indices[i + 2],\n shuffled_indices[i + 3],\n ),\n );\n }\n return result;\n }\n\n /**\n * Computes and applies gradients, and updates momentum.\n *\n * @private\n * @param {boolean} distance_exaggeration\n */\n _nestrov_iteration(distance_exaggeration) {\n if (!this._momentums || !this._grads || this._LR === undefined) throw new Error(\"Call init() first!\");\n const momentums = this._momentums.mult(0.99, { inline: true });\n const LR = this._LR;\n const grads = this._fill_MDS_grads(this.Y.add(momentums), this._grads, distance_exaggeration);\n const [n, d] = momentums.shape;\n for (let i = 0; i < n; ++i) {\n const g_i = grads.row(i);\n const g_i_norm = norm(g_i);\n if (g_i_norm === 0) continue;\n const mul = LR / g_i_norm;\n const m_i = momentums.row(i);\n for (let j = 0; j < d; ++j) {\n m_i[j] -= mul * g_i[j];\n }\n } // momentums -= (LR / norm) * grads\n this.Y.add(momentums, { inline: true });\n }\n\n /**\n * Computes the gradients.\n *\n * @param {Matrix} Y - The Projection.\n * @param {Matrix} grads - The gradients.\n * @param {boolean} [exaggeration=false] - Whether or not to use early exaggeration. Default is `false`\n * @param {boolean} [zero_grad=true] - Whether or not to reset the gradient in the beginning. Default is `true`\n * @returns {Matrix} The gradients.\n */\n _fill_MDS_grads(Y, grads, exaggeration = false, zero_grad = true) {\n if (!this._HD_metric || !this._HD_metric_exaggeration || !this._add) throw new Error(\"Call init() first!\");\n if (zero_grad) {\n // compute new gradients\n grads.values.fill(0);\n }\n const add = this._add;\n const X = this.X;\n let HD_metric;\n if (exaggeration === true) {\n HD_metric = this._HD_metric_exaggeration;\n } else {\n HD_metric = this._HD_metric;\n }\n\n const D_quartet = new Float64Array(6);\n const quartets = this.__quartets();\n for (const [i, j, k, l] of quartets) {\n // compute quartet's HD distances.\n D_quartet[0] = HD_metric(i, j, X);\n D_quartet[1] = HD_metric(i, k, X);\n D_quartet[2] = HD_metric(i, l, X);\n D_quartet[3] = HD_metric(j, k, X);\n D_quartet[4] = HD_metric(j, l, X);\n D_quartet[5] = HD_metric(k, l, X);\n\n const D_quartet_sum = neumair_sum(D_quartet);\n\n if (D_quartet_sum > 0) {\n for (let i = 0; i < 6; ++i) {\n D_quartet[i] /= D_quartet_sum;\n D_quartet[i] += 1e-11;\n }\n }\n const [gi, gj, gk, gl] = this._compute_quartet_grads(Y, [i, j, k, l], D_quartet);\n\n // add is inline, row acces the matrix\n add(grads.row(i), gi);\n add(grads.row(j), gj);\n add(grads.row(k), gk);\n add(grads.row(l), gl);\n }\n return grads;\n }\n\n /**\n * Quartet gradients for a projection.\n *\n * @private\n * @param {Matrix} Y - The acutal projection.\n * @param {number[]} quartet - The indices of the quartet.\n * @param {Float64Array} D_hd - The high-dimensional distances of the quartet.\n * @returns {Float64Array[]} The gradients for the quartet.\n */\n _compute_quartet_grads(Y, quartet, [p_ab, p_ac, p_ad, p_bc, p_bd, p_cd]) {\n const [a, b, c, d] = quartet.map((index) => Y.row(index));\n // LD distances, add a small number just in case\n const d_ab = euclidean(a, b) + 1e-12;\n const d_ac = euclidean(a, c) + 1e-12;\n const d_ad = euclidean(a, d) + 1e-12;\n const d_bc = euclidean(b, c) + 1e-12;\n const d_bd = euclidean(b, d) + 1e-12;\n const d_cd = euclidean(c, d) + 1e-12;\n const sum_LD_dist = neumair_sum([d_ab, d_ac, d_ad, d_bc, d_bd, d_cd]);\n\n // for each element of the sum: use the same gradient function and just permute the points given in input.\n const [gA1, gB1, gC1, gD1] = this._ABCD_grads(\n a,\n b,\n c,\n d,\n d_ab,\n d_ac,\n d_ad,\n d_bc,\n d_bd,\n d_cd,\n p_ab,\n sum_LD_dist,\n );\n const [gA2, gC2, gB2, gD2] = this._ABCD_grads(\n a,\n c,\n b,\n d,\n d_ac,\n d_ab,\n d_ad,\n d_bc,\n d_cd,\n d_bd,\n p_ac,\n sum_LD_dist,\n );\n const [gA3, gD3, gC3, gB3] = this._ABCD_grads(\n a,\n d,\n c,\n b,\n d_ad,\n d_ac,\n d_ab,\n d_cd,\n d_bd,\n d_bc,\n p_ad,\n sum_LD_dist,\n );\n const [gB4, gC4, gA4, gD4] = this._ABCD_grads(\n b,\n c,\n a,\n d,\n d_bc,\n d_ab,\n d_bd,\n d_ac,\n d_cd,\n d_ad,\n p_bc,\n sum_LD_dist,\n );\n const [gB5, gD5, gA5, gC5] = this._ABCD_grads(\n b,\n d,\n a,\n c,\n d_bd,\n d_ab,\n d_bc,\n d_ad,\n d_cd,\n d_ac,\n p_bd,\n sum_LD_dist,\n );\n const [gC6, gD6, gA6, gB6] = this._ABCD_grads(\n c,\n d,\n a,\n b,\n d_cd,\n d_ac,\n d_bc,\n d_ad,\n d_bd,\n d_ab,\n p_cd,\n sum_LD_dist,\n );\n\n if (!this._add) throw new Error(\"Call init() first!\");\n const add = this._add;\n const gA = add(gA1, gA2, gA3, gA4, gA5, gA6);\n const gB = add(gB1, gB2, gB3, gB4, gB5, gB6);\n const gC = add(gC1, gC2, gC3, gC4, gC5, gC6);\n const gD = add(gD1, gD2, gD3, gD4, gD5, gD6);\n\n return [gA, gB, gC, gD];\n }\n\n /**\n * Gradients for one element of the loss function's sum.\n *\n * @private\n * @param {Float64Array} a\n * @param {Float64Array} b\n * @param {Float64Array} c\n * @param {Float64Array} d\n * @param {number} d_ab\n * @param {number} d_ac\n * @param {number} d_ad\n * @param {number} d_bc\n * @param {number} d_bd\n * @param {number} d_cd\n * @param {number} p_ab\n * @param {number} sum_LD_dist\n * @returns {Float64Array[]}\n */\n _ABCD_grads(a, b, c, d, d_ab, d_ac, d_ad, d_bc, d_bd, d_cd, p_ab, sum_LD_dist) {\n if (!this._minus || !this._add || !this._mult || !this._sub_div) throw new Error(\"Call init() first!\");\n const ratio = d_ab / sum_LD_dist;\n const twice_ratio = 2 * ((p_ab - ratio) / sum_LD_dist);\n const minus = this._minus;\n const add = this._add;\n const mult = this._mult;\n const sub_div = this._sub_div;\n // no side effects because sub_div creates new arrays, and the inline functions work on this new created arrays.\n const gA = mult(\n minus(mult(add(sub_div(a, b, d_ab), sub_div(a, c, d_ac), sub_div(a, d, d_ad)), ratio), sub_div(a, b, d_ab)),\n twice_ratio,\n );\n const gB = mult(\n minus(mult(add(sub_div(b, a, d_ab), sub_div(b, c, d_bc), sub_div(b, d, d_bd)), ratio), sub_div(b, a, d_ab)),\n twice_ratio,\n );\n const gC = mult(add(sub_div(c, a, d_ac), sub_div(c, b, d_bc), sub_div(c, d, d_cd)), ratio * twice_ratio);\n const gD = mult(add(sub_div(d, a, d_ad), sub_div(d, b, d_bd), sub_div(d, c, d_cd)), ratio * twice_ratio);\n return [gA, gB, gC, gD];\n }\n\n /**\n * Inline!\n *\n * @param {number} d\n */\n __minus(d) {\n return /** @type {(a: Float64Array, b: Float64Array) => Float64Array} */ (a, b) => {\n for (let i = 0; i < d; ++i) {\n a[i] -= b[i];\n }\n return a;\n };\n }\n\n /**\n * Inline!\n *\n * @param {number} d\n */\n __add(d) {\n return /** @type {(...summands: Float64Array[]) => Float64Array} */ (...summands) => {\n const n = summands.length;\n const s1 = summands[0];\n for (let j = 1; j < n; ++j) {\n const summand = summands[j];\n for (let i = 0; i < d; ++i) {\n s1[i] += summand[i];\n }\n }\n return s1;\n };\n }\n\n /**\n * Inline!\n *\n * @param {number} d\n */\n __mult(d) {\n return /** @type {(a: Float64Array, v: number) => Float64Array} */ (a, v) => {\n for (let i = 0; i < d; ++i) {\n a[i] *= v;\n }\n return a;\n };\n }\n\n /**\n * Creates a new array `(x - y) / div`.\n *\n * @param {number} d\n */\n __sub_div(d) {\n return /** @type {(x: Float64Array, y: Float64Array, div: number) => Float64Array} */ (x, y, div) => {\n return Float64Array.from({ length: d }, (_, i) => (x[i] - y[i]) / div);\n };\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new SQDMDS(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new SQDMDS(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new SQDMDS(X, parameters);\n return dr.transform_async();\n }\n}\n","import { DisjointSet } from \"../datastructure/index.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersTopoMap} from \"./index.js\" */\n\n/**\n * TopoMap\n *\n * A 0-dimensional Homology Preserving Projection of High-Dimensional Data.\n * It aims to preserve the topological structure of the data by maintaining\n * the connectivity of a minimum spanning tree.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class TopoMap extends DR {\n /**\n * TopoMap: A 0-dimensional Homology Preserving Projection of High-Dimensional Data.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://arxiv.org/pdf/2009.01512.pdf}\n */\n constructor(X, parameters) {\n super(X, { metric: euclidean, seed: 1212 }, parameters);\n [this._N, this._D] = this.X.shape;\n this._distance_matrix = new Matrix(this._N, this._N, -1);\n }\n\n /**\n * @private\n * @param {number} i\n * @param {number} j\n * @param {import(\"../metrics/index.js\").Metric} metric\n * @returns {number}\n */\n __lazy_distance_matrix(i, j, metric) {\n const D = this._distance_matrix;\n const X = this.X;\n const D_ij = D.entry(i, j);\n if (D_ij === -1 && i !== j) {\n const dist = metric(X.row(i), X.row(j));\n D.set_entry(i, j, dist);\n D.set_entry(j, i, dist);\n return dist;\n }\n return i === j ? 0 : D_ij;\n }\n\n /**\n * Computes the minimum spanning tree, using a given metric\n *\n * @private\n * @param {import(\"../metrics/index.js\").Metric} metric\n * @see {@link https://en.wikipedia.org/wiki/Kruskal%27s_algorithm}\n */\n _make_minimum_spanning_tree(metric = euclidean) {\n const N = this._N;\n const X = [...this.X];\n\n this._disjoint_set = new DisjointSet(X);\n const disjoint_set = this._disjoint_set;\n const F = [];\n let E = [];\n for (let i = 0; i < N; ++i) {\n for (let j = i + 1; j < N; ++j) {\n E.push([i, j, this.__lazy_distance_matrix(i, j, metric)]);\n }\n }\n E = E.sort((a, b) => a[2] - b[2]);\n\n for (const [u, v, w] of E) {\n const set_u = disjoint_set.find(X[u]);\n const set_v = disjoint_set.find(X[v]);\n if (!set_u || !set_v) throw new Error(\"Should not happen!\");\n if (set_u !== set_v) {\n F.push([u, v, w]);\n disjoint_set.union(set_u, set_v);\n }\n }\n\n return F.sort((a, b) => a[2] - b[2]);\n }\n\n /** Initializes TopoMap. Sets all projcted points to zero, and computes a minimum spanning tree. */\n init() {\n const { metric } = this._parameters;\n this.Y = new Matrix(this._N, 2, 0);\n this._Emst = this._make_minimum_spanning_tree(metric);\n this._is_initialized = true;\n return this;\n }\n\n /**\n * Returns true if Point C is left of line AB.\n *\n * @private\n * @param {Float64Array} PointA - Point A of line AB\n * @param {Float64Array} PointB - Point B of line AB\n * @param {Float64Array} PointC - Point C\n * @returns {boolean}\n */\n __hull_cross([ax, ay], [bx, by], [sx, sy]) {\n return (bx - ax) * (sy - ay) - (by - ay) * (sx - ax) <= 0;\n }\n\n /**\n * Computes the convex hull of the set of Points S\n *\n * @private\n * @param {Float64Array[]} S - Set of Points.\n * @returns {Float64Array[]} Convex hull of S. Starts at the bottom-most point and continues counter-clockwise.\n * @see {@link https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain#JavaScript}\n */\n __hull(S) {\n const points = S.sort(([x1, y1], [x2, y2]) => y1 - y2 || x1 - x2);\n const N = points.length;\n if (N <= 2) return points;\n\n const lower = [];\n for (let i = 0; i < N; ++i) {\n while (\n lower.length >= 2 &&\n this.__hull_cross(lower[lower.length - 2], lower[lower.length - 1], points[i])\n ) {\n lower.pop();\n }\n lower.push(points[i]);\n }\n const upper = [];\n for (let i = N - 1; i >= 0; --i) {\n while (\n upper.length >= 2 &&\n this.__hull_cross(upper[upper.length - 2], upper[upper.length - 1], points[i])\n ) {\n upper.pop();\n }\n upper.push(points[i]);\n }\n upper.pop();\n lower.pop();\n return lower.concat(upper);\n }\n\n /**\n * Finds the angle to rotate Point A and B to lie on a line parallel to the x-axis.\n *\n * @private\n * @param {Float64Array} PointA\n * @param {Float64Array} PointB\n * @returns {{ sin: number; cos: number }} Object containing the sinus- and cosinus-values for a rotation.\n */\n __findAngle([p1x, p1y], [p2x, p2y]) {\n const n = euclidean([p1x, p1y], [p2x, p2y]);\n if (n === 0)\n return {\n sin: 0,\n cos: 1,\n };\n const vec = [(p2x - p1x) / n, (p2y - p1y) / n];\n const cos = vec[0];\n let sin = Math.sqrt(1 - cos * cos);\n sin = vec[1] >= 0 ? -sin : sin;\n return {\n sin: sin,\n cos: cos,\n };\n }\n\n /**\n * @private\n * @param {Float64Array[]} hull\n * @param {Float64Array} p\n * @param {boolean} topEdge\n * @returns {{ sin: number; cos: number; tx: number; ty: number }}\n */\n __align_hull(hull, p, topEdge) {\n let v = -1;\n /** @type {number} */\n let d2 = -Infinity;\n for (let i = 0; i < hull.length; ++i) {\n const d = euclidean(hull[i], p);\n if (v === -1) {\n d2 = d;\n v = i;\n } else {\n if (d2 > d) {\n d2 = d;\n v = i;\n }\n }\n }\n\n const v1 = hull[v];\n let v2;\n if (topEdge) {\n v2 = hull[(v + 1) % hull.length];\n } else {\n v2 = hull[(v - 1 + hull.length) % hull.length];\n }\n\n /** @type {{ sin?: number; cos?: number; tx: number; ty: number }} */\n const transformation = {\n tx: -v1[0],\n ty: -v1[1],\n };\n\n if (hull.length >= 2) {\n const { sin, cos } = this.__findAngle(v1, v2);\n transformation.sin = sin;\n transformation.cos = cos;\n } else {\n transformation.sin = 0;\n transformation.cos = 1;\n }\n\n return /** @type {{ sin: number; cos: number; tx: number; ty: number }} */ (transformation);\n }\n\n /**\n * @private\n * @param {Float64Array} Point - The point which should get transformed.\n * @param {{ sin: number; cos: number; tx: number; ty: number }} Transformation - Contains the values for\n * translation and rotation.\n */\n __transform([px, py], { tx, ty, sin, cos }) {\n const x = px + tx;\n const y = py + ty;\n const xx = x * cos - y * sin;\n const yy = x * sin + y * cos;\n return [xx, yy];\n }\n\n /**\n * Calls `__transform` for each point in Set C\n *\n * @private\n * @param {Float64Array[]} C - Set of points.\n * @param {{ sin: number; cos: number; tx: number; ty: number }} t - Transform object.\n * @param {number} yOffset - Value to offset set C.\n */\n __transform_component(C, t, yOffset) {\n const N = C.length;\n for (let i = 0; i < N; ++i) {\n const c = C[i];\n const [cx, cy] = this.__transform(c, t);\n c[0] = cx;\n c[1] = cy + yOffset;\n }\n }\n\n /**\n * @private\n * @param {Float64Array} root_u - Root of component u\n * @param {Float64Array} root_v - Root of component v\n * @param {Float64Array} p_u - Point u\n * @param {Float64Array} p_v - Point v\n * @param {number} w - Edge weight w\n * @param {DisjointSet} components - The disjoint set containing the components\n */\n __align_components(root_u, root_v, p_u, p_v, w, components) {\n if (!components) throw new Error(\"components not provided!\");\n const u_children = components.get_children(root_u);\n const v_children = components.get_children(root_v);\n if (!u_children || !v_children) throw new Error(\"should not happen!\");\n\n const points_u = [...u_children];\n const points_v = [...v_children];\n\n const hull_u = this.__hull(points_u);\n const hull_v = this.__hull(points_v);\n\n const t_u = this.__align_hull(hull_u, p_u, false);\n const t_v = this.__align_hull(hull_v, p_v, true);\n\n this.__transform_component(points_u, t_u, 0);\n this.__transform_component(points_v, t_v, w);\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality 2.\n *\n * @returns {T}\n */\n transform() {\n if (!this._is_initialized) this.init();\n if (!this._Emst) throw new Error(\"Call init() first!\");\n const Emst = this._Emst;\n const Y = this.Y.to2dArray();\n /** @type {DisjointSet} */\n const components = new DisjointSet(\n Y,\n // Y.map((y, i) => {\n // y.i = i;\n // return y;\n // }),\n );\n\n for (const [u, v, w] of Emst) {\n const p_u = Y[u];\n const p_v = Y[v];\n const component_u = components.find(p_u);\n const component_v = components.find(p_v);\n if (!component_u || !component_v) throw new Error(\"Should not happen!\");\n if (component_u === component_v) continue;\n this.__align_components(component_u, component_v, p_u, p_v, w, components);\n components.union(component_u, component_v);\n }\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality 2.\n *\n * @returns {Generator}\n */\n *generator() {\n if (!this._is_initialized) this.init();\n if (!this._Emst) throw new Error(\"call init() first!\");\n const Emst = this._Emst;\n const Y = this.Y.to2dArray();\n const components = new DisjointSet(\n Y,\n // Y.map((y, i) => {\n // y.i = i;\n // return y;\n // }),\n );\n\n for (const [u, v, w] of Emst) {\n const p_u = Y[u];\n const p_v = Y[v];\n const component_u = components.find(p_u);\n const component_v = components.find(p_v);\n if (!component_u || !component_v) throw new Error(\"should not happen!\");\n if (component_u === component_v) continue;\n this.__align_components(component_u, component_v, p_u, p_v, w, components);\n components.union(component_u, component_v);\n yield this.projection;\n }\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new TopoMap(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new TopoMap(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new TopoMap(X, parameters);\n return dr.transform_async();\n }\n}\n","import { BallTree } from \"../knn/index.js\";\nimport { linspace, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\nimport { PCA } from \"./PCA.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersTriMap} from \"./index.js\" */\n/** @import {KNN} from \"../knn/KNN.js\" */\n\n/**\n * TriMap\n *\n * A dimensionality reduction technique that preserves both local and global\n * structure using triplets. It is designed to be a more robust alternative\n * to t-SNE and UMAP.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class TriMap extends DR {\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n * @see {@link https://arxiv.org/pdf/1910.00204v1.pdf}\n * @see {@link https://github.com/eamid/trimap}\n */\n constructor(X, parameters) {\n super(\n X,\n {\n weight_adj: 500,\n n_inliers: 10,\n n_outliers: 5,\n n_random: 5,\n d: 2,\n metric: euclidean,\n tol: 1e-8,\n seed: 1212,\n },\n parameters,\n );\n }\n\n /**\n * @param {Matrix | null} [pca=null] - Initial Embedding (if null then PCA gets used). Default is `null`\n * @param {import(\"../knn/KNN.js\").KNN | null} [knn=null] - KNN Object (if null then BallTree gets used). Default is `null`\n */\n init(pca = null, knn = null) {\n const X = this.X;\n const N = X.shape[0];\n //const c = /** @type {number} */ (this._parameters.c);\n const d = /** @type {number} */ (this._parameters.d);\n const metric = /** @type {Metric} */ (this._parameters.metric);\n const seed = /** @type {number} */ (this._parameters.seed);\n this.n_inliers = /** @type {number} */ (this._parameters.n_inliers);\n this.n_outliers = /** @type {number} */ (this._parameters.n_outliers);\n this.n_random = /** @type {number} */ (this._parameters.n_random);\n this.Y = pca ?? PCA.transform(X, { d, seed });\n this.knn = knn ?? new BallTree(X.to2dArray(), { metric, seed });\n const { triplets, weights } = this._generate_triplets(this.n_inliers, this.n_outliers, this.n_random);\n this.triplets = triplets;\n this.weights = weights;\n this.lr = (1000 * N) / triplets.shape[0];\n this.C = Infinity;\n this.vel = new Matrix(N, d, 0);\n this.gain = new Matrix(N, d, 1);\n return this;\n }\n\n /**\n * Generates {@link n_inliers} x {@link n_outliers} x {@link n_random} triplets.\n *\n * @param {number} n_inliers\n * @param {number} n_outliers\n * @param {number} n_random\n */\n _generate_triplets(n_inliers, n_outliers, n_random) {\n const metric = /** @type {Metric} */ (this._parameters.metric);\n const weight_adj = /** @type {number} */ (this._parameters.weight_adj);\n const X = this.X;\n const N = X.shape[0];\n const knn = this.knn;\n if (!knn) throw new Error(\"Call init() first!\");\n const n_extra = Math.min(n_inliers + 20, N);\n const nbrs = new Matrix(N, n_extra);\n const knn_distances = new Matrix(N, n_extra);\n for (let i = 0; i < N; ++i) {\n const results = knn\n .search(X.row(i), n_extra + 1)\n .filter((d) => d.distance !== 0)\n .sort((a, b) => a.distance - b.distance);\n\n results.forEach((d, j) => {\n if (j < n_extra) {\n nbrs.set_entry(i, j, d.index);\n knn_distances.set_entry(i, j, d.distance);\n }\n });\n }\n // scale parameter\n const sig = new Float64Array(N);\n for (let i = 0; i < N; ++i) {\n sig[i] = Math.max(\n (knn_distances.entry(i, 3) + knn_distances.entry(i, 4) + knn_distances.entry(i, 5)) / 3,\n 1e-10,\n );\n }\n\n const P = this._find_p(knn_distances, sig, nbrs);\n\n let triplets = this._sample_knn_triplets(P, nbrs, n_inliers, n_outliers);\n let n_triplets = triplets.shape[0];\n const outlier_distances = new Float64Array(n_triplets);\n for (let i = 0; i < n_triplets; ++i) {\n const j = triplets.entry(i, 0);\n const k = triplets.entry(i, 2);\n outlier_distances[i] = metric(X.row(j), X.row(k));\n }\n let weights = this._find_weights(triplets, P, nbrs, outlier_distances, sig);\n\n if (n_random > 0) {\n const { random_triplets, random_weights } = this._sample_random_triplets(X, n_random, sig);\n triplets = triplets.concat(random_triplets, \"vertical\");\n weights = Float64Array.from([...weights, ...random_weights]);\n }\n n_triplets = triplets.shape[0];\n let max_weight = -Infinity;\n for (let i = 0; i < n_triplets; ++i) {\n if (Number.isNaN(weights[i])) {\n weights[i] = 0;\n }\n if (max_weight < weights[i]) max_weight = weights[i];\n }\n let max_weight_2 = -Infinity;\n for (let i = 0; i < n_triplets; ++i) {\n weights[i] /= max_weight;\n weights[i] += 0.0001;\n weights[i] = Math.log(1 + weight_adj * weights[i]);\n if (max_weight_2 < weights[i]) max_weight_2 = weights[i];\n }\n for (let i = 0; i < n_triplets; ++i) {\n weights[i] /= max_weight_2;\n }\n return {\n triplets: triplets,\n weights: weights,\n };\n }\n\n /**\n * Calculates the similarity matrix P\n *\n * @private\n * @param {Matrix} knn_distances - Matrix of pairwise knn distances\n * @param {Float64Array} sig - Scaling factor for the distances\n * @param {Matrix} nbrs - Nearest neighbors\n * @returns {Matrix} Pairwise similarity matrix\n */\n _find_p(knn_distances, sig, nbrs) {\n const [N, n_neighbors] = knn_distances.shape;\n return new Matrix(N, n_neighbors, (i, j) => {\n return Math.exp(-(knn_distances.entry(i, j) ** 2 / sig[i] / sig[nbrs.entry(i, j)]));\n });\n }\n\n /**\n * Sample nearest neighbors triplets based on the similarity values given in P.\n *\n * @private\n * @param {Matrix} P - Matrix of pairwise similarities between each point and its neighbors given in matrix nbrs.\n * @param {Matrix} nbrs - Nearest neighbors indices for each point. The similarity values are given in matrix\n * {@link P}. Row i corresponds to the i-th point.\n * @param {number} n_inliers - Number of inlier points.\n * @param {number} n_outliers - Number of outlier points.\n */\n _sample_knn_triplets(P, nbrs, n_inliers, n_outliers) {\n const N = nbrs.shape[0];\n const triplets_list = [];\n for (let i = 0; i < N; ++i) {\n const sort_indices = this.__argsort(P.row(i));\n for (let j = 0; j < n_inliers; ++j) {\n const sim = nbrs.entry(i, sort_indices[sort_indices[j] === i ? j + 1 : j]);\n const rejects = [i, ...Array.from(sort_indices.slice(0, j + 2)).map((idx) => nbrs.entry(i, idx))];\n const samples = this._rejection_sample(n_outliers, N, rejects);\n for (let k = 0; k < samples.length; ++k) {\n const out = samples[k];\n triplets_list.push([i, sim, out]);\n }\n }\n }\n const triplets = new Matrix(triplets_list.length, 3);\n for (let t = 0; t < triplets_list.length; ++t) {\n triplets.set_entry(t, 0, triplets_list[t][0]);\n triplets.set_entry(t, 1, triplets_list[t][1]);\n triplets.set_entry(t, 2, triplets_list[t][2]);\n }\n return triplets;\n }\n\n /**\n * Should do the same as np.argsort()\n *\n * @private\n * @param {Float64Array | number[]} A\n */\n __argsort(A) {\n return linspace(0, A.length - 1).sort((i, j) => A[j] - A[i]);\n }\n\n /**\n * Samples {@link n_samples} integers from a given interval [0, {@link max_int}] while rejection the values that are\n * in the {@link rejects}.\n *\n * @private\n * @param {number} n_samples\n * @param {number} max_int\n * @param {number[]} rejects\n */\n _rejection_sample(n_samples, max_int, rejects) {\n const randomizer = this._randomizer;\n const interval = linspace(0, max_int - 1).filter((d) => rejects.indexOf(d) < 0);\n return randomizer.choice(interval, Math.min(n_samples, interval.length));\n }\n\n /**\n * Calculates the weights for the sampled nearest neighbors triplets\n *\n * @private\n * @param {Matrix} triplets - Sampled Triplets.\n * @param {Matrix} P - Pairwise similarity matrix.\n * @param {Matrix} nbrs - Nearest Neighbors\n * @param {Float64Array} outlier_distances - Matrix of pairwise outlier distances\n * @param {Float64Array} sig - Scaling factor for the distances.\n */\n _find_weights(triplets, P, nbrs, outlier_distances, sig) {\n const n_triplets = triplets.shape[0];\n const weights = new Float64Array(n_triplets);\n for (let t = 0; t < n_triplets; ++t) {\n const i = triplets.entry(t, 0);\n const sim = nbrs.row(i).indexOf(triplets.entry(t, 1));\n const p_sim = P.entry(i, sim);\n let p_out = Math.exp(-(outlier_distances[t] ** 2 / (sig[i] * sig[triplets.entry(t, 2)])));\n if (p_out < 1e-20) p_out = 1e-20;\n weights[t] = p_sim / p_out;\n }\n return weights;\n }\n\n /**\n * Sample uniformly ranom triplets\n *\n * @private\n * @param {Matrix} X - Data matrix.\n * @param {number} n_random - Number of random triplets per point\n * @param {Float64Array} sig - Scaling factor for the distances\n */\n _sample_random_triplets(X, n_random, sig) {\n const metric = /** @type {Metric} */ (this.parameter(\"metric\"));\n const randomizer = this._randomizer;\n const N = X.shape[0];\n const random_triplets = new Matrix(N * n_random, 3);\n const random_weights = new Float64Array(N * n_random);\n for (let i = 0; i < N; ++i) {\n const n_i = i * n_random;\n const indices = Array.from({ length: N }, (_, idx) => idx).filter((idx) => idx !== i);\n for (let j = 0; j < n_random; ++j) {\n let [sim, out] = randomizer.choice(indices, 2);\n let p_sim = Math.exp(-(metric(X.row(i), X.row(sim)) ** 2 / (sig[i] * sig[sim])));\n if (p_sim < 1e-20) p_sim = 1e-20;\n let p_out = Math.exp(-(metric(X.row(i), X.row(out)) ** 2 / (sig[i] * sig[out])));\n if (p_out < 1e-20) p_out = 1e-20;\n\n if (p_sim < p_out) {\n [sim, out] = [out, sim];\n [p_sim, p_out] = [p_out, p_sim];\n }\n const index = n_i + j;\n random_triplets.set_entry(index, 0, i);\n random_triplets.set_entry(index, 1, sim);\n random_triplets.set_entry(index, 2, out);\n random_weights[index] = 0.1 * (p_sim / p_out);\n }\n }\n return {\n random_triplets: random_triplets,\n random_weights: random_weights,\n };\n }\n\n /**\n * Computes the gradient for updating the embedding.\n *\n * @param {Matrix} Y - The embedding\n */\n _grad(Y) {\n const n_inliers = this.n_inliers;\n const n_outliers = this.n_outliers;\n const triplets = this.triplets;\n const weights = this.weights;\n if (!triplets || n_inliers === undefined || n_outliers === undefined || !weights)\n throw new Error(\"Call init() first!\");\n const [N, dim] = Y.shape;\n const n_triplets = triplets.shape[0];\n const grad = new Matrix(N, dim, 0);\n const y_ij = new Float64Array(dim);\n const y_ik = new Float64Array(dim);\n let d_ij = 1;\n let d_ik = 1;\n let n_viol = 0;\n let loss = 0;\n const n_knn_triplets = N * n_inliers * n_outliers;\n\n for (let t = 0; t < n_triplets; ++t) {\n const [i, j, k] = triplets.row(t);\n // update y_ij, y_ik, d_ij, d_ik\n if (t % n_outliers === 0 || t >= n_knn_triplets) {\n d_ij = 1;\n d_ik = 1;\n for (let d = 0; d < dim; ++d) {\n const Y_id = Y.entry(i, d);\n const Y_jd = Y.entry(j, d);\n const Y_kd = Y.entry(k, d);\n y_ij[d] = Y_id - Y_jd;\n y_ik[d] = Y_id - Y_kd;\n d_ij += y_ij[d] ** 2;\n d_ik += y_ik[d] ** 2;\n }\n // update y_ik and d_ik only\n } else {\n d_ik = 1;\n for (let d = 0; d < dim; ++d) {\n const Y_id = Y.entry(i, d);\n const Y_kd = Y.entry(k, d);\n y_ik[d] = Y_id - Y_kd;\n d_ik += y_ik[d] ** 2;\n }\n }\n\n if (d_ij > d_ik) ++n_viol;\n loss += weights[t] / (1 + d_ik / d_ij);\n const w = weights[t] / (d_ij + d_ik) ** 2;\n for (let d = 0; d < dim; ++d) {\n const gs = y_ij[d] * d_ik * w;\n const go = y_ik[d] * d_ij * w;\n grad.add_entry(i, d, gs - go);\n grad.sub_entry(j, d, gs);\n grad.add_entry(k, d, go);\n }\n }\n return { grad, loss, n_viol };\n }\n\n /**\n * @param {number} max_iteration\n * @returns {T}\n */\n transform(max_iteration = 800) {\n this.check_init();\n for (let iter = 0; iter < max_iteration; ++iter) {\n this._next(iter);\n }\n return this.projection;\n }\n\n /**\n * @param {number} max_iteration\n * @returns {Generator}\n */\n *generator(max_iteration = 800) {\n this.check_init();\n for (let iter = 0; iter < max_iteration; ++iter) {\n this._next(iter);\n yield this.projection;\n }\n return this.projection;\n }\n\n /**\n * Does the iteration step.\n *\n * @private\n * @param {number} iter\n */\n _next(iter) {\n const gamma = iter > 250 ? 0.5 : 0.3;\n const old_C = this.C;\n const vel = this.vel;\n if (!vel || old_C === undefined || this.lr === undefined) throw new Error(\"Call init() first!\");\n const Y = this.Y.add(vel.mult(gamma));\n const { grad, loss } = this._grad(Y);\n this.C = loss;\n this.Y = this._update_embedding(Y, iter, grad);\n const tol = /** @type {number} */ (this.parameter(\"tol\"));\n this.lr *= old_C > loss + tol ? 1.01 : 0.9;\n return this.Y;\n }\n\n /**\n * Updates the embedding.\n *\n * @private\n * @param {Matrix} Y\n * @param {number} iter\n * @param {Matrix} grad\n */\n _update_embedding(Y, iter, grad) {\n const [N, dim] = Y.shape;\n const gamma = iter > 250 ? 0.8 : 0.5; // moment parameter\n const min_gain = 0.01;\n const gain = this.gain;\n const vel = this.vel;\n const lr = this.lr;\n if (!vel || !gain || lr === undefined) throw new Error(\"Call init() first!\");\n for (let i = 0; i < N; ++i) {\n for (let d = 0; d < dim; ++d) {\n const new_gain =\n Math.sign(vel.entry(i, d)) !== Math.sign(grad.entry(i, d))\n ? gain.entry(i, d) + 0.2\n : Math.max(gain.entry(i, d) * 0.8, min_gain);\n gain.set_entry(i, d, new_gain);\n vel.set_entry(i, d, gamma * vel.entry(i, d) - lr * gain.entry(i, d) * grad.entry(i, d));\n Y.set_entry(i, d, Y.entry(i, d) + vel.entry(i, d));\n }\n }\n return Y;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new TriMap(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new TriMap(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new TriMap(X, parameters);\n return dr.transform_async();\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { euclidean_squared } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersTSNE} from \"./index.js\" */\n/**\n * t-SNE (t-Distributed Stochastic Neighbor Embedding)\n *\n * A nonlinear dimensionality reduction technique particularly well-suited\n * for visualizing high-dimensional data in 2D or 3D. Preserves local\n * structure while revealing global patterns.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link https://lvdmaaten.github.io/tsne/|t-SNE Paper}\n * @see {@link UMAP} for faster alternative with similar results\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];\n * const tsne = new druid.TSNE(X, {\n * perplexity: 30,\n * epsilon: 10,\n * d: 2,\n * seed: 42\n * });\n *\n * const Y = tsne.transform(500); // 500 iterations\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class TSNE extends DR {\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X, parameters) {\n super(\n X,\n {\n perplexity: 50,\n epsilon: 10,\n d: 2,\n metric: euclidean_squared,\n seed: 1212,\n },\n parameters,\n );\n [this._N, this._D] = this.X.shape;\n this._iter = 0;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n this.Y = new Matrix(this._N, d, () => this._randomizer.gauss_random() * 1e-4);\n }\n\n init() {\n // init\n const perplexity = /** @type {number} */ (this.parameter(\"perplexity\"));\n const Htarget = Math.log(perplexity);\n const N = this._N;\n const D = this._D;\n const metric = /** @type {Metric | \"precomputed\"} */ (this._parameters.metric);\n const X = this.X;\n let Delta;\n if (metric === \"precomputed\") {\n Delta = Matrix.from(X);\n } else {\n Delta = new Matrix(N, N);\n for (let i = 0; i < N; ++i) {\n const X_i = X.row(i);\n for (let j = i + 1; j < N; ++j) {\n const distance = metric(X_i, X.row(j));\n Delta.set_entry(i, j, distance);\n Delta.set_entry(j, i, distance);\n }\n }\n }\n\n const P = new Matrix(N, N, 0);\n\n this._ystep = new Matrix(N, D, 0);\n this._gains = new Matrix(N, D, 1);\n\n // search for fitting sigma\n const tol = 1e-4;\n const maxtries = 50;\n for (let i = 0; i < N; ++i) {\n const dist_i = Delta.row(i);\n const prow = P.row(i);\n let betamin = -Infinity;\n let betamax = Infinity;\n let beta = 1;\n let cnt = maxtries;\n let done = false;\n let psum = 0;\n\n while (!done && cnt--) {\n // compute entropy and kernel row with beta precision\n psum = 0;\n let dp_sum = 0;\n for (let j = 0; j < N; ++j) {\n const dist = dist_i[j];\n const pj = i !== j ? Math.exp(-dist * beta) : 0;\n dp_sum += dist * pj;\n prow[j] = pj;\n psum += pj;\n }\n // compute entropy\n const H = psum > 0 ? Math.log(psum) + (beta * dp_sum) / psum : 0;\n if (H > Htarget) {\n betamin = beta;\n beta = betamax === Infinity ? beta * 2 : (beta + betamax) / 2;\n } else {\n betamax = beta;\n beta = betamin === -Infinity ? beta / 2 : (beta + betamin) / 2;\n }\n done = Math.abs(H - Htarget) < tol;\n }\n // normalize p\n for (let j = 0; j < N; ++j) {\n prow[j] /= psum;\n }\n }\n\n // compute probabilities\n const N2 = N * 2;\n for (let i = 0; i < N; ++i) {\n for (let j = i; j < N; ++j) {\n const p = Math.max((P.entry(i, j) + P.entry(j, i)) / N2, 1e-100);\n P.set_entry(i, j, p);\n P.set_entry(j, i, p);\n }\n }\n this._P = P;\n return this;\n }\n\n /**\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {T} The projection.\n */\n transform(iterations = 500) {\n this.check_init();\n for (let i = 0; i < iterations; ++i) {\n this.next();\n }\n return this.projection;\n }\n\n /**\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {Generator} - The projection.\n */\n *generator(iterations = 500) {\n this.check_init();\n for (let i = 0; i < iterations; ++i) {\n this.next();\n yield this.projection;\n }\n return this.projection;\n }\n\n /**\n * Performs a optimization step\n *\n * @private\n * @returns {Matrix}\n */\n next() {\n const iter = ++this._iter;\n if (!this._P || !this._ystep || !this._gains) throw new Error(\"Call init() first!\");\n const P = this._P;\n const ystep = this._ystep;\n const gains = this._gains;\n const N = this._N;\n const dim = /** @type {number} */ (this._parameters.d);\n const epsilon = /** @type {number} */ (this._parameters.epsilon);\n const Y = this.Y;\n\n //calc cost gradient;\n const pmul = iter < 100 ? 4 : 1;\n\n // compute Q dist (unnormalized)\n const Qu = new Matrix(N, N, \"zeros\");\n let qsum = 0;\n for (let i = 0; i < N; ++i) {\n for (let j = i + 1; j < N; ++j) {\n let dsum = 0;\n for (let d = 0; d < dim; ++d) {\n const dhere = Y.entry(i, d) - Y.entry(j, d);\n dsum += dhere * dhere;\n }\n const qu = 1 / (1 + dsum);\n Qu.set_entry(i, j, qu);\n Qu.set_entry(j, i, qu);\n qsum += 2 * qu;\n }\n }\n\n // normalize Q dist\n const Q = new Matrix(N, N, 0);\n for (let i = 0; i < N; ++i) {\n for (let j = i + 1; j < N; ++j) {\n const val = Math.max(Qu.entry(i, j) / qsum, 1e-100);\n Q.set_entry(i, j, val);\n Q.set_entry(j, i, val);\n }\n }\n\n const grad = new Matrix(N, dim, \"zeros\");\n for (let i = 0; i < N; ++i) {\n for (let j = 0; j < N; ++j) {\n const premult = 4 * (pmul * P.entry(i, j) - Q.entry(i, j)) * Qu.entry(i, j);\n for (let d = 0; d < dim; ++d) {\n grad.add_entry(i, d, premult * (Y.entry(i, d) - Y.entry(j, d)));\n }\n }\n }\n\n // perform gradient step\n const ymean = new Float64Array(dim);\n for (let i = 0; i < N; ++i) {\n for (let d = 0; d < dim; ++d) {\n const gid = grad.entry(i, d);\n const sid = ystep.entry(i, d);\n const gainid = gains.entry(i, d);\n\n let newgain = Math.sign(gid) === Math.sign(sid) ? gainid * 0.8 : gainid + 0.2;\n if (newgain < 0.01) newgain = 0.01;\n gains.set_entry(i, d, newgain);\n\n const momval = iter < 250 ? 0.5 : 0.8;\n const newsid = momval * sid - epsilon * newgain * gid;\n ystep.set_entry(i, d, newsid);\n\n Y.add_entry(i, d, newsid);\n ymean[d] += Y.entry(i, d);\n }\n }\n\n for (let i = 0; i < N; ++i) {\n for (let d = 0; d < dim; ++d) {\n Y.sub_entry(i, d, ymean[d] / N);\n }\n }\n\n return this.Y;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new TSNE(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new TSNE(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new TSNE(X, parameters);\n return dr.transform_async();\n }\n}\n","/**\n * @template {Float64Array | number[]} T\n * @category Optimization\n * @param {(d: T) => number} f\n * @param {T} x0\n * @param {number} [max_iter=300] Default is `300`\n * @returns {T}\n * @see http://optimization-js.github.io/optimization-js/optimization.js.html#line438\n */\nexport function powell(f, x0, max_iter = 300) {\n const epsilon = 1e-2;\n const n = x0.length;\n let alpha = 1e-3;\n let pfx = 10000;\n const x = /** @type {T} */ (x0.slice());\n let fx = f(x);\n let convergence = false;\n\n while (max_iter-- >= 0 && !convergence) {\n convergence = true;\n for (let i = 0; i < n; ++i) {\n x[i] += 1e-6;\n const fxi = f(x);\n x[i] -= 1e-6;\n const dx = (fxi - fx) / 1e-6;\n if (Math.abs(dx) > epsilon) {\n convergence = false;\n }\n x[i] -= alpha * dx;\n fx = f(x);\n }\n alpha *= pfx >= fx ? 1.05 : 0.4;\n pfx = fx;\n }\n return x;\n}\n","import { BallTree, NaiveKNN } from \"../knn/index.js\";\nimport { linspace, Matrix } from \"../matrix/index.js\";\nimport { euclidean, euclidean_squared } from \"../metrics/index.js\";\nimport { neumair_sum } from \"../numerical/index.js\";\nimport { powell } from \"../optimization/index.js\";\nimport { max } from \"../util/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersUMAP} from \"./index.js\" */\n\n/**\n * Uniform Manifold Approximation and Projection (UMAP)\n *\n * A novel manifold learning technique for dimensionality reduction. UMAP is constructed\n * from a theoretical framework based on Riemannian geometry and algebraic topology.\n * It is often faster than t-SNE while preserving more of the global structure.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link https://arxiv.org/abs/1802.03426|UMAP Paper}\n * @see {@link TSNE} for a similar visualization technique\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];\n * const umap = new druid.UMAP(X, {\n * n_neighbors: 15,\n * min_dist: 0.1,\n * d: 2,\n * seed: 42\n * });\n *\n * const Y = umap.transform(500); // 500 iterations\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class UMAP extends DR {\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X, parameters) {\n super(\n X,\n {\n n_neighbors: 15,\n local_connectivity: 1,\n min_dist: 1,\n d: 2,\n metric: euclidean,\n seed: 1212,\n _spread: 1,\n _set_op_mix_ratio: 1,\n _repulsion_strength: 1,\n _negative_sample_rate: 5,\n _n_epochs: 350,\n _initial_alpha: 1,\n },\n parameters,\n );\n [this._N, this._D] = this.X.shape;\n const n_neighbors = /** @type {number} */ (this.parameter(\"n_neighbors\"));\n const local_connectivity = /** @type {number} */ (this.parameter(\"local_connectivity\"));\n const d = /** @type {number} */ (this.parameter(\"d\"));\n /* let n_neighbors = Math.min(this._N - 1, parameters.n_neighbors);\n this.parameter(\"n_neighbors\", n_neighbors);\n this.parameter(\"local_connectivity\", Math.min(this.parameter(\"local_connectivity\"), n_neighbors - 1)); */\n if (n_neighbors > this._N) {\n throw new Error(\n `Parameter n_neighbors (=${n_neighbors}) needs to be smaller than dataset size (N=${this._N})!`,\n );\n }\n if (local_connectivity > n_neighbors) {\n throw new Error(\n `Parameter local_connectivity (=${local_connectivity}) needs to be smaller than parameter n_neighbors (=${n_neighbors})`,\n );\n }\n this._iter = 0;\n const randomizer = this._randomizer;\n this.Y = new Matrix(this._N, d, () => randomizer.random);\n }\n\n /**\n * @private\n * @param {number} spread\n * @param {number} min_dist\n * @returns {number[]}\n */\n _find_ab_params(spread, min_dist) {\n /** @type {(x: number, a: number, b: number) => number} */\n const curve = (x, a, b) => 1 / (1 + a * x ** (2 * b));\n const xv = linspace(0, spread * 3, 300);\n const yv = linspace(0, spread * 3, 300);\n\n for (let i = 0, n = xv.length; i < n; ++i) {\n const xv_i = xv[i];\n yv[i] = xv_i < min_dist ? 1 : Math.exp(-(xv_i - min_dist) / spread);\n }\n\n /** @type {(p: [number, number]) => number} */\n const err = (p) => {\n const error = linspace(1, 300).map((_, i) => yv[i] - curve(xv[i], p[0], p[1]));\n return Math.sqrt(neumair_sum(error.map((e) => e * e)));\n };\n\n return powell(err, [1, 1]);\n }\n\n /**\n * @private\n * @param {{ element: Float64Array; index: number; distance: number }[][]} distances\n * @param {number[]} sigmas\n * @param {number[]} rhos\n * @returns {{ element: Float64Array; index: number; distance: number }[][]}\n */\n _compute_membership_strengths(distances, sigmas, rhos) {\n for (let i = 0, n = distances.length; i < n; ++i) {\n const rho = rhos[i];\n const curr_dist = distances[i];\n for (let j = 0, m = curr_dist.length; j < m; ++j) {\n const v = curr_dist[j].distance - rho;\n curr_dist[j].distance = v > 0 ? Math.exp(-v / sigmas[i]) : 1.0;\n }\n }\n return distances;\n }\n\n /**\n * @private\n * @param {NaiveKNN | BallTree} knn\n * @param {number} k\n * @returns {{\n * distances: { element: Float64Array; index: number; distance: number }[][];\n * sigmas: number[];\n * rhos: number[];\n * }}\n */\n _smooth_knn_dist(knn, k) {\n const SMOOTH_K_TOLERANCE = 1e-5;\n const MIN_K_DIST_SCALE = 1e-3;\n const n_iter = 64;\n const local_connectivity = /** @type {number} */ (this._parameters.local_connectivity);\n const metric = /** @type {Metric | \"precomputed\"} */ (this._parameters.metric);\n const target = Math.log2(k);\n const rhos = [];\n const sigmas = [];\n const X = this.X;\n const N = X.shape[0];\n //const distances = [...X].map(x_i => knn.search(x_i, k).raw_data().reverse());\n\n /** @type {{ element: Float64Array; index: number; distance: number }[][]} */\n const distances = [];\n if (metric === \"precomputed\" || knn instanceof NaiveKNN) {\n for (let i = 0; i < N; ++i) {\n distances.push(knn.search_by_index(i, k).reverse());\n }\n } else {\n for (const x_i of X) {\n distances.push(knn.search(x_i, k).reverse());\n }\n }\n\n const index = Math.floor(local_connectivity);\n const interpolation = local_connectivity - index;\n for (let i = 0; i < N; ++i) {\n let lo = 0;\n let hi = Infinity;\n let mid = 1;\n let rho = 0;\n\n const search_result = distances[i];\n const non_zero_dist = search_result.filter((d) => d.distance > 0);\n const non_zero_dist_length = non_zero_dist.length;\n if (non_zero_dist_length >= local_connectivity) {\n if (index > 0) {\n rho = non_zero_dist[index - 1].distance;\n if (interpolation > SMOOTH_K_TOLERANCE) {\n rho += interpolation * (non_zero_dist[index].distance - non_zero_dist[index - 1].distance);\n }\n } else {\n rho = interpolation * non_zero_dist[0].distance;\n }\n } else if (non_zero_dist_length > 0) {\n rho = non_zero_dist[non_zero_dist_length - 1].distance;\n }\n for (let x = 0; x < n_iter; ++x) {\n let psum = 0;\n for (let j = 0; j < k; ++j) {\n const d = search_result[j].distance - rho;\n psum += d > 0 ? Math.exp(-(d / mid)) : 1;\n }\n if (Math.abs(psum - target) < SMOOTH_K_TOLERANCE) {\n break;\n }\n if (psum > target) {\n [hi, mid] = [mid, (lo + hi) / 2];\n } else {\n if (hi === Infinity) {\n [lo, mid] = [mid, mid * 2];\n } else {\n [lo, mid] = [mid, (lo + hi) / 2];\n }\n }\n }\n\n //let mean_d = null;\n if (rho > 0) {\n const mean_ithd = search_result.reduce((a, b) => a + b.distance, 0) / search_result.length;\n if (mid < MIN_K_DIST_SCALE * mean_ithd) {\n mid = MIN_K_DIST_SCALE * mean_ithd;\n }\n } else {\n const mean_d = distances.reduce(\n (acc, res) => acc + res.reduce((a, b) => a + b.distance, 0) / res.length,\n 0,\n );\n if (mid < MIN_K_DIST_SCALE * mean_d) {\n mid = MIN_K_DIST_SCALE * mean_d;\n }\n }\n rhos[i] = rho;\n sigmas[i] = mid;\n }\n return {\n distances: distances,\n sigmas: sigmas,\n rhos: rhos,\n };\n }\n\n /**\n * @private\n * @param {Matrix} X\n * @param {number} n_neighbors\n * @returns {Matrix}\n */\n _fuzzy_simplicial_set(X, n_neighbors) {\n const N = X.shape[0];\n const metric = /** @type {Metric | \"precomputed\"} */ (this._parameters.metric);\n const _set_op_mix_ratio = /** @type {number} */ (this._parameters._set_op_mix_ratio);\n\n const knn =\n metric === \"precomputed\"\n ? new NaiveKNN(X.to2dArray(), {\n metric: \"precomputed\",\n seed: /** @type {number} */ (this._parameters.seed),\n })\n : new BallTree(X.to2dArray(), { metric, seed: /** @type {number} */ (this._parameters.seed) });\n let { distances, sigmas, rhos } = this._smooth_knn_dist(knn, n_neighbors);\n distances = this._compute_membership_strengths(distances, sigmas, rhos);\n const result = new Matrix(N, N, \"zeros\");\n for (let i = 0; i < N; ++i) {\n const distances_i = distances[i];\n for (let j = 0; j < distances_i.length; ++j) {\n result.set_entry(i, distances_i[j].index, distances_i[j].distance);\n }\n }\n\n const transposed_result = result.T;\n const prod_matrix = result.mult(transposed_result);\n return result\n .add(transposed_result)\n .sub(prod_matrix)\n .mult(_set_op_mix_ratio)\n .add(prod_matrix.mult(1 - _set_op_mix_ratio));\n }\n\n /**\n * @private\n * @param {number} n_epochs\n * @returns {Float32Array}\n */\n _make_epochs_per_sample(n_epochs) {\n if (!this._weights) throw new Error(\"Call init() first!\");\n const weights = this._weights;\n const result = new Float32Array(weights.length).fill(-1);\n const weight_scl = n_epochs / max(weights);\n weights.forEach((w, i) => {\n const sample = w * weight_scl;\n if (sample > 0) result[i] = Math.round(n_epochs / sample);\n });\n return result;\n }\n\n /**\n * @private\n * @param {Matrix} graph\n * @returns {{ rows: number[]; cols: number[]; data: number[] }}\n */\n _tocoo(graph) {\n const rows = [];\n const cols = [];\n const data = [];\n const [rows_n, cols_n] = graph.shape;\n for (let row = 0; row < rows_n; ++row) {\n for (let col = 0; col < cols_n; ++col) {\n const entry = graph.entry(row, col);\n if (entry !== 0) {\n rows.push(row);\n cols.push(col);\n data.push(entry);\n }\n }\n }\n return {\n rows: rows,\n cols: cols,\n data: data,\n };\n }\n\n /**\n * Computes all necessary\n *\n * @returns {UMAP}\n */\n init() {\n const _spread = /** @type {number} */ (this._parameters._spread);\n const min_dist = /** @type {number} */ (this._parameters.min_dist);\n const n_neighbors = /** @type {number} */ (this._parameters.n_neighbors);\n const _n_epochs = /** @type {number} */ (this._parameters._n_epochs);\n const _negative_sample_rate = /** @type {number} */ (this._parameters._negative_sample_rate);\n const [a, b] = this._find_ab_params(_spread, min_dist);\n this._a = a;\n this._b = b;\n this._graph = this._fuzzy_simplicial_set(this.X, n_neighbors);\n const { rows, cols, data: weights } = this._tocoo(this._graph);\n this._head = rows;\n this._tail = cols;\n this._weights = weights;\n this._epochs_per_sample = this._make_epochs_per_sample(_n_epochs);\n this._epochs_per_negative_sample = this._epochs_per_sample.map((d) => d * _negative_sample_rate);\n this._epoch_of_next_sample = this._epochs_per_sample.slice();\n this._epoch_of_next_negative_sample = this._epochs_per_negative_sample.slice();\n return this;\n }\n\n graph() {\n this.check_init();\n return { cols: this._head, rows: this._tail, weights: this._weights };\n }\n\n /**\n * @param {number} [iterations=350] - Number of iterations. Default is `350`\n * @returns {T}\n */\n transform(iterations = 350) {\n if (this.parameter(\"_n_epochs\") !== iterations) {\n this.parameter(\"_n_epochs\", iterations);\n this.init();\n }\n this.check_init();\n for (let i = 0; i < iterations; ++i) {\n this.next();\n }\n return this.projection;\n }\n\n /**\n * @param {number} [iterations=350] - Number of iterations. Default is `350`\n * @returns {Generator}\n */\n *generator(iterations = 350) {\n if (this.parameter(\"_n_epochs\") !== iterations) {\n this.parameter(\"_n_epochs\", iterations);\n this.init();\n }\n this.check_init();\n for (let i = 0; i < iterations; ++i) {\n this.next();\n yield this.projection;\n }\n return this.projection;\n }\n\n /**\n * @private\n * @param {number} x\n * @returns {number}\n */\n _clip(x) {\n if (x > 4) return 4;\n if (x < -4) return -4;\n return x;\n }\n\n /**\n * Performs the optimization step.\n *\n * @private\n * @param {Matrix} head_embedding\n * @param {Matrix} tail_embedding\n * @param {number[]} head\n * @param {number[]} tail\n * @returns {Matrix}\n */\n _optimize_layout(head_embedding, tail_embedding, head, tail) {\n const randomizer = this._randomizer;\n const _repulsion_strength = /** @type {number} */ (this.parameter(\"_repulsion_strength\"));\n const dim = /** @type {number} */ (this.parameter(\"d\"));\n const {\n _alpha: alpha,\n _a: a,\n _b: b,\n _epochs_per_sample: epochs_per_sample,\n _epochs_per_negative_sample: epochs_per_negative_sample,\n _epoch_of_next_negative_sample: epoch_of_next_negative_sample,\n _epoch_of_next_sample: epoch_of_next_sample,\n _clip: clip,\n } = this;\n if (\n alpha === undefined ||\n a === undefined ||\n b === undefined ||\n epochs_per_sample === undefined ||\n epochs_per_negative_sample === undefined ||\n epoch_of_next_negative_sample === undefined ||\n epoch_of_next_sample === undefined ||\n clip === undefined\n ) {\n throw new Error(\"call init() first!\");\n }\n const tail_length = tail.length;\n\n for (let i = 0, n = epochs_per_sample.length; i < n; ++i) {\n if (epoch_of_next_sample[i] <= this._iter) {\n const j = head[i];\n const k = tail[i];\n const current = head_embedding.row(j);\n const other = tail_embedding.row(k);\n const dist = euclidean_squared(current, other);\n if (dist > 0) {\n const grad_coeff = (-2 * a * b * dist ** (b - 1)) / (a * dist ** b + 1);\n for (let d = 0; d < dim; ++d) {\n const grad_d = clip(grad_coeff * (current[d] - other[d])) * alpha;\n current[d] += grad_d;\n other[d] -= grad_d;\n }\n }\n epoch_of_next_sample[i] += epochs_per_sample[i];\n const n_neg_samples = (this._iter - epoch_of_next_negative_sample[i]) / epochs_per_negative_sample[i];\n for (let p = 0; p < n_neg_samples; ++p) {\n const k = randomizer.random_int % tail_length;\n const other = tail_embedding.row(tail[k]);\n const dist = euclidean_squared(current, other);\n if (dist > 0) {\n const grad_coeff = (2 * _repulsion_strength * b) / ((0.01 + dist) * (a * dist ** b + 1));\n for (let d = 0; d < dim; ++d) {\n const grad_d = clip(grad_coeff * (current[d] - other[d])) * alpha;\n current[d] += grad_d;\n other[d] -= grad_d;\n }\n } else if (j === k) {\n }\n }\n epoch_of_next_negative_sample[i] += n_neg_samples * epochs_per_negative_sample[i];\n }\n }\n return head_embedding;\n }\n\n /**\n * @private\n * @returns {Matrix}\n */\n next() {\n if (!this._head || !this._tail) throw new Error(\"Call init() first!\");\n const iter = ++this._iter;\n const Y = this.Y;\n const _initial_alpha = /** @type {number} */ (this._parameters._initial_alpha);\n const _n_epochs = /** @type {number} */ (this._parameters._n_epochs);\n this._alpha = _initial_alpha * (1 - iter / _n_epochs);\n this.Y = this._optimize_layout(Y, Y, this._head, this._tail);\n\n return this.Y;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new UMAP(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new UMAP(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new UMAP(X, parameters);\n return dr.transform_async();\n }\n}\n","import pkg from \"../package.json\" with { type: \"json\" };\n\nconst version = pkg.version;\nexport { version };\n\n/** @import {Matrix} from \"./matrix/index.js\" */\n/** @typedef {Matrix | Float64Array[] | number[][]} InputType*/\n\n//export { version } from \"../package.json\" with { type: \"json\" };\nexport * from \"./clustering/index.js\";\nexport * from \"./datastructure/index.js\";\nexport * from \"./dimred/index.js\";\nexport * from \"./knn/index.js\";\nexport * from \"./linear_algebra/index.js\";\nexport * from \"./matrix/index.js\";\nexport * from \"./metrics/index.js\";\nexport * from \"./numerical/index.js\";\nexport * from \"./optimization/index.js\";\nexport * from \"./util/index.js\";\n"],"names":["qr","qr_gramschmidt"],"mappings":";;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE;AAClC,IAAI,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC;AAChG,IAAI,IAAI,YAAY,GAAG,CAAC;AACxB,IAAI,IAAI,MAAM,GAAG,CAAC;AAClB,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE;AACvC,QAAQ,YAAY,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7C,QAAQ,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC7B,IAAI;AACJ,IAAI,OAAO,YAAY,GAAG,MAAM;AAChC;;AClBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE;AAC/B,IAAI,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC;AAChG,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM;AACtB,IAAI,IAAI,GAAG,GAAG,CAAC;AACf,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAChC,QAAQ,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxE,IAAI;AACJ,IAAI,OAAO,GAAG;AACd;;ACjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE;AAChC,IAAI,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC;AAChG,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM;AACtB,IAAI,MAAM,GAAG,GAAG,EAAE;AAClB,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAChC,QAAQ,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvC,IAAI;AACJ,IAAI,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;AAC3B;;AChBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE;AAC7B,IAAI,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC;AAChG,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM;AACtB,IAAI,IAAI,GAAG,GAAG,CAAC;AACf,IAAI,IAAI,KAAK,GAAG,CAAC;AACjB,IAAI,IAAI,KAAK,GAAG,CAAC;AACjB,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAChC,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC1B,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC5B,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC5B,IAAI;AACJ,IAAI,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AACjE;;ACzBA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACO,SAAS,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE;AACxC,IAAI,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC;AAChG,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM;AACtB,IAAI,IAAI,GAAG,GAAG,CAAC;AACf,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAChC,QAAQ,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC/B,QAAQ,GAAG,IAAI,GAAG,GAAG,GAAG;AACxB,IAAI;AACJ,IAAI,OAAO,GAAG;AACd;;AChBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE;AAChC,IAAI,OAAO,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC7C;;ACZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE;AACtC,IAAI,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC;AAChG,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM;AACtB,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;;AAEvB,IAAI,IAAI,UAAU,GAAG,CAAC;AACtB,IAAI,IAAI,UAAU,GAAG,CAAC;AACtB,IAAI,IAAI,KAAK,GAAG,CAAC;AACjB,IAAI,IAAI,KAAK,GAAG,CAAC;;AAEjB,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAChC,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxC,YAAY,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACtC,YAAY,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACtC,YAAY,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC;AACvC,YAAY,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC;;AAEvC,YAAY,IAAI,MAAM,IAAI,MAAM,EAAE,CACrB,MAAM,IAAI,MAAM,EAAE;AAC/B,gBAAgB,KAAK,EAAE;AACvB,YAAY,CAAC,MAAM,IAAI,MAAM,EAAE;AAC/B,gBAAgB,KAAK,EAAE;AACvB,YAAY,CAAC,MAAM,IAAI,MAAM,GAAG,MAAM,GAAG,CAAC,EAAE;AAC5C,gBAAgB,UAAU,EAAE;AAC5B,YAAY,CAAC,MAAM;AACnB,gBAAgB,UAAU,EAAE;AAC5B,YAAY;AACZ,QAAQ;AACR,IAAI;;AAEJ,IAAI,MAAM,WAAW,GAAG,UAAU,GAAG,UAAU,GAAG,KAAK,GAAG,KAAK;AAC/D,IAAI,IAAI,WAAW,KAAK,CAAC,EAAE,OAAO,CAAC;;AAEnC,IAAI,MAAM,SAAS,GAAG,UAAU,GAAG,UAAU;AAC7C,IAAI,IAAI,SAAS,KAAK,CAAC,EAAE,OAAO,CAAC;;AAEjC,IAAI,OAAO,CAAC,UAAU,GAAG,UAAU,IAAI,SAAS;AAChD;;AC9CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE;AAC9B,IAAI,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC;AAChG,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM;AACtB,IAAI,IAAI,QAAQ,GAAG,CAAC;AACpB,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAChC,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACtB,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACtB,QAAQ,QAAQ,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;AACnC,IAAI;AACJ,IAAI,OAAO,QAAQ,GAAG,CAAC;AACvB;;AClBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE;AAChC,IAAI,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;AACxC,QAAQ,MAAM,IAAI,KAAK,CAAC,8EAA8E,CAAC;AACvG,IAAI,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;AACrB,IAAI,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;AACrB,IAAI,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;AACrB,IAAI,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;;AAErB,IAAI,MAAM,IAAI,GAAG,IAAI,GAAG,IAAI;AAC5B,IAAI,MAAM,IAAI,GAAG,IAAI,GAAG,IAAI;;AAE5B,IAAI,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC;AACxC,IAAI,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC;;AAExC,IAAI,MAAM,CAAC,GAAG,SAAS,GAAG,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,SAAS,GAAG,SAAS;AAC7F,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;;AAE5D,IAAI,OAAO,CAAC;AACZ;;AC3BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE;AAC9B,IAAI,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC;AAChG,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM;AACtB,IAAI,IAAI,YAAY,GAAG,CAAC;AACxB,IAAI,IAAI,SAAS,GAAG,CAAC;AACrB,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAChC,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC5B,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC5B,QAAQ,YAAY,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;AACtC,QAAQ,SAAS,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;AACnC,IAAI;AACJ,IAAI,OAAO,CAAC,YAAY,GAAG,SAAS,IAAI,YAAY;AACpD;;ACpBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE;AAChC,IAAI,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC;AAChG,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM;AACtB,IAAI,IAAI,GAAG,GAAG,CAAC;AACf,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAChC,QAAQ,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACpC,IAAI;AACJ,IAAI,OAAO,GAAG;AACd;;AChBA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACO,SAAS,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE;AACrC,IAAI,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC;AAChG,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM;AACtB,IAAI,IAAI,aAAa,GAAG,CAAC;AACzB,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAChC,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC5B,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC5B,QAAQ,aAAa,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;AACxC,IAAI;AACJ,IAAI,OAAO,CAAC,CAAC,GAAG,aAAa,KAAK,CAAC,GAAG,aAAa,CAAC;AACpD;;ACnBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE;AAClC,IAAI,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC;AAChG,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM;AACtB,IAAI,IAAI,IAAI,GAAG,CAAC;AAChB,IAAI,IAAI,IAAI,GAAG,CAAC;AAChB,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AAChC,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,IAAI;;AAEJ;AACA,IAAI,IAAI,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,EAAE,OAAO,CAAC;AAC1C,IAAI,IAAI,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,EAAE,OAAO,QAAQ;;AAEjD,IAAI,IAAI,QAAQ,GAAG,CAAC;AACpB,IAAI,IAAI,IAAI,GAAG,CAAC;AAChB,IAAI,IAAI,IAAI,GAAG,CAAC;AAChB,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AAChC,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;AAC3B,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;AAC3B,QAAQ,QAAQ,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;AACzC,IAAI;AACJ,IAAI,OAAO,QAAQ;AACnB;;AChCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE;AAC3B,IAAI,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC;AAChG,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM;AACtB,IAAI,IAAI,aAAa,GAAG,CAAC;AACzB,IAAI,IAAI,cAAc,GAAG,CAAC;AAC1B,IAAI,IAAI,cAAc,GAAG,CAAC;AAC1B,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAChC,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC5B,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC5B,QAAQ,aAAa,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;AACvC,QAAQ,cAAc,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;AACzC,QAAQ,cAAc,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;AACzC,IAAI;AACJ,IAAI,MAAM,eAAe,GAAG,CAAC,GAAG,aAAa,GAAG,cAAc,GAAG,cAAc;AAC/E,IAAI,OAAO,cAAc,KAAK,CAAC,IAAI,cAAc,KAAK;AACtD,UAAU;AACV,UAAU,CAAC,CAAC,GAAG,cAAc,GAAG,cAAc,KAAK,aAAa,GAAG,eAAe,GAAG,cAAc,GAAG,cAAc,CAAC;AACrH;;ACtBA;;AAEA;AACA;AACA;AACA;AACA,SAAS,QAAQ,CAAC,CAAC,EAAE;AACrB,IAAI,OAAO,CAAC,YAAY,MAAM;AAC9B;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE;AACvD;AACA,IAAI,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM;AACjD,IAAI,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;AAC9B,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAChC,QAAQ,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACjD,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxC,YAAY,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACnE,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC;AACnC,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC;AACnC,QAAQ;AACR,IAAI;AACJ,IAAI,OAAO,CAAC;AACZ;;AClCA;;;AAKA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,mBAAmB,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE;AAC9D,IAAI,CAAC,GAAG,CAAC,YAAY,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;AAChD,IAAI,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC3B,IAAI,MAAM,CAAC,GAAG,MAAM,KAAK,aAAa,GAAG,CAAC,GAAG,eAAe,CAAC,CAAC,EAAE,MAAM,CAAC;AACvE;AACA,IAAI,MAAM,EAAE,GAAG,EAAE;AACjB,IAAI,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AACzC,QAAQ,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;AACzC,aAAa,GAAG,CAAC,CAAC,QAAQ,EAAE,GAAG,KAAK;AACpC,gBAAgB,OAAO;AACvB,oBAAoB,CAAC,EAAE,GAAG;AAC1B,oBAAoB,CAAC,EAAE,GAAG;AAC1B,oBAAoB,QAAQ,EAAE,QAAQ;AACtC,iBAAiB;AACjB,YAAY,CAAC;AACb,aAAa,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ;AACnD,aAAa,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;AAC5B,QAAQ,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC;AACpB,IAAI;AACJ,IAAI,OAAO,EAAE;AACb;;ACpCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,QAAQ,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE;AAC7C,IAAI,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,IAAI,EAAE;AACjD,QAAQ,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AACzD,IAAI;AACJ,IAAI,IAAI,MAAM,GAAG,CAAC,EAAE;AACpB,QAAQ,OAAO,MAAM,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE;AAC1C,IAAI;AACJ,IAAI,MAAM,MAAM,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC;AACpC,IAAI,MAAM,IAAI,CAAC;AACf,IAAI,KAAK,IAAI,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE;AACtC,QAAQ,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,IAAI,MAAM;AAC7D,IAAI;AACJ,IAAI,OAAO,MAAM;AACjB;;ACtBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE;AACpC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM;AACtB,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE;AACxB,QAAQ,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC;AACnE,IAAI;AACJ,IAAI,IAAI,GAAG,GAAG,CAAC;AACf,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAChC,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC1B,IAAI;AACJ,IAAI,OAAO,GAAG;AACd;;AClBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,SAAS,CAAC,QAAQ,EAAE;AACpC,IAAI,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM;AAC7B,IAAI,IAAI,GAAG,GAAG,CAAC;AACf,IAAI,IAAI,YAAY,GAAG,CAAC;AACxB,IAAI,IAAI,CAAC,EAAE,CAAC;;AAEZ,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAChC,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,YAAY;AACtC,QAAQ,CAAC,GAAG,GAAG,GAAG,CAAC;AACnB,QAAQ,YAAY,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC;AAClC,QAAQ,GAAG,GAAG,CAAC;AACf,IAAI;AACJ,IAAI,OAAO,GAAG;AACd;;ACrBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,WAAW,CAAC,QAAQ,EAAE;AACtC,IAAI,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM;AAC7B,IAAI,IAAI,GAAG,GAAG,CAAC;AACf,IAAI,IAAI,YAAY,GAAG,CAAC;;AAExB,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAChC,QAAQ,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC;AACnC,QAAQ,MAAM,CAAC,GAAG,GAAG,GAAG,OAAO;AAC/B,QAAQ,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE;AAChD,YAAY,YAAY,IAAI,GAAG,GAAG,CAAC,GAAG,OAAO;AAC7C,QAAQ,CAAC,MAAM;AACf,YAAY,YAAY,IAAI,OAAO,GAAG,CAAC,GAAG,GAAG;AAC7C,QAAQ;AACR,QAAQ,GAAG,GAAG,CAAC;AACf,IAAI;AACJ,IAAI,OAAO,GAAG,GAAG,YAAY;AAC7B;;ACpBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,EAAE,CAAC,CAAC,EAAE;AACtB,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK;AAChC,IAAI,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,CAAC;AAChD,IAAI,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;;AAEvC,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,EAAE;AACnC,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1B,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAC9B,YAAY,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpE,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,EAAE;AAC3C,gBAAgB,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC;AACtC,YAAY;AACZ,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC;AACtC,QAAQ;AACR,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,EAAE,SAAS,CAAC;AACzC,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,EAAE;AACvC,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC;AAC5C,QAAQ;AACR,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;AACjC,IAAI;AACJ,IAAI,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE;AACnB;;AChCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,cAAc,CAAC,CAAC,EAAE;AAClC,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK;AAChC,IAAI,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC;AACzC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE;;AAEvB,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,EAAE;AACnC,QAAQ,MAAM,CAAC,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC;AAC9D,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;AAC9B,QAAQ,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAChC,QAAQ,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AAClC,QAAQ,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,MAAM;AACpC,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACjD,QAAQ,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,GAAG,EAAE,IAAI,MAAM;;AAEzC,QAAQ,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AACpC,QAAQ,MAAM,OAAO,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC;AACzC,QAAQ,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACpE,QAAQ,MAAM,OAAO,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC;AACzC,QAAQ,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACpE,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC;AAChC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC;AAChC,IAAI;AACJ,IAAI,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE;AACnB;;AClCA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,GAAG,CAAC,MAAM,EAAE;AAC5B,IAAI,IAAI,GAAG,GAAG,CAAC,QAAQ;AACvB,IAAI,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE;AAChC,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,GAAG,GAAG,KAAK,EAAE;AAC3C,YAAY,GAAG,GAAG,KAAK;AACvB,QAAQ;AACR,IAAI;AACJ,IAAI,OAAO,GAAG;AACd;;ACfA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,GAAG,CAAC,MAAM,EAAE;AAC5B,IAAI,IAAI,GAAG,GAAG,QAAQ;AACtB,IAAI,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE;AAChC,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,GAAG,GAAG,KAAK,EAAE;AAC3C,YAAY,GAAG,GAAG,KAAK;AACvB,QAAQ;AACR,IAAI;AACJ,IAAI,OAAO,GAAG;AACd;;ACbA;AACA;AACA;AACA;AACO,MAAM,UAAU,CAAC;AACxB,IAAI,EAAE,GAAG,GAAG;AACZ,IAAI,EAAE,GAAG,GAAG;AACZ,IAAI,SAAS,GAAG,UAAU;AAC1B,IAAI,WAAW,GAAG,UAAU;AAC5B,IAAI,WAAW,GAAG,UAAU;;AAE5B;AACA,IAAI,GAAG;AACP;AACA,IAAI,IAAI;AACR;AACA,IAAI,KAAK;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,KAAK,EAAE;AACvB,QAAQ,IAAI,CAAC,GAAG,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;AACrC,QAAQ,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC;AAC/B,QAAQ,IAAI,CAAC,KAAK,GAAG,KAAK,IAAI,IAAI,CAAC,GAAG,EAAE;AACxC,QAAQ,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK;AAC9B,IAAI;;AAEJ;AACA,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE;AACpB,QAAQ,IAAI,CAAC,KAAK,GAAG,KAAK;AAC1B,QAAQ,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG;;AAE3B,QAAQ,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,KAAK,CAAC;AAC3B,QAAQ,KAAK,IAAI,CAAC,IAAI,GAAG,CAAC,EAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE;AACjE,YAAY,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI;AACjC,YAAY,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC;AACxD,YAAY,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,UAAU,MAAM,EAAE,IAAI,UAAU,KAAK,EAAE,IAAI,CAAC,CAAC,GAAG,UAAU,IAAI,UAAU,GAAG,GAAG;AAC5G,YAAY,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;AAC1B,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,IAAI,GAAG;AACf,QAAQ,OAAO,IAAI,CAAC,KAAK;AACzB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,MAAM,GAAG;AACjB,QAAQ,OAAO,IAAI,CAAC,UAAU,IAAI,GAAG,GAAG,YAAY,CAAC;AACrD,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,UAAU,GAAG;AACrB,QAAQ,IAAI,CAAC;AACb,YAAY,KAAK,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC;AACzC,QAAQ,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,EAAE,EAAE;AAClC,YAAY,IAAI,EAAE;;AAElB;AACA;AACA;;AAEA,YAAY,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE;AACzC,YAAY,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE;;AAEzC,YAAY,KAAK,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,GAAG,EAAE,EAAE,EAAE,EAAE;AACzC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,WAAW,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC;AAC7F,gBAAgB,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC;AAClF,YAAY;AACZ,YAAY,OAAO,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE;AAC3C,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,WAAW,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC;AAC7F,gBAAgB,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC;AAC9E,YAAY;;AAEZ,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,WAAW,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC;AAC7F,YAAY,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC;;AAEtF,YAAY,IAAI,CAAC,IAAI,GAAG,CAAC;AACzB,QAAQ;AACR,QAAQ,IAAI,CAAC,IAAI,IAAI,CAAC;AACtB,QAAQ,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;AAC/B,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE;AACrB,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,UAAU;AAClC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,UAAU;AACnC,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE;;AAErB,QAAQ,OAAO,CAAC,KAAK,CAAC;AACtB,IAAI;;AAEJ,IAAI,YAAY,GAAG;AACnB,QAAQ,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;AACnB,QAAQ,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,EAAE;AAC/B,YAAY,CAAC,GAAG,IAAI,CAAC,IAAI;AACzB,YAAY,IAAI,CAAC,IAAI,GAAG,IAAI;AAC5B,YAAY,OAAO,CAAC;AACpB,QAAQ,CAAC;AACT,YAAY,GAAG;AACf,gBAAgB,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC;AACvC,gBAAgB,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC;AACvC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC;AACjC,YAAY,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;AAChC,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACnD,QAAQ,IAAI,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;AAC1B,QAAQ,OAAO,CAAC,GAAG,CAAC;AACpB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE;AACjB,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC;AACrE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM;AAC7B,QAAQ,IAAI,CAAC,GAAG,IAAI,EAAE;AACtB,YAAY,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC;AAC/C,QAAQ;AACR,QAAQ,MAAM,MAAM,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC;AACnC,QAAQ,MAAM,UAAU,GAAG,QAAQ,CAAC,CAAC,EAAE,IAAI,GAAG,CAAC,CAAC;AAChD,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE;AAChE,YAAY,MAAM,YAAY,GAAG,IAAI,CAAC,UAAU,GAAG,CAAC;AACpD,YAAY,MAAM,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7D,QAAQ;AACR,QAAQ,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACtC;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,GAAG,IAAI,EAAE;AACrC,QAAQ,MAAM,CAAC,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC;AACtC,QAAQ,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;AAC7B,IAAI;AACJ;;ACzKA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,2BAA2B;AAC3C,IAAI,CAAC;AACL,IAAI,CAAC,GAAG,CAAC;AACT,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,cAAc,GAAG,GAAG,MAAEA,IAAE,GAAGC,EAAc,EAAE,GAAG,GAAG,IAAI,EAAE,GAAG,EAAE;AAC/E,EAAE;AACF,IAAI,MAAM,UAAU,GAAG,IAAI,YAAY,UAAU,GAAG,IAAI,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC;AAC/E,IAAI,IAAI,EAAE,CAAC,YAAY,MAAM,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;AAClD,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AACxB,IAAI,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,GAAGD,IAAE,CAAC,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC;AAC5E,IAAI,OAAO,cAAc,EAAE,EAAE;AAC7B,QAAQ,MAAM,IAAI,GAAG,CAAC;AACtB,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1B,QAAQ,MAAM,EAAE,GAAGA,IAAE,CAAC,CAAC,CAAC;AACxB,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC;AAChB,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC;AAChB,QAAQ,MAAM,KAAK,GAAG,iBAAiB,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;AAC9D,QAAQ,IAAI,KAAK,GAAG,GAAG,EAAE;AACzB,YAAY;AACZ,QAAQ;AACR,IAAI;;AAEJ,IAAI,MAAM,WAAW,GAAG,CAAC,CAAC,IAAI,EAAE;AAChC,IAAI,MAAM,YAAY,GAAG,CAAC,CAAC,SAAS,EAAE,CAAC,SAAS,EAAE;AAClD,IAAI,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE;AACxC;;ACtCA;;AAEA;AACA;AACA;AACA;AACO,MAAM,MAAM,CAAC;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,GAAG,CAAC,EAAE;AACvC,8BAA8B,IAAI,CAAC,KAAK,GAAG,IAAI;AAC/C,8BAA8B,IAAI,CAAC,KAAK,GAAG,IAAI;AAC/C,oCAAoC,IAAI,CAAC,KAAK;;AAE9C,QAAQ,IAAI,IAAI,IAAI,IAAI,EAAE;AAC1B,YAAY,IAAI,CAAC,KAAK,EAAE;AACxB,gBAAgB,IAAI,CAAC,KAAK,GAAG,IAAI,YAAY,CAAC,IAAI,GAAG,IAAI,CAAC;AAC1D,YAAY;AACZ,YAAY,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE;AAC7C,gBAAgB,IAAI,CAAC,KAAK,GAAG,IAAI,YAAY,CAAC,IAAI,GAAG,IAAI,CAAC;AAC1D,gBAAgB,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AACrD,oBAAoB,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AACzD,wBAAwB,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC;AACtE,oBAAoB;AACpB,gBAAgB;AAChB,YAAY;AACZ,YAAY,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;AAC3C,gBAAgB,IAAI,KAAK,KAAK,OAAO,EAAE;AACvC,oBAAoB,IAAI,CAAC,KAAK,GAAG,IAAI,YAAY,CAAC,IAAI,GAAG,IAAI,CAAC;AAC9D,oBAAoB,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AACzD,wBAAwB,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AAC7D,4BAA4B,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC;AAC5D,wBAAwB;AACxB,oBAAoB;AACpB,gBAAgB;AAChB,gBAAgB,IAAI,KAAK,KAAK,UAAU,IAAI,KAAK,KAAK,GAAG,EAAE;AAC3D,oBAAoB,IAAI,CAAC,KAAK,GAAG,IAAI,YAAY,CAAC,IAAI,GAAG,IAAI,CAAC;AAC9D,oBAAoB,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AACzD,wBAAwB,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC;AACxD,oBAAoB;AACpB,gBAAgB;AAChB,gBAAgB,IAAI,KAAK,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,EAAE;AACzD,oBAAoB,IAAI,CAAC,KAAK,GAAG,IAAI,YAAY,CAAC,IAAI,GAAG,IAAI,CAAC;AAC9D,oBAAoB,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI;AAClE,oBAAoB,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AACzD,wBAAwB,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AAC7D,4BAA4B,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC;AAC1E,wBAAwB;AACxB,oBAAoB;AACpB,gBAAgB;AAChB,YAAY;AACZ,YAAY,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;AAC3C,gBAAgB,IAAI,CAAC,KAAK,GAAG,IAAI,YAAY,CAAC,IAAI,GAAG,IAAI,CAAC;AAC1D,gBAAgB,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AACrD,oBAAoB,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AACzD,wBAAwB,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,GAAG,GAAG,CAAC,GAAG,KAAK;AAC5D,oBAAoB;AACpB,gBAAgB;AAChB,YAAY;AACZ,YAAY,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;AACtC,gBAAgB,IAAI,CAAC,KAAK,GAAG,IAAI,YAAY,CAAC,IAAI,GAAG,IAAI,CAAC;AAC1D,gBAAgB,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AACrD,oBAAoB,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AACzD,wBAAwB,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC;AACtE,oBAAoB;AACpB,gBAAgB;AAChB,YAAY;AACZ,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,IAAI,CAAC,CAAC,EAAE;AACnB,QAAQ,IAAI,CAAC,YAAY,MAAM,EAAE;AACjC,YAAY,OAAO,CAAC,CAAC,KAAK,EAAE;AAC5B,QAAQ;AACR,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;AACjC,YAAY,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM;AAC9B,YAAY,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM;AACjC,YAAY,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE;AAC9C,gBAAgB,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE;AACzC,oBAAoB,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC;AAC5D,gBAAgB;AAChB,YAAY;AACZ,YAAY,OAAO,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtD,QAAQ;AACR,QAAQ,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC;AAChC,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,SAAS,CAAC,CAAC,EAAE;AACxB,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM;AAC1B,QAAQ,OAAO,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAC/D,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,WAAW,CAAC,CAAC,EAAE,IAAI,EAAE;AAChC,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM;AAC1B,QAAQ,IAAI,IAAI,KAAK,KAAK,EAAE;AAC5B,YAAY,OAAO,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,QAAQ,CAAC,MAAM;AACf,YAAY,OAAO,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,GAAG,CAAC,GAAG,EAAE;AACb,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM;AAChC,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK;AAC/B,QAAQ,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,GAAG,IAAI,EAAE,CAAC,GAAG,GAAG,CAAC,IAAI,IAAI,CAAC;AAC1D,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,CAAC,YAAY,GAAG;AACpB,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK;AAC/B,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK;AAC/B,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM;AAChC,QAAQ,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AAC7C,YAAY,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,GAAG,IAAI,EAAE,CAAC,GAAG,GAAG,CAAC,IAAI,IAAI,CAAC;AAC7D,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG;AACzB,QAAQ,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,YAAY,EAAE,EAAE;AAC/C,YAAY,MAAM,GAAG;AACrB,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE;AACzB,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK;AAC/B,QAAQ,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI,EAAE;AAC9D,YAAY,MAAM,MAAM,GAAG,GAAG,GAAG,IAAI;AACrC,YAAY,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AACjD,gBAAgB,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC;AACvD,YAAY;AACZ,QAAQ,CAAC,MAAM,IAAI,MAAM,YAAY,MAAM,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE;AAClG,YAAY,MAAM,MAAM,GAAG,GAAG,GAAG,IAAI;AACrC,YAAY,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AACjD,gBAAgB,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC;AAC7D,YAAY;AACZ,QAAQ,CAAC,MAAM;AACf,YAAY,MAAM,IAAI,KAAK,CAAC,qFAAqF,CAAC;AAClH,QAAQ;AACR,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE;AAC1B,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK;AAC/B,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM;AAChC,QAAQ,KAAK,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE;AACzF,YAAY,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;AAC7B,YAAY,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;AAC7B,YAAY,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;AACvB,QAAQ;AACR,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,GAAG,CAAC,GAAG,EAAE;AACb,QAAQ,MAAM,UAAU,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC;AACvD,QAAQ,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE;AACnD,YAAY,UAAU,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC;AACjE,QAAQ;AACR,QAAQ,OAAO,UAAU;AACzB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE;AACpB,QAAQ,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC;AAClD,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE;AAC/B,QAAQ,IAAI,CAAC,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,KAAK;AACnD,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE;AAC/B,QAAQ,IAAI,CAAC,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,IAAI,KAAK;AACpD,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE;AAC/B,QAAQ,IAAI,CAAC,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,IAAI,KAAK;AACpD,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,SAAS,GAAG;AAChB,QAAQ,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AACxF,QAAQ,OAAO,CAAC;AAChB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,CAAC,GAAG;AACZ,QAAQ,OAAO,IAAI,CAAC,SAAS,EAAE;AAC/B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,GAAG;AACd,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK;AAC/B,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK;AAC/B,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE;AAC9B,QAAQ,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC;;AAE7C;AACA,QAAQ,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AAC7C;AACA,YAAY,IAAI,OAAO,GAAG,GAAG;AAC7B,YAAY,IAAI,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AACrD,YAAY,KAAK,IAAI,GAAG,GAAG,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AACvD,gBAAgB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AACvD,gBAAgB,IAAI,OAAO,GAAG,GAAG,EAAE;AACnC,oBAAoB,OAAO,GAAG,GAAG;AACjC,oBAAoB,OAAO,GAAG,GAAG;AACjC,gBAAgB;AAChB,YAAY;AACZ,YAAY,IAAI,OAAO,KAAK,CAAC,EAAE;AAC/B,gBAAgB,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC;AACxF,YAAY;AACZ;AACA,YAAY,IAAI,OAAO,KAAK,GAAG,EAAE;AACjC,gBAAgB,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC;AACzC,gBAAgB,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC;AACzC,YAAY;;AAEZ;AACA,YAAY,MAAM,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;AACpC,YAAY,MAAM,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;AACpC,YAAY,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AACjD,gBAAgB,IAAI,GAAG,KAAK,GAAG,EAAE;AACjC;AACA,oBAAoB,MAAM,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;AAC5C,oBAAoB,MAAM,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;AAC5C,oBAAoB,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;AAC1C,wBAAwB,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC;AACzD;AACA,wBAAwB,KAAK,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,EAAE;AACzD,4BAA4B,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;AACpD,wBAAwB;AACxB,wBAAwB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,EAAE;AACvD,4BAA4B,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;AACpD,wBAAwB;AACxB,oBAAoB;AACpB,gBAAgB,CAAC,MAAM;AACvB;AACA;AACA,oBAAoB,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC;AACxC,oBAAoB,KAAK,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,EAAE;AACrD,wBAAwB,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACrC,oBAAoB;AACpB,oBAAoB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,EAAE;AACnD,wBAAwB,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACrC,oBAAoB;AACpB,gBAAgB;AAChB,YAAY;AACZ,QAAQ;AACR,QAAQ,OAAO,CAAC;AAChB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,GAAG,CAAC,CAAC,EAAE;AACX,QAAQ,IAAI,CAAC,YAAY,MAAM,EAAE;AACjC,YAAY,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK;AAC/C,YAAY,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK;AAC5C,YAAY,IAAI,MAAM,KAAK,MAAM,EAAE;AACnC,gBAAgB,MAAM,IAAI,KAAK,CAAC,CAAC,iBAAiB,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,gBAAgB,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACjH,sBAAsB,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC;AACpD,8BAA8B,CAAC,CAAC;AAChC,YAAY;AACZ,YAAY,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;AACnD,YAAY,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM;AACrC,YAAY,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM;AAClC,YAAY,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM;;AAElC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,EAAE,CAAC,EAAE;AAC7C,gBAAgB,MAAM,QAAQ,GAAG,CAAC,GAAG,MAAM;AAC3C,gBAAgB,MAAM,QAAQ,GAAG,CAAC,GAAG,MAAM;AAC3C,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,EAAE,CAAC,EAAE;AACjD,oBAAoB,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC;AACnD,oBAAoB,IAAI,GAAG,KAAK,CAAC,EAAE;AACnC,oBAAoB,MAAM,QAAQ,GAAG,CAAC,GAAG,MAAM;AAC/C,oBAAoB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,EAAE,CAAC,EAAE;AACrD,wBAAwB,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,IAAI,GAAG,GAAG,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC;AACxE,oBAAoB;AACpB,gBAAgB;AAChB,YAAY;AACZ,YAAY,OAAO,CAAC;AACpB,QAAQ,CAAC,MAAM,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AACtC;AACA,YAAY,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK;AACnC,YAAY,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI,EAAE;AACnC,gBAAgB,MAAM,IAAI,KAAK,CAAC,CAAC,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;AAC1G,YAAY;AACZ,YAAY,MAAM,CAAC,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC;AACrC,YAAY,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AACjD,gBAAgB,CAAC,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1E,YAAY;AACZ,YAAY,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;AACjC,QAAQ,CAAC,MAAM;AACf,YAAY,MAAM,IAAI,KAAK,CAAC,CAAC,yBAAyB,CAAC,CAAC;AACxD,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,QAAQ,CAAC,CAAC,EAAE;AAChB,QAAQ,IAAI,CAAC,YAAY,MAAM,EAAE;AACjC,YAAY,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC;AAChD,YAAY,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK;AAC5C,YAAY,IAAI,MAAM,KAAK,MAAM,EAAE;AACnC,gBAAgB,MAAM,IAAI,KAAK,CAAC,CAAC,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,gBAAgB,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACvH,sBAAsB,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,2BAA2B,CAAC,CAAC;AACjF,YAAY;AACZ;AACA;AACA,YAAY,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;AACnD,YAAY,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC;AACtC,YAAY,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM;AAClC,YAAY,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM;;AAElC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,EAAE,CAAC,EAAE;AAC7C;AACA,gBAAgB,MAAM,QAAQ,GAAG,CAAC,GAAG,MAAM;AAC3C,gBAAgB,MAAM,QAAQ,GAAG,CAAC,GAAG,MAAM;AAC3C,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,EAAE,CAAC,EAAE;AACjD,oBAAoB,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC;AACnD,oBAAoB,IAAI,GAAG,KAAK,CAAC,EAAE;AACnC,oBAAoB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,EAAE,CAAC,EAAE;AACrD,wBAAwB,KAAK,CAAC,CAAC,GAAG,MAAM,GAAG,CAAC,CAAC,IAAI,GAAG,GAAG,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC;AAC1E,oBAAoB;AACpB,gBAAgB;AAChB,YAAY;AACZ,YAAY,OAAO,CAAC;AACpB,QAAQ,CAAC,MAAM,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AACtC;AACA,YAAY,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK;AACnC,YAAY,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI,EAAE;AACnC,gBAAgB,MAAM,IAAI,KAAK,CAAC,CAAC,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;AAC1G,YAAY;AACZ,YAAY,MAAM,CAAC,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC;AACrC,YAAY,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AACjD,gBAAgB,CAAC,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1E,YAAY;AACZ,YAAY,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;AACjC,QAAQ,CAAC,MAAM;AACf,YAAY,MAAM,IAAI,KAAK,CAAC,CAAC,yBAAyB,CAAC,CAAC;AACxD,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,QAAQ,CAAC,CAAC,EAAE;AAChB,QAAQ,IAAI,CAAC,YAAY,MAAM,EAAE;AACjC,YAAY,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK;AAC/C,YAAY,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK;AAC5C,YAAY,IAAI,MAAM,KAAK,MAAM,EAAE;AACnC,gBAAgB,MAAM,IAAI,KAAK,CAAC,CAAC,iBAAiB,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC1H,sBAAsB,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,2BAA2B,CAAC,CAAC;AACjF,YAAY;AACZ,YAAY,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK;AAC/D,gBAAgB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;AACzC,gBAAgB,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;AACtC,gBAAgB,IAAI,GAAG,GAAG,CAAC;AAC3B,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,EAAE,CAAC,EAAE;AACjD,oBAAoB,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;AAC1C,gBAAgB;AAChB,gBAAgB,OAAO,GAAG;AAC1B,YAAY,CAAC,CAAC;AACd,YAAY,OAAO,CAAC;AACpB,QAAQ,CAAC,MAAM,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AACtC;AACA,YAAY,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK;AACnC,YAAY,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI,EAAE;AACnC,gBAAgB,MAAM,IAAI,KAAK,CAAC,CAAC,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;AAC1G,YAAY;AACZ,YAAY,MAAM,CAAC,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC;AACrC,YAAY,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AACjD,gBAAgB,CAAC,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1E,YAAY;AACZ,YAAY,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;AACjC,QAAQ,CAAC,MAAM;AACf,YAAY,MAAM,IAAI,KAAK,CAAC,CAAC,yBAAyB,CAAC,CAAC;AACxD,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,KAAK,CAAC,CAAC,EAAE;AACb,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM;AACnC,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM;AAChC,QAAQ,IAAI,CAAC,KAAK,CAAC,EAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC;AACtF,QAAQ,MAAM,CAAC,GAAG,IAAI,MAAM;AAC5B,YAAY,CAAC;AACb,YAAY,CAAC;AACb,oCAAoC,CAAC,CAAC,EAAE,CAAC,KAAK;AAC9C,gBAAgB,IAAI,CAAC,IAAI,CAAC,EAAE;AAC5B,oBAAoB,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AACrD,gBAAgB,CAAC,MAAM;AACvB,oBAAoB,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAC3C,gBAAgB;AAChB,YAAY,CAAC;AACb,SAAS;;AAET,QAAQ,OAAO,CAAC;AAChB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,MAAM,CAAC,CAAC,EAAE,IAAI,GAAG,YAAY,EAAE;AACnC,QAAQ,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK;AAC3C,QAAQ,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK;AACxC,QAAQ,IAAI,IAAI,KAAK,YAAY,EAAE;AACnC,YAAY,IAAI,MAAM,KAAK,MAAM,EAAE;AACnC,gBAAgB,MAAM,IAAI,KAAK;AAC/B,oBAAoB,CAAC,mEAAmE,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC;AAC9H,iBAAiB;AACjB,YAAY;AACZ,YAAY,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,OAAO,CAAC;AAClE,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC;AACnC,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;AACrC,YAAY,OAAO,CAAC;AACpB,QAAQ,CAAC,MAAM,IAAI,IAAI,KAAK,UAAU,EAAE;AACxC,YAAY,IAAI,MAAM,KAAK,MAAM,EAAE;AACnC,gBAAgB,MAAM,IAAI,KAAK;AAC/B,oBAAoB,CAAC,oEAAoE,EAAE,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,SAAS,CAAC;AACrI,iBAAiB;AACjB,YAAY;AACZ,YAAY,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC;AAClE,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC;AACnC,YAAY,CAAC,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;AACrC,YAAY,OAAO,CAAC;AACpB,QAAQ,CAAC,MAAM,IAAI,IAAI,KAAK,MAAM,EAAE;AACpC,YAAY,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,OAAO,CAAC;AAC3E,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC;AACnC,YAAY,CAAC,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;AAC1C,YAAY,OAAO,CAAC;AACpB,QAAQ,CAAC,MAAM;AACf,YAAY,MAAM,IAAI,KAAK,CAAC,CAAC,qDAAqD,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;AAC5F,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,SAAS,CAAC,UAAU,EAAE,UAAU,EAAE,CAAC,EAAE;AACzC,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAClE,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAClE,QAAQ,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AAC7C,YAAY,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AACjD,gBAAgB,IAAI,CAAC,SAAS,CAAC,GAAG,GAAG,UAAU,EAAE,GAAG,GAAG,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AACrF,YAAY;AACZ,QAAQ;AACR,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,SAAS,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE;AACtD,QAAQ,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK;AACvC,QAAQ,OAAO,GAAG,OAAO,IAAI,IAAI;AACjC,QAAQ,OAAO,GAAG,OAAO,IAAI,IAAI;AACjC,QAAQ,IAAI,OAAO,IAAI,SAAS,IAAI,OAAO,IAAI,SAAS,EAAE;AAC1D,YAAY,MAAM,IAAI,KAAK,CAAC;AAC5B;AACA;AACA,0BAA0B,EAAE,OAAO,CAAC,cAAc,EAAE,SAAS,CAAC,YAAY,EAAE,OAAO,CAAC,kBAAkB,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;AACrH,QAAQ;AACR,QAAQ,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,OAAO,GAAG,SAAS,EAAE,OAAO,GAAG,SAAS,EAAE,OAAO,CAAC;AAC/E,QAAQ,KAAK,IAAI,GAAG,GAAG,SAAS,EAAE,OAAO,GAAG,CAAC,EAAE,GAAG,GAAG,OAAO,EAAE,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE;AAChF,YAAY,KAAK,IAAI,GAAG,GAAG,SAAS,EAAE,OAAO,GAAG,CAAC,EAAE,GAAG,GAAG,OAAO,EAAE,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE;AACpF,gBAAgB,CAAC,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AACnE,YAAY;AACZ,QAAQ;AACR,QAAQ,OAAO,CAAC;AAChB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,MAAM,CAAC,WAAW,EAAE,WAAW,EAAE;AACrC,QAAQ,MAAM,CAAC,GAAG,WAAW,CAAC,MAAM;AACpC,QAAQ,MAAM,CAAC,GAAG,WAAW,CAAC,MAAM;;AAEpC,QAAQ,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;AAClC,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,MAAM,SAAS,GAAG,WAAW,CAAC,CAAC,CAAC;AAC5C,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxC,gBAAgB,MAAM,SAAS,GAAG,WAAW,CAAC,CAAC,CAAC;AAChD,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;AACnE,YAAY;AACZ,QAAQ;;AAER,QAAQ,OAAO,CAAC;AAChB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE;AACvB,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM;AAChC,QAAQ,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK;AACvC,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AACpD,YAAY,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE;AACtD,gBAAgB,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AACjD,YAAY;AACZ,QAAQ;AACR,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,oBAAoB,CAAC,MAAM,EAAE,CAAC,EAAE;AACpC,QAAQ,OAAO,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC;AACxD,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA,IAAI,oBAAoB,CAAC,MAAM,EAAE,CAAC,EAAE;AACpC,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM;AAChC,QAAQ,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK;AACvC,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AACpD,YAAY,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC;AACnC,YAAY,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE;AACtD,gBAAgB,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;AACzC,YAAY;AACZ,QAAQ;AACR,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE;AACrB,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM;AAChC,QAAQ,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK;AACvC,QAAQ,IAAI,KAAK,YAAY,MAAM,EAAE;AACrC,YAAY,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM;AACvC,YAAY,MAAM,CAAC,UAAU,EAAE,UAAU,CAAC,GAAG,KAAK,CAAC,KAAK;AACxD,YAAY,IAAI,UAAU,KAAK,CAAC,EAAE;AAClC,gBAAgB,IAAI,IAAI,KAAK,UAAU,EAAE;AACzC,oBAAoB,MAAM,IAAI,KAAK,CAAC,CAAC,mBAAmB,CAAC,CAAC;AAC1D,gBAAgB;AAChB,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AAC5D,oBAAoB,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE;AAC9D,wBAAwB,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;AACzD,oBAAoB;AACpB,gBAAgB;AAChB,YAAY,CAAC,MAAM,IAAI,UAAU,KAAK,CAAC,EAAE;AACzC,gBAAgB,IAAI,IAAI,KAAK,UAAU,EAAE;AACzC,oBAAoB,MAAM,IAAI,KAAK,CAAC,CAAC,mBAAmB,CAAC,CAAC;AAC1D,gBAAgB;AAChB,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AAC5D,oBAAoB,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC;AACzC,oBAAoB,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE;AAC9D,wBAAwB,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC/C,oBAAoB;AACpB,gBAAgB;AAChB,YAAY,CAAC,MAAM,IAAI,IAAI,KAAK,UAAU,IAAI,IAAI,KAAK,UAAU,EAAE;AACnE,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAC7D,oBAAoB,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;AACnD,gBAAgB;AAChB,YAAY,CAAC,MAAM;AACnB,gBAAgB,MAAM,IAAI,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;AACxC,YAAY;AACZ,QAAQ,CAAC,MAAM,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;AAC1C,YAAY,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,EAAE;AACvC,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AAC5D,oBAAoB,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC;AACxC,oBAAoB,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE;AAC9D,wBAAwB,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC/C,oBAAoB;AACpB,gBAAgB;AAChB,YAAY,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,EAAE;AAC9C,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AAC5D,oBAAoB,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE;AAC9D,wBAAwB,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;AACxD,oBAAoB;AACpB,gBAAgB;AAChB,YAAY,CAAC,MAAM;AACnB,gBAAgB,MAAM,IAAI,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;AACxC,YAAY;AACZ,QAAQ,CAAC,MAAM;AACf;AACA,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACzD,gBAAgB,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC;AAC3C,YAAY;AACZ,QAAQ;AACR,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,KAAK,GAAG;AACZ,QAAQ,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC;AACpD;AACA;AACA,QAAQ,IAAI,IAAI,CAAC,KAAK,EAAE;AACxB,YAAY,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;AACzC,QAAQ;AACR,QAAQ,OAAO,CAAC;AAChB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,CAAC,KAAK,EAAE,EAAE,MAAM,GAAG,KAAK,EAAE,GAAG,EAAE,EAAE;AACzC,QAAQ,MAAM,CAAC,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE;AAC9C,QAAQ,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AAC/C,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,GAAG,KAAK,EAAE,GAAG,EAAE,EAAE;AAC3C,QAAQ,MAAM,CAAC,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE;AAC9C,QAAQ,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AAC/C,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,GAAG,CAAC,KAAK,EAAE,EAAE,MAAM,GAAG,KAAK,EAAE,GAAG,EAAE,EAAE;AACxC,QAAQ,MAAM,CAAC,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE;AAC9C,QAAQ,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AAC/C,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,GAAG,CAAC,KAAK,EAAE,EAAE,MAAM,GAAG,KAAK,EAAE,GAAG,EAAE,EAAE;AACxC,QAAQ,MAAM,CAAC,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE;AAC9C,QAAQ,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AAC/C,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,KAAK,GAAG;AAChB,QAAQ,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC;AACvC,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,KAAK,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,GAAG,MAAM,CAAC,CAAC,EAAE;AAC7C,QAAQ,IAAI,CAAC,KAAK,GAAG,IAAI;AACzB,QAAQ,IAAI,CAAC,KAAK,GAAG,IAAI;AACzB,QAAQ,IAAI,CAAC,KAAK,GAAG,IAAI,YAAY,CAAC,IAAI,GAAG,IAAI,CAAC;AAClD,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AACpD,YAAY,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE;AACtD,gBAAgB,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC;AAC/C,YAAY;AACZ,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,SAAS,GAAG;AAChB,QAAQ,MAAM,MAAM,GAAG,EAAE;AACzB,QAAQ,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,YAAY,EAAE,EAAE;AAC/C,YAAY,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;AAC5B,QAAQ;AACR,QAAQ,OAAO,MAAM;AACrB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,GAAG;AACd,QAAQ,MAAM,MAAM,GAAG,EAAE;AACzB,QAAQ,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,YAAY,EAAE,EAAE;AAC/C,YAAY,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACxC,QAAQ;AACR,QAAQ,OAAO,MAAM;AACrB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,GAAG;AACX,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK;AAC/B,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK;AAC/B,QAAQ,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC;AAChD,QAAQ,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,WAAW,CAAC;AACpD,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,EAAE,EAAE,CAAC,EAAE;AAC9C,YAAY,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACxC,QAAQ;AACR,QAAQ,OAAO,MAAM;AACrB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,GAAG;AACX,QAAQ,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;AAC9B,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK;AACzC,QAAQ,OAAO,GAAG,GAAG,CAAC;AACtB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,GAAG,GAAG;AACV,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM;AAChC,QAAQ,OAAO,WAAW,CAAC,IAAI,CAAC;AAChC,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,MAAM,GAAG;AACjB,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK;AAC/B,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,QAAQ,GAAG;AACf,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM;AAChC,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK;AAC/B,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK;AAC/B,QAAQ,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AAC1D,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AACpD,YAAY,IAAI,GAAG,GAAG,CAAC;AACvB,YAAY,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE;AACtD,gBAAgB,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC;AAC9B,YAAY;AACZ,YAAY,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,IAAI;AACpC,QAAQ;AACR,QAAQ,OAAO,MAAM;AACrB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,QAAQ,GAAG;AACf,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM;AAChC,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK;AAC/B,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK;AAC/B,QAAQ,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AAC1D,QAAQ,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AAC7C,YAAY,IAAI,GAAG,GAAG,CAAC;AACvB,YAAY,KAAK,IAAI,CAAC,GAAG,GAAG,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE;AACrE,gBAAgB,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC;AAC9B,YAAY;AACZ,YAAY,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,IAAI;AACpC,QAAQ;AACR,QAAQ,OAAO,MAAM;AACrB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,GAAG,GAAG,IAAI,EAAE;AAClD,QAAQ,IAAI,CAAC,UAAU,EAAE;AACzB,YAAY,UAAU,GAAG,IAAI,UAAU,EAAE;AACzC,QAAQ;AACR,QAAQ,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC/B,QAAQ,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC/B,QAAQ,IAAI,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;AACxC,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,EAAE;AACvC,YAAY,MAAM,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC;AAC3D,YAAY,IAAI,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,MAAM,UAAU,CAAC,MAAM,CAAC;AAChE,YAAY,IAAI,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACrC,YAAY,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE;AAC7B,YAAY,IAAI,IAAI,GAAG,CAAC;AACxB,YAAY,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAE,CAAC;AACvC,YAAY,GAAG;AACf,gBAAgB,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAClC,gBAAgB,MAAM,KAAK,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACnF,gBAAgB,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACxC,gBAAgB,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACnD,gBAAgB,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAC5F,gBAAgB,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC5C,gBAAgB,CAAC,GAAG,MAAM;AAC1B,gBAAgB,IAAI,EAAE;AACtB,YAAY,CAAC,QAAQ,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,GAAG,IAAI,IAAI,GAAG,QAAQ;AAChE,YAAY,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,YAAY,CAAC;AACnD,QAAQ;AACR,QAAQ,OAAO,MAAM;AACrB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE;AACvB,QAAQ,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;AAChE,QAAQ,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC/B,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE;;AAE3B;AACA,QAAQ,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AAC7C,YAAY,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,GAAG,EAAE,EAAE,GAAG,EAAE;AAChD,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACxE,YAAY;AACZ,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AACpE,QAAQ;;AAER;AACA,QAAQ,KAAK,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,EAAE,GAAG,EAAE;AAClD,YAAY,KAAK,IAAI,GAAG,GAAG,IAAI,GAAG,CAAC,EAAE,GAAG,GAAG,GAAG,EAAE,EAAE,GAAG,EAAE;AACvD,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACxE,YAAY;AACZ,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AACpE,QAAQ;;AAER,QAAQ,OAAO,CAAC;AAChB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,EAAE,CAAC,CAAC,EAAE;AACjB,QAAQ,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC/B,QAAQ,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC;AACjD,QAAQ,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,CAAC;;AAEpD,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,EAAE;AACvC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,EAAE;AAC3C,gBAAgB,IAAI,GAAG,GAAG,CAAC;AAC3B,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAC5C,oBAAoB,GAAG,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACxD,gBAAgB;AAChB,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC;AACtD,YAAY;AACZ,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,EAAE;AAC3C,gBAAgB,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE;AACzC,oBAAoB,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC;AACzE,gBAAgB;AAChB,gBAAgB,IAAI,GAAG,GAAG,CAAC;AAC3B,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAC5C,oBAAoB,GAAG,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACxD,gBAAgB;AAChB,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACxE,YAAY;AACZ,QAAQ;;AAER,QAAQ,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE;AACvB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,GAAG,CAAC,CAAC,EAAE;AAClB,QAAQ,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK;;AAEpC,QAAQ,IAAI,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,EAAE;AACtC,YAAY,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAChF,QAAQ;AACR,QAAQ,IAAI,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,EAAE;AACtC,YAAY,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACnC,YAAY,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACnC,YAAY,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACnC,YAAY,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACnC,YAAY,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACnC,YAAY,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACnC,YAAY,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACnC,YAAY,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACnC,YAAY,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACnC,YAAY,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAClF,QAAQ;;AAER,QAAQ,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;AACrC,QAAQ,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE;AAC/B,QAAQ,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE;AAC/B,QAAQ,IAAI,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;AACvC,QAAQ,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AAC7C,YAAY,GAAG,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC;AAC5C,QAAQ;AACR,QAAQ,OAAO,GAAG;AAClB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE;AACzB,QAAQ,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;AACjC,QAAQ,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;AACjC,QAAQ,MAAM,EAAE,YAAY,EAAE,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,2BAA2B,CAAC,GAAG,EAAE,CAAC,CAAC;AAC3F,QAAQ,MAAM,EAAE,YAAY,EAAE,CAAC,EAAE,GAAG,2BAA2B,CAAC,GAAG,EAAE,CAAC,CAAC;AACvE,QAAQ,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;;AAE5E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,OAAO,OAAO,CAAC,CAAC,EAAE;AACtB,QAAQ,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,YAAY,IAAI,CAAC,YAAY,YAAY;AACzF,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,OAAO,SAAS,CAAC,CAAC,EAAE;AACxB,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE;AACjD,YAAY,OAAO,KAAK;AACxB,QAAQ;AACR,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM;AAC7B,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE;AAC3C,YAAY,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,YAAY,CAAC,EAAE;AACzE,gBAAgB,OAAO,KAAK;AAC5B,YAAY;AACZ,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE;AACnC,gBAAgB,OAAO,KAAK;AAC5B,YAAY;AACZ,QAAQ;AACR,QAAQ,OAAO,IAAI;AACnB,IAAI;AACJ;;ACjrCA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE;AAC5C,IAAI,IAAI,MAAM,GAAG,IAAI;AACrB,IAAI,IAAI,CAAC,YAAY,MAAM,EAAE;AAC7B,QAAQ,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK;AACpC,QAAQ,IAAI,IAAI,KAAK,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACzC,aAAa,IAAI,IAAI,KAAK,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAC9C,aAAa,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;AAClD,IAAI,CAAC,MAAM;AACX,QAAQ,MAAM,GAAG,CAAC;AAClB,IAAI;AACJ,IAAI,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM;AAC3B,IAAI,MAAM,KAAK,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC;AACrC,IAAI,OAAO,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC;AAChC;;ACvBA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE;AACjD,IAAI,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC;AAClC,IAAI,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,KAAK,KAAK,GAAG,MAAM,CAAC;AAC3C;;ACdA;;AAEA;AACA;AACA;AACA;AACO,MAAM,UAAU,CAAC;AACxB;AACA,IAAI,OAAO;AACX;AACA,IAAI,WAAW;AACf;AACA,IAAI,OAAO;AACX;AACA,IAAI,EAAE;AACN;AACA,IAAI,EAAE;;AAEN;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,MAAM,EAAE,UAAU,EAAE;AACpC,QAAQ,IAAI,CAAC,OAAO,GAAG,MAAM;AAC7B,QAAQ,IAAI,CAAC,WAAW,GAAG,UAAU;;AAErC,QAAQ,IAAI,CAAC,OAAO,GAAG,MAAM,YAAY,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;AAC9E,QAAQ,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK;AACzC,QAAQ,IAAI,CAAC,EAAE,GAAG,CAAC;AACnB,QAAQ,IAAI,CAAC,EAAE,GAAG,CAAC;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,YAAY,CAAC,GAAG,IAAI,EAAE;AAE1B,QAAQ,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC;AACzE,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,gBAAgB,CAAC,GAAG,IAAI,EAAE;AAE9B,QAAQ,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC;AAC7E,IAAI;AACJ;;ACnDA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,IAAI,SAAS,UAAU,CAAC;AACrC;AACA,IAAI,EAAE;AACN;AACA,IAAI,oBAAoB;AACxB;AACA,IAAI,cAAc;AAClB;AACA;AACA;AACA;AACA,IAAI,SAAS,GAAG,EAAE;AAClB;AACA,IAAI,YAAY,GAAG,EAAE;;AAErB;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,EAAE,EAAE;AACzC,QAAQ,KAAK;AACb,YAAY,MAAM;AAClB;AACA,gBAAgB,MAAM,CAAC,MAAM;AAC7B,oBAAoB,EAAE,CAAC,EAAE,CAAC,EAAE,mBAAmB,EAAE,CAAC,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE;AACvG,oBAAoB,UAAU;AAC9B;AACA;AACA,SAAS;;AAET,QAAQ,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC;AACzC,QAAQ,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC,WAAW,CAAC,mBAAmB,IAAI,CAAC;AAC7E,QAAQ,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,WAAW,CAAC,aAAa,IAAI,GAAG;;AAEnE;AACA,QAAQ,IAAI,CAAC,oBAAoB,EAAE;AACnC;AACA,QAAQ,IAAI,CAAC,KAAK,EAAE;AACpB,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,oBAAoB,GAAG;AAC3B,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB;AACA,QAAQ,IAAI,CAAC,SAAS,GAAG,EAAE;;AAE3B,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;AAC7C,YAAY,MAAM,QAAQ,GAAG,IAAI,YAAY,CAAC,KAAK,CAAC;AACpD;AACA,YAAY,MAAM,eAAe,GAAG,CAAC,IAAI,YAAY,CAAC,KAAK,CAAC,CAAC;;AAE7D,YAAY,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,eAAe,CAAC,CAAC;AAChF,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE;AAC1C,QAAQ,MAAM,KAAK,GAAG,QAAQ,CAAC,eAAe;AAC9C,QAAQ,MAAM,KAAK,GAAG,QAAQ,CAAC,eAAe;AAC9C,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM;;AAE9C,QAAQ,IAAI,QAAQ,GAAG,QAAQ;AAC/B,QAAQ,KAAK,MAAM,EAAE,IAAI,KAAK,EAAE;AAChC,YAAY,KAAK,MAAM,EAAE,IAAI,KAAK,EAAE;AACpC,gBAAgB,MAAM,IAAI,GAAG,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC;AAC3C,gBAAgB,IAAI,IAAI,GAAG,QAAQ,EAAE;AACrC,oBAAoB,QAAQ,GAAG,IAAI;AACnC,gBAAgB;AAChB,YAAY;AACZ,QAAQ;AACR,QAAQ,OAAO,QAAQ;AACvB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,sBAAsB,GAAG;AAC7B,QAAQ,IAAI,QAAQ,GAAG,QAAQ;AAC/B,QAAQ,IAAI,KAAK,GAAG,CAAC;AACrB,QAAQ,IAAI,KAAK,GAAG,CAAC;;AAErB,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE;AACxD,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE;AAChE,gBAAgB,MAAM,IAAI,GAAG,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACzF,gBAAgB,IAAI,IAAI,GAAG,QAAQ,EAAE;AACrC,oBAAoB,QAAQ,GAAG,IAAI;AACnC,oBAAoB,KAAK,GAAG,CAAC;AAC7B,oBAAoB,KAAK,GAAG,CAAC;AAC7B,gBAAgB;AAChB,YAAY;AACZ,QAAQ;;AAER,QAAQ,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,CAAC;AACvC,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,eAAe,CAAC,QAAQ,EAAE,QAAQ,EAAE;AACxC;AACA,QAAQ,MAAM,cAAc,GAAG,CAAC,GAAG,QAAQ,CAAC,OAAO,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC;;AAEzE;AACA,QAAQ,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM;AAC7C,QAAQ,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM;AAC7C,QAAQ,MAAM,UAAU,GAAG,KAAK,GAAG,KAAK;AACxC,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,YAAY,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC;;AAEhD,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,UAAU;AACxG,QAAQ;;AAER;AACA;AACA,QAAQ,MAAM,UAAU,GAAG,EAAE;AAC7B,QAAQ,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,OAAO,EAAE;AAC5C,YAAY,UAAU,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;AACzE,QAAQ;AACR,QAAQ,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,OAAO,EAAE;AAC5C,YAAY,UAAU,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;AACzE,QAAQ;;AAER;AACA,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,oBAAoB,EAAE,UAAU,CAAC,MAAM,CAAC;AAC/E,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM;;AAE9C;AACA,QAAQ,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,MAAM,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;;AAEpF;AACA,QAAQ,MAAM,gBAAgB,GAAG,EAAE;AACnC,QAAQ,MAAM,IAAI,GAAG,IAAI,GAAG,EAAE;;AAE9B,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,EAAE,CAAC,EAAE;AAC3C,YAAY,IAAI,QAAQ,GAAG,EAAE;AAC7B,YAAY,IAAI,OAAO,GAAG,EAAE;;AAE5B,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE;AACvD,gBAAgB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,GAAG,QAAQ,EAAE;AAC7D,oBAAoB,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC;AAC3C,oBAAoB,OAAO,GAAG,CAAC;AAC/B,gBAAgB;AAChB,YAAY;;AAEZ,YAAY,IAAI,OAAO,IAAI,CAAC,EAAE;AAC9B,gBAAgB,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;AACjC,gBAAgB,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC;AAC9C,YAAY;AACZ,QAAQ;;AAER;AACA,QAAQ,MAAM,mBAAmB,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK;AAClE,YAAY,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,KAAK;AAC/C,YAAY,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC;AAC9C,YAAY,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc;;AAE7C,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxC,gBAAgB,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,YAAY,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;AAC3E,YAAY;;AAEZ,YAAY,OAAO,MAAM;AACzB,QAAQ,CAAC,CAAC;;AAEV,QAAQ,OAAO,IAAI,WAAW,CAAC,cAAc,EAAE,YAAY,EAAE,mBAAmB,CAAC;AACjF,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,KAAK,GAAG;AACZ;AACA,QAAQ,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,EAAE;AAChD,YAAY,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,sBAAsB,EAAE;;AAExD;AACA,YAAY,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;;AAErF;AACA;AACA;AACA,YAAY,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;AACvC,YAAY,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;;AAEvC,YAAY,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC;AACvC,QAAQ;;AAER;AACA,QAAQ,IAAI,CAAC,kBAAkB,EAAE;AACjC,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,kBAAkB,GAAG;AACzB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,IAAI,CAAC,YAAY,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;;AAEjD,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE;AACxD,YAAY,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE;AACzD,gBAAgB,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC;AAC1C,YAAY;AACZ,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA,IAAI,YAAY,GAAG;AACnB,QAAQ,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC;AAC/D,IAAI;;AAEJ;AACA;AACA;AACA,IAAI,gBAAgB,GAAG;AACvB,QAAQ,OAAO,IAAI,CAAC,YAAY;AAChC,IAAI;AACJ;;AAEA;AACA;AACA;AACA;AACA,MAAM,WAAW,CAAC;AAClB;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE;AACpD;AACA,QAAQ,IAAI,CAAC,OAAO,GAAG,OAAO;AAC9B;AACA,QAAQ,IAAI,CAAC,QAAQ,GAAG,QAAQ;AAChC;AACA,QAAQ,IAAI,CAAC,eAAe,GAAG,eAAe;AAC9C,IAAI;AACJ;;AC5QA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,sBAAsB,SAAS,UAAU,CAAC;AACvD;AACA,IAAI,IAAI,GAAG,IAAI;;AAEf;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,EAAE,EAAE;AACzC,QAAQ,KAAK;AACb,YAAY,MAAM;AAClB;AACA,gBAAgB,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,UAAU;AACpF;AACA,SAAS;AACT,QAAQ,IAAI,CAAC,GAAG,GAAG,CAAC;AACpB,QAAQ,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,KAAK,aAAa,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;AAC1G,YAAY,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC;AACxF,QAAQ;;AAER,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM;AAC9C,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO;AAC9B,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,IAAI,CAAC,MAAM,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC;AACzC,QAAQ,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM;AACjC,QAAQ,IAAI,eAAe;AAC3B,QAAQ,IAAI,MAAM,KAAK,aAAa,EAAE;AACtC,YAAY,eAAe,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC;AACxD,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxC,gBAAgB,eAAe,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAClD,gBAAgB,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAC7B,gBAAgB,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACnC,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAChD,oBAAoB,MAAM,IAAI,GAAG,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACrD,oBAAoB,eAAe,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC;AACzD,oBAAoB,eAAe,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC;AACzD,gBAAgB;AAChB,YAAY;AACZ,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AACxC,gBAAgB,IAAI,KAAK,GAAG,CAAC;AAC7B,gBAAgB,IAAI,KAAK,GAAG,QAAQ;AACpC,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AAC5C,oBAAoB,IAAI,CAAC,KAAK,CAAC,EAAE;AACjC,oBAAoB,MAAM,CAAC,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACzD,oBAAoB,IAAI,CAAC,GAAG,KAAK,EAAE;AACnC,wBAAwB,KAAK,GAAG,CAAC;AACjC,wBAAwB,KAAK,GAAG,CAAC;AACjC,oBAAoB;AACpB,gBAAgB;AAChB,gBAAgB,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK;AAChC,YAAY;AACZ,QAAQ,CAAC,MAAM;AACf,YAAY,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE;AAClD,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxC,gBAAgB,eAAe,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAClD,gBAAgB,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;AAC1C,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAC5C,oBAAoB,IAAI,CAAC,KAAK,CAAC,EAAE;AACjC,oBAAoB,IAAI,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;AAC1F,wBAAwB,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;AACpC,oBAAoB;AACpB,gBAAgB;AAChB,YAAY;AACZ,QAAQ;AACR,QAAQ,IAAI,CAAC,gBAAgB,GAAG,eAAe;AAC/C,QAAQ,IAAI,CAAC,SAAS,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC;AACrC,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS;AACvC,QAAQ,IAAI,CAAC,OAAO,GAAG,IAAI,WAAW,CAAC,CAAC,CAAC;AACzC,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO;AACnC,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE;AAC5B,YAAY,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACtF,YAAY,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;AACzB,QAAQ;AACR,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,gBAAgB;AACvC,QAAQ,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO;AAChD,QAAQ,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC;AAC3B,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,EAAE,CAAC,EAAE;AACxC,YAAY,IAAI,EAAE,GAAG,EAAE;AACvB,YAAY,IAAI,QAAQ,GAAG,QAAQ;AACnC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxC,gBAAgB,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,QAAQ,EAAE;AAChD,gBAAgB,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;AACjD,gBAAgB,IAAI,IAAI,GAAG,QAAQ,EAAE;AACrC,oBAAoB,QAAQ,GAAG,IAAI;AACnC,oBAAoB,EAAE,GAAG,CAAC;AAC1B,gBAAgB;AAChB,YAAY;AACZ,YAAY,IAAI,EAAE,KAAK,EAAE,EAAE;;AAE3B,YAAY,MAAM,EAAE,GAAG,KAAK,CAAC,EAAE,CAAC;AAChC,YAAY,MAAM,UAAU,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9C,YAAY,MAAM,UAAU,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9C,YAAY,MAAM,kBAAkB,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,UAAU,CAAC,KAAK;AAChG,YAAY,MAAM,kBAAkB,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,UAAU,CAAC,KAAK;AAChG,YAAY,MAAM,OAAO,GAAG,kBAAkB,CAAC,MAAM,CAAC,kBAAkB,CAAC;AACzE,YAAY,MAAM,WAAW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC;AAC/G,YAAY,UAAU,CAAC,MAAM,GAAG,WAAW;AAC3C,YAAY,UAAU,CAAC,MAAM,GAAG,WAAW;AAC3C,YAAY,QAAQ,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;;AAE7C,YAAY,MAAM,KAAK,GAAG,MAAM,CAAC,EAAE,CAAC;AACpC,YAAY,MAAM,KAAK,GAAG,MAAM,CAAC,EAAE,CAAC;AACpC,YAAY,MAAM,CAAC,EAAE,CAAC,IAAI,KAAK;;AAE/B,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxC,gBAAgB,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,QAAQ,EAAE;AACxE,gBAAgB,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;AAC7C,gBAAgB,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;AAC7C,gBAAgB,IAAI,KAAK;AACzB,gBAAgB,QAAQ,OAAO;AAC/B,oBAAoB,KAAK,QAAQ;AACjC,wBAAwB,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;AACxD,wBAAwB;AACxB,oBAAoB,KAAK,UAAU;AACnC,wBAAwB,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;AACxD,wBAAwB;AACxB,oBAAoB,KAAK,SAAS;AAClC,wBAAwB,KAAK,GAAG,CAAC,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,KAAK,KAAK,GAAG,KAAK,CAAC;AACnF,wBAAwB;AACxB;AACA,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC;AACzC,gBAAgB,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC,EAAE,KAAK,CAAC;AACzC,YAAY;;AAEZ,YAAY,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,EAAE,QAAQ,CAAC;AACzC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxC,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC;AAC5C,gBAAgB,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC,EAAE,QAAQ,CAAC;AAC5C,YAAY;;AAEZ;AACA,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AACxC,gBAAgB,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,QAAQ,EAAE;AAChD,gBAAgB,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE;AACpE,oBAAoB,IAAI,KAAK,GAAG,CAAC;AACjC,oBAAoB,IAAI,KAAK,GAAG,QAAQ;AACxC,oBAAoB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AAChD,wBAAwB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,QAAQ,EAAE;AACnE,wBAAwB,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAC/C,wBAAwB,IAAI,CAAC,GAAG,KAAK,EAAE;AACvC,4BAA4B,KAAK,GAAG,CAAC;AACrC,4BAA4B,KAAK,GAAG,CAAC;AACrC,wBAAwB;AACxB,oBAAoB;AACpB,oBAAoB,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK;AACpC,gBAAgB,CAAC,MAAM;AACvB,oBAAoB,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;AAC/D,wBAAwB,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE;AACrC,oBAAoB;AACpB,gBAAgB;AAChB,YAAY;;AAEZ,YAAY,IAAI,CAAC,IAAI,GAAG,WAAW;AACnC,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,gBAAgB,CAAC,KAAK,EAAE,IAAI,GAAG,UAAU,EAAE;AAC/C;AACA,QAAQ,MAAM,QAAQ,GAAG,EAAE;AAC3B;AACA,QAAQ,IAAI,QAAQ;AACpB,QAAQ,QAAQ,IAAI;AACpB,YAAY,KAAK,UAAU;AAC3B,gBAAgB,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI;AACxC,gBAAgB;AAChB,YAAY,KAAK,OAAO;AACxB,gBAAgB,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK;AACzC,gBAAgB;AAChB,YAAY;AACZ,gBAAgB,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC;AAC/C;AACA,QAAQ,IAAI,CAAC,SAAS,yBAAyB,IAAI,CAAC,IAAI,GAAG,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC;AACrF,QAAQ,OAAO,QAAQ;AACvB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,YAAY,CAAC,KAAK,EAAE,IAAI,GAAG,UAAU,EAAE;AAC3C;AACA,QAAQ,MAAM,QAAQ,GAAG,EAAE;AAC3B;AACA,QAAQ,IAAI,QAAQ;AACpB,QAAQ,QAAQ,IAAI;AACpB,YAAY,KAAK,UAAU;AAC3B,gBAAgB,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI;AACxC,gBAAgB;AAChB,YAAY,KAAK,OAAO;AACxB,gBAAgB,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK;AACzC,gBAAgB;AAChB,YAAY;AACZ,gBAAgB,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC;AAC/C;AACA,QAAQ,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC;AAC3E,QAAQ,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;AACrE,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,gBAAgB,CAAC,KAAK,EAAE,IAAI,GAAG,UAAU,EAAE;AAC/C,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC;AACvD;AACA,QAAQ,MAAM,IAAI,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC/C,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE;AAClD,YAAY,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC;AACvC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE;AACrD,gBAAgB,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC;AACxC,gBAAgB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;AAC/B,YAAY;AACZ,QAAQ;AACR,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE;AACtC,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,EAAE;AAC9B,YAAY,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;AACtC,QAAQ,CAAC,MAAM;AACf,YAAY,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC;AACtE,YAAY,IAAI,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC;AACxE,QAAQ;AACR,IAAI;AACJ;;AAEA;AACA,MAAM,OAAO,CAAC;AACd;AACA,IAAI,IAAI;AACR;AACA,IAAI,KAAK;AACT;AACA,IAAI,MAAM;;AAEV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE;AACrE,QAAQ,IAAI,CAAC,EAAE,GAAG,EAAE;AACpB,QAAQ,IAAI,CAAC,IAAI,GAAG,IAAI;AACxB,QAAQ,IAAI,CAAC,KAAK,GAAG,KAAK;AAC1B,QAAQ,IAAI,CAAC,IAAI,GAAG,IAAI;AACxB,QAAQ,IAAI,CAAC,KAAK,GAAG,KAAK;AAC1B,QAAQ,IAAI,IAAI,EAAE;AAClB,YAAY,IAAI,CAAC,IAAI,GAAG,IAAI;AAC5B,QAAQ,CAAC,MAAM;AACf,YAAY,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC;AACtG,YAAY,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI;AAC9C,QAAQ;;AAER,QAAQ,IAAI,KAAK,KAAK,SAAS,EAAE;AACjC,YAAY,IAAI,CAAC,KAAK,GAAG,KAAK;AAC9B,QAAQ,CAAC,MAAM;AACf,YAAY,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC;AACvG,YAAY,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;AAC9D,QAAQ;;AAER,QAAQ,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,IAAI,EAAE;AACzD,YAAY,IAAI,CAAC,QAAQ,GAAG,QAAQ;AACpC,QAAQ,CAAC,MAAM;AACf,YAAY,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC;;AAE1G,YAAY,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,mBAAmB,CAAC,IAAI,EAAE,KAAK,CAAC;AACjE,QAAQ;;AAER,QAAQ,IAAI,CAAC,MAAM,GAAG,IAAI;AAC1B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,mBAAmB,CAAC,IAAI,EAAE,KAAK,EAAE;AACrC,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI;AAChC,QAAQ,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI;AACjC,QAAQ,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ;AACxC,QAAQ,MAAM,UAAU,GAAG,KAAK,CAAC,QAAQ;AACzC,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI;AAC9B,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM;AACtC,QAAQ,MAAM,YAAY,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC;AAChD,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,IAAI;AACtF,QAAQ;AACR,QAAQ,OAAO,YAAY;AAC3B,IAAI;;AAEJ,IAAI,IAAI,MAAM,GAAG;AACjB,QAAQ,OAAO,IAAI,CAAC,KAAK,KAAK,CAAC;AAC/B,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,MAAM,GAAG;AACb,QAAQ,IAAI,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC;AACtC,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI;AAC9B,QAAQ,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK;AAChC,QAAQ,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,MAAM;AAC1E,YAAY,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE;AAClE,SAAS;AACT,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,WAAW,GAAG;AAClB,QAAQ,IAAI,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC;AACtC,QAAQ,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE;AACzE,QAAQ,MAAM,iBAAiB,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,GAAG,EAAE;AAC5E,QAAQ,OAAO,gBAAgB,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC;AACxE,IAAI;AACJ;;ACpWA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,WAAW,CAAC;AACzB;AACA;AACA;AACA,IAAI,WAAW,CAAC,QAAQ,GAAG,IAAI,EAAE;AACjC;AACA;AACA;AACA;AACA,QAAQ,IAAI,CAAC,KAAK,GAAG,IAAI,GAAG,EAAE;AAC9B,QAAQ,IAAI,QAAQ,EAAE;AACtB,YAAY,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE;AACtC,gBAAgB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AAChC,YAAY;AACZ,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,QAAQ,CAAC,CAAC,EAAE;AAChB,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK;AAC/B,QAAQ,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;AAC1B,YAAY,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;AACvE,QAAQ;AACR,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,IAAI,CAAC,CAAC,EAAE;AACZ,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK;AAC/B,QAAQ,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACxC,QAAQ,IAAI,YAAY,EAAE;AAC1B,YAAY,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE;AAC3C,gBAAgB,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;AAC5C,gBAAgB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;AACjE,gBAAgB,IAAI,CAAC,UAAU,EAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;AACtE,gBAAgB,YAAY,CAAC,MAAM,GAAG,UAAU;AAChD,gBAAgB,OAAO,YAAY,CAAC,MAAM;AAC1C,YAAY,CAAC,MAAM;AACnB,gBAAgB,OAAO,CAAC;AACxB,YAAY;AACZ,QAAQ,CAAC,MAAM;AACf,YAAY,OAAO,IAAI;AACvB,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE;AAChB,QAAQ,IAAI,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AACjC,QAAQ,IAAI,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;;AAEjC,QAAQ,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC;;AAEpE,QAAQ,IAAI,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC;AACnD,QAAQ,IAAI,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC;;AAEnD,QAAQ,IAAI,CAAC,cAAc,IAAI,CAAC,cAAc,EAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;;AAErF,QAAQ,IAAI,MAAM,KAAK,MAAM,EAAE,OAAO,IAAI;AAC1C,QAAQ,IAAI,cAAc,CAAC,IAAI,GAAG,cAAc,CAAC,IAAI,EAAE;AACvD,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;AAC/C,YAAY,CAAC,cAAc,EAAE,cAAc,CAAC,GAAG,CAAC,cAAc,EAAE,cAAc,CAAC;AAC/E,QAAQ;;AAER,QAAQ,cAAc,CAAC,MAAM,GAAG,MAAM;AACtC;AACA,QAAQ,cAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,cAAc,CAAC,QAAQ,CAAC,GAAG,EAAE,cAAc,CAAC,QAAQ,CAAC;AAC7F,QAAQ,cAAc,CAAC,IAAI,IAAI,cAAc,CAAC,IAAI;;AAElD,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA,IAAI,YAAY,CAAC,CAAC,EAAE;AACpB,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;AACtC,QAAQ,IAAI,IAAI,EAAE;AAClB,YAAY,OAAO,IAAI,CAAC,QAAQ;AAChC,QAAQ,CAAC,MAAM;AACf,YAAY,OAAO,IAAI;AACvB,QAAQ;AACR,IAAI;AACJ;;ACzGA;;AAEA;AACA;AACA;AACA;AACA;AACO,MAAM,IAAI,CAAC;AAClB;AACA,IAAI,UAAU;;AAEd;AACA,IAAI,WAAW;;AAEf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,QAAQ,GAAG,IAAI,EAAE,QAAQ,EAAE,UAAU,GAAG,KAAK,EAAE;AAC/D;AACA,QAAQ,IAAI,CAAC,SAAS,GAAG,QAAQ;AACjC,QAAQ,IAAI,CAAC,UAAU,GAAG,EAAE;AAC5B,QAAQ,IAAI,UAAU,KAAK,KAAK,EAAE;AAClC,YAAY,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC;AAC9C,QAAQ,CAAC,MAAM,IAAI,UAAU,KAAK,KAAK,EAAE;AACzC,YAAY,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC;AAC9C,QAAQ,CAAC,MAAM;AACf,YAAY,IAAI,CAAC,WAAW,GAAG,UAAU;AACzC,QAAQ;AACR,QAAQ,IAAI,QAAQ,EAAE;AACtB,YAAY,IAAI,CAAC,UAAU,GAAG,EAAE;AAChC,YAAY,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE;AACtC,gBAAgB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;AACrC,oBAAoB,OAAO,EAAE,CAAC;AAC9B,oBAAoB,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC;AACtC,iBAAiB,CAAC;AAClB,YAAY;AACZ,YAAY,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE;AAC3E,gBAAgB,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;AACrC,YAAY;AACZ,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,OAAO,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,GAAG,KAAK,EAAE;AAC3D,QAAQ,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,CAAC;AACzD,QAAQ,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU;AACzC,QAAQ,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE;AAClC,YAAY,SAAS,CAAC,IAAI,CAAC;AAC3B,gBAAgB,OAAO,EAAE,CAAC;AAC1B,gBAAgB,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC;AAClC,aAAa,CAAC;AACd,QAAQ;AACR,QAAQ,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE;AACvE,YAAY,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;AACjC,QAAQ;AACR,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE;AAC5B,QAAQ,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU;AACzC,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC;AAC3F,QAAQ;AACR,IAAI;;AAEJ;AACA,IAAI,WAAW,GAAG;AAClB,QAAQ,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU;AACzC,QAAQ,IAAI,KAAK,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC;AACxC,QAAQ,OAAO,KAAK,GAAG,CAAC,EAAE;AAC1B,YAAY,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,CAAC;AAC3D,YAAY,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,EAAE;AACzF,gBAAgB;AAChB,YAAY,CAAC,MAAM;AACnB,gBAAgB,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC;AAC9C,gBAAgB,KAAK,GAAG,WAAW;AACnC,YAAY;AACZ,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,CAAC,OAAO,EAAE;AAClB,QAAQ,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;AAC7C;AACA,QAAQ,MAAM,IAAI,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE;AACvD,QAAQ,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;AAClC,QAAQ,IAAI,CAAC,WAAW,EAAE;AAC1B,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,aAAa,CAAC,WAAW,GAAG,CAAC,EAAE;AACnC,QAAQ,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU;AACzC,QAAQ,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW;AAC3C,QAAQ,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM;AACvC,QAAQ,MAAM,IAAI,GAAG,CAAC,GAAG,WAAW,GAAG,CAAC;AACxC,QAAQ,MAAM,KAAK,GAAG,CAAC,GAAG,WAAW,GAAG,CAAC;AACzC,QAAQ,IAAI,KAAK,GAAG,WAAW;AAC/B,QAAQ,IAAI,KAAK,IAAI,MAAM,EAAE,MAAM,0BAA0B;AAC7D,QAAQ,IAAI,IAAI,GAAG,MAAM,IAAI,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE;AACxF,YAAY,KAAK,GAAG,IAAI;AACxB,QAAQ;AACR,QAAQ,IAAI,KAAK,GAAG,MAAM,IAAI,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE;AAC1F,YAAY,KAAK,GAAG,KAAK;AACzB,QAAQ;AACR,QAAQ,IAAI,KAAK,KAAK,WAAW,EAAE;AACnC,YAAY,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC;AAC1C,YAAY,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC;AACrC,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,GAAG,GAAG;AACV,QAAQ,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU;AACzC,QAAQ,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE;AACpC,YAAY,OAAO,IAAI;AACvB,QAAQ,CAAC,MAAM,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE;AAC3C,YAAY,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,EAAE;AACxC,YAAY,IAAI,CAAC,IAAI,EAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC;AACxD,YAAY,OAAO,IAAI;AACvB,QAAQ;AACR,QAAQ,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;AAC3C,QAAQ,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,EAAE;AACpC,QAAQ,IAAI,CAAC,aAAa,EAAE;AAC5B,QAAQ,OAAO,IAAI,IAAI,IAAI;AAC3B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,KAAK,GAAG;AAChB,QAAQ,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI;AACrE,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,CAAC,OAAO,GAAG;AACf,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAChE,YAAY,MAAM,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO;AAC5C,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,GAAG;AACd,QAAQ,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC;AAClH,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,GAAG;AACX,QAAQ,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC;AACpD,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,QAAQ,GAAG;AACf,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,MAAM,GAAG;AACjB,QAAQ,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM;AACrC,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,KAAK,GAAG;AAChB,QAAQ,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC;AAChC,IAAI;AACJ;;AC/NA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,MAAM,SAAS,UAAU,CAAC;AACvC;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,EAAE,EAAE;AACzC,QAAQ,KAAK;AACb,YAAY,MAAM;AAClB,6CAA6C,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,UAAU,CAAC;AAC/G,SAAS;;AAET,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC;AACpC,QAAQ,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI;;AAEpC;AACA,QAAQ,IAAI,MAAM,YAAY,MAAM,EAAE;AACtC,YAAY,IAAI,CAAC,OAAO,GAAG,MAAM;AACjC,QAAQ,CAAC,MAAM;AACf,YAAY,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;AAC9C,QAAQ;;AAER,QAAQ,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK;AACzC,QAAQ,IAAI,CAAC,EAAE,GAAG,CAAC;AACnB,QAAQ,IAAI,CAAC,EAAE,GAAG,CAAC;;AAEnB,QAAQ,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC;AAC/B,QAAQ,IAAI,CAAC,WAAW,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC;;AAE/C;AACA,QAAQ,IAAI,CAAC,SAAS,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;;AAE7C,QAAQ,IAAI,CAAC,kBAAkB,GAAG,UAAU,CAAC;AAC7C,cAAc,UAAU,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,YAAY,CAAC,CAAC,CAAC;AACzE,cAAc,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,EAAE,CAAC;AACjD,QAAQ,IAAI,iBAAiB,GAAG,IAAI,CAAC,kBAAkB;AACvD,QAAQ,IAAI,UAAU,GAAG,CAAC;AAC1B,QAAQ,MAAM,cAAc,GAAG,GAAG;AAClC,QAAQ,IAAI,gBAAgB,GAAG,IAAI;;AAEnC,QAAQ,OAAO,gBAAgB,IAAI,UAAU,GAAG,cAAc,EAAE;AAChE,YAAY,MAAM,gBAAgB,GAAG,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC;AACvE,YAAY,iBAAiB,GAAG,gBAAgB,CAAC,iBAAiB;AAClE,YAAY,gBAAgB,GAAG,gBAAgB,CAAC,gBAAgB;AAChE,YAAY,UAAU,EAAE;AACxB,QAAQ;;AAER,QAAQ,IAAI,CAAC,kBAAkB,GAAG,iBAAiB;AACnD,IAAI;;AAEJ;AACA,IAAI,IAAI,CAAC,GAAG;AACZ,QAAQ,OAAO,IAAI,CAAC,EAAE;AACtB,IAAI;;AAEJ;AACA,IAAI,IAAI,SAAS,GAAG;AACpB,QAAQ,OAAO,IAAI,CAAC,kBAAkB;AACtC,IAAI;;AAEJ;AACA,IAAI,gBAAgB,GAAG;AACvB,QAAQ,OAAO,IAAI,CAAC,SAAS;AAC7B,IAAI;;AAEJ;AACA,IAAI,YAAY,GAAG;AACnB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS;AACvC;AACA,QAAQ,MAAM,MAAM,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;AACzD,QAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK;AACnC,YAAY,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;AACjC,gBAAgB,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACjC,YAAY;AACZ,QAAQ,CAAC,CAAC;AACV,QAAQ,OAAO,MAAM;AACrB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,eAAe,CAAC,aAAa,EAAE,UAAU,EAAE;AAC/C,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO;AAC9B,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM;;AAE9C,QAAQ,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE;AACnE,YAAY,OAAO,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;AACrC,QAAQ;;AAER,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO;AAC9B,YAAY,UAAU;AACtB,YAAY,CAAC,CAAC,KAAK;AACnB,gBAAgB,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACnC,gBAAgB,IAAI,GAAG,GAAG,CAAC;AAC3B,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE;AAC/D,oBAAoB,GAAG,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9D,gBAAgB;AAChB,gBAAgB,OAAO,GAAG;AAC1B,YAAY,CAAC;AACb,YAAY,KAAK;AACjB,SAAS;;AAET,QAAQ,MAAM,QAAQ,GAAG,CAAC,CAAC,GAAG,EAAE;AAChC,QAAQ,IAAI,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;;AAE5D,QAAQ,OAAO,QAAQ,CAAC,OAAO;AAC/B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,qBAAqB,CAAC,CAAC,EAAE;AAC7B,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW;AAC3C,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO;AAC9B;AACA,QAAQ,MAAM,iBAAiB,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC;AAC9C,QAAQ,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;;AAE1C;AACA,QAAQ,MAAM,YAAY,GAAG,UAAU,CAAC,UAAU,GAAG,CAAC;AACtD,QAAQ,iBAAiB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC;AAClD,QAAQ,MAAM,WAAW,GAAG,CAAC,YAAY,CAAC;;AAE1C,QAAQ,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;;AAEhE,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC7E,YAAY,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE;;AAExC,YAAY,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;AAChG,YAAY,MAAM,cAAc,GAAG,IAAI,CAAC,eAAe,CAAC,WAAW,EAAE,MAAM,CAAC;;AAE5E,YAAY,WAAW,CAAC,IAAI,CAAC,cAAc,CAAC;AAC5C,YAAY,iBAAiB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC;AACxD,QAAQ;;AAER,QAAQ,OAAO,iBAAiB;AAChC,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,UAAU,CAAC,iBAAiB,EAAE;AAClC,QAAQ,MAAM,CAAC,GAAG,iBAAiB,CAAC,MAAM;AAC1C,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM;AAC9C,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO;AAC9B,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS;AACvC,QAAQ,IAAI,gBAAgB,GAAG,KAAK;;AAEpC;AACA,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAC/B,YAAY,IAAI,QAAQ,GAAG,QAAQ;AACnC,YAAY,IAAI,WAAW,GAAG,CAAC;;AAE/B,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxC,gBAAgB,MAAM,CAAC,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AAC1D,gBAAgB,IAAI,CAAC,GAAG,QAAQ,EAAE;AAClC,oBAAoB,QAAQ,GAAG,CAAC;AAChC,oBAAoB,WAAW,GAAG,CAAC;AACnC,gBAAgB;AAChB,YAAY;;AAEZ,YAAY,IAAI,QAAQ,CAAC,CAAC,CAAC,KAAK,WAAW,EAAE;AAC7C,gBAAgB,gBAAgB,GAAG,IAAI;AACvC,gBAAgB,QAAQ,CAAC,CAAC,CAAC,GAAG,WAAW;AACzC,YAAY;AACZ,QAAQ;;AAER;AACA,QAAQ,MAAM,aAAa,GAAG,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;;AAEvD,QAAQ,OAAO;AACf,YAAY,gBAAgB,EAAE,gBAAgB;AAC9C,YAAY,iBAAiB,EAAE,aAAa;AAC5C,SAAS;AACT,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,iBAAiB,CAAC,CAAC,EAAE;AACzB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO;AAC9B,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS;;AAEvC;AACA;AACA,QAAQ,MAAM,aAAa,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC;AAC1C,QAAQ,MAAM,eAAe,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;;AAEpD,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC;AAClD,QAAQ;;AAER;AACA,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAC/B,YAAY,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC;AAClC,YAAY,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE;AACnC,gBAAgB,eAAe,CAAC,EAAE,CAAC,EAAE;AACrC,gBAAgB,MAAM,QAAQ,GAAG,aAAa,CAAC,EAAE,CAAC;AAClD,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAC5C,oBAAoB,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;AACxC,gBAAgB;AAChB,YAAY;AACZ,QAAQ;;AAER;AACA,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC;AACxC,YAAY,IAAI,CAAC,GAAG,CAAC,EAAE;AACvB,gBAAgB,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC,CAAC;AACjD,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAC5C,oBAAoB,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;AACpC,gBAAgB;AAChB,YAAY;AACZ,QAAQ;;AAER,QAAQ,OAAO,aAAa;AAC5B,IAAI;AACJ;;AChQA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,QAAQ,SAAS,UAAU,CAAC;AACzC;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,EAAE,EAAE;AACzC,QAAQ,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,UAAU,CAAC,CAAC;AACzG,QAAQ,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE;AAC1C,QAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC;AAClC,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AACxE,QAAQ,IAAI,CAAC,gBAAgB,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC;;AAEzD,QAAQ,IAAI,CAAC,GAAG,CAAC,EAAE;AACnB,YAAY,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;AACtC,QAAQ;AACR,QAAQ,IAAI,CAAC,WAAW,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;AAChE,QAAQ,IAAI,CAAC,SAAS,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;AAC9C,QAAQ,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC;AAC3D,QAAQ,IAAI,CAAC,eAAe,GAAG,KAAK;AACpC,IAAI;;AAEJ;AACA,IAAI,gBAAgB,GAAG;AACvB,QAAQ,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE;AACnC,YAAY,IAAI,CAAC,YAAY,EAAE;AAC/B,QAAQ;AACR,QAAQ,OAAO,IAAI,CAAC,SAAS;AAC7B,IAAI;;AAEJ;AACA,IAAI,YAAY,GAAG;AACnB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC;AACpC,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE;AACnC,YAAY,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,gBAAgB,CAAC;AAC/C,QAAQ;AACR;AACA,QAAQ,MAAM,MAAM,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;AACzD,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AACpC,YAAY,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AACzD,YAAY,MAAM,WAAW,GAAG,OAAO,CAAC,aAAa;AACrD,YAAY,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACvC,YAAY,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,WAAW;AAC3C,QAAQ;AACR,QAAQ,OAAO,MAAM;AACrB,IAAI;;AAEJ;AACA,IAAI,IAAI,CAAC,GAAG;AACZ,QAAQ,OAAO,IAAI,CAAC,WAAW,CAAC,CAAC;AACjC,IAAI;;AAEJ;AACA,IAAI,IAAI,OAAO,GAAG;AAClB,QAAQ,OAAO,IAAI,CAAC,WAAW,EAAE;AACjC,IAAI;;AAEJ;AACA,IAAI,WAAW,GAAG;AAClB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC;AACpC,QAAQ,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE;AACnC,YAAY,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,gBAAgB,CAAC;AAC/C,QAAQ;AACR,QAAQ,OAAO,IAAI,CAAC,gBAAgB;AACpC,IAAI;;AAEJ,IAAI,OAAO,SAAS,GAAG;AACvB,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS;AACvC,QAAQ,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE;AACnC,YAAY,IAAI,CAAC,YAAY,EAAE;AAC/B,QAAQ;AACR,QAAQ,MAAM,IAAI,CAAC,YAAY,EAAE;AACjC,QAAQ,IAAI,CAAC,GAAG,CAAC;AACjB,QAAQ,OAAO,CAAC,GAAG,QAAQ,EAAE;AAC7B,YAAY,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE;AAC5C,YAAY,IAAI,CAAC,gBAAgB,EAAE;AACnC,YAAY,MAAM,IAAI,CAAC,YAAY,EAAE;AACrC,YAAY,IAAI,MAAM,EAAE;AACxB,YAAY,CAAC,EAAE;AACf,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,IAAI,UAAU,GAAG;AACjB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC;AACpC,QAAQ,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB;AAC7C,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;;AAEzB;AACA,QAAQ,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC;AAClC,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AACpC,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AACpD,QAAQ;;AAER,QAAQ,IAAI,UAAU,GAAG,CAAC;AAC1B,QAAQ,IAAI,SAAS,GAAG,IAAI,CAAC;;AAE7B;AACA,QAAQ,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC;AAC3C,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AACpC,YAAY,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;;AAEnC,YAAY,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;AAC5B,YAAY,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,gBAAgB;;AAEjD;AACA,YAAY,MAAM,OAAO,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC;;AAEnD,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AACxC,gBAAgB,IAAI,CAAC,KAAK,CAAC,EAAE;AAC7B,gBAAgB,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;AACpE,gBAAgB,MAAM,EAAE,aAAa,EAAE,CAAC,EAAE,gBAAgB,EAAE,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC;;AAElG;AACA,gBAAgB,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,GAAG,GAAG;;AAE3D;AACA,gBAAgB,IAAI,QAAQ,GAAG,GAAG,EAAE;AACpC,oBAAoB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AAChD,wBAAwB,IAAI,CAAC,KAAK,CAAC,EAAE;AACrC,4BAA4B,OAAO,CAAC,CAAC,CAAC,IAAI,QAAQ,GAAG,GAAG;AACxD,wBAAwB;AACxB,oBAAoB;AACpB,gBAAgB;AAChB,YAAY;;AAEZ;AACA,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AACxC,gBAAgB,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG,UAAU,EAAE;AAC7C,oBAAoB,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC;AAC3C,oBAAoB,SAAS,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;AACtD,gBAAgB;AAChB,YAAY;AACZ,QAAQ;;AAER,QAAQ,IAAI,SAAS,IAAI,UAAU,GAAG,CAAC,EAAE;AACzC,YAAY,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC,KAAK;AACtD,YAAY,IAAI,CAAC,gBAAgB,GAAG,OAAO;AAC3C,YAAY,OAAO,KAAK,CAAC;AACzB,QAAQ;;AAER,QAAQ,OAAO,IAAI,CAAC;AACpB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,GAAG,GAAG,IAAI,EAAE;AAChD,QAAQ,IAAI,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;AAC7B,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,gBAAgB;AACvC,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM;AAC9C,QAAQ,IAAI,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAChC,QAAQ,IAAI,IAAI,KAAK,CAAC,EAAE;AACxB,YAAY,IAAI,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC;AACnC,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC;AACnC,QAAQ;AACR,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,eAAe,CAAC,GAAG,EAAE,CAAC,EAAE;AAC5B,QAAQ,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB;AAC7C,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE;AAClC,YAAY,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC;AAC3E,QAAQ;;AAER,QAAQ,IAAI,GAAG,GAAG,QAAQ;AAC1B,QAAQ,IAAI,CAAC,GAAG,EAAE;AAClB,QAAQ,IAAI,GAAG,GAAG,QAAQ;AAC1B,QAAQ,IAAI,CAAC,GAAG,EAAE;;AAElB,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AACjD,YAAY,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;AAChC,YAAY,MAAM,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AACzD,YAAY,IAAI,CAAC,GAAG,GAAG,EAAE;AACzB,gBAAgB,GAAG,GAAG,GAAG;AACzB,gBAAgB,CAAC,GAAG,CAAC;AACrB,gBAAgB,GAAG,GAAG,CAAC;AACvB,gBAAgB,CAAC,GAAG,CAAC;AACrB,YAAY,CAAC,MAAM,IAAI,CAAC,GAAG,GAAG,EAAE;AAChC,gBAAgB,GAAG,GAAG,CAAC;AACvB,gBAAgB,CAAC,GAAG,CAAC;AACrB,YAAY;AACZ,QAAQ;;AAER,QAAQ,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC;;AAE3B,QAAQ,OAAO;AACf,YAAY,gBAAgB,EAAE,GAAG;AACjC,YAAY,aAAa,EAAE,CAAC;AAC5B,YAAY,eAAe,EAAE,GAAG;AAChC,YAAY,YAAY,EAAE,CAAC;AAC3B,SAAS;AACT,IAAI;;AAEJ,IAAI,gBAAgB,GAAG;AACvB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AACpC,YAAY,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AACzD,YAAY,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,aAAa;AACrD,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,CAAC,CAAC,EAAE,eAAe,EAAE;AAC7B,QAAQ,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC;AACtC,QAAQ,IAAI,CAAC,eAAe,EAAE,eAAe,GAAG,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC;AAC3E,QAAQ,IAAI,CAAC,gBAAgB,GAAG,eAAe;AAC/C,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS;AACvC,QAAQ,IAAI,MAAM,GAAG,KAAK;AAC1B,QAAQ,IAAI,CAAC,GAAG,CAAC;AACjB,QAAQ,GAAG;AACX,YAAY,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE;AACtC,QAAQ,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC,GAAG,QAAQ;AAC1C,QAAQ,IAAI,CAAC,gBAAgB,EAAE;AAC/B,QAAQ,IAAI,CAAC,eAAe,GAAG,IAAI;AACnC,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,mBAAmB,CAAC,CAAC,EAAE;AAC3B,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;AAC1C,QAAQ,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW;AAC3C,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;;AAE3D;AACA,QAAQ,IAAI,CAAC,IAAI,CAAC,EAAE;AACpB,YAAY,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACtC,QAAQ;;AAER;AACA,QAAQ,MAAM,OAAO,GAAG,EAAE;;AAE1B;AACA,QAAQ,IAAI,MAAM,GAAG,EAAE;AACvB,QAAQ,IAAI,MAAM,GAAG,QAAQ;AAC7B,QAAQ,IAAI,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;AAC7C,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE;AAC3C,YAAY,IAAI,EAAE,GAAG,CAAC;AACtB,YAAY,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;AAC5B,YAAY,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC;AAC9B,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE;AAC/C,gBAAgB,IAAI,CAAC,KAAK,CAAC,EAAE;AAC7B,gBAAgB,EAAE,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjE,YAAY;AACZ,YAAY,IAAI,EAAE,GAAG,MAAM,EAAE;AAC7B,gBAAgB,MAAM,GAAG,EAAE;AAC3B,gBAAgB,MAAM,GAAG,GAAG;AAC5B,YAAY;AACZ,QAAQ;AACR,QAAQ,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;;AAE5B;AACA,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,IAAI,QAAQ,GAAG,EAAE;AAC7B,YAAY,IAAI,UAAU,GAAG,QAAQ;;AAErC,YAAY,MAAM,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AACpF,YAAY,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE;;AAE/C,YAAY,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,gBAAgB,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;AACzF,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE;AAC/C,gBAAgB,IAAI,OAAO,GAAG,CAAC;AAC/B,gBAAgB,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;AAChC,gBAAgB,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC;;AAElC;AACA,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE;AACnD,oBAAoB,IAAI,CAAC,KAAK,CAAC,EAAE;AACjC,oBAAoB,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;AACpC,oBAAoB,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC;;AAEtC;AACA,oBAAoB,IAAI,cAAc,GAAG,QAAQ;AACjD,oBAAoB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AAC7D,wBAAwB,MAAM,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AACzF,wBAAwB,IAAI,CAAC,GAAG,cAAc,EAAE,cAAc,GAAG,CAAC;AAClE,oBAAoB;;AAEpB,oBAAoB,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,cAAc;AACzF,oBAAoB,IAAI,KAAK,GAAG,CAAC,EAAE;AACnC,wBAAwB,OAAO,IAAI,KAAK;AACxC,oBAAoB;AACpB,gBAAgB;;AAEhB,gBAAgB,IAAI,OAAO,GAAG,UAAU,EAAE;AAC1C,oBAAoB,UAAU,GAAG,OAAO;AACxC,oBAAoB,QAAQ,GAAG,GAAG;AAClC,gBAAgB;AAChB,YAAY;AACZ,YAAY,IAAI,QAAQ,KAAK,EAAE,EAAE;AACjC,gBAAgB,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC;AACtC,YAAY;AACZ,QAAQ;AACR,QAAQ,OAAO,OAAO;AACtB,IAAI;AACJ;;AC3YA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,SAAS,SAAS,UAAU,CAAC;AAC1C;AACA,IAAI,UAAU;AACd;AACA,IAAI,SAAS;AACb;AACA,IAAI,UAAU;AACd;AACA,IAAI,OAAO;AACX;AACA,IAAI,OAAO;AACX;AACA,IAAI,SAAS;AACb;AACA,IAAI,aAAa;AACjB;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,EAAE,EAAE;AACzC,QAAQ,KAAK;AACb,YAAY,MAAM;AAClB;AACA,gBAAgB,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,UAAU;AAC7G;AACA,SAAS;;AAET;AACA,QAAQ,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC,SAAS,IAAI,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC;AACvF,QAAQ,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,QAAQ,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;AAClG,QAAQ,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC,SAAS,IAAI,IAAI;AACtD,QAAQ,MAAM,YAAY,GAAG,UAAU,CAAC,MAAM,IAAI,UAAU;AAC5D;AACA,QAAQ,IAAI,OAAO,YAAY,KAAK,QAAQ,EAAE;AAC9C,YAAY,IAAI,YAAY,KAAK,MAAM,EAAE;AACzC,gBAAgB,IAAI,CAAC,OAAO,GAAG,CAAC,IAAI,MAAM,IAAI,IAAI,IAAI,CAAC,UAAU,GAAG,CAAC,GAAG,CAAC,CAAC;AAC1E,YAAY,CAAC,MAAM;AACnB;AACA,gBAAgB,IAAI,CAAC,OAAO,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;AAC3G,YAAY;AACZ,QAAQ,CAAC,MAAM;AACf;AACA,YAAY,IAAI,CAAC,OAAO,GAAG,YAAY;AACvC,QAAQ;;AAER;AACA,QAAQ,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE;;AAE3C,QAAQ,IAAI,CAAC,WAAW,EAAE;AAC1B,QAAQ,IAAI,CAAC,gBAAgB,EAAE;AAC/B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,kBAAkB,CAAC,MAAM,EAAE;AAC/B,QAAQ,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AACjC;AACA;AACA,QAAQ,IAAI,SAAS,GAAG,CAAC;AACzB,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;AACvC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAC5C,gBAAgB,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;AAC3C,gBAAgB,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC;AAClE,gBAAgB,SAAS,IAAI,IAAI;AACjC,YAAY;AACZ,QAAQ;AACR,QAAQ,MAAM,OAAO,GAAG,SAAS,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;AACvD;AACA,QAAQ,OAAO,OAAO,GAAG,CAAC;AAC1B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,cAAc,CAAC,IAAI,EAAE;AACzB,QAAQ,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;AACjC,IAAI;;AAEJ;AACA,IAAI,WAAW,GAAG;AAClB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO;AACnC,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM;AAC9C;AACA,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;AACrD,QAAQ,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU;;AAEzC,QAAQ,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE;AAC1D,YAAY,IAAI,SAAS,GAAG,CAAC;AAC7B;AACA,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxC,gBAAgB,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;AAC3C,gBAAgB,IAAI,WAAW,GAAG,CAAC;AACnC,gBAAgB,MAAM,YAAY,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC;AACxD,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAC5C,oBAAoB,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;AAC/C,oBAAoB,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC;AACrD,oBAAoB,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC;AAC/C,oBAAoB,WAAW,IAAI,MAAM;AACzC,oBAAoB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAChD,wBAAwB,YAAY,CAAC,CAAC,CAAC,IAAI,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC;AAC5D,oBAAoB;AACpB,gBAAgB;AAChB,gBAAgB,IAAI,WAAW,KAAK,CAAC,EAAE;AACvC;AACA;AACA;AACA,oBAAoB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;AACjG,oBAAoB,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC;AAC/D,gBAAgB,CAAC,MAAM;AACvB,oBAAoB,MAAM,KAAK,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC;AACrD,oBAAoB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAChD,wBAAwB,KAAK,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,WAAW,GAAG,KAAK,CAAC,CAAC,CAAC;AAC3E,oBAAoB;AACpB,oBAAoB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;AAC1F,oBAAoB,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC;AAC/D;AACA,oBAAoB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAChD,wBAAwB,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC;AAC5C,oBAAoB;AACpB,gBAAgB;AAChB,YAAY;AACZ,YAAY,IAAI,SAAS,GAAG,SAAS,EAAE;AACvC;AACA,gBAAgB;AAChB,YAAY;AACZ,QAAQ;AACR,IAAI;;AAEJ;AACA,IAAI,gBAAgB,GAAG;AACvB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM;AAC9C,QAAQ,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU;;AAEzC;AACA;AACA,QAAQ,MAAM,cAAc,GAAG,SAAS,GAAG,GAAG;AAC9C;AACA,QAAQ,MAAM,KAAK,GAAG,EAAE,CAAC;AACzB,QAAQ,MAAM,aAAa,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;;AAEnD,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,IAAI,aAAa,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,SAAS;;AAElD,YAAY,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;AAC7C,YAAY,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC;AAC5B,YAAY,aAAa,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM;;AAE3C;AACA,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAC5C,gBAAgB,IAAI,aAAa,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE;;AAE7C,gBAAgB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;AACjD,gBAAgB,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC;;AAEjD,gBAAgB,IAAI,IAAI,GAAG,cAAc,EAAE;AAC3C,oBAAoB,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,oBAAoB,aAAa,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM;AACnD,gBAAgB;AAChB,YAAY;;AAEZ,YAAY,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;AAC5B,QAAQ;;AAER;AACA;AACA,QAAQ,MAAM,QAAQ,GAAG,EAAE;AAC3B,QAAQ,MAAM,WAAW,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;;AAEjD,QAAQ,KAAK,IAAI,QAAQ,GAAG,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE;AACpE,YAAY,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC;AACxC,YAAY,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AACpC,YAAY,KAAK,MAAM,SAAS,IAAI,IAAI,EAAE;AAC1C,gBAAgB,WAAW,CAAC,SAAS,CAAC,GAAG,QAAQ;AACjD,YAAY;AACZ,QAAQ;;AAER,QAAQ,IAAI,CAAC,SAAS,GAAG,WAAW;AACpC,QAAQ,IAAI,CAAC,aAAa,GAAG,QAAQ;AACrC,IAAI;;AAEJ;AACA;AACA;AACA,IAAI,YAAY,GAAG;AACnB;AACA,QAAQ,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;AACjC,YAAY,IAAI,CAAC,WAAW,EAAE;AAC9B,YAAY,IAAI,CAAC,gBAAgB,EAAE;AACnC,QAAQ;AACR,QAAQ,kCAAkC,IAAI,CAAC,aAAa;AAC5D,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,gBAAgB,GAAG;AACvB,QAAQ,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;AAC7B,YAAY,IAAI,CAAC,WAAW,EAAE;AAC9B,YAAY,IAAI,CAAC,gBAAgB,EAAE;AACnC,QAAQ;AACR,QAAQ,gCAAgC,IAAI,CAAC,SAAS;AACtD,IAAI;AACJ;;AClOA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,MAAM,SAAS,UAAU,CAAC;AACvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,EAAE,EAAE;AACzC,QAAQ,KAAK;AACb,YAAY,MAAM;AAClB;AACA,gBAAgB,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,UAAU;AAC1F;AACA,SAAS;AACT,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO;AACnC;AACA;AACA;AACA;AACA,QAAQ,IAAI,CAAC,aAAa,GAAG,EAAE;AAC/B,QAAQ,MAAM,YAAY,GAAG,IAAI,CAAC,aAAa;AAC/C;AACA,QAAQ,IAAI,CAAC,SAAS,GAAG,EAAE;AAC3B,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS;;AAEvC,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;;AAEzB;AACA;AACA;AACA;AACA,QAAQ,IAAI,CAAC,GAAG,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK;AACtD,YAAY,OAAO;AACnB,gBAAgB,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;AACtC,gBAAgB,KAAK,EAAE,CAAC;AACxB,gBAAgB,qBAAqB,EAAE,SAAS;AAChD,gBAAgB,SAAS,EAAE,KAAK;AAChC,aAAa;AACb,QAAQ,CAAC,CAAC;AACV,QAAQ,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG;;AAE3B,QAAQ,IAAI,CAAC,cAAc,GAAG,CAAC;AAC/B,QAAQ,IAAI,aAAa,GAAG,IAAI,CAAC,cAAc;;AAE/C,QAAQ,KAAK,MAAM,CAAC,IAAI,EAAE,EAAE;AAC5B,YAAY,IAAI,CAAC,CAAC,SAAS,EAAE;AAC7B,YAAY,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;AAChD,YAAY,CAAC,CAAC,SAAS,GAAG,IAAI;AAC9B,YAAY,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;AACpC,YAAY,aAAa,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC;AAC/C,YAAY,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,YAAY,IAAI,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE;AACtD,gBAAgB,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,qBAAqB,EAAE,KAAK,CAAC;AACnF,gBAAgB,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,KAAK,CAAC;AACtC,gBAAgB,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAC;AACpE,YAAY;AACZ,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,cAAc,CAAC,CAAC,EAAE;AACtB,QAAQ,IAAI,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,SAAS;AAC5C,QAAQ,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG;AAC3B,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM;AAC9C,QAAQ,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO;AAChD,QAAQ,MAAM,SAAS,GAAG,EAAE;AAC5B,QAAQ,KAAK,MAAM,CAAC,IAAI,EAAE,EAAE;AAC5B,YAAY,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,EAAE;AACrC,YAAY,IAAI,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,OAAO,EAAE;AACzD,gBAAgB,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AACjC,YAAY;AACZ,QAAQ;AACR,QAAQ,OAAO,SAAS;AACxB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,cAAc,CAAC,CAAC,EAAE;AACtB,QAAQ,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU;AACtD,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM;AAC9C;AACA,QAAQ,IAAI,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,UAAU,GAAG,CAAC,EAAE;AACjE,YAAY,OAAO,SAAS;AAC5B,QAAQ;AACR;AACA,QAAQ,MAAM,eAAe,GAAG,CAAC,CAAC,SAAS,CAAC,QAAQ;AACpD,YAAY,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC;AACjF,SAAS;AACT;AACA,QAAQ,OAAO,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,eAAe,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC;AACzE,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE;AACtB,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM;AAC9C,QAAQ,MAAM,aAAa,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;AACpD;AACA,QAAQ,IAAI,aAAa,KAAK,SAAS,EAAE;AACzC,YAAY;AACZ,QAAQ;AACR,QAAQ,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AACjD,QAAQ,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE;AACnC,YAAY,IAAI,CAAC,CAAC,SAAS,EAAE;AAC7B,YAAY,MAAM,yBAAyB,GAAG,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;AACnG;AACA,YAAY,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE;AACxE,gBAAgB,CAAC,CAAC,qBAAqB,GAAG,yBAAyB;AACnE,gBAAgB,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;AAC7B,YAAY,CAAC,MAAM;AACnB;AACA,gBAAgB,IAAI,yBAAyB,IAAI,CAAC,CAAC,qBAAqB,IAAI,QAAQ,CAAC,EAAE;AACvF,oBAAoB,CAAC,CAAC,qBAAqB,GAAG,yBAAyB;AACvE,oBAAoB,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,qBAAqB,IAAI,QAAQ,EAAE,KAAK,CAAC,CAAC;AAC1G,gBAAgB;AAChB,YAAY;AACZ,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE;AACpC,QAAQ,MAAM,YAAY,GAAG,IAAI,CAAC,aAAa;AAC/C,QAAQ,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE;AAC7B,YAAY,MAAM,CAAC,qDAAqD,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,OAAO;AAC7F,YAAY,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;AAChD,YAAY,CAAC,CAAC,SAAS,GAAG,IAAI;AAC9B,YAAY,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;AACjC,YAAY,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,YAAY,IAAI,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE;AACtD,gBAAgB,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,KAAK,CAAC;AACtC;AACA,YAAY;AACZ,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,YAAY,GAAG;AACnB,QAAQ,MAAM,QAAQ,GAAG,EAAE;AAC3B,QAAQ,MAAM,QAAQ,GAAG,EAAE;AAC3B,QAAQ,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU;AACtD,QAAQ,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,SAAS,EAAE;AAC9C,YAAY,IAAI,OAAO,CAAC,MAAM,GAAG,UAAU,EAAE;AAC7C,gBAAgB,QAAQ,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;AACzC,YAAY,CAAC,MAAM;AACnB,gBAAgB,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC;AACtC,YAAY;AACZ,QAAQ;AACR,QAAQ,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC;AAC/B,QAAQ,OAAO,QAAQ;AACvB,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,gBAAgB,GAAG;AACvB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;AACvC;AACA,QAAQ,MAAM,MAAM,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3C,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,EAAE;AAC5C,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACzD,YAAY,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC;AACvC,YAAY,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE;AACzC,gBAAgB,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE;AAClD,YAAY;AACZ,QAAQ;AACR,QAAQ,OAAO,MAAM;AACrB,IAAI;AACJ;;ACrNA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,MAAM,SAAS,UAAU,CAAC;AACvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,EAAE,EAAE;AACzC,QAAQ,MAAM,QAAQ,GAAG;AACzB,YAAY,KAAK,EAAE,EAAE;AACrB,YAAY,KAAK,EAAE,CAAC;AACpB,YAAY,MAAM,EAAE,SAAS;AAC7B,YAAY,IAAI,EAAE,IAAI;AACtB,YAAY,gBAAgB,EAAE,EAAE;AAChC,YAAY,SAAS,EAAE,KAAK;AAC5B,SAAS;AACT,QAAQ,KAAK,CAAC,MAAM,mCAAmC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE;AAC5F,QAAQ,IAAI,CAAC,WAAW,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;;AAEhE;AACA,QAAQ,IAAI,CAAC,YAAY,GAAG,IAAI;;AAEhC;AACA,QAAQ,IAAI,CAAC,IAAI,EAAE;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,GAAG;AACX;AACA,QAAQ,MAAM,UAAU,GAAG,IAAI,GAAG,EAAE;AACpC,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO;;AAE9B;AACA,QAAQ,IAAI,cAAc,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE;AACtD,YAAY,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,KAAK;AACrC,YAAY,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM;AAC3C,YAAY,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;AACvC,SAAS,CAAC;;AAEV,QAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK;;AAEtC,QAAQ,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE;AAC1B,YAAY,MAAM,EAAE,cAAc;AAClC,YAAY,KAAK,EAAE,CAAC,QAAQ;AAC5B,SAAS,CAAC;;AAEV;AACA,QAAQ,OAAO,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE;AAC3C,YAAY,MAAM,QAAQ,GAAG,cAAc,CAAC,YAAY,EAAE;AAC1D,YAAY,MAAM,SAAS,GAAG,cAAc,CAAC,SAAS;;AAEtD;AACA;AACA,YAAY,MAAM,aAAa,GAAG,EAAE;;AAEpC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE;AACtD,gBAAgB,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC;;AAE3C;AACA,gBAAgB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,gBAAgB,EAAE;AACxE,oBAAoB;AACpB,gBAAgB;;AAEhB;AACA;AACA,gBAAgB,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK;AAC3D,oBAAoB,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;AAC1C,oBAAoB,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;AAC1C,gBAAgB,CAAC,CAAC;;AAElB;AACA,gBAAgB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;;AAEvE;AACA,gBAAgB,MAAM,aAAa,GAAG,IAAI,MAAM,CAAC,aAAa,EAAE;AAChE,oBAAoB,CAAC,EAAE,CAAC;AACxB,oBAAoB,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM;AACnD,oBAAoB,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;AAC/C,iBAAiB,CAAC;;AAElB,gBAAgB,MAAM,oBAAoB,GAAG,aAAa,CAAC,YAAY,EAAE;AACzE,gBAAgB,MAAM,eAAe,GAAG,aAAa,CAAC,SAAS;;AAE/D;AACA;AACA,gBAAgB,MAAM,qBAAqB,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC,aAAa;AACrF,oBAAoB,aAAa,CAAC,GAAG,CAAC,CAAC,SAAS,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;AACxE,iBAAiB;;AAEjB;AACA,gBAAgB,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,qBAAqB,EAAE,eAAe,CAAC;;AAEtF,gBAAgB,aAAa,CAAC,IAAI,CAAC;AACnC,oBAAoB,KAAK,EAAE,CAAC;AAC5B,oBAAoB,UAAU,EAAE,UAAU;AAC1C,oBAAoB,YAAY,EAAE,YAAY;AAC9C,oBAAoB,cAAc,EAAE,qBAAqB;AACzD,oBAAoB,eAAe,EAAE,eAAe;AACpD,iBAAiB,CAAC;AAClB,YAAY;;AAEZ;AACA;AACA,YAAY,MAAM,eAAe,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,YAAY,GAAG,MAAM,CAAC,UAAU,CAAC;;AAE7G;AACA,YAAY,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE;AAC9C,gBAAgB;AAChB,YAAY;;AAEZ;AACA;AACA,YAAY,MAAM,aAAa,GAAG,EAAE;AACpC,YAAY,MAAM,aAAa,GAAG,IAAI,GAAG,EAAE;;AAE3C;AACA,YAAY,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC;;AAE3G,YAAY,KAAK,MAAM,KAAK,IAAI,eAAe,EAAE;AACjD,gBAAgB,IAAI,SAAS,CAAC,MAAM,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE;AACzF,oBAAoB,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;AAClD,gBAAgB,CAAC,MAAM;AACvB,oBAAoB;AACpB,gBAAgB;AAChB,YAAY;;AAEZ,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE;AACvD,gBAAgB,IAAI,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;AAC1C;AACA,oBAAoB,MAAM,YAAY,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC;AACnF,oBAAoB,IAAI,YAAY,EAAE;AACtC,wBAAwB,aAAa,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,eAAe,CAAC;AAC3E,oBAAoB;AACpB,gBAAgB,CAAC,MAAM;AACvB;AACA,oBAAoB,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACpD,gBAAgB;AAChB,YAAY;;AAEZ;AACA;AACA,YAAY,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM;;AAE7C;AACA,YAAY,cAAc,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE;AACtD,gBAAgB,CAAC,EAAE,IAAI;AACvB,gBAAgB,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM;AAC/C,gBAAgB,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;AAC3C,gBAAgB,iBAAiB,EAAE,aAAa;AAChD,aAAa,CAAC;;AAEd;AACA,YAAY,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE;AACjC,gBAAgB,MAAM,EAAE,cAAc;AACtC,gBAAgB,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,YAAY,EAAE,EAAE,cAAc,CAAC,SAAS,CAAC;AACzF,aAAa,CAAC;;AAEd,YAAY,CAAC,GAAG,IAAI;AACpB,QAAQ;;AAER;AACA,QAAQ,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,sBAAsB,CAAC,UAAU,CAAC;AACnE,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,sBAAsB,CAAC,UAAU,EAAE;AACvC,QAAQ,IAAI,UAAU,CAAC,IAAI,KAAK,CAAC,EAAE;AACnC,YAAY,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC;AAClD,QAAQ;;AAER,QAAQ,MAAM,eAAe,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;AACtE,QAAQ,IAAI,CAAC,eAAe,EAAE;AAC9B,YAAY,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC;AACxD,QAAQ;;AAER,QAAQ,IAAI,UAAU,GAAG,eAAe,CAAC,KAAK;AAC9C;AACA,QAAQ,IAAI,WAAW,GAAG,eAAe,CAAC,MAAM;;AAEhD,QAAQ,KAAK,MAAM,SAAS,IAAI,UAAU,CAAC,MAAM,EAAE,EAAE;AACrD,YAAY,IAAI,SAAS,CAAC,KAAK,GAAG,UAAU,EAAE;AAC9C,gBAAgB,UAAU,GAAG,SAAS,CAAC,KAAK;AAC5C,gBAAgB,WAAW,GAAG,SAAS,CAAC,MAAM;AAC9C,YAAY;AACZ,QAAQ;;AAER,QAAQ,OAAO,WAAW;AAC1B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE;AAC9B,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO;AAC9B,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,CAAC,GAAG,SAAS,CAAC,MAAM;;AAElC,QAAQ,IAAI,cAAc,GAAG,CAAC;AAC9B,QAAQ,IAAI,CAAC,GAAG,CAAC;;AAEjB;AACA,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC;AACvC,YAAY,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC;AACzC,YAAY,CAAC,IAAI,OAAO,CAAC,MAAM;;AAE/B,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE;AACrD,gBAAgB,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC;AAC5C,gBAAgB,MAAM,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC;AAC9C;AACA,gBAAgB,cAAc,IAAI,iBAAiB,CAAC,QAAQ,EAAE,KAAK,CAAC;AACpE,YAAY;AACZ,QAAQ;;AAER;AACA,QAAQ,IAAI,CAAC,IAAI,CAAC,EAAE;AACpB,YAAY,OAAO,CAAC,QAAQ;AAC5B,QAAQ;;AAER;AACA,QAAQ,MAAM,QAAQ,GAAG,cAAc,IAAI,CAAC,GAAG,CAAC,CAAC;;AAEjD;AACA,QAAQ,IAAI,QAAQ,IAAI,CAAC,EAAE;AAC3B,YAAY,OAAO,CAAC,QAAQ;AAC5B,QAAQ;;AAER;AACA,QAAQ,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC;;AAEnC;AACA,QAAQ,IAAI,cAAc,GAAG,CAAC;AAC9B,QAAQ,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC;;AAE7C,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM;AACxC,YAAY,IAAI,CAAC,IAAI,CAAC,EAAE;;AAExB;AACA,YAAY,MAAM,sBAAsB;AACxC,gBAAgB,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;;AAE1G,YAAY,cAAc,IAAI,sBAAsB;AACpD,QAAQ;;AAER;AACA,QAAQ,OAAO,cAAc,GAAG,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACrD,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,YAAY,GAAG;AACnB,QAAQ,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE;AAChC,YAAY,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC;AACtD,QAAQ;AACR,QAAQ,OAAO,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE;AAC/C,IAAI;;AAEJ;AACA,IAAI,gBAAgB,GAAG;AACvB,QAAQ,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE;AAChC,YAAY,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC;AACtD,QAAQ;AACR,QAAQ,OAAO,IAAI,CAAC,YAAY,CAAC,gBAAgB,EAAE;AACnD,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,SAAS,GAAG;AACpB,QAAQ,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE;AAChC,YAAY,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC;AACtD,QAAQ;AACR,QAAQ,OAAO,IAAI,CAAC,YAAY,CAAC,SAAS;AAC1C,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,CAAC,GAAG;AACZ,QAAQ,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE;AAChC,YAAY,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC;AACtD,QAAQ;AACR,QAAQ,OAAO,IAAI,CAAC,YAAY,CAAC,CAAC;AAClC,IAAI;AACJ;;ACtWA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,EAAE,CAAC;AAChB;AACA,IAAI,EAAE;AACN;AACA,IAAI,EAAE;AACN;AACA,IAAI,WAAW;AACf;AACA,IAAI,eAAe;;AAEnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,CAAC,EAAE,kBAAkB,EAAE,UAAU,GAAG,EAAE,EAAE;AACxD;AACA,QAAQ,IAAI,CAAC,OAAO,GAAG,CAAC;;AAExB;AACA,QAAQ,IAAI,CAAC,WAAW,uBAAuB,MAAM,CAAC,IAAI,CAAC;AAC3D,YAAY,GAAG,kBAAkB;AACjC,YAAY,GAAG,UAAU;AACzB,SAAS,CAAC;AACV;AACA,QAAQ,IAAI,CAAC,KAAK;AAClB;AACA,QAAQ,IAAI,CAAC,CAAC;AACd;AACA,QAAQ,IAAI,CAAC,CAAC;;AAEd,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;AAC9B,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,YAAY,YAAY,EAAE;AAC9C,gBAAgB,IAAI,CAAC,KAAK,GAAG,OAAO;AACpC,YAAY,CAAC,MAAM;AACnB,gBAAgB,IAAI,CAAC,KAAK,GAAG,OAAO;AACpC,YAAY;AACZ,YAAY,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;AACnC,QAAQ,CAAC,MAAM,IAAI,CAAC,YAAY,MAAM,EAAE;AACxC,YAAY,IAAI,CAAC,KAAK,GAAG,QAAQ;AACjC,YAAY,IAAI,CAAC,CAAC,GAAG,CAAC;AACtB,QAAQ,CAAC,MAAM;AACf,YAAY,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC;AACnD,QAAQ;AACR,QAAQ,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK;AACnC,QAAQ,IAAI,CAAC,EAAE,GAAG,CAAC;AACnB,QAAQ,IAAI,CAAC,EAAE,GAAG,CAAC;AACnB,QAAQ,IAAI,CAAC,WAAW,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;AAChE,QAAQ,IAAI,CAAC,eAAe,GAAG,KAAK;AACpC,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE;AAC3B,QAAQ,IAAI,IAAI,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,EAAE;AACvD,YAAY,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,WAAW,CAAC;AACtD,QAAQ;AACR,QAAQ,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE;AAC5D,YAAY,MAAM,IAAI,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,0BAA0B,CAAC,CAAC;AACxE,QAAQ;AACR,QAAQ,IAAI,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE;AACzC,YAAY,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,KAAK;AAC1C,YAAY,IAAI,CAAC,eAAe,GAAG,KAAK;AACxC,YAAY,OAAO,IAAI;AACvB,QAAQ,CAAC,MAAM,IAAI,IAAI,EAAE;AACzB,YAAY,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;AACzC,QAAQ;AACR,QAAQ,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;AAC7C,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,SAAS,CAAC,GAAG,IAAI,EAAE;AAEvB,QAAQ,IAAI,CAAC,UAAU,EAAE;AACzB,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE;AAE7C,QAAQ,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC;AACpD,QAAQ,yBAAyB,EAAE,CAAC,SAAS,EAAE;AAC/C,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE;AACxB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;AACzC,QAAQ,MAAM,CAAC;AACf,QAAQ,OAAO,CAAC;AAChB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,QAAQ,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE;AAC9C,QAAQ,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC;AACpD,QAAQ,MAAM,SAAS,GAAG,EAAE,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;AAC/C,QAAQ,IAAI,MAAM;AAClB,QAAQ,GAAG;AACX,YAAY,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE;AACrC,YAAY,MAAM,MAAM,CAAC,KAAK;AAC9B,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI;;AAE7B,QAAQ,OAAO,MAAM,CAAC,KAAK;AAC3B,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,IAAI,CAAC,GAAG,IAAI,EAAE;AAElB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,UAAU,GAAG;AACjB,QAAQ,IAAI,CAAC,IAAI,CAAC,eAAe,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE;AACtE,YAAY,IAAI,CAAC,IAAI,EAAE;AACvB,YAAY,IAAI,CAAC,eAAe,GAAG,IAAI;AACvC,QAAQ;AACR,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA,IAAI,IAAI,UAAU,GAAG;AACrB,QAAQ,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE;AACtC,YAAY,IAAI,CAAC,UAAU,EAAE;AAC7B;AACA,YAAY,IAAI,IAAI,CAAC,KAAK,KAAK,QAAQ,EAAE;AACzC,gBAAgB,6CAA6C,IAAI,CAAC,CAAC;AACnE,YAAY,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,KAAK,OAAO,EAAE;AAC/C,gBAAgB,6CAA6C,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE;AAC/E,YAAY,CAAC,MAAM;AACnB,gBAAgB,6CAA6C,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE;AAC7E,YAAY;AACZ,QAAQ,CAAC,MAAM;AACf,YAAY,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC;AAClE,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,MAAM,eAAe,CAAC,GAAG,IAAI,EAAE;AACnC,QAAQ,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;AACtC,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,aAAa,eAAe,CAAC,CAAC,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE;AACzD,QAAQ,OAAO,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;AACnD,IAAI;AACJ;;ACpPA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,OAAO,SAAS,EAAE,CAAC;AAChC;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,CAAC,EAAE,UAAU,EAAE;AAC/B,QAAQ,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,UAAU,CAAC;AACrE,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,uBAAuB,CAAC,IAAI,EAAE;AAClC,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AACxB,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5B,QAAQ,IAAI,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU,GAAG,CAAC;AACrD;AACA,QAAQ,IAAI,OAAO,GAAG,IAAI;AAC1B,QAAQ,IAAI,QAAQ,GAAG,CAAC,QAAQ;AAChC,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;AACzC,YAAY,IAAI,IAAI,GAAG,QAAQ,EAAE;AACjC,gBAAgB,QAAQ,GAAG,IAAI;AAC/B,gBAAgB,OAAO,GAAG,CAAC;AAC3B,YAAY;AACZ,QAAQ;AACR,QAAQ,IAAI,OAAO,KAAK,IAAI,EAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;AACnE,QAAQ,QAAQ,GAAG,CAAC,QAAQ;AAC5B,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;AACzC,YAAY,IAAI,IAAI,GAAG,QAAQ,EAAE;AACjC,gBAAgB,QAAQ,GAAG,IAAI;AAC/B,gBAAgB,OAAO,GAAG,CAAC;AAC3B,YAAY;AACZ,QAAQ;AACR,QAAQ,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC;AAC3C,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,SAAS,GAAG;AAChB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AACxB,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5B,QAAQ,MAAM,CAAC,0BAA0B,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;AAC5D,QAAQ,MAAM,MAAM,oCAAoC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;AAChF,QAAQ,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACrC;AACA,QAAQ,IAAI,IAAI,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;;AAEvD,QAAQ,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE;AAC7C,YAAY,MAAM,QAAQ,GAAG,IAAI;AACjC;AACA,YAAY,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC;AAC/E,YAAY,IAAI,IAAI,KAAK,CAAC,EAAE;AAC5B;AACA,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAC5C,oBAAoB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;AACjD,oBAAoB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;AACjD,oBAAoB,MAAM,GAAG,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;AAChF,oBAAoB,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC;AAC7C,gBAAgB;AAChB;AACA;AACA;AACA;AACA,gBAAgB,IAAI,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;AAC5G,YAAY;AACZ,QAAQ;AACR;AACA,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC;AAClB,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ,IAAI,CAAC,SAAS,GAAG;AACjB,QAAQ,MAAM,IAAI,CAAC,SAAS,EAAE;AAC9B,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACpC,QAAQ,MAAM,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC,EAAE,UAAU,CAAC;AAC7C,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,QAAQ,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACrC,QAAQ,MAAM,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC,EAAE,UAAU,CAAC;AAC7C,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,QAAQ,OAAO,EAAE,CAAC,UAAU;AAC5B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,aAAa,eAAe,CAAC,CAAC,EAAE,UAAU,EAAE;AAChD,QAAQ,MAAM,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC,EAAE,UAAU,CAAC;AAC7C,QAAQ,OAAO,EAAE,CAAC,eAAe,EAAE;AACnC,IAAI;AACJ;;AC5IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,GAAG,CAAC;AACjB;AACA,IAAI,SAAS;AACb;AACA,IAAI,WAAW;AACf;AACA,IAAI,KAAK;;AAET;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,QAAQ,EAAE,UAAU,EAAE;AACtC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC;AACrG,QAAQ,IAAI,QAAQ,CAAC,CAAC,CAAC,YAAY,YAAY,EAAE;AACjD,YAAY,IAAI,CAAC,KAAK,GAAG,OAAO;AAChC,QAAQ,CAAC,MAAM;AACf,YAAY,IAAI,CAAC,KAAK,GAAG,OAAO;AAChC,QAAQ;AACR,QAAQ,IAAI,CAAC,WAAW,GAAG,UAAU;AACrC,QAAQ,IAAI,CAAC,SAAS,GAAG,QAAQ;AACjC,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE;AAGjB,QAAQ,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC;AACnE,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE;AAG1B,QAAQ,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC;AAC5E,IAAI;AACJ;;ACpDA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,KAAK,SAAS,GAAG,CAAC;AAC/B;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW;AACf,QAAQ,QAAQ;AAChB,QAAQ,UAAU,GAAG;AACrB,YAAY,MAAM,EAAE,SAAS;AAC7B,YAAY,QAAQ,EAAE,EAAE;AACxB,YAAY,gBAAgB,EAAE,EAAE;AAChC,YAAY,IAAI,EAAE,IAAI;AACtB,SAAS;AACT,MAAM;AACN;AACA,QAAQ,MAAM,WAAW,GAAG,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;AAC3D,QAAQ,MAAM,YAAY,qBAAqB,WAAW,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;;AAEjG,QAAQ,KAAK,CAAC,CAAC,YAAY,CAAC,EAAE,UAAU,CAAC;;AAEzC,QAAQ,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,IAAI,SAAS;AAC3D,QAAQ,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,IAAI,EAAE;AACxD,QAAQ,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,WAAW,CAAC,gBAAgB,IAAI,EAAE;AACxE,QAAQ,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,IAAI,IAAI;AAClD,QAAQ,IAAI,CAAC,WAAW,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;;AAErD;AACA;AACA;AACA;AACA,QAAQ,IAAI,CAAC,MAAM,GAAG,EAAE;;AAExB;AACA,QAAQ,IAAI,WAAW,EAAE;AACzB;AACA;AACA,YAAY,IAAI,CAAC,SAAS,GAAG,EAAE;AAC/B,YAAY,IAAI,CAAC,MAAM,GAAG,EAAE;AAC5B,YAAY,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC9B,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,IAAI,SAAS,GAAG;AACpB,QAAQ,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM;AACjC,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,IAAI,SAAS,GAAG;AACpB,QAAQ,IAAI,KAAK,GAAG,CAAC;AACrB,QAAQ,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,MAAM,EAAE;AACxC,YAAY,KAAK,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;AAC3C,QAAQ;AACR,QAAQ,OAAO,KAAK;AACpB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,IAAI,EAAE;AACtB,QAAQ,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC;AAC3B,QAAQ,OAAO,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC;AAC7E,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,GAAG,CAAC,QAAQ,EAAE;AAClB;AACA,QAAQ,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC;;AAExD;AACA,QAAQ,IAAI,CAAC,MAAM,GAAG,EAAE;AACxB,QAAQ,IAAI,CAAC,WAAW,EAAE;;AAE1B,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,WAAW,GAAG;AAClB,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS;AACvC,QAAQ,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM;;AAEjC,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC,EAAE,EAAE;AACjD;AACA,YAAY,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;AAClE,YAAY,MAAM,IAAI,GAAG,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC;AAC1D,YAAY,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;AAClC,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,mBAAmB,CAAC,OAAO,EAAE;AACjC,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS;;AAEvC;AACA,QAAQ,IAAI,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,iBAAiB,EAAE;AACtD,YAAY,OAAO;AACnB,gBAAgB,MAAM,EAAE,IAAI;AAC5B,gBAAgB,OAAO,EAAE,OAAO;AAChC,gBAAgB,MAAM,EAAE,EAAE;AAC1B,gBAAgB,MAAM,EAAE,CAAC;AACzB,gBAAgB,IAAI,EAAE,IAAI;AAC1B,gBAAgB,KAAK,EAAE,IAAI;AAC3B,aAAa;AACb,QAAQ;;AAER;AACA,QAAQ,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AAClF,QAAQ,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;;AAElF,QAAQ,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC;AACrC,QAAQ,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC;;AAErC;AACA,QAAQ,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM;AACjC;AACA,QAAQ,MAAM,MAAM,GAAG,IAAI,KAAK,CAAC,GAAG,CAAC;AACrC,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE;AACtC,YAAY,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;AAC7C,QAAQ;;AAER;AACA,QAAQ,IAAI,IAAI,GAAG,CAAC;AACpB,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE;AACtC,YAAY,IAAI,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;AACzC,QAAQ;AACR,QAAQ,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;;AAE9B,QAAQ,IAAI,IAAI,GAAG,KAAK,EAAE;AAC1B,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE;AAC1C,gBAAgB,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI;AACjC,YAAY;AACZ,QAAQ;;AAER;AACA;AACA,QAAQ,MAAM,QAAQ,GAAG,IAAI,KAAK,CAAC,GAAG,CAAC;AACvC,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE;AACtC,YAAY,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACrD,QAAQ;;AAER;AACA,QAAQ,IAAI,MAAM,GAAG,CAAC;AACtB,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE;AACtC,YAAY,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;AAC7C,QAAQ;;AAER;AACA,QAAQ,MAAM,WAAW,GAAG,EAAE;AAC9B,QAAQ,MAAM,YAAY,GAAG,EAAE;;AAE/B,QAAQ,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE;AACnC,YAAY,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC;AACvC,YAAY,IAAI,GAAG,GAAG,CAAC;AACvB,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE;AAC1C,gBAAgB,GAAG,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;AAC3C,YAAY;;AAEZ,YAAY,IAAI,GAAG,GAAG,MAAM,EAAE;AAC9B,gBAAgB,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC;AACrC,YAAY,CAAC,MAAM;AACnB,gBAAgB,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC;AACtC,YAAY;AACZ,QAAQ;;AAER;AACA,QAAQ,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE;AACnE,YAAY,OAAO;AACnB,gBAAgB,MAAM,EAAE,IAAI;AAC5B,gBAAgB,OAAO,EAAE,OAAO;AAChC,gBAAgB,MAAM,EAAE,EAAE;AAC1B,gBAAgB,MAAM,EAAE,CAAC;AACzB,gBAAgB,IAAI,EAAE,IAAI;AAC1B,gBAAgB,KAAK,EAAE,IAAI;AAC3B,aAAa;AACb,QAAQ;;AAER;AACA,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,mBAAmB,CAAC,WAAW,CAAC;AAC1D,QAAQ,MAAM,KAAK,GAAG,IAAI,CAAC,mBAAmB,CAAC,YAAY,CAAC;;AAE5D,QAAQ,OAAO;AACf,YAAY,MAAM,EAAE,KAAK;AACzB,YAAY,OAAO,EAAE,EAAE;AACvB,YAAY,MAAM,EAAE,MAAM;AAC1B,YAAY,MAAM,EAAE,MAAM;AAC1B,YAAY,IAAI,EAAE,IAAI;AACtB,YAAY,KAAK,EAAE,KAAK;AACxB,SAAS;AACT,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE;AACjD,QAAQ,IAAI,GAAG,GAAG,CAAC;AACnB,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AAC/C,YAAY,GAAG,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;AACvC,QAAQ;AACR,QAAQ,OAAO,GAAG,GAAG,MAAM;AAC3B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE;AACzB,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO;AACnC,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS;;AAEvC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,OAAO,EAAE;;AAE5C;AACA,QAAQ,MAAM,UAAU,GAAG,IAAI,GAAG,EAAE;;AAEpC;AACA;AACA,QAAQ,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC;;AAE/E,QAAQ,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,MAAM,EAAE;AACxC,YAAY,IAAI,CAAC,mBAAmB,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,aAAa,CAAC;AAC5E,QAAQ;;AAER;AACA;AACA,QAAQ,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC;;AAE7D,QAAQ,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE;AACtC,YAAY,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC;AACzC,YAAY,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,EAAE;;AAE7D,YAAY,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC;;AAE/C,YAAY,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;AACjC,gBAAgB,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AACzD,YAAY,CAAC,MAAM,IAAI,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,KAAK,IAAI,QAAQ,CAAC,EAAE;AAC/D,gBAAgB,IAAI,CAAC,GAAG,EAAE;AAC1B,gBAAgB,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AACzD,YAAY;AACZ,QAAQ;;AAER;AACA,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;AAC7B,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AACzE,gBAAgB,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;;AAEvC,gBAAgB,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC;AAC3C,gBAAgB,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,EAAE;;AAEjE,gBAAgB,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC;AACnD,gBAAgB,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AACvD,YAAY;AACZ,QAAQ;;AAER;AACA;AACA,QAAQ,MAAM,MAAM,GAAG,EAAE;AACzB,QAAQ,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;AAChC,YAAY,MAAM,IAAI,mFAAmF,IAAI,CAAC,GAAG,EAAE,CAAC;AACpH,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,gBAAgB,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;AACrD,gBAAgB,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK;AACzC,gBAAgB,QAAQ,EAAE,IAAI,CAAC,KAAK;AACpC,aAAa,CAAC;AACd,QAAQ;;AAER,QAAQ,OAAO,MAAM,CAAC,OAAO,EAAE;AAC/B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,mBAAmB,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE;AAChE,QAAQ,IAAI,CAAC,IAAI,EAAE;;AAEnB;AACA;AACA,QAAQ,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC;AACvD,QAAQ,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;;AAExC,QAAQ,OAAO,CAAC,EAAE,CAAC,KAAK,IAAI,UAAU,CAAC,IAAI,GAAG,aAAa,EAAE;AAC7D,YAAY,MAAM,KAAK,GAAG,EAAE,CAAC,GAAG,EAAE;AAClC,YAAY,IAAI,CAAC,KAAK,EAAE;;AAExB,YAAY,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI;;AAElD;AACA,YAAY,IAAI,WAAW,CAAC,MAAM,EAAE;AACpC,gBAAgB,KAAK,MAAM,GAAG,IAAI,WAAW,CAAC,OAAO,EAAE;AACvD,oBAAoB,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC;AACvC,oBAAoB,IAAI,UAAU,CAAC,IAAI,IAAI,aAAa,EAAE;AAC1D,gBAAgB;AAChB,gBAAgB;AAChB,YAAY;;AAEZ;AACA,YAAY,MAAM,IAAI,GAAG,IAAI,CAAC,qBAAqB,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC;;AAElG;AACA,YAAY,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,GAAG,WAAW,CAAC,IAAI,GAAG,WAAW,CAAC,KAAK;AAC9E,YAAY,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,GAAG,WAAW,CAAC,KAAK,GAAG,WAAW,CAAC,IAAI;;AAE/E;AACA,YAAY,IAAI,UAAU,EAAE;AAC5B,gBAAgB,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;AACtD,YAAY;;AAEZ;AACA,YAAY,IAAI,WAAW,IAAI,UAAU,CAAC,IAAI,GAAG,aAAa,EAAE;AAChE,gBAAgB,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;AACpE,YAAY;AACZ,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,eAAe,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE;AAC9B,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE;AAC1D,QAAQ,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAChD,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,YAAY,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE;AAC3B,QAAQ,OAAO,IAAI,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC;AACzC,IAAI;AACJ;;ACxZA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,QAAQ,SAAS,GAAG,CAAC;AAClC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,QAAQ,EAAE,UAAU,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;AAC1E,QAAQ,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,UAAU,CAAC,CAAC;AAClE;AACA;AACA;AACA;AACA,QAAQ,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;AAC5F,IAAI;;AAEJ;AACA,IAAI,IAAI,OAAO,GAAG;AAClB,QAAQ,OAAO,IAAI,CAAC,WAAW,CAAC,MAAM;AACtC,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,UAAU,CAAC,QAAQ,EAAE;AACzB,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE;AACnC,YAAY,OAAO,IAAI,YAAY,CAAC,QAAQ,CAAC;AAC7C,QAAQ,CAAC,MAAM;AACf,YAAY,MAAM,CAAC,GAAG,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC;AACrD,YAAY,MAAM,eAAe,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACxF,YAAY,MAAM,CAAC,GAAG,eAAe,CAAC,MAAM;AAC5C,YAAY,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC;AAC7C,YAAY,MAAM,CAAC,GAAG,eAAe,CAAC,OAAO,CAAC;AAC9C,YAAY,MAAM,CAAC,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC;AACvD,YAAY,MAAM,CAAC,GAAG,eAAe,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;AACvD,YAAY,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAC/F,YAAY,IAAI,CAAC;AACjB,YAAY,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE;AAC9C,gBAAgB,CAAC,GAAG,IAAI,YAAY,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC;AACvF,YAAY,CAAC,MAAM;AACnB,gBAAgB,CAAC,GAAG,IAAI,YAAY,CAAC,QAAQ,CAAC;AAC9C,YAAY;AACZ,YAAY,OAAO,CAAC;AACpB,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,gBAAgB,CAAC,CAAC,EAAE;AACxB,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM;AACrC,QAAQ,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC;;AAElC,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC;AAC5C,QAAQ;;AAER,QAAQ,IAAI,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,OAAO,KAAK;AAChD,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxC,gBAAgB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACnE,gBAAgB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACnE,YAAY;AACZ,YAAY,OAAO,GAAG;AACtB,QAAQ,CAAC,EAAE,KAAK,CAAC;AACjB,QAAQ,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;;AAE/C,QAAQ,IAAI,CAAC,GAAG,CAAC;AACjB,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;AAC7C,QAAQ;AACR,QAAQ,OAAO,CAAC;AAChB,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,eAAe,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE;AAC9B,QAAQ,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAChD,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE;AACrB;AACA,QAAQ,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC;AAC7E,QAAQ,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC;;AAE5C;AACA;AACA,QAAQ,MAAM,MAAM,GAAG,EAAE;AACzB,QAAQ,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;AAChC,YAAY,MAAM,IAAI,mEAAmE,IAAI,CAAC,GAAG,EAAE,CAAC;AACpG,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,gBAAgB,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO;AAC7C,gBAAgB,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK;AACzC,gBAAgB,QAAQ,EAAE,IAAI,CAAC,KAAK;AACpC,aAAa,CAAC;AACd,QAAQ;AACR,QAAQ,OAAO,MAAM,CAAC,OAAO,EAAE,CAAC;AAChC,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AACxB,QAAQ,IAAI,CAAC,CAAC,EAAE;;AAEhB,QAAQ,IAAI,CAAC,YAAY,YAAY,EAAE;AACvC,YAAY,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;AAClE,YAAY,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,aAAa,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,KAAK,EAAE,KAAK,IAAI,CAAC,QAAQ,CAAC,EAAE;AAC5F,gBAAgB;AAChB,YAAY;;AAEZ,YAAY,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM;AAC/B,YAAY,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM;;AAE/B,YAAY,IAAI,EAAE,GAAG,QAAQ;AAC7B,YAAY,IAAI,EAAE,GAAG,QAAQ;;AAE7B,YAAY,IAAI,EAAE,YAAY,YAAY,EAAE,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC;AAClF,iBAAiB,IAAI,EAAE,YAAY,YAAY,EAAE,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;;AAE3F,YAAY,IAAI,EAAE,YAAY,YAAY,EAAE,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC;AAClF,iBAAiB,IAAI,EAAE,YAAY,YAAY,EAAE,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;;AAE3F,YAAY,IAAI,EAAE,GAAG,EAAE,EAAE;AACzB,gBAAgB,IAAI,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;AACjD,gBAAgB,IAAI,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;AACjD,YAAY,CAAC,MAAM;AACnB,gBAAgB,IAAI,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;AACjD,gBAAgB,IAAI,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;AACjD,YAAY;AACZ,QAAQ,CAAC,MAAM,IAAI,CAAC,YAAY,YAAY,EAAE;AAC9C,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAC7D,gBAAgB,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACrC,gBAAgB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;AACvD,gBAAgB,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE;AAClC,oBAAoB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC7B,gBAAgB,CAAC,MAAM,IAAI,IAAI,IAAI,CAAC,CAAC,KAAK,EAAE,KAAK,IAAI,QAAQ,CAAC,EAAE;AAChE,oBAAoB,CAAC,CAAC,GAAG,EAAE;AAC3B,oBAAoB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC7B,gBAAgB;AAChB,YAAY;AACZ,QAAQ;AACR,IAAI;AACJ;;AAEA;AACA;AACA;AACA;AACA,MAAM,YAAY,CAAC;AACnB;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,GAAG,CAAC,EAAE;AACjE,QAAQ,IAAI,CAAC,KAAK,GAAG,KAAK;AAC1B,QAAQ,IAAI,CAAC,MAAM,GAAG,MAAM;AAC5B,QAAQ,IAAI,CAAC,MAAM,GAAG,MAAM;AAC5B,QAAQ,IAAI,CAAC,MAAM,GAAG,MAAM;AAC5B,IAAI;AACJ;;AAEA;AACA;AACA;AACA;AACA,MAAM,YAAY,CAAC;AACnB;AACA,IAAI,WAAW,CAAC,MAAM,EAAE;AACxB,QAAQ,IAAI,CAAC,MAAM,GAAG,MAAM;AAC5B,IAAI;AACJ;;AClNA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,IAAI,SAAS,GAAG,CAAC;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW;AACf,QAAQ,MAAM;AACd,QAAQ,UAAU,GAAG;AACrB,YAAY,MAAM,EAAE,SAAS;AAC7B,YAAY,SAAS,EAAE,IAAI;AAC3B,YAAY,CAAC,EAAE,EAAE;AACjB,YAAY,eAAe,EAAE,GAAG;AAChC,YAAY,EAAE,EAAE,IAAI;AACpB,YAAY,EAAE,EAAE,IAAI;AACpB,YAAY,IAAI,EAAE,IAAI;AACtB,YAAY,EAAE,EAAE,EAAE;AAClB,SAAS;AACT,MAAM;AACN;AACA,QAAQ,MAAM,WAAW,GAAG,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;AACvD,QAAQ,IAAI,YAAY,qBAAqB,WAAW,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;;AAE7F;AACA,QAAQ,IAAI,WAAW,EAAE;AACzB,YAAY,MAAM,YAAY,GAAG,YAAY,CAAC,MAAM;AACpD,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AACpD,gBAAgB,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,YAAY,EAAE;AACrE,oBAAoB,OAAO,CAAC,IAAI;AAChC,wBAAwB,CAAC,YAAY,EAAE,CAAC,CAAC,uCAAuC,EAAE,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAC3H,qBAAqB;AACrB;AACA,oBAAoB,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,GAAG,KAAK,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,MAAM,KAAK,YAAY,CAAC;AACzG,oBAAoB,YAAY,GAAG,MAAM,CAAC,CAAC,CAAC;AAC5C,gBAAgB;AAChB,YAAY;AACZ,QAAQ;;AAER,QAAQ,KAAK,CAAC,CAAC,YAAY,CAAC,EAAE,UAAU,CAAC;;AAEzC;AACA,QAAQ,MAAM,aAAa,GAAG,WAAW,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,EAAE;AAC5D;AACA,QAAQ,IAAI,CAAC,SAAS,GAAG,EAAE;;AAE3B;AACA,QAAQ,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,IAAI,SAAS;;AAE3D;AACA,QAAQ,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,SAAS,GAAG,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;;AAEtH;AACA;AACA;AACA;AACA,QAAQ,IAAI,CAAC,MAAM,GAAG,IAAI,GAAG,EAAE;;AAE/B;AACA,QAAQ,IAAI,CAAC,WAAW,GAAG,CAAC;;AAE5B;AACA,QAAQ,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE;AAChD,QAAQ,IAAI,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE;AACxD,YAAY,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC;AAC7E,QAAQ;AACR;AACA,QAAQ,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC;;AAEtC,QAAQ,MAAM,qBAAqB,GAAG,IAAI,CAAC,WAAW,CAAC,eAAe,IAAI,GAAG;AAC7E,QAAQ,IAAI,qBAAqB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,qBAAqB,CAAC,EAAE;AACpF,YAAY,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC;AAC3F,QAAQ;AACR;AACA,QAAQ,IAAI,CAAC,gBAAgB,GAAG,qBAAqB;;AAErD,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE;AAClD,QAAQ,IAAI,QAAQ,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE;AAC1D,YAAY,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC;AAC9E,QAAQ;AACR;AACA,QAAQ,IAAI,CAAC,GAAG,GAAG,QAAQ;;AAE3B,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE;AAC3D,QAAQ,IAAI,QAAQ,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE;AAC1D,YAAY,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC;AAC9E,QAAQ;AACR;AACA,QAAQ,IAAI,CAAC,GAAG,GAAG,QAAQ;;AAE3B;AACA,QAAQ,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;;AAE/D;AACA,QAAQ,IAAI,CAAC,WAAW,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;;AAEhE;AACA,QAAQ,IAAI,CAAC,EAAE,GAAG,EAAE;;AAEpB;AACA,QAAQ,IAAI,CAAC,GAAG,GAAG,IAAI;;AAEvB;AACA,QAAQ,IAAI,aAAa,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE;AACvD,YAAY,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC;AACnC,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,MAAM,CAAC,OAAO,EAAE;AACpB,QAAQ,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC;AAClC,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,GAAG,CAAC,YAAY,EAAE;AACtB;AACA,QAAQ,IAAI,CAAC,YAAY,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE;AACxD,YAAY,OAAO,IAAI;AACvB,QAAQ;;AAER,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,eAAe,GAAG,IAAI,CAAC,gBAAgB;AACrD,QAAQ,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG;AAC3B,QAAQ,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG;AAC3B,QAAQ,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW;AAC3C,QAAQ,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM;;AAEjC;AACA,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE;AAC5C,YAAY,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;AACvD,QAAQ;AACR,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS;;AAEvC;AACA,QAAQ,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,EAAE,MAAM;;AAE/F,QAAQ,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE;AAC5C;AACA,YAAY,IAAI,CAAC,OAAO,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,YAAY,YAAY,CAAC,CAAC,EAAE;AAC7F,gBAAgB,OAAO,CAAC,IAAI,CAAC,mEAAmE,CAAC;AACjG,gBAAgB;AAChB,YAAY;;AAEZ;AACA,YAAY,IAAI,OAAO,CAAC,MAAM,KAAK,YAAY,EAAE;AACjD,gBAAgB,OAAO,CAAC,IAAI;AAC5B,oBAAoB,CAAC,uDAAuD,EAAE,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;AACpH,iBAAiB;AACjB,gBAAgB;AAChB,YAAY;;AAEZ,YAAY,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC;AAClC,YAAY,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC;;AAEpD;AACA;AACA,YAAY,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAC5D,YAAY,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;;AAEpE,YAAY,IAAI,UAAU,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI;AAC5D,YAAY,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;;AAE7B,YAAY,IAAI,CAAC,IAAI,CAAC,EAAE;AACxB;AACA;AACA,gBAAgB,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE;AAClD,oBAAoB,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE,CAAC,EAAE,GAAG,CAAC;AACzF,oBAAoB,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE;AAClD,wBAAwB,UAAU,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC7D,oBAAoB;AACpB,gBAAgB;;AAEhB;AACA,gBAAgB,KAAK,IAAI,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,EAAE,GAAG,EAAE;AAChE,oBAAoB,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;AAChD,oBAAoB,IAAI,CAAC,KAAK,EAAE;;AAEhC,oBAAoB,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC;;AAE1D;AACA,oBAAoB,IAAI,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,GAAG,CAAC;;AAEzF;AACA;AACA,oBAAoB,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE;AAC/D,wBAAwB,MAAM,kBAAkB,GAAG,EAAE;AACrD,wBAAwB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AACtE,4BAA4B,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC;AACpD,4BAA4B,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE;AACxE,gCAAgC,kBAAkB,CAAC,IAAI,CAAC;AACxD,oCAAoC,OAAO,EAAE,IAAI;AACjD,oCAAoC,KAAK,EAAE,CAAC;AAC5C,oCAAoC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC;AACzE,iCAAiC,CAAC;AAClC,4BAA4B;AAC5B,wBAAwB;AACxB,wBAAwB,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;AAClF,wBAAwB,CAAC,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,CAAC;AACxE;AACA,wBAAwB,IAAI,GAAG,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;AACpD,4BAA4B,UAAU,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC;AAC9D,wBAAwB;AACxB,oBAAoB;;AAEpB;AACA,oBAAoB,MAAM,gBAAgB,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,EAAE,GAAG,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC;;AAE9F;AACA,oBAAoB,KAAK,MAAM,YAAY,IAAI,gBAAgB,EAAE;AACjE,wBAAwB,IAAI,YAAY,KAAK,YAAY,EAAE;;AAE3D;AACA,wBAAwB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE;AAC5D,4BAA4B,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,EAAE,EAAE,CAAC;AAC7D,wBAAwB;AACxB,wBAAwB,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,IAAI,CAAC,YAAY,CAAC;;AAEzE;AACA,wBAAwB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE;AAC5D,4BAA4B,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,EAAE,EAAE,CAAC;AAC7D,wBAAwB;AACxB,wBAAwB,MAAM,kBAAkB,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC;AAChF,wBAAwB,IAAI,kBAAkB,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE;AAC9F,4BAA4B,kBAAkB,CAAC,IAAI,CAAC,YAAY,CAAC;AACjE,wBAAwB;;AAExB;AACA,wBAAwB,MAAM,QAAQ,GAAG,GAAG,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC;AAC3D,wBAAwB,MAAM,cAAc,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC;AAC5E,wBAAwB,IAAI,cAAc,IAAI,cAAc,CAAC,MAAM,GAAG,QAAQ,EAAE;AAChF,4BAA4B,MAAM,gBAAgB,GAAG,QAAQ,CAAC,YAAY,CAAC;AAC3E;AACA,4BAA4B,MAAM,oBAAoB,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,GAAG,KAAK,YAAY,CAAC;AAC7G,4BAA4B,MAAM,mBAAmB,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM;AAC3F,gCAAgC,OAAO,EAAE,QAAQ,CAAC,GAAG,CAAC;AACtD,gCAAgC,KAAK,EAAE,GAAG;AAC1C,gCAAgC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;AACvF,6BAA6B,CAAC,CAAC;AAC/B,4BAA4B,MAAM,MAAM;AACxC,gCAAgC,GAAG,KAAK;AACxC,sCAAsC,IAAI,CAAC,cAAc,CAAC,gBAAgB,EAAE,mBAAmB,EAAE,QAAQ;AACzG,sCAAsC,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,GAAG,CAAC;AACxG,4BAA4B,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,EAAE,MAAM,CAAC;AACjE,wBAAwB;AACxB,oBAAoB;;AAEpB;AACA,oBAAoB,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE;AACtC,wBAAwB,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AACjD,oBAAoB;AACpB,gBAAgB;AAChB,YAAY;;AAEZ;AACA,YAAY,IAAI,CAAC,GAAG,CAAC,EAAE;AACvB,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE;AACjD,oBAAoB,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE;AACjC,wBAAwB,GAAG,EAAE,CAAC;AAC9B,wBAAwB,aAAa,EAAE,CAAC,YAAY,CAAC;AACrD,wBAAwB,KAAK,EAAE,IAAI,GAAG,EAAE;AACxC,qBAAqB,CAAC;AACtB,gBAAgB;AAChB;AACA,gBAAgB,IAAI,CAAC,GAAG,GAAG,CAAC,YAAY,CAAC;AACzC,gBAAgB,IAAI,CAAC,EAAE,GAAG,CAAC;AAC3B,YAAY;;AAEZ;AACA;AACA,YAAY,IAAI,CAAC,KAAK,EAAE,EAAE;AAC1B,gBAAgB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;AACnC,oBAAoB,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE;AACjC,wBAAwB,GAAG,EAAE,CAAC;AAC9B,wBAAwB,aAAa,EAAE,CAAC,YAAY,CAAC;AACrD,wBAAwB,KAAK,EAAE,IAAI,GAAG,EAAE;AACxC,qBAAqB,CAAC;AACtB,gBAAgB;AAChB,gBAAgB,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;AAC3C,gBAAgB,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE;AAC/D,oBAAoB,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,EAAE,EAAE,CAAC;AACtD,gBAAgB;AAChB,YAAY;AACZ,QAAQ;;AAER,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,iBAAiB,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,GAAG,EAAE,iBAAiB,GAAG,IAAI,EAAE,uBAAuB,GAAG,IAAI,EAAE;AACvG,QAAQ,IAAI,GAAG,GAAG,IAAI,CAAC,EAAE,EAAE;AAC3B,YAAY,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC;AACjD,QAAQ;;AAER,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO;AACnC,QAAQ,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC;AAC1C,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS;;AAEvC;AACA,QAAQ,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;AAC7D,QAAQ,IAAI,iBAAiB,EAAE;AAC/B,YAAY,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE;AACxC,gBAAgB,MAAM,KAAK,GAAG,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC;AACvD,gBAAgB,IAAI,KAAK,EAAE;AAC3B,oBAAoB,KAAK,MAAM,YAAY,IAAI,KAAK,EAAE;AACtD,wBAAwB,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC;AAC/C,oBAAoB;AACpB,gBAAgB;AAChB,YAAY;AACZ,QAAQ;;AAER;AACA,QAAQ,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK;AAC3B,aAAa,GAAG,CAAC,CAAC,GAAG,MAAM;AAC3B,gBAAgB,OAAO,EAAE,QAAQ,CAAC,GAAG,CAAC;AACtC,gBAAgB,KAAK,EAAE,GAAG;AAC1B,gBAAgB,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAClD,aAAa,CAAC;AACd,aAAa,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;;AAEpD,QAAQ,MAAM,CAAC,GAAG,EAAE;AACpB,QAAQ,MAAM,WAAW,GAAG,EAAE;;AAE9B;AACA,QAAQ,KAAK,MAAM,CAAC,IAAI,CAAC,EAAE;AAC3B,YAAY,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,EAAE;;AAE/B,YAAY,IAAI,UAAU,GAAG,IAAI;;AAEjC;AACA,YAAY,KAAK,MAAM,CAAC,IAAI,CAAC,EAAE;AAC/B,gBAAgB,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC;AAC5D,gBAAgB,IAAI,OAAO,GAAG,CAAC,CAAC,QAAQ,EAAE;AAC1C,oBAAoB,UAAU,GAAG,KAAK;AACtC,oBAAoB;AACpB,gBAAgB;AAChB,YAAY;;AAEZ,YAAY,IAAI,UAAU,EAAE;AAC5B,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACzB,YAAY,CAAC,MAAM;AACnB,gBAAgB,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;AACnC,YAAY;AACZ,QAAQ;;AAER;AACA,QAAQ,IAAI,uBAAuB,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE;AACrD,YAAY,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE;AACzC,gBAAgB,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,EAAE;AACnC,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACzB,YAAY;AACZ,QAAQ;;AAER,QAAQ,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC;AACpC,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AAC5B,QAAQ,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC;;AAEvD;AACA,QAAQ,OAAO,CAAC,CAAC,KAAK;AACtB,aAAa,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ;AACnD,aAAa,KAAK,CAAC,CAAC,EAAE,CAAC;AACvB,aAAa,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC;AAChC,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,aAAa,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,GAAG,EAAE;AAC1C,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO;AACnC,QAAQ,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC;AAC1C,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS;;AAEvC,QAAQ,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE;AACxF,YAAY,OAAO,EAAE;AACrB,QAAQ;;AAER;AACA,QAAQ,MAAM,gBAAgB,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,QAAQ,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC;AACxF,QAAQ,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE;AAC3C,YAAY,OAAO,EAAE;AACrB,QAAQ;;AAER;AACA,QAAQ,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,gBAAgB,CAAC;;AAEjD;AACA,QAAQ,MAAM,CAAC,GAAG,IAAI,IAAI;AAC1B,YAAY,gBAAgB,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM;AAC3C,gBAAgB,OAAO,EAAE,QAAQ,CAAC,GAAG,CAAC;AACtC,gBAAgB,KAAK,EAAE,GAAG;AAC1B,gBAAgB,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAClD,aAAa,CAAC,CAAC;AACf,YAAY,CAAC,IAAI,KAAK,IAAI,CAAC,QAAQ;AACnC,YAAY,KAAK;AACjB,SAAS;;AAET;AACA,QAAQ,MAAM,CAAC,GAAG,IAAI,IAAI;AAC1B,YAAY,gBAAgB,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM;AAC3C,gBAAgB,OAAO,EAAE,QAAQ,CAAC,GAAG,CAAC;AACtC,gBAAgB,KAAK,EAAE,GAAG;AAC1B,gBAAgB,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAClD,aAAa,CAAC,CAAC;AACf,YAAY,CAAC,IAAI,KAAK,IAAI,CAAC,QAAQ;AACnC,YAAY,KAAK;AACjB,SAAS;;AAET;AACA;AACA,QAAQ,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE;AACzB,YAAY,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE;AAC7B,YAAY,IAAI,CAAC,CAAC,EAAE;AACpB,YAAY,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,IAAI,QAAQ;;AAE5D;AACA,YAAY,IAAI,CAAC,CAAC,KAAK,GAAG,aAAa,EAAE;AACzC,gBAAgB;AAChB,YAAY;;AAEZ,YAAY,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;AAC1D,YAAY,IAAI,CAAC,KAAK,EAAE;;AAExB,YAAY,KAAK,MAAM,YAAY,IAAI,KAAK,EAAE;AAC9C,gBAAgB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE;AAChD,oBAAoB,MAAM,gBAAgB,GAAG,QAAQ,CAAC,YAAY,CAAC;AACnE;AACA,oBAAoB,IAAI,CAAC,gBAAgB,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE;;AAEnF;AACA,oBAAoB,IAAI,YAAY,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE;;AAE1D,oBAAoB,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;AAC7C,oBAAoB,MAAM,MAAM,GAAG,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAC;;AAE9D,oBAAoB,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,IAAI,QAAQ;AACvE,oBAAoB,IAAI,MAAM,GAAG,gBAAgB,IAAI,CAAC,CAAC,MAAM,GAAG,EAAE,EAAE;AACpE,wBAAwB,CAAC,CAAC,IAAI,CAAC;AAC/B,4BAA4B,OAAO,EAAE,gBAAgB;AACrD,4BAA4B,KAAK,EAAE,YAAY;AAC/C,4BAA4B,QAAQ,EAAE,MAAM;AAC5C,yBAAyB,CAAC;AAC1B,wBAAwB,CAAC,CAAC,IAAI,CAAC;AAC/B,4BAA4B,OAAO,EAAE,gBAAgB;AACrD,4BAA4B,KAAK,EAAE,YAAY;AAC/C,4BAA4B,QAAQ,EAAE,MAAM;AAC5C,yBAAyB,CAAC;;AAE1B,wBAAwB,IAAI,CAAC,CAAC,MAAM,GAAG,EAAE,EAAE;AAC3C,4BAA4B,CAAC,CAAC,GAAG,EAAE;AACnC,wBAAwB;AACxB,oBAAoB;AACpB,gBAAgB;AAChB,YAAY;AACZ,QAAQ;;AAER;AACA,QAAQ,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;AAC/D,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE;AACjB;AACA,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;AAC5C,YAAY,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC;AAC7E,QAAQ;;AAER;AACA,QAAQ,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,YAAY,YAAY,CAAC,CAAC,EAAE;AACvE,YAAY,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC;AAC3D,QAAQ;;AAER,QAAQ,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG;;AAElC;AACA,QAAQ,IAAI,IAAI,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE;AACrE,YAAY,OAAO,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC;AAC5C,QAAQ;;AAER,QAAQ,IAAI,UAAU,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC;;AAEtC;AACA,QAAQ,KAAK,IAAI,GAAG,GAAG,IAAI,CAAC,EAAE,EAAE,GAAG,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE;AAChD,YAAY,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,GAAG,CAAC;AACpE,YAAY,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE;AACnC,gBAAgB,UAAU,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC9C,YAAY;AACZ,QAAQ;;AAER;AACA,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;;AAEnF;AACA,QAAQ,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE;AACjC,YAAY,OAAO,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC;AAC5C,QAAQ;;AAER;AACA,QAAQ,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACjC,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE;AACzB,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO;AACnC,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS;AACvC,QAAQ,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM;;AAEjC,QAAQ,IAAI,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE;;AAE9B;AACA,QAAQ,MAAM,UAAU,GAAG,EAAE;AAC7B,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AACpC,YAAY,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC;AACvC;AACA,YAAY,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE;;AAEzD,YAAY,UAAU,CAAC,IAAI,CAAC;AAC5B,gBAAgB,OAAO,EAAE,OAAO;AAChC,gBAAgB,KAAK,EAAE,CAAC;AACxB,gBAAgB,QAAQ,EAAE,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC;AAC5C,aAAa,CAAC;AACd,QAAQ;;AAER,QAAQ,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;AAC1D,QAAQ,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACrC,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,IAAI,EAAE;AAClC,QAAQ,MAAM,SAAS,GAAG,EAAE,IAAI,IAAI,CAAC,GAAG;;AAExC,QAAQ,IAAI,IAAI,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE;AACtC,YAAY;AACZ,QAAQ;;AAER,QAAQ,IAAI,UAAU,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC;;AAEtC;AACA,QAAQ,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;AAClD,QAAQ,IAAI,SAAS,IAAI,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE;AAC1D,YAAY,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAC1C,iBAAiB,MAAM,CAAC,CAAC,GAAG,KAAK,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,SAAS;AAClE,iBAAiB,GAAG,CAAC,CAAC,GAAG,MAAM;AAC/B,oBAAoB,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;AAChD,oBAAoB,KAAK,EAAE,GAAG;AAC9B,oBAAoB,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAClE,iBAAiB,CAAC,CAAC;AACnB,YAAY,MAAM;AAClB,gBAAgB,KAAK,EAAE,IAAI,CAAC,EAAE;AAC9B,gBAAgB,UAAU,EAAE,gBAAgB;AAC5C,aAAa;AACb,QAAQ;;AAER,QAAQ,KAAK,IAAI,GAAG,GAAG,IAAI,CAAC,EAAE,EAAE,GAAG,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE;AAChD,YAAY,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,GAAG,CAAC;AACpE,YAAY,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE;AACpD;AACA,YAAY,UAAU,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,UAAU;AAC3E,QAAQ;;AAER,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;AACnF,QAAQ,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE;AAC9C,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,IAAI,GAAG;AACf,QAAQ,OAAO,IAAI,CAAC,SAAS,EAAE,MAAM,IAAI,CAAC;AAC1C,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,UAAU,GAAG;AACrB,QAAQ,OAAO,IAAI,CAAC,EAAE,GAAG,CAAC;AAC1B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,KAAK,EAAE;AACvB,QAAQ,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;AACpC,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,eAAe,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE;AAC9B,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS;AACvC,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE;;AAEpD,QAAQ,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC;AACnC,QAAQ,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE;;AAE/B,QAAQ,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;AACtC,IAAI;AACJ;;AC/tBA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,MAAM,SAAS,GAAG,CAAC;AAChC;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,QAAQ,EAAE,UAAU,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;AAC1E,QAAQ,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,UAAU,CAAC,CAAC;AAClE;AACA;AACA;AACA;AACA,QAAQ,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,UAAU;AACpC,YAAY,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;AAClE,YAAY,CAAC;AACb,SAAS;AACT,IAAI;;AAEJ;AACA,IAAI,IAAI,OAAO,GAAG;AAClB,QAAQ,OAAO,IAAI,CAAC,WAAW,CAAC,MAAM;AACtC,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,UAAU,CAAC,QAAQ,EAAE,KAAK,EAAE;AAChC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE;AACnC,YAAY,OAAO,IAAI;AACvB,QAAQ;;AAER,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE;AACnC,YAAY,OAAO,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC9C,QAAQ;;AAER,QAAQ,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM;AAC5C,QAAQ,MAAM,IAAI,GAAG,KAAK,GAAG,CAAC;;AAE9B;AACA,QAAQ,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAClE,QAAQ,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;AAC3D,QAAQ,MAAM,WAAW,GAAG,QAAQ,CAAC,WAAW,CAAC;;AAEjD;AACA,QAAQ,MAAM,YAAY,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC;AAC3D,QAAQ,MAAM,aAAa,GAAG,QAAQ,CAAC,KAAK,CAAC,WAAW,GAAG,CAAC,CAAC;;AAE7D,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,YAAY,EAAE,KAAK,GAAG,CAAC,CAAC;AAC7D,QAAQ,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,EAAE,KAAK,GAAG,CAAC,CAAC;;AAE/D,QAAQ,OAAO,IAAI,UAAU,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC;AAC7D,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,eAAe,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE;AAC9B,QAAQ,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAChD,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE;AACrB;AACA,QAAQ,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC;;AAE7D,QAAQ,IAAI,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC;;AAEtD;AACA;AACA,QAAQ,MAAM,MAAM,GAAG,EAAE;AACzB,QAAQ,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;AAChC,YAAY,MAAM,IAAI;AACtB,gBAAgB,IAAI,CAAC,GAAG;AACxB,aAAa;AACb,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,gBAAgB,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO;AACnD,gBAAgB,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK;AAC/C,gBAAgB,QAAQ,EAAE,IAAI,CAAC,KAAK;AACpC,aAAa,CAAC;AACd,QAAQ;AACR,QAAQ,OAAO,MAAM,CAAC,OAAO,EAAE;AAC/B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,iBAAiB,CAAC,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE;AAC7C,QAAQ,IAAI,IAAI,KAAK,IAAI,EAAE;;AAE3B,QAAQ,IAAI,IAAI,YAAY,UAAU,EAAE;AACxC,YAAY,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;AACjE,YAAY,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;AACjC,gBAAgB,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAChE,YAAY,CAAC,MAAM,IAAI,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,KAAK,IAAI,QAAQ,CAAC,EAAE;AAC/D,gBAAgB,IAAI,CAAC,GAAG,EAAE;AAC1B,gBAAgB,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAChE,YAAY;AACZ,YAAY;AACZ,QAAQ;;AAER;AACA,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI;AAC9B,QAAQ,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK;AAChC,QAAQ,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;AAC9C,QAAQ,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC;;AAExC;AACA,QAAQ,MAAM,YAAY,GAAG,WAAW,GAAG,UAAU,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK;AAC9E,QAAQ,MAAM,aAAa,GAAG,WAAW,GAAG,UAAU,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI;;AAE/E;AACA,QAAQ,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC;;AAE7D;AACA;AACA,QAAQ,MAAM,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,UAAU,CAAC;AACnE,QAAQ,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,EAAE,KAAK,IAAI,QAAQ;;AAE5D;AACA,QAAQ,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC;AAC/D,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;AAC7B,YAAY,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;AAC9D,QAAQ,CAAC,MAAM,IAAI,WAAW,GAAG,cAAc,EAAE;AACjD,YAAY,IAAI,CAAC,GAAG,EAAE;AACtB,YAAY,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;AAC9D,QAAQ;;AAER;AACA,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,gBAAgB,IAAI,IAAI,CAAC,KAAK,EAAE,KAAK,IAAI,QAAQ,CAAC,EAAE;AACnF,YAAY,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,CAAC,EAAE,aAAa,EAAE,IAAI,CAAC;AAClE,QAAQ;AACR,IAAI;AACJ;;AAEA;AACA;AACA;AACA;AACA,MAAM,UAAU,CAAC;AACjB;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE;AACxD,QAAQ,IAAI,CAAC,KAAK,GAAG,KAAK;AAC1B,QAAQ,IAAI,CAAC,IAAI,GAAG,IAAI;AACxB,QAAQ,IAAI,CAAC,IAAI,GAAG,IAAI;AACxB,QAAQ,IAAI,CAAC,KAAK,GAAG,KAAK;AAC1B,IAAI;AACJ;;AAEA;AACA;AACA;AACA;AACA,MAAM,UAAU,CAAC;AACjB;AACA;AACA;AACA,IAAI,WAAW,CAAC,KAAK,EAAE;AACvB,QAAQ,IAAI,CAAC,KAAK,GAAG,KAAK;AAC1B,IAAI;AACJ;;AC/MA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,GAAG,SAAS,GAAG,CAAC;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW;AACf,QAAQ,QAAQ;AAChB,QAAQ,UAAU,GAAG;AACrB,YAAY,MAAM,EAAE,SAAS;AAC7B,YAAY,aAAa,EAAE,EAAE;AAC7B,YAAY,gBAAgB,EAAE,EAAE;AAChC,YAAY,IAAI,EAAE,IAAI;AACtB,SAAS;AACT,MAAM;AACN;AACA,QAAQ,MAAM,WAAW,GAAG,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;AAC3D,QAAQ,MAAM,YAAY,qBAAqB,WAAW,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;;AAEjG,QAAQ,KAAK,CAAC,CAAC,YAAY,CAAC,EAAE,UAAU,CAAC;;AAEzC,QAAQ,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,IAAI,SAAS;AAC3D,QAAQ,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,WAAW,CAAC,aAAa,IAAI,EAAE;AAClE,QAAQ,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,WAAW,CAAC,gBAAgB,IAAI,EAAE;AACxE,QAAQ,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,IAAI,IAAI;AAClD,QAAQ,IAAI,CAAC,WAAW,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;;AAErD;AACA;AACA,QAAQ,IAAI,CAAC,WAAW,GAAG,EAAE;;AAE7B;AACA;AACA,QAAQ,IAAI,CAAC,YAAY,GAAG,EAAE;;AAE9B;AACA;AACA,QAAQ,IAAI,CAAC,QAAQ,GAAG,EAAE;;AAE1B;AACA;AACA,QAAQ,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC,MAAM;;AAEvC;AACA,QAAQ,IAAI,CAAC,wBAAwB,EAAE;;AAEvC;AACA,QAAQ,IAAI,CAAC,WAAW,EAAE;AAC1B;AACA,YAAY,IAAI,CAAC,SAAS,GAAG,EAAE;AAC/B,QAAQ,CAAC,MAAM;AACf;AACA;AACA,YAAY,IAAI,CAAC,SAAS,GAAG,EAAE;AAC/B,YAAY,IAAI,CAAC,WAAW,GAAG,EAAE;AACjC,YAAY,IAAI,CAAC,YAAY,GAAG,EAAE;AAClC,YAAY,IAAI,CAAC,QAAQ,GAAG,EAAE;AAC9B,YAAY,IAAI,CAAC,wBAAwB,EAAE;AAC3C,YAAY,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC9B,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,wBAAwB,GAAG;AAC/B,QAAQ,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC;;AAElD,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC,EAAE,EAAE;AACtD,YAAY,MAAM,gBAAgB,GAAG,EAAE;AACvC,YAAY,MAAM,YAAY,GAAG,EAAE;;AAEnC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC,EAAE,EAAE;AAC7D;AACA,gBAAgB,MAAM,UAAU,GAAG,IAAI,YAAY,CAAC,GAAG,CAAC;AACxD,gBAAgB,IAAI,IAAI,GAAG,CAAC;AAC5B,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE;AAC9C;AACA,oBAAoB,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM;AACtD,oBAAoB,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM;AACtD,oBAAoB,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;AACvF,oBAAoB,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC;AACrC,oBAAoB,IAAI,IAAI,CAAC,GAAG,CAAC;AACjC,gBAAgB;AAChB;AACA,gBAAgB,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AACtC,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE;AAC9C,oBAAoB,UAAU,CAAC,CAAC,CAAC,IAAI,IAAI;AACzC,gBAAgB;;AAEhB,gBAAgB,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC;AACjD;AACA,gBAAgB,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;AAC1D,YAAY;;AAEZ,YAAY,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,gBAAgB,CAAC;AACpD,YAAY,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC;AAC5C,YAAY,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC;AAC5C,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,YAAY,CAAC,OAAO,EAAE,UAAU,EAAE;AACtC,QAAQ,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC;AACzD,QAAQ,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC;AACjD,QAAQ,MAAM,IAAI,GAAG,EAAE;;AAEvB,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC,EAAE,EAAE;AACzD;AACA,YAAY,IAAI,GAAG,GAAG,CAAC;AACvB,YAAY,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC;AACvC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AACrD,gBAAgB,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;AAC3C,YAAY;AACZ;AACA,YAAY,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AACvD,YAAY,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;AAC7B,QAAQ;;AAER,QAAQ,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;AAC7B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,GAAG,CAAC,QAAQ,EAAE;AAClB;AACA,QAAQ,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM;AAChD,QAAQ,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC;;AAExD;AACA,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AAClD,YAAY,MAAM,WAAW,GAAG,UAAU,GAAG,CAAC;AAC9C,YAAY,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC;;AAEvC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC,EAAE,EAAE;AAC1D,gBAAgB,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC;AAC1D,gBAAgB,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;;AAEjD,gBAAgB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;AACtC,oBAAoB,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;AACvC,gBAAgB;AAChB,gBAAgB,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;AAC9C,gBAAgB,IAAI,MAAM,EAAE;AAC5B,oBAAoB,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC;AAC5C,gBAAgB;AAChB,YAAY;AACZ,QAAQ;;AAER,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE;AACzB,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO;AACnC,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS;;AAEvC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,OAAO,EAAE;;AAE5C;AACA,QAAQ,MAAM,UAAU,GAAG,IAAI,GAAG,EAAE;;AAEpC,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC,EAAE,EAAE;AACtD,YAAY,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC;AACpD,YAAY,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;AAC7C,YAAY,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;;AAE1C,YAAY,IAAI,MAAM,EAAE;AACxB,gBAAgB,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE;AAC1C,oBAAoB,IAAI,GAAG,KAAK,SAAS,EAAE;AAC3C,wBAAwB,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC;AAC3C,oBAAoB;AACpB,gBAAgB;AAChB,YAAY;AACZ,QAAQ;;AAER;AACA,QAAQ,IAAI,UAAU,CAAC,IAAI,GAAG,CAAC,EAAE;AACjC;AACA;;AAEA;AACA,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,cAAc,IAAI,UAAU,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AACjF,gBAAgB,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;AACjD,gBAAgB,KAAK,MAAM,GAAG,MAAM,CAAC,IAAI,KAAK,EAAE;AAChD,oBAAoB,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE;AAC9C,wBAAwB,IAAI,GAAG,KAAK,SAAS,EAAE;AAC/C,4BAA4B,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC;AAC/C,4BAA4B,IAAI,UAAU,CAAC,IAAI,IAAI,CAAC,EAAE;AACtD,wBAAwB;AACxB,oBAAoB;AACpB,oBAAoB,IAAI,UAAU,CAAC,IAAI,IAAI,CAAC,EAAE;AAC9C,gBAAgB;AAChB,YAAY;;AAEZ;AACA,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,IAAI,UAAU,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AAC7E,gBAAgB,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;AACjC,YAAY;AACZ,QAAQ;;AAER;AACA;AACA,QAAQ,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC;;AAE7D,QAAQ,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE;AACtC,YAAY,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC;AACzC,YAAY,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,EAAE;;AAE7D,YAAY,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC;;AAE/C,YAAY,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;AACjC,gBAAgB,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AACzD,YAAY,CAAC,MAAM,IAAI,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,KAAK,IAAI,QAAQ,CAAC,EAAE;AAC/D,gBAAgB,IAAI,CAAC,GAAG,EAAE;AAC1B,gBAAgB,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AACzD,YAAY;AACZ,QAAQ;;AAER;AACA;AACA,QAAQ,MAAM,MAAM,GAAG,EAAE;AACzB,QAAQ,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;AAChC,YAAY,MAAM,IAAI,mFAAmF,IAAI,CAAC,GAAG,EAAE,CAAC;AACpH,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,gBAAgB,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;AACrD,gBAAgB,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK;AACzC,gBAAgB,QAAQ,EAAE,IAAI,CAAC,KAAK;AACpC,aAAa,CAAC;AACd,QAAQ;;AAER,QAAQ,OAAO,MAAM,CAAC,OAAO,EAAE;AAC/B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,eAAe,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE;AAC9B,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE;AAC1D,QAAQ,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAChD,IAAI;AACJ;;AC9RA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,QAAQ,SAAS,GAAG,CAAC;AAClC;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,QAAQ,EAAE,UAAU,GAAG,EAAE,EAAE;AAC3C,QAAQ,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,UAAU,CAAC;AACnF,QAAQ,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC;AAC/B,QAAQ,MAAM,CAAC;AACf,YAAY,IAAI,CAAC,SAAS,YAAY,MAAM,sBAAsB,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM;AACnH,QAAQ,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,KAAK,aAAa,EAAE;AACvD,YAAY,IAAI,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,iEAAiE,IAAI,CAAC,SAAS,GAAG;AACnH,QAAQ,CAAC,MAAM;AACf,YAAY,IAAI,CAAC,EAAE,GAAG,eAAe;AACrC,4DAA4D,IAAI,CAAC,SAAS;AAC1E,gBAAgB,IAAI,CAAC,WAAW,CAAC,MAAM;AACvC,aAAa;AACb,QAAQ;;AAER;AACA,QAAQ,IAAI,CAAC,GAAG,GAAG,EAAE;AACrB,QAAQ,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE;AAC1C,YAAY,MAAM,SAAS,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC;AAC9C;AACA,YAAY,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC;AAC3D,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxC,gBAAgB,CAAC,CAAC,IAAI,CAAC;AACvB,oBAAoB,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC;AACvC,oBAAoB,KAAK,EAAE,CAAC;AAC5B,iBAAiB,CAAC;AAClB,YAAY;AACZ,YAAY,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AAC5B,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,eAAe,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE;AAC9B,QAAQ,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,KAAK,aAAa,EAAE;AACvD,YAAY,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACjC;AACA,YAAY,MAAM,MAAM,GAAG,EAAE;AAC7B,YAAY,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;AACrC,YAAY,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC;AACnE,YAAY,MAAM,CAAC;AACnB,gBAAgB,IAAI,CAAC,SAAS,YAAY,MAAM,sBAAsB,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM;AACvH,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE;AACrD,gBAAgB,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,EAAE;AAC5C,gBAAgB,IAAI,CAAC,IAAI,EAAE;AAC3B,gBAAgB,MAAM,CAAC,IAAI,CAAC;AAC5B,oBAAoB,OAAO;AAC3B,wBAAwB,IAAI,CAAC,SAAS,YAAY;AAClD,iDAAiD,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK;AACxF,8BAA8B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK;AAC/D,qBAAqB;AACrB,oBAAoB,KAAK,yBAAyB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;AACrE,oBAAoB,QAAQ,yBAAyB,IAAI,CAAC,KAAK,CAAC;AAChE,iBAAiB,CAAC;AAClB,YAAY;AACZ,YAAY,OAAO,MAAM;AACzB,QAAQ;AACR,QAAQ,OAAO,IAAI,CAAC,MAAM;AAC1B;AACA,gBAAgB,IAAI,CAAC,SAAS,YAAY,MAAM,sBAAsB,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;AAChH;AACA,YAAY,CAAC;AACb,SAAS;AACT,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE;AACrB,QAAQ,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,KAAK,aAAa,EAAE;AACvD,YAAY,MAAM,IAAI,KAAK,CAAC,wFAAwF,CAAC;AACrH,QAAQ;AACR;AACA,QAAQ,MAAM,MAAM,uBAAuB,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;;AAEnE,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,YAAY,MAAM;AACzD,QAAQ,MAAM,WAAW,uBAAuB,IAAI,CAAC,SAAS,CAAC;AAC/D,QAAQ,MAAM,CAAC,GAAG,QAAQ,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM;;AAEzE;AACA,QAAQ,MAAM,SAAS,GAAG,EAAE;AAC5B,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AACpC,YAAY,MAAM,OAAO,qBAAqB,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAChG,YAAY,SAAS,CAAC,IAAI,CAAC;AAC3B,gBAAgB,OAAO,EAAE,OAAO;AAChC,gBAAgB,KAAK,EAAE,CAAC;AACxB,gBAAgB,QAAQ,EAAE,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC;AAC5C,aAAa,CAAC;AACd,QAAQ;;AAER;AACA,QAAQ,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;AACzD,QAAQ,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACpC,IAAI;AACJ;;ACtHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,SAAS,SAAS,GAAG,CAAC;AACnC;AACA;AACA;AACA;AACA,IAAI,EAAE,GAAG,EAAE;AACX;AACA;AACA;AACA;AACA,IAAI,EAAE,GAAG,EAAE;;AAEX;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,QAAQ,EAAE,UAAU,GAAG,EAAE,EAAE;AAC3C,QAAQ,KAAK;AACb,YAAY,QAAQ;AACpB;AACA,gBAAgB,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,UAAU;AACvG;AACA,SAAS;AACT,QAAQ,IAAI,CAAC,EAAE,GAAG,QAAQ,CAAC,MAAM;AACjC,QAAQ,IAAI,CAAC,WAAW,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;AAChE,QAAQ,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG;;AAE3E,QAAQ,IAAI,CAAC,mBAAmB,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK;AAC1D,YAAY,OAAO;AACnB,gBAAgB,KAAK,EAAE,CAAC;AACxB,gBAAgB,KAAK,EAAE,CAAC;AACxB,gBAAgB,IAAI,EAAE,IAAI;AAC1B,aAAa;AACb,QAAQ,CAAC,CAAC;;AAEV,QAAQ,IAAI,QAAQ,EAAE;AACtB,YAAY,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;AAC9B,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,CAAC,CAAC,EAAE;AACf,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM;AAC1B,QAAQ,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY;AAC7C,QAAQ,IAAI,WAAW,GAAG,CAAC,EAAE;AAC7B,YAAY,OAAO,CAAC;AACpB,QAAQ,CAAC,MAAM;AACf,YAAY,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW;AAC/C,YAAY,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,CAAC;AACpD,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE;AAClB,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;;AAExC,QAAQ,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK;AAC7B,QAAQ,IAAI,KAAK,IAAI,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE;AAC3D,YAAY,MAAM,IAAI,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AACvC,YAAY,MAAM,UAAU,GAAG,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC;AACzD,YAAY,IAAI,IAAI,IAAI,UAAU,EAAE;AACpC,gBAAgB,OAAO,CAAC,CAAC;AACzB,YAAY;AACZ,QAAQ;;AAER,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACjB,QAAQ,CAAC,CAAC,IAAI,GAAG,IAAI;AACrB,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE;AACjD,YAAY,CAAC,CAAC,GAAG,EAAE;AACnB,QAAQ;AACR,QAAQ,OAAO,CAAC;AAChB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,QAAQ,CAAC,CAAC,EAAE;AAChB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,CAAC,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC;AAC9B,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AACpC,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AACrB,QAAQ;AACR,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AACpC,YAAY,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;AAC3B,YAAY,IAAI,EAAE,EAAE;AACpB,gBAAgB,MAAM,MAAM,GAAG,EAAE,CAAC,IAAI,EAAE;AACxC,gBAAgB,KAAK,MAAM,QAAQ,IAAI,MAAM,EAAE;AAC/C,oBAAoB,MAAM,CAAC,GAAG,QAAQ,CAAC,KAAK;AAC5C,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;AACvC,gBAAgB;AAChB,YAAY;AACZ,QAAQ;AACR,QAAQ,OAAO,CAAC;AAChB,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,GAAG,CAAC,QAAQ,EAAE;AAClB,QAAQ,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW;AAC3C,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM;AAC9C,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO;AAC1C,QAAQ,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK;AAC5C,QAAQ,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM;AACjC,QAAQ,IAAI,CAAC,EAAE,GAAG,CAAC;AACnB;AACA,QAAQ,MAAM,CAAC,GAAG,EAAE;AACpB,QAAQ,IAAI,CAAC,EAAE,GAAG,CAAC;AACnB,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AACpC,YAAY,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;AACjC,YAAY,MAAM,MAAM,GAAG;AAC3B,iBAAiB,MAAM;AACvB,oBAAoB,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;AAC5D,oBAAoB,CAAC;AACrB;AACA,iBAAiB,GAAG,CAAC,CAAC,CAAC,KAAK;AAC5B,oBAAoB,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE;AACnF,gBAAgB,CAAC,CAAC;AAClB,YAAY,MAAM,EAAE,GAAG,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC;AACpE,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;AACtB,QAAQ;;AAER,QAAQ,IAAI,CAAC,GAAG,QAAQ;AACxB,QAAQ,IAAI,KAAK,GAAG,CAAC,QAAQ;AAC7B,QAAQ,OAAO,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,EAAE;AACjD,YAAY,MAAM,IAAI,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC;AACrC,YAAY,MAAM,IAAI,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC;AACrC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AACxC,gBAAgB,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;AACtC,gBAAgB,MAAM,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACzD,gBAAgB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;AACrE,gBAAgB,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE;AACxC,oBAAoB,CAAC,CAAC,IAAI,GAAG,KAAK;AAClC,gBAAgB;AAChB,gBAAgB,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC;AACxE,gBAAgB,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC;AACvE,YAAY;AACZ,YAAY,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;AACnD,YAAY,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;AACnD,YAAY,KAAK,GAAG,CAAC;AACrB,YAAY,CAAC,GAAG,CAAC;AACjB,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AACxC,gBAAgB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9D,oBAAoB,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACnC,gBAAgB;AAChB,gBAAgB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE;AAC9D,oBAAoB,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACnC,gBAAgB;;AAEhB,gBAAgB,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;AAC5C,gBAAgB,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;AAC5C,gBAAgB,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM;AACvC,gBAAgB,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM;AACvC,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE;AAC7C,oBAAoB,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC;AACvC,oBAAoB,MAAM,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC;AAC3C,oBAAoB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE;AACjD,wBAAwB,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC;AAC3C,wBAAwB,IAAI,EAAE,CAAC,KAAK,KAAK,EAAE,CAAC,KAAK,EAAE;AACnD,wBAAwB,MAAM,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC;AAC/C,wBAAwB,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC;AAClD,wBAAwB,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC;AAClD,oBAAoB;AACpB,oBAAoB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE;AACjD,wBAAwB,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC;AAC3C,wBAAwB,IAAI,EAAE,CAAC,KAAK,KAAK,EAAE,CAAC,KAAK,EAAE;AACnD,wBAAwB,MAAM,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC;AAC/C,wBAAwB,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC;AAClD,wBAAwB,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC;AAClD,oBAAoB;AACpB,gBAAgB;AAChB,YAAY;AACZ,QAAQ;AACR,QAAQ,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC;AACpD,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE;AACrB,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM;AAC9C,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS;;AAEvC,QAAQ,IAAI,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE;AAC9B,QAAQ,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM;;AAEhC;AACA,QAAQ,MAAM,OAAO,GAAG,IAAI,GAAG,EAAE;AACjC;AACA,QAAQ,IAAI,IAAI,GAAG,EAAE;;AAErB;AACA,QAAQ,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW;AAC3C,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;AACpE,YAAY,IAAI,GAAG;AACnB,YAAY,GAAG;AACf,gBAAgB,GAAG,GAAG,UAAU,CAAC,UAAU,GAAG,CAAC;AAC/C,YAAY,CAAC,QAAQ,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;AACrC,YAAY,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;;AAE5B,YAAY,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC;AACzC,YAAY,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO,EAAE;;AAExD,YAAY,IAAI,CAAC,IAAI,CAAC;AACtB,gBAAgB,KAAK,EAAE,GAAG;AAC1B,gBAAgB,IAAI,EAAE,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC;AACxC,gBAAgB,SAAS,EAAE,KAAK;AAChC,aAAa,CAAC;AACd,QAAQ;;AAER,QAAQ,IAAI,SAAS,GAAG,IAAI;AAC5B,QAAQ,OAAO,SAAS,EAAE;AAC1B,YAAY,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC;AAChD;AACA,YAAY,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;;AAErD,YAAY,SAAS,GAAG,KAAK;AAC7B,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AAClD,gBAAgB,MAAM,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC;AACzC,gBAAgB,IAAI,SAAS,CAAC,SAAS,EAAE;;AAEzC,gBAAgB,SAAS,CAAC,SAAS,GAAG,IAAI;AAC1C,gBAAgB,SAAS,GAAG,IAAI;;AAEhC;AACA,gBAAgB,MAAM,SAAS,GAAG,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC;AAC1D,gBAAgB,IAAI,CAAC,SAAS,EAAE;;AAEhC,gBAAgB,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE;AAClD,oBAAoB,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK;AAChD,oBAAoB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;AAC7C,wBAAwB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;AAC1C,wBAAwB,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC;AACvD,wBAAwB,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO,EAAE;AACnE,4BAA4B,IAAI,CAAC,IAAI,CAAC;AACtC,gCAAgC,KAAK,EAAE,KAAK;AAC5C,gCAAgC,IAAI,EAAE,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC;AACxD,gCAAgC,SAAS,EAAE,KAAK;AAChD,6BAA6B,CAAC;AAC9B,wBAAwB;AACxB,oBAAoB;AACpB,gBAAgB;AAChB;AACA;AACA,YAAY;AACZ,QAAQ;;AAER,QAAQ,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC;;AAE5C;AACA,QAAQ,MAAM,MAAM,GAAG,EAAE;AACzB,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE;AAC3D,YAAY,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC;AAChC,YAAY,MAAM,CAAC,IAAI,CAAC;AACxB,gBAAgB,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC;AAC7C,gBAAgB,KAAK,EAAE,IAAI,CAAC,KAAK;AACjC,gBAAgB,QAAQ,EAAE,IAAI,CAAC,IAAI;AACnC,aAAa,CAAC;AACd,QAAQ;AACR,QAAQ,OAAO,MAAM;AACrB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,eAAe,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE;AAC9B;AACA,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS;AACvC,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE;;AAEpD,QAAQ,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC;AACnC,QAAQ,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE;;AAE/B,QAAQ,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;AACtC,IAAI;AACJ;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,MAAM,OAAO,SAAS,IAAI,CAAC;AAC3B;AACA,IAAI,GAAG;;AAEP;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE;AAChD,QAAQ,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,CAAC;AACzC,QAAQ,IAAI,CAAC,GAAG,GAAG,IAAI,GAAG,EAAE;AAC5B,QAAQ,IAAI,QAAQ,EAAE;AACtB,YAAY,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;AAC5C,gBAAgB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;AAClC,YAAY;AACZ,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,IAAI,CAAC,OAAO,EAAE;AAClB,QAAQ,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG;AAC5B,QAAQ,IAAI,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;AACpC,YAAY,OAAO,IAAI;AACvB,QAAQ,CAAC,MAAM;AACf,YAAY,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC;AAClC,YAAY,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC;AAC/B,YAAY,OAAO,IAAI;AACvB,QAAQ;AACR,IAAI;;AAEJ;AACA,IAAI,GAAG,GAAG;AACV,QAAQ,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,EAAE;AAClC,QAAQ,IAAI,MAAM,EAAE,OAAO,EAAE;AAC7B,YAAY,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;AACjD,YAAY,OAAO,MAAM;AACzB,QAAQ;AACR,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA,IAAI,IAAI,GAAG;AACX,QAAQ,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC;AACpD,IAAI;AACJ;;ACvYA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,MAAM,SAAS,EAAE,CAAC;AAC/B;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,CAAC,EAAE,UAAU,GAAG,EAAE,EAAE;AACpC,QAAQ,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,UAAU,CAAC;AACrG,IAAI;;AAEJ;AACA;AACA;AACA,IAAI,CAAC,SAAS,GAAG;AACjB,QAAQ,IAAI,CAAC,UAAU,EAAE;AACzB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AACxB,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;AAC5B,QAAQ,MAAM,CAAC,0BAA0B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;AAC7D,QAAQ,MAAM,MAAM,oDAAoD,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;AACjG,QAAQ,MAAM,UAAU,0BAA0B,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;AAC/E,QAAQ,MAAM,OAAO,0BAA0B,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;;AAEzE,QAAQ,MAAM,gBAAgB,GAAG,MAAM,KAAK,aAAa,GAAG,CAAC,GAAG,eAAe,CAAC,CAAC,EAAE,MAAM,CAAC;;AAE1F,QAAQ,IAAI,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC;;AAE9E;AACA,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAChC,YAAY,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI;AAC9D,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,EAAE;AAC3C,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC;AACvC,YAAY;AACZ,QAAQ;;AAER,QAAQ,IAAI,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC;;AAE3C,QAAQ,IAAI,WAAW,GAAG,QAAQ;;AAElC,QAAQ,IAAI,EAAE,UAAU,GAAG,CAAC,CAAC,EAAE;AAC/B,YAAY,MAAM,IAAI,CAAC,UAAU;AACjC,YAAY,OAAO,IAAI,CAAC,UAAU;AAClC,QAAQ;;AAER,QAAQ,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,UAAU,EAAE,EAAE,IAAI,EAAE;AACtD,YAAY,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;;AAE/C,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,EAAE;AAC3C,gBAAgB,IAAI,GAAG,GAAG,CAAC;AAC3B,gBAAgB,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACpC,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,EAAE;AAC/C,oBAAoB,IAAI,CAAC,KAAK,CAAC,EAAE;AACjC,oBAAoB,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACxC,oBAAoB,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC;AACtD,oBAAoB,MAAM,WAAW,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;;AAEpE,oBAAoB,IAAI,GAAG,GAAG,CAAC;AAC/B,oBAAoB,IAAI,MAAM,GAAG,KAAK,EAAE;AACxC,wBAAwB,GAAG,GAAG,CAAC,WAAW,GAAG,MAAM;AACnD,oBAAoB;AACpB,oBAAoB,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC;AAC1C,oBAAoB,GAAG,IAAI,GAAG;AAC9B,gBAAgB;AAChB,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC;AACtC,YAAY;;AAEZ;AACA,YAAY,MAAM,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC;;AAEpE,YAAY,IAAI,CAAC,CAAC,0BAA0B,KAAK,CAAC;AAClD,YAAY,CAAC,0BAA0B,KAAK,CAAC;;AAE7C;AACA,YAAY,IAAI,UAAU,GAAG,CAAC;AAC9B,YAAY,IAAI,UAAU,GAAG,CAAC;AAC9B,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,EAAE;AAC3C,gBAAgB,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACpC,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,EAAE;AACnD,oBAAoB,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACxC,oBAAoB,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC;AACtD,oBAAoB,MAAM,IAAI,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,MAAM;AACtE,oBAAoB,UAAU,IAAI,IAAI,GAAG,IAAI;AAC7C,oBAAoB,UAAU,IAAI,gBAAgB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC;AACnE,gBAAgB;AAChB,YAAY;AACZ,YAAY,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;;AAEtF,YAAY,MAAM,IAAI,CAAC,UAAU;;AAEjC,YAAY,IAAI,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,cAAc,CAAC,GAAG,OAAO,EAAE;AAClE,gBAAgB;AAChB,YAAY;AACZ,YAAY,WAAW,GAAG,cAAc;AACxC,QAAQ;AACR,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA,IAAI,SAAS,GAAG;AAChB,QAAQ,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,EAAE;AACpC,QAAQ,IAAI,GAAG,qBAAqB,IAAI,CAAC,CAAC,CAAC;AAC3C,QAAQ,KAAK,MAAM,IAAI,IAAI,GAAG,EAAE;AAChC,YAAY,GAAG,GAAG,IAAI;AACtB,QAAQ;AACR,QAAQ,OAAO,GAAG;AAClB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACpC,QAAQ,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC;AAC5C,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,QAAQ,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACrC,QAAQ,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC;AAC5C,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,QAAQ,OAAO,EAAE,CAAC,UAAU;AAC5B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,aAAa,eAAe,CAAC,CAAC,EAAE,UAAU,EAAE;AAChD,QAAQ,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC;AAC5C,QAAQ,OAAO,EAAE,CAAC,eAAe,EAAE;AACnC,IAAI;AACJ;;AC3JA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,MAAM,SAAS,EAAE,CAAC;AAC/B;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,CAAC,EAAE,UAAU,GAAG,EAAE,EAAE;AACpC;AACA,QAAQ,MAAM,QAAQ,GAAG;AACzB,YAAY,SAAS,EAAE,CAAC,QAAQ;AAChC,YAAY,CAAC,EAAE,CAAC;AAChB,YAAY,MAAM,EAAE,SAAS;AAC7B,YAAY,IAAI,EAAE,IAAI;AACtB,YAAY,OAAO,EAAE,KAAK;AAC1B,YAAY,QAAQ,EAAE,EAAE;AACxB,SAAS;AACT,QAAQ,KAAK,CAAC,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC;;AAEtC,QAAQ,IAAI,CAAC,QAAQ,GAAG,QAAQ;;AAEhC,QAAQ,IAAI,IAAI,CAAC,WAAW,CAAC,SAAS,KAAK,CAAC,QAAQ,EAAE;AACtD,YAAY,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;AAC7G,QAAQ;;AAER,QAAQ,MAAM,QAAQ,sCAAsC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;AACvF,QAAQ,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE;AAC9C,YAAY,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW;AAC5C,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,CAAC,SAAS,GAAG;AACjB,QAAQ,MAAM,IAAI,CAAC,SAAS,EAAE;AAC9B,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA,IAAI,SAAS,GAAG;AAChB,QAAQ,IAAI,CAAC,UAAU,EAAE;AACzB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AACxB,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;AAC5B,QAAQ,MAAM,CAAC,0BAA0B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;AAC7D,QAAQ,MAAM,MAAM,oCAAoC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;AACjF,QAAQ,MAAM,QAAQ,sCAAsC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;AACvF,QAAQ,MAAM,SAAS,0BAA0B,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;AAC7E;AACA,QAAQ,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;AAC3C,QAAQ,CAAC,CAAC,KAAK,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;;AAE/F;AACA,QAAQ,MAAM,iBAAiB,GAAG,EAAE;AACpC,QAAQ,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,yBAAyB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;AAClH,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,EAAE;AACvC;AACA;AACA,YAAY,MAAM,aAAa,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC;AACxE,YAAY,iBAAiB,CAAC,IAAI;AAClC,gBAAgB,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM;AACnD,oBAAoB,KAAK,EAAE,CAAC,CAAC,KAAK;AAClC,oBAAoB,QAAQ,EAAE,CAAC,CAAC,QAAQ;AACxC,iBAAiB,CAAC,CAAC;AACnB,aAAa;AACb,QAAQ;;AAER;AACA;AACA,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,EAAE;AACvC,YAAY,KAAK,MAAM,QAAQ,IAAI,iBAAiB,CAAC,CAAC,CAAC,EAAE;AACzD,gBAAgB,MAAM,CAAC,GAAG,QAAQ,CAAC,KAAK;AACxC,gBAAgB,MAAM,CAAC,GAAG,QAAQ,CAAC,QAAQ;AAC3C,gBAAgB,MAAM,eAAe,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC;AACvF,gBAAgB,IAAI,CAAC,eAAe,EAAE;AACtC,oBAAoB,iBAAiB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;AACxE,gBAAgB;AAChB,YAAY;AACZ,QAAQ;;AAER;AACA;AACA;AACA,QAAQ,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC;;AAElD,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,EAAE;AACvC,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAChC,YAAY,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC;;AAErF,YAAY,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE;AAC7B,gBAAgB,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE;AACpC,gBAAgB,IAAI,CAAC,IAAI,EAAE;;AAE3B,gBAAgB,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK;AAC5C,gBAAgB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ;;AAEpD,gBAAgB,IAAI,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;;AAE5C,gBAAgB,KAAK,MAAM,QAAQ,IAAI,iBAAiB,CAAC,CAAC,CAAC,EAAE;AAC7D,oBAAoB,MAAM,CAAC,GAAG,QAAQ,CAAC,KAAK;AAC5C,oBAAoB,MAAM,GAAG,GAAG,MAAM,GAAG,QAAQ,CAAC,QAAQ;AAC1D,oBAAoB,IAAI,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;AAC7C,wBAAwB,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC;AAC9C,wBAAwB,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;AAC3D,oBAAoB;AACpB,gBAAgB;AAChB,YAAY;AACZ,QAAQ;;AAER,QAAQ,IAAI,OAAO,GAAG,CAAC;AACvB,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE;AACvC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE;AAC3C,gBAAgB,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACzC,gBAAgB,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,GAAG,OAAO,EAAE,OAAO,GAAG,GAAG;AACpE,YAAY;AACZ,QAAQ;AACR,QAAQ,MAAM,OAAO,GAAG,OAAO,GAAG,EAAE;;AAEpC,QAAQ,MAAM,OAAO,oCAAoC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;;AAEnF,QAAQ,IAAI,OAAO,KAAK,QAAQ,EAAE;AAClC;AACA,YAAY,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK;AAC9D,gBAAgB,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACzC,gBAAgB,OAAO,GAAG,KAAK,QAAQ,GAAG,OAAO,GAAG,GAAG;AACvD,YAAY,CAAC,CAAC;AACd,YAAY,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;AAC3G,YAAY,MAAM,CAAC,SAAS,EAAE;AAC9B,YAAY,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;AAC7B,QAAQ,CAAC,MAAM;AACf;AACA,YAAY,MAAM,IAAI,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK;AAC1D,gBAAgB,IAAI,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACvC,gBAAgB,IAAI,GAAG,KAAK,QAAQ,EAAE,GAAG,GAAG,OAAO;AACnD,gBAAgB,OAAO,GAAG,GAAG,GAAG;AAChC,YAAY,CAAC,CAAC;;AAEd,YAAY,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE;AACvC,YAAY,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE;AACvC,YAAY,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE;AACnC,YAAY,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;;AAEzG;AACA,YAAY,MAAM,EAAE,YAAY,EAAE,CAAC,EAAE,GAAG,2BAA2B,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC;AACnF,YAAY,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE;AAC/C,QAAQ;AACR;AACA,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACpC,QAAQ,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC;AAC5C,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,QAAQ,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACrC,QAAQ,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC;AAC5C,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,QAAQ,OAAO,EAAE,CAAC,UAAU;AAC5B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,aAAa,eAAe,CAAC,CAAC,EAAE,UAAU,EAAE;AAChD,QAAQ,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC;AAC5C,QAAQ,OAAO,EAAE,CAAC,eAAe,EAAE;AACnC,IAAI;AACJ;;ACjNA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,GAAG,SAAS,EAAE,CAAC;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,CAAC,EAAE,UAAU,EAAE;AAC/B,QAAQ,KAAK,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,UAAU,CAAC;AAC3F,QAAQ,MAAM,QAAQ,sCAAsC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;AACvF,QAAQ,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE;AAC9C,YAAY,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW;AAC5C,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,CAAC,SAAS,GAAG;AACjB,QAAQ,MAAM,IAAI,CAAC,SAAS,EAAE;AAC9B,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,SAAS,GAAG;AAChB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AACxB,QAAQ,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK;AACpC,QAAQ,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,WAAW;AACxD,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI,EAAE;AACvD,YAAY,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC;AACpF,QAAQ;;AAER;AACA,QAAQ,MAAM,aAAa,GAAG,EAAE;AAChC,QAAQ,IAAI,QAAQ,GAAG,CAAC;AACxB,QAAQ,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK;AACjC,YAAY,IAAI,CAAC,IAAI,aAAa,EAAE;AACpC,gBAAgB,aAAa,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE;AACxC,gBAAgB,aAAa,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACpD,YAAY,CAAC,MAAM;AACnB,gBAAgB,aAAa,CAAC,CAAC,CAAC,GAAG;AACnC,oBAAoB,EAAE,EAAE,QAAQ,EAAE;AAClC,oBAAoB,KAAK,EAAE,CAAC;AAC5B,oBAAoB,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACpC,iBAAiB;AACjB,YAAY;AACZ,QAAQ,CAAC,CAAC;;AAEV;AACA,QAAQ,MAAM,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE;AACnC,QAAQ,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC;AACjD,QAAQ,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE;AAC3C,YAAY,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC;AAC5D,YAAY,MAAM,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE;AACvC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,EAAE;AAC3C,gBAAgB,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;AACvE,YAAY;AACZ,QAAQ;AACR;AACA,QAAQ,IAAI,GAAG,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC;AACxC,QAAQ,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE;AAC3C,YAAY,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;AACzD,YAAY,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACjE,YAAY,MAAM,CAAC,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK;AAChD,YAAY,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAChD,QAAQ;;AAER;AACA,QAAQ,IAAI,GAAG,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC;AACxC,QAAQ,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE;AAC3C,YAAY,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;AACzD,YAAY,MAAM,CAAC,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,IAAI;AAC/C,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxE,gBAAgB,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvE,gBAAgB,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACpD,YAAY;AACZ,QAAQ;;AAER,QAAQ,MAAM,EAAE,YAAY,EAAE,EAAE,EAAE,GAAG,2BAA2B;AAChE,YAAY,GAAG,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC;AAClC,YAAY,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,GAAG,CAAC,CAAC;AAC7C,YAAY,QAAQ;AACpB,SAAS;AACT,QAAQ,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,SAAS,EAAE;AAC7C,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;;AAEzB;AACA,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACpC;AACA,QAAQ,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC;AACzC,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,QAAQ,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACrC;AACA,QAAQ,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC;AACzC,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,QAAQ,OAAO,EAAE,CAAC,UAAU;AAC5B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,aAAa,eAAe,CAAC,CAAC,EAAE,UAAU,EAAE;AAChD;AACA,QAAQ,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC;AACzC,QAAQ,OAAO,EAAE,CAAC,eAAe,EAAE;AACnC,IAAI;AACJ;;ACrJA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,GAAG,SAAS,EAAE,CAAC;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,CAAC,EAAE,UAAU,EAAE;AAC/B,QAAQ,KAAK;AACb,YAAY,CAAC;AACb,YAAY;AACZ,gBAAgB,SAAS,EAAE,CAAC,QAAQ;AACpC,gBAAgB,CAAC,EAAE,CAAC;AACpB,gBAAgB,MAAM,EAAE,SAAS;AACjC,gBAAgB,IAAI,EAAE,IAAI;AAC1B,gBAAgB,QAAQ,EAAE,EAAE;AAC5B,aAAa;AACb,YAAY,UAAU;AACtB,SAAS;AACT,QAAQ,IAAI,IAAI,CAAC,WAAW,CAAC,SAAS,KAAK,CAAC,QAAQ,EAAE;AACtD,YAAY,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;AACrG,QAAQ;;AAER,QAAQ,MAAM,QAAQ,sCAAsC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;AACvF,QAAQ,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE;AAC9C,YAAY,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW;AAC5C,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,CAAC,SAAS,GAAG;AACjB,QAAQ,MAAM,IAAI,CAAC,SAAS,EAAE;AAC9B,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,SAAS,GAAG;AAChB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AACxB,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;AAC5B,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;AAC5B,QAAQ,MAAM,SAAS,0BAA0B,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;AAC7E,QAAQ,MAAM,CAAC,0BAA0B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;AAC7D,QAAQ,MAAM,QAAQ,sCAAsC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;AACvF,QAAQ,MAAM,MAAM,oCAAoC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;AACjF,QAAQ,MAAM,EAAE,GAAG,mBAAmB,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC;AAC5D,QAAQ,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC;AAC7C,QAAQ,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC;;AAExC,QAAQ,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AAC7C,YAAY,MAAM,MAAM,GAAG,EAAE,CAAC,GAAG,CAAC;AAClC,YAAY,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;AACtG,YAAY,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;AACnC,YAAY,IAAI,SAAS,GAAG,IAAI,EAAE;AAClC,gBAAgB,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI;AAC5D,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,EAAE,CAAC,EAAE;AACpD,oBAAoB,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC;AAC9C,gBAAgB;AAChB,YAAY;AACZ;AACA,YAAY,IAAI,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC;AAC3D,YAAY,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;AACjC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,EAAE,CAAC,EAAE;AAChD,gBAAgB,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC5D,YAAY;AACZ,QAAQ;AACR;AACA,QAAQ,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,CAAC;AACpD,QAAQ,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAC3B,QAAQ,MAAM,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC;;AAEjC;AACA;AACA;AACA,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC;AACtC,QAAQ,MAAM,IAAI,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;;AAExF,QAAQ,MAAM,EAAE,YAAY,EAAE,CAAC,EAAE,GAAG,2BAA2B,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC;AACtF;AACA,QAAQ,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;;AAEjD;AACA,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACpC,QAAQ,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC;AACzC,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,QAAQ,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACrC,QAAQ,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC;AACzC,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,QAAQ,OAAO,EAAE,CAAC,UAAU;AAC5B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,aAAa,eAAe,CAAC,CAAC,EAAE,UAAU,EAAE;AAChD,QAAQ,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC;AACzC,QAAQ,OAAO,EAAE,CAAC,eAAe,EAAE;AACnC,IAAI;AACJ;;AChJA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,GAAG,SAAS,EAAE,CAAC;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,CAAC,EAAE,UAAU,GAAG,EAAE,EAAE;AACpC,QAAQ,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,UAAU,CAAC;AACnF,QAAQ,MAAM,QAAQ,sCAAsC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;AACvF,QAAQ,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE;AAC9C,YAAY,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW;AAC5C,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,CAAC,SAAS,GAAG;AACjB,QAAQ,MAAM,IAAI,CAAC,SAAS,EAAE;AAC9B,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,SAAS,GAAG;AAChB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AACxB,QAAQ,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC/B,QAAQ,MAAM,CAAC,0BAA0B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;AAC7D,QAAQ,MAAM,MAAM,oDAAoD,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;AACjG,QAAQ,MAAM,QAAQ,sCAAsC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;AACvF,QAAQ,MAAM,CAAC,GAAG,MAAM,KAAK,aAAa,GAAG,CAAC,GAAG,eAAe,CAAC,CAAC,EAAE,MAAM,CAAC;;AAE3E,QAAQ,MAAM,IAAI,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK;AACtD,YAAY,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACrC,YAAY,OAAO,GAAG,GAAG,GAAG;AAC5B,QAAQ,CAAC,CAAC;;AAEV,QAAQ,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE;AACnC,QAAQ,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE;AACnC,QAAQ,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE;;AAE/B,QAAQ,IAAI,CAAC,IAAI,GAAG,CAAC;AACrB,QAAQ,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;;AAErG,QAAQ,MAAM,EAAE,YAAY,EAAE,CAAC,EAAE,GAAG,2BAA2B,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC;AAC/E,QAAQ,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE;;AAE3C,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA,IAAI,MAAM,GAAG;AACb,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AACjC,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AACxB,QAAQ,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI;AAC7B,QAAQ,IAAI,CAAC,GAAG,EAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC;;AAErD,QAAQ,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACvC,QAAQ,GAAG,CAAC,KAAK,GAAG;AACpB,YAAY,CAAC;AACb,YAAY,CAAC;AACb,YAAY,CAAC,CAAC,EAAE,CAAC,KAAK;AACtB,gBAAgB,OAAO,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAC9E,YAAY,CAAC;AACb,SAAS;AACT,QAAQ,IAAI,OAAO,GAAG,CAAC;AACvB,QAAQ,IAAI,UAAU,GAAG,CAAC;AAC1B,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAC5C,gBAAgB,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC;AACnE,gBAAgB,UAAU,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC;AAClD,YAAY;AACZ,QAAQ;AACR,QAAQ,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,GAAG,UAAU,CAAC;AAC9C,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACpC,QAAQ,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC;AACzC,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,QAAQ,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACrC,QAAQ,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC;AACzC,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,QAAQ,OAAO,EAAE,CAAC,UAAU;AAC5B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,aAAa,eAAe,CAAC,CAAC,EAAE,UAAU,EAAE;AAChD,QAAQ,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC;AACzC,QAAQ,OAAO,EAAE,CAAC,eAAe,EAAE;AACnC,IAAI;AACJ;;AClIA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,GAAG,SAAS,EAAE,CAAC;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,CAAC,EAAE,UAAU,EAAE;AAC/B,QAAQ,KAAK;AACb,YAAY,CAAC;AACb,YAAY;AACZ,gBAAgB,SAAS,EAAE,CAAC,QAAQ;AACpC,gBAAgB,cAAc,EAAE,CAAC,QAAQ;AACzC,gBAAgB,CAAC,EAAE,CAAC;AACpB,gBAAgB,MAAM,EAAE,SAAS;AACjC,gBAAgB,IAAI,EAAE,IAAI;AAC1B,aAAa;AACb,YAAY,UAAU;AACtB,SAAS;AACT,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,QAAQ,EAAE;AACvD,YAAY,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;AACrG,QAAQ;AACR,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,KAAK,CAAC,QAAQ,EAAE;AAC5D,YAAY,IAAI,CAAC,SAAS,CAAC,gBAAgB,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;AAClG,QAAQ;AACR,QAAQ,IAAI,CAAC,eAAe,GAAG,KAAK;AACpC,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,IAAI,GAAG;AACX,QAAQ,MAAM,EAAE,GAAG,GAAG;AACtB,QAAQ,IAAI,aAAa,GAAG,EAAE;AAC9B,QAAQ,MAAM,GAAG,GAAG,QAAQ;AAC5B,QAAQ,IAAI,IAAI,CAAC,eAAe,EAAE,OAAO,IAAI;AAC7C,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AACxB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,CAAC,0BAA0B,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;AACrE,QAAQ,MAAM,CAAC,0BAA0B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;AAC7D,QAAQ,MAAM,IAAI,0BAA0B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;AACnE,QAAQ,MAAM,MAAM,oCAAoC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;AACjF,QAAQ,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,aAAa,CAAC;AACzE,QAAQ,MAAM,EAAE,0BAA0B,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;AAC3E,QAAQ,MAAM,cAAc,GAAG,IAAI,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,WAAW,EAAE;AAC/E,QAAQ,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC;AAC5C,QAAQ,cAAc,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK;AAC3C,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;AAClC,QAAQ,CAAC,CAAC;;AAEV,QAAQ,MAAM,qBAAqB,GAAG,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1F,QAAQ,MAAM,GAAG,GAAG,IAAI,EAAE,CAAC,qBAAqB,EAAE,aAAa,CAAC,CAAC,SAAS,EAAE;;AAE5E,QAAQ,MAAM,EAAE,GAAG,CAAC,CAAC,SAAS,EAAE;AAChC,QAAQ,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AACjD,QAAQ,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC;AACvC,QAAQ,MAAM,KAAK,GAAG,EAAE,GAAG,CAAC;AAC5B,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK;AAC/B,YAAY,KAAK,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE;AAC3D,gBAAgB,IAAI,CAAC,KAAK,CAAC,EAAE;AAC7B,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC;AACxC,YAAY;AACZ,QAAQ,CAAC,CAAC;AACV,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC;;AAEzC,QAAQ,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC;AAC3C,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,UAAU,CAAC;;AAE3C,QAAQ,IAAI,CAAC,EAAE,GAAG,CAAC;AACnB,QAAQ,IAAI,CAAC,EAAE,GAAG,CAAC;AACnB,QAAQ,IAAI,CAAC,eAAe,GAAG,IAAI;AACnC,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,SAAS,GAAG;AAChB,QAAQ,IAAI,CAAC,UAAU,EAAE;AACzB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;;AAEzB,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;AAC3D,QAAQ,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;AACjC,QAAQ,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;AACjC,QAAQ,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,WAAW,CAAC;AAC5D,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACpC,QAAQ,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC;AACzC,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,QAAQ,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACrC,QAAQ,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC;AACzC,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,QAAQ,OAAO,EAAE,CAAC,UAAU;AAC5B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,aAAa,eAAe,CAAC,CAAC,EAAE,UAAU,EAAE;AAChD,QAAQ,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC;AACzC,QAAQ,OAAO,EAAE,CAAC,eAAe,EAAE;AACnC,IAAI;AACJ;;AC/IA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,IAAI,SAAS,EAAE,CAAC;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,CAAC,EAAE,UAAU,EAAE;AAC/B,QAAQ,KAAK;AACb,YAAY,CAAC;AACb,YAAY;AACZ,gBAAgB,SAAS,EAAE,CAAC,QAAQ;AACpC,gBAAgB,CAAC,EAAE,CAAC;AACpB,gBAAgB,MAAM,EAAE,SAAS;AACjC,gBAAgB,IAAI,EAAE,IAAI;AAC1B,gBAAgB,QAAQ,EAAE,EAAE;AAC5B,aAAa;AACb,YAAY,UAAU;AACtB,SAAS;AACT,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,QAAQ,EAAE;AACvD,YAAY,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;AACrG,QAAQ;AACR,QAAQ,MAAM,QAAQ,sCAAsC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;AACvF,QAAQ,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE;AAC9C,YAAY,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW;AAC5C,QAAQ;;AAER,QAAQ,MAAM,CAAC,0BAA0B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;AAC7D,QAAQ,IAAI,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE;AAC1B,YAAY,MAAM,IAAI,KAAK;AAC3B,gBAAgB,CAAC,yBAAyB,EAAE,IAAI,CAAC,EAAE,CAAC,sEAAsE,EAAE,CAAC,CAAC,EAAE,CAAC;AACjI,aAAa;AACb,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,CAAC,SAAS,GAAG;AACjB,QAAQ,MAAM,IAAI,CAAC,SAAS,EAAE;AAC9B,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,SAAS,GAAG;AAChB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AACxB,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK;AACjC,QAAQ,MAAM,SAAS,0BAA0B,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;AAC7E,QAAQ,MAAM,CAAC,0BAA0B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;AAC7D,QAAQ,MAAM,QAAQ,sCAAsC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;AACvF,QAAQ,MAAM,MAAM,oCAAoC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;AACjF;AACA,QAAQ,MAAM,EAAE,GAAG,mBAAmB,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC;AAC5D;AACA,QAAQ,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC;AAC5C,QAAQ,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;;AAE3C,QAAQ,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE;AAC7C;AACA,YAAY,MAAM,GAAG,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACzD,YAAY,IAAI,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3D;AACA,YAAY,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAC5B;AACA,YAAY,MAAM,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;AACvC,YAAY,MAAM,EAAE,YAAY,EAAE,CAAC,EAAE,GAAG,2BAA2B,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC;AACnF;AACA,YAAY,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;AACxC;AACA,YAAY,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;AAC/E,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpD,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxD,oBAAoB,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AACpF,gBAAgB;AAChB,YAAY;AACZ,QAAQ;;AAER;AACA,QAAQ,MAAM,EAAE,YAAY,EAAE,CAAC,EAAE,GAAG,2BAA2B,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC;AACnF,QAAQ,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE;;AAEpD;AACA,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACpC,QAAQ,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC;AAC1C,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,QAAQ,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACrC,QAAQ,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC;AAC1C,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,QAAQ,OAAO,EAAE,CAAC,UAAU;AAC5B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,aAAa,eAAe,CAAC,CAAC,EAAE,UAAU,EAAE;AAChD,QAAQ,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC;AAC1C,QAAQ,OAAO,EAAE,CAAC,eAAe,EAAE;AACnC,IAAI;AACJ;;AC9IA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,GAAG,SAAS,EAAE,CAAC;AAC5B;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,CAAC,EAAE,UAAU,GAAG,EAAE,EAAE;AACpC,QAAQ,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,UAAU,CAAC;AAChE,QAAQ,MAAM,QAAQ,sCAAsC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;AACvF,QAAQ,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE;AAC9C,YAAY,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW;AAC5C,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,CAAC,SAAS,GAAG;AACjB,QAAQ,MAAM,IAAI,CAAC,SAAS,EAAE;AAC9B,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,SAAS,GAAG;AAChB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,oBAAoB,EAAE;AAC7C,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AACxB,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACzB,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACpC,QAAQ,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC;AACzC,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,oBAAoB,GAAG;AAC3B,QAAQ,IAAI,IAAI,CAAC,CAAC,EAAE;AACpB,YAAY,OAAO,IAAI,CAAC,CAAC;AACzB,QAAQ;AACR,QAAQ,MAAM,CAAC,0BAA0B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;AAC7D,QAAQ,MAAM,QAAQ,sCAAsC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;AACvF,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AACxB,QAAQ,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;AAC1C,QAAQ,MAAM,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;AACzC,QAAQ,MAAM,EAAE,YAAY,EAAE,CAAC,EAAE,GAAG,2BAA2B,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC;AAC/E,QAAQ,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE;AAC3C,QAAQ,OAAO,IAAI,CAAC,CAAC;AACrB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,oBAAoB,CAAC,CAAC,EAAE,UAAU,EAAE;AAC/C,QAAQ,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC;AACzC,QAAQ,OAAO,EAAE,CAAC,oBAAoB,EAAE;AACxC,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,QAAQ,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACrC,QAAQ,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC;AACzC,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,QAAQ,OAAO,EAAE,CAAC,UAAU;AAC5B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,aAAa,eAAe,CAAC,CAAC,EAAE,UAAU,EAAE;AAChD,QAAQ,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC;AACzC,QAAQ,OAAO,EAAE,CAAC,eAAe,EAAE;AACnC,IAAI;AACJ;;ACzHA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,MAAM,SAAS,EAAE,CAAC;AAC/B;AACA,IAAI,eAAe;;AAEnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,CAAC,EAAE,UAAU,EAAE;AAC/B,QAAQ,KAAK;AACb,YAAY,CAAC;AACb,YAAY;AACZ,gBAAgB,KAAK,EAAE,GAAG;AAC1B,gBAAgB,CAAC,EAAE,CAAC;AACpB,gBAAgB,MAAM,EAAE,SAAS;AACjC,gBAAgB,IAAI,EAAE,IAAI;AAC1B,gBAAgB,OAAO,EAAE,QAAQ;AACjC,gBAAgB,eAAe,EAAE,EAAE;AACnC,aAAa;AACb,YAAY,UAAU;AACtB,SAAS;AACT,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,CAAC,CAAC,EAAE;AACZ,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AACjC,QAAQ,MAAM,CAAC,0BAA0B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;AAC7D,QAAQ,MAAM,MAAM,oDAAoD,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;AACjG,QAAQ,MAAM,OAAO,iCAAiC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;AAChF,QAAQ,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC;AAC/D,QAAQ,IAAI,OAAO,KAAK,QAAQ,EAAE;AAClC,YAAY,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW;AAC/C,YAAY,IAAI,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,UAAU,CAAC,MAAM,CAAC;AAC9D,QAAQ,CAAC,MAAM,IAAI,OAAO,KAAK,KAAK,EAAE;AACtC,YAAY,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,gCAAgC,aAAa,EAAE,CAAC;AACrG,QAAQ,CAAC,MAAM,IAAI,OAAO,KAAK,KAAK,EAAE;AACtC,YAAY,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,gCAAgC,aAAa,EAAE,CAAC;AACrG,QAAQ,CAAC,MAAM;AACf,YAAY,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC;AAClF,QAAQ;AACR,QAAQ,CAAC,GAAG,MAAM,KAAK,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC;AAC5F,QAAQ,IAAI,CAAC,eAAe,GAAG,CAAC;AAChC,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,SAAS,CAAC,QAAQ,GAAG,GAAG,EAAE;AAC9B,QAAQ,IAAI,CAAC,UAAU,EAAE;AACzB,QAAQ,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC;AAClE,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,EAAE,CAAC,EAAE;AAC3C,YAAY,IAAI,CAAC,KAAK,EAAE;AACxB,QAAQ;AACR,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,CAAC,SAAS,CAAC,QAAQ,GAAG,GAAG,EAAE;AAC/B,QAAQ,IAAI,CAAC,UAAU,EAAE;AACzB,QAAQ,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC;;AAElE,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,EAAE,CAAC,EAAE;AAC3C,YAAY,IAAI,CAAC,KAAK,EAAE;AACxB,YAAY,MAAM,IAAI,CAAC,UAAU;AACjC,QAAQ;;AAER,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ,IAAI,KAAK,GAAG;AACZ,QAAQ,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC;AAClE,QAAQ,MAAM,KAAK,0BAA0B,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;AACrE,QAAQ,MAAM,CAAC,0BAA0B,IAAI,CAAC,eAAe,CAAC;AAC9D,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AACjC,QAAQ,MAAM,CAAC,0BAA0B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;AAC7D,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;;AAExB,QAAQ,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;;AAErC,QAAQ,MAAM,GAAG,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC;AACvC,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,MAAM,EAAE,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC;AAC1C,YAAY,MAAM,EAAE,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC;AAC1C,YAAY,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAC/B,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxC,gBAAgB,IAAI,CAAC,KAAK,CAAC,EAAE;AAC7B,gBAAgB,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACxC,gBAAgB,IAAI,EAAE,KAAK,CAAC,EAAE,SAAS;;AAEvC,gBAAgB,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACnC,gBAAgB,MAAM,KAAK,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC;AACjD,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAC5C,oBAAoB,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;AAC5C,gBAAgB;AAChB,gBAAgB,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC;AAC5D,gBAAgB,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE;AAClC,gBAAgB,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE;AAClC,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAC5C,oBAAoB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE;AACjD,oBAAoB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE;AAC7E,gBAAgB;AAChB,YAAY;AACZ,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxC,gBAAgB,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACpF,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC;AACtC,gBAAgB,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG;AAC7B,YAAY;AACZ,QAAQ;AACR,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AACvB,QAAQ;;AAER,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxC,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;AACzD,YAAY;AACZ,QAAQ;AACR,QAAQ,OAAO,CAAC;AAChB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACpC,QAAQ,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC;AAC5C,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,QAAQ,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACrC,QAAQ,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC;AAC5C,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,QAAQ,OAAO,EAAE,CAAC,UAAU;AAC5B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,aAAa,eAAe,CAAC,CAAC,EAAE,UAAU,EAAE;AAChD,QAAQ,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC;AAC5C,QAAQ,OAAO,EAAE,CAAC,eAAe,EAAE;AACnC,IAAI;AACJ;;AC5LA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,MAAM,SAAS,EAAE,CAAC;AAC/B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,CAAC,EAAE,UAAU,EAAE;AAC/B,QAAQ,KAAK;AACb,YAAY,CAAC;AACb,YAAY;AACZ,gBAAgB,CAAC,EAAE,CAAC;AACpB,gBAAgB,MAAM,EAAE,SAAS;AACjC,gBAAgB,IAAI,EAAE,IAAI;AAC1B,gBAAgB,WAAW,EAAE,GAAG;AAChC,gBAAgB,SAAS,EAAE,IAAI;AAC/B,aAAa;AACb,YAAY,UAAU;AACtB,SAAS;;AAET,QAAQ,IAAI,CAAC,IAAI,EAAE;AACnB,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,aAAa,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;AAC/F,YAAY,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC;AACxE,QAAQ;AACR,IAAI;;AAEJ,IAAI,IAAI,GAAG;AACX,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,CAAC,0BAA0B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;;AAE7D;AACA,QAAQ,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AACjC,QAAQ,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;AACzC,QAAQ,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;AACrC,QAAQ,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AACnC,QAAQ,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC;AAC9C,QAAQ,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,QAAQ;AAChC,QAAQ,MAAM,SAAS,0BAA0B,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;AAC7E,QAAQ,IAAI,CAAC,OAAO,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,SAAS,CAAC;AAChD,QAAQ,IAAI,CAAC,UAAU,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAC7C,QAAQ,IAAI,CAAC,MAAM,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACzC,QAAQ,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;AAC1C;AACA,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW;AAClC,QAAQ,IAAI,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC;;AAEvD;AACA,QAAQ,MAAM,WAAW,0CAA0C,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;AAC5F,QAAQ,IAAI,WAAW,KAAK,aAAa,EAAE;AAC3C;AACA,YAAY,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACxD;AACA,YAAY,IAAI,CAAC,uBAAuB,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC;AAC1E,QAAQ,CAAC,MAAM;AACf,YAAY,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC1E,YAAY,IAAI,WAAW,KAAK,SAAS,EAAE;AAC3C,gBAAgB,IAAI,CAAC,uBAAuB,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,iBAAiB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACjG,YAAY,CAAC,MAAM;AACnB,gBAAgB,IAAI,CAAC,uBAAuB,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAChG,YAAY;AACZ,QAAQ;AACR,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,SAAS,CAAC,UAAU,GAAG,GAAG,EAAE;AAChC,QAAQ,IAAI,CAAC,UAAU,EAAE;AACzB,QAAQ,MAAM,WAAW,0BAA0B,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;AACjF,QAAQ,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,UAAU,CAAC;AAChE,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,EAAE,CAAC,EAAE;AAC7C,YAAY,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC;AACrC,QAAQ;AACR,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,CAAC,SAAS,CAAC,UAAU,GAAG,GAAG,EAAE;AACjC,QAAQ,IAAI,CAAC,UAAU,EAAE;AACzB,QAAQ,MAAM,WAAW,0BAA0B,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;AACjF,QAAQ,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,UAAU,CAAC;AAChE,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,EAAE,CAAC,EAAE;AAC7C,YAAY,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC;AACrC,YAAY,MAAM,IAAI,CAAC,UAAU;AACjC,QAAQ;;AAER,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,KAAK,CAAC,CAAC,EAAE,UAAU,EAAE;AACzB,QAAQ,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,EAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;;AAE5G,QAAQ,MAAM,WAAW,0BAA0B,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;AACjF,QAAQ,IAAI,CAAC,GAAG,WAAW,EAAE;AAC7B,YAAY,MAAM,SAAS,0BAA0B,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;AACjF,YAAY,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO;AACvC,YAAY,MAAM,KAAK,GAAG,CAAC,CAAC,GAAG,WAAW,KAAK,UAAU,GAAG,WAAW,CAAC;AACxE,YAAY,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,GAAG,SAAS,CAAC,GAAG,MAAM,CAAC;AACxF,YAAY,IAAI,CAAC,sBAAsB,GAAG,KAAK;AAC/C,QAAQ,CAAC,MAAM;AACf,YAAY,IAAI,CAAC,sBAAsB,GAAG,IAAI;AAC9C,QAAQ;AACR,QAAQ,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,sBAAsB,CAAC;AAC5D,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,UAAU,GAAG;AACjB,QAAQ,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;AACjE,QAAQ,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,EAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;AAC7E,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACjC,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW;AAClC,QAAQ,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC;AAC/D,QAAQ,MAAM,MAAM,GAAG,EAAE;AACzB,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE;AAC3C,YAAY,MAAM,CAAC,IAAI;AACvB,gBAAgB,WAAW,CAAC,EAAE;AAC9B,oBAAoB,gBAAgB,CAAC,CAAC,CAAC;AACvC,oBAAoB,gBAAgB,CAAC,CAAC,GAAG,CAAC,CAAC;AAC3C,oBAAoB,gBAAgB,CAAC,CAAC,GAAG,CAAC,CAAC;AAC3C,oBAAoB,gBAAgB,CAAC,CAAC,GAAG,CAAC,CAAC;AAC3C,iBAAiB;AACjB,aAAa;AACb,QAAQ;AACR,QAAQ,OAAO,MAAM;AACrB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,kBAAkB,CAAC,qBAAqB,EAAE;AAC9C,QAAQ,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS,EAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;AAC7G,QAAQ,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AACtE,QAAQ,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG;AAC3B,QAAQ,MAAM,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,qBAAqB,CAAC;AACrG,QAAQ,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,SAAS,CAAC,KAAK;AACtC,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;AACpC,YAAY,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC;AACtC,YAAY,IAAI,QAAQ,KAAK,CAAC,EAAE;AAChC,YAAY,MAAM,GAAG,GAAG,EAAE,GAAG,QAAQ;AACrC,YAAY,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;AACxC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxC,gBAAgB,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;AACtC,YAAY;AACZ,QAAQ,CAAC;AACT,QAAQ,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AAC/C,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,eAAe,CAAC,CAAC,EAAE,KAAK,EAAE,YAAY,GAAG,KAAK,EAAE,SAAS,GAAG,IAAI,EAAE;AACtE,QAAQ,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,uBAAuB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;AAClH,QAAQ,IAAI,SAAS,EAAE;AACvB;AACA,YAAY,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,QAAQ;AACR,QAAQ,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI;AAC7B,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AACxB,QAAQ,IAAI,SAAS;AACrB,QAAQ,IAAI,YAAY,KAAK,IAAI,EAAE;AACnC,YAAY,SAAS,GAAG,IAAI,CAAC,uBAAuB;AACpD,QAAQ,CAAC,MAAM;AACf,YAAY,SAAS,GAAG,IAAI,CAAC,UAAU;AACvC,QAAQ;;AAER,QAAQ,MAAM,SAAS,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC;AAC7C,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,EAAE;AAC1C,QAAQ,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,QAAQ,EAAE;AAC7C;AACA,YAAY,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAC7C,YAAY,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAC7C,YAAY,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAC7C,YAAY,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAC7C,YAAY,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAC7C,YAAY,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;;AAE7C,YAAY,MAAM,aAAa,GAAG,WAAW,CAAC,SAAS,CAAC;;AAExD,YAAY,IAAI,aAAa,GAAG,CAAC,EAAE;AACnC,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAC5C,oBAAoB,SAAS,CAAC,CAAC,CAAC,IAAI,aAAa;AACjD,oBAAoB,SAAS,CAAC,CAAC,CAAC,IAAI,KAAK;AACzC,gBAAgB;AAChB,YAAY;AACZ,YAAY,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,sBAAsB,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,CAAC;;AAE5F;AACA,YAAY,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AACjC,YAAY,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AACjC,YAAY,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AACjC,YAAY,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AACjC,QAAQ;AACR,QAAQ,OAAO,KAAK;AACpB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,sBAAsB,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE;AAC7E,QAAQ,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACjE;AACA,QAAQ,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK;AAC5C,QAAQ,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK;AAC5C,QAAQ,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK;AAC5C,QAAQ,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK;AAC5C,QAAQ,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK;AAC5C,QAAQ,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK;AAC5C,QAAQ,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;;AAE7E;AACA,QAAQ,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,WAAW;AACrD,YAAY,CAAC;AACb,YAAY,CAAC;AACb,YAAY,CAAC;AACb,YAAY,CAAC;AACb,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,WAAW;AACvB,SAAS;AACT,QAAQ,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,WAAW;AACrD,YAAY,CAAC;AACb,YAAY,CAAC;AACb,YAAY,CAAC;AACb,YAAY,CAAC;AACb,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,WAAW;AACvB,SAAS;AACT,QAAQ,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,WAAW;AACrD,YAAY,CAAC;AACb,YAAY,CAAC;AACb,YAAY,CAAC;AACb,YAAY,CAAC;AACb,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,WAAW;AACvB,SAAS;AACT,QAAQ,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,WAAW;AACrD,YAAY,CAAC;AACb,YAAY,CAAC;AACb,YAAY,CAAC;AACb,YAAY,CAAC;AACb,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,WAAW;AACvB,SAAS;AACT,QAAQ,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,WAAW;AACrD,YAAY,CAAC;AACb,YAAY,CAAC;AACb,YAAY,CAAC;AACb,YAAY,CAAC;AACb,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,WAAW;AACvB,SAAS;AACT,QAAQ,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,WAAW;AACrD,YAAY,CAAC;AACb,YAAY,CAAC;AACb,YAAY,CAAC;AACb,YAAY,CAAC;AACb,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,IAAI;AAChB,YAAY,WAAW;AACvB,SAAS;;AAET,QAAQ,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;AAC7D,QAAQ,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI;AAC7B,QAAQ,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;AACpD,QAAQ,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;AACpD,QAAQ,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;AACpD,QAAQ,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;;AAEpD,QAAQ,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;AAC/B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE;AACnF,QAAQ,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;AAC9G,QAAQ,MAAM,KAAK,GAAG,IAAI,GAAG,WAAW;AACxC,QAAQ,MAAM,WAAW,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,KAAK,IAAI,WAAW,CAAC;AAC9D,QAAQ,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM;AACjC,QAAQ,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI;AAC7B,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK;AAC/B,QAAQ,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ;AACrC;AACA,QAAQ,MAAM,EAAE,GAAG,IAAI;AACvB,YAAY,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;AACvH,YAAY,WAAW;AACvB,SAAS;AACT,QAAQ,MAAM,EAAE,GAAG,IAAI;AACvB,YAAY,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;AACvH,YAAY,WAAW;AACvB,SAAS;AACT,QAAQ,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,KAAK,GAAG,WAAW,CAAC;AAChH,QAAQ,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,KAAK,GAAG,WAAW,CAAC;AAChH,QAAQ,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;AAC/B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,CAAC,CAAC,EAAE;AACf,QAAQ,yEAAyE,CAAC,CAAC,EAAE,CAAC,KAAK;AAC3F,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxC,gBAAgB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC5B,YAAY;AACZ,YAAY,OAAO,CAAC;AACpB,QAAQ,CAAC;AACT,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,KAAK,CAAC,CAAC,EAAE;AACb,QAAQ,oEAAoE,CAAC,GAAG,QAAQ,KAAK;AAC7F,YAAY,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM;AACrC,YAAY,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC;AAClC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxC,gBAAgB,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC;AAC3C,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAC5C,oBAAoB,EAAE,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC;AACvC,gBAAgB;AAChB,YAAY;AACZ,YAAY,OAAO,EAAE;AACrB,QAAQ,CAAC;AACT,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,MAAM,CAAC,CAAC,EAAE;AACd,QAAQ,mEAAmE,CAAC,CAAC,EAAE,CAAC,KAAK;AACrF,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxC,gBAAgB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB,YAAY;AACZ,YAAY,OAAO,CAAC;AACpB,QAAQ,CAAC;AACT,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,SAAS,CAAC,CAAC,EAAE;AACjB,QAAQ,sFAAsF,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,KAAK;AAC7G,YAAY,OAAO,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;AAClF,QAAQ,CAAC;AACT,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACpC,QAAQ,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC;AAC5C,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,QAAQ,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACrC,QAAQ,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC;AAC5C,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,QAAQ,OAAO,EAAE,CAAC,UAAU;AAC5B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,aAAa,eAAe,CAAC,CAAC,EAAE,UAAU,EAAE;AAChD,QAAQ,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC;AAC5C,QAAQ,OAAO,EAAE,CAAC,eAAe,EAAE;AACnC,IAAI;AACJ;;AC3eA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,OAAO,SAAS,EAAE,CAAC;AAChC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,CAAC,EAAE,UAAU,EAAE;AAC/B,QAAQ,KAAK,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,UAAU,CAAC;AAC/D,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK;AACzC,QAAQ,IAAI,CAAC,gBAAgB,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC;AAChE,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,sBAAsB,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE;AACzC,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,gBAAgB;AACvC,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AACxB,QAAQ,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAClC,QAAQ,IAAI,IAAI,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE;AACpC,YAAY,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACnD,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC;AACnC,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC;AACnC,YAAY,OAAO,IAAI;AACvB,QAAQ;AACR,QAAQ,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI;AACjC,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,2BAA2B,CAAC,MAAM,GAAG,SAAS,EAAE;AACpD,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;;AAE7B,QAAQ,IAAI,CAAC,aAAa,GAAG,IAAI,WAAW,CAAC,CAAC,CAAC;AAC/C,QAAQ,MAAM,YAAY,GAAG,IAAI,CAAC,aAAa;AAC/C,QAAQ,MAAM,CAAC,GAAG,EAAE;AACpB,QAAQ,IAAI,CAAC,GAAG,EAAE;AAClB,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAC5C,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,sBAAsB,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AACzE,YAAY;AACZ,QAAQ;AACR,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;;AAEzC,QAAQ,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE;AACnC,YAAY,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,YAAY,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,YAAY,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,EAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;AACvE,YAAY,IAAI,KAAK,KAAK,KAAK,EAAE;AACjC,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACjC,gBAAgB,YAAY,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC;AAChD,YAAY;AACZ,QAAQ;;AAER,QAAQ,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,IAAI;;AAEJ;AACA,IAAI,IAAI,GAAG;AACX,QAAQ,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW;AAC3C,QAAQ,IAAI,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;AAC1C,QAAQ,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,2BAA2B,CAAC,MAAM,CAAC;AAC7D,QAAQ,IAAI,CAAC,eAAe,GAAG,IAAI;AACnC,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,YAAY,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE;AAC/C,QAAQ,OAAO,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC;AACjE,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,MAAM,CAAC,CAAC,EAAE;AACd,QAAQ,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;AACzE,QAAQ,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM;AAC/B,QAAQ,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,MAAM;;AAEjC,QAAQ,MAAM,KAAK,GAAG,EAAE;AACxB,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY;AACZ,gBAAgB,KAAK,CAAC,MAAM,IAAI,CAAC;AACjC,gBAAgB,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAC7F,cAAc;AACd,gBAAgB,KAAK,CAAC,GAAG,EAAE;AAC3B,YAAY;AACZ,YAAY,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACjC,QAAQ;AACR,QAAQ,MAAM,KAAK,GAAG,EAAE;AACxB,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE;AACzC,YAAY;AACZ,gBAAgB,KAAK,CAAC,MAAM,IAAI,CAAC;AACjC,gBAAgB,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAC7F,cAAc;AACd,gBAAgB,KAAK,CAAC,GAAG,EAAE;AAC3B,YAAY;AACZ,YAAY,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACjC,QAAQ;AACR,QAAQ,KAAK,CAAC,GAAG,EAAE;AACnB,QAAQ,KAAK,CAAC,GAAG,EAAE;AACnB,QAAQ,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;AAClC,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE;AACxC,QAAQ,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AACnD,QAAQ,IAAI,CAAC,KAAK,CAAC;AACnB,YAAY,OAAO;AACnB,gBAAgB,GAAG,EAAE,CAAC;AACtB,gBAAgB,GAAG,EAAE,CAAC;AACtB,aAAa;AACb,QAAQ,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,CAAC;AACtD,QAAQ,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC;AAC1B,QAAQ,IAAI,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC;AAC1C,QAAQ,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG;AACtC,QAAQ,OAAO;AACf,YAAY,GAAG,EAAE,GAAG;AACpB,YAAY,GAAG,EAAE,GAAG;AACpB,SAAS;AACT,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,YAAY,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE;AACnC,QAAQ,IAAI,CAAC,GAAG,EAAE;AAClB;AACA,QAAQ,IAAI,EAAE,GAAG,CAAC,QAAQ;AAC1B,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE;AAC9C,YAAY,MAAM,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC3C,YAAY,IAAI,CAAC,KAAK,EAAE,EAAE;AAC1B,gBAAgB,EAAE,GAAG,CAAC;AACtB,gBAAgB,CAAC,GAAG,CAAC;AACrB,YAAY,CAAC,MAAM;AACnB,gBAAgB,IAAI,EAAE,GAAG,CAAC,EAAE;AAC5B,oBAAoB,EAAE,GAAG,CAAC;AAC1B,oBAAoB,CAAC,GAAG,CAAC;AACzB,gBAAgB;AAChB,YAAY;AACZ,QAAQ;;AAER,QAAQ,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;AAC1B,QAAQ,IAAI,EAAE;AACd,QAAQ,IAAI,OAAO,EAAE;AACrB,YAAY,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC;AAC5C,QAAQ,CAAC,MAAM;AACf,YAAY,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC;AAC1D,QAAQ;;AAER;AACA,QAAQ,MAAM,cAAc,GAAG;AAC/B,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACtB,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACtB,SAAS;;AAET,QAAQ,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE;AAC9B,YAAY,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,CAAC;AACzD,YAAY,cAAc,CAAC,GAAG,GAAG,GAAG;AACpC,YAAY,cAAc,CAAC,GAAG,GAAG,GAAG;AACpC,QAAQ,CAAC,MAAM;AACf,YAAY,cAAc,CAAC,GAAG,GAAG,CAAC;AAClC,YAAY,cAAc,CAAC,GAAG,GAAG,CAAC;AAClC,QAAQ;;AAER,QAAQ,4EAA4E,cAAc;AAClG,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;AAChD,QAAQ,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE;AACzB,QAAQ,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE;AACzB,QAAQ,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG;AACpC,QAAQ,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG;AACpC,QAAQ,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC;AACvB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,qBAAqB,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE;AACzC,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM;AAC1B,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC1B,YAAY,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC;AACnD,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;AACrB,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,OAAO;AAC/B,QAAQ;AACR,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,UAAU,EAAE;AAChE,QAAQ,IAAI,CAAC,UAAU,EAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC;AACpE,QAAQ,MAAM,UAAU,GAAG,UAAU,CAAC,YAAY,CAAC,MAAM,CAAC;AAC1D,QAAQ,MAAM,UAAU,GAAG,UAAU,CAAC,YAAY,CAAC,MAAM,CAAC;AAC1D,QAAQ,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,EAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;;AAE7E,QAAQ,MAAM,QAAQ,GAAG,CAAC,GAAG,UAAU,CAAC;AACxC,QAAQ,MAAM,QAAQ,GAAG,CAAC,GAAG,UAAU,CAAC;;AAExC,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;AAC5C,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;;AAE5C,QAAQ,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC;AACzD,QAAQ,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC;;AAExD,QAAQ,IAAI,CAAC,qBAAqB,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;AACpD,QAAQ,IAAI,CAAC,qBAAqB,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;AACpD,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,SAAS,GAAG;AAChB,QAAQ,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,IAAI,EAAE;AAC9C,QAAQ,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;AAC9D,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK;AAC/B,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE;AACpC;AACA,QAAQ,MAAM,UAAU,GAAG,IAAI,WAAW;AAC1C,YAAY,CAAC;AACb;AACA;AACA;AACA;AACA,SAAS;;AAET,QAAQ,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,EAAE;AACtC,YAAY,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;AAC5B,YAAY,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;AAC5B,YAAY,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC;AACpD,YAAY,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC;AACpD,YAAY,IAAI,CAAC,WAAW,IAAI,CAAC,WAAW,EAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;AACnF,YAAY,IAAI,WAAW,KAAK,WAAW,EAAE;AAC7C,YAAY,IAAI,CAAC,kBAAkB,CAAC,WAAW,EAAE,WAAW,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,UAAU,CAAC;AACtF,YAAY,UAAU,CAAC,KAAK,CAAC,WAAW,EAAE,WAAW,CAAC;AACtD,QAAQ;AACR,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,CAAC,SAAS,GAAG;AACjB,QAAQ,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,IAAI,EAAE;AAC9C,QAAQ,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;AAC9D,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK;AAC/B,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE;AACpC,QAAQ,MAAM,UAAU,GAAG,IAAI,WAAW;AAC1C,YAAY,CAAC;AACb;AACA;AACA;AACA;AACA,SAAS;;AAET,QAAQ,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,IAAI,EAAE;AACtC,YAAY,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;AAC5B,YAAY,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;AAC5B,YAAY,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC;AACpD,YAAY,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC;AACpD,YAAY,IAAI,CAAC,WAAW,IAAI,CAAC,WAAW,EAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;AACnF,YAAY,IAAI,WAAW,KAAK,WAAW,EAAE;AAC7C,YAAY,IAAI,CAAC,kBAAkB,CAAC,WAAW,EAAE,WAAW,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,UAAU,CAAC;AACtF,YAAY,UAAU,CAAC,KAAK,CAAC,WAAW,EAAE,WAAW,CAAC;AACtD,YAAY,MAAM,IAAI,CAAC,UAAU;AACjC,QAAQ;AACR,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACpC,QAAQ,MAAM,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC,EAAE,UAAU,CAAC;AAC7C,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,QAAQ,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACrC,QAAQ,MAAM,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC,EAAE,UAAU,CAAC;AAC7C,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,QAAQ,OAAO,EAAE,CAAC,UAAU;AAC5B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,aAAa,eAAe,CAAC,CAAC,EAAE,UAAU,EAAE;AAChD,QAAQ,MAAM,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC,EAAE,UAAU,CAAC;AAC7C,QAAQ,OAAO,EAAE,CAAC,eAAe,EAAE;AACnC,IAAI;AACJ;;ACvXA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,MAAM,SAAS,EAAE,CAAC;AAC/B;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,CAAC,EAAE,UAAU,EAAE;AAC/B,QAAQ,KAAK;AACb,YAAY,CAAC;AACb,YAAY;AACZ,gBAAgB,UAAU,EAAE,GAAG;AAC/B,gBAAgB,SAAS,EAAE,EAAE;AAC7B,gBAAgB,UAAU,EAAE,CAAC;AAC7B,gBAAgB,QAAQ,EAAE,CAAC;AAC3B,gBAAgB,CAAC,EAAE,CAAC;AACpB,gBAAgB,MAAM,EAAE,SAAS;AACjC,gBAAgB,GAAG,EAAE,IAAI;AACzB,gBAAgB,IAAI,EAAE,IAAI;AAC1B,aAAa;AACb,YAAY,UAAU;AACtB,SAAS;AACT,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,IAAI,CAAC,GAAG,GAAG,IAAI,EAAE,GAAG,GAAG,IAAI,EAAE;AACjC,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AACxB,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5B;AACA,QAAQ,MAAM,CAAC,0BAA0B,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;AAC5D,QAAQ,MAAM,MAAM,0BAA0B,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;AACtE,QAAQ,MAAM,IAAI,0BAA0B,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;AAClE,QAAQ,IAAI,CAAC,SAAS,0BAA0B,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC;AAC3E,QAAQ,IAAI,CAAC,UAAU,0BAA0B,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC;AAC7E,QAAQ,IAAI,CAAC,QAAQ,0BAA0B,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC;AACzE,QAAQ,IAAI,CAAC,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC;AACrD,QAAQ,IAAI,CAAC,GAAG,GAAG,GAAG,IAAI,IAAI,QAAQ,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AACvE,QAAQ,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC;AAC7G,QAAQ,IAAI,CAAC,QAAQ,GAAG,QAAQ;AAChC,QAAQ,IAAI,CAAC,OAAO,GAAG,OAAO;AAC9B,QAAQ,IAAI,CAAC,EAAE,GAAG,CAAC,IAAI,GAAG,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAChD,QAAQ,IAAI,CAAC,CAAC,GAAG,QAAQ;AACzB,QAAQ,IAAI,CAAC,GAAG,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACtC,QAAQ,IAAI,CAAC,IAAI,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACvC,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,kBAAkB,CAAC,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE;AACxD,QAAQ,MAAM,MAAM,0BAA0B,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;AACtE,QAAQ,MAAM,UAAU,0BAA0B,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC;AAC9E,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AACxB,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5B,QAAQ,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG;AAC5B,QAAQ,IAAI,CAAC,GAAG,EAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;AACvD,QAAQ,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,EAAE,EAAE,CAAC,CAAC;AACnD,QAAQ,MAAM,IAAI,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC;AAC3C,QAAQ,MAAM,aAAa,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC;AACpD,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,MAAM,OAAO,GAAG;AAC5B,iBAAiB,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC;AAC7C,iBAAiB,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,KAAK,CAAC;AAC/C,iBAAiB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;;AAExD,YAAY,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK;AACtC,gBAAgB,IAAI,CAAC,GAAG,OAAO,EAAE;AACjC,oBAAoB,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC;AACjD,oBAAoB,aAAa,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC;AAC7D,gBAAgB;AAChB,YAAY,CAAC,CAAC;AACd,QAAQ;AACR;AACA,QAAQ,MAAM,GAAG,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC;AACvC,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG;AAC7B,gBAAgB,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC;AACvG,gBAAgB,KAAK;AACrB,aAAa;AACb,QAAQ;;AAER,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,EAAE,IAAI,CAAC;;AAExD,QAAQ,IAAI,QAAQ,GAAG,IAAI,CAAC,oBAAoB,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,CAAC;AAChF,QAAQ,IAAI,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAC1C,QAAQ,MAAM,iBAAiB,GAAG,IAAI,YAAY,CAAC,UAAU,CAAC;AAC9D,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,EAAE,CAAC,EAAE;AAC7C,YAAY,MAAM,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAC1C,YAAY,MAAM,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAC1C,YAAY,iBAAiB,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC7D,QAAQ;AACR,QAAQ,IAAI,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,GAAG,CAAC;;AAEnF,QAAQ,IAAI,QAAQ,GAAG,CAAC,EAAE;AAC1B,YAAY,MAAM,EAAE,eAAe,EAAE,cAAc,EAAE,GAAG,IAAI,CAAC,uBAAuB,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC;AACtG,YAAY,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,eAAe,EAAE,UAAU,CAAC;AACnE,YAAY,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,cAAc,CAAC,CAAC;AACxE,QAAQ;AACR,QAAQ,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AACtC,QAAQ,IAAI,UAAU,GAAG,CAAC,QAAQ;AAClC,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,EAAE,CAAC,EAAE;AAC7C,YAAY,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE;AAC1C,gBAAgB,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;AAC9B,YAAY;AACZ,YAAY,IAAI,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC;AAChE,QAAQ;AACR,QAAQ,IAAI,YAAY,GAAG,CAAC,QAAQ;AACpC,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,EAAE,CAAC,EAAE;AAC7C,YAAY,OAAO,CAAC,CAAC,CAAC,IAAI,UAAU;AACpC,YAAY,OAAO,CAAC,CAAC,CAAC,IAAI,MAAM;AAChC,YAAY,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAC9D,YAAY,IAAI,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC;AACpE,QAAQ;AACR,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,EAAE,CAAC,EAAE;AAC7C,YAAY,OAAO,CAAC,CAAC,CAAC,IAAI,YAAY;AACtC,QAAQ;AACR,QAAQ,OAAO;AACf,YAAY,QAAQ,EAAE,QAAQ;AAC9B,YAAY,OAAO,EAAE,OAAO;AAC5B,SAAS;AACT,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,CAAC,aAAa,EAAE,GAAG,EAAE,IAAI,EAAE;AACtC,QAAQ,MAAM,CAAC,CAAC,EAAE,WAAW,CAAC,GAAG,aAAa,CAAC,KAAK;AACpD,QAAQ,OAAO,IAAI,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK;AACpD,YAAY,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/F,QAAQ,CAAC,CAAC;AACV,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,oBAAoB,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE;AACzD,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AAC/B,QAAQ,MAAM,aAAa,GAAG,EAAE;AAChC,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACzD,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,EAAE,CAAC,EAAE;AAChD,gBAAgB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1F,gBAAgB,MAAM,OAAO,GAAG,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;AACjH,gBAAgB,MAAM,OAAO,GAAG,IAAI,CAAC,iBAAiB,CAAC,UAAU,EAAE,CAAC,EAAE,OAAO,CAAC;AAC9E,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE;AACzD,oBAAoB,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC;AAC1C,oBAAoB,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AACrD,gBAAgB;AAChB,YAAY;AACZ,QAAQ;AACR,QAAQ,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC;AAC5D,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE;AACvD,YAAY,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzD,YAAY,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzD,YAAY,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzD,QAAQ;AACR,QAAQ,OAAO,QAAQ;AACvB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,SAAS,CAAC,CAAC,EAAE;AACjB,QAAQ,OAAO,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACpE,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,iBAAiB,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE;AACnD,QAAQ,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW;AAC3C,QAAQ,MAAM,QAAQ,GAAG,QAAQ,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AACvF,QAAQ,OAAO,UAAU,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;AAChF,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,aAAa,CAAC,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,GAAG,EAAE;AAC7D,QAAQ,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5C,QAAQ,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,UAAU,CAAC;AACpD,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,EAAE,CAAC,EAAE;AAC7C,YAAY,MAAM,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAC1C,YAAY,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACjE,YAAY,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;AACzC,YAAY,IAAI,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrG,YAAY,IAAI,KAAK,GAAG,KAAK,EAAE,KAAK,GAAG,KAAK;AAC5C,YAAY,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,KAAK;AACtC,QAAQ;AACR,QAAQ,OAAO,OAAO;AACtB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,uBAAuB,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE;AAC9C,QAAQ,MAAM,MAAM,0BAA0B,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;AACvE,QAAQ,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW;AAC3C,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5B,QAAQ,MAAM,eAAe,GAAG,IAAI,MAAM,CAAC,CAAC,GAAG,QAAQ,EAAE,CAAC,CAAC;AAC3D,QAAQ,MAAM,cAAc,GAAG,IAAI,YAAY,CAAC,CAAC,GAAG,QAAQ,CAAC;AAC7D,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,MAAM,GAAG,GAAG,CAAC,GAAG,QAAQ;AACpC,YAAY,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,GAAG,KAAK,CAAC,CAAC;AACjG,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,EAAE,CAAC,EAAE;AAC/C,gBAAgB,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;AAC9D,gBAAgB,IAAI,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAChG,gBAAgB,IAAI,KAAK,GAAG,KAAK,EAAE,KAAK,GAAG,KAAK;AAChD,gBAAgB,IAAI,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAChG,gBAAgB,IAAI,KAAK,GAAG,KAAK,EAAE,KAAK,GAAG,KAAK;;AAEhD,gBAAgB,IAAI,KAAK,GAAG,KAAK,EAAE;AACnC,oBAAoB,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC;AAC3C,oBAAoB,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC;AACnD,gBAAgB;AAChB,gBAAgB,MAAM,KAAK,GAAG,GAAG,GAAG,CAAC;AACrC,gBAAgB,eAAe,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;AACtD,gBAAgB,eAAe,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC;AACxD,gBAAgB,eAAe,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC;AACxD,gBAAgB,cAAc,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,KAAK,GAAG,KAAK,CAAC;AAC7D,YAAY;AACZ,QAAQ;AACR,QAAQ,OAAO;AACf,YAAY,eAAe,EAAE,eAAe;AAC5C,YAAY,cAAc,EAAE,cAAc;AAC1C,SAAS;AACT,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,KAAK,CAAC,CAAC,EAAE;AACb,QAAQ,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS;AACxC,QAAQ,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU;AAC1C,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ;AACtC,QAAQ,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO;AACpC,QAAQ,IAAI,CAAC,QAAQ,IAAI,SAAS,KAAK,SAAS,IAAI,UAAU,KAAK,SAAS,IAAI,CAAC,OAAO;AACxF,YAAY,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;AACjD,QAAQ,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK;AAChC,QAAQ,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5C,QAAQ,MAAM,IAAI,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;AAC1C,QAAQ,MAAM,IAAI,GAAG,IAAI,YAAY,CAAC,GAAG,CAAC;AAC1C,QAAQ,MAAM,IAAI,GAAG,IAAI,YAAY,CAAC,GAAG,CAAC;AAC1C,QAAQ,IAAI,IAAI,GAAG,CAAC;AACpB,QAAQ,IAAI,IAAI,GAAG,CAAC;AACpB,QAAQ,IAAI,MAAM,GAAG,CAAC;AACtB,QAAQ,IAAI,IAAI,GAAG,CAAC;AACpB,QAAQ,MAAM,cAAc,GAAG,CAAC,GAAG,SAAS,GAAG,UAAU;;AAEzD,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,EAAE,CAAC,EAAE;AAC7C,YAAY,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;AAC7C;AACA,YAAY,IAAI,CAAC,GAAG,UAAU,KAAK,CAAC,IAAI,CAAC,IAAI,cAAc,EAAE;AAC7D,gBAAgB,IAAI,GAAG,CAAC;AACxB,gBAAgB,IAAI,GAAG,CAAC;AACxB,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,EAAE,CAAC,EAAE;AAC9C,oBAAoB,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAC9C,oBAAoB,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAC9C,oBAAoB,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAC9C,oBAAoB,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI;AACzC,oBAAoB,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI;AACzC,oBAAoB,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACxC,oBAAoB,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACxC,gBAAgB;AAChB;AACA,YAAY,CAAC,MAAM;AACnB,gBAAgB,IAAI,GAAG,CAAC;AACxB,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,EAAE,CAAC,EAAE;AAC9C,oBAAoB,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAC9C,oBAAoB,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAC9C,oBAAoB,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI;AACzC,oBAAoB,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACxC,gBAAgB;AAChB,YAAY;;AAEZ,YAAY,IAAI,IAAI,GAAG,IAAI,EAAE,EAAE,MAAM;AACrC,YAAY,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AAClD,YAAY,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,KAAK,CAAC;AACrD,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,EAAE,CAAC,EAAE;AAC1C,gBAAgB,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC;AAC7C,gBAAgB,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC;AAC7C,gBAAgB,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC;AAC7C,gBAAgB,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;AACxC,gBAAgB,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;AACxC,YAAY;AACZ,QAAQ;AACR,QAAQ,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE;AACrC,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,SAAS,CAAC,aAAa,GAAG,GAAG,EAAE;AACnC,QAAQ,IAAI,CAAC,UAAU,EAAE;AACzB,QAAQ,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,aAAa,EAAE,EAAE,IAAI,EAAE;AACzD,YAAY,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;AAC5B,QAAQ;AACR,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,CAAC,SAAS,CAAC,aAAa,GAAG,GAAG,EAAE;AACpC,QAAQ,IAAI,CAAC,UAAU,EAAE;AACzB,QAAQ,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,aAAa,EAAE,EAAE,IAAI,EAAE;AACzD,YAAY,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;AAC5B,YAAY,MAAM,IAAI,CAAC,UAAU;AACjC,QAAQ;AACR,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,KAAK,CAAC,IAAI,EAAE;AAChB,QAAQ,MAAM,KAAK,GAAG,IAAI,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG;AAC5C,QAAQ,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC;AAC5B,QAAQ,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG;AAC5B,QAAQ,IAAI,CAAC,GAAG,IAAI,KAAK,KAAK,SAAS,IAAI,IAAI,CAAC,EAAE,KAAK,SAAS,EAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;AACvG,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC7C,QAAQ,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5C,QAAQ,IAAI,CAAC,CAAC,GAAG,IAAI;AACrB,QAAQ,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,iBAAiB,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC;AACtD,QAAQ,MAAM,GAAG,0BAA0B,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AACjE,QAAQ,IAAI,CAAC,EAAE,IAAI,KAAK,GAAG,IAAI,GAAG,GAAG,GAAG,IAAI,GAAG,GAAG;AAClD,QAAQ,OAAO,IAAI,CAAC,CAAC;AACrB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,iBAAiB,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE;AACrC,QAAQ,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK;AAChC,QAAQ,MAAM,KAAK,GAAG,IAAI,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAC7C,QAAQ,MAAM,QAAQ,GAAG,IAAI;AAC7B,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI;AAC9B,QAAQ,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG;AAC5B,QAAQ,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE;AAC1B,QAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,EAAE,KAAK,SAAS,EAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;AACpF,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,EAAE,CAAC,EAAE;AAC1C,gBAAgB,MAAM,QAAQ;AAC9B,oBAAoB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAC7E,0BAA0B,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;AAC7C,0BAA0B,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,GAAG,EAAE,QAAQ,CAAC;AACpE,gBAAgB,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC;AAC9C,gBAAgB,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACvG,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAClE,YAAY;AACZ,QAAQ;AACR,QAAQ,OAAO,CAAC;AAChB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACpC,QAAQ,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC;AAC5C,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,QAAQ,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACrC,QAAQ,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC;AAC5C,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,QAAQ,OAAO,EAAE,CAAC,UAAU;AAC5B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,aAAa,eAAe,CAAC,CAAC,EAAE,UAAU,EAAE;AAChD,QAAQ,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC;AAC5C,QAAQ,OAAO,EAAE,CAAC,eAAe,EAAE;AACnC,IAAI;AACJ;;AC5cA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,IAAI,SAAS,EAAE,CAAC;AAC7B;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,CAAC,EAAE,UAAU,EAAE;AAC/B,QAAQ,KAAK;AACb,YAAY,CAAC;AACb,YAAY;AACZ,gBAAgB,UAAU,EAAE,EAAE;AAC9B,gBAAgB,OAAO,EAAE,EAAE;AAC3B,gBAAgB,CAAC,EAAE,CAAC;AACpB,gBAAgB,MAAM,EAAE,iBAAiB;AACzC,gBAAgB,IAAI,EAAE,IAAI;AAC1B,aAAa;AACb,YAAY,UAAU;AACtB,SAAS;AACT,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK;AACzC,QAAQ,IAAI,CAAC,KAAK,GAAG,CAAC;AACtB,QAAQ,MAAM,CAAC,0BAA0B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;AAC7D,QAAQ,IAAI,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE,MAAM,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE,GAAG,IAAI,CAAC;AACrF,IAAI;;AAEJ,IAAI,IAAI,GAAG;AACX;AACA,QAAQ,MAAM,UAAU,0BAA0B,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;AAC/E,QAAQ,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC;AAC5C,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,MAAM,0CAA0C,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;AACtF,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AACxB,QAAQ,IAAI,KAAK;AACjB,QAAQ,IAAI,MAAM,KAAK,aAAa,EAAE;AACtC,YAAY,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;AAClC,QAAQ,CAAC,MAAM;AACf,YAAY,KAAK,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;AACpC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxC,gBAAgB,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACpC,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAChD,oBAAoB,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC1D,oBAAoB,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC;AACnD,oBAAoB,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC;AACnD,gBAAgB;AAChB,YAAY;AACZ,QAAQ;;AAER,QAAQ,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;;AAErC,QAAQ,IAAI,CAAC,MAAM,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACzC,QAAQ,IAAI,CAAC,MAAM,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;;AAEzC;AACA,QAAQ,MAAM,GAAG,GAAG,IAAI;AACxB,QAAQ,MAAM,QAAQ,GAAG,EAAE;AAC3B,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;AACvC,YAAY,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACjC,YAAY,IAAI,OAAO,GAAG,CAAC,QAAQ;AACnC,YAAY,IAAI,OAAO,GAAG,QAAQ;AAClC,YAAY,IAAI,IAAI,GAAG,CAAC;AACxB,YAAY,IAAI,GAAG,GAAG,QAAQ;AAC9B,YAAY,IAAI,IAAI,GAAG,KAAK;AAC5B,YAAY,IAAI,IAAI,GAAG,CAAC;;AAExB,YAAY,OAAO,CAAC,IAAI,IAAI,GAAG,EAAE,EAAE;AACnC;AACA,gBAAgB,IAAI,GAAG,CAAC;AACxB,gBAAgB,IAAI,MAAM,GAAG,CAAC;AAC9B,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAC5C,oBAAoB,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC;AAC1C,oBAAoB,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC;AACnE,oBAAoB,MAAM,IAAI,IAAI,GAAG,EAAE;AACvC,oBAAoB,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE;AAChC,oBAAoB,IAAI,IAAI,EAAE;AAC9B,gBAAgB;AAChB;AACA,gBAAgB,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,MAAM,IAAI,IAAI,GAAG,CAAC;AAChF,gBAAgB,IAAI,CAAC,GAAG,OAAO,EAAE;AACjC,oBAAoB,OAAO,GAAG,IAAI;AAClC,oBAAoB,IAAI,GAAG,OAAO,KAAK,QAAQ,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,GAAG,OAAO,IAAI,CAAC;AACjF,gBAAgB,CAAC,MAAM;AACvB,oBAAoB,OAAO,GAAG,IAAI;AAClC,oBAAoB,IAAI,GAAG,OAAO,KAAK,CAAC,QAAQ,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,GAAG,OAAO,IAAI,CAAC;AAClF,gBAAgB;AAChB,gBAAgB,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC,GAAG,GAAG;AAClD,YAAY;AACZ;AACA,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxC,gBAAgB,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI;AAC/B,YAAY;AACZ,QAAQ;;AAER;AACA,QAAQ,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC;AACxB,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxC,gBAAgB,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,MAAM,CAAC;AAChF,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACpC,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACpC,YAAY;AACZ,QAAQ;AACR,QAAQ,IAAI,CAAC,EAAE,GAAG,CAAC;AACnB,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,SAAS,CAAC,UAAU,GAAG,GAAG,EAAE;AAChC,QAAQ,IAAI,CAAC,UAAU,EAAE;AACzB,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,EAAE,CAAC,EAAE;AAC7C,YAAY,IAAI,CAAC,IAAI,EAAE;AACvB,QAAQ;AACR,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,CAAC,SAAS,CAAC,UAAU,GAAG,GAAG,EAAE;AACjC,QAAQ,IAAI,CAAC,UAAU,EAAE;AACzB,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,EAAE,CAAC,EAAE;AAC7C,YAAY,IAAI,CAAC,IAAI,EAAE;AACvB,YAAY,MAAM,IAAI,CAAC,UAAU;AACjC,QAAQ;AACR,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,GAAG;AACX,QAAQ,MAAM,IAAI,GAAG,EAAE,IAAI,CAAC,KAAK;AACjC,QAAQ,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;AAC3F,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM;AACjC,QAAQ,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM;AACjC,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE;AACzB,QAAQ,MAAM,GAAG,0BAA0B,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;AAC9D,QAAQ,MAAM,OAAO,0BAA0B,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;AACxE,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;;AAExB;AACA,QAAQ,MAAM,IAAI,GAAG,IAAI,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;;AAEvC;AACA,QAAQ,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC;AAC5C,QAAQ,IAAI,IAAI,GAAG,CAAC;AACpB,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAC5C,gBAAgB,IAAI,IAAI,GAAG,CAAC;AAC5B,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,EAAE,CAAC,EAAE;AAC9C,oBAAoB,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAC/D,oBAAoB,IAAI,IAAI,KAAK,GAAG,KAAK;AACzC,gBAAgB;AAChB,gBAAgB,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AACzC,gBAAgB,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;AACtC,gBAAgB,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;AACtC,gBAAgB,IAAI,IAAI,CAAC,GAAG,EAAE;AAC9B,YAAY;AACZ,QAAQ;;AAER;AACA,QAAQ,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACrC,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAC5C,gBAAgB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC;AACnE,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC;AACtC,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC;AACtC,YAAY;AACZ,QAAQ;;AAER,QAAQ,MAAM,IAAI,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC;AAChD,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxC,gBAAgB,MAAM,OAAO,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAC3F,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,EAAE,CAAC,EAAE;AAC9C,oBAAoB,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACnF,gBAAgB;AAChB,YAAY;AACZ,QAAQ;;AAER;AACA,QAAQ,MAAM,KAAK,GAAG,IAAI,YAAY,CAAC,GAAG,CAAC;AAC3C,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,EAAE,CAAC,EAAE;AAC1C,gBAAgB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAC5C,gBAAgB,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAC7C,gBAAgB,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;;AAEhD,gBAAgB,IAAI,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,GAAG,GAAG,GAAG,MAAM,GAAG,GAAG;AAC7F,gBAAgB,IAAI,OAAO,GAAG,IAAI,EAAE,OAAO,GAAG,IAAI;AAClD,gBAAgB,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC;;AAE9C,gBAAgB,MAAM,MAAM,GAAG,IAAI,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG;AACrD,gBAAgB,MAAM,MAAM,GAAG,MAAM,GAAG,GAAG,GAAG,OAAO,GAAG,OAAO,GAAG,GAAG;AACrE,gBAAgB,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;;AAE7C,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;AACzC,gBAAgB,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AACzC,YAAY;AACZ,QAAQ;;AAER,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,EAAE,CAAC,EAAE;AAC1C,gBAAgB,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAC/C,YAAY;AACZ,QAAQ;;AAER,QAAQ,OAAO,IAAI,CAAC,CAAC;AACrB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACpC,QAAQ,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC;AAC1C,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,QAAQ,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACrC,QAAQ,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC;AAC1C,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,QAAQ,OAAO,EAAE,CAAC,UAAU;AAC5B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,aAAa,eAAe,CAAC,CAAC,EAAE,UAAU,EAAE;AAChD,QAAQ,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC;AAC1C,QAAQ,OAAO,EAAE,CAAC,eAAe,EAAE;AACnC,IAAI;AACJ;;AC7RA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,GAAG,GAAG,EAAE;AAC9C,IAAI,MAAM,OAAO,GAAG,IAAI;AACxB,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC,MAAM;AACvB,IAAI,IAAI,KAAK,GAAG,IAAI;AACpB,IAAI,IAAI,GAAG,GAAG,KAAK;AACnB,IAAI,MAAM,CAAC,qBAAqB,EAAE,CAAC,KAAK,EAAE,CAAC;AAC3C,IAAI,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;AACjB,IAAI,IAAI,WAAW,GAAG,KAAK;;AAE3B,IAAI,OAAO,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;AAC5C,QAAQ,WAAW,GAAG,IAAI;AAC1B,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI;AACxB,YAAY,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;AAC5B,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI;AACxB,YAAY,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,IAAI,IAAI;AACxC,YAAY,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,EAAE;AACxC,gBAAgB,WAAW,GAAG,KAAK;AACnC,YAAY;AACZ,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,EAAE;AAC9B,YAAY,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;AACrB,QAAQ;AACR,QAAQ,KAAK,IAAI,GAAG,IAAI,EAAE,GAAG,IAAI,GAAG,GAAG;AACvC,QAAQ,GAAG,GAAG,EAAE;AAChB,IAAI;AACJ,IAAI,OAAO,CAAC;AACZ;;AC3BA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,IAAI,SAAS,EAAE,CAAC;AAC7B;AACA;AACA;AACA;AACA,IAAI,WAAW,CAAC,CAAC,EAAE,UAAU,EAAE;AAC/B,QAAQ,KAAK;AACb,YAAY,CAAC;AACb,YAAY;AACZ,gBAAgB,WAAW,EAAE,EAAE;AAC/B,gBAAgB,kBAAkB,EAAE,CAAC;AACrC,gBAAgB,QAAQ,EAAE,CAAC;AAC3B,gBAAgB,CAAC,EAAE,CAAC;AACpB,gBAAgB,MAAM,EAAE,SAAS;AACjC,gBAAgB,IAAI,EAAE,IAAI;AAC1B,gBAAgB,OAAO,EAAE,CAAC;AAC1B,gBAAgB,iBAAiB,EAAE,CAAC;AACpC,gBAAgB,mBAAmB,EAAE,CAAC;AACtC,gBAAgB,qBAAqB,EAAE,CAAC;AACxC,gBAAgB,SAAS,EAAE,GAAG;AAC9B,gBAAgB,cAAc,EAAE,CAAC;AACjC,aAAa;AACb,YAAY,UAAU;AACtB,SAAS;AACT,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK;AACzC,QAAQ,MAAM,WAAW,0BAA0B,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;AACjF,QAAQ,MAAM,kBAAkB,0BAA0B,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;AAC/F,QAAQ,MAAM,CAAC,0BAA0B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;AAC7D;AACA;AACA;AACA,QAAQ,IAAI,WAAW,GAAG,IAAI,CAAC,EAAE,EAAE;AACnC,YAAY,MAAM,IAAI,KAAK;AAC3B,gBAAgB,CAAC,wBAAwB,EAAE,WAAW,CAAC,2CAA2C,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;AAC/G,aAAa;AACb,QAAQ;AACR,QAAQ,IAAI,kBAAkB,GAAG,WAAW,EAAE;AAC9C,YAAY,MAAM,IAAI,KAAK;AAC3B,gBAAgB,CAAC,+BAA+B,EAAE,kBAAkB,CAAC,mDAAmD,EAAE,WAAW,CAAC,CAAC,CAAC;AACxI,aAAa;AACb,QAAQ;AACR,QAAQ,IAAI,CAAC,KAAK,GAAG,CAAC;AACtB,QAAQ,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW;AAC3C,QAAQ,IAAI,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE,MAAM,UAAU,CAAC,MAAM,CAAC;AAChE,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,eAAe,CAAC,MAAM,EAAE,QAAQ,EAAE;AACtC;AACA,QAAQ,MAAM,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;AAC7D,QAAQ,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE,GAAG,CAAC;AAC/C,QAAQ,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE,GAAG,CAAC;;AAE/C,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACnD,YAAY,MAAM,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC;AAC9B,YAAY,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,GAAG,QAAQ,CAAC,GAAG,MAAM,CAAC;AAC/E,QAAQ;;AAER;AACA,QAAQ,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK;AAC3B,YAAY,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1F,YAAY,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAClE,QAAQ,CAAC;;AAET,QAAQ,OAAO,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAClC,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,6BAA6B,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE;AAC3D,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAC1D,YAAY,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC;AAC/B,YAAY,MAAM,SAAS,GAAG,SAAS,CAAC,CAAC,CAAC;AAC1C,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAC9D,gBAAgB,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,GAAG;AACrD,gBAAgB,SAAS,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG;AAC9E,YAAY;AACZ,QAAQ;AACR,QAAQ,OAAO,SAAS;AACxB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,gBAAgB,CAAC,GAAG,EAAE,CAAC,EAAE;AAC7B,QAAQ,MAAM,kBAAkB,GAAG,IAAI;AACvC,QAAQ,MAAM,gBAAgB,GAAG,IAAI;AACrC,QAAQ,MAAM,MAAM,GAAG,EAAE;AACzB,QAAQ,MAAM,kBAAkB,0BAA0B,IAAI,CAAC,WAAW,CAAC,kBAAkB,CAAC;AAC9F,QAAQ,MAAM,MAAM,0CAA0C,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;AACtF,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AACnC,QAAQ,MAAM,IAAI,GAAG,EAAE;AACvB,QAAQ,MAAM,MAAM,GAAG,EAAE;AACzB,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AACxB,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5B;;AAEA;AACA,QAAQ,MAAM,SAAS,GAAG,EAAE;AAC5B,QAAQ,IAAI,MAAM,KAAK,aAAa,IAAI,GAAG,YAAY,QAAQ,EAAE;AACjE,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACxC,gBAAgB,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;AACnE,YAAY;AACZ,QAAQ,CAAC,MAAM;AACf,YAAY,KAAK,MAAM,GAAG,IAAI,CAAC,EAAE;AACjC,gBAAgB,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;AAC5D,YAAY;AACZ,QAAQ;;AAER,QAAQ,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC;AACpD,QAAQ,MAAM,aAAa,GAAG,kBAAkB,GAAG,KAAK;AACxD,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,IAAI,EAAE,GAAG,CAAC;AACtB,YAAY,IAAI,EAAE,GAAG,QAAQ;AAC7B,YAAY,IAAI,GAAG,GAAG,CAAC;AACvB,YAAY,IAAI,GAAG,GAAG,CAAC;;AAEvB,YAAY,MAAM,aAAa,GAAG,SAAS,CAAC,CAAC,CAAC;AAC9C,YAAY,MAAM,aAAa,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC;AAC7E,YAAY,MAAM,oBAAoB,GAAG,aAAa,CAAC,MAAM;AAC7D,YAAY,IAAI,oBAAoB,IAAI,kBAAkB,EAAE;AAC5D,gBAAgB,IAAI,KAAK,GAAG,CAAC,EAAE;AAC/B,oBAAoB,GAAG,GAAG,aAAa,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ;AAC3D,oBAAoB,IAAI,aAAa,GAAG,kBAAkB,EAAE;AAC5D,wBAAwB,GAAG,IAAI,aAAa,IAAI,aAAa,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,aAAa,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC;AAClH,oBAAoB;AACpB,gBAAgB,CAAC,MAAM;AACvB,oBAAoB,GAAG,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,QAAQ;AACnE,gBAAgB;AAChB,YAAY,CAAC,MAAM,IAAI,oBAAoB,GAAG,CAAC,EAAE;AACjD,gBAAgB,GAAG,GAAG,aAAa,CAAC,oBAAoB,GAAG,CAAC,CAAC,CAAC,QAAQ;AACtE,YAAY;AACZ,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,EAAE,CAAC,EAAE;AAC7C,gBAAgB,IAAI,IAAI,GAAG,CAAC;AAC5B,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAC5C,oBAAoB,MAAM,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,GAAG;AAC7D,oBAAoB,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC;AAC5D,gBAAgB;AAChB,gBAAgB,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC,GAAG,kBAAkB,EAAE;AAClE,oBAAoB;AACpB,gBAAgB;AAChB,gBAAgB,IAAI,IAAI,GAAG,MAAM,EAAE;AACnC,oBAAoB,CAAC,EAAE,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;AACpD,gBAAgB,CAAC,MAAM;AACvB,oBAAoB,IAAI,EAAE,KAAK,QAAQ,EAAE;AACzC,wBAAwB,CAAC,EAAE,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC;AAClD,oBAAoB,CAAC,MAAM;AAC3B,wBAAwB,CAAC,EAAE,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;AACxD,oBAAoB;AACpB,gBAAgB;AAChB,YAAY;;AAEZ;AACA,YAAY,IAAI,GAAG,GAAG,CAAC,EAAE;AACzB,gBAAgB,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,GAAG,aAAa,CAAC,MAAM;AAC1G,gBAAgB,IAAI,GAAG,GAAG,gBAAgB,GAAG,SAAS,EAAE;AACxD,oBAAoB,GAAG,GAAG,gBAAgB,GAAG,SAAS;AACtD,gBAAgB;AAChB,YAAY,CAAC,MAAM;AACnB,gBAAgB,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM;AAC/C,oBAAoB,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM;AAC5F,oBAAoB,CAAC;AACrB,iBAAiB;AACjB,gBAAgB,IAAI,GAAG,GAAG,gBAAgB,GAAG,MAAM,EAAE;AACrD,oBAAoB,GAAG,GAAG,gBAAgB,GAAG,MAAM;AACnD,gBAAgB;AAChB,YAAY;AACZ,YAAY,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG;AACzB,YAAY,MAAM,CAAC,CAAC,CAAC,GAAG,GAAG;AAC3B,QAAQ;AACR,QAAQ,OAAO;AACf,YAAY,SAAS,EAAE,SAAS;AAChC,YAAY,MAAM,EAAE,MAAM;AAC1B,YAAY,IAAI,EAAE,IAAI;AACtB,SAAS;AACT,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,qBAAqB,CAAC,CAAC,EAAE,WAAW,EAAE;AAC1C,QAAQ,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC5B,QAAQ,MAAM,MAAM,0CAA0C,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;AACtF,QAAQ,MAAM,iBAAiB,0BAA0B,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAAC;;AAE5F,QAAQ,MAAM,GAAG;AACjB,YAAY,MAAM,KAAK;AACvB,kBAAkB,IAAI,QAAQ,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE;AAC9C,sBAAsB,MAAM,EAAE,aAAa;AAC3C,sBAAsB,IAAI,yBAAyB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;AACzE,mBAAmB;AACnB,kBAAkB,IAAI,QAAQ,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,yBAAyB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;AAC9G,QAAQ,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,gBAAgB,CAAC,GAAG,EAAE,WAAW,CAAC;AACjF,QAAQ,SAAS,GAAG,IAAI,CAAC,6BAA6B,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC;AAC/E,QAAQ,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC;AAChD,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AACpC,YAAY,MAAM,WAAW,GAAG,SAAS,CAAC,CAAC,CAAC;AAC5C,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE;AACzD,gBAAgB,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AAClF,YAAY;AACZ,QAAQ;;AAER,QAAQ,MAAM,iBAAiB,GAAG,MAAM,CAAC,CAAC;AAC1C,QAAQ,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC;AAC1D,QAAQ,OAAO;AACf,aAAa,GAAG,CAAC,iBAAiB;AAClC,aAAa,GAAG,CAAC,WAAW;AAC5B,aAAa,IAAI,CAAC,iBAAiB;AACnC,aAAa,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,GAAG,iBAAiB,CAAC,CAAC;AACzD,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,uBAAuB,CAAC,QAAQ,EAAE;AACtC,QAAQ,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;AACjE,QAAQ,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ;AACrC,QAAQ,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;AAChE,QAAQ,MAAM,UAAU,GAAG,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC;AAClD,QAAQ,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK;AAClC,YAAY,MAAM,MAAM,GAAG,CAAC,GAAG,UAAU;AACzC,YAAY,IAAI,MAAM,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,MAAM,CAAC;AACrE,QAAQ,CAAC,CAAC;AACV,QAAQ,OAAO,MAAM;AACrB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,MAAM,CAAC,KAAK,EAAE;AAClB,QAAQ,MAAM,IAAI,GAAG,EAAE;AACvB,QAAQ,MAAM,IAAI,GAAG,EAAE;AACvB,QAAQ,MAAM,IAAI,GAAG,EAAE;AACvB,QAAQ,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK;AAC5C,QAAQ,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,MAAM,EAAE,EAAE,GAAG,EAAE;AAC/C,YAAY,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,MAAM,EAAE,EAAE,GAAG,EAAE;AACnD,gBAAgB,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC;AACnD,gBAAgB,IAAI,KAAK,KAAK,CAAC,EAAE;AACjC,oBAAoB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;AAClC,oBAAoB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;AAClC,oBAAoB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;AACpC,gBAAgB;AAChB,YAAY;AACZ,QAAQ;AACR,QAAQ,OAAO;AACf,YAAY,IAAI,EAAE,IAAI;AACtB,YAAY,IAAI,EAAE,IAAI;AACtB,YAAY,IAAI,EAAE,IAAI;AACtB,SAAS;AACT,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,IAAI,GAAG;AACX,QAAQ,MAAM,OAAO,0BAA0B,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;AACxE,QAAQ,MAAM,QAAQ,0BAA0B,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC;AAC1E,QAAQ,MAAM,WAAW,0BAA0B,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC;AAChF,QAAQ,MAAM,SAAS,0BAA0B,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC;AAC5E,QAAQ,MAAM,qBAAqB,0BAA0B,IAAI,CAAC,WAAW,CAAC,qBAAqB,CAAC;AACpG,QAAQ,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,QAAQ,CAAC;AAC9D,QAAQ,IAAI,CAAC,EAAE,GAAG,CAAC;AACnB,QAAQ,IAAI,CAAC,EAAE,GAAG,CAAC;AACnB,QAAQ,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,EAAE,WAAW,CAAC;AACrE,QAAQ,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;AACtE,QAAQ,IAAI,CAAC,KAAK,GAAG,IAAI;AACzB,QAAQ,IAAI,CAAC,KAAK,GAAG,IAAI;AACzB,QAAQ,IAAI,CAAC,QAAQ,GAAG,OAAO;AAC/B,QAAQ,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,uBAAuB,CAAC,SAAS,CAAC;AACzE,QAAQ,IAAI,CAAC,2BAA2B,GAAG,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,qBAAqB,CAAC;AACxG,QAAQ,IAAI,CAAC,qBAAqB,GAAG,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE;AACpE,QAAQ,IAAI,CAAC,8BAA8B,GAAG,IAAI,CAAC,2BAA2B,CAAC,KAAK,EAAE;AACtF,QAAQ,OAAO,IAAI;AACnB,IAAI;;AAEJ,IAAI,KAAK,GAAG;AACZ,QAAQ,IAAI,CAAC,UAAU,EAAE;AACzB,QAAQ,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,QAAQ,EAAE;AAC7E,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,SAAS,CAAC,UAAU,GAAG,GAAG,EAAE;AAChC,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,KAAK,UAAU,EAAE;AACxD,YAAY,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,UAAU,CAAC;AACnD,YAAY,IAAI,CAAC,IAAI,EAAE;AACvB,QAAQ;AACR,QAAQ,IAAI,CAAC,UAAU,EAAE;AACzB,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,EAAE,CAAC,EAAE;AAC7C,YAAY,IAAI,CAAC,IAAI,EAAE;AACvB,QAAQ;AACR,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,CAAC,SAAS,CAAC,UAAU,GAAG,GAAG,EAAE;AACjC,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,KAAK,UAAU,EAAE;AACxD,YAAY,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,UAAU,CAAC;AACnD,YAAY,IAAI,CAAC,IAAI,EAAE;AACvB,QAAQ;AACR,QAAQ,IAAI,CAAC,UAAU,EAAE;AACzB,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,EAAE,CAAC,EAAE;AAC7C,YAAY,IAAI,CAAC,IAAI,EAAE;AACvB,YAAY,MAAM,IAAI,CAAC,UAAU;AACjC,QAAQ;AACR,QAAQ,OAAO,IAAI,CAAC,UAAU;AAC9B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI,KAAK,CAAC,CAAC,EAAE;AACb,QAAQ,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;AAC3B,QAAQ,IAAI,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE;AAC7B,QAAQ,OAAO,CAAC;AAChB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,gBAAgB,CAAC,cAAc,EAAE,cAAc,EAAE,IAAI,EAAE,IAAI,EAAE;AACjE,QAAQ,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW;AAC3C,QAAQ,MAAM,mBAAmB,0BAA0B,IAAI,CAAC,SAAS,CAAC,qBAAqB,CAAC,CAAC;AACjG,QAAQ,MAAM,GAAG,0BAA0B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;AAC/D,QAAQ,MAAM;AACd,YAAY,MAAM,EAAE,KAAK;AACzB,YAAY,EAAE,EAAE,CAAC;AACjB,YAAY,EAAE,EAAE,CAAC;AACjB,YAAY,kBAAkB,EAAE,iBAAiB;AACjD,YAAY,2BAA2B,EAAE,0BAA0B;AACnE,YAAY,8BAA8B,EAAE,6BAA6B;AACzE,YAAY,qBAAqB,EAAE,oBAAoB;AACvD,YAAY,KAAK,EAAE,IAAI;AACvB,SAAS,GAAG,IAAI;AAChB,QAAQ;AACR,YAAY,KAAK,KAAK,SAAS;AAC/B,YAAY,CAAC,KAAK,SAAS;AAC3B,YAAY,CAAC,KAAK,SAAS;AAC3B,YAAY,iBAAiB,KAAK,SAAS;AAC3C,YAAY,0BAA0B,KAAK,SAAS;AACpD,YAAY,6BAA6B,KAAK,SAAS;AACvD,YAAY,oBAAoB,KAAK,SAAS;AAC9C,YAAY,IAAI,KAAK;AACrB,UAAU;AACV,YAAY,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;AACjD,QAAQ;AACR,QAAQ,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM;;AAEvC,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,iBAAiB,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,EAAE;AAClE,YAAY,IAAI,oBAAoB,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE;AACvD,gBAAgB,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;AACjC,gBAAgB,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;AACjC,gBAAgB,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC;AACrD,gBAAgB,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC;AACnD,gBAAgB,MAAM,IAAI,GAAG,iBAAiB,CAAC,OAAO,EAAE,KAAK,CAAC;AAC9D,gBAAgB,IAAI,IAAI,GAAG,CAAC,EAAE;AAC9B,oBAAoB,MAAM,UAAU,GAAG,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;AAC3F,oBAAoB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,EAAE,CAAC,EAAE;AAClD,wBAAwB,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK;AACzF,wBAAwB,OAAO,CAAC,CAAC,CAAC,IAAI,MAAM;AAC5C,wBAAwB,KAAK,CAAC,CAAC,CAAC,IAAI,MAAM;AAC1C,oBAAoB;AACpB,gBAAgB;AAChB,gBAAgB,oBAAoB,CAAC,CAAC,CAAC,IAAI,iBAAiB,CAAC,CAAC,CAAC;AAC/D,gBAAgB,MAAM,aAAa,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,6BAA6B,CAAC,CAAC,CAAC,IAAI,0BAA0B,CAAC,CAAC,CAAC;AACrH,gBAAgB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,EAAE,EAAE,CAAC,EAAE;AACxD,oBAAoB,MAAM,CAAC,GAAG,UAAU,CAAC,UAAU,GAAG,WAAW;AACjE,oBAAoB,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC7D,oBAAoB,MAAM,IAAI,GAAG,iBAAiB,CAAC,OAAO,EAAE,KAAK,CAAC;AAClE,oBAAoB,IAAI,IAAI,GAAG,CAAC,EAAE;AAClC,wBAAwB,MAAM,UAAU,GAAG,CAAC,CAAC,GAAG,mBAAmB,GAAG,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAChH,wBAAwB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,EAAE,CAAC,EAAE;AACtD,4BAA4B,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK;AAC7F,4BAA4B,OAAO,CAAC,CAAC,CAAC,IAAI,MAAM;AAChD,4BAA4B,KAAK,CAAC,CAAC,CAAC,IAAI,MAAM;AAC9C,wBAAwB;AACxB,oBAAoB;AAEpB,gBAAgB;AAChB,gBAAgB,6BAA6B,CAAC,CAAC,CAAC,IAAI,aAAa,GAAG,0BAA0B,CAAC,CAAC,CAAC;AACjG,YAAY;AACZ,QAAQ;AACR,QAAQ,OAAO,cAAc;AAC7B,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI,IAAI,GAAG;AACX,QAAQ,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC;AAC7E,QAAQ,MAAM,IAAI,GAAG,EAAE,IAAI,CAAC,KAAK;AACjC,QAAQ,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AACxB,QAAQ,MAAM,cAAc,0BAA0B,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC;AACtF,QAAQ,MAAM,SAAS,0BAA0B,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC;AAC5E,QAAQ,IAAI,CAAC,MAAM,GAAG,cAAc,IAAI,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;AAC7D,QAAQ,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC;;AAEpE,QAAQ,OAAO,IAAI,CAAC,CAAC;AACrB,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,OAAO,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACpC,QAAQ,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC;AAC1C,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,QAAQ,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE;AACrC,QAAQ,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC;AAC1C,QAAQ,OAAO,EAAE,CAAC,SAAS,EAAE;AAC7B,QAAQ,OAAO,EAAE,CAAC,UAAU;AAC5B,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,aAAa,eAAe,CAAC,CAAC,EAAE,UAAU,EAAE;AAChD,QAAQ,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC;AAC1C,QAAQ,OAAO,EAAE,CAAC,eAAe,EAAE;AACnC,IAAI;AACJ;;AChgBK,MAAC,OAAO,GAAG,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"} \ No newline at end of file +{"version":3,"file":"druid.cjs","sources":["../src/metrics/bray_curtis.js","../src/metrics/canberra.js","../src/metrics/chebyshev.js","../src/metrics/cosine.js","../src/metrics/euclidean_squared.js","../src/metrics/euclidean.js","../src/metrics/goodman_kruskal.js","../src/metrics/hamming.js","../src/metrics/haversine.js","../src/metrics/jaccard.js","../src/metrics/manhattan.js","../src/metrics/sokal_michener.js","../src/metrics/wasserstein.js","../src/metrics/yule.js","../src/matrix/distance_matrix.js","../src/matrix/k_nearest_neighbors.js","../src/matrix/linspace.js","../src/linear_algebra/inner_product.js","../src/numerical/kahan_sum.js","../src/numerical/neumair_sum.js","../src/linear_algebra/qr.js","../src/linear_algebra/qr_householder.js","../src/util/max.js","../src/util/min.js","../src/util/randomizer.js","../src/linear_algebra/simultaneous_poweriteration.js","../src/matrix/Matrix.js","../src/matrix/norm.js","../src/matrix/normalize.js","../src/clustering/Clustering.js","../src/clustering/CURE.js","../src/clustering/Hierarchical_Clustering.js","../src/datastructure/DisjointSet.js","../src/datastructure/Heap.js","../src/clustering/KMeans.js","../src/clustering/KMedoids.js","../src/clustering/MeanShift.js","../src/clustering/OPTICS.js","../src/clustering/XMeans.js","../src/dimred/DR.js","../src/dimred/FASTMAP.js","../src/knn/KNN.js","../src/knn/Annoy.js","../src/knn/BallTree.js","../src/knn/HNSW.js","../src/knn/KDTree.js","../src/knn/LSH.js","../src/knn/NaiveKNN.js","../src/knn/NNDescent.js","../src/dimred/PCA.js","../src/dimred/PaCMAP.js","../src/dimred/LocalMAP.js","../src/dimred/SMACOF.js","../src/dimred/ISOMAP.js","../src/dimred/LDA.js","../src/dimred/LLE.js","../src/dimred/MDS.js","../src/dimred/LSP.js","../src/dimred/LTSA.js","../src/dimred/SAMMON.js","../src/dimred/SQDMDS.js","../src/dimred/TopoMap.js","../src/dimred/TriMap.js","../src/dimred/TSNE.js","../src/optimization/powell.js","../src/dimred/UMAP.js","../src/index.js"],"sourcesContent":["/**\n * Computes the Bray-Curtis distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The Bray-Curtis distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Bray%E2%80%93Curtis_dissimilarity}\n */\nexport function bray_curtis(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n let sum_abs_diff = 0;\n let sum_ab = 0;\n for (let i = 0; i < a.length; ++i) {\n sum_abs_diff += Math.abs(a[i] - b[i]);\n sum_ab += a[i] + b[i];\n }\n return sum_abs_diff / sum_ab;\n}\n","/**\n * Computes the canberra distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The canberra distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Canberra_distance}\n */\nexport function canberra(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let sum = 0;\n for (let i = 0; i < n; ++i) {\n sum += Math.abs(a[i] - b[i]) / (Math.abs(a[i]) + Math.abs(b[i]));\n }\n return sum;\n}\n","/**\n * Computes the chebyshev distance (L) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The chebyshev distance between `a` and `b`.\n */\nexport function chebyshev(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n const res = [];\n for (let i = 0; i < n; ++i) {\n res.push(Math.abs(a[i] - b[i]));\n }\n return Math.max(...res);\n}\n","/**\n * Computes the cosine distance (not similarity) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The cosine distance between `a` and `b`.\n * @example\n * import { cosine } from \"@saehrimnir/druidjs\";\n * const a = [1, 2, 3];\n * const b = [4, 5, 6];\n * const distance = cosine(a, b); // 0.9746318461970762\n */\nexport function cosine(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let sum = 0;\n let sum_a = 0;\n let sum_b = 0;\n for (let i = 0; i < n; ++i) {\n sum += a[i] * b[i];\n sum_a += a[i] * a[i];\n sum_b += b[i] * b[i];\n }\n return Math.acos(sum / (Math.sqrt(sum_a) * Math.sqrt(sum_b)));\n}\n","/**\n * Computes the squared euclidean distance (l_2^2) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The squared euclidean distance between `a` and `b`.\n\n */\nexport function euclidean_squared(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let sum = 0;\n for (let i = 0; i < n; ++i) {\n const a_b = a[i] - b[i];\n sum += a_b * a_b;\n }\n return sum;\n}\n","import { euclidean_squared } from \"../metrics/euclidean_squared.js\";\n\n/**\n * Computes the euclidean distance (`l_2`) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The euclidean distance between `a` and `b`.\n */\nexport function euclidean(a, b) {\n return Math.sqrt(euclidean_squared(a, b));\n}\n","/**\n * Computes the Goodman-Kruskal gamma coefficient for ordinal association.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a - First categorical/ordinal variable\n * @param {number[] | Float64Array} b - Second categorical/ordinal variable\n * @returns {number} The Goodman-Kruskal gamma coefficient between `a` and `b` (-1 to 1).\n * @see {@link https://en.wikipedia.org/wiki/Goodman_and_Kruskal%27s_gamma}\n */\nexport function goodman_kruskal(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n if (n < 2) return 0;\n\n let concordant = 0;\n let discordant = 0;\n let tie_a = 0;\n let tie_b = 0;\n\n for (let i = 0; i < n; ++i) {\n for (let j = i + 1; j < n; ++j) {\n const a_diff = a[i] - a[j];\n const b_diff = b[i] - b[j];\n const a_tied = a_diff === 0;\n const b_tied = b_diff === 0;\n\n if (a_tied && b_tied) {\n } else if (a_tied) {\n tie_a++;\n } else if (b_tied) {\n tie_b++;\n } else if (a_diff * b_diff > 0) {\n concordant++;\n } else {\n discordant++;\n }\n }\n }\n\n const denominator = concordant + discordant + tie_a + tie_b;\n if (denominator === 0) return 0;\n\n const numerator = concordant + discordant;\n if (numerator === 0) return 0;\n\n return (concordant - discordant) / numerator;\n}\n","/**\n * Computes the hamming distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The hamming distance between `a` and `b`.\n */\nexport function hamming(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let disagree = 0;\n for (let i = 0; i < n; ++i) {\n const x = a[i];\n const y = b[i];\n disagree += x !== y ? 1 : 0;\n }\n return disagree / n;\n}\n","/**\n * Computes the Haversine distance between two points on a sphere of unit length 1. Multiply the result with the radius of the sphere. (For instance Earth's radius is 6371km)\n *\n * @category Metrics\n * @param {number[] | Float64Array} a - Point [lat1, lon1] in radians\n * @param {number[] | Float64Array} b - Point [lat2, lon2] in radians\n * @returns {number} The Haversine distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Haversine_formula}\n */\nexport function haversine(a, b) {\n if (a.length !== 2 || b.length !== 2)\n throw new Error(\"Haversine distance requires exactly 2 coordinates [lat, lon] for each point!\");\n const lat1 = a[0];\n const lon1 = a[1];\n const lat2 = b[0];\n const lon2 = b[1];\n\n const dlat = lat2 - lat1;\n const dlon = lon2 - lon1;\n\n const sin_dlat2 = Math.sin(dlat / 2);\n const sin_dlon2 = Math.sin(dlon / 2);\n\n const x = sin_dlat2 * sin_dlat2 + Math.cos(lat1) * Math.cos(lat2) * sin_dlon2 * sin_dlon2;\n const c = 2 * Math.atan2(Math.sqrt(x), Math.sqrt(1 - x));\n\n return c;\n}\n","/**\n * Computes the jaccard distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The jaccard distance between `a` and `b`.\n */\nexport function jaccard(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let num_non_zero = 0;\n let num_equal = 0;\n for (let i = 0; i < n; ++i) {\n const x = a[i] !== 0;\n const y = b[i] !== 0;\n num_non_zero += x || y ? 1 : 0;\n num_equal += x && y ? 1 : 0;\n }\n return (num_non_zero - num_equal) / num_non_zero;\n}\n","/**\n * Computes the manhattan distance (`l_1`) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The manhattan distance between `a` and `b`.\n */\nexport function manhattan(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let sum = 0;\n for (let i = 0; i < n; ++i) {\n sum += Math.abs(a[i] - b[i]);\n }\n return sum;\n}\n","/**\n * Computes the Sokal-Michener distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The Sokal-Michener distance between `a` and `b`.\n\n */\nexport function sokal_michener(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let num_not_equal = 0;\n for (let i = 0; i < n; ++i) {\n const x = a[i] !== 0;\n const y = b[i] !== 0;\n num_not_equal += x !== y ? 1 : 0;\n }\n return (2 * num_not_equal) / (n + num_not_equal);\n}\n","/**\n * Computes the 1D Wasserstein distance (Earth Mover's Distance) between two distributions.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a - First distribution (histogram or probability mass)\n * @param {number[] | Float64Array} b - Second distribution (histogram or probability mass)\n * @returns {number} The Wasserstein/EMD distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Wasserstein_metric}\n */\nexport function wasserstein(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let sumA = 0;\n let sumB = 0;\n for (let i = 0; i < n; i++) {\n sumA += a[i];\n sumB += b[i];\n }\n\n // Fallback if sums are 0\n if (sumA === 0 && sumB === 0) return 0;\n if (sumA === 0 || sumB === 0) return Infinity;\n\n let distance = 0;\n let cumA = 0;\n let cumB = 0;\n for (let i = 0; i < n; i++) {\n cumA += a[i] / sumA;\n cumB += b[i] / sumB;\n distance += Math.abs(cumA - cumB);\n }\n return distance;\n}\n","/**\n * Computes the yule distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The yule distance between `a` and `b`.\n */\nexport function yule(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let num_true_true = 0;\n let num_true_false = 0;\n let num_false_true = 0;\n for (let i = 0; i < n; ++i) {\n const x = a[i] !== 0;\n const y = b[i] !== 0;\n num_true_true += x && y ? 1 : 0;\n num_true_false += x && !y ? 1 : 0;\n num_false_true += !x && y ? 1 : 0;\n }\n const num_false_false = n - num_true_true - num_true_false - num_false_true;\n return num_true_false === 0 || num_false_true === 0\n ? 0\n : (2 * num_true_false * num_false_true) / (num_true_true * num_false_false + num_true_false * num_false_true);\n}\n","import { euclidean } from \"../metrics/index.js\";\nimport { Matrix } from \"./index.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n\n/**\n * @param {Matrix | Float64Array[] | number[][]} A\n * @returns {A is Matrix}\n */\nfunction isMatrix(A) {\n return A instanceof Matrix;\n}\n\n/**\n * Computes the distance matrix of datamatrix `A`.\n *\n * @category Matrix\n * @param {Matrix | Float64Array[] | number[][]} A - Matrix.\n * @param {Metric} [metric=euclidean] - The diistance metric. Default is `euclidean`\n * @returns {Matrix} The distance matrix of `A`.\n */\nexport function distance_matrix(A, metric = euclidean) {\n /** @type {number} */\n const n = isMatrix(A) ? A.shape[0] : A.length;\n const D = new Matrix(n, n);\n for (let i = 0; i < n; ++i) {\n const A_i = isMatrix(A) ? A.row(i) : A[i];\n for (let j = i + 1; j < n; ++j) {\n const dist = metric(A_i, isMatrix(A) ? A.row(j) : A[j]);\n D.set_entry(i, j, dist);\n D.set_entry(j, i, dist);\n }\n }\n return D;\n}\n","//@ts-check\n\nimport { distance_matrix, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n\n/**\n * Computes the k-nearest neighbors of each row of `A`.\n *\n * @category Matrix\n * @param {Matrix} A - Either the data matrix, or a distance matrix.\n * @param {number} k - The number of neighbors to compute.\n * @param {Metric | \"precomputed\"} [metric=euclidean] Default is `euclidean`\n * @returns {{ i: number; j: number; distance: number }[][]} The kNN graph.\n */\nexport function k_nearest_neighbors(A, k, metric = euclidean) {\n A = A instanceof Matrix ? A : Matrix.from(A);\n const rows = A.shape[0];\n const D = metric === \"precomputed\" ? A : distance_matrix(A, metric);\n /** @type {{ i: number; j: number; distance: number }[][]} */\n const nN = [];\n for (let row = 0; row < rows; ++row) {\n const res = Array.from(D.row(row))\n .map((distance, col) => {\n return {\n i: row,\n j: col,\n distance: distance,\n };\n })\n .sort((a, b) => a.distance - b.distance)\n .slice(1, k + 1);\n nN.push(res);\n }\n return nN;\n}\n","/**\n * Creates an Array containing `number` numbers from `start` to `end`. If `number = null`.\n *\n * @category Matrix\n * @param {number} start - Start value.\n * @param {number} end - End value.\n * @param {number} [number] - Number of number between `start` and `end`.\n * @returns {number[]} An array with `number` entries, beginning at `start` ending at `end`.\n */\nexport function linspace(start, end, number) {\n if (number === undefined || number === null) {\n number = Math.max(Math.round(end - start) + 1, 1);\n }\n if (number < 2) {\n return number === 1 ? [start] : [];\n }\n const result = new Array(number);\n number -= 1;\n for (let i = number; i >= 0; --i) {\n result[i] = (i * end + (number - i) * start) / number;\n }\n return result;\n}\n","/**\n * Computes the inner product between two arrays of the same length.\n *\n * @category Linear Algebra\n * @param {number[] | Float64Array} a - Array a.\n * @param {number[] | Float64Array} b - Array b.\n * @returns The inner product between `a` and `b`.\n */\nexport function inner_product(a, b) {\n const N = a.length;\n if (N !== b.length) {\n throw new Error(\"Array a and b must have the same length!\");\n }\n let sum = 0;\n for (let i = 0; i < N; ++i) {\n sum += a[i] * b[i];\n }\n return sum;\n}\n","/**\n * Numerical stable summation with the Kahan summation algorithm.\n *\n * @category Numerical\n * @param {number[] | Float64Array} summands - Array of values to sum up.\n * @returns {number} The sum.\n * @see {@link https://en.wikipedia.org/wiki/Kahan_summation_algorithm}\n */\nexport function kahan_sum(summands) {\n const n = summands.length;\n let sum = 0;\n let compensation = 0;\n let y, t;\n\n for (let i = 0; i < n; ++i) {\n y = summands[i] - compensation;\n t = sum + y;\n compensation = t - sum - y;\n sum = t;\n }\n return sum;\n}\n","/**\n * Numerical stable summation with the Neumair summation algorithm.\n *\n * @category Numerical\n * @param {number[] | Float64Array} summands - Array of values to sum up.\n * @returns {number} The sum.\n * @see {@link https://en.wikipedia.org/wiki/Kahan_summation_algorithm#Further_enhancements}\n */\nexport function neumair_sum(summands) {\n const n = summands.length;\n let sum = 0;\n let compensation = 0;\n\n for (let i = 0; i < n; ++i) {\n const summand = summands[i];\n const t = sum + summand;\n if (Math.abs(sum) >= Math.abs(summand)) {\n compensation += sum - t + summand;\n } else {\n compensation += summand - t + sum;\n }\n sum = t;\n }\n return sum + compensation;\n}\n","import { Matrix, norm } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { neumair_sum } from \"../numerical/index.js\";\n\n/**\n * Computes the QR Decomposition of the Matrix `A` using Gram-Schmidt process.\n *\n * @category Linear Algebra\n * @param {Matrix} A\n * @returns {{ R: Matrix; Q: Matrix }}\n * @see {@link https://en.wikipedia.org/wiki/QR_decomposition#Using_the_Gram%E2%80%93Schmidt_process}\n */\nexport function qr(A) {\n const [rows, cols] = A.shape;\n const Q = new Matrix(rows, cols, \"identity\");\n const R = new Matrix(cols, cols, 0);\n\n for (let j = 0; j < cols; ++j) {\n const v = A.col(j);\n for (let i = 0; i < j; ++i) {\n const q = Q.col(i);\n const q_dot_v = neumair_sum(q.map((q_, k) => q_ * v[k]));\n for (let k = 0; k < rows; ++k) {\n v[k] -= q_dot_v * q[k];\n }\n R.set_entry(i, j, q_dot_v);\n }\n const v_norm = norm(v, euclidean);\n for (let k = 0; k < rows; ++k) {\n Q.set_entry(k, j, v[k] / v_norm);\n }\n R.set_entry(j, j, v_norm);\n }\n return { R, Q };\n}\n","import { Matrix, norm } from \"../matrix/index.js\";\n\n/**\n * Computes the QR Decomposition of the Matrix `A` with householder transformations.\n *\n * @category Linear Algebra\n * @param {Matrix} A\n * @returns {{ R: Matrix; Q: Matrix }}\n * @see {@link https://en.wikipedia.org/wiki/QR_decomposition#Using_Householder_reflections}\n * @see {@link http://mlwiki.org/index.php/Householder_Transformation}\n */\nexport function qr_householder(A) {\n const [rows, cols] = A.shape;\n const Q = new Matrix(rows, rows, \"I\");\n const R = A.clone();\n\n for (let j = 0; j < cols; ++j) {\n const x = Matrix.from_vector(R.col(j).slice(j), \"row\");\n const x_norm = norm(x);\n const x0 = x.entry(0, 0);\n const rho = -Math.sign(x0);\n const u1 = x0 - rho * x_norm;\n const u = x.divide(u1).set_entry(0, 0, 1);\n const beta = (-rho * u1) / x_norm;\n\n const u_outer_u = u.outer(u);\n const R_block = R.get_block(j, 0);\n const new_R = R_block.sub(u_outer_u.dot(R_block).mult(beta));\n const Q_block = Q.get_block(0, j);\n const new_Q = Q_block.sub(Q_block.dot(u_outer_u).mult(beta));\n R.set_block(j, 0, new_R);\n Q.set_block(0, j, new_Q);\n }\n return { R, Q };\n}\n","/**\n * Returns maximum in Array `values`.\n *\n * @category Utils\n * @param {Iterable} values\n * @returns {number}\n */\nexport function max(values) {\n let max = -Infinity;\n for (const value of values) {\n if (value !== null && max < value) {\n max = value;\n }\n }\n return max;\n}\n","/**\n * Returns maximum in Array `values`.\n *\n * @category Utils\n * @param {Iterable} values\n * @returns {number}\n */\nexport function min(values) {\n let min = Infinity;\n for (const value of values) {\n if (value !== null && min > value) {\n min = value;\n }\n }\n return min;\n}\n","import { linspace } from \"../matrix/index.js\";\n\n/**\n * @category Utils\n * @class\n */\nexport class Randomizer {\n _N = 624;\n _M = 397;\n _MATRIX_A = 0x9908b0df;\n _UPPER_MASK = 0x80000000;\n _LOWER_MASK = 0x7fffffff;\n\n /** @type {number[]} */\n _mt;\n /** @type {number} */\n _mti;\n /** @type {number} */\n _seed;\n\n /**\n * Mersenne Twister random number generator.\n *\n * @param {number} [_seed=new Date().getTime()] - The seed for the random number generator. If `_seed == null` then\n * the actual time gets used as seed. Default is `new Date().getTime()`\n * @see https://github.com/bmurray7/mersenne-twister-examples/blob/master/javascript-mersenne-twister.js\n */\n constructor(_seed) {\n this._mt = new Array(this._N);\n this._mti = this._N + 1;\n this._seed = _seed ?? Date.now();\n this.seed = this._seed;\n }\n\n /** @type {number} seed */\n set seed(_seed) {\n this._seed = _seed;\n const mt = this._mt;\n\n mt[0] = _seed >>> 0;\n for (this._mti = 1; this._mti < this._N; this._mti += 1) {\n const mti = this._mti;\n const s = mt[mti - 1] ^ (mt[mti - 1] >>> 30);\n mt[mti] = ((((s & 0xffff0000) >>> 16) * 1812433253) << 16) + (s & 0x0000ffff) * 1812433253 + mti;\n mt[mti] >>>= 0;\n }\n }\n\n /**\n * Returns the seed of the random number generator.\n *\n * @returns {number} - The seed.\n */\n get seed() {\n return this._seed;\n }\n\n /**\n * Returns a float between 0 and 1.\n *\n * @returns {number} - A random number between [0, 1]\n */\n get random() {\n return this.random_int * (1.0 / 4294967296.0);\n }\n\n /**\n * Returns an integer between 0 and MAX_INTEGER.\n *\n * @returns {number} - A random integer.\n */\n get random_int() {\n let y,\n mag01 = [0x0, this._MATRIX_A];\n if (this._mti >= this._N) {\n let kk;\n\n /* if (this._mti == this._N + 1) {\n this.seed = 5489;\n } */\n\n const N_M = this._N - this._M;\n const M_N = this._M - this._N;\n\n for (kk = 0; kk < N_M; ++kk) {\n y = (this._mt[kk] & this._UPPER_MASK) | (this._mt[kk + 1] & this._LOWER_MASK);\n this._mt[kk] = this._mt[kk + this._M] ^ (y >>> 1) ^ mag01[y & 0x1];\n }\n for (; kk < this._N - 1; ++kk) {\n y = (this._mt[kk] & this._UPPER_MASK) | (this._mt[kk + 1] & this._LOWER_MASK);\n this._mt[kk] = this._mt[kk + M_N] ^ (y >>> 1) ^ mag01[y & 0x1];\n }\n\n y = (this._mt[this._N - 1] & this._UPPER_MASK) | (this._mt[0] & this._LOWER_MASK);\n this._mt[this._N - 1] = this._mt[this._M - 1] ^ (y >>> 1) ^ mag01[y & 0x1];\n\n this._mti = 0;\n }\n this._mti += 1;\n y = this._mt[this._mti];\n y ^= y >>> 11;\n y ^= (y << 7) & 0x9d2c5680;\n y ^= (y << 15) & 0xefc60000;\n y ^= y >>> 18;\n\n return y >>> 0;\n }\n\n gauss_random() {\n let x, y, r;\n if (this._val != null) {\n x = this._val;\n this._val = null;\n return x;\n } else\n do {\n x = 2 * this.random - 1;\n y = 2 * this.random - 1;\n r = x * x + y * y;\n } while (!r || r > 1);\n const c = Math.sqrt((-2 * Math.log(r)) / r);\n this._val = y * c; // cache this for next function call for efficiency\n return x * c;\n }\n\n /**\n * @template T Returns samples from an input Matrix or Array.\n * @param {T[]} A - The input Matrix or Array.\n * @param {number} n - The number of samples.\n * @returns {T[]} A random selection form `A` of `n` samples.\n */\n choice(A, n) {\n if (!Array.isArray(A)) throw new Error(\"A must be an Array!\");\n // if (A instanceof Matrix) {\n // let rows = A.shape[0];\n // if (n > rows) {\n // throw new Error(\"n bigger than A!\");\n // }\n // /** @type {number[]} */\n // let sample = new Array(n);\n // let index_list = linspace(0, rows - 1);\n // for (let i = 0, l = index_list.length; i < n; ++i, --l) {\n // let random_index = this.random_int % l;\n // sample[i] = index_list.splice(random_index, 1)[0];\n // }\n // return sample.map((d) => A.row(d));\n // } else if (Array.isArray(A) || A instanceof Float64Array) {\n const rows = A.length;\n if (n > rows) {\n throw new Error(\"n bigger than A!\");\n }\n const sample = new Array(n);\n const index_list = linspace(0, rows - 1);\n for (let i = 0, l = index_list.length; i < n; ++i, --l) {\n const random_index = this.random_int % l;\n sample[i] = index_list.splice(random_index, 1)[0];\n }\n return sample.map((d) => A[d]);\n //} else {\n //throw new Error(\"A must be of type Matrix or Float64Array or number[]!\");\n // }\n }\n\n /**\n * @template T Returns samples from an input Matrix or Array.\n * @param {T[]} A - The input Matrix or Array.\n * @param {number} n - The number of samples.\n * @param {number} seed - The seed for the random number generator.\n * @returns {T[]} - A random selection form `A` of `n` samples.\n */\n static choice(A, n, seed = 1212) {\n const R = new Randomizer(seed);\n return R.choice(A, n);\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { euclidean_squared } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { qr as qr_gramschmidt } from \"./index.js\";\n\n/** @import { EigenArgs } from \"./index.js\" */\n\n/**\n * Computes the `k` biggest Eigenvectors and Eigenvalues from Matrix `A` with the QR-Algorithm.\n *\n * @category Linear Algebra\n * @param {Matrix} A - The Matrix\n * @param {number} k - The number of eigenvectors and eigenvalues to compute.\n * @param {EigenArgs} parameters - Object containing parameterization of the simultanious\n * poweriteration method.\n * @returns {{ eigenvalues: Float64Array; eigenvectors: Float64Array[] }} The `k` biggest eigenvectors and eigenvalues\n * of Matrix `A`.\n */\nexport function simultaneous_poweriteration(\n A,\n k = 2,\n { seed = 1212, max_iterations = 100, qr = qr_gramschmidt, tol = 1e-8 } = {},\n) {\n const randomizer = seed instanceof Randomizer ? seed : new Randomizer(seed);\n if (!(A instanceof Matrix)) A = Matrix.from(A);\n const n = A.shape[0];\n let { Q, R } = qr(new Matrix(n, k, () => (randomizer.random - 0.5) * 2));\n while (max_iterations--) {\n const oldQ = Q;\n const Z = A.dot(Q);\n const QR = qr(Z);\n Q = QR.Q;\n R = QR.R;\n const error = euclidean_squared(Q.values, oldQ.values);\n if (error < tol) {\n break;\n }\n }\n\n const eigenvalues = R.diag();\n const eigenvectors = Q.transpose().to2dArray();\n return { eigenvalues, eigenvectors };\n}\n","import { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { neumair_sum } from \"../numerical/index.js\";\nimport { Randomizer } from \"../util/index.js\";\n\n/** @typedef {(i: number, j: number) => number} Accessor */\n\n/**\n * @class\n * @category Matrix\n */\nexport class Matrix {\n /**\n * Creates a new Matrix. Entries are stored in a Float64Array.\n *\n * @example let A = new Matrix(10, 10, () => Math.random()); //creates a 10 times 10 random matrix. let B = new\n * Matrix(3, 3, \"I\"); // creates a 3 times 3 identity matrix.\n *\n * @param {number} rows - The amount of rows of the matrix.\n * @param {number} cols - The amount of columns of the matrix.\n * @param {Accessor | string | number} value - Can be a function with row and col as parameters, a number, or\n * \"zeros\", \"identity\" or \"I\", or \"center\".\n *\n * - **function**: for each entry the function gets called with the parameters for the actual row and column.\n * - **string**: allowed are\n *\n * - \"zero\", creates a zero matrix.\n * - \"identity\" or \"I\", creates an identity matrix.\n * - \"center\", creates an center matrix.\n * - **number**: create a matrix filled with the given value.\n */\n constructor(rows, cols, value = 0) {\n /** @type {number} */ this._rows = rows;\n /** @type {number} */ this._cols = cols;\n /** @type {Float64Array} */ this._data;\n\n if (rows && cols) {\n if (!value) {\n this._data = new Float64Array(rows * cols);\n }\n if (typeof value === \"function\") {\n this._data = new Float64Array(rows * cols);\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col) {\n this._data[row * cols + col] = value(row, col);\n }\n }\n }\n if (typeof value === \"string\") {\n if (value === \"zeros\") {\n this._data = new Float64Array(rows * cols);\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col) {\n this._data[row * cols + col] = 0;\n }\n }\n }\n if (value === \"identity\" || value === \"I\") {\n this._data = new Float64Array(rows * cols);\n for (let row = 0; row < rows; ++row) {\n this._data[row * cols + row] = 1;\n }\n }\n if (value === \"center\" && rows === cols) {\n this._data = new Float64Array(rows * cols);\n value = (i, j) => (i === j ? 1 : 0) - 1 / rows;\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col) {\n this._data[row * cols + col] = value(row, col);\n }\n }\n }\n }\n if (typeof value === \"number\") {\n this._data = new Float64Array(rows * cols);\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col) {\n this._data[row * cols + col] = value;\n }\n }\n }\n if (Array.isArray(value)) {\n this._data = new Float64Array(rows * cols);\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col) {\n this._data[row * cols + col] = value[row][col];\n }\n }\n }\n }\n }\n\n /**\n * Creates a Matrix out of `A`.\n * @param {Matrix | Float64Array[] | number[][]} A - The matrix, array, or number, which should converted to a Matrix.\n * @returns {Matrix}\n * @example\n * let A = Matrix.from([ [1, 0], [0, 1], ]); //creates a two by two identity matrix.\n */\n static from(A) {\n if (A instanceof Matrix) {\n return A.clone();\n }\n if (Matrix.is2dArray(A)) {\n const m = A.length;\n const n = A[0].length;\n for (let row = 0; row < m; ++row) {\n if (A[row].length !== n) {\n throw new Error(\"various array lengths\");\n }\n }\n return new Matrix(m, n, (i, j) => A[i][j]);\n }\n throw new Error(\"error\");\n }\n\n /**\n * Creates a Matrix with the diagonal being the values of `v`.\n *\n * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]]\n *\n * @param {number[] | Float64Array} v\n * @returns {Matrix}\n */\n static from_diag(v) {\n const N = v.length;\n return new Matrix(N, N, (i, j) => (i === j ? v[i] : 0));\n }\n\n /**\n * Creates a Matrix with the diagonal being the values of `v`.\n *\n * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]]\n *\n * @param {number[] | Float64Array} v\n * @param {\"col\" | \"row\"} type\n * @returns {Matrix}\n */\n static from_vector(v, type) {\n const N = v.length;\n if (type === \"col\") {\n return new Matrix(N, 1, (i, _) => v[i]);\n } else {\n return new Matrix(1, N, (_, j) => v[j]);\n }\n }\n\n /**\n * Returns the `row`th row from the Matrix.\n *\n * @param {number} row\n * @returns {Float64Array}\n */\n row(row) {\n const data = this.values;\n const cols = this._cols;\n return data.subarray(row * cols, (row + 1) * cols);\n }\n\n /**\n * Returns an generator yielding each row of the Matrix.\n *\n * @yields {Float64Array}\n */\n *iterate_rows() {\n const cols = this._cols;\n const rows = this._rows;\n const data = this.values;\n for (let row = 0; row < rows; ++row) {\n yield data.subarray(row * cols, (row + 1) * cols);\n }\n }\n\n /**\n * Makes a `Matrix` object an iterable object.\n *\n * @yields {Float64Array}\n */\n *[Symbol.iterator]() {\n for (const row of this.iterate_rows()) {\n yield row;\n }\n }\n\n /**\n * Sets the entries of `row`th row from the Matrix to the entries from `values`.\n *\n * @param {number} row\n * @param {number[]} values\n * @returns {Matrix}\n */\n set_row(row, values) {\n const cols = this._cols;\n if (Matrix.isArray(values) && values.length === cols) {\n const offset = row * cols;\n for (let col = 0; col < cols; ++col) {\n this.values[offset + col] = values[col];\n }\n } else if (values instanceof Matrix && values.shape[1] === cols && values.shape[0] === 1) {\n const offset = row * cols;\n for (let col = 0; col < cols; ++col) {\n this.values[offset + col] = values._data[col];\n }\n } else {\n throw new Error(\"Values not valid! Needs to be either an Array, a Float64Array, or a fitting Matrix!\");\n }\n return this;\n }\n\n /**\n * Swaps the rows `row1` and `row2` of the Matrix.\n *\n * @param {number} row1\n * @param {number} row2\n * @returns {Matrix}\n */\n swap_rows(row1, row2) {\n const cols = this._cols;\n const data = this.values;\n for (let i = row1 * cols, j = row2 * cols, col = 0; col < cols; ++col, ++i, ++j) {\n const t = data[i];\n data[i] = data[j];\n data[j] = t;\n }\n return this;\n }\n\n /**\n * Returns the colth column from the Matrix.\n *\n * @param {number} col\n * @returns {Float64Array}\n */\n col(col) {\n const result_col = new Float64Array(this._rows);\n for (let row = 0; row < this._rows; ++row) {\n result_col[row] = this.values[row * this._cols + col];\n }\n return result_col;\n }\n\n /**\n * Returns the `col`th entry from the `row`th row of the Matrix.\n *\n * @param {number} row\n * @param {number} col\n * @returns {number}\n */\n entry(row, col) {\n return this.values[row * this._cols + col];\n }\n\n /**\n * Sets the {@link col}th entry from the {@link row}th row of the Matrix to the given\n * {@link value}.\n *\n * @param {number} row\n * @param {number} col\n * @param {number} value\n * @returns {Matrix}\n */\n set_entry(row, col, value) {\n this.values[row * this._cols + col] = value;\n return this;\n }\n\n /**\n * Adds a given {@link value} to the {@link col}th entry from the {@link row}th row of the\n * Matrix.\n *\n * @param {number} row\n * @param {number} col\n * @param {number} value\n * @returns {Matrix}\n */\n add_entry(row, col, value) {\n this.values[row * this._cols + col] += value;\n return this;\n }\n\n /**\n * Subtracts a given {@link value} from the {@link col}th entry from the {@link row}th row of the\n * Matrix.\n *\n * @param {number} row\n * @param {number} col\n * @param {number} value\n * @returns {Matrix}\n */\n sub_entry(row, col, value) {\n this.values[row * this._cols + col] -= value;\n return this;\n }\n\n /**\n * Returns a new transposed Matrix.\n *\n * @returns {Matrix}\n */\n transpose() {\n const B = new Matrix(this._cols, this._rows, (row, col) => this.entry(col, row));\n return B;\n }\n\n /**\n * Returns a new transposed Matrix. Short-form of `transpose`.\n *\n * @returns {Matrix}\n */\n get T() {\n return this.transpose();\n }\n\n /**\n * Returns the inverse of the Matrix.\n *\n * @returns {Matrix}\n */\n inverse() {\n const rows = this._rows;\n const cols = this._cols;\n const A = this.clone();\n const B = new Matrix(rows, cols, \"I\");\n\n // foreach column\n for (let col = 0; col < cols; ++col) {\n // Search for maximum in this column (pivot)\n let max_idx = col;\n let max_val = Math.abs(A.entry(col, col));\n for (let row = col + 1; row < rows; ++row) {\n const val = Math.abs(A.entry(row, col));\n if (max_val < val) {\n max_idx = row;\n max_val = val;\n }\n }\n if (max_val === 0) {\n throw new Error(\"Cannot compute inverse of Matrix, determinant is zero\");\n }\n // Swap maximum row with current row\n if (max_idx !== col) {\n A.swap_rows(col, max_idx);\n B.swap_rows(col, max_idx);\n }\n\n // eliminate non-zero values on the other rows at column c\n const A_col = A.row(col);\n const B_col = B.row(col);\n for (let row = 0; row < rows; ++row) {\n if (row !== col) {\n // eliminate value at column c and row r\n const A_row = A.row(row);\n const B_row = B.row(row);\n if (A_row[col] !== 0) {\n const f = A_row[col] / A_col[col];\n // sub (f * row c) from row r to eliminate the value at column c\n for (let s = col; s < cols; ++s) {\n A_row[s] -= f * A_col[s];\n }\n for (let s = 0; s < cols; ++s) {\n B_row[s] -= f * B_col[s];\n }\n }\n } else {\n // normalize value at Acc to 1 (diagonal):\n // divide each value of row r=c by the value at Acc\n const f = A_col[col];\n for (let s = col; s < cols; ++s) {\n A_col[s] /= f;\n }\n for (let s = 0; s < cols; ++s) {\n B_col[s] /= f;\n }\n }\n }\n }\n return B;\n }\n\n /**\n * Returns the dot product. If `B` is an Array or Float64Array then an Array gets returned. If `B` is a Matrix then\n * a Matrix gets returned.\n *\n * @param {Matrix | number[] | Float64Array} B The right side\n * @returns {Matrix}\n */\n dot(B) {\n if (B instanceof Matrix) {\n const [rows_A, cols_A] = this.shape;\n const [rows_B, cols_B] = B.shape;\n if (cols_A !== rows_B) {\n throw new Error(`A.dot(B): A is a ${this.shape.join(\" ⨯ \")}-Matrix, B is a ${B.shape.join(\" ⨯ \")}-Matrix:\n A has ${cols_A} cols and B ${rows_B} rows.\n Must be equal!`);\n }\n const C = new Matrix(rows_A, cols_B, 0);\n const A_val = this.values;\n const B_val = B.values;\n const C_val = C.values;\n\n for (let i = 0; i < rows_A; ++i) {\n const i_cols_A = i * cols_A;\n const i_cols_B = i * cols_B;\n for (let k = 0; k < cols_A; ++k) {\n const aik = A_val[i_cols_A + k];\n if (aik === 0) continue;\n const k_cols_B = k * cols_B;\n for (let j = 0; j < cols_B; ++j) {\n C_val[i_cols_B + j] += aik * B_val[k_cols_B + j];\n }\n }\n }\n return C;\n } else if (Matrix.isArray(B)) {\n // TODO: create Matrix directly\n const rows = this._rows;\n if (B.length !== rows) {\n throw new Error(`A.dot(B): A has ${rows} cols and B has ${B.length} rows. Must be equal!`);\n }\n const C = new Array(rows);\n for (let row = 0; row < rows; ++row) {\n C[row] = neumair_sum(this.row(row).map((e) => e * B[row]));\n }\n return Matrix.from(C);\n } else {\n throw new Error(`B must be Matrix or Array`);\n }\n }\n\n /**\n * Transposes the current matrix and returns the dot product with `B`. If `B` is an Array or Float64Array then an\n * Array gets returned. If `B` is a Matrix then a Matrix gets returned.\n *\n * @param {Matrix | number[] | Float64Array} B The right side\n * @returns {Matrix}\n */\n transDot(B) {\n if (B instanceof Matrix) {\n const [cols_A, rows_A] = this.shape; // transpose matrix\n const [rows_B, cols_B] = B.shape;\n if (cols_A !== rows_B) {\n throw new Error(`A.dot(B): A is a ${[rows_A, cols_A].join(\" ⨯ \")}-Matrix, B is a ${B.shape.join(\" ⨯ \")}-Matrix:\n A has ${cols_A} cols and B ${rows_B} rows, which must be equal!`);\n }\n // let B = new Matrix(this._cols, this._rows, (row, col) => this.entry(col, row));\n // this.values[row * this._cols + col];\n const C = new Matrix(rows_A, cols_B, 0);\n const A_val = this.values; // A is rows_B x rows_A (transposed)\n const B_val = B.values;\n const C_val = C.values;\n\n for (let k = 0; k < cols_A; ++k) {\n // cols_A is rows_B\n const k_rows_A = k * rows_A;\n const k_cols_B = k * cols_B;\n for (let i = 0; i < rows_A; ++i) {\n const aki = A_val[k_rows_A + i];\n if (aki === 0) continue;\n for (let j = 0; j < cols_B; ++j) {\n C_val[i * cols_B + j] += aki * B_val[k_cols_B + j];\n }\n }\n }\n return C;\n } else if (Matrix.isArray(B)) {\n // TODO: create Matrix directly\n const rows = this._cols;\n if (B.length !== rows) {\n throw new Error(`A.dot(B): A has ${rows} cols and B has ${B.length} rows. Must be equal!`);\n }\n const C = new Array(rows);\n for (let row = 0; row < rows; ++row) {\n C[row] = neumair_sum(this.col(row).map((e) => e * B[row]));\n }\n return Matrix.from(C);\n } else {\n throw new Error(`B must be Matrix or Array`);\n }\n }\n\n /**\n * Returns the dot product with the transposed version of `B`. If `B` is an Array or Float64Array then an Array gets\n * returned. If `B` is a Matrix then a Matrix gets returned.\n *\n * @param {Matrix | number[] | Float64Array} B The right side\n * @returns {Matrix}\n */\n dotTrans(B) {\n if (B instanceof Matrix) {\n const [rows_A, cols_A] = this.shape;\n const [cols_B, rows_B] = B.shape;\n if (cols_A !== rows_B) {\n throw new Error(`A.dot(B): A is a ${this.shape.join(\" ⨯ \")}-Matrix, B is a ${[rows_B, cols_B].join(\" ⨯ \")}-Matrix:\n A has ${cols_A} cols and B ${rows_B} rows, which must be equal!`);\n }\n const C = new Matrix(rows_A, cols_B, (row, col) => {\n const A_i = this.row(row);\n const B_i = B.row(col);\n let sum = 0;\n for (let i = 0; i < cols_A; ++i) {\n sum += A_i[i] * B_i[i];\n }\n return sum;\n });\n return C;\n } else if (Matrix.isArray(B)) {\n // TODO: create Matrix directly\n const rows = this._rows;\n if (B.length !== rows) {\n throw new Error(`A.dot(B): A has ${rows} cols and B has ${B.length} rows. Must be equal!`);\n }\n const C = new Array(rows);\n for (let row = 0; row < rows; ++row) {\n C[row] = neumair_sum(this.row(row).map((e) => e * B[row]));\n }\n return Matrix.from(C);\n } else {\n throw new Error(`B must be Matrix or Array`);\n }\n }\n\n /**\n * Computes the outer product from `this` and `B`.\n *\n * @param {Matrix} B\n * @returns {Matrix}\n */\n outer(B) {\n const l = this._data.length;\n const r = B._data.length;\n if (l !== r) throw new Error(\"Matrix A and B needs to be of the same length!\");\n const C = new Matrix(\n l,\n l,\n /** @type {Accessor} */ (i, j) => {\n if (i <= j) {\n return this._data[i] * B._data[j];\n } else {\n return this.entry(j, i);\n }\n },\n );\n\n return C;\n }\n\n /**\n * Appends matrix `B` to the matrix.\n *\n * @example let A = Matrix.from([ [1, 1], [1, 1], ]); // 2 by 2 matrix filled with ones. let B = Matrix.from([ [2,\n * 2], [2, 2], ]); // 2 by 2 matrix filled with twos.\n *\n * A.concat(B, \"horizontal\"); // 2 by 4 matrix. [[1, 1, 2, 2], [1, 1, 2, 2]]\n * A.concat(B, \"vertical\"); // 4 by 2 matrix. [[1, 1], [1, 1], [2, 2], [2, 2]]\n * A.concat(B, \"diag\"); // 4 by 4 matrix. [[1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 2, 2], [0, 0, 2, 2]]\n *\n * @param {Matrix} B - Matrix to append.\n * @param {\"horizontal\" | \"vertical\" | \"diag\"} [type=\"horizontal\"] - Type of concatenation. Default is\n * `\"horizontal\"`\n * @returns {Matrix}\n */\n concat(B, type = \"horizontal\") {\n const [rows_A, cols_A] = this.shape;\n const [rows_B, cols_B] = B.shape;\n if (type === \"horizontal\") {\n if (rows_A !== rows_B) {\n throw new Error(\n `A.concat(B, \"horizontal\"): A and B need same number of rows, A has ${rows_A} rows, B has ${rows_B} rows.`,\n );\n }\n const X = new Matrix(rows_A, cols_A + cols_B, \"zeros\");\n X.set_block(0, 0, this);\n X.set_block(0, cols_A, B);\n return X;\n } else if (type === \"vertical\") {\n if (cols_A !== cols_B) {\n throw new Error(\n `A.concat(B, \"vertical\"): A and B need same number of columns, A has ${cols_A} columns, B has ${cols_B} columns.`,\n );\n }\n const X = new Matrix(rows_A + rows_B, cols_A, \"zeros\");\n X.set_block(0, 0, this);\n X.set_block(rows_A, 0, B);\n return X;\n } else if (type === \"diag\") {\n const X = new Matrix(rows_A + rows_B, cols_A + cols_B, \"zeros\");\n X.set_block(0, 0, this);\n X.set_block(rows_A, cols_A, B);\n return X;\n } else {\n throw new Error(`type must be \"horizontal\" or \"vertical\", but type is ${type}!`);\n }\n }\n\n /**\n * Writes the entries of B in A at an offset position given by `offset_row` and `offset_col`.\n *\n * @param {number} offset_row\n * @param {number} offset_col\n * @param {Matrix} B\n * @returns {Matrix}\n */\n set_block(offset_row, offset_col, B) {\n const rows = Math.min(this._rows - offset_row, B.shape[0]);\n const cols = Math.min(this._cols - offset_col, B.shape[1]);\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col) {\n this.set_entry(row + offset_row, col + offset_col, B.entry(row, col));\n }\n }\n return this;\n }\n\n /**\n * Extracts the entries from the `start_row`th row to the `end_row`th row, the\n * `start_col`th column to the `end_col`th column of the matrix. If `end_row` or `end_col` is\n * empty, the respective value is set to `this.rows` or `this.cols`.\n *\n * @example let A = Matrix.from([ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]); // a 3 by 3 matrix.\n *\n * A.get_block(1, 1); // [[5, 6], [8, 9]]\n * A.get_block(0, 0, 1, 1); // [[1]]\n * A.get_block(1, 1, 2, 2); // [[5]]\n * A.get_block(0, 0, 2, 2); // [[1, 2], [4, 5]]\n *\n * @param {number} start_row\n * @param {number} start_col\n * @param {number | null} [end_row]\n * @param {number | null} [end_col]\n * @returns {Matrix} Returns a `end_row` - `start_row` times `end_col` - `start_col` matrix, with respective entries\n * from the matrix.\n */\n get_block(start_row, start_col, end_row, end_col) {\n const [rows, cols] = this.shape;\n end_row = end_row ?? rows;\n end_col = end_col ?? cols;\n if (end_row <= start_row || end_col <= start_col) {\n throw new Error(`\n end_row must be greater than start_row, and\n end_col must be greater than start_col, but\n end_row = ${end_row}, start_row = ${start_row}, end_col = ${end_col}, and start_col = ${start_col}!`);\n }\n const X = new Matrix(end_row - start_row, end_col - start_col, \"zeros\");\n for (let row = start_row, new_row = 0; row < end_row; ++row, ++new_row) {\n for (let col = start_col, new_col = 0; col < end_col; ++col, ++new_col) {\n X.set_entry(new_row, new_col, this.entry(row, col));\n }\n }\n return X;\n }\n\n /**\n * Returns a new array gathering entries defined by the indices given by argument.\n *\n * @param {number[]} row_indices - Array consists of indices of rows for gathering entries of this matrix\n * @param {number[]} col_indices - Array consists of indices of cols for gathering entries of this matrix\n * @returns {Matrix}\n */\n gather(row_indices, col_indices) {\n const N = row_indices.length;\n const D = col_indices.length;\n\n const R = new Matrix(N, D);\n for (let i = 0; i < N; ++i) {\n const row_index = row_indices[i];\n for (let j = 0; j < D; ++j) {\n const col_index = col_indices[j];\n R.set_entry(i, j, this.entry(row_index, col_index));\n }\n }\n\n return R;\n }\n\n /**\n * Applies a function to each entry of the matrix.\n *\n * @private\n * @param {(d: number, v: number) => number} f Function takes 2 parameters, the value of the actual entry and a\n * value given by the function `v`. The result of `f` gets writen to the Matrix.\n * @param {Accessor} v Function takes 2 parameters for `row` and `col`, and returns a value witch should be applied\n * to the `col`th entry of the `row`th row of the matrix.\n * @returns {Matrix}\n */\n _apply_array(f, v) {\n const data = this.values;\n const [rows, cols] = this.shape;\n for (let i = 0, row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col, ++i) {\n data[i] = f(data[i], v(row, col));\n }\n }\n return this;\n }\n\n /**\n * @param {number[] | Float64Array} values\n * @param {(d: number, v: number) => number} f\n * @returns {Matrix}\n */\n _apply_rowwise_array(values, f) {\n return this._apply_array(f, (_, j) => values[j]);\n }\n /**\n * @param {number[] | Float64Array} values\n * @param {(d: number, v: number) => number} f\n * @returns {Matrix}\n */\n _apply_colwise_array(values, f) {\n const data = this.values;\n const [rows, cols] = this.shape;\n for (let i = 0, row = 0; row < rows; ++row) {\n const val = values[row];\n for (let col = 0; col < cols; ++col, ++i) {\n data[i] = f(data[i], val);\n }\n }\n return this;\n }\n\n /**\n * @param {Matrix | number[] | Float64Array | number} value\n * @param {(d: number, v: number) => number} f\n * @returns {Matrix}\n */\n _apply(value, f) {\n const data = this.values;\n const [rows, cols] = this.shape;\n if (value instanceof Matrix) {\n const values = value.values;\n const [value_rows, value_cols] = value.shape;\n if (value_rows === 1) {\n if (cols !== value_cols) {\n throw new Error(`cols !== value_cols`);\n }\n for (let i = 0, row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col, ++i) {\n data[i] = f(data[i], values[col]);\n }\n }\n } else if (value_cols === 1) {\n if (rows !== value_rows) {\n throw new Error(`rows !== value_rows`);\n }\n for (let i = 0, row = 0; row < rows; ++row) {\n const v = values[row];\n for (let col = 0; col < cols; ++col, ++i) {\n data[i] = f(data[i], v);\n }\n }\n } else if (rows === value_rows && cols === value_cols) {\n for (let i = 0, n = rows * cols; i < n; ++i) {\n data[i] = f(data[i], values[i]);\n }\n } else {\n throw new Error(`error`);\n }\n } else if (Matrix.isArray(value)) {\n if (value.length === rows) {\n for (let i = 0, row = 0; row < rows; ++row) {\n const v = value[row];\n for (let col = 0; col < cols; ++col, ++i) {\n data[i] = f(data[i], v);\n }\n }\n } else if (value.length === cols) {\n for (let i = 0, row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col, ++i) {\n data[i] = f(data[i], value[col]);\n }\n }\n } else {\n throw new Error(`error`);\n }\n } else {\n // scalar value\n for (let i = 0, n = rows * cols; i < n; ++i) {\n data[i] = f(data[i], value);\n }\n }\n return this;\n }\n\n /**\n * Clones the Matrix.\n *\n * @returns {Matrix}\n */\n clone() {\n const B = new Matrix(this._rows, this._cols);\n //B._rows = this._rows;\n //B._cols = this._cols;\n if (this._data) {\n B._data = this._data.slice(0);\n }\n return B;\n }\n\n /**\n * Entrywise multiplication with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.mult(2); // [[2, 4], [6, 8]];\n * A.mult(B); // [[1, 4], [9, 16]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {boolean} [options.inline=false] - If true, applies multiplication to the element, otherwise it creates\n * first a copy and applies the multiplication on the copy. Default is `false`\n * @returns {Matrix}\n */\n mult(value, { inline = false } = {}) {\n const A = inline ? this : this.clone();\n return A._apply(value, (a, b) => a * b);\n }\n\n /**\n * Entrywise division with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.divide(2); // [[0.5, 1], [1.5, 2]];\n * A.divide(B); // [[1, 1], [1, 1]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {Boolean} [options.inline=false] - If true, applies division to the element, otherwise it creates first a\n * copy and applies the division on the copy. Default is `false`\n * @returns {Matrix}\n */\n divide(value, { inline = false } = {}) {\n const A = inline ? this : this.clone();\n return A._apply(value, (a, b) => a / b);\n }\n\n /**\n * Entrywise addition with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.add(2); // [[3, 4], [5, 6]];\n * A.add(B); // [[2, 4], [6, 8]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {boolean} [options.inline=false] - If true, applies addition to the element, otherwise it creates first a\n * copy and applies the addition on the copy. Default is `false`\n * @returns {Matrix}\n */\n add(value, { inline = false } = {}) {\n const A = inline ? this : this.clone();\n return A._apply(value, (a, b) => a + b);\n }\n\n /**\n * Entrywise subtraction with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.sub(2); // [[-1, 0], [1, 2]];\n * A.sub(B); // [[0, 0], [0, 0]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {boolean} [options.inline=false] - If true, applies subtraction to the element, otherwise it creates first\n * a copy and applies the subtraction on the copy. Default is `false`\n * @returns {Matrix}\n */\n sub(value, { inline = false } = {}) {\n const A = inline ? this : this.clone();\n return A._apply(value, (a, b) => a - b);\n }\n\n /**\n * Returns the number of rows and columns of the Matrix.\n *\n * @returns {number[]} An Array in the form [rows, columns].\n */\n get shape() {\n return [this._rows, this._cols];\n }\n\n /**\n * Returns the matrix in the given shape with the given function which returns values for the entries of the matrix.\n *\n * @param {[number, number, Accessor]} parameter - Takes an Array in the form [rows, cols, value], where rows and\n * cols are the number of rows and columns of the matrix, and value is a function which takes two parameters (row\n * and col) which has to return a value for the colth entry of the rowth row.\n * @returns {Matrix}\n */\n set shape([rows, cols, value = () => 0]) {\n this._rows = rows;\n this._cols = cols;\n this._data = new Float64Array(rows * cols);\n for (let i = 0, row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col, ++i) {\n this._data[i] = value(row, col);\n }\n }\n }\n\n /**\n * Returns the Matrix as a Array of Float64Arrays.\n *\n * @returns {Float64Array[]}\n */\n to2dArray() {\n const result = [];\n for (const row of this.iterate_rows()) {\n result.push(row);\n }\n return result;\n }\n\n /**\n * Returns the Matrix as a Array of Arrays.\n *\n * @returns {number[][]}\n */\n asArray() {\n const result = [];\n for (const row of this.iterate_rows()) {\n result.push(Array.from(row));\n }\n return result;\n }\n\n /**\n * Returns the diagonal of the Matrix.\n *\n * @returns {Float64Array}\n */\n diag() {\n const rows = this._rows;\n const cols = this._cols;\n const min_row_col = Math.min(rows, cols);\n const result = new Float64Array(min_row_col);\n for (let i = 0; i < min_row_col; ++i) {\n result[i] = this.entry(i, i);\n }\n return result;\n }\n\n /**\n * Returns the mean of all entries of the Matrix.\n *\n * @returns {number}\n */\n mean() {\n const sum = this.sum();\n const n = this._rows * this._cols;\n return sum / n;\n }\n\n /**\n * Returns the sum oof all entries of the Matrix.\n *\n * @returns {number}\n */\n sum() {\n const data = this.values;\n return neumair_sum(data);\n }\n\n /**\n * Returns the entries of the Matrix.\n *\n * @returns {Float64Array}\n */\n get values() {\n const data = this._data;\n return data;\n }\n\n /**\n * Returns the mean of each row of the matrix.\n *\n * @returns {Float64Array}\n */\n meanRows() {\n const data = this.values;\n const rows = this._rows;\n const cols = this._cols;\n const result = Float64Array.from({ length: rows });\n for (let i = 0, row = 0; row < rows; ++row) {\n let sum = 0;\n for (let col = 0; col < cols; ++col, ++i) {\n sum += data[i];\n }\n result[row] = sum / cols;\n }\n return result;\n }\n\n /**\n * Returns the mean of each column of the matrix.\n *\n * @returns {Float64Array}\n */\n meanCols() {\n const data = this.values;\n const rows = this._rows;\n const cols = this._cols;\n const result = Float64Array.from({ length: cols });\n for (let col = 0; col < cols; ++col) {\n let sum = 0;\n for (let i = col, row = 0; row < rows; ++row, i += cols) {\n sum += data[i];\n }\n result[col] = sum / rows;\n }\n return result;\n }\n\n /**\n * Solves the equation `Ax = b` using the conjugate gradient method. Returns the result `x`.\n *\n * @param {Matrix} A - Matrix\n * @param {Matrix} b - Matrix\n * @param {Randomizer | null} [randomizer]\n * @param {number} [tol=1e-3] Default is `1e-3`\n * @returns {Matrix}\n */\n static solve_CG(A, b, randomizer, tol = 1e-3) {\n if (!randomizer) {\n randomizer = new Randomizer();\n }\n const rows = A.shape[0];\n const cols = b.shape[1];\n let result = new Matrix(rows, 0);\n for (let i = 0; i < cols; ++i) {\n const b_i = Matrix.from_vector(b.col(i), \"col\");\n let x = new Matrix(rows, 1, () => randomizer.random);\n let r = b_i.sub(A.dot(x));\n let d = r.clone();\n let iter = 0;\n const max_iter = rows * 10; // Prevent infinite loops\n do {\n const z = A.dot(d);\n const alpha = r.transDot(r).entry(0, 0) / d.transDot(z).entry(0, 0);\n x = x.add(d.mult(alpha));\n const r_next = r.sub(z.mult(alpha));\n const beta = r_next.transDot(r_next).entry(0, 0) / r.transDot(r).entry(0, 0);\n d = r_next.add(d.mult(beta));\n r = r_next;\n iter++;\n } while (Math.abs(r.mean()) > tol && iter < max_iter);\n result = result.concat(x, \"horizontal\");\n }\n return result;\n }\n\n /**\n * Solves the equation `Ax = b`. Returns the result `x`.\n *\n * @param {Matrix | { L: Matrix; U: Matrix }} A - Matrix or LU Decomposition\n * @param {Matrix} b - Matrix\n * @returns {Matrix}\n */\n static solve(A, b) {\n const { L, U } = \"L\" in A && \"U\" in A ? A : Matrix.LU(A);\n const rows = L.shape[0];\n const x = b.clone();\n\n // forward\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < row; ++col) {\n x.sub_entry(0, row, L.entry(row, col) * x.entry(0, col));\n }\n x.set_entry(0, row, x.entry(0, row) / L.entry(row, row));\n }\n\n // backward\n for (let row = rows - 1; row >= 0; --row) {\n for (let col = rows - 1; col > row; --col) {\n x.sub_entry(0, row, U.entry(row, col) * x.entry(0, col));\n }\n x.set_entry(0, row, x.entry(0, row) / U.entry(row, row));\n }\n\n return x;\n }\n\n /**\n * `LU` decomposition of the Matrix `A`. Creates two matrices, so that the dot product `LU` equals `A`.\n *\n * @param {Matrix} A\n * @returns {{ L: Matrix; U: Matrix }} The left triangle matrix `L` and the upper triangle matrix `U`.\n */\n static LU(A) {\n const rows = A.shape[0];\n const L = new Matrix(rows, rows, \"zeros\");\n const U = new Matrix(rows, rows, \"identity\");\n\n for (let j = 0; j < rows; ++j) {\n for (let i = j; i < rows; ++i) {\n let sum = 0;\n for (let k = 0; k < j; ++k) {\n sum += L.entry(i, k) * U.entry(k, j);\n }\n L.set_entry(i, j, A.entry(i, j) - sum);\n }\n for (let i = j; i < rows; ++i) {\n if (L.entry(j, j) === 0) {\n throw new Error(\"L's diagonal not supposed to be 0!\");\n }\n let sum = 0;\n for (let k = 0; k < j; ++k) {\n sum += L.entry(j, k) * U.entry(k, i);\n }\n U.set_entry(j, i, (A.entry(j, i) - sum) / L.entry(j, j));\n }\n }\n\n return { L, U };\n }\n\n /**\n * Computes the determinante of `A`, by using the `LU` decomposition of `A`.\n *\n * @param {Matrix} A\n * @returns {number} The determinate of the Matrix `A`.\n */\n static det(A) {\n const [rows, cols] = A.shape;\n\n if (rows === 2 && cols === 2) {\n return A.entry(0, 0) * A.entry(1, 1) - A.entry(0, 1) * A.entry(1, 0);\n }\n if (rows === 3 && cols === 3) {\n const a = A.entry(0, 0);\n const b = A.entry(0, 1);\n const c = A.entry(0, 2);\n const d = A.entry(1, 0);\n const e = A.entry(1, 1);\n const f = A.entry(1, 2);\n const g = A.entry(2, 0);\n const h = A.entry(2, 1);\n const i = A.entry(2, 2);\n return a * (e * i - f * h) - b * (d * i - f * g) + c * (d * h - e * g);\n }\n\n const { L, U } = Matrix.LU(A);\n const L_diag = L.diag();\n const U_diag = U.diag();\n let det = L_diag[0] * U_diag[0];\n for (let row = 1; row < rows; ++row) {\n det *= L_diag[row] * U_diag[row];\n }\n return det;\n }\n\n /**\n * Computes the `k` components of the SVD decomposition of the matrix `M`.\n *\n * @param {Matrix} M\n * @param {number} [k=2] Default is `2`\n * @returns {{ U: Float64Array[]; Sigma: Float64Array; V: Float64Array[] }}\n */\n static SVD(M, k = 2) {\n const MtM = M.transDot(M);\n const MMt = M.dotTrans(M);\n const { eigenvectors: V, eigenvalues: Sigma } = simultaneous_poweriteration(MtM, k);\n const { eigenvectors: U } = simultaneous_poweriteration(MMt, k);\n return { U: U, Sigma: Sigma.map((sigma) => Math.sqrt(sigma)), V: V };\n\n //Algorithm 1a: Householder reduction to bidiagonal form:\n /* const [m, n] = A.shape;\n let U = new Matrix(m, n, (i, j) => i == j ? 1 : 0);\n console.log(U.to2dArray)\n let V = new Matrix(n, m, (i, j) => i == j ? 1 : 0);\n console.log(V.to2dArray)\n let B = Matrix.bidiagonal(A.clone(), U, V);\n console.log(U,V,B)\n return { U: U, \"Sigma\": B, V: V }; */\n }\n\n /**\n * @param {unknown} A\n * @returns {A is unknown[]|number[]|Float64Array|Float32Array}\n */\n static isArray(A) {\n return Array.isArray(A) || A instanceof Float64Array || A instanceof Float32Array;\n }\n\n /**\n * @param {any[]} A\n * @returns {A is number[][]|Float64Array[]}\n */\n static is2dArray(A) {\n if (!Array.isArray(A) || A.length === 0) {\n return false;\n }\n const n = A[0].length;\n for (let i = 0; i < A.length; ++i) {\n if (!Array.isArray(A[i]) && !(A[i] instanceof Float64Array)) {\n return false;\n }\n if (A[i].length !== n) {\n return false;\n }\n }\n return true;\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n\n/**\n * Computes the norm of a vector, by computing its distance to **0**.\n *\n * @category Matrix\n * @param {Matrix | number[] | Float64Array} v - Vector.\n * @param {Metric} [metric=euclidean] - Which metric should be used to compute the norm. Default is `euclidean`\n * @returns {number} - The norm of `v`.\n */\nexport function norm(v, metric = euclidean) {\n let vector = null;\n if (v instanceof Matrix) {\n const [rows, cols] = v.shape;\n if (rows === 1) vector = v.row(0);\n else if (cols === 1) vector = v.col(0);\n else throw new Error(\"Matrix must be 1d!\");\n } else {\n vector = v;\n }\n const n = vector.length;\n const zeros = new Float64Array(n);\n return metric(vector, zeros);\n}\n","import { euclidean } from \"../metrics/index.js\";\nimport { norm } from \"./index.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n\n/**\n * Normalizes Vector `v`.\n *\n * @category Matrix\n * @param {number[] | Float64Array} v - Vector\n * @param {Metric} metric\n * @returns {number[] | Float64Array} - The normalized vector with length 1.\n */\nexport function normalize(v, metric = euclidean) {\n const v_norm = norm(v, metric);\n return v.map((value) => value / v_norm);\n}\n","import { Matrix } from \"../matrix/index.js\";\n\n/** @import {InputType} from \"../index.js\" */\n\n/**\n * Base class for all clustering algorithms.\n * @template Para\n */\nexport class Clustering {\n /** @type {InputType} */\n _points;\n /** @type {Para} */\n _parameters;\n /** @type {Matrix} */\n _matrix;\n /** @type {number} */\n _N;\n /** @type {number} */\n _D;\n\n /**\n * Compute the respective Clustering with given parameters\n * @param {InputType} points\n * @param {Para} parameters\n */\n constructor(points, parameters) {\n this._points = points;\n this._parameters = parameters;\n\n this._matrix = points instanceof Matrix ? points : Matrix.from(points);\n const [N, D] = this._matrix.shape;\n this._N = N;\n this._D = D;\n }\n\n /**\n * @abstract\n * @param {...unknown} args\n * @returns {number[][]} An array with the indices of the clusters.\n */\n get_clusters(...args) {\n args;\n throw new Error(\"The function get_clusters must be implemented!\");\n }\n\n /**\n * @abstract\n * @param {...unknown} args\n * @returns {number[]} An array with the clusters id's for each point.\n */\n get_cluster_list(...args) {\n args;\n throw new Error(\"The function get_cluster_list must be implemented!\");\n }\n}\n","import { euclidean } from \"../metrics/index.js\";\nimport { Clustering } from \"./Clustering.js\";\n\n/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersCURE } from \"./index.js\" */\n\n/**\n * CURE (Clustering Using REpresentatives)\n *\n * An efficient clustering algorithm for large databases that is robust to outliers\n * and identifies clusters with non-spherical shapes and wide variances in size.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class CURE extends Clustering {\n /** @type {number} */\n _K;\n /** @type {number} */\n _num_representatives;\n /** @type {number} */\n _shrink_factor;\n /**\n * @private\n * @type {CURECluster[]}\n */\n _clusters = [];\n /** @type {number[]} */\n _cluster_ids = [];\n\n /**\n * @param {InputType} points\n * @param {Partial} parameters\n */\n constructor(points, parameters = {}) {\n super(\n points,\n /** @type {ParametersCURE} */ (\n Object.assign(\n { K: 2, num_representatives: 5, shrink_factor: 0.5, metric: euclidean, seed: 1212 },\n parameters,\n )\n ),\n );\n\n this._K = this._parameters.K ?? 2;\n this._num_representatives = this._parameters.num_representatives ?? 5;\n this._shrink_factor = this._parameters.shrink_factor ?? 0.5;\n\n // Initialize clusters\n this._initialize_clusters();\n // Run CURE algorithm\n this._cure();\n }\n\n /**\n * Initialize each point as its own cluster\n * @private\n */\n _initialize_clusters() {\n const N = this._N;\n //const D = this._D;\n this._clusters = [];\n\n for (let i = 0; i < N; ++i) {\n const point = this._matrix.row(i);\n const centroid = new Float64Array(point);\n // For single point, representative is the point itself\n const representatives = [new Float64Array(point)];\n\n this._clusters.push(new CURECluster([i], centroid, representatives));\n }\n }\n\n /**\n * Compute distance between two clusters using representative points\n * @private\n * @param {CURECluster} cluster1\n * @param {CURECluster} cluster2\n * @returns {number}\n */\n _cluster_distance(cluster1, cluster2) {\n const reps1 = cluster1.representatives;\n const reps2 = cluster2.representatives;\n const metric = this._parameters.metric;\n\n let min_dist = Infinity;\n for (const r1 of reps1) {\n for (const r2 of reps2) {\n const dist = metric(r1, r2);\n if (dist < min_dist) {\n min_dist = dist;\n }\n }\n }\n return min_dist;\n }\n\n /**\n * Find the closest pair of clusters\n * @private\n * @returns {[number, number, number]} [index1, index2, distance]\n */\n _find_closest_clusters() {\n let min_dist = Infinity;\n let min_i = 0;\n let min_j = 1;\n\n for (let i = 0; i < this._clusters.length; ++i) {\n for (let j = i + 1; j < this._clusters.length; ++j) {\n const dist = this._cluster_distance(this._clusters[i], this._clusters[j]);\n if (dist < min_dist) {\n min_dist = dist;\n min_i = i;\n min_j = j;\n }\n }\n }\n\n return [min_i, min_j, min_dist];\n }\n\n /**\n * Merge two clusters\n * @private\n * @param {CURECluster} cluster1\n * @param {CURECluster} cluster2\n * @returns {CURECluster}\n */\n _merge_clusters(cluster1, cluster2) {\n // Merge indices\n const merged_indices = [...cluster1.indices, ...cluster2.indices];\n\n // Calculate new centroid\n const size1 = cluster1.indices.length;\n const size2 = cluster2.indices.length;\n const total_size = size1 + size2;\n const D = this._D;\n const new_centroid = new Float64Array(D);\n\n for (let d = 0; d < D; ++d) {\n new_centroid[d] = (size1 * cluster1.centroid[d] + size2 * cluster2.centroid[d]) / total_size;\n }\n\n // Collect all points from both clusters\n /** @type {{index: number, point: Float64Array}[]} */\n const all_points = [];\n for (const idx of cluster1.indices) {\n all_points.push({ index: idx, point: this._matrix.row(idx) });\n }\n for (const idx of cluster2.indices) {\n all_points.push({ index: idx, point: this._matrix.row(idx) });\n }\n\n // Select representative points - pick points farthest from centroid\n const num_reps = Math.min(this._num_representatives, all_points.length);\n const metric = this._parameters.metric;\n\n // Calculate distances from centroid for all points\n const distances = all_points.map(({ point }) => metric(point, new_centroid));\n\n // Select num_reps points with maximum distance (farthest from centroid)\n const selected_indices = [];\n const used = new Set();\n\n for (let r = 0; r < num_reps; ++r) {\n let max_dist = -1;\n let max_idx = -1;\n\n for (let i = 0; i < distances.length; ++i) {\n if (!used.has(i) && distances[i] > max_dist) {\n max_dist = distances[i];\n max_idx = i;\n }\n }\n\n if (max_idx >= 0) {\n used.add(max_idx);\n selected_indices.push(max_idx);\n }\n }\n\n // Shrink representative points toward centroid\n const new_representatives = selected_indices.map((idx) => {\n const point = all_points[idx].point;\n const shrunk = new Float64Array(D);\n const alpha = this._shrink_factor;\n\n for (let d = 0; d < D; ++d) {\n shrunk[d] = point[d] + alpha * (new_centroid[d] - point[d]);\n }\n\n return shrunk;\n });\n\n return new CURECluster(merged_indices, new_centroid, new_representatives);\n }\n\n /**\n * Run CURE clustering algorithm\n * @private\n */\n _cure() {\n // Merge clusters until we have K clusters\n while (this._clusters.length > this._K) {\n const [i, j] = this._find_closest_clusters();\n\n // Merge clusters i and j\n const merged = this._merge_clusters(this._clusters[i], this._clusters[j]);\n\n // Remove the old clusters and add the merged one\n // Remove larger index first to maintain correct indices\n // min_i < min_j is always true from _find_closest_clusters\n this._clusters.splice(j, 1);\n this._clusters.splice(i, 1);\n\n this._clusters.push(merged);\n }\n\n // Build cluster list for get_cluster_list\n this._build_cluster_ids();\n }\n\n /**\n * Build the cluster list (point -> cluster assignment)\n * @private\n */\n _build_cluster_ids() {\n const N = this._N;\n this._cluster_ids = new Array(N).fill(-1);\n\n for (let c = 0; c < this._clusters.length; ++c) {\n for (const idx of this._clusters[c].indices) {\n this._cluster_ids[idx] = c;\n }\n }\n }\n\n /**\n * @returns {number[][]}\n */\n get_clusters() {\n return this._clusters.map((cluster) => cluster.indices);\n }\n\n /**\n * @returns {number[]}\n */\n get_cluster_list() {\n return this._cluster_ids;\n }\n}\n\n/**\n * @private\n * Represents a cluster in CURE algorithm\n */\nclass CURECluster {\n /**\n * @param {number[]} indices - Indices of points in the cluster\n * @param {Float64Array} centroid - Centroid of the cluster\n * @param {Float64Array[]} representatives - Representative points (shrunk toward centroid)\n */\n constructor(indices, centroid, representatives) {\n /** @type {number[]} */\n this.indices = indices;\n /** @type {Float64Array} */\n this.centroid = centroid;\n /** @type {Float64Array[]} */\n this.representatives = representatives;\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Clustering } from \"./Clustering.js\";\n\n/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersHierarchicalClustering } from \"./index.js\" */\n\n/**\n * Hierarchical Clustering\n *\n * A bottom-up approach (agglomerative) to clustering that builds a tree of clusters (dendrogram).\n * Supports different linkage criteria: single, complete, and average.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class HierarchicalClustering extends Clustering {\n /** @type {Cluster | null} */\n root = null;\n\n /**\n * @param {InputType} points - Data or distance matrix if metric is 'precomputed'\n * @param {Partial} parameters\n */\n constructor(points, parameters = {}) {\n super(\n points,\n /** @type {ParametersHierarchicalClustering} */ (\n Object.assign({ linkage: \"complete\", metric: euclidean }, parameters)\n ),\n );\n this._id = 0;\n if (this._parameters.metric === \"precomputed\" && this._matrix.shape[0] !== this._matrix.shape[1]) {\n throw new Error(\"If metric is 'precomputed', then matrix has to be square!\");\n }\n\n const metric = this._parameters.metric;\n const A = this._matrix;\n const N = this._N;\n this._d_min = new Float64Array(N);\n const d_min = this._d_min;\n let distance_matrix;\n if (metric !== \"precomputed\") {\n distance_matrix = new Matrix(N, N, Infinity);\n for (let i = 0; i < N; ++i) {\n distance_matrix.set_entry(i, i, 0);\n d_min[i] = i; // temporary\n const Ai = A.row(i);\n for (let j = i + 1; j < N; ++j) {\n const dist = metric(Ai, A.row(j));\n distance_matrix.set_entry(i, j, dist);\n distance_matrix.set_entry(j, i, dist);\n }\n }\n for (let i = 0; i < N; i++) {\n let min_j = 0;\n let min_d = Infinity;\n for (let j = 0; j < N; j++) {\n if (i === j) continue;\n const d = distance_matrix.entry(i, j);\n if (d < min_d) {\n min_d = d;\n min_j = j;\n }\n }\n d_min[i] = min_j;\n }\n } else {\n distance_matrix = this._matrix.clone();\n for (let i = 0; i < N; ++i) {\n distance_matrix.set_entry(i, i, 0);\n d_min[i] = i === 0 ? 1 : 0;\n for (let j = 0; j < N; ++j) {\n if (i === j) continue;\n if (distance_matrix.entry(i, d_min[i]) > distance_matrix.entry(i, j)) {\n d_min[i] = j;\n }\n }\n }\n }\n this._distance_matrix = distance_matrix;\n this._clusters = new Array(N);\n const clusters = this._clusters;\n this._c_size = new Uint16Array(N);\n const c_size = this._c_size;\n for (let i = 0; i < N; ++i) {\n clusters[i] = [];\n clusters[i][0] = new Cluster(this._id++, null, null, 0, A.row(i), i, 1, 0);\n c_size[i] = 1;\n }\n const D = this._distance_matrix;\n const linkage = this._parameters.linkage;\n const p_max = N - 1;\n for (let p = 0; p < p_max; ++p) {\n let c1 = -1;\n let min_dist = Infinity;\n for (let i = 0; i < N; ++i) {\n if (D.entry(i, i) === Infinity) continue;\n const dist = D.entry(i, d_min[i]);\n if (dist < min_dist) {\n min_dist = dist;\n c1 = i;\n }\n }\n if (c1 === -1) break;\n\n const c2 = d_min[c1];\n const c1_cluster = clusters[c1][0];\n const c2_cluster = clusters[c2][0];\n const c1_cluster_indices = c1_cluster.isLeaf ? [c1_cluster.index] : c1_cluster.index;\n const c2_cluster_indices = c2_cluster.isLeaf ? [c2_cluster.index] : c2_cluster.index;\n const indices = c1_cluster_indices.concat(c2_cluster_indices);\n const new_cluster = new Cluster(this._id++, c1_cluster, c2_cluster, D.entry(c1, c2), null, indices);\n c1_cluster.parent = new_cluster;\n c2_cluster.parent = new_cluster;\n clusters[c1].unshift(new_cluster);\n\n const size1 = c_size[c1];\n const size2 = c_size[c2];\n c_size[c1] += size2;\n\n for (let j = 0; j < N; ++j) {\n if (j === c1 || j === c2 || D.entry(j, j) === Infinity) continue;\n const D_c1_j = D.entry(c1, j);\n const D_c2_j = D.entry(c2, j);\n let value;\n switch (linkage) {\n case \"single\":\n value = Math.min(D_c1_j, D_c2_j);\n break;\n case \"complete\":\n value = Math.max(D_c1_j, D_c2_j);\n break;\n case \"average\":\n value = (size1 * D_c1_j + size2 * D_c2_j) / (size1 + size2);\n break;\n }\n D.set_entry(j, c1, value);\n D.set_entry(c1, j, value);\n }\n\n D.set_entry(c2, c2, Infinity);\n for (let i = 0; i < N; ++i) {\n D.set_entry(i, c2, Infinity);\n D.set_entry(c2, i, Infinity);\n }\n\n // Update d_min for all rows\n for (let i = 0; i < N; i++) {\n if (D.entry(i, i) === Infinity) continue;\n if (d_min[i] === c1 || d_min[i] === c2 || i === c1) {\n let min_j = 0;\n let min_d = Infinity;\n for (let j = 0; j < N; j++) {\n if (i === j || D.entry(j, j) === Infinity) continue;\n const d = D.entry(i, j);\n if (d < min_d) {\n min_d = d;\n min_j = j;\n }\n }\n d_min[i] = min_j;\n } else {\n if (D.entry(i, c1) < D.entry(i, d_min[i])) {\n d_min[i] = c1;\n }\n }\n }\n\n this.root = new_cluster;\n }\n }\n\n /**\n * @param {number} value - Value where to cut the tree.\n * @param {\"distance\" | \"depth\"} [type=\"distance\"] - Type of value. Default is `\"distance\"`\n * @returns {Cluster[][]} - Array of clusters with the indices of the rows in given points.\n */\n get_clusters_raw(value, type = \"distance\") {\n /** @type {Cluster[][]} */\n const clusters = [];\n /** @type {(d: {dist: number, depth: number}) => number} */\n let accessor;\n switch (type) {\n case \"distance\":\n accessor = (d) => d.dist;\n break;\n case \"depth\":\n accessor = (d) => d.depth;\n break;\n default:\n throw new Error(\"invalid type\");\n }\n this._traverse(/** @type {Cluster} */ (this.root), accessor, value, clusters);\n return clusters;\n }\n\n /**\n * @param {number} value - Value where to cut the tree.\n * @param {\"distance\" | \"depth\"} [type=\"distance\"] - Type of value. Default is `\"distance\"`\n * @returns {number[][]} - Array of clusters with the indices of the rows in given points.\n */\n get_clusters(value, type = \"distance\") {\n /** @type {Cluster[][]} */\n const clusters = [];\n /** @type {(d: {dist: number, depth: number}) => number} */\n let accessor;\n switch (type) {\n case \"distance\":\n accessor = (d) => d.dist;\n break;\n case \"depth\":\n accessor = (d) => d.depth;\n break;\n default:\n throw new Error(\"invalid type\");\n }\n if (this.root) this._traverse(this.root, accessor, value, clusters);\n return clusters.map((cluster) => cluster.map((d) => d.index));\n }\n\n /**\n * @param {number} value - Value where to cut the tree.\n * @param {\"distance\" | \"depth\"} [type=\"distance\"] - Type of value. Default is `\"distance\"`\n * @returns {number[]} - Array of clusters with the indices of the rows in given points.\n */\n get_cluster_list(value, type = \"distance\") {\n const clusters = this.get_clusters(value, type);\n /** @type {number[]} */\n const list = new Array(this._N).fill(0);\n for (let i = 0; i < clusters.length; ++i) {\n const cluster = clusters[i];\n for (let j = 0; j < cluster.length; ++j) {\n const index = cluster[j];\n list[index] = i;\n }\n }\n return list;\n }\n\n /**\n * @private\n * @param {Cluster} node\n * @param {(d: {dist: number, depth: number}) => number} f\n * @param {number} value\n * @param {Cluster[][]} result\n */\n _traverse(node, f, value, result) {\n if (f(node) <= value) {\n result.push(node.leaves());\n } else {\n if (node.left) this._traverse(node.left, f, value, result);\n if (node.right) this._traverse(node.right, f, value, result);\n }\n }\n}\n\n/** @private */\nclass Cluster {\n /**@type {number} */\n size;\n /**@type {number} */\n depth;\n /**@type {Cluster | null} */\n parent;\n\n /**\n *\n * @param {number} id\n * @param {Cluster?} left\n * @param {Cluster?} right\n * @param {number} dist\n * @param {Float64Array?} centroid\n * @param {number} index\n * @param {number} [size]\n * @param {number} [depth]\n */\n constructor(id, left, right, dist, centroid, index, size, depth) {\n this.id = id;\n this.left = left;\n this.right = right;\n this.dist = dist;\n this.index = index;\n if (size) {\n this.size = size;\n } else {\n if (!left || !right) throw new Error(\"If size is not given, left & right cannot be null!\");\n this.size = left.size + right.size;\n }\n\n if (depth !== undefined) {\n this.depth = depth;\n } else {\n if (!left || !right) throw new Error(\"If depth is not given, left & right cannot be null!\");\n this.depth = Math.max(left.depth, right.depth) + 1;\n }\n\n if (centroid !== undefined && centroid !== null) {\n this.centroid = centroid;\n } else {\n if (!left || !right) throw new Error(\"If centroid is not given, left & right cannot be null!\");\n\n this.centroid = this._calculate_centroid(left, right);\n }\n\n this.parent = null;\n }\n\n /**\n *\n * @param {Cluster} left\n * @param {Cluster} right\n * @returns {Float64Array}\n */\n _calculate_centroid(left, right) {\n const l_size = left.size;\n const r_size = right.size;\n const l_centroid = left.centroid;\n const r_centroid = right.centroid;\n const size = this.size;\n const n = left.centroid.length;\n const new_centroid = new Float64Array(n);\n for (let i = 0; i < n; ++i) {\n new_centroid[i] = (l_size * l_centroid[i] + r_size * r_centroid[i]) / size;\n }\n return new_centroid;\n }\n\n get isLeaf() {\n return this.depth === 0;\n }\n\n /**\n *\n * @returns {Cluster[]}\n */\n leaves() {\n if (this.isLeaf) return [this];\n const left = this.left;\n const right = this.right;\n return (left ? (left.isLeaf ? [left] : left.leaves()) : []).concat(\n right ? (right.isLeaf ? [right] : right.leaves()) : [],\n );\n }\n\n /**\n *\n * @returns {Cluster[]}\n */\n descendants() {\n if (this.isLeaf) return [this];\n const left_descendants = this.left ? this.left.descendants() : [];\n const right_descendants = this.right ? this.right.descendants() : [];\n return left_descendants.concat(right_descendants).concat([this]);\n }\n}\n","/**\n * @template T\n * @typedef {Object} DisjointSetPayload\n * @property {T} parent\n * @property {Set} children\n * @property {number} size\n */\n\n/**\n * @template T\n * @class\n * @category Data Structures\n * @see {@link https://en.wikipedia.org/wiki/Disjoint-set_data_structure}\n */\nexport class DisjointSet {\n /**\n * @param {T[]?} elements\n */\n constructor(elements = null) {\n /**\n * @private\n * @type {Map>}\n */\n this._list = new Map();\n if (elements) {\n for (const e of elements) {\n this.make_set(e);\n }\n }\n }\n\n /**\n * @private\n * @param {T} x\n * @returns {DisjointSet}\n */\n make_set(x) {\n const list = this._list;\n if (!list.has(x)) {\n list.set(x, { parent: x, children: new Set([x]), size: 1 });\n }\n return this;\n }\n\n /**\n * @param {T} x\n * @returns\n */\n find(x) {\n const list = this._list;\n const disjoint_set = list.get(x);\n if (disjoint_set) {\n if (disjoint_set.parent !== x) {\n disjoint_set.children.add(x);\n const new_parent = this.find(disjoint_set.parent);\n if (!new_parent) throw new Error(\"should not happen!\");\n disjoint_set.parent = new_parent;\n return disjoint_set.parent;\n } else {\n return x;\n }\n } else {\n return null;\n }\n }\n\n /**\n * @param {T} x\n * @param {T} y\n * @returns\n */\n union(x, y) {\n let node_x = this.find(x);\n let node_y = this.find(y);\n\n if (!node_x || !node_y) throw new Error(\"x or y not found!\");\n\n let disjoint_set_x = this._list.get(node_x);\n let disjoint_set_y = this._list.get(node_y);\n\n if (!disjoint_set_x || !disjoint_set_y) throw new Error(\"should not happen!\");\n\n if (node_x === node_y) return this;\n if (disjoint_set_x.size < disjoint_set_y.size) {\n [node_x, node_y] = [node_y, node_x];\n [disjoint_set_x, disjoint_set_y] = [disjoint_set_y, disjoint_set_x];\n }\n\n disjoint_set_y.parent = node_x;\n // keep track of children\n disjoint_set_y.children.forEach(disjoint_set_x.children.add, disjoint_set_x.children);\n disjoint_set_x.size += disjoint_set_y.size;\n\n return this;\n }\n\n /** @param {T} x */\n get_children(x) {\n const node = this._list.get(x);\n if (node) {\n return node.children;\n } else {\n return null;\n }\n }\n}\n","/** @import { Comparator } from \"./index.js\" */\n\n/**\n * @template T\n * @class\n * @category Data Structures\n */\nexport class Heap {\n /** @type {{ element: T; value: number }[]} */\n _container;\n\n /** @type {Comparator} */\n _comparator;\n\n /**\n * A heap is a datastructure holding its elements in a specific way, so that the top element would be the first\n * entry of an ordered list.\n *\n * @param {T[]?} elements - Contains the elements for the Heap. `elements` can be null.\n * @param {(d: T) => number} accessor - Function returns the value of the element.\n * @param {\"min\" | \"max\" | Comparator} [comparator=\"min\"] - Function returning true or false\n * defining the wished order of the Heap, or String for predefined function. (\"min\" for a Min-Heap, \"max\" for a\n * Max_heap). Default is `\"min\"`\n * @see {@link https://en.wikipedia.org/wiki/Binary_heap}\n */\n constructor(elements = null, accessor, comparator = \"min\") {\n /** @type {(d: T) => number} */\n this._accessor = accessor;\n this._container = [];\n if (comparator === \"min\") {\n this._comparator = (a, b) => a < b;\n } else if (comparator === \"max\") {\n this._comparator = (a, b) => a > b;\n } else {\n this._comparator = comparator;\n }\n if (elements) {\n this._container = [];\n for (const e of elements) {\n this._container.push({\n element: e,\n value: accessor(e),\n });\n }\n for (let i = Math.floor(elements.length / 2 - 1); i >= 0; --i) {\n this._heapify_down(i);\n }\n }\n }\n\n /**\n * Creates a Heap from an Array\n *\n * @template T\n * @param {T[]} elements - Contains the elements for the Heap.\n * @param {(d: T) => number} accessor - Function returns the value of the element.\n * @param {\"min\" | \"max\" | Comparator} [comparator=\"min\"] - Function returning true or false\n * defining the wished order of the Heap, or String for predefined function. (\"min\" for a Min-Heap, \"max\" for a\n * Max_heap). Default is `\"min\"`\n * @returns {Heap}\n */\n static heapify(elements, accessor, comparator = \"min\") {\n const heap = new Heap(null, accessor, comparator);\n const container = heap._container;\n for (const e of elements) {\n container.push({\n element: e,\n value: accessor(e),\n });\n }\n for (let i = Math.floor(elements.length / 2 - 1); i >= 0; --i) {\n heap._heapify_down(i);\n }\n return heap;\n }\n\n /**\n * Swaps elements of container array.\n *\n * @private\n * @param {number} index_a\n * @param {number} index_b\n */\n _swap(index_a, index_b) {\n const container = this._container;\n [container[index_b], container[index_a]] = [container[index_a], container[index_b]];\n return;\n }\n\n /** @private */\n _heapify_up() {\n const container = this._container;\n let index = container.length - 1;\n while (index > 0) {\n const parentIndex = Math.floor((index - 1) / 2);\n if (!this._comparator(container[index].value, container[parentIndex].value)) {\n break;\n } else {\n this._swap(parentIndex, index);\n index = parentIndex;\n }\n }\n }\n\n /**\n * Pushes the element to the heap.\n *\n * @param {T} element\n * @returns {Heap}\n */\n push(element) {\n const value = this._accessor(element);\n //const node = new Node(element, value);\n const node = { element: element, value: value };\n this._container.push(node);\n this._heapify_up();\n return this;\n }\n\n /**\n * @private\n * @param {Number} [start_index=0] Default is `0`\n */\n _heapify_down(start_index = 0) {\n const container = this._container;\n const comparator = this._comparator;\n const length = container.length;\n const left = 2 * start_index + 1;\n const right = 2 * start_index + 2;\n let index = start_index;\n if (index >= length) throw \"index higher than length\";\n if (left < length && comparator(container[left].value, container[index].value)) {\n index = left;\n }\n if (right < length && comparator(container[right].value, container[index].value)) {\n index = right;\n }\n if (index !== start_index) {\n this._swap(start_index, index);\n this._heapify_down(index);\n }\n }\n\n /**\n * Removes and returns the top entry of the heap.\n *\n * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by\n * `accessor`}).\n */\n pop() {\n const container = this._container;\n if (container.length === 0) {\n return null;\n } else if (container.length === 1) {\n const item = container.pop();\n if (!item) throw new Error(\"Cannot happen!\");\n return item;\n }\n this._swap(0, container.length - 1);\n const item = container.pop();\n this._heapify_down();\n return item ?? null;\n }\n\n /**\n * Returns the top entry of the heap without removing it.\n *\n * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by\n * `accessor`).\n */\n get first() {\n return this._container.length > 0 ? this._container[0] : null;\n }\n\n /**\n * Yields the raw data\n *\n * @yields {T} Object consists of the element and its value (computed by `accessor`}).\n */\n *iterate() {\n for (let i = 0, n = this._container.length; i < n; ++i) {\n yield this._container[i].element;\n }\n }\n\n /**\n * Returns the heap as ordered array.\n *\n * @returns {T[]} Array consisting the elements ordered by `comparator`.\n */\n toArray() {\n return this._container.sort((a, b) => (this._comparator(a.value, b.value) ? -1 : 1)).map((d) => d.element);\n }\n\n /**\n * Returns elements of container array.\n *\n * @returns {T[]} Array consisting the elements.\n */\n data() {\n return this._container.map((d) => d.element);\n }\n\n /**\n * Returns the container array.\n *\n * @returns {{ element: T; value: number }[]} The container array.\n */\n raw_data() {\n return this._container;\n }\n\n /**\n * The size of the heap.\n *\n * @returns {number}\n */\n get length() {\n return this._container.length;\n }\n\n /**\n * Returns false if the the heap has entries, true if the heap has no entries.\n *\n * @returns {boolean}\n */\n get empty() {\n return this.length === 0;\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { linspace, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { Clustering } from \"./Clustering.js\";\n\n/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersKMeans } from \"./index.js\" */\n/**\n * K-Means Clustering\n *\n * A popular clustering algorithm that partitions data into K clusters where each point\n * belongs to the cluster with the nearest mean (centroid).\n *\n * @class\n * @extends Clustering\n * @category Clustering\n * @see {@link KMedoids} for a more robust alternative\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const points = [[1, 1], [1.5, 1.5], [5, 5], [5.5, 5.5]];\n * const kmeans = new druid.KMeans(points, { K: 2 });\n *\n * const clusters = kmeans.get_cluster_list(); // [0, 0, 1, 1]\n * const centroids = kmeans.centroids; // center points\n */\nexport class KMeans extends Clustering {\n /**\n * @param {InputType} points\n * @param {Partial} parameters\n */\n constructor(points, parameters = {}) {\n super(\n points,\n /** @type {ParametersKMeans} */ (Object.assign({ K: 4, metric: euclidean, seed: 1212 }, parameters)),\n );\n\n const K = this._parameters.K;\n const seed = parameters.seed;\n\n // Convert points to Matrix if needed\n if (points instanceof Matrix) {\n this._matrix = points;\n } else {\n this._matrix = Matrix.from(points);\n }\n\n const [N, D] = this._matrix.shape;\n this._N = N;\n this._D = D;\n\n this._K = K > N ? N : K;\n this._randomizer = new Randomizer(seed);\n\n /** @type {number[]} */\n this._clusters = new Array(N).fill(0);\n\n this._cluster_centroids = parameters.initial_centroids\n ? parameters.initial_centroids.map((c) => new Float64Array(c))\n : this._get_random_centroids(this._K);\n let cluster_centroids = this._cluster_centroids;\n let iterations = 0;\n const max_iterations = 300;\n let clusters_changed = true;\n\n while (clusters_changed && iterations < max_iterations) {\n const iteration_result = this._iteration(cluster_centroids);\n cluster_centroids = iteration_result.cluster_centroids;\n clusters_changed = iteration_result.clusters_changed;\n iterations++;\n }\n\n this._cluster_centroids = cluster_centroids;\n }\n\n /** @returns {number} The number of clusters */\n get k() {\n return this._K;\n }\n\n /** @returns {Float64Array[]} The cluster centroids */\n get centroids() {\n return this._cluster_centroids;\n }\n\n /** @returns {number[]} The cluster list */\n get_cluster_list() {\n return this._clusters;\n }\n\n /** @returns {number[][]} An Array of clusters with the indices of the points. */\n get_clusters() {\n const K = this._K;\n const clusters = this._clusters;\n /** @type {number[][]} */\n const result = new Array(K).fill(0).map(() => []);\n clusters.forEach((c, i) => {\n if (c >= 0 && c < K) {\n result[c].push(i);\n }\n });\n return result;\n }\n\n /**\n * @private\n * @param {number[]} point_indices\n * @param {number[]} candidates\n * @returns {number}\n */\n _furthest_point(point_indices, candidates) {\n const A = this._matrix;\n const metric = this._parameters.metric;\n\n if (point_indices.length === 0 || candidates.length === 0) {\n return candidates[0] ?? 0;\n }\n\n const H = Heap.heapify(\n candidates,\n (d) => {\n const Ad = A.row(d);\n let sum = 0;\n for (let j = 0; j < point_indices.length; ++j) {\n sum += metric(Ad, A.row(point_indices[j]));\n }\n return sum;\n },\n \"max\",\n );\n\n const furthest = H.pop();\n if (!furthest) throw new Error(\"Should not happen!\");\n\n return furthest.element;\n }\n\n /**\n * @private\n * @param {number} K\n * @returns {Float64Array[]}\n */\n _get_random_centroids(K) {\n const N = this._N;\n const randomizer = this._randomizer;\n const A = this._matrix;\n /** @type {Float64Array[]} */\n const cluster_centroids = new Array(K);\n const indices = linspace(0, N - 1);\n\n // First centroid: random selection\n const random_point = randomizer.random_int % N;\n cluster_centroids[0] = A.row(random_point);\n const init_points = [random_point];\n\n const sample_size = Math.max(1, Math.floor((N - K) / K));\n\n for (let i = 1; i < K; ++i) {\n const remaining = indices.filter((d) => !init_points.includes(d));\n if (remaining.length === 0) break;\n\n const sample = randomizer.choice(remaining, Math.min(sample_size, remaining.length));\n const furthest_point = this._furthest_point(init_points, sample);\n\n init_points.push(furthest_point);\n cluster_centroids[i] = A.row(furthest_point);\n }\n\n return cluster_centroids;\n }\n\n /**\n * @private\n * @param {Float64Array[]} cluster_centroids\n * @returns {{ clusters_changed: boolean; cluster_centroids: Float64Array[] }}\n */\n _iteration(cluster_centroids) {\n const K = cluster_centroids.length;\n const N = this._N;\n const metric = this._parameters.metric;\n const A = this._matrix;\n const clusters = this._clusters;\n let clusters_changed = false;\n\n // Find nearest cluster centroid for each point\n for (let i = 0; i < N; ++i) {\n const Ai = A.row(i);\n let min_dist = Infinity;\n let min_cluster = 0;\n\n for (let j = 0; j < K; ++j) {\n const d = metric(cluster_centroids[j], Ai);\n if (d < min_dist) {\n min_dist = d;\n min_cluster = j;\n }\n }\n\n if (clusters[i] !== min_cluster) {\n clusters_changed = true;\n clusters[i] = min_cluster;\n }\n }\n\n // Update cluster centroids\n const new_centroids = this._compute_centroid(K);\n\n return {\n clusters_changed: clusters_changed,\n cluster_centroids: new_centroids,\n };\n }\n\n /**\n * @private\n * @param {number} K\n * @returns {Float64Array[]}\n */\n _compute_centroid(K) {\n const N = this._N;\n const D = this._D;\n const A = this._matrix;\n const clusters = this._clusters;\n\n // Initialize new centroids and counters\n /** @type {Float64Array[]} */\n const new_centroids = new Array(K);\n const cluster_counter = new Array(K).fill(0);\n\n for (let i = 0; i < K; ++i) {\n new_centroids[i] = new Float64Array(D);\n }\n\n // Sum up all points in each cluster\n for (let i = 0; i < N; ++i) {\n const Ai = A.row(i);\n const ci = clusters[i];\n if (ci >= 0 && ci < K) {\n cluster_counter[ci]++;\n const centroid = new_centroids[ci];\n for (let j = 0; j < D; ++j) {\n centroid[j] += Ai[j];\n }\n }\n }\n\n // Divide by count to get mean\n for (let i = 0; i < K; ++i) {\n const n = cluster_counter[i];\n if (n > 0) {\n const centroid = new_centroids[i];\n for (let j = 0; j < D; ++j) {\n centroid[j] /= n;\n }\n }\n }\n\n return new_centroids;\n }\n}\n","import { linspace, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { Clustering } from \"./Clustering.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import { ParametersKMedoids } from \"./index.js\" */\n\n/**\n * K-Medoids (PAM - Partitioning Around Medoids)\n *\n * A robust clustering algorithm similar to K-Means, but uses actual data points (medoids)\n * as cluster centers and can work with any distance metric.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n * @see {@link KMeans} for a faster but less robust alternative\n */\nexport class KMedoids extends Clustering {\n /**\n * @param {InputType} points - Data matrix\n * @param {Partial} parameters\n * @see {@link https://link.springer.com/chapter/10.1007/978-3-030-32047-8_16} Faster k-Medoids Clustering: Improving the PAM, CLARA, and CLARANS Algorithms\n */\n constructor(points, parameters = {}) {\n super(points, Object.assign({ K: 4, max_iter: null, metric: euclidean, seed: 1212 }, parameters));\n this._A = this._matrix.to2dArray();\n let K = this._parameters.K;\n const N = this._N;\n this._max_iter = this._parameters.max_iter ?? 10 * Math.log10(N);\n this._distance_matrix = new Matrix(N, N, \"zeros\");\n\n if (K > N) {\n this._parameters.K = K = N;\n }\n this._randomizer = new Randomizer(this._parameters.seed);\n this._clusters = new Array(N).fill(-1);\n this._cluster_medoids = this._get_random_medoids(K);\n this._is_initialized = false;\n }\n\n /** @returns {number[]} The cluster list */\n get_cluster_list() {\n if (!this._is_initialized) {\n this.get_clusters();\n }\n return this._clusters;\n }\n\n /** @returns {number[][]} - Array of clusters with the indices of the rows in given points. */\n get_clusters() {\n const K = this._parameters.K;\n const A = this._A;\n const N = this._N;\n if (!this._is_initialized) {\n this.init(K, this._cluster_medoids);\n }\n /** @type {number[][]} */\n const result = new Array(K).fill(0).map(() => []);\n for (let j = 0; j < N; j++) {\n const nearest = this._nearest_medoid(A[j], j);\n const cluster_idx = nearest.index_nearest;\n result[cluster_idx].push(j);\n this._clusters[j] = cluster_idx;\n }\n return result;\n }\n\n /** @returns {number} */\n get k() {\n return this._parameters.K;\n }\n\n /** @returns {number[]} */\n get medoids() {\n return this.get_medoids();\n }\n\n /** @returns {number[]} */\n get_medoids() {\n const K = this._parameters.K;\n if (!this._is_initialized) {\n this.init(K, this._cluster_medoids);\n }\n return this._cluster_medoids;\n }\n\n async *generator() {\n const max_iter = this._max_iter;\n if (!this._is_initialized) {\n this.get_clusters();\n }\n yield this.get_clusters();\n let i = 0;\n while (i < max_iter) {\n const finish = this._iteration();\n this._update_clusters();\n yield this.get_clusters();\n if (finish) break;\n i++;\n }\n }\n\n /** Algorithm 1. FastPAM1: Improved SWAP algorithm */\n /* _iteration_1() {\n const A = this._A;\n const N = this._N;\n const K = this._K;\n const medoids = this._cluster_medoids;\n let DeltaTD = 0;\n let m0 = null;\n let x0 = null;\n A.forEach((x_j, j) => {\n if (medoids.findIndex(m => m === j) < 0) {\n const nearest_medoid = this._nearest_medoid(x_j, j);\n const d_j = nearest_medoid.distance_nearest; // distance to current medoid\n const deltaTD = new Array(K).fill(-d_j); // change if making j a medoid\n A.forEach((x_o, o) => {\n // disance to new medoid\n const d_oj = this._get_distance(o, j, x_o, x_j);\n const {\n \"index_nearest\": n,\n \"distance_nearest\": d_n,\n \"distance_second\": d_s,\n } = this._nearest_medoid(x_o, o);\n this._clusters[o] = n; // cached values\n deltaTD[n] += Math.min(d_oj, d_s) - d_n; // loss change\n if (d_oj < d_n) { // reassignment check\n deltaTD.forEach((d_i, i) => {\n if (n !== i) {\n deltaTD[i] = d_i + d_oj - d_n; // update loss change\n }\n });\n }\n });\n // choose best medoid i;\n const i = deltaTD\n .map((d, i) => [d, i])\n .sort((d1, d2) => d1[0] - d2[0])[0][1];\n const deltaTD_i = deltaTD[i];\n // store\n if (deltaTD_i < DeltaTD) {\n DeltaTD = deltaTD_i;\n m0 = i;\n x0 = j;\n }\n }\n });\n\n if (DeltaTD >= 0) {\n return true // break loop if DeltaTD >= 0\n }\n // swap roles of medoid m and non-medoid x;\n medoids[m0] = x0;\n this._cluster_medoids = medoids;\n return false\n } */\n\n /**\n * FastPAM1: One best swap per iteration\n * @private\n * @returns {boolean}\n */\n _iteration() {\n const A = this._A;\n const K = this._parameters.K;\n const medoids = this._cluster_medoids;\n const N = this._N;\n\n // Precompute nearest and second nearest medoid for all points\n const cache = new Array(N);\n for (let i = 0; i < N; i++) {\n cache[i] = this._nearest_medoid(A[i], i);\n }\n\n let best_delta = 0;\n let best_swap = null; // { m_idx: index in medoids, x_idx: index in A }\n\n // For each non-medoid point j, evaluate swapping it with each medoid i\n const medoid_set = new Set(medoids);\n for (let j = 0; j < N; j++) {\n if (medoid_set.has(j)) continue;\n\n const x_j = A[j];\n const d_j = cache[j].distance_nearest;\n\n // deltaTD[i] will store the change in total distance if we swap medoid[i] with j\n const deltaTD = new Array(K).fill(-d_j);\n\n for (let o = 0; o < N; o++) {\n if (o === j) continue;\n const dist_o_j = this._get_distance(o, j, A[o], x_j);\n const { index_nearest: n, distance_nearest: d_n, distance_second: d_s } = cache[o];\n\n // If o is assigned to the current medoid being swapped out (n)\n deltaTD[n] += Math.min(dist_o_j, d_s) - d_n;\n\n // For all other medoids i != n, if j is closer to o than its current medoid\n if (dist_o_j < d_n) {\n for (let i = 0; i < K; i++) {\n if (i !== n) {\n deltaTD[i] += dist_o_j - d_n;\n }\n }\n }\n }\n\n // Find best medoid to swap with j\n for (let i = 0; i < K; i++) {\n if (deltaTD[i] < best_delta) {\n best_delta = deltaTD[i];\n best_swap = { m_idx: i, x_idx: j };\n }\n }\n }\n\n if (best_swap && best_delta < 0) {\n medoids[best_swap.m_idx] = best_swap.x_idx;\n this._cluster_medoids = medoids;\n return false; // not finished\n }\n\n return true; // finished\n }\n\n /**\n * @private\n * Get distance between two points\n * @param {number} i\n * @param {number} j\n * @param {Float64Array?} x_i\n * @param {Float64Array?} x_j\n * @returns {number}\n */\n _get_distance(i, j, x_i = null, x_j = null) {\n if (i === j) return 0;\n const D = this._distance_matrix;\n const A = this._A;\n const metric = this._parameters.metric;\n let d_ij = D.entry(i, j);\n if (d_ij === 0) {\n d_ij = metric(x_i || A[i], x_j || A[j]);\n D.set_entry(i, j, d_ij);\n D.set_entry(j, i, d_ij);\n }\n return d_ij;\n }\n\n /**\n * @private\n * @param {Float64Array} x_j\n * @param {number} j\n * @returns\n */\n _nearest_medoid(x_j, j) {\n const medoids = this._cluster_medoids;\n const A = this._A;\n if (medoids.length === 0) {\n throw new Error(\"No medoids available. Initialization failed.\");\n }\n\n let d_n = Infinity;\n let n = -1;\n let d_s = Infinity;\n let s = -1;\n\n for (let i = 0; i < medoids.length; i++) {\n const m = medoids[i];\n const d = this._get_distance(j, m, x_j, A[m]);\n if (d < d_n) {\n d_s = d_n;\n s = n;\n d_n = d;\n n = i;\n } else if (d < d_s) {\n d_s = d;\n s = i;\n }\n }\n\n if (s === -1) s = n;\n\n return {\n distance_nearest: d_n,\n index_nearest: n,\n distance_second: d_s,\n index_second: s,\n };\n }\n\n /**\n * @private\n */\n _update_clusters() {\n const N = this._N;\n const A = this._A;\n for (let j = 0; j < N; j++) {\n const nearest = this._nearest_medoid(A[j], j);\n this._clusters[j] = nearest.index_nearest;\n }\n }\n\n /**\n * Computes `K` clusters out of the `matrix`.\n * @param {number} K - Number of clusters.\n * @param {number[]} cluster_medoids\n */\n init(K, cluster_medoids) {\n if (!K) K = this._parameters.K;\n if (!cluster_medoids) cluster_medoids = this._get_random_medoids(K);\n this._cluster_medoids = cluster_medoids;\n const max_iter = this._max_iter;\n let finish = false;\n let i = 0;\n do {\n finish = this._iteration();\n } while (!finish && ++i < max_iter);\n this._update_clusters();\n this._is_initialized = true;\n return this;\n }\n\n /**\n * Algorithm 3. FastPAM LAB: Linear Approximate BUILD initialization.\n * @private\n * @param {number} K - Number of clusters\n * @returns {number[]}\n */\n _get_random_medoids(K) {\n const N = this._N;\n const A = this._A;\n const indices = linspace(0, N - 1);\n const randomizer = this._randomizer;\n const n = Math.min(N, 10 + Math.ceil(Math.sqrt(N)));\n\n // Handle case where K >= N\n if (K >= N) {\n return indices.slice(0, N);\n }\n\n /** @type {number[]} */\n const medoids = [];\n\n // first medoid: select from a random sample of size n\n let best_j = -1;\n let min_td = Infinity;\n let S = randomizer.choice(indices, n);\n for (let j = 0; j < S.length; ++j) {\n let td = 0;\n const S_j = S[j];\n const x_j = A[S_j];\n for (let o = 0; o < S.length; ++o) {\n if (o === j) continue;\n td += this._get_distance(S_j, S[o], x_j, A[S[o]]);\n }\n if (td < min_td) {\n min_td = td;\n best_j = S_j;\n }\n }\n medoids.push(best_j);\n\n // other medoids: greedy additive selection (Algorithm LAB)\n for (let i = 1; i < K; ++i) {\n let best_idx = -1;\n let best_delta = Infinity;\n\n const remainingIndices = indices.filter((idx) => !medoids.includes(idx));\n if (remainingIndices.length === 0) break;\n\n S = randomizer.choice(remainingIndices, Math.min(n, remainingIndices.length));\n for (let j = 0; j < S.length; ++j) {\n let deltaTD = 0;\n const S_j = S[j];\n const x_j = A[S_j];\n\n // Estimate TD reduction on the sample S\n for (let o = 0; o < S.length; ++o) {\n if (o === j) continue;\n const S_o = S[o];\n const x_o = A[S_o];\n\n // Closest distance to current medoids\n let min_d_existing = Infinity;\n for (let m = 0; m < medoids.length; m++) {\n const d = this._get_distance(S_o, medoids[m], x_o, A[medoids[m]]);\n if (d < min_d_existing) min_d_existing = d;\n }\n\n const delta = this._get_distance(S_j, S_o, x_j, x_o) - min_d_existing;\n if (delta < 0) {\n deltaTD += delta;\n }\n }\n\n if (deltaTD < best_delta) {\n best_delta = deltaTD;\n best_idx = S_j;\n }\n }\n if (best_idx !== -1) {\n medoids.push(best_idx);\n }\n }\n return medoids;\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Clustering } from \"./Clustering.js\";\n\n/** @import { ParametersMeanShift } from \"./index.js\" */\n/** @import { InputType } from \"../index.js\" */\n\n/**\n * Mean Shift Clustering\n *\n * A non-parametric clustering technique that does not require prior knowledge of the\n * number of clusters. It identifies centers of density in the data.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class MeanShift extends Clustering {\n /**\n * @private\n * @type {number}\n */\n _bandwidth;\n /**\n * @private\n * @type {number}\n */\n _max_iter;\n /**\n * @private\n * @type {number}\n */\n _tolerance;\n /**\n * @private\n * @type {(dist: number) => number}\n */\n _kernel;\n /**\n * @type {Matrix}\n */\n _points;\n /**\n * @private\n * @type {number[] | undefined}\n */\n _clusters;\n /**\n * @private\n * @type {number[][] | undefined}\n */\n _cluster_list;\n\n /**\n *\n * @param {InputType} points\n * @param {Partial} parameters\n */\n constructor(points, parameters = {}) {\n super(\n points,\n /** @type {ParametersMeanShift} */ (\n Object.assign({ seed: 1212, metric: euclidean, bandwidth: 0, kernel: \"gaussian\" }, parameters)\n ),\n );\n\n // Ensure bandwidth is positive\n this._bandwidth = parameters.bandwidth ?? this._compute_bandwidth(this._matrix);\n this._max_iter = parameters.max_iter ?? Math.max(10, Math.floor(10 * Math.log10(this._N)));\n this._tolerance = parameters.tolerance ?? 1e-3;\n const kernel_param = parameters.kernel ?? \"gaussian\";\n // If kernel is a string, map to function\n if (typeof kernel_param === \"string\") {\n if (kernel_param === \"flat\") {\n this._kernel = (dist) => (dist <= this._bandwidth ? 1 : 0);\n } else {\n // gaussian (default)\n this._kernel = (dist) => Math.exp(-(dist * dist) / (2 * this._bandwidth * this._bandwidth));\n }\n } else {\n // custom function\n this._kernel = kernel_param;\n }\n\n // Copy points to a mutable matrix\n this._points = this._matrix.clone();\n\n this._mean_shift();\n this._assign_clusters();\n }\n\n /**\n * Helper to compute bandwidth if not provided\n * @private\n * @param {Matrix} matrix\n * @returns {number}\n */\n _compute_bandwidth(matrix) {\n const N = matrix.shape[0];\n //const D = matrix.shape[1];\n // Compute average pairwise distance\n let totalDist = 0;\n for (let i = 0; i < N; ++i) {\n const row_i = matrix.row(i);\n for (let j = i + 1; j < N; ++j) {\n const row_j = matrix.row(j);\n const dist = this._parameters.metric(row_i, row_j);\n totalDist += dist;\n }\n }\n const avgDist = totalDist / ((N * (N - 1)) / 2);\n // Use a fraction of avgDist as bandwidth\n return avgDist / 2;\n }\n\n /**\n * Compute kernel weight\n * @private\n * @param {number} dist\n * @returns {number}\n */\n _kernel_weight(dist) {\n return this._kernel(dist);\n }\n\n /**\n * Perform mean shift iterations\n * @private\n */\n _mean_shift() {\n const N = this._N;\n const D = this._D;\n const points = this._points;\n const metric = this._parameters.metric;\n //const bandwidth = this._bandwidth;\n const kernel = this._kernel_weight.bind(this);\n const tolerance = this._tolerance;\n\n for (let iter = 0; iter < this._max_iter; ++iter) {\n let max_shift = 0;\n // For each point compute shift\n for (let i = 0; i < N; ++i) {\n const row_i = points.row(i);\n let sum_weights = 0;\n const weighted_sum = new Float64Array(D);\n for (let j = 0; j < N; ++j) {\n const row_j = points.row(j);\n const dist = metric(row_i, row_j);\n const weight = kernel(dist);\n sum_weights += weight;\n for (let d = 0; d < D; ++d) {\n weighted_sum[d] += weight * row_j[d];\n }\n }\n if (sum_weights === 0) {\n // No neighbors within kernel, shift is zero\n //const shift = new Float64Array(D);\n // Compute shift magnitude\n const shift_norm = Math.sqrt(weighted_sum.reduce((acc, v) => acc + v * v, 0));\n max_shift = Math.max(max_shift, shift_norm);\n } else {\n const shift = new Float64Array(D);\n for (let d = 0; d < D; ++d) {\n shift[d] = weighted_sum[d] / sum_weights - row_i[d];\n }\n const shift_norm = Math.sqrt(shift.reduce((acc, v) => acc + v * v, 0));\n max_shift = Math.max(max_shift, shift_norm);\n // Update point\n for (let d = 0; d < D; ++d) {\n row_i[d] += shift[d];\n }\n }\n }\n if (max_shift < tolerance) {\n // Converged\n break;\n }\n }\n }\n\n /**\n * After convergence, assign clusters based on nearest mode\n * @private\n */\n _assign_clusters() {\n const N = this._N;\n const metric = this._parameters.metric;\n const bandwidth = this._bandwidth;\n\n // Group points that converged to the same mode\n // Two points are in the same mode if they're within bandwidth/2 of each other\n const mode_threshold = bandwidth * 0.5;\n /** @type {number[][]} */\n const modes = []; // Each mode contains indices of points in that mode\n const point_to_mode = new Array(N).fill(-1);\n\n for (let i = 0; i < N; ++i) {\n if (point_to_mode[i] !== -1) continue; // Already assigned to a mode\n\n const row_i = this._points.row(i);\n const mode = [i];\n point_to_mode[i] = modes.length;\n\n // Find all points close to this mode\n for (let j = i + 1; j < N; ++j) {\n if (point_to_mode[j] !== -1) continue;\n\n const row_j = this._points.row(j);\n const dist = metric(row_i, row_j);\n\n if (dist < mode_threshold) {\n mode.push(j);\n point_to_mode[j] = modes.length;\n }\n }\n\n modes.push(mode);\n }\n\n // Build final clusters - each mode becomes a cluster\n /** @type {number[][]} */\n const clusters = [];\n const cluster_ids = new Array(N).fill(-1);\n\n for (let mode_idx = 0; mode_idx < modes.length; ++mode_idx) {\n const mode = modes[mode_idx];\n clusters.push([...mode]);\n for (const point_idx of mode) {\n cluster_ids[point_idx] = mode_idx;\n }\n }\n\n this._clusters = cluster_ids;\n this._cluster_list = clusters;\n }\n\n /**\n * @returns {number[][]}\n */\n get_clusters() {\n // Ensure algorithm has been run\n if (!this._cluster_list) {\n this._mean_shift();\n this._assign_clusters();\n }\n return /** @type {number[][]} */ (this._cluster_list);\n }\n\n /**\n *\n * @returns {number[]}\n */\n get_cluster_list() {\n if (!this._clusters) {\n this._mean_shift();\n this._assign_clusters();\n }\n return /** @type {number[]} */ (this._clusters);\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Clustering } from \"./Clustering.js\";\n\n/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersOptics } from \"./index.js\" */\n\n/** @typedef {Object} DBEntry\n * @property {Float64Array} element\n * @property {number} index\n * @property {number} [reachability_distance]\n * @property {boolean} processed\n * @property {DBEntry[]} [neighbors]\n */\n\n/**\n * OPTICS (Ordering Points To Identify the Clustering Structure)\n *\n * A density-based clustering algorithm that extends DBSCAN. It handles clusters of varying\n * densities and produces a reachability plot that can be used to extract clusters.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class OPTICS extends Clustering {\n /**\n * **O**rdering **P**oints **T**o **I**dentify the **C**lustering **S**tructure.\n *\n * @param {InputType} points - The data.\n * @param {Partial} [parameters={}]\n * @see {@link https://www.dbs.ifi.lmu.de/Publikationen/Papers/OPTICS.pdf}\n * @see {@link https://en.wikipedia.org/wiki/OPTICS_algorithm}\n */\n constructor(points, parameters = {}) {\n super(\n points,\n /** @type {ParametersOptics} */ (\n Object.assign({ epsilon: 1, min_points: 4, metric: euclidean }, parameters)\n ),\n );\n const matrix = this._matrix;\n /**\n * @private\n * @type {DBEntry[]}\n */\n this._ordered_list = [];\n const ordered_list = this._ordered_list;\n /** @type {number[][]} */\n this._clusters = [];\n const clusters = this._clusters;\n\n const N = this._N;\n\n /**\n * @private\n * @type {DBEntry[]}\n */\n this._DB = new Array(N).fill(0).map((_, i) => {\n return {\n element: matrix.row(i),\n index: i,\n reachability_distance: undefined,\n processed: false,\n };\n });\n const DB = this._DB;\n\n this._cluster_index = 0;\n let cluster_index = this._cluster_index;\n\n for (const p of DB) {\n if (p.processed) continue;\n p.neighbors = this._get_neighbors(p);\n p.processed = true;\n clusters.push([p.index]);\n cluster_index = clusters.length - 1;\n ordered_list.push(p);\n if (this._core_distance(p) !== undefined) {\n const seeds = new Heap(null, (d) => d.reachability_distance, \"min\");\n this._update(p, seeds);\n this._expand_cluster(seeds, clusters[cluster_index]);\n }\n }\n }\n\n /**\n * @private\n * @param {DBEntry} p - A point of the data.\n * @returns {DBEntry[]} An array consisting of the `epsilon`-neighborhood of `p`.\n */\n _get_neighbors(p) {\n if (p?.neighbors) return p.neighbors;\n const DB = this._DB;\n const metric = this._parameters.metric;\n const epsilon = this._parameters.epsilon;\n const neighbors = [];\n for (const q of DB) {\n if (q.index === p.index) continue;\n if (metric(p.element, q.element) <= epsilon) {\n neighbors.push(q);\n }\n }\n return neighbors;\n }\n\n /**\n * @private\n * @param {DBEntry} p - A point of `matrix`.\n * @returns {number|undefined} The distance to the `min_points`-th nearest point of `p`, or undefined if the\n * `epsilon`-neighborhood has fewer elements than `min_points`.\n */\n _core_distance(p) {\n const min_points = this._parameters.min_points;\n const metric = this._parameters.metric;\n // Need min_points - 1 other points plus the point itself\n if (!p.neighbors || p.neighbors.length < min_points - 1) {\n return undefined;\n }\n // Sort neighbors by distance to find the MinPts-th closest\n const sortedNeighbors = p.neighbors.toSorted(\n (a, b) => metric(p.element, a.element) - metric(p.element, b.element),\n );\n // MinPts-th closest is at index min_points - 2 (0-indexed, excluding p itself)\n return metric(p.element, sortedNeighbors[min_points - 2].element);\n }\n\n /**\n * Updates the reachability distance of the points.\n *\n * @private\n * @param {DBEntry} p\n * @param {Heap} seeds\n */\n _update(p, seeds) {\n const metric = this._parameters.metric;\n const core_distance = this._core_distance(p);\n // If p is not a core point, don't update seeds\n if (core_distance === undefined) {\n return;\n }\n const neighbors = this._get_neighbors(p); //p.neighbors;\n for (const q of neighbors) {\n if (q.processed) continue;\n const new_reachability_distance = Math.max(core_distance, metric(p.element, q.element));\n //if (q.reachability_distance == undefined) { // q is not in seeds\n if (seeds.raw_data().findIndex((d) => d.element === q) < 0) {\n q.reachability_distance = new_reachability_distance;\n seeds.push(q);\n } else {\n // q is in seeds\n if (new_reachability_distance < (q.reachability_distance ?? Infinity)) {\n q.reachability_distance = new_reachability_distance;\n seeds = Heap.heapify(seeds.data(), (d) => d.reachability_distance ?? Infinity, \"min\"); // seeds change key =/\n }\n }\n }\n }\n\n /**\n * Expands the `cluster` with points in `seeds`.\n *\n * @private\n * @param {Heap} seeds\n * @param {number[]} cluster\n */\n _expand_cluster(seeds, cluster) {\n const ordered_list = this._ordered_list;\n while (!seeds.empty) {\n const q = /** @type {{ element: DBEntry, value: number}} */ (seeds.pop()).element;\n q.neighbors = this._get_neighbors(q);\n q.processed = true;\n cluster.push(q.index);\n ordered_list.push(q);\n if (this._core_distance(q) !== undefined) {\n this._update(q, seeds);\n // Recursive call removed - while loop handles iteration correctly\n }\n }\n }\n\n /**\n * Returns an array of clusters.\n *\n * @returns {number[][]} Array of clusters with the indices of the rows in given `matrix`.\n */\n get_clusters() {\n const clusters = [];\n const outliers = [];\n const min_points = this._parameters.min_points;\n for (const cluster of this._clusters) {\n if (cluster.length < min_points) {\n outliers.push(...cluster);\n } else {\n clusters.push(cluster);\n }\n }\n clusters.push(outliers);\n return clusters;\n }\n\n /**\n * @returns {number[]} Returns an array, where the ith entry defines the cluster affirmation of the ith point of\n * given data. (-1 stands for outlier)\n */\n get_cluster_list() {\n const N = this._matrix.shape[0];\n /** @type {number[]} */\n const result = new Array(N).fill(0);\n const clusters = this.get_clusters();\n for (let i = 0, n = clusters.length; i < n; ++i) {\n const cluster = clusters[i];\n for (const index of cluster) {\n result[index] = i < n - 1 ? i : -1;\n }\n }\n return result;\n }\n}\n","import { euclidean, euclidean_squared } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport { KMeans } from \"./KMeans.js\";\n\n/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersXMeans } from \"./index.js\" */\n\n/**\n * @typedef SplitResult\n * @property {number} index - Index of the cluster being split\n * @property {number} bic_parent - BIC score of the parent cluster\n * @property {number} bic_children - BIC score of the split children\n * @property {number[][]} child_clusters - Clusters after splitting\n * @property {Float64Array[]} child_centroids - Centroids of child clusters\n */\n\n/**\n * @typedef CandidateResult\n * @property {KMeans} kmeans - The KMeans instance for this K\n * @property {number} score - BIC score\n */\n\n/**\n * X-Means Clustering\n *\n * An extension of K-Means that automatically determines the number of clusters (K)\n * using the Bayesian Information Criterion (BIC).\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class XMeans extends Clustering {\n /**\n * XMeans clustering algorithm that automatically determines the optimal number of clusters.\n *\n * X-Means extends K-Means by starting with a minimum number of clusters and iteratively\n * splitting clusters to improve the Bayesian Information Criterion (BIC).\n *\n * Algorithm:\n * 1. Start with K_min clusters using KMeans\n * 2. For each cluster, try splitting it into 2 sub-clusters\n * 3. If BIC improves after splitting, keep the split\n * 4. Run KMeans again with all (old + new) centroids\n * 5. Repeat until K_max is reached or no more improvements\n *\n * @param {InputType} points - The data points to cluster\n * @param {Partial} [parameters={}] - Configuration parameters\n * @see {@link https://www.cs.cmu.edu/~dpelleg/download/xmeans.pdf}\n * @see {@link https://github.com/annoviko/pyclustering/blob/master/pyclustering/cluster/xmeans.py}\n * @see {@link https://github.com/haifengl/smile/blob/master/core/src/main/java/smile/clustering/XMeans.java}\n */\n constructor(points, parameters = {}) {\n const defaults = {\n K_max: 10,\n K_min: 2,\n metric: euclidean,\n seed: 1212,\n min_cluster_size: 35,\n tolerance: 0.001,\n };\n super(points, /** @type {ParametersXMeans} */ (Object.assign(defaults, parameters)));\n this._randomizer = new Randomizer(this._parameters.seed);\n\n /** @type {KMeans | null} */\n this._best_kmeans = null;\n\n // Run XMeans algorithm\n this._run();\n }\n\n /**\n * Run the XMeans algorithm\n *\n * @private\n */\n _run() {\n /** @type {Map} */\n const candidates = new Map();\n const A = this._matrix;\n\n // Initialize with K_min clusters\n let current_kmeans = new KMeans(this._points, {\n K: this._parameters.K_min,\n metric: this._parameters.metric,\n seed: this._parameters.seed,\n });\n\n let K = this._parameters.K_min;\n\n candidates.set(K, {\n kmeans: current_kmeans,\n score: -Infinity,\n });\n\n // Iteratively improve clustering\n while (K < this._parameters.K_max) {\n const clusters = current_kmeans.get_clusters();\n const centroids = current_kmeans.centroids;\n\n // Try splitting each cluster\n /** @type {SplitResult[]} */\n const split_results = [];\n\n for (let j = 0; j < clusters.length; ++j) {\n const cluster = clusters[j];\n\n // Skip small clusters - need enough points for reliable BIC\n if (cluster.length < this._parameters.min_cluster_size) {\n continue;\n }\n\n // Get subset data for this cluster\n /** @type {number[][]} */\n const subset_points = cluster.map((idx) => {\n const row = A.row(idx);\n return Array.from(row);\n });\n\n // Calculate BIC for parent (single cluster)\n const parent_bic = this._bic([cluster], [centroids[j]]);\n\n // Run KMeans with K=2 on subset\n const subset_kmeans = new KMeans(subset_points, {\n K: 2,\n metric: this._parameters.metric,\n seed: this._randomizer.seed,\n });\n\n const child_clusters_local = subset_kmeans.get_clusters();\n const child_centroids = subset_kmeans.centroids;\n\n // Map local indices back to global indices\n /** @type {number[][]} */\n const child_clusters_global = child_clusters_local.map((local_cluster) =>\n local_cluster.map((local_idx) => cluster[local_idx]),\n );\n\n // Calculate BIC for children (split into 2 clusters)\n const children_bic = this._bic(child_clusters_global, child_centroids);\n\n split_results.push({\n index: j,\n bic_parent: parent_bic,\n bic_children: children_bic,\n child_clusters: child_clusters_global,\n child_centroids: child_centroids,\n });\n }\n\n // Keep all splits that improve BIC (BIC_children > BIC_parent)\n /** @type {SplitResult[]} */\n const accepted_splits = split_results.filter((result) => result.bic_children > result.bic_parent);\n\n // If no splits improve BIC, we're done\n if (accepted_splits.length === 0) {\n break;\n }\n\n // Build new centroids array: keep non-split centroids + add split centroids\n /** @type {Float64Array[]} */\n const new_centroids = [];\n const split_indices = new Set();\n\n // Sort accepted splits by improvement (descending)\n accepted_splits.sort((a, b) => b.bic_children - b.bic_parent - (a.bic_children - a.bic_parent));\n\n for (const split of accepted_splits) {\n if (centroids.length + split_indices.size + 1 <= this._parameters.K_max) {\n split_indices.add(split.index);\n } else {\n break;\n }\n }\n\n for (let i = 0; i < centroids.length; ++i) {\n if (split_indices.has(i)) {\n // This cluster was split - add both child centroids\n const split_result = accepted_splits.find((s) => s.index === i);\n if (split_result) {\n new_centroids.push(...split_result.child_centroids);\n }\n } else {\n // This cluster wasn't split - keep its centroid\n new_centroids.push(centroids[i]);\n }\n }\n\n // Run KMeans on full dataset with new centroids as initialization\n // This is crucial - we need to reassign all points to all clusters\n const newK = new_centroids.length;\n\n // Create a new KMeans instance with K set to new number of clusters\n current_kmeans = new KMeans(this._matrix, {\n K: newK,\n metric: this._parameters.metric,\n seed: this._randomizer.seed,\n initial_centroids: new_centroids,\n });\n\n // Store the candidate with the BIC of the FULL dataset\n candidates.set(newK, {\n kmeans: current_kmeans,\n score: this._bic(current_kmeans.get_clusters(), current_kmeans.centroids),\n });\n\n K = newK;\n }\n\n // Select best candidate based on BIC score\n this._best_kmeans = this._select_best_candidate(candidates);\n }\n\n /**\n * Select the best candidate based on BIC score\n *\n * @private\n * @param {Map} candidates\n * @returns {KMeans}\n */\n _select_best_candidate(candidates) {\n if (candidates.size === 0) {\n throw new Error(\"No candidates found\");\n }\n\n const first_candidate = candidates.get(this._parameters.K_min);\n if (!first_candidate) {\n throw new Error(\"Missing initial candidate\");\n }\n\n let best_score = first_candidate.score;\n /** @type {KMeans} */\n let best_kmeans = first_candidate.kmeans;\n\n for (const candidate of candidates.values()) {\n if (candidate.score > best_score) {\n best_score = candidate.score;\n best_kmeans = candidate.kmeans;\n }\n }\n\n return best_kmeans;\n }\n\n /**\n * Calculate Bayesian Information Criterion for a set of clusters.\n *\n * Uses Kass's formula for BIC calculation:\n * BIC(θ) = L(D) - 0.5 * p * ln(N)\n *\n * Where:\n * - L(D) is the log-likelihood of the data\n * - p is the number of free parameters: (K-1) + D*K + 1\n * - N is the total number of points\n *\n * @private\n * @param {number[][]} clusters - Array of clusters with point indices\n * @param {Float64Array[]} centroids - Array of centroids\n * @returns {number} BIC score (higher is better)\n */\n _bic(clusters, centroids) {\n const A = this._matrix;\n const D = this._D;\n const K = centroids.length;\n\n let total_variance = 0;\n let N = 0;\n\n // Calculate total variance (sum of squared distances)\n for (let i = 0; i < K; ++i) {\n const cluster = clusters[i];\n const centroid = centroids[i];\n N += cluster.length;\n\n for (let j = 0; j < cluster.length; ++j) {\n const point_idx = cluster[j];\n const point = A.row(point_idx);\n // Sum of squared distances (variance term)\n total_variance += euclidean_squared(centroid, point);\n }\n }\n\n // Not enough points for meaningful BIC\n if (N <= K) {\n return -Infinity;\n }\n\n // Estimate variance (ML estimate)\n const variance = total_variance / (N - K);\n\n // Handle case of zero variance (all points identical)\n if (variance <= 0) {\n return -Infinity;\n }\n\n // Number of free parameters: (K-1) cluster weights + K*D centroid coordinates + 1 variance\n const p = K - 1 + D * K + 1;\n\n // Calculate log-likelihood\n let log_likelihood = 0;\n const log_2pi = Math.log(2 * Math.PI);\n\n for (let i = 0; i < K; ++i) {\n const n = clusters[i].length;\n if (n <= 1) continue;\n\n // Log-likelihood for cluster i\n const cluster_log_likelihood =\n n * Math.log(n / N) - 0.5 * n * log_2pi - 0.5 * n * D * Math.log(variance) - 0.5 * (n - 1);\n\n log_likelihood += cluster_log_likelihood;\n }\n\n // BIC = log_likelihood - 0.5 * p * ln(N)\n return log_likelihood - 0.5 * p * Math.log(N);\n }\n\n /**\n * Get the computed clusters\n *\n * @returns {number[][]} Array of clusters, each containing indices of points\n */\n get_clusters() {\n if (!this._best_kmeans) {\n throw new Error(\"XMeans has not been run\");\n }\n return this._best_kmeans.get_clusters();\n }\n\n /** @returns {number[]} The cluster list */\n get_cluster_list() {\n if (!this._best_kmeans) {\n throw new Error(\"XMeans has not been run\");\n }\n return this._best_kmeans.get_cluster_list();\n }\n\n /**\n * Get the final centroids\n *\n * @returns {Float64Array[]} Array of centroids\n */\n get centroids() {\n if (!this._best_kmeans) {\n throw new Error(\"XMeans has not been run\");\n }\n return this._best_kmeans.centroids;\n }\n\n /**\n * Get the optimal number of clusters found\n *\n * @returns {number} The number of clusters\n */\n get k() {\n if (!this._best_kmeans) {\n throw new Error(\"XMeans has not been run\");\n }\n return this._best_kmeans.k;\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { Randomizer } from \"../util/index.js\";\n\n/** @import {InputType} from \"../index.js\" */\n\n/**\n * @abstract\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n *\n * Base class for all Dimensionality Reduction (DR) algorithms.\n *\n * Provides a common interface for parameters management, data initialization,\n * and transformation (both synchronous and asynchronous).\n *\n * @class\n */\nexport class DR {\n /** @type {number} */\n _D;\n /** @type {number} */\n _N;\n /** @type {Randomizer} */\n _randomizer;\n /** @type {boolean} */\n _is_initialized;\n\n /**\n * Takes the default parameters and seals them, remembers the type of input `X`, and initializes the random number\n * generator.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Para} default_parameters - Object containing default parameterization of the DR method.\n * @param {Partial} parameters - Object containing parameterization of the DR method to override defaults.\n */\n constructor(X, default_parameters, parameters = {}) {\n /** @type {T} */\n this.__input = X;\n\n /** @type {Para} */\n this._parameters = /** @type {Para} */ Object.seal({\n ...default_parameters,\n ...parameters,\n });\n /** @type {\"array\" | \"matrix\" | \"typed\"} */\n this._type;\n /** @type {Matrix} */\n this.X;\n /** @type {Matrix} */\n this.Y;\n\n if (Array.isArray(X)) {\n if (X[0] instanceof Float64Array) {\n this._type = \"typed\";\n } else {\n this._type = \"array\";\n }\n this.X = Matrix.from(X);\n } else if (X instanceof Matrix) {\n this._type = \"matrix\";\n this.X = X;\n } else {\n throw new Error(\"No valid type for X!\");\n }\n const [N, D] = this.X.shape;\n this._N = N;\n this._D = D;\n this._randomizer = new Randomizer(this._parameters.seed);\n this._is_initialized = false;\n }\n\n /**\n * Get all Parameters.\n * @overload\n * @returns {Para}\n */\n /**\n * Get value of given parameter.\n * @template {keyof Para} K\n * @overload\n * @param {K} name - Name of the parameter.\n * @returns {Para[K]}\n */\n /**\n * Set value of given parameter.\n * @template {keyof Para} K\n * @overload\n * @param {K} name - Name of the parameter.\n * @param {Para[K]} value - Value of the parameter to set.\n * @returns {this}\n */\n /**\n * @param {keyof Para} [name] - Name of the parameter. If null, returns all parameters as an Object.\n * @param {Para[keyof Para]} [value] - Value of the parameter to set. If name is set and value is not given, returns the\n * current value.\n * @returns {Para | Para[keyof Para] | this} On setting a parameter, returns the DR object. If name is set and value is not\n * given, returns the parameter value. If name is null, returns all parameters. On setting a parameter, this\n * function returns the DR object. If `name` is set and `value == null` then return actual parameter value. If\n * `name` is not given, then returns all parameters as an Object.\n * @example\n * ```js\n * const DR = new druid.TSNE(X, {d: 3}); // creates a new DR object, with parameter for `d = 3`.\n * DR.parameter(\"d\"); // returns 3\n * DR.parameter(\"d\", 2); // sets parameter `d` to 2 and returns `DR`.\n * ```\n *\n */\n parameter(name, value) {\n if (name === undefined && value === undefined) {\n return Object.assign({}, this._parameters);\n }\n if (name && !Object.hasOwn(this._parameters, name)) {\n throw new Error(`${String(name)} is not a valid parameter!`);\n }\n if (name && value !== undefined) {\n this._parameters[name] = value;\n this._is_initialized = false;\n return this;\n } else if (name) {\n return this._parameters[name];\n }\n throw new Error(\"Should not happen!\");\n }\n\n /**\n * Computes the projection.\n *\n * @abstract\n * @param {...unknown} args\n * @returns {T} The projection.\n */\n transform(...args) {\n args;\n this.check_init();\n return this.projection;\n }\n\n /**\n * Computes the projection.\n *\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.\n * @returns {T} The dimensionality reduced dataset.\n */\n static transform(X, parameters, ...args) {\n args;\n const dr = new DR(X, parameters, parameters);\n return /** @type {T} */ (dr.transform());\n }\n\n /**\n * Computes the projection.\n *\n * @abstract\n * @param {...unknown} args\n * @returns {Generator} The intermediate steps of the projection.\n */\n *generator(...args) {\n const R = this.transform(...args);\n yield R;\n return R;\n }\n\n /**\n * Computes the projection.\n *\n * @template {{ seed?: number }} Para\n * @param {InputType} X\n * @param {Para} parameters\n * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.\n * @returns {Generator} A generator yielding the intermediate steps of the dimensionality\n * reduction method.\n */\n static *generator(X, parameters, ...args) {\n const dr = new DR(X, parameters, parameters);\n const generator = dr.generator(...args);\n let result;\n do {\n result = generator.next();\n yield result.value;\n } while (!result.done);\n\n return result.value;\n }\n\n /**\n * @abstract\n * @param {...unknown} args\n */\n init(...args) {\n args;\n }\n\n /**\n * If the respective DR method has an `init` function, call it before `transform`.\n *\n * @returns {DR}\n */\n check_init() {\n if (!this._is_initialized && typeof this.init === \"function\") {\n this.init();\n this._is_initialized = true;\n }\n return this;\n }\n\n /** @returns {T} The projection in the type of input `X`. */\n get projection() {\n if (Object.hasOwn(this, \"Y\")) {\n this.check_init();\n //return this._type === \"matrix\" ? this.Y : this.Y.to2dArray();\n if (this._type === \"matrix\") {\n return /** @type {T} */ (/** @type {any} */ (this.Y));\n } else if (this._type === \"typed\") {\n return /** @type {T} */ (/** @type {any} */ (this.Y.to2dArray()));\n } else {\n return /** @type {T} */ (/** @type {any} */ (this.Y.asArray()));\n }\n } else {\n throw new Error(\"The dataset is not transformed yet!\");\n }\n }\n\n /**\n * Computes the projection.\n *\n * @param {...unknown} args - Arguments the transform method of the respective DR method takes.\n * @returns {Promise} The dimensionality reduced dataset.\n */\n async transform_async(...args) {\n return this.transform(...args);\n }\n\n /**\n * Computes the projection.\n *\n * @template {{ seed?: number }} Para\n * @param {InputType} X\n * @param {Para} parameters\n * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.\n * @returns {Promise} A promise yielding the dimensionality reduced dataset.\n */\n static async transform_async(X, parameters, ...args) {\n return DR.transform(X, parameters, ...args);\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersFASTMAP } from \"./index.js\"; */\n\n/**\n * FastMap algorithm for dimensionality reduction.\n *\n * A very fast algorithm for projecting high-dimensional data into a lower-dimensional\n * space while preserving pairwise distances. It works similarly to PCA but uses\n * only a subset of the data to find projection axes.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class FASTMAP extends DR {\n /**\n * FastMap: a fast algorithm for indexing, data-mining and visualization of traditional and multimedia datasets.\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://doi.org/10.1145/223784.223812}\n */\n constructor(X, parameters) {\n super(X, { d: 2, metric: euclidean, seed: 1212 }, parameters);\n }\n\n /**\n * Chooses two points which are the most distant in the actual projection.\n *\n * @private\n * @param {(a: number, b: number) => number} dist\n * @returns {[number, number, number]} An array consisting of first index, second index, and distance between the\n * two points.\n */\n _choose_distant_objects(dist) {\n const X = this.X;\n const N = X.shape[0];\n let a_index = this._randomizer.random_int % N;\n /** @type {number | null} */\n let b_index = null;\n let max_dist = -Infinity;\n for (let i = 0; i < N; ++i) {\n const d_ai = dist(a_index, i);\n if (d_ai > max_dist) {\n max_dist = d_ai;\n b_index = i;\n }\n }\n if (b_index === null) throw new Error(\"should not happen!\");\n max_dist = -Infinity;\n for (let i = 0; i < N; ++i) {\n const d_bi = dist(b_index, i);\n if (d_bi > max_dist) {\n max_dist = d_bi;\n a_index = i;\n }\n }\n return [a_index, b_index, max_dist];\n }\n\n /**\n * Computes the projection.\n *\n * @returns {T} The `d`-dimensional projection of the data matrix `X`.\n */\n transform() {\n const X = this.X;\n const N = X.shape[0];\n const d = /** @type {number} */ (this._parameters.d);\n const metric = /** @type {typeof euclidean} */ (this._parameters.metric);\n const Y = new Matrix(N, d, 0);\n /** @type {(a: number, b: number) => number} */\n let dist = (a, b) => metric(X.row(a), X.row(b));\n\n for (let _col = 0; _col < d; ++_col) {\n const old_dist = dist;\n // choose pivot objects\n const [a_index, b_index, d_ab] = this._choose_distant_objects(dist);\n if (d_ab !== 0) {\n // project the objects on the line (O_a, O_b)\n for (let i = 0; i < N; ++i) {\n const d_ai = dist(a_index, i);\n const d_bi = dist(b_index, i);\n const y_i = (d_ai ** 2 + d_ab ** 2 - d_bi ** 2) / (2 * d_ab);\n Y.set_entry(i, _col, y_i);\n }\n // consider the projections of the objects on a\n // hyperplane perpendicluar to the line (a, b);\n // the distance function D'() between two\n // projections is given by Eq.4\n dist = (a, b) => Math.sqrt(old_dist(a, b) ** 2 - (Y.entry(a, _col) - Y.entry(b, _col)) ** 2);\n }\n }\n // return embedding.\n this.Y = Y;\n return this.projection;\n }\n\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new FASTMAP(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new FASTMAP(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new FASTMAP(X, parameters);\n return dr.transform_async();\n }\n}\n","/**\n * Base class for all K-Nearest Neighbors (KNN) search algorithms.\n *\n * Provides a common interface for elements management and search operations.\n *\n * @abstract\n * @category KNN\n * @template {number[] | Float64Array} T - Type of elements\n * @template {Object} Para - Type of parameters\n * @class\n */\nexport class KNN {\n /** @type {T[]} */\n _elements;\n /** @type {Para} */\n _parameters;\n /** @type {\"typed\" | \"array\"} */\n _type;\n\n /**\n * @param {T[]} elements\n * @param {Para} parameters\n */\n constructor(elements, parameters) {\n if (elements.length === 0) throw new Error(\"Elements needs to contain at least one element!\");\n if (elements[0] instanceof Float64Array) {\n this._type = \"typed\";\n } else {\n this._type = \"array\";\n }\n this._parameters = parameters;\n this._elements = elements;\n }\n\n /**\n * @abstract\n * @param {T} t\n * @param {number} k\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search(t, k) {\n t;\n k;\n throw new Error(\"The function search must be implemented!\");\n }\n\n /**\n * @abstract\n * @param {number} i\n * @param {number} k\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i, k) {\n i;\n k;\n throw new Error(\"The function search_by_index must be implemented!\");\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersAnnoy } from \"./index.js\" */\n\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} AnnoyNode\n * @property {boolean} isLeaf - Whether this is a leaf node\n * @property {number[]} indices - Indices of points in this node (leaf) or children (internal)\n * @property {number[]} normal - Hyperplane normal vector (internal nodes only)\n * @property {number} offset - Hyperplane offset (internal nodes only)\n * @property {AnnoyNode | null} left - Left child (internal nodes only)\n * @property {AnnoyNode | null} right - Right child (internal nodes only)\n */\n\n/**\n * Annoy-style (Approximate Nearest Neighbors Oh Yeah) implementation using Random Projection Trees.\n *\n * This implementation builds multiple random projection trees where each tree randomly selects\n * two points and splits the space based on a hyperplane equidistant between them.\n *\n * Key features:\n * - Multiple random projection trees for better recall\n * - Each tree uses random hyperplanes for splitting\n * - Priority queue search for better recall\n * - Combines results from all trees\n *\n * Best suited for:\n * - High-dimensional data\n * - Approximate nearest neighbor search\n * - Large datasets\n * - When high recall is needed with approximate methods\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link https://github.com/spotify/annoy}\n * @see {@link https://erikbern.com/2015/09/24/nearest-neighbors-and-vector-models-epilogue-curse-of-dimensionality.html}\n */\nexport class Annoy extends KNN {\n /**\n * Creates a new Annoy-style index with random projection trees.\n *\n * @param {T[]} elements - Elements to index\n * @param {ParametersAnnoy} [parameters={}] - Configuration parameters\n */\n constructor(\n elements,\n parameters = {\n metric: euclidean,\n numTrees: 10,\n maxPointsPerLeaf: 10,\n seed: 1212,\n },\n ) {\n // Handle empty initialization - use dummy element\n const hasElements = elements && elements.length > 0;\n const firstElement = /** @type {T} */ (hasElements ? elements[0] : new Float64Array([0]));\n\n super([firstElement], parameters);\n\n this._metric = this._parameters.metric ?? euclidean;\n this._numTrees = this._parameters.numTrees ?? 10;\n this._maxPointsPerLeaf = this._parameters.maxPointsPerLeaf ?? 10;\n this._seed = this._parameters.seed ?? 1212;\n this._randomizer = new Randomizer(this._seed);\n\n /**\n * @private\n * @type {AnnoyNode[]}\n */\n this._trees = [];\n\n // Build trees\n if (hasElements) {\n // Reset elements and rebuild properly\n /** @type {T[]} */\n this._elements = [];\n this._trees = [];\n this.add(elements);\n }\n }\n\n /**\n * Get the number of trees in the index.\n * @returns {number}\n */\n get num_trees() {\n return this._trees.length;\n }\n\n /**\n * Get the total number of nodes in all trees.\n * @returns {number}\n */\n get num_nodes() {\n let total = 0;\n for (const tree of this._trees) {\n total += this._countNodes(tree);\n }\n return total;\n }\n\n /**\n * @private\n * @param {any} node\n * @returns {number}\n */\n _countNodes(node) {\n if (!node) return 0;\n return 1 + this._countNodes(node.left) + this._countNodes(node.right);\n }\n\n /**\n * Add elements to the Annoy index.\n * @param {T[]} elements\n * @returns {this}\n */\n add(elements) {\n // Extend elements array\n this._elements = this._elements.concat(elements);\n\n // Rebuild all trees with new elements\n this._trees = [];\n this._buildTrees();\n\n return this;\n }\n\n /**\n * Build all random projection trees.\n * @private\n */\n _buildTrees() {\n const elements = this._elements;\n const n = elements.length;\n\n for (let t = 0; t < this._numTrees; t++) {\n // Create index array for this tree\n const indices = Array.from({ length: n }, (_, i) => i);\n const tree = this._buildTreeRecursive(indices);\n this._trees.push(tree);\n }\n }\n\n /**\n * Recursively build a random projection tree.\n * @private\n * @param {number[]} indices - Indices of elements to include\n * @returns {AnnoyNode}\n */\n _buildTreeRecursive(indices) {\n const elements = this._elements;\n\n // Base case: small enough to be a leaf\n if (indices.length <= this._maxPointsPerLeaf) {\n return {\n isLeaf: true,\n indices: indices,\n normal: [],\n offset: 0,\n left: null,\n right: null,\n };\n }\n\n // Select two random points to define the splitting hyperplane\n const idx1 = indices[Math.floor(this._randomizer.random * indices.length)];\n const idx2 = indices[Math.floor(this._randomizer.random * indices.length)];\n\n const point1 = elements[idx1];\n const point2 = elements[idx2];\n\n // Compute normal vector (point2 - point1)\n const dim = point1.length;\n /** @type {number[]} */\n const normal = new Array(dim);\n for (let i = 0; i < dim; i++) {\n normal[i] = point2[i] - point1[i];\n }\n\n // Normalize\n let norm = 0;\n for (let i = 0; i < dim; i++) {\n norm += normal[i] * normal[i];\n }\n norm = Math.sqrt(norm);\n\n if (norm > 1e-10) {\n for (let i = 0; i < dim; i++) {\n normal[i] /= norm;\n }\n }\n\n // Compute midpoint and offset\n /** @type {number[]} */\n const midpoint = new Array(dim);\n for (let i = 0; i < dim; i++) {\n midpoint[i] = (point1[i] + point2[i]) / 2;\n }\n\n // Compute offset: dot(normal, midpoint)\n let offset = 0;\n for (let i = 0; i < dim; i++) {\n offset += normal[i] * midpoint[i];\n }\n\n // Split points based on which side of hyperplane they fall\n const leftIndices = [];\n const rightIndices = [];\n\n for (const idx of indices) {\n const point = elements[idx];\n let dot = 0;\n for (let i = 0; i < dim; i++) {\n dot += normal[i] * point[i];\n }\n\n if (dot < offset) {\n leftIndices.push(idx);\n } else {\n rightIndices.push(idx);\n }\n }\n\n // Handle edge case where all points fall on one side\n if (leftIndices.length === 0 || rightIndices.length === 0) {\n return {\n isLeaf: true,\n indices: indices,\n normal: [],\n offset: 0,\n left: null,\n right: null,\n };\n }\n\n // Recursively build subtrees\n const left = this._buildTreeRecursive(leftIndices);\n const right = this._buildTreeRecursive(rightIndices);\n\n return {\n isLeaf: false,\n indices: [],\n normal: normal,\n offset: offset,\n left: left,\n right: right,\n };\n }\n\n /**\n * Compute distance from point to hyperplane.\n * @private\n * @param {T} point\n * @param {number[]} normal\n * @param {number} offset\n * @returns {number} Signed distance (positive = right side, negative = left side)\n */\n _distanceToHyperplane(point, normal, offset) {\n let dot = 0;\n for (let i = 0; i < point.length; i++) {\n dot += normal[i] * point[i];\n }\n return dot - offset;\n }\n\n /**\n * Search for k approximate nearest neighbors.\n * @param {T} query\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search(query, k = 5) {\n const metric = this._metric;\n const elements = this._elements;\n\n if (elements.length === 0) return [];\n\n // Collect candidates from all trees using priority queue\n const candidates = new Set();\n\n // Collect more candidates for better recall\n // Search at least k * numTrees * 2 candidates\n const minCandidates = Math.min(k * this._numTrees * 3, elements.length);\n\n for (const tree of this._trees) {\n this._searchTreePriority(tree, query, candidates, minCandidates);\n }\n\n // Compute exact distances for all candidates\n /** @type {Heap<{ index: number; distance: number }>} */\n const best = new Heap(null, (d) => d.distance, \"max\");\n\n for (const idx of candidates) {\n const element = elements[idx];\n if (!element || element.length !== query.length) continue;\n\n const dist = metric(query, element);\n\n if (best.length < k) {\n best.push({ index: idx, distance: dist });\n } else if (dist < (best.first?.value ?? Infinity)) {\n best.pop();\n best.push({ index: idx, distance: dist });\n }\n }\n\n // If we still don't have enough candidates, do a linear scan fallback\n if (best.length < k) {\n for (let i = 0; i < elements.length && best.length < k; i++) {\n if (candidates.has(i)) continue;\n\n const element = elements[i];\n if (!element || element.length !== query.length) continue;\n\n const dist = metric(query, element);\n best.push({ index: i, distance: dist });\n }\n }\n\n // Convert to result format\n /** @type {{ element: T; index: number; distance: number }[]} */\n const result = [];\n while (best.length > 0) {\n const item = /** @type {{ element: { index: number; distance: number }; value: number }} */ (best.pop());\n result.push({\n element: elements[item.element.index],\n index: item.element.index,\n distance: item.value,\n });\n }\n\n return result.reverse();\n }\n\n /**\n * Search tree using priority queue for better recall.\n * Explores nodes in order of distance to hyperplane.\n * @private\n * @param {AnnoyNode} node\n * @param {T} query\n * @param {Set} candidates\n * @param {number} maxCandidates\n */\n _searchTreePriority(node, query, candidates, maxCandidates) {\n if (!node) return;\n\n // Priority queue entry: { node, distance }\n /** @type {Heap<{ node: AnnoyNode; dist: number }>} */\n const pq = new Heap(null, (d) => d.dist, \"min\");\n pq.push({ node: node, dist: 0 });\n\n while (!pq.empty && candidates.size < maxCandidates) {\n const entry = pq.pop();\n if (!entry) continue;\n\n const currentNode = entry.element.node;\n\n // Leaf node: add all points\n if (currentNode.isLeaf) {\n for (const idx of currentNode.indices) {\n candidates.add(idx);\n if (candidates.size >= maxCandidates) return;\n }\n continue;\n }\n\n // Internal node: compute distance to hyperplane\n const dist = this._distanceToHyperplane(query, currentNode.normal, currentNode.offset);\n\n // Determine which side is closer\n const closerSide = dist < 0 ? currentNode.left : currentNode.right;\n const fartherSide = dist < 0 ? currentNode.right : currentNode.left;\n\n // Add closer side with priority 0 (explore first)\n if (closerSide) {\n pq.push({ node: closerSide, dist: 0 });\n }\n\n // Add farther side with priority = |dist| (explore later if needed)\n if (fartherSide && candidates.size < maxCandidates) {\n pq.push({ node: fartherSide, dist: Math.abs(dist) });\n }\n }\n }\n\n /**\n * @param {number} i\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i, k = 5) {\n if (i < 0 || i >= this._elements.length) return [];\n return this.search(this._elements[i], k);\n }\n\n /**\n * Alias for search_by_index for backward compatibility.\n *\n * @param {number} i - Index of the query element\n * @param {number} [k=5] - Number of nearest neighbors to return\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_index(i, k = 5) {\n return this.search_by_index(i, k);\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersBallTree } from \"./index.js\" */\n\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} ElementWithIndex\n * @property {number} index\n * @property {T} element\n */\n\n/**\n * Ball Tree for efficient nearest neighbor search.\n *\n * A Ball Tree is a metric tree that partitions points into a nested set of\n * hyperspheres (balls). It is particularly effective for high-dimensional\n * data and supports any valid metric.\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n */\nexport class BallTree extends KNN {\n /**\n * Generates a BallTree with given `elements`.\n *\n * @param {T[]} elements - Elements which should be added to the BallTree\n * @param {ParametersBallTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}`\n * @see {@link https://en.wikipedia.org/wiki/Ball_tree}\n * @see {@link https://github.com/invisal/noobjs/blob/master/src/tree/BallTree.js}\n */\n constructor(elements, parameters = { metric: euclidean, seed: 1212 }) {\n super(elements, Object.assign({ seed: 1212 }, parameters));\n /**\n * @private\n * @type {BallTreeNode | BallTreeLeaf}\n */\n this._root = this._construct(elements.map((element, index) => ({ index, element })));\n }\n\n /** @returns {Metric} */\n get _metric() {\n return this._parameters.metric;\n }\n\n /**\n * @private\n * @param {ElementWithIndex[]} elements\n * @returns {BallTreeNode | BallTreeLeaf} Root of balltree.\n */\n _construct(elements) {\n if (elements.length === 1) {\n return new BallTreeLeaf(elements);\n } else {\n const c = this._greatest_spread(elements);\n const sorted_elements = elements.sort((a, b) => a.element[c] - b.element[c]);\n const n = sorted_elements.length;\n const p_index = Math.floor(n / 2);\n const p = sorted_elements[p_index];\n const L = sorted_elements.slice(0, p_index);\n const R = sorted_elements.slice(p_index, n);\n const radius = Math.max(...elements.map((d) => this._metric(p.element, d.element)));\n let B;\n if (L.length > 0 && R.length > 0) {\n B = new BallTreeNode(p, this._construct(L), this._construct(R), radius);\n } else {\n B = new BallTreeLeaf(elements);\n }\n return B;\n }\n }\n\n /**\n * @private\n * @param {ElementWithIndex[]} B\n * @returns {number}\n */\n _greatest_spread(B) {\n const d = B[0].element.length;\n const start = new Array(d);\n\n for (let i = 0; i < d; ++i) {\n start[i] = [Infinity, -Infinity];\n }\n\n let spread = B.reduce((acc, current) => {\n for (let i = 0; i < d; ++i) {\n acc[i][0] = Math.min(acc[i][0], current.element[i]);\n acc[i][1] = Math.max(acc[i][1], current.element[i]);\n }\n return acc;\n }, start);\n spread = spread.map((d) => d[1] - d[0]);\n\n let c = 0;\n for (let i = 0; i < d; ++i) {\n c = spread[i] > spread[c] ? i : c;\n }\n return c;\n }\n\n /**\n * @param {number} i\n * @param {number} k\n */\n search_by_index(i, k = 5) {\n return this.search(this._elements[i], k);\n }\n\n /**\n * @param {T} t - Query element.\n * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors.\n */\n search(t, k = 5) {\n /** @type {Heap>} */\n const heap = new Heap(null, (d) => this._metric(d.element, t), \"max\");\n this._search(t, k, heap, this._root);\n\n // Convert heap to result array\n /** @type {{ element: T; index: number; distance: number }[]} */\n const result = [];\n while (heap.length > 0) {\n const item = /** @type {{ element: ElementWithIndex; value: number }} */ (heap.pop());\n result.push({\n element: item.element.element,\n index: item.element.index,\n distance: item.value,\n });\n }\n return result.reverse(); // Reverse to get closest first\n }\n\n /**\n * @private\n * @param {T} t - Query element.\n * @param {number} k - Number of nearest neighbors to return.\n * @param {Heap>} Q - Heap consists of the currently found `k` nearest neighbors.\n * @param {BallTreeNode | BallTreeLeaf} B\n */\n _search(t, k, Q, B) {\n if (!B) return;\n\n if (B instanceof BallTreeNode) {\n const dist_to_pivot = this._metric(t, B.pivot.element);\n if (Q.length >= k && dist_to_pivot - B.radius >= (Q.first?.value ?? -Infinity)) {\n return;\n }\n\n const c1 = B.child1;\n const c2 = B.child2;\n\n let d1 = Infinity;\n let d2 = Infinity;\n\n if (c1 instanceof BallTreeNode) d1 = this._metric(t, c1.pivot.element);\n else if (c1 instanceof BallTreeLeaf) d1 = this._metric(t, c1.points[0].element);\n\n if (c2 instanceof BallTreeNode) d2 = this._metric(t, c2.pivot.element);\n else if (c2 instanceof BallTreeLeaf) d2 = this._metric(t, c2.points[0].element);\n\n if (d1 < d2) {\n if (c1) this._search(t, k, Q, c1);\n if (c2) this._search(t, k, Q, c2);\n } else {\n if (c2) this._search(t, k, Q, c2);\n if (c1) this._search(t, k, Q, c1);\n }\n } else if (B instanceof BallTreeLeaf) {\n for (let i = 0, n = B.points.length; i < n; ++i) {\n const p = B.points[i];\n const dist = this._metric(p.element, t);\n if (Q.length < k) {\n Q.push(p);\n } else if (dist < (Q.first?.value ?? Infinity)) {\n Q.pop();\n Q.push(p);\n }\n }\n }\n }\n}\n\n/**\n * @private\n * @template {number[] | Float64Array} T\n */\nclass BallTreeNode {\n /**\n * @param {ElementWithIndex} pivot\n * @param {BallTreeNode | BallTreeLeaf | null} child1\n * @param {BallTreeNode | BallTreeLeaf | null} child2\n * @param {number} radius\n */\n constructor(pivot, child1 = null, child2 = null, radius = 0) {\n this.pivot = pivot;\n this.child1 = child1;\n this.child2 = child2;\n this.radius = radius;\n }\n}\n\n/**\n * @private\n * @template {number[] | Float64Array} T\n */\nclass BallTreeLeaf {\n /** @param {ElementWithIndex[]} points */\n constructor(points) {\n this.points = points;\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersHNSW } from \"./index.js\" */\n\n/**\n * @typedef {Object} Layer\n * @property {number} l_c - Layer number\n * @property {number[]} point_indices - Global indices of points in this layer\n * @property {Map} edges - Global index -> array of connected global indices\n */\n\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} Candidate\n * @property {T} element - The actual data point\n * @property {number} index - Global index in the dataset\n * @property {number} distance - Distance from query\n */\n\n/**\n * Hierarchical Navigable Small World (HNSW) graph for approximate nearest neighbor search.\n *\n * HNSW builds a multi-layer graph structure where each layer is a navigable small world graph.\n * The top layers serve as \"highways\" for fast traversal, while lower layers provide accuracy.\n * Each element is assigned to a random level, allowing logarithmic search complexity.\n *\n * Key parameters:\n * - `m`: Controls the number of connections per element (affects accuracy/memory)\n * - `ef_construction`: Controls the quality of the graph during construction (higher = better but slower)\n * - `ef`: Controls the quality of search (higher = better recall but slower)\n *\n * Based on:\n * - \"Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs\"\n * by Malkov & Yashunin (2016)\n * - \"Approximate Nearest Neighbor Search on High Dimensional Data\"\n * by Li et al. (2019)\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const points = [[1, 2], [3, 4], [5, 6], [7, 8]];\n * const hnsw = new druid.HNSW(points, {\n * metric: druid.euclidean,\n * m: 16,\n * ef_construction: 200\n * });\n *\n * const query = [2, 3];\n * const neighbors = hnsw.search(query, 2);\n * // [{ element: [1, 2], index: 0, distance: 1.41 }, ...]\n */\nexport class HNSW extends KNN {\n /**\n * Creates a new HNSW index.\n *\n * @param {T[]} points - Initial points to add to the index\n * @param {ParametersHNSW} [parameters={}] - Configuration parameters\n */\n constructor(\n points,\n parameters = {\n metric: euclidean,\n heuristic: true,\n m: 16,\n ef_construction: 200,\n m0: null,\n mL: null,\n seed: 1212,\n ef: 50,\n },\n ) {\n // Handle empty initialization - use dummy element\n const hasElements = points && points.length > 0;\n let firstElement = /** @type {T} */ (hasElements ? points[0] : new Float64Array([0]));\n\n // Validate all points have consistent dimensions\n if (hasElements) {\n const expected_dim = firstElement.length;\n for (let i = 1; i < points.length; i++) {\n if (!points[i] || points[i].length !== expected_dim) {\n console.warn(\n `HNSW: Point ${i} has inconsistent dimensions (expected ${expected_dim}, got ${points[i]?.length})`,\n );\n // Remove invalid points\n points = points.filter((_, idx) => idx === 0 || points[idx]?.length === expected_dim);\n firstElement = points[0];\n }\n }\n }\n\n super([firstElement], parameters);\n\n // Store reference to elements before clearing\n const elementsToAdd = hasElements ? [...points] : [];\n /** @type {T[]} */\n this._elements = [];\n\n /** @type {Metric} */\n this._metric = this._parameters.metric || euclidean;\n\n /** @type {Function} */\n this._select = this._parameters.heuristic ? this._select_heuristic.bind(this) : this._select_simple.bind(this);\n\n /**\n * @private\n * @type {Map}\n */\n this._graph = new Map();\n\n /** @type {number} */\n this._next_index = 0;\n\n // Validate and set parameters\n const m_param = this._parameters.m ?? 16;\n if (m_param <= 0 || !Number.isInteger(m_param)) {\n throw new Error(\"HNSW: parameter 'm' must be a positive integer\");\n }\n /** @type {number} */\n this._m = Math.max(2, m_param);\n\n const ef_construction_param = this._parameters.ef_construction ?? 200;\n if (ef_construction_param <= 0 || !Number.isInteger(ef_construction_param)) {\n throw new Error(\"HNSW: parameter 'ef_construction' must be a positive integer\");\n }\n /** @type {number} */\n this._ef_construction = ef_construction_param;\n\n const ef_param = this._parameters.ef ?? 50;\n if (ef_param <= 0 || !Number.isInteger(ef_param)) {\n throw new Error(\"HNSW: parameter 'ef' must be a positive integer\");\n }\n /** @type {number} */\n this._ef = ef_param;\n\n const m0_param = this._parameters.m0 ?? 2 * this._m;\n if (m0_param <= 0 || !Number.isInteger(m0_param)) {\n throw new Error(\"HNSW: parameter 'm0' must be a positive integer\");\n }\n /** @type {number} */\n this._m0 = m0_param;\n\n /** @type {number} */\n this._mL = this._parameters.mL ?? 1 / Math.log(this._m);\n\n /** @type {Randomizer} */\n this._randomizer = new Randomizer(this._parameters.seed);\n\n /** @type {number} - Current maximum layer in the graph */\n this._L = -1;\n\n /** @type {number[] | null} - Entry point indices for search */\n this._ep = null;\n\n // Add initial points\n if (elementsToAdd && elementsToAdd.length > 0) {\n this.add(elementsToAdd);\n }\n }\n\n /**\n * Add a single element to the index.\n *\n * @param {T} element - Element to add\n * @returns {HNSW} This instance for chaining\n */\n addOne(element) {\n return this.add([element]);\n }\n\n /**\n * Add multiple elements to the index.\n *\n * @param {T[]} new_elements - Elements to add\n * @returns {HNSW} This instance for chaining\n */\n add(new_elements) {\n // Handle empty array\n if (!new_elements || new_elements.length === 0) {\n return this;\n }\n\n const m = this._m;\n const ef_construction = this._ef_construction;\n const m0 = this._m0;\n const mL = this._mL;\n const randomizer = this._randomizer;\n const graph = this._graph;\n\n // Ensure _elements is a proper array that supports push\n if (!Array.isArray(this._elements)) {\n this._elements = Array.from(this._elements);\n }\n const elements = this._elements;\n\n // Get expected dimension from first existing element or first new element\n const expected_dim = elements.length > 0 ? elements[0].length : new_elements[0]?.length;\n\n for (const element of new_elements) {\n // Validate element\n if (!element || (!Array.isArray(element) && !(element instanceof Float64Array))) {\n console.warn(\"HNSW: Skipping invalid element (null, undefined, or not an array)\");\n continue;\n }\n\n // Validate dimensions\n if (element.length !== expected_dim) {\n console.warn(\n `HNSW: Skipping element with wrong dimensions (expected ${expected_dim}, got ${element.length})`,\n );\n continue;\n }\n\n elements.push(element);\n const global_index = elements.length - 1;\n\n // Assign random level to the element\n // Level is drawn from exponential distribution: l = floor(-ln(uniform(0,1)) * mL)\n const rand = Math.max(randomizer.random, 1e-10); // Avoid log(0)\n const l = Math.min(31, Math.floor(-Math.log(rand) * mL));\n\n let ep_indices = this._ep ? [...this._ep] : null;\n const L = this._L;\n\n if (L >= 0) {\n // Search from top layer down to min(L, l) + 1\n // These are the layers where element will NOT be inserted\n for (let l_c = L; l_c > l; --l_c) {\n const search_result = this._search_layer(element, ep_indices, 1, l_c);\n if (search_result.length > 0) {\n ep_indices = [search_result[0].index];\n }\n }\n\n // Insert element into layers l down to 0\n for (let l_c = Math.min(L, l); l_c >= 0; --l_c) {\n const layer = graph.get(l_c);\n if (!layer) continue;\n\n layer.point_indices.push(global_index);\n\n // Search for ef_construction nearest neighbors\n let W = this._search_layer(element, ep_indices, ef_construction, l_c);\n\n // If graph search returns no results (e.g., graph is empty or disconnected),\n // fall back to linear search over all existing elements\n if (W.length === 0 && elements.length > 1) {\n const fallbackCandidates = [];\n for (let i = 0; i < elements.length - 1; i++) {\n const elem = elements[i];\n if (elem && elem.length === element.length) {\n fallbackCandidates.push({\n element: elem,\n index: i,\n distance: this._metric(element, elem),\n });\n }\n }\n fallbackCandidates.sort((a, b) => a.distance - b.distance);\n W = fallbackCandidates.slice(0, ef_construction);\n // Update ep_indices for next layer based on fallback results\n if (l_c === Math.min(L, l)) {\n ep_indices = W.map((c) => c.index);\n }\n }\n\n // Select neighbors using heuristic or simple approach (respect heuristic setting on all layers)\n const neighbor_indices = this._select(element, W, l_c === 0 ? m0 : m, l_c);\n\n // Add bidirectional connections\n for (const neighbor_idx of neighbor_indices) {\n if (neighbor_idx === global_index) continue;\n\n // Add connection from element to neighbor\n if (!layer.edges.has(global_index)) {\n layer.edges.set(global_index, []);\n }\n layer.edges.get(global_index)?.push(neighbor_idx);\n\n // Add connection from neighbor to element\n if (!layer.edges.has(neighbor_idx)) {\n layer.edges.set(neighbor_idx, []);\n }\n const neighbor_edge_list = layer.edges.get(neighbor_idx);\n if (neighbor_edge_list && !neighbor_edge_list.includes(global_index)) {\n neighbor_edge_list.push(global_index);\n }\n\n // Prune connections if too many\n const max_conn = l_c === 0 ? m0 : m;\n const neighbor_edges = layer.edges.get(neighbor_idx);\n if (neighbor_edges && neighbor_edges.length > max_conn) {\n const neighbor_element = elements[neighbor_idx];\n // Filter out self-connections before pruning\n const valid_neighbor_edges = neighbor_edges.filter((idx) => idx !== neighbor_idx);\n const neighbor_candidates = valid_neighbor_edges.map((idx) => ({\n element: elements[idx],\n index: idx,\n distance: this._metric(neighbor_element, elements[idx]),\n }));\n const pruned =\n l_c === 0\n ? this._select_simple(neighbor_element, neighbor_candidates, max_conn)\n : this._select(neighbor_element, neighbor_candidates, max_conn, l_c);\n layer.edges.set(neighbor_idx, pruned);\n }\n }\n\n // Use closest neighbor as entry point for next layer (following HNSW paper)\n if (W.length > 0) {\n ep_indices = [W[0].index];\n }\n }\n }\n\n // If element's level is higher than current max, create new layers\n if (l > L) {\n for (let i = L + 1; i <= l; ++i) {\n graph.set(i, {\n l_c: i,\n point_indices: [global_index],\n edges: new Map(),\n });\n }\n // Element becomes the new entry point\n this._ep = [global_index];\n this._L = l;\n }\n\n // Special case: if this is the first element (L was -1),\n // we need to ensure layer 0 has proper structure for future insertions\n if (L === -1) {\n if (!graph.has(0)) {\n graph.set(0, {\n l_c: 0,\n point_indices: [global_index],\n edges: new Map(),\n });\n }\n const layer0 = graph.get(0);\n if (layer0 && !layer0.edges.has(global_index)) {\n layer0.edges.set(global_index, []);\n }\n }\n }\n\n return this;\n }\n\n /**\n * Select neighbors using the heuristic approach.\n *\n * The heuristic extends candidates with their neighbors and selects\n * points that are closer to the query than to already selected points.\n * This maintains graph connectivity better than simple selection.\n *\n * @private\n * @param {T} q - Query element\n * @param {Candidate[]} candidates - Candidate elements with distances\n * @param {number} M - Maximum number of neighbors to return\n * @param {number} l_c - Layer number\n * @param {boolean} [extend_candidates=true] - Whether to extend candidates with their neighbors\n * @param {boolean} [keep_pruned_connections=true] - Whether to add pruned connections back if needed\n * @returns {number[]} Selected neighbor indices\n */\n _select_heuristic(q, candidates, M, l_c, extend_candidates = true, keep_pruned_connections = true) {\n if (l_c > this._L) {\n return candidates.map((c) => c.index);\n }\n\n const metric = this._metric;\n const layer = this._graph.get(l_c);\n const elements = this._elements;\n\n // Extend candidate set with neighbors of candidates\n const W_set = new Set(candidates.map((c) => c.index));\n if (extend_candidates) {\n for (const c of candidates) {\n const edges = layer?.edges.get(c.index);\n if (edges) {\n for (const neighbor_idx of edges) {\n W_set.add(neighbor_idx);\n }\n }\n }\n }\n\n // Create extended candidates with distances\n const W = [...W_set]\n .map((idx) => ({\n element: elements[idx],\n index: idx,\n distance: metric(elements[idx], q),\n }))\n .sort((a, b) => a.distance - b.distance);\n\n const R = [];\n const W_discarded = [];\n\n // Select neighbors: prefer points closer to query than to already selected points\n for (const e of W) {\n if (R.length >= M) break;\n\n let should_add = true;\n\n // Check if e is closer to query than to any already selected point\n for (const r of R) {\n const dist_er = metric(e.element, r.element);\n if (dist_er < e.distance) {\n should_add = false;\n break;\n }\n }\n\n if (should_add) {\n R.push(e);\n } else {\n W_discarded.push(e);\n }\n }\n\n // Add discarded connections if we need more\n if (keep_pruned_connections && R.length < M) {\n for (const e of W_discarded) {\n if (R.length >= M) break;\n R.push(e);\n }\n }\n\n return R.map((c) => c.index);\n }\n\n /**\n * Select neighbors using simple distance-based selection.\n *\n * Simply returns the M closest candidates to the query.\n *\n * @private\n * @param {T} q - Query element\n * @param {Candidate[]} C - Candidate elements with distances\n * @param {number} M - Maximum number of neighbors to return\n * @returns {number[]} M nearest candidate indices\n */\n _select_simple(q, C, M) {\n if (C.length <= M) return C.map((c) => c.index);\n\n // Candidates already have distance computed, use it directly\n return C.slice()\n .sort((a, b) => a.distance - b.distance)\n .slice(0, M)\n .map((c) => c.index);\n }\n\n /**\n * Search a single layer for nearest neighbors.\n *\n * Implements the greedy search algorithm: start from entry points,\n * always expand the closest unvisited candidate, maintain a list\n * of the ef closest found neighbors.\n *\n * @private\n * @param {T} q - Query element\n * @param {number[] | null} ep_indices - Entry point indices\n * @param {number} ef - Number of nearest neighbors to find\n * @param {number} l_c - Layer number to search\n * @returns {Candidate[]} ef nearest neighbors found with their distances\n */\n _search_layer(q, ep_indices, ef, l_c) {\n const metric = this._metric;\n const layer = this._graph.get(l_c);\n const elements = this._elements;\n\n if (!layer || layer.edges.size === 0 || !ep_indices || ep_indices.length === 0) {\n return [];\n }\n\n // Filter out invalid indices\n const valid_ep_indices = ep_indices.filter((idx) => elements[idx] !== undefined);\n if (valid_ep_indices.length === 0) {\n return [];\n }\n\n // Visited set to avoid cycles\n const visited = new Set(valid_ep_indices);\n\n // Candidate set (min-heap): closest unvisited candidates to expand\n const C = new Heap(\n valid_ep_indices.map((idx) => ({\n element: elements[idx],\n index: idx,\n distance: metric(elements[idx], q),\n })),\n (item) => item.distance,\n \"min\",\n );\n\n // Result set (max-heap): ef closest found neighbors\n const W = new Heap(\n valid_ep_indices.map((idx) => ({\n element: elements[idx],\n index: idx,\n distance: metric(elements[idx], q),\n })),\n (item) => item.distance,\n \"max\",\n );\n\n // Algorithm 2 stops when the distance from query to the next candidate is greater\n // than the distance to the furthest element in the result set W.\n while (!C.empty) {\n const c = C.pop();\n if (!c) break;\n const furthest_dist = W.first?.value ?? Infinity;\n\n // Stop if current candidate is farther than furthest result\n if (c.value > furthest_dist) {\n break;\n }\n\n const edges = layer.edges.get(c.element.index);\n if (!edges) continue;\n\n for (const neighbor_idx of edges) {\n if (!visited.has(neighbor_idx)) {\n const neighbor_element = elements[neighbor_idx];\n // Skip invalid elements or elements with different dimensions\n if (!neighbor_element || neighbor_element.length !== q.length) continue;\n\n // Skip self-connections\n if (neighbor_idx === c.element.index) continue;\n\n visited.add(neighbor_idx);\n const dist_e = metric(neighbor_element, q);\n\n const current_furthest = W.first?.value ?? Infinity;\n if (dist_e < current_furthest || W.length < ef) {\n C.push({\n element: neighbor_element,\n index: neighbor_idx,\n distance: dist_e,\n });\n W.push({\n element: neighbor_element,\n index: neighbor_idx,\n distance: dist_e,\n });\n\n if (W.length > ef) {\n W.pop();\n }\n }\n }\n }\n }\n\n // Return sorted results for consistent entry point selection\n return W.data().sort((a, b) => a.distance - b.distance);\n }\n\n /**\n * Searches for the K nearest neighbors to a query element in the HNSW graph.\n *\n * Performs a multi-layer search starting from the entry point and traversing\n * each layer as entry points for the next.\n *\n * @param {T} q - Query element\n * @param {number} K - Number of nearest neighbors to return\n * @returns {Candidate[]} K nearest neighbors with their distances\n */\n search(q, K) {\n // Validate K\n if (!Number.isInteger(K) || K <= 0) {\n throw new Error(\"HNSW: parameter 'K' must be a positive integer\");\n }\n\n // Validate query dimensions\n if (!q || (!Array.isArray(q) && !(q instanceof Float64Array))) {\n throw new Error(\"HNSW: query must be an array\");\n }\n\n const search_ef = this._ef;\n\n // Fallback to linear search if graph is not properly initialized\n if (this._L < 0 || !this._ep || this._elements.length === 0) {\n return this._linear_search(q, K);\n }\n\n let ep_indices = [...this._ep];\n\n // Search from top layer down to layer 1\n for (let l_c = this._L; l_c > 0; --l_c) {\n const result = this._search_layer(q, ep_indices, 1, l_c);\n if (result.length > 0) {\n ep_indices = [result[0].index];\n }\n }\n\n // Search layer 0 with ef candidates\n const result = this._search_layer(q, ep_indices, Math.max(search_ef, K), 0);\n\n // If graph search returns no results, fallback to linear search\n if (result.length === 0) {\n return this._linear_search(q, K);\n }\n\n // Return K closest\n return result.slice(0, K);\n }\n\n /**\n * Fallback linear search when graph search fails\n * @private\n * @param {T} q - Query element\n * @param {number} K - Number of nearest neighbors to return\n * @returns {Candidate[]}\n */\n _linear_search(q, K) {\n const metric = this._metric;\n const elements = this._elements;\n const N = elements.length;\n\n if (N === 0) return [];\n\n /** @type {Candidate[]} */\n const candidates = [];\n for (let i = 0; i < N; i++) {\n const element = elements[i];\n // Skip elements with different dimensions (can happen with inconsistent data)\n if (!element || element.length !== q.length) continue;\n\n candidates.push({\n element: element,\n index: i,\n distance: metric(q, element),\n });\n }\n\n candidates.sort((a, b) => a.distance - b.distance);\n return candidates.slice(0, K);\n }\n\n /**\n * Iterator for searching the HNSW graph layer by layer.\n *\n * Yields intermediate results at each layer for debugging or visualization.\n *\n * @param {T} q - Query element\n * @param {number} K - Number of nearest neighbors to return\n * @param {number?} [ef] - Size of dynamic candidate list\n * @yields {{layer: number, candidates: Candidate[]}}\n */\n *search_iter(q, K, ef = null) {\n const search_ef = ef ?? this._ef;\n\n if (this._L < 0 || !this._ep) {\n return;\n }\n\n let ep_indices = [...this._ep];\n\n // Yield entry points at top layer instead of query itself\n const top_layer = this._graph.get(this._L);\n if (top_layer && this._ep && this._ep.length > 0) {\n const entry_candidates = this._ep\n .filter((idx) => this._elements[idx] !== undefined)\n .map((idx) => ({\n element: this._elements[idx],\n index: idx,\n distance: this._metric(this._elements[idx], q),\n }));\n yield {\n layer: this._L,\n candidates: entry_candidates,\n };\n }\n\n for (let l_c = this._L; l_c > 0; --l_c) {\n const result = this._search_layer(q, ep_indices, 1, l_c);\n yield { layer: l_c, candidates: result };\n // Use closest candidate as entry point for next layer (following HNSW paper)\n ep_indices = result.length > 0 ? [result[0].index] : ep_indices;\n }\n\n const result = this._search_layer(q, ep_indices, Math.max(search_ef, K), 0);\n yield { layer: 0, candidates: result };\n }\n\n /**\n * Get the number of elements in the index.\n *\n * @returns {number} Number of elements\n */\n get size() {\n return this._elements?.length ?? 0;\n }\n\n /**\n * Get the number of layers in the graph.\n *\n * @returns {number} Number of layers\n */\n get num_layers() {\n return this._L + 1;\n }\n\n /**\n * Get an element by its index.\n *\n * @param {number} index - Element index\n * @returns {T} The element at the given index\n */\n get_element(index) {\n return this._elements[index];\n }\n\n /**\n * Search for nearest neighbors using an element index as the query.\n *\n * @param {number} i - Index of the query element\n * @param {number} [K=5] - Number of nearest neighbors to return\n * @returns {Candidate[]} K nearest neighbors\n */\n search_by_index(i, K = 5) {\n const elements = this._elements;\n if (i < 0 || i >= elements.length) return [];\n\n const element = elements[i];\n if (!element) return [];\n\n return this.search(element, K);\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersKDTree } from \"./index.js\" */\n\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} ElementWithIndex\n * @property {number} index\n * @property {T} element\n */\n\n/**\n * KD-Tree (K-dimensional Tree) for efficient nearest neighbor search.\n *\n * KD-Trees partition k-dimensional space by recursively splitting along coordinate axes.\n * At each level, the tree splits points based on the median of the coordinate with the largest spread.\n * This creates a balanced binary tree structure that enables efficient O(log n) search on average.\n *\n * Best suited for:\n * - Low to moderate dimensional data (d < 20-30)\n * - When exact nearest neighbors are needed\n * - When dimensionality is not too high\n *\n * Performance degrades in high dimensions (curse of dimensionality) where approximate\n * methods like HNSW or LSH become more effective.\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link https://en.wikipedia.org/wiki/K-d_tree}\n */\nexport class KDTree extends KNN {\n /**\n * Generates a KD-Tree with given `elements`.\n *\n * @param {T[]} elements - Elements which should be added to the KD-Tree\n * @param {ParametersKDTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}`\n */\n constructor(elements, parameters = { metric: euclidean, seed: 1212 }) {\n super(elements, Object.assign({ seed: 1212 }, parameters));\n /**\n * @private\n * @type {KDTreeNode | KDTreeLeaf | null}\n */\n this._root = this._construct(\n elements.map((element, index) => ({ index, element })),\n 0,\n );\n }\n\n /** @returns {Metric} */\n get _metric() {\n return this._parameters.metric;\n }\n\n /**\n * @private\n * @param {ElementWithIndex[]} elements\n * @param {number} depth - Current depth in the tree (determines splitting axis)\n * @returns {KDTreeNode | KDTreeLeaf | null} Root of KD-Tree.\n */\n _construct(elements, depth) {\n if (elements.length === 0) {\n return null;\n }\n\n if (elements.length === 1) {\n return new KDTreeLeaf(elements[0]);\n }\n\n const k = elements[0].element.length;\n const axis = depth % k;\n\n // Sort by the splitting axis and find median\n elements.sort((a, b) => a.element[axis] - b.element[axis]);\n const medianIndex = Math.floor(elements.length / 2);\n const medianPoint = elements[medianIndex];\n\n // Recursively build left and right subtrees\n const leftElements = elements.slice(0, medianIndex);\n const rightElements = elements.slice(medianIndex + 1);\n\n const left = this._construct(leftElements, depth + 1);\n const right = this._construct(rightElements, depth + 1);\n\n return new KDTreeNode(medianPoint, axis, left, right);\n }\n\n /**\n * @param {number} i\n * @param {number} k\n */\n search_by_index(i, k = 5) {\n return this.search(this._elements[i], k);\n }\n\n /**\n * @param {T} t - Query element.\n * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors.\n */\n search(t, k = 5) {\n /** @type {Heap<{ point: ElementWithIndex; distance: number }>} */\n const best = new Heap(null, (d) => d.distance, \"max\");\n\n this._search_recursive(t, k, this._root, best);\n\n // Convert heap to result array (closest first)\n /** @type {{ element: T; index: number; distance: number }[]} */\n const result = [];\n while (best.length > 0) {\n const item = /** @type {{ element: { point: ElementWithIndex; distance: number }; value: number }} */ (\n best.pop()\n );\n result.push({\n element: item.element.point.element,\n index: item.element.point.index,\n distance: item.value,\n });\n }\n return result.reverse();\n }\n\n /**\n * @private\n * @param {T} target - Query element.\n * @param {number} k - Number of nearest neighbors to return.\n * @param {KDTreeNode | KDTreeLeaf | null} node - Current node.\n * @param {Heap<{ point: ElementWithIndex; distance: number }>} best - Heap of k best found so far.\n */\n _search_recursive(target, k, node, best) {\n if (node === null) return;\n\n if (node instanceof KDTreeLeaf) {\n const dist = this._metric(target, node.point.element);\n if (best.length < k) {\n best.push({ point: node.point, distance: dist });\n } else if (dist < (best.first?.value ?? Infinity)) {\n best.pop();\n best.push({ point: node.point, distance: dist });\n }\n return;\n }\n\n // Node is an internal node\n const axis = node.axis;\n const point = node.point;\n const pointValue = point.element[axis];\n const targetValue = target[axis];\n\n // Determine which subtree to search first\n const firstSubtree = targetValue < pointValue ? node.left : node.right;\n const secondSubtree = targetValue < pointValue ? node.right : node.left;\n\n // Search the nearer subtree\n this._search_recursive(target, k, firstSubtree, best);\n\n // Check if we need to search the other subtree\n // The hyperplane could contain closer points\n const distToHyperplane = Math.abs(targetValue - pointValue);\n const currentMaxDist = best.first?.value ?? Infinity;\n\n // Calculate distance to current point\n const distToPoint = this._metric(target, point.element);\n if (best.length < k) {\n best.push({ point: point, distance: distToPoint });\n } else if (distToPoint < currentMaxDist) {\n best.pop();\n best.push({ point: point, distance: distToPoint });\n }\n\n // Check if we need to explore the other side of the hyperplane\n if (best.length < k || distToHyperplane < (best.first?.value ?? Infinity)) {\n this._search_recursive(target, k, secondSubtree, best);\n }\n }\n}\n\n/**\n * @private\n * @template {number[] | Float64Array} T\n */\nclass KDTreeNode {\n /**\n * @param {ElementWithIndex} point\n * @param {number} axis - The splitting axis\n * @param {KDTreeNode | KDTreeLeaf | null} left\n * @param {KDTreeNode | KDTreeLeaf | null} right\n */\n constructor(point, axis, left = null, right = null) {\n this.point = point;\n this.axis = axis;\n this.left = left;\n this.right = right;\n }\n}\n\n/**\n * @private\n * @template {number[] | Float64Array} T\n */\nclass KDTreeLeaf {\n /**\n * @param {ElementWithIndex} point\n */\n constructor(point) {\n this.point = point;\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersLSH } from \"./index.js\" */\n\n/**\n * Locality Sensitive Hashing (LSH) for approximate nearest neighbor search.\n *\n * LSH uses hash functions that map similar items to the same buckets with high probability.\n * This implementation uses Random Projection hashing (SimHash-style) which works well for\n * cosine similarity and Euclidean distance.\n *\n * Key concepts:\n * - Multiple hash tables increase recall probability\n * - Each hash function projects data onto random hyperplanes\n * - Points on the same side of hyperplanes are hashed together\n * - Combines results from all tables for better accuracy\n *\n * Best suited for:\n * - High-dimensional data where exact methods fail\n * - Approximate nearest neighbor needs\n * - Large datasets where linear scan is too slow\n * - When some false positives/negatives are acceptable\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link https://en.wikipedia.org/wiki/Locality-sensitive_hashing}\n */\nexport class LSH extends KNN {\n /**\n * Creates a new LSH index.\n *\n * @param {T[]} elements - Elements to index\n * @param {ParametersLSH} [parameters={}] - Configuration parameters\n */\n constructor(\n elements,\n parameters = {\n metric: euclidean,\n numHashTables: 10,\n numHashFunctions: 10,\n seed: 1212,\n },\n ) {\n // Handle empty initialization - use dummy element\n const hasElements = elements && elements.length > 0;\n const firstElement = /** @type {T} */ (hasElements ? elements[0] : new Float64Array([0]));\n\n super([firstElement], parameters);\n\n this._metric = this._parameters.metric ?? euclidean;\n this._numHashTables = this._parameters.numHashTables ?? 10;\n this._numHashFunctions = this._parameters.numHashFunctions ?? 10;\n this._seed = this._parameters.seed ?? 1212;\n this._randomizer = new Randomizer(this._seed);\n\n // Hash tables: array of Maps where key is hash bucket, value is array of element indices\n /** @type {Map[]} */\n this._hashTables = [];\n\n // Random projection vectors for each hash table and hash function\n /** @type {Float64Array[][]} */\n this._projections = [];\n\n // Random offsets for each hash table and hash function (for quantization)\n /** @type {number[][]} */\n this._offsets = [];\n\n // Store dimensionality for later\n /** @type {number} */\n this._dim = firstElement.length;\n\n // Initialize hash functions\n this._initializeHashFunctions();\n\n // Reset elements if we were initialized with dummy\n if (!hasElements) {\n /** @type {T[]} */\n this._elements = [];\n } else {\n // Clear and re-add elements properly\n /** @type {T[]} */\n this._elements = [];\n this._hashTables = [];\n this._projections = [];\n this._offsets = [];\n this._initializeHashFunctions();\n this.add(elements);\n }\n }\n\n /**\n * Initialize random projection vectors for all hash tables.\n * @private\n */\n _initializeHashFunctions() {\n const dim = this._elements[0]?.length ?? 0;\n\n for (let t = 0; t < this._numHashTables; t++) {\n const tableProjections = [];\n const tableOffsets = [];\n\n for (let h = 0; h < this._numHashFunctions; h++) {\n // Generate random projection vector (normalized)\n const projection = new Float64Array(dim);\n let norm = 0;\n for (let i = 0; i < dim; i++) {\n // Box-Muller transform for normal distribution\n const u1 = this._randomizer.random;\n const u2 = this._randomizer.random;\n const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);\n projection[i] = z;\n norm += z * z;\n }\n // Normalize\n norm = Math.sqrt(norm);\n for (let i = 0; i < dim; i++) {\n projection[i] /= norm;\n }\n\n tableProjections.push(projection);\n // Random offset for quantization buckets\n tableOffsets.push(this._randomizer.random);\n }\n\n this._projections.push(tableProjections);\n this._offsets.push(tableOffsets);\n this._hashTables.push(new Map());\n }\n }\n\n /**\n * Compute hash signature for an element using random projections.\n * @private\n * @param {T} element\n * @param {number} tableIndex\n * @returns {string} Hash signature\n */\n _computeHash(element, tableIndex) {\n const projections = this._projections[tableIndex];\n const offsets = this._offsets[tableIndex];\n const bits = [];\n\n for (let i = 0; i < this._numHashFunctions; i++) {\n // Compute dot product\n let dot = 0;\n const proj = projections[i];\n for (let j = 0; j < element.length; j++) {\n dot += element[j] * proj[j];\n }\n // Quantize with offset\n const bucket = Math.floor(dot + offsets[i]);\n bits.push(bucket);\n }\n\n return bits.join(\",\");\n }\n\n /**\n * Add elements to the LSH index.\n * @param {T[]} elements\n * @returns {this}\n */\n add(elements) {\n // Extend elements array\n const startIndex = this._elements.length;\n this._elements = this._elements.concat(elements);\n\n // Hash each new element and add to tables\n for (let i = 0; i < elements.length; i++) {\n const globalIndex = startIndex + i;\n const element = elements[i];\n\n for (let t = 0; t < this._numHashTables; t++) {\n const hash = this._computeHash(element, t);\n const table = this._hashTables[t];\n\n if (!table.has(hash)) {\n table.set(hash, []);\n }\n const bucket = table.get(hash);\n if (bucket) {\n bucket.push(globalIndex);\n }\n }\n }\n\n return this;\n }\n\n /**\n * Search for k approximate nearest neighbors.\n * @param {T} query\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search(query, k = 5) {\n const metric = this._metric;\n const elements = this._elements;\n\n if (elements.length === 0) return [];\n\n // Collect candidate indices from all hash tables\n const candidates = new Set();\n\n for (let t = 0; t < this._numHashTables; t++) {\n const hash = this._computeHash(query, t);\n const table = this._hashTables[t];\n const bucket = table.get(hash);\n\n if (bucket) {\n for (const idx of bucket) {\n if (idx !== undefined) {\n candidates.add(idx);\n }\n }\n }\n }\n\n // If insufficient candidates found, fall back to linear search\n if (candidates.size < k) {\n // Add more candidates from all buckets or entire dataset\n //const needed = k - candidates.size;\n\n // First, try to add from neighboring buckets (different hashes)\n for (let t = 0; t < this._numHashTables && candidates.size < k; t++) {\n const table = this._hashTables[t];\n for (const [, bucket] of table) {\n for (const idx of bucket) {\n if (idx !== undefined) {\n candidates.add(idx);\n if (candidates.size >= k) break;\n }\n }\n if (candidates.size >= k) break;\n }\n }\n\n // If still not enough, add from entire dataset\n for (let i = 0; i < elements.length && candidates.size < k; i++) {\n candidates.add(i);\n }\n }\n\n // Compute exact distances for candidates\n /** @type {Heap<{ index: number; distance: number }>} */\n const best = new Heap(null, (d) => d.distance, \"max\");\n\n for (const idx of candidates) {\n const element = elements[idx];\n if (!element || element.length !== query.length) continue;\n\n const dist = metric(query, element);\n\n if (best.length < k) {\n best.push({ index: idx, distance: dist });\n } else if (dist < (best.first?.value ?? Infinity)) {\n best.pop();\n best.push({ index: idx, distance: dist });\n }\n }\n\n // Convert to result format\n /** @type {{ element: T; index: number; distance: number }[]} */\n const result = [];\n while (best.length > 0) {\n const item = /** @type {{ element: { index: number; distance: number }; value: number }} */ (best.pop());\n result.push({\n element: elements[item.element.index],\n index: item.element.index,\n distance: item.value,\n });\n }\n\n return result.reverse();\n }\n\n /**\n * @param {number} i\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i, k = 5) {\n if (i < 0 || i >= this._elements.length) return [];\n return this.search(this._elements[i], k);\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { distance_matrix, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import { ParametersNaiveKNN } from \"./index.js\" */\n\n/**\n * Naive KNN implementation using a distance matrix.\n *\n * This implementation pre-computes the entire distance matrix and performs\n * an exhaustive search. Best suited for small datasets or when a distance\n * matrix is already available.\n *\n * @template {number[] | Float64Array} T\n * @category KNN\n * @class\n * @extends KNN\n */\nexport class NaiveKNN extends KNN {\n /**\n * Generates a KNN list with given `elements`.\n *\n * @param {T[]} elements - Elements which should be added to the KNN list\n * @param {ParametersNaiveKNN} parameters\n */\n constructor(elements, parameters = {}) {\n const params = Object.assign({ metric: euclidean, seed: 1212 }, parameters);\n super(elements, params);\n const N =\n this._elements instanceof Matrix ? /** @type {any} */ (this._elements).shape[0] : this._elements.length;\n if (this._parameters.metric === \"precomputed\") {\n this._D = Matrix.from(/** @type {number[][] | Float64Array[]} */ (/** @type {any} */ (this._elements)));\n } else {\n this._D = distance_matrix(\n /** @type {number[][] | Float64Array[]} */ (this._elements),\n this._parameters.metric,\n );\n }\n\n /** @type {Heap<{ value: number; index: number }>[]} */\n this.KNN = [];\n for (let row = 0; row < N; ++row) {\n const distances = this._D.row(row);\n /** @type {Heap<{ value: number; index: number }>} */\n const H = new Heap(null, (d) => d.value, \"min\");\n for (let j = 0; j < N; ++j) {\n H.push({\n value: distances[j],\n index: j,\n });\n }\n this.KNN.push(H);\n }\n }\n\n /**\n * @param {number} i\n * @param {number} k\n */\n search_by_index(i, k = 5) {\n if (this._parameters.metric === \"precomputed\") {\n const H = this.KNN[i];\n /** @type {{ element: T; index: number; distance: number }[]} */\n const result = [];\n const data = H.toArray(); // Get array representation\n const temp_heap = new Heap(data, (d) => d.value, \"min\");\n const N =\n this._elements instanceof Matrix ? /** @type {any} */ (this._elements).shape[0] : this._elements.length;\n for (let j = 0; j < Math.min(k, N); ++j) {\n const node = temp_heap.pop();\n if (!node) break;\n result.push({\n element: /** @type {T} */ (\n this._elements instanceof Matrix\n ? /** @type {any} */ (this._elements).row(node.element.index)\n : this._elements[node.element.index]\n ),\n index: /** @type {number} */ (node.element.index),\n distance: /** @type {number} */ (node.value),\n });\n }\n return result;\n }\n return this.search(\n /** @type {T} */ (\n this._elements instanceof Matrix ? /** @type {any} */ (this._elements).row(i) : this._elements[i]\n ),\n k,\n );\n }\n\n /**\n * @param {T} t - Query element.\n * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors.\n */\n search(t, k = 5) {\n if (this._parameters.metric === \"precomputed\") {\n throw new Error(\"Search by query element is only possible when not using a precomputed distance matrix!\");\n }\n /** @type {import(\"../metrics/index.js\").Metric} */\n const metric = /** @type {any} */ (this._parameters.metric);\n\n const isMatrix = this._elements instanceof Matrix;\n const elementsAny = /** @type {any} */ (this._elements);\n const N = isMatrix ? elementsAny.shape[0] : this._elements.length;\n\n // Compute distances from query to ALL points\n const distances = [];\n for (let i = 0; i < N; i++) {\n const element = /** @type {T} */ (isMatrix ? elementsAny.row(i) : this._elements[i]);\n distances.push({\n element: element,\n index: i,\n distance: metric(t, element),\n });\n }\n\n // Sort by distance and return k nearest\n distances.sort((a, b) => a.distance - b.distance);\n return distances.slice(0, k);\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import {ParametersNNDescent} from \"./index.js\" */\n/**\n *\n * @template {number[] | Float64Array} T\n * @typedef {Object} NNDescentElement\n * @property {T} value\n * @property {number} index\n * @property {boolean} flag\n */\n\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} NNDescentNeighbor\n * @property {T} value\n * @property {number} index\n * @property {number} distance\n * @property {boolean} [flag]\n */\n\n/**\n * NN-Descent\n *\n * An efficient graph-based approximate nearest neighbor search algorithm.\n * It works by iteratively improving a neighbor graph using the fact that\n * \"neighbors of neighbors are likely to be neighbors\".\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf|NN-Descent Paper}\n */\nexport class NNDescent extends KNN {\n /**\n * @private\n * @type {KNNHeap[]}\n */\n _B = [];\n /**\n * @private\n * @type {NNDescentNeighbor[][]}\n */\n nn = [];\n\n /**\n * @param {T[]} elements - Called V in paper.\n * @param {Partial} parameters\n * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf}\n */\n constructor(elements, parameters = {}) {\n super(\n elements,\n /** @type {ParametersNNDescent} */ (\n Object.assign({ metric: euclidean, K: 10, rho: 1, delta: 1e-3, seed: 1212 }, parameters)\n ),\n );\n this._N = elements.length;\n this._randomizer = new Randomizer(this._parameters.seed);\n this._sample_size = this._parameters.samples * this._parameters.rho;\n\n this._nndescent_elements = elements.map((e, i) => {\n return {\n value: e,\n index: i,\n flag: true,\n };\n });\n\n if (elements) {\n this.add(elements);\n }\n }\n\n /**\n * Samples Array A with sample size.\n *\n * @private\n * @template U\n * @param {U[]} A\n * @returns {U[]}\n */\n _sample(A) {\n const n = A.length;\n const sample_size = this._sample_size;\n if (sample_size > n) {\n return A;\n } else {\n const randomizer = this._randomizer;\n return randomizer.choice(A, sample_size);\n }\n }\n\n /**\n * @private\n * @param {KNNHeap} B\n * @param {NNDescentNeighbor} u\n * @returns {number}\n */\n _update(B, u) {\n if (B.set.has(u.index)) return 0;\n\n const worst = B.first;\n if (worst && B.length >= this._parameters.samples) {\n const dist = B._accessor(u);\n const worst_dist = B._accessor(worst.element);\n if (dist >= worst_dist) {\n return 0; // u is worse than the worst neighbor\n }\n }\n\n B.push(u);\n u.flag = true;\n if (B.length > this._parameters.samples) {\n B.pop();\n }\n return 1;\n }\n\n /**\n * @private\n * @param {(KNNHeap | null)[]} B\n * @returns {NNDescentNeighbor[][]}\n */\n _reverse(B) {\n const N = this._N;\n const R = new Array(N);\n for (let i = 0; i < N; i++) {\n R[i] = [];\n }\n for (let j = 0; j < N; j++) {\n const Bi = B[j];\n if (Bi) {\n const Bjdata = Bi.data();\n for (const neighbor of Bjdata) {\n const v = neighbor.index;\n R[v].push(neighbor);\n }\n }\n }\n return R;\n }\n\n /**\n * @param {T[]} elements\n * @returns {this}\n */\n add(elements) {\n const randomizer = this._randomizer;\n const metric = this._parameters.metric;\n const K = this._parameters.samples;\n const delta = this._parameters.delta;\n const N = elements.length;\n this._N = N;\n /** @type {KNNHeap[]} */\n const B = [];\n this._B = B;\n for (let i = 0; i < N; i++) {\n const e = elements[i];\n const sample = randomizer\n .choice(\n elements.map((el, idx) => ({ el, idx })),\n K,\n )\n .map((d) => {\n return { index: d.idx, distance: metric(d.el, e), value: d.el };\n });\n const Bi = new KNNHeap(sample, (d) => d.distance, \"max\");\n B.push(Bi);\n }\n\n let c = Infinity;\n let old_c = -Infinity;\n while (c > delta * N * K && c !== old_c) {\n const old_ = new Array(N);\n const new_ = new Array(N);\n for (let i = 0; i < N; i++) {\n const Bi = B[i].data();\n const falseBs = Bi.filter((d) => !d.flag);\n const trueBs = this._sample(Bi.filter((d) => d.flag));\n for (const d of trueBs) {\n d.flag = false;\n }\n old_[i] = new KNNHeap(falseBs, (d) => d.distance, \"max\");\n new_[i] = new KNNHeap(trueBs, (d) => d.distance, \"max\");\n }\n const old_reverse = this._reverse(old_);\n const new_reverse = this._reverse(new_);\n old_c = c;\n c = 0;\n for (let i = 0; i < N; i++) {\n for (const o of this._sample(old_reverse[i])) {\n old_[i].push(o);\n }\n for (const n of this._sample(new_reverse[i])) {\n new_[i].push(n);\n }\n\n const new_i = new_[i].data();\n const old_i = old_[i].data();\n const n1 = new_i.length;\n const n2 = old_i.length;\n for (let j = 0; j < n1; j++) {\n const u1 = new_i[j];\n const Bu1 = B[u1.index];\n for (let k = 0; k < n1; k++) {\n const u2 = new_i[k];\n if (u1.index === u2.index) continue;\n const Bu2 = B[u2.index];\n c += this._update(Bu2, u1);\n c += this._update(Bu1, u2);\n }\n for (let k = 0; k < n2; k++) {\n const u2 = old_i[k];\n if (u1.index === u2.index) continue;\n const Bu2 = B[u2.index];\n c += this._update(Bu2, u1);\n c += this._update(Bu1, u2);\n }\n }\n }\n }\n this.nn = this._B.map((heap) => heap.data());\n return this;\n }\n\n /**\n * @param {T} x\n * @param {number} [k=5] Default is `5`\n * @returns {{ element: T, index: number; distance: number }[]}\n */\n search(x, k = 5) {\n const metric = this._parameters.metric;\n const N = this._N;\n const elements = this._elements;\n\n if (N === 0) return [];\n const xLength = x.length;\n\n // Initialize candidate pool\n const visited = new Set();\n /** @type {{index: number, dist: number, evaluated: boolean}[]} */\n let pool = [];\n\n // Randomly pick initial candidates\n const randomizer = this._randomizer;\n for (let i = 0; i < Math.min(N, Math.max(k * 10, 50)); i++) {\n let rnd;\n do {\n rnd = randomizer.random_int % N;\n } while (visited.has(rnd));\n visited.add(rnd);\n\n const element = elements[rnd];\n if (!element || element.length !== xLength) continue;\n\n pool.push({\n index: rnd,\n dist: metric(x, element),\n evaluated: false,\n });\n }\n\n let searching = true;\n while (searching) {\n pool.sort((a, b) => a.dist - b.dist);\n // keep the top subset for exploration\n pool = pool.slice(0, Math.max(k * 5, 50));\n\n searching = false;\n for (let i = 0; i < pool.length; i++) {\n const candidate = pool[i];\n if (candidate.evaluated) continue;\n\n candidate.evaluated = true;\n searching = true;\n\n // get neighbors of this candidate from graph\n const neighbors = this.nn[candidate.index];\n if (!neighbors) continue;\n\n for (const neighbor of neighbors) {\n const n_idx = neighbor.index;\n if (!visited.has(n_idx)) {\n visited.add(n_idx);\n const element = elements[n_idx];\n if (element && element.length === xLength) {\n pool.push({\n index: n_idx,\n dist: metric(x, element),\n evaluated: false,\n });\n }\n }\n }\n // Don't break here! Look at more candidates per iteration for better convergence\n // break;\n }\n }\n\n pool.sort((a, b) => a.dist - b.dist);\n\n /** @type {{ element: T, index: number; distance: number }[]} */\n const result = [];\n for (let i = 0; i < Math.min(k, pool.length); i++) {\n const item = pool[i];\n result.push({\n element: elements[item.index],\n index: item.index,\n distance: item.dist,\n });\n }\n return result;\n }\n\n /**\n * @param {number} i\n * @param {number} [k=5] Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i, k = 5) {\n // Use regular search with the element at index i\n const elements = this._elements;\n if (i < 0 || i >= elements.length) return [];\n\n const element = elements[i];\n if (!element) return [];\n\n return this.search(element, k);\n }\n}\n\n/**\n * @template {number[] | Float64Array} U\n * @typedef {Object} HeapEntry\n * @property {NNDescentNeighbor} element\n * @property {number} value\n */\n\n/**\n * @template {number[] | Float64Array} U\n * @extends {Heap>}\n */\nclass KNNHeap extends Heap {\n /** @type {Set} */\n set;\n\n /**\n * @param {NNDescentNeighbor[]} elements\n * @param {(d: NNDescentNeighbor) => number} accessor\n * @param {\"max\" | \"min\"} comparator\n */\n constructor(elements, accessor, comparator) {\n super(null, accessor, comparator);\n this.set = new Set();\n if (elements) {\n for (const element of elements) {\n this.push(element);\n }\n }\n }\n\n /**\n * @param {NNDescentNeighbor} element\n * @returns {KNNHeap}\n */\n push(element) {\n const set = this.set;\n if (set.has(element.index)) {\n return this;\n } else {\n set.add(element.index);\n super.push(element);\n return this;\n }\n }\n\n /** @returns {{ element: NNDescentNeighbor; value: number } | null} */\n pop() {\n const result = super.pop();\n if (result?.element) {\n this.set.delete(result.element.index);\n return result;\n }\n return null;\n }\n\n /** @returns {NNDescentNeighbor[]} */\n data() {\n return this._container.map((d) => d.element);\n }\n}\n","import { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersPCA} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n\n/**\n * Principal Component Analysis (PCA)\n *\n * A linear dimensionality reduction technique that identifies the axes (principal components)\n * along which the variance of the data is maximized.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link MDS} for another linear alternative\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2], [3, 4], [5, 6]];\n * const pca = new druid.PCA(X, { d: 2 });\n * const Y = pca.transform();\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class PCA extends DR {\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X, parameters = {}) {\n super(X, { d: 2, seed: 1212, eig_args: {} }, parameters);\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n if (!Object.hasOwn(eig_args, \"seed\")) {\n eig_args.seed = this._randomizer;\n }\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T} - The projected data.\n */\n transform() {\n const V = this.principal_components();\n const X = this.X;\n this.Y = X.dot(V);\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new PCA(X, parameters);\n return dr.transform();\n }\n\n /**\n * Computes the `d` principal components of Matrix `X`.\n *\n * @returns {Matrix}\n */\n principal_components() {\n if (this.V) {\n return this.V;\n }\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n const X = this.X;\n const X_cent = X.sub(X.meanCols());\n const C = X_cent.transDot(X_cent);\n const { eigenvectors: V } = simultaneous_poweriteration(C, d, eig_args);\n this.V = Matrix.from(V).transpose();\n return this.V;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Matrix}\n */\n static principal_components(X, parameters) {\n const dr = new PCA(X, parameters);\n return dr.principal_components();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new PCA(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new PCA(X, parameters);\n return dr.transform_async();\n }\n}\n","import { BallTree } from \"../knn/index.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { euclidean, euclidean_squared } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\nimport { PCA } from \"./PCA.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersPaCMAP} from \"./index.js\" */\n\n/**\n * Pairwise Controlled Manifold Approximation Projection (PaCMAP)\n *\n * A dimensionality reduction technique that uses three types of point pairs —\n * nearest neighbor (NN), mid-near (MN), and further (FP) pairs — with a\n * dynamic three-phase weight schedule and Adam optimization to preserve both\n * local and global structure.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link https://arxiv.org/abs/2012.04456|PaCMAP Paper}\n * @see {@link https://github.com/YingfanWang/PaCMAP|PaCMAP GitHub}\n * @see {@link UMAP} for a related graph-based technique\n * @see {@link LocalMAP} for the local-refinement variant\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];\n * const pacmap = new druid.PaCMAP(X, {\n * n_neighbors: 10,\n * MN_ratio: 0.5,\n * FP_ratio: 2.0,\n * seed: 42\n * });\n *\n * const Y = pacmap.transform(); // 450 iterations (default)\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class PaCMAP extends DR {\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X, parameters) {\n super(\n X,\n {\n n_neighbors: 10,\n MN_ratio: 0.5,\n FP_ratio: 2.0,\n d: 2,\n metric: euclidean,\n lr: 1.0,\n num_iters: [100, 100, 250],\n seed: 1212,\n },\n parameters,\n );\n [this._N, this._D] = this.X.shape;\n const n_neighbors = /** @type {number} */ (this.parameter(\"n_neighbors\"));\n if (n_neighbors >= this._N) {\n throw new Error(\n `Parameter n_neighbors (=${n_neighbors}) needs to be smaller than dataset size (N=${this._N})!`,\n );\n }\n this._iter = 0;\n }\n\n /**\n * Samples mid-near pairs for each point.\n * For each point i, repeats n_MN times: samples 6 random non-neighbor\n * candidates, picks the 2nd closest by high-dim distance.\n *\n * @protected\n * @param {Set[]} nn_sets - Array of neighbor index sets per point\n * @param {number} n_MN - Number of mid-near pairs per point\n * @returns {Int32Array} Flat array of [i, j] pairs\n */\n _sample_mn_pairs(nn_sets, n_MN) {\n const N = this._N;\n const X = this.X;\n const randomizer = this._randomizer;\n const pairs = new Int32Array(N * n_MN * 2);\n let idx = 0;\n\n for (let i = 0; i < N; ++i) {\n const nn_set = nn_sets[i];\n const x_i = X.row(i);\n\n for (let k = 0; k < n_MN; ++k) {\n // Sample 6 random non-neighbor candidates\n /** @type {{idx: number, dist: number}[]} */\n const candidates = [];\n let attempts = 0;\n while (candidates.length < 6 && attempts < N * 2) {\n const j = randomizer.random_int % N;\n attempts++;\n if (j !== i && !nn_set.has(j)) {\n candidates.push({ idx: j, dist: euclidean_squared(x_i, X.row(j)) });\n }\n }\n if (candidates.length < 2) {\n // Fallback: use any available non-self point\n const j = (i + 1) % N;\n pairs[idx++] = i;\n pairs[idx++] = j;\n continue;\n }\n candidates.sort((a, b) => a.dist - b.dist);\n // Pick the 2nd closest (index 1)\n pairs[idx++] = i;\n pairs[idx++] = candidates[1].idx;\n }\n }\n return pairs.slice(0, idx);\n }\n\n /**\n * Samples further pairs for each point (random non-neighbors).\n *\n * @protected\n * @param {Set[]} nn_sets - Array of neighbor index sets per point\n * @param {number} n_FP - Number of further pairs per point\n * @returns {Int32Array} Flat array of [i, j] pairs\n */\n _sample_fp_pairs(nn_sets, n_FP) {\n const N = this._N;\n const randomizer = this._randomizer;\n const pairs = new Int32Array(N * n_FP * 2);\n let idx = 0;\n\n for (let i = 0; i < N; ++i) {\n const nn_set = nn_sets[i];\n let count = 0;\n let attempts = 0;\n while (count < n_FP && attempts < N * 3) {\n const j = randomizer.random_int % N;\n attempts++;\n if (j !== i && !nn_set.has(j)) {\n pairs[idx++] = i;\n pairs[idx++] = j;\n count++;\n }\n }\n }\n return pairs.slice(0, idx);\n }\n\n /**\n * Computes gradient coefficients and updates the gradient matrix for one pair type.\n *\n * @protected\n * @param {Float64Array} grad_flat - Flat N×d gradient accumulator (modified in place)\n * @param {Int32Array} pairs - Flat [i, j, i, j, ...] pair array\n * @param {number} w - Weight for this pair type\n * @param {number} attr_num - Numerator constant for attractive (10 for NN, 10000 for MN); 0 for repulsive\n * @param {boolean} repulsive - Whether this is a repulsive pair type\n */\n _accumulate_gradients(grad_flat, pairs, w, attr_num, repulsive) {\n if (w === 0) return;\n const Y = this.Y;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const n_pairs = pairs.length / 2;\n\n for (let p = 0; p < n_pairs; ++p) {\n const i = pairs[p * 2];\n const j = pairs[p * 2 + 1];\n const y_i = Y.row(i);\n const y_j = Y.row(j);\n\n // d_ij = 1 + ||y_i - y_j||²\n let sq_dist = 0;\n for (let k = 0; k < d; ++k) {\n const diff = y_i[k] - y_j[k];\n sq_dist += diff * diff;\n }\n const d_ij = 1 + sq_dist;\n\n /** @type {number} */\n let coeff;\n if (repulsive) {\n // FP loss: 1/(1+d_ij), gradient: -2/(1+d_ij)²\n coeff = (-w * 2) / (d_ij * d_ij);\n } else {\n // NN loss: d_ij/(attr_num+d_ij), gradient: 2*attr_num/(attr_num+d_ij)²\n const denom = attr_num + d_ij;\n coeff = (w * 2 * attr_num) / (denom * denom);\n }\n\n const base_i = i * d;\n const base_j = j * d;\n for (let k = 0; k < d; ++k) {\n const diff = y_i[k] - y_j[k];\n const g = coeff * diff;\n grad_flat[base_i + k] += g;\n grad_flat[base_j + k] -= g;\n }\n }\n }\n\n /**\n * Returns the weight schedule for the current iteration.\n *\n * @protected\n * @param {number} iter - Current iteration (0-indexed)\n * @returns {{ w_nn: number; w_mn: number; w_fp: number }}\n */\n _get_weights(iter) {\n const num_iters = /** @type {number[]} */ (this.parameter(\"num_iters\"));\n const [p1, p2] = num_iters;\n if (iter < p1) {\n // Phase 1: MN weight linearly decays from 1000 to 3\n const t = iter / p1;\n return { w_nn: 2.0, w_mn: 1000.0 * (1 - t) + 3.0 * t, w_fp: 1.0 };\n } else if (iter < p1 + p2) {\n // Phase 2: fixed weights\n return { w_nn: 3.0, w_mn: 3.0, w_fp: 1.0 };\n } else {\n // Phase 3: MN disabled\n return { w_nn: 1.0, w_mn: 0.0, w_fp: 1.0 };\n }\n }\n\n /**\n * Applies Adam optimizer update to Y using accumulated gradients.\n *\n * @protected\n * @param {Float64Array} grad_flat - Flat N×d gradient\n */\n _adam_update(grad_flat) {\n const lr = /** @type {number} */ (this.parameter(\"lr\"));\n const N = this._N;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const beta1 = 0.9;\n const beta2 = 0.999;\n const eps = 1e-7;\n this._adam_t = (this._adam_t ?? 0) + 1;\n const t = /** @type {number} */ (this._adam_t);\n const bc1 = 1 - beta1 ** t;\n const bc2 = 1 - beta2 ** t;\n const Y = this.Y;\n const m = /** @type {Float64Array} */ (this._adam_m);\n const v = /** @type {Float64Array} */ (this._adam_v);\n\n for (let i = 0; i < N; ++i) {\n const base = i * d;\n const y_i = Y.row(i);\n for (let k = 0; k < d; ++k) {\n const g = grad_flat[base + k];\n m[base + k] = beta1 * m[base + k] + (1 - beta1) * g;\n v[base + k] = beta2 * v[base + k] + (1 - beta2) * g * g;\n const m_hat = m[base + k] / bc1;\n const v_hat = v[base + k] / bc2;\n y_i[k] -= lr * (m_hat / (Math.sqrt(v_hat) + eps));\n }\n }\n }\n\n /**\n * Initializes PaCMAP: PCA embedding, KNN pairs, MN pairs, FP pairs, Adam state.\n *\n * @returns {PaCMAP}\n */\n init() {\n const X = this.X;\n const N = this._N;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const seed = /** @type {number} */ (this.parameter(\"seed\"));\n const metric = /** @type {Metric} */ (this.parameter(\"metric\"));\n const n_neighbors = /** @type {number} */ (this.parameter(\"n_neighbors\"));\n const MN_ratio = /** @type {number} */ (this.parameter(\"MN_ratio\"));\n const FP_ratio = /** @type {number} */ (this.parameter(\"FP_ratio\"));\n\n // 1. PCA initialization scaled by 0.01 (X is always Matrix here)\n const pca_init = /** @type {Matrix} */ (PCA.transform(X, { d, seed }));\n this.Y = new Matrix(N, d, (i, j) => pca_init.entry(i, j) * 0.01);\n\n // 2. Build KNN graph for NN pairs\n const knn = new BallTree(X.to2dArray(), { metric, seed });\n const n_MN = Math.max(1, Math.round(n_neighbors * MN_ratio));\n const n_FP = Math.max(1, Math.round(n_neighbors * FP_ratio));\n\n /** @type {Int32Array[]} */\n const nn_indices = [];\n /** @type {Set[]} */\n const nn_sets = [];\n // NN pairs: flat [i, j] pairs\n const nn_pairs = new Int32Array(N * n_neighbors * 2);\n let nn_idx = 0;\n\n for (let i = 0; i < N; ++i) {\n const neighbors = knn.search(X.row(i), n_neighbors + 1);\n /** @type {number[]} */\n const idxs = [];\n for (const nb of neighbors) {\n if (nb.index !== i) idxs.push(nb.index);\n if (idxs.length >= n_neighbors) break;\n }\n nn_indices[i] = new Int32Array(idxs);\n nn_sets[i] = new Set(idxs);\n for (const j of idxs) {\n nn_pairs[nn_idx++] = i;\n nn_pairs[nn_idx++] = j;\n }\n }\n this._nn_pairs = nn_pairs.slice(0, nn_idx);\n\n // 3. MN pairs (mid-near sampling)\n this._mn_pairs = this._sample_mn_pairs(nn_sets, n_MN);\n\n // 4. FP pairs (random non-neighbors)\n this._fp_pairs = this._sample_fp_pairs(nn_sets, n_FP);\n\n // 5. Adam optimizer state\n this._adam_m = new Float64Array(N * d);\n this._adam_v = new Float64Array(N * d);\n this._adam_t = 0;\n\n this._iter = 0;\n return this;\n }\n\n /**\n * Performs one optimization step.\n *\n * @returns {Matrix}\n */\n next() {\n if (!this._nn_pairs) throw new Error(\"Call init() first!\");\n const N = this._N;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const { w_nn, w_mn, w_fp } = this._get_weights(this._iter);\n\n const grad_flat = new Float64Array(N * d);\n this._accumulate_gradients(grad_flat, /** @type {Int32Array} */ (this._nn_pairs), w_nn, 10, false);\n this._accumulate_gradients(grad_flat, /** @type {Int32Array} */ (this._mn_pairs), w_mn, 10000, false);\n this._accumulate_gradients(grad_flat, /** @type {Int32Array} */ (this._fp_pairs), w_fp, 0, true);\n this._adam_update(grad_flat);\n\n this._iter++;\n return this.Y;\n }\n\n /**\n * @param {number} [iterations] - Total number of iterations. Defaults to sum of `num_iters`.\n * @returns {T}\n */\n transform(iterations) {\n const num_iters = /** @type {number[]} */ (this.parameter(\"num_iters\"));\n const total = iterations ?? num_iters.reduce((a, b) => a + b, 0);\n this.check_init();\n for (let i = 0; i < total; ++i) {\n this.next();\n }\n return this.projection;\n }\n\n /**\n * @param {number} [iterations] - Total number of iterations. Defaults to sum of `num_iters`.\n * @returns {Generator}\n */\n *generator(iterations) {\n const num_iters = /** @type {number[]} */ (this.parameter(\"num_iters\"));\n const total = iterations ?? num_iters.reduce((a, b) => a + b, 0);\n this.check_init();\n for (let i = 0; i < total; ++i) {\n this.next();\n yield this.projection;\n }\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new PaCMAP(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new PaCMAP(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new PaCMAP(X, parameters);\n return dr.transform_async();\n }\n}\n","import { BallTree } from \"../knn/index.js\";\nimport { euclidean_squared } from \"../metrics/index.js\";\nimport { PaCMAP } from \"./PaCMAP.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLocalMAP} from \"./index.js\" */\n\n/**\n * LocalMAP\n *\n * A variant of PaCMAP that improves local cluster separation by dynamically\n * resampling further pairs (FP) in phase 3 using nearby points in the current\n * low-dimensional embedding space, rather than randomly sampled non-neighbors.\n *\n * @class\n * @template {InputType} T\n * @extends PaCMAP\n * @category Dimensionality Reduction\n * @see {@link https://arxiv.org/abs/2012.04456|PaCMAP Paper}\n * @see {@link PaCMAP} for the base algorithm\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];\n * const localmap = new druid.LocalMAP(X, {\n * n_neighbors: 10,\n * low_dist_thres: 10,\n * seed: 42\n * });\n *\n * const Y = localmap.transform(); // 450 iterations (default)\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class LocalMAP extends PaCMAP {\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X, parameters = {}) {\n // Merge low_dist_thres into parameters before the seal in DR constructor.\n // DR.constructor does Object.seal({ ...defaults, ...parameters }), so\n // passing low_dist_thres here ensures it lands in the sealed object.\n super(X, { low_dist_thres: 10, ...parameters });\n }\n\n /**\n * Performs one optimization step.\n * In phase 3, resamples FP pairs from the current embedding space\n * and applies distance-based weight scaling.\n *\n * @returns {import(\"../matrix/index.js\").Matrix}\n */\n next() {\n if (!this._nn_pairs) throw new Error(\"Call init() first!\");\n const num_iters = /** @type {number[]} */ (this.parameter(\"num_iters\"));\n const phase3_start = num_iters[0] + num_iters[1];\n\n if (this._iter < phase3_start) {\n // Phases 1 and 2: identical to PaCMAP\n return super.next();\n }\n\n // Phase 3: resample FP pairs from embedding neighbors\n const N = this._N;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const low_dist_thres = /** @type {number} */ (this._low_dist_thres ?? 10);\n const low_dist_thres_sq = low_dist_thres * low_dist_thres;\n const { w_nn, w_mn, w_fp } = this._get_weights(this._iter);\n const Y = this.Y;\n\n // Build a KNN structure on the current embedding to find nearby pairs\n const y_array = Y.to2dArray();\n const seed = /** @type {number} */ (this.parameter(\"seed\"));\n const emb_knn = new BallTree(y_array, { metric: euclidean_squared, seed });\n const n_FP = /** @type {number} */ (this.parameter(\"FP_ratio\")) *\n /** @type {number} */ (this.parameter(\"n_neighbors\"));\n const n_FP_int = Math.max(1, Math.round(n_FP));\n\n // Build local FP pairs by finding nearby embedding neighbors\n // (these are not NN neighbors in high-dim space but nearby in low-dim)\n const nn_sets = this._nn_sets_cache;\n /** @type {Int32Array} */\n let local_fp_pairs;\n\n if (nn_sets) {\n const pair_buf = new Int32Array(N * n_FP_int * 2);\n let idx = 0;\n for (let i = 0; i < N; ++i) {\n const nn_set = nn_sets[i];\n // Search for nearby points in embedding space\n const neighbors = emb_knn.search(y_array[i], Math.min(n_FP_int * 3 + 1, N));\n let count = 0;\n for (const nb of neighbors) {\n if (nb.index === i || (nn_set && nn_set.has(nb.index))) continue;\n pair_buf[idx++] = i;\n pair_buf[idx++] = nb.index;\n count++;\n if (count >= n_FP_int) break;\n }\n }\n local_fp_pairs = pair_buf.slice(0, idx);\n } else {\n local_fp_pairs = /** @type {Int32Array} */ (this._fp_pairs);\n }\n\n // Accumulate gradients with local weight scaling for FP pairs\n const grad_flat = new Float64Array(N * d);\n this._accumulate_gradients(grad_flat, /** @type {Int32Array} */ (this._nn_pairs), w_nn, 10, false);\n this._accumulate_gradients(grad_flat, /** @type {Int32Array} */ (this._mn_pairs), w_mn, 10000, false);\n\n // FP pairs with local distance-based weight scaling\n this._accumulate_gradients_local_fp(\n grad_flat,\n local_fp_pairs,\n w_fp,\n low_dist_thres,\n low_dist_thres_sq,\n );\n\n this._adam_update(grad_flat);\n this._iter++;\n return this.Y;\n }\n\n /**\n * Accumulates FP gradients with LocalMAP's distance-based weight scaling.\n * For pairs within low_dist_thres, scales w_fp by low_dist_thres / (2 * sqrt(d_ij)).\n *\n * @private\n * @param {Float64Array} grad_flat - Flat N×d gradient accumulator (modified in place)\n * @param {Int32Array} pairs - Flat [i, j, i, j, ...] pair array\n * @param {number} w_fp - Base FP weight\n * @param {number} low_dist_thres - Distance threshold\n * @param {number} low_dist_thres_sq - Squared distance threshold\n */\n _accumulate_gradients_local_fp(grad_flat, pairs, w_fp, low_dist_thres, low_dist_thres_sq) {\n if (w_fp === 0) return;\n const Y = this.Y;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const n_pairs = pairs.length / 2;\n\n for (let p = 0; p < n_pairs; ++p) {\n const i = pairs[p * 2];\n const j = pairs[p * 2 + 1];\n const y_i = Y.row(i);\n const y_j = Y.row(j);\n\n let sq_dist = 0;\n for (let k = 0; k < d; ++k) {\n const diff = y_i[k] - y_j[k];\n sq_dist += diff * diff;\n }\n const d_ij = 1 + sq_dist;\n\n // Apply local weight scaling when pair is within distance threshold\n let w = w_fp;\n if (sq_dist < low_dist_thres_sq) {\n w *= low_dist_thres / (2 * Math.sqrt(d_ij));\n }\n\n // FP loss: 1/(1+d_ij), gradient: -2/(1+d_ij)²\n const coeff = (-w * 2) / (d_ij * d_ij);\n\n const base_i = i * d;\n const base_j = j * d;\n for (let k = 0; k < d; ++k) {\n const diff = y_i[k] - y_j[k];\n const g = coeff * diff;\n grad_flat[base_i + k] += g;\n grad_flat[base_j + k] -= g;\n }\n }\n }\n\n /**\n * Initializes LocalMAP (same as PaCMAP, but caches nn_sets for phase 3 resampling).\n *\n * @returns {LocalMAP}\n */\n init() {\n super.init();\n // Cache low_dist_thres from sealed parameters (avoids type indexing issues)\n this._low_dist_thres = /** @type {number} */ (/** @type {any} */ (this._parameters)[\"low_dist_thres\"] ?? 10);\n // Cache nn_sets for use in phase 3 FP resampling\n // We rebuild them from _nn_pairs\n const N = this._N;\n const nn_pairs = this._nn_pairs;\n if (!nn_pairs) return this;\n /** @type {Set[]} */\n const nn_sets = Array.from({ length: N }, () => new Set());\n for (let p = 0; p < nn_pairs.length; p += 2) {\n nn_sets[nn_pairs[p]].add(nn_pairs[p + 1]);\n }\n this._nn_sets_cache = nn_sets;\n return this;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new LocalMAP(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new LocalMAP(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new LocalMAP(X, parameters);\n return dr.transform_async();\n }\n}\n","import { distance_matrix, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersSMACOF} from \"./index.js\" */\n\n/**\n * Metric Multidimensional Scaling (MDS) via SMACOF.\n *\n * SMACOF (Scaling by Majorizing a Complicated Function) is an iterative majorization\n * algorithm for solving metric multidimensional scaling problems, which aims to\n * minimize the stress function.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link MDS} for the classical approach.\n */\nexport class SMACOF extends DR {\n /**\n * SMACOF for MDS.\n *\n * @param {T} X - The high-dimensional data or precomputed distance matrix.\n * @param {Partial} [parameters] - Object containing parameterization.\n */\n constructor(X, parameters = {}) {\n super(X, { d: 2, metric: euclidean, seed: 1212, iterations: 300, epsilon: 1e-4 }, parameters);\n }\n\n /**\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n this.check_init();\n const X = this.X;\n const rows = this._N;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const metric = /** @type {typeof euclidean | \"precomputed\"} */ (this.parameter(\"metric\"));\n const iterations = /** @type {number} */ (this.parameter(\"iterations\"));\n const epsilon = /** @type {number} */ (this.parameter(\"epsilon\"));\n\n const target_distances = metric === \"precomputed\" ? X : distance_matrix(X, metric);\n\n let Z = new Matrix(rows, d, () => (this._randomizer.random - 0.5) * 2);\n\n // Center Z\n for (let j = 0; j < d; ++j) {\n const col = Z.col(j);\n const mean = col.reduce((a, b) => a + b, 0) / rows;\n for (let i = 0; i < rows; ++i) {\n Z.sub_entry(i, j, mean);\n }\n }\n\n this.Y = /** @type {Matrix} */ (Z); // Initial state\n\n let prev_stress = Infinity;\n\n if (!(iterations > 0)) {\n yield this.projection;\n return this.projection;\n }\n\n for (let iter = 0; iter < iterations; ++iter) {\n const B = new Matrix(rows, rows, 0);\n\n for (let i = 0; i < rows; ++i) {\n let bii = 0;\n const z_i = Z.row(i);\n for (let j = 0; j < rows; ++j) {\n if (i === j) continue;\n const z_j = Z.row(j);\n const dist_Z = euclidean(z_i, z_j);\n const dist_target = target_distances.entry(i, j);\n\n let bij = 0;\n if (dist_Z > 1e-12) {\n bij = -dist_target / dist_Z;\n }\n B.set_entry(i, j, bij);\n bii -= bij;\n }\n B.set_entry(i, i, bii);\n }\n\n // Z_new = 1/N * B(Z) * Z\n const Z_new = B.dot(Z)._apply(rows, (val, n) => val / n);\n\n this.Y = /** @type {Matrix} */ (Z_new);\n Z = /** @type {Matrix} */ (Z_new);\n\n // Calculate stress\n let stress_num = 0;\n let stress_den = 0;\n for (let i = 0; i < rows; ++i) {\n const z_i = Z.row(i);\n for (let j = i + 1; j < rows; ++j) {\n const z_j = Z.row(j);\n const dist_Y = euclidean(z_i, z_j);\n const diff = target_distances.entry(i, j) - dist_Y;\n stress_num += diff * diff;\n stress_den += target_distances.entry(i, j) ** 2;\n }\n }\n const current_stress = Math.sqrt(stress_num / Math.max(stress_den, 1e-12));\n\n yield this.projection;\n\n if (Math.abs(prev_stress - current_stress) < epsilon) {\n break;\n }\n prev_stress = current_stress;\n }\n return this.projection;\n }\n\n /**\n * @returns {T}\n */\n transform() {\n const gen = this.generator();\n let res = /** @type {T} */ (this.X);\n for (const step of gen) {\n res = step;\n }\n return res;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new SMACOF(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new SMACOF(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new SMACOF(X, parameters);\n return dr.transform_async();\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { BallTree } from \"../knn/index.js\";\nimport { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\nimport { SMACOF } from \"./SMACOF.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersISOMAP} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n\n/**\n * Isomap (Isometric Mapping)\n *\n * A nonlinear dimensionality reduction algorithm that uses geodesic distances\n * between points on a manifold to perform embedding. It builds a neighborhood\n * graph and uses MDS on the shortest-path distances.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link LLE} for another nonlinear alternative\n */\nexport class ISOMAP extends DR {\n /**\n * Isometric feature mapping (ISOMAP).\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n * @see {@link https://doi.org/10.1126/science.290.5500.2319}\n */\n constructor(X, parameters = {}) {\n /** @type {ParametersISOMAP} */\n const defaults = {\n neighbors: -Infinity,\n d: 2,\n metric: euclidean,\n seed: 1212,\n project: \"MDS\",\n eig_args: {},\n };\n super(X, defaults, parameters);\n\n this.defaults = defaults;\n\n if (this._parameters.neighbors === -Infinity) {\n this.parameter(\"neighbors\", Math.min(Math.max(Math.floor(this.X.shape[0] / 10), 2), this._N - 1));\n }\n\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n if (!Object.hasOwn(eig_args, \"seed\")) {\n eig_args.seed = this._randomizer;\n }\n }\n\n /**\n * Computes the projection.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * @returns {T}\n */\n transform() {\n this.check_init();\n const X = this.X;\n const rows = this._N;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const metric = /** @type {typeof euclidean} */ (this.parameter(\"metric\"));\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n const neighbors = /** @type {number} */ (this.parameter(\"neighbors\"));\n // TODO: make knn extern and parameter for constructor or transform?\n const D = new Matrix(rows, rows, 0);\n D.shape = [rows, rows, (i, j) => (i <= j ? metric(X.row(i), X.row(j)) : D.entry(j, i))];\n\n /** @type {{ index: number; distance: number }[][]} */\n const kNearestNeighbors = [];\n const tree = new BallTree(X.to2dArray(), {\n metric,\n seed: /** @type {number} */ (this.parameter(\"seed\")),\n });\n for (let i = 0; i < rows; ++i) {\n // BallTree search returns elements including the queried point itself (at distance 0).\n // Request neighbors + 1 and slice off the first one (which should be the query point).\n const neighborsList = tree.search_by_index(i, neighbors + 1);\n kNearestNeighbors.push(\n neighborsList.slice(1).map((n) => ({\n index: n.index,\n distance: n.distance,\n })),\n );\n }\n\n // ISOMAP requires an undirected/symmetric nearest neighbor graph.\n // If i is a nearest neighbor of j, then j should be connected to i as well.\n for (let i = 0; i < rows; ++i) {\n for (const neighbor of kNearestNeighbors[i]) {\n const j = neighbor.index;\n const d = neighbor.distance;\n const reciprocal_edge = kNearestNeighbors[j].find((n) => n.index === i);\n if (!reciprocal_edge) {\n kNearestNeighbors[j].push({ index: i, distance: d });\n }\n }\n }\n\n /*D = dijkstra(kNearestNeighbors);*/\n // compute shortest paths using Dijkstra's algorithm\n // TODO: make extern\n const G = new Matrix(rows, rows, Infinity);\n\n for (let i = 0; i < rows; ++i) {\n G.set_entry(i, i, 0);\n const H = new Heap([{ index: i, distance: 0 }], (d) => d.distance, \"min\");\n\n while (!H.empty) {\n const item = H.pop();\n if (!item) break;\n\n const u = item.element.index;\n const dist_u = item.element.distance;\n\n if (dist_u > G.entry(i, u)) continue;\n\n for (const neighbor of kNearestNeighbors[u]) {\n const v = neighbor.index;\n const alt = dist_u + neighbor.distance;\n if (alt < G.entry(i, v)) {\n G.set_entry(i, v, alt);\n H.push({ index: v, distance: alt });\n }\n }\n }\n }\n\n let max_val = 0;\n for (let i = 0; i < rows; i++) {\n for (let j = 0; j < rows; j++) {\n const val = G.entry(i, j);\n if (val !== Infinity && val > max_val) max_val = val;\n }\n }\n const big_val = max_val * 10;\n\n const project = /** @type {\"MDS\" | \"SMACOF\"} */ (this.parameter(\"project\"));\n\n if (project === \"SMACOF\") {\n // Apply SMACOF metric MDS to the distance matrix directly\n const D_matrix = new Matrix(rows, rows, (i, j) => {\n const val = G.entry(i, j);\n return val === Infinity ? big_val : val;\n });\n const smacof = new SMACOF(D_matrix, {\n metric: \"precomputed\",\n d,\n seed: this.parameter(\"seed\"),\n });\n smacof.transform();\n this.Y = smacof.Y;\n } else {\n // \"MDS\" (Classical MDS) via Eigendecomposition of double-centered squared distance matrix\n const D_sq = new Matrix(rows, rows, (i, j) => {\n let val = G.entry(i, j);\n if (val === Infinity) val = big_val;\n return val * val;\n });\n\n const ai_ = D_sq.meanCols();\n const a_j = D_sq.meanRows();\n const a__ = D_sq.mean();\n const B = new Matrix(rows, rows, (i, j) => -0.5 * (D_sq.entry(i, j) - ai_[i] - a_j[j] + a__));\n\n // compute d eigenvectors\n const { eigenvectors: V } = simultaneous_poweriteration(B, d, eig_args);\n this.Y = Matrix.from(V).transpose();\n }\n // return embedding\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new ISOMAP(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new ISOMAP(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new ISOMAP(X, parameters);\n return dr.transform_async();\n }\n}\n","import { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLDA} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n\n/**\n * Linear Discriminant Analysis (LDA)\n *\n * A supervised dimensionality reduction technique that finds the axes that\n * maximize the separation between multiple classes.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class LDA extends DR {\n /**\n * Linear Discriminant Analysis.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial & { labels: any[] | Float64Array }} parameters - Object containing parameterization of the DR method.\n * @see {@link https://onlinelibrary.wiley.com/doi/10.1111/j.1469-1809.1936.tb02137.x}\n */\n constructor(X, parameters) {\n super(X, { labels: parameters.labels, d: 2, seed: 1212, eig_args: {} }, parameters);\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n if (!Object.hasOwn(eig_args, \"seed\")) {\n eig_args.seed = this._randomizer;\n }\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T} - The projected data.\n */\n transform() {\n const X = this.X;\n const [rows, cols] = X.shape;\n const { d, labels, eig_args } = this._parameters;\n if (labels === null || labels.length !== rows) {\n throw new Error(\"LDA needs parameter label to every datapoint to work!\");\n }\n\n /** @type {Record} */\n const unique_labels = {};\n let label_id = 0;\n labels.forEach((l, i) => {\n if (l in unique_labels) {\n unique_labels[l].count++;\n unique_labels[l].rows.push(X.row(i));\n } else {\n unique_labels[l] = {\n id: label_id++,\n count: 1,\n rows: [X.row(i)],\n };\n }\n });\n\n // create X_mean and vector means;\n const X_mean = X.meanCols();\n const V_mean = new Matrix(label_id, cols);\n for (const label in unique_labels) {\n const V = Matrix.from(unique_labels[label].rows);\n const v_mean = V.meanCols();\n for (let j = 0; j < cols; ++j) {\n V_mean.set_entry(unique_labels[label].id, j, v_mean[j]);\n }\n }\n // scatter_between\n let S_b = new Matrix(cols, cols);\n for (const label in unique_labels) {\n const v = V_mean.row(unique_labels[label].id);\n const m = Matrix.from([v]).sub(Matrix.from([X_mean]));\n const N = unique_labels[label].count;\n S_b = S_b.add(m.transDot(m).mult(N));\n }\n\n // scatter_within\n let S_w = new Matrix(cols, cols);\n for (const label in unique_labels) {\n const v = V_mean.row(unique_labels[label].id);\n const R = unique_labels[label].rows;\n for (let i = 0, n = unique_labels[label].count; i < n; ++i) {\n const row_v = Matrix.from([R[i]]).sub(Matrix.from([v]));\n S_w = S_w.add(row_v.transDot(row_v));\n }\n }\n\n const { eigenvectors: EV } = simultaneous_poweriteration(\n S_w.inverse().dot(S_b),\n d || Math.min(cols, label_id - 1),\n eig_args,\n );\n const V = Matrix.from(EV).transpose();\n this.Y = X.dot(V);\n\n // return embedding\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @returns {T}\n */\n static transform(X, parameters) {\n // @ts-expect-error: LDA requires labels, but DR static transform doesn't\n const dr = new LDA(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n // @ts-expect-error: LDA requires labels, but DR static generator doesn't\n const dr = new LDA(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n // @ts-expect-error: LDA requires labels, but DR static transform doesn't\n const dr = new LDA(X, parameters);\n return dr.transform_async();\n }\n}\n","import { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { k_nearest_neighbors, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { neumair_sum } from \"../numerical/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLLE} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n\n/**\n * Locally Linear Embedding (LLE)\n *\n * A nonlinear dimensionality reduction technique that preserves local\n * linear relationships between points. It represents each point as a linear\n * combination of its neighbors.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link ISOMAP} for another nonlinear alternative\n */\nexport class LLE extends DR {\n /**\n * Locally Linear Embedding.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://doi.org/10.1126/science.290.5500.2323}\n */\n constructor(X, parameters) {\n super(\n X,\n {\n neighbors: -Infinity,\n d: 2,\n metric: euclidean,\n seed: 1212,\n eig_args: {},\n },\n parameters,\n );\n if (this._parameters.neighbors === -Infinity) {\n this.parameter(\"neighbors\", Math.min(Math.max(Math.floor(this._N / 10), 2), this._N - 1));\n }\n\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n if (!Object.hasOwn(eig_args, \"seed\")) {\n eig_args.seed = this._randomizer;\n }\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T}\n */\n transform() {\n const X = this.X;\n const rows = this._N;\n const cols = this._D;\n const neighbors = /** @type {number} */ (this.parameter(\"neighbors\"));\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n const metric = /** @type {typeof euclidean} */ (this.parameter(\"metric\"));\n const nN = k_nearest_neighbors(X, neighbors, metric);\n const O = new Matrix(neighbors, 1, 1);\n const W = new Matrix(rows, rows);\n\n for (let row = 0; row < rows; ++row) {\n const nN_row = nN[row];\n const Z = new Matrix(neighbors, cols, (i, j) => X.entry(nN_row[i].j, j) - X.entry(row, j));\n const C = Z.dotTrans(Z);\n if (neighbors > cols) {\n const C_trace = neumair_sum(C.diag()) / 1000;\n for (let j = 0; j < neighbors; ++j) {\n C.add_entry(j, j, C_trace);\n }\n }\n // reconstruct;\n let w = Matrix.solve_CG(C, O, this._randomizer);\n w = w.divide(w.sum());\n for (let j = 0; j < neighbors; ++j) {\n W.set_entry(row, nN_row[j].j, w.entry(j, 0));\n }\n }\n // comp embedding\n const I = new Matrix(rows, rows, \"identity\");\n const IW = I.sub(W);\n const M = IW.transDot(IW);\n\n // M is symmetric positive semi-definite. Smallest eigenvalue is 0 (ones vector).\n // To find smallest eigenvalues of M, we can find largest of (C*I - M)\n // Upper bound for max eigenvalue: Frobenius norm or sum of absolute values\n const C = M.mean() * rows * 2; // Safe upper bound for a sparse-ish M in LLE\n const CI_M = new Matrix(rows, rows, (i, j) => (i === j ? C : 0) - M.entry(i, j));\n\n const { eigenvectors: V } = simultaneous_poweriteration(CI_M, d + 1, eig_args);\n // Skip the first eigenvector (the ones vector corresponding to eigenvalue C)\n this.Y = Matrix.from(V.slice(1, 1 + d)).T;\n\n // return embedding\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new LLE(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new LLE(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new LLE(X, parameters);\n return dr.transform_async();\n }\n}\n","import { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { distance_matrix, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersMDS} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n\n/**\n * Classical Multidimensional Scaling (MDS)\n *\n * A linear dimensionality reduction technique that seeks to preserve the\n * pairwise distances between points as much as possible in the lower-dimensional\n * space.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link PCA} for another linear alternative\n */\nexport class MDS extends DR {\n /**\n * Classical MDS.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X, parameters = {}) {\n super(X, { d: 2, metric: euclidean, seed: 1212, eig_args: {} }, parameters);\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n if (!Object.hasOwn(eig_args, \"seed\")) {\n eig_args.seed = this._randomizer;\n }\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T}\n */\n transform() {\n const X = this.X;\n const rows = X.shape[0];\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const metric = /** @type {typeof euclidean | \"precomputed\"} */ (this.parameter(\"metric\"));\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n const A = metric === \"precomputed\" ? X : distance_matrix(X, metric);\n\n const D_sq = new Matrix(rows, rows, (i, j) => {\n const val = A.entry(i, j);\n return val * val;\n });\n\n const ai_ = D_sq.meanCols();\n const a_j = D_sq.meanRows();\n const a__ = D_sq.mean();\n\n this._d_X = A;\n const B = new Matrix(rows, rows, (i, j) => -0.5 * (D_sq.entry(i, j) - ai_[i] - a_j[j] + a__));\n\n const { eigenvectors: V } = simultaneous_poweriteration(B, d, eig_args);\n this.Y = Matrix.from(V).transpose();\n\n return this.projection;\n }\n\n /** @returns {number} - The stress of the projection. */\n stress() {\n const N = this.X.shape[0];\n const Y = this.Y;\n const d_X = this._d_X;\n if (!d_X) throw new Error(\"First transform!\");\n\n const d_Y = new Matrix(N, N, 0);\n d_Y.shape = [\n N,\n N,\n (i, j) => {\n return i < j ? euclidean(Y.row(i), Y.row(j)) : d_Y.entry(j, i);\n },\n ];\n let top_sum = 0;\n let bottom_sum = 0;\n for (let i = 0; i < N; ++i) {\n for (let j = i + 1; j < N; ++j) {\n top_sum += (d_X.entry(i, j) - d_Y.entry(i, j)) ** 2;\n bottom_sum += d_X.entry(i, j) ** 2;\n }\n }\n return Math.sqrt(top_sum / bottom_sum);\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new MDS(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new MDS(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new MDS(X, parameters);\n return dr.transform_async();\n }\n}\n","import { KMedoids } from \"../clustering/index.js\";\nimport { BallTree } from \"../knn/index.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\nimport { MDS } from \"./MDS.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLSP} from \"./index.js\" */\n\n/**\n * Least Square Projection (LSP)\n *\n * A dimensionality reduction technique that uses a small set of control points\n * (projected with MDS) to define the projection for the rest of the data\n * using a Laplacian-based optimization.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class LSP extends DR {\n /**\n * Least Squares Projection.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n * @see {@link https://ieeexplore.ieee.org/document/4378370}\n */\n constructor(X, parameters) {\n super(\n X,\n {\n neighbors: -Infinity,\n control_points: -Infinity,\n d: 2,\n metric: euclidean,\n seed: 1212,\n },\n parameters,\n );\n if (this.parameter(\"neighbors\") === -Infinity) {\n this.parameter(\"neighbors\", Math.min(Math.max(Math.floor(this._N / 10), 2), this._N - 1));\n }\n if (this.parameter(\"control_points\") === -Infinity) {\n this.parameter(\"control_points\", Math.min(Math.ceil(Math.sqrt(this._N)), this._N - 1));\n }\n this._is_initialized = false;\n }\n\n /**\n * @returns {LSP}\n */\n //\tinit(DR = MDS, DR_parameters = {}, KNN = BallTree) {\n init() {\n const DR = MDS;\n let DR_parameters = {};\n const KNN = BallTree;\n if (this._is_initialized) return this;\n const X = this.X;\n const N = this._N;\n const K = /** @type {number} */ (this.parameter(\"neighbors\"));\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const seed = /** @type {number} */ (this.parameter(\"seed\"));\n const metric = /** @type {typeof euclidean} */ (this.parameter(\"metric\"));\n DR_parameters = Object.assign({ d, metric, seed }, DR_parameters);\n const nc = /** @type {number} */ (this.parameter(\"control_points\"));\n const control_points = new KMedoids(X, { K: nc, metric }).get_medoids();\n const C = new Matrix(nc, N, \"zeros\");\n control_points.forEach((c_i, i) => {\n C.set_entry(i, c_i, 1);\n });\n\n const control_points_matrix = Matrix.from(control_points.map((c_i) => X.row(c_i)));\n const Y_C = new DR(control_points_matrix, DR_parameters).transform();\n\n const XA = X.to2dArray();\n const knn = new KNN(XA, { metric, seed });\n const L = new Matrix(N, N, \"I\");\n const alpha = -1 / K;\n XA.forEach((x_i, i) => {\n for (const { index: j } of knn.search(x_i, K)) {\n if (i === j) continue;\n L.set_entry(i, j, alpha);\n }\n });\n const A = L.concat(C, \"vertical\");\n\n const z = new Matrix(N, d, \"zeros\");\n const b = z.concat(Y_C, \"vertical\");\n\n this._A = A;\n this._b = b;\n this._is_initialized = true;\n return this;\n }\n\n /**\n * Computes the projection.\n *\n * @returns {T} Returns the projection.\n */\n transform() {\n this.check_init();\n const A = this._A;\n const b = this._b;\n\n if (!A || !b) throw new Error(\"Call init() first!\");\n const ATA = A.transDot(A);\n const ATb = A.transDot(b);\n this.Y = Matrix.solve_CG(ATA, ATb, this._randomizer);\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new LSP(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new LSP(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new LSP(X, parameters);\n return dr.transform_async();\n }\n}\n","import { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { k_nearest_neighbors, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLTSA} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n\n/**\n * Local Tangent Space Alignment (LTSA)\n *\n * A nonlinear dimensionality reduction algorithm that represents the local\n * geometry of the manifold by tangent spaces and then aligns them to reveal\n * the global structure.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class LTSA extends DR {\n /**\n * Local Tangent Space Alignment\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://epubs.siam.org/doi/abs/10.1137/S1064827502419154}\n */\n constructor(X, parameters) {\n super(\n X,\n {\n neighbors: -Infinity,\n d: 2,\n metric: euclidean,\n seed: 1212,\n eig_args: {},\n },\n parameters,\n );\n if (this.parameter(\"neighbors\") === -Infinity) {\n this.parameter(\"neighbors\", Math.min(Math.max(Math.floor(this._N / 10), 2), this._N - 1));\n }\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n if (!Object.hasOwn(eig_args, \"seed\")) {\n eig_args.seed = this._randomizer;\n }\n\n const d = /** @type {number} */ (this.parameter(\"d\"));\n if (this._D <= d) {\n throw new Error(\n `Dimensionality of X (D = ${this._D}) must be greater than the required dimensionality of the result (d = ${d})!`,\n );\n }\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimenionality `d`.\n *\n * @returns {T}\n */\n transform() {\n const X = this.X;\n const [rows, D] = X.shape;\n const neighbors = /** @type {number} */ (this.parameter(\"neighbors\"));\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n const metric = /** @type {typeof euclidean} */ (this.parameter(\"metric\"));\n // 1.1 determine k nearest neighbors\n const nN = k_nearest_neighbors(X, neighbors, metric);\n // center matrix\n const O = new Matrix(D, D, \"center\");\n const B = new Matrix(rows, rows, 0);\n\n for (let row = 0; row < rows; ++row) {\n // 1.2 compute the d largest eigenvectors of the correlation matrix\n const I_i = [row, ...nN[row].map((n) => n.j)];\n let X_i = Matrix.from(I_i.map((n) => X.row(n)));\n // center X_i\n X_i = X_i.dot(O);\n // correlation matrix\n const C = X_i.dotTrans(X_i);\n const { eigenvectors: g } = simultaneous_poweriteration(C, d, eig_args);\n //g.push(linspace(0, k).map(_ => 1 / Math.sqrt(k + 1)));\n const G_i_t = Matrix.from(g);\n // 2. Constructing alignment matrix\n const W_i = G_i_t.transDot(G_i_t).add(1 / Math.sqrt(neighbors + 1));\n for (let i = 0; i < neighbors + 1; ++i) {\n for (let j = 0; j < neighbors + 1; ++j) {\n B.add_entry(I_i[i], I_i[j], W_i.entry(i, j) - (i === j ? 1 : 0));\n }\n }\n }\n\n // 3. Aligning global coordinates\n const { eigenvectors: Y } = simultaneous_poweriteration(B, d + 1, eig_args);\n this.Y = Matrix.from(Y.slice(1)).transpose();\n\n // return embedding\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new LTSA(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new LTSA(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new LTSA(X, parameters);\n return dr.transform_async();\n }\n}\n","import { distance_matrix, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\nimport { MDS, PCA } from \"./index.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersPCA, ParametersMDS, ParametersSAMMON} from \"./index.js\" */\n/** @typedef {\"PCA\" | \"MDS\" | \"random\"} AvailableInit */\n\n/** @typedef {{ PCA: ParametersPCA; MDS: ParametersMDS; random: {} }} ChooseDR */\n\n/**\n * Sammon's Mapping\n *\n * A nonlinear dimensionality reduction technique that minimizes a stress\n * function based on the ratio of pairwise distances in high and low dimensional spaces.\n *\n * @class\n * @template {InputType} T\n * @extends DR>\n * @category Dimensionality Reduction\n */\nexport class SAMMON extends DR {\n /** @type {Matrix | undefined} */\n distance_matrix;\n\n /**\n * SAMMON's Mapping\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial>} [parameters] - Object containing parameterization of the DR\n * method.\n * @see {@link https://arxiv.org/pdf/2009.01512.pdf}\n */\n constructor(X, parameters) {\n super(\n X,\n {\n magic: 0.1,\n d: 2,\n metric: euclidean,\n seed: 1212,\n init_DR: \"random\",\n init_parameters: {},\n },\n parameters,\n );\n }\n\n /**\n * Initializes the projection.\n *\n * @param {Matrix | undefined} D\n * @returns {asserts D is Matrix}\n */\n init(D) {\n const N = this.X.shape[0];\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const metric = /** @type {typeof euclidean | \"precomputed\"} */ (this.parameter(\"metric\"));\n const init_DR = /** @type {AvailableInit} */ (this.parameter(\"init_DR\"));\n const DR_parameters = this.parameter(\"init_parameters\");\n if (init_DR === \"random\") {\n const randomizer = this._randomizer;\n this.Y = new Matrix(N, d, () => randomizer.random);\n } else if (init_DR === \"PCA\") {\n this.Y = Matrix.from(PCA.transform(this.X, /** @type {ParametersPCA} */ (DR_parameters)));\n } else if (init_DR === \"MDS\") {\n this.Y = Matrix.from(MDS.transform(this.X, /** @type {ParametersMDS} */ (DR_parameters)));\n } else {\n throw new Error('init_DR needs to be either \"random\" or a DR method!');\n }\n D = metric === \"precomputed\" ? Matrix.from(this.X) : distance_matrix(this.X, metric);\n this.distance_matrix = D;\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality 2.\n *\n * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200`\n * @returns {T} The projection of `X`.\n */\n transform(max_iter = 200) {\n this.check_init();\n if (!this.distance_matrix) this.init(this.distance_matrix);\n for (let j = 0; j < max_iter; ++j) {\n this._step();\n }\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimenionality 2.\n *\n * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200`\n * @returns {Generator} A generator yielding the intermediate steps of the projection of\n * `X`.\n */\n *generator(max_iter = 200) {\n this.check_init();\n if (!this.distance_matrix) this.init(this.distance_matrix);\n\n for (let j = 0; j < max_iter; ++j) {\n this._step();\n yield this.projection;\n }\n\n return this.projection;\n }\n\n _step() {\n if (!this.distance_matrix) this.init(this.distance_matrix);\n const MAGIC = /** @type {number} */ (this.parameter(\"magic\"));\n const D = /** @type {Matrix} */ (this.distance_matrix);\n const N = this.X.shape[0];\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const Y = this.Y;\n\n const G = new Matrix(N, d, 0);\n\n const sum = new Float64Array(d);\n for (let i = 0; i < N; ++i) {\n const e1 = new Float64Array(d);\n const e2 = new Float64Array(d);\n const Yi = Y.row(i);\n for (let j = 0; j < N; ++j) {\n if (i === j) continue;\n const dX = D.entry(i, j);\n if (dX === 0) continue; // Skip identical points in high-dim\n\n const Yj = Y.row(j);\n const delta = new Float64Array(d);\n for (let k = 0; k < d; ++k) {\n delta[k] = Yi[k] - Yj[k];\n }\n const dY = Math.max(euclidean(Yi, Yj), 1e-6);\n const dq = dX - dY;\n const dr = dX * dY;\n for (let k = 0; k < d; ++k) {\n e1[k] += (delta[k] * dq) / dr;\n e2[k] += (dq - (delta[k] ** 2 * (1 + dq / dY)) / dY) / dr;\n }\n }\n for (let k = 0; k < d; ++k) {\n const val = Y.entry(i, k) + ((MAGIC * e1[k]) / Math.abs(e2[k]) || 0);\n G.set_entry(i, k, val);\n sum[k] += val;\n }\n }\n for (let k = 0; k < d; ++k) {\n sum[k] /= N;\n }\n\n for (let i = 0; i < N; ++i) {\n for (let k = 0; k < d; ++k) {\n Y.set_entry(i, k, G.entry(i, k) - sum[k]);\n }\n }\n return Y;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial>} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new SAMMON(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial>} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new SAMMON(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial>} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new SAMMON(X, parameters);\n return dr.transform_async();\n }\n}\n","import { linspace, Matrix, norm } from \"../matrix/index.js\";\nimport { euclidean, euclidean_squared } from \"../metrics/index.js\";\nimport { neumair_sum } from \"../numerical/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersSQDMDS} from \"./index.js\" */\n\n/**\n * SQuadMDS (Stochastic Quartet MDS)\n *\n * A lean Stochastic Quartet MDS improving global structure preservation in\n * neighbor embedding like t-SNE and UMAP.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class SQDMDS extends DR {\n /**\n * SQuadMDS: a lean Stochastic Quartet MDS improving global structure preservation in neighbor embedding like t-SNE\n * and UMAP.\n *\n * @param {T} X\n * @param {Partial} [parameters]\n * @see {@link https://arxiv.org/pdf/2202.12087.pdf}\n */\n constructor(X, parameters) {\n super(\n X,\n {\n d: 2,\n metric: euclidean,\n seed: 1212,\n decay_start: 0.1,\n decay_cte: 0.34, // 0.34\n },\n parameters,\n );\n\n this.init();\n if (this.parameter(\"metric\") === \"precomputed\" && this.X.shape[0] !== this.X.shape[1]) {\n throw new Error(\"SQDMDS input data must be a square Matrix\");\n }\n }\n\n init() {\n const N = this._N;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n\n // initialize helpers.\n this._add = this.__add(d);\n this._sub_div = this.__sub_div(d);\n this._minus = this.__minus(d);\n this._mult = this.__mult(d);\n this._LR_init = Math.max(2, 0.005 * N);\n this._LR = this._LR_init;\n const decay_cte = /** @type {number} */ (this.parameter(\"decay_cte\"));\n this._offset = -Math.exp(-1 / decay_cte);\n this._momentums = new Matrix(N, d, 0);\n this._grads = new Matrix(N, d, 0);\n this._indices = linspace(0, N - 1);\n // initialize projection.\n const R = this._randomizer;\n this.Y = new Matrix(N, d, () => R.random - 0.5);\n\n // preparing metric for optimization.\n const this_metric = /** @type {Metric | \"precomputed\"} */ (this.parameter(\"metric\"));\n if (this_metric === \"precomputed\") {\n /** @type {(i: number, j: number, X: Matrix) => number} */\n this._HD_metric = (i, j, X) => X.entry(i, j);\n /** @type {(i: number, j: number, X: Matrix) => number} */\n this._HD_metric_exaggeration = (i, j, X) => X.entry(i, j) ** 2;\n } else {\n this._HD_metric = (i, j, X) => this_metric(X.row(i), X.row(j));\n if (this_metric === euclidean) {\n this._HD_metric_exaggeration = (i, j, X) => euclidean_squared(X.row(i), X.row(j));\n } else {\n this._HD_metric_exaggeration = (i, j, X) => this_metric(X.row(i), X.row(j)) ** 2;\n }\n }\n return;\n }\n\n /**\n * Computes the projection.\n *\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {T} The projection.\n */\n transform(iterations = 500) {\n this.check_init();\n const decay_start = /** @type {number} */ (this.parameter(\"decay_start\"));\n this._decay_start = Math.round(decay_start * iterations);\n for (let i = 0; i < iterations; ++i) {\n this._step(i, iterations);\n }\n return this.projection;\n }\n\n /**\n * Computes the projection.\n *\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {Generator} The intermediate steps of the projection.\n */\n *generator(iterations = 500) {\n this.check_init();\n const decay_start = /** @type {number} */ (this.parameter(\"decay_start\"));\n this._decay_start = Math.round(decay_start * iterations);\n for (let i = 0; i < iterations; ++i) {\n this._step(i, iterations);\n yield this.projection;\n }\n\n return this.projection;\n }\n\n /**\n * Performs an optimization step.\n *\n * @private\n * @param {number} i - Acutal iteration.\n * @param {number} iterations - Number of iterations.\n */\n _step(i, iterations) {\n if (this._LR_init === undefined || this._offset === undefined) throw new Error(\"Call init() first!\");\n\n const decay_start = /** @type {number} */ (this.parameter(\"decay_start\"));\n if (i > decay_start) {\n const decay_cte = /** @type {number} */ (this.parameter(\"decay_cte\"));\n const offset = this._offset;\n const ratio = (i - decay_start) / (iterations - decay_start);\n this._LR = this._LR_init * (Math.exp(-(ratio * ratio) / decay_cte) + offset);\n this._distance_exaggeration = false;\n } else {\n this._distance_exaggeration = true;\n }\n this._nestrov_iteration(this._distance_exaggeration);\n }\n\n /**\n * Creates quartets of non overlapping indices.\n *\n * @private\n * @returns {Uint32Array[]}\n */\n __quartets() {\n if (!this._indices) throw new Error(\"Call init() first!\");\n if (this._offset === undefined) throw new Error(\"Call init() first!\");\n const N = this._N;\n const max_N = N - (N % 4);\n const R = this._randomizer;\n const shuffled_indices = R.choice(this._indices, max_N);\n const result = [];\n for (let i = 0; i < max_N; i += 4) {\n result.push(\n Uint32Array.of(\n shuffled_indices[i],\n shuffled_indices[i + 1],\n shuffled_indices[i + 2],\n shuffled_indices[i + 3],\n ),\n );\n }\n return result;\n }\n\n /**\n * Computes and applies gradients, and updates momentum.\n *\n * @private\n * @param {boolean} distance_exaggeration\n */\n _nestrov_iteration(distance_exaggeration) {\n if (!this._momentums || !this._grads || this._LR === undefined) throw new Error(\"Call init() first!\");\n const momentums = this._momentums.mult(0.99, { inline: true });\n const LR = this._LR;\n const grads = this._fill_MDS_grads(this.Y.add(momentums), this._grads, distance_exaggeration);\n const [n, d] = momentums.shape;\n for (let i = 0; i < n; ++i) {\n const g_i = grads.row(i);\n const g_i_norm = norm(g_i);\n if (g_i_norm === 0) continue;\n const mul = LR / g_i_norm;\n const m_i = momentums.row(i);\n for (let j = 0; j < d; ++j) {\n m_i[j] -= mul * g_i[j];\n }\n } // momentums -= (LR / norm) * grads\n this.Y.add(momentums, { inline: true });\n }\n\n /**\n * Computes the gradients.\n *\n * @param {Matrix} Y - The Projection.\n * @param {Matrix} grads - The gradients.\n * @param {boolean} [exaggeration=false] - Whether or not to use early exaggeration. Default is `false`\n * @param {boolean} [zero_grad=true] - Whether or not to reset the gradient in the beginning. Default is `true`\n * @returns {Matrix} The gradients.\n */\n _fill_MDS_grads(Y, grads, exaggeration = false, zero_grad = true) {\n if (!this._HD_metric || !this._HD_metric_exaggeration || !this._add) throw new Error(\"Call init() first!\");\n if (zero_grad) {\n // compute new gradients\n grads.values.fill(0);\n }\n const add = this._add;\n const X = this.X;\n let HD_metric;\n if (exaggeration === true) {\n HD_metric = this._HD_metric_exaggeration;\n } else {\n HD_metric = this._HD_metric;\n }\n\n const D_quartet = new Float64Array(6);\n const quartets = this.__quartets();\n for (const [i, j, k, l] of quartets) {\n // compute quartet's HD distances.\n D_quartet[0] = HD_metric(i, j, X);\n D_quartet[1] = HD_metric(i, k, X);\n D_quartet[2] = HD_metric(i, l, X);\n D_quartet[3] = HD_metric(j, k, X);\n D_quartet[4] = HD_metric(j, l, X);\n D_quartet[5] = HD_metric(k, l, X);\n\n const D_quartet_sum = neumair_sum(D_quartet);\n\n if (D_quartet_sum > 0) {\n for (let i = 0; i < 6; ++i) {\n D_quartet[i] /= D_quartet_sum;\n D_quartet[i] += 1e-11;\n }\n }\n const [gi, gj, gk, gl] = this._compute_quartet_grads(Y, [i, j, k, l], D_quartet);\n\n // add is inline, row acces the matrix\n add(grads.row(i), gi);\n add(grads.row(j), gj);\n add(grads.row(k), gk);\n add(grads.row(l), gl);\n }\n return grads;\n }\n\n /**\n * Quartet gradients for a projection.\n *\n * @private\n * @param {Matrix} Y - The acutal projection.\n * @param {number[]} quartet - The indices of the quartet.\n * @param {Float64Array} D_hd - The high-dimensional distances of the quartet.\n * @returns {Float64Array[]} The gradients for the quartet.\n */\n _compute_quartet_grads(Y, quartet, [p_ab, p_ac, p_ad, p_bc, p_bd, p_cd]) {\n const [a, b, c, d] = quartet.map((index) => Y.row(index));\n // LD distances, add a small number just in case\n const d_ab = euclidean(a, b) + 1e-12;\n const d_ac = euclidean(a, c) + 1e-12;\n const d_ad = euclidean(a, d) + 1e-12;\n const d_bc = euclidean(b, c) + 1e-12;\n const d_bd = euclidean(b, d) + 1e-12;\n const d_cd = euclidean(c, d) + 1e-12;\n const sum_LD_dist = neumair_sum([d_ab, d_ac, d_ad, d_bc, d_bd, d_cd]);\n\n // for each element of the sum: use the same gradient function and just permute the points given in input.\n const [gA1, gB1, gC1, gD1] = this._ABCD_grads(\n a,\n b,\n c,\n d,\n d_ab,\n d_ac,\n d_ad,\n d_bc,\n d_bd,\n d_cd,\n p_ab,\n sum_LD_dist,\n );\n const [gA2, gC2, gB2, gD2] = this._ABCD_grads(\n a,\n c,\n b,\n d,\n d_ac,\n d_ab,\n d_ad,\n d_bc,\n d_cd,\n d_bd,\n p_ac,\n sum_LD_dist,\n );\n const [gA3, gD3, gC3, gB3] = this._ABCD_grads(\n a,\n d,\n c,\n b,\n d_ad,\n d_ac,\n d_ab,\n d_cd,\n d_bd,\n d_bc,\n p_ad,\n sum_LD_dist,\n );\n const [gB4, gC4, gA4, gD4] = this._ABCD_grads(\n b,\n c,\n a,\n d,\n d_bc,\n d_ab,\n d_bd,\n d_ac,\n d_cd,\n d_ad,\n p_bc,\n sum_LD_dist,\n );\n const [gB5, gD5, gA5, gC5] = this._ABCD_grads(\n b,\n d,\n a,\n c,\n d_bd,\n d_ab,\n d_bc,\n d_ad,\n d_cd,\n d_ac,\n p_bd,\n sum_LD_dist,\n );\n const [gC6, gD6, gA6, gB6] = this._ABCD_grads(\n c,\n d,\n a,\n b,\n d_cd,\n d_ac,\n d_bc,\n d_ad,\n d_bd,\n d_ab,\n p_cd,\n sum_LD_dist,\n );\n\n if (!this._add) throw new Error(\"Call init() first!\");\n const add = this._add;\n const gA = add(gA1, gA2, gA3, gA4, gA5, gA6);\n const gB = add(gB1, gB2, gB3, gB4, gB5, gB6);\n const gC = add(gC1, gC2, gC3, gC4, gC5, gC6);\n const gD = add(gD1, gD2, gD3, gD4, gD5, gD6);\n\n return [gA, gB, gC, gD];\n }\n\n /**\n * Gradients for one element of the loss function's sum.\n *\n * @private\n * @param {Float64Array} a\n * @param {Float64Array} b\n * @param {Float64Array} c\n * @param {Float64Array} d\n * @param {number} d_ab\n * @param {number} d_ac\n * @param {number} d_ad\n * @param {number} d_bc\n * @param {number} d_bd\n * @param {number} d_cd\n * @param {number} p_ab\n * @param {number} sum_LD_dist\n * @returns {Float64Array[]}\n */\n _ABCD_grads(a, b, c, d, d_ab, d_ac, d_ad, d_bc, d_bd, d_cd, p_ab, sum_LD_dist) {\n if (!this._minus || !this._add || !this._mult || !this._sub_div) throw new Error(\"Call init() first!\");\n const ratio = d_ab / sum_LD_dist;\n const twice_ratio = 2 * ((p_ab - ratio) / sum_LD_dist);\n const minus = this._minus;\n const add = this._add;\n const mult = this._mult;\n const sub_div = this._sub_div;\n // no side effects because sub_div creates new arrays, and the inline functions work on this new created arrays.\n const gA = mult(\n minus(mult(add(sub_div(a, b, d_ab), sub_div(a, c, d_ac), sub_div(a, d, d_ad)), ratio), sub_div(a, b, d_ab)),\n twice_ratio,\n );\n const gB = mult(\n minus(mult(add(sub_div(b, a, d_ab), sub_div(b, c, d_bc), sub_div(b, d, d_bd)), ratio), sub_div(b, a, d_ab)),\n twice_ratio,\n );\n const gC = mult(add(sub_div(c, a, d_ac), sub_div(c, b, d_bc), sub_div(c, d, d_cd)), ratio * twice_ratio);\n const gD = mult(add(sub_div(d, a, d_ad), sub_div(d, b, d_bd), sub_div(d, c, d_cd)), ratio * twice_ratio);\n return [gA, gB, gC, gD];\n }\n\n /**\n * Inline!\n *\n * @param {number} d\n */\n __minus(d) {\n return /** @type {(a: Float64Array, b: Float64Array) => Float64Array} */ (a, b) => {\n for (let i = 0; i < d; ++i) {\n a[i] -= b[i];\n }\n return a;\n };\n }\n\n /**\n * Inline!\n *\n * @param {number} d\n */\n __add(d) {\n return /** @type {(...summands: Float64Array[]) => Float64Array} */ (...summands) => {\n const n = summands.length;\n const s1 = summands[0];\n for (let j = 1; j < n; ++j) {\n const summand = summands[j];\n for (let i = 0; i < d; ++i) {\n s1[i] += summand[i];\n }\n }\n return s1;\n };\n }\n\n /**\n * Inline!\n *\n * @param {number} d\n */\n __mult(d) {\n return /** @type {(a: Float64Array, v: number) => Float64Array} */ (a, v) => {\n for (let i = 0; i < d; ++i) {\n a[i] *= v;\n }\n return a;\n };\n }\n\n /**\n * Creates a new array `(x - y) / div`.\n *\n * @param {number} d\n */\n __sub_div(d) {\n return /** @type {(x: Float64Array, y: Float64Array, div: number) => Float64Array} */ (x, y, div) => {\n return Float64Array.from({ length: d }, (_, i) => (x[i] - y[i]) / div);\n };\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new SQDMDS(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new SQDMDS(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new SQDMDS(X, parameters);\n return dr.transform_async();\n }\n}\n","import { DisjointSet } from \"../datastructure/index.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersTopoMap} from \"./index.js\" */\n\n/**\n * TopoMap\n *\n * A 0-dimensional Homology Preserving Projection of High-Dimensional Data.\n * It aims to preserve the topological structure of the data by maintaining\n * the connectivity of a minimum spanning tree.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class TopoMap extends DR {\n /**\n * TopoMap: A 0-dimensional Homology Preserving Projection of High-Dimensional Data.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://arxiv.org/pdf/2009.01512.pdf}\n */\n constructor(X, parameters) {\n super(X, { metric: euclidean, seed: 1212 }, parameters);\n [this._N, this._D] = this.X.shape;\n this._distance_matrix = new Matrix(this._N, this._N, -1);\n }\n\n /**\n * @private\n * @param {number} i\n * @param {number} j\n * @param {import(\"../metrics/index.js\").Metric} metric\n * @returns {number}\n */\n __lazy_distance_matrix(i, j, metric) {\n const D = this._distance_matrix;\n const X = this.X;\n const D_ij = D.entry(i, j);\n if (D_ij === -1 && i !== j) {\n const dist = metric(X.row(i), X.row(j));\n D.set_entry(i, j, dist);\n D.set_entry(j, i, dist);\n return dist;\n }\n return i === j ? 0 : D_ij;\n }\n\n /**\n * Computes the minimum spanning tree, using a given metric\n *\n * @private\n * @param {import(\"../metrics/index.js\").Metric} metric\n * @see {@link https://en.wikipedia.org/wiki/Kruskal%27s_algorithm}\n */\n _make_minimum_spanning_tree(metric = euclidean) {\n const N = this._N;\n const X = [...this.X];\n\n this._disjoint_set = new DisjointSet(X);\n const disjoint_set = this._disjoint_set;\n const F = [];\n let E = [];\n for (let i = 0; i < N; ++i) {\n for (let j = i + 1; j < N; ++j) {\n E.push([i, j, this.__lazy_distance_matrix(i, j, metric)]);\n }\n }\n E = E.sort((a, b) => a[2] - b[2]);\n\n for (const [u, v, w] of E) {\n const set_u = disjoint_set.find(X[u]);\n const set_v = disjoint_set.find(X[v]);\n if (!set_u || !set_v) throw new Error(\"Should not happen!\");\n if (set_u !== set_v) {\n F.push([u, v, w]);\n disjoint_set.union(set_u, set_v);\n }\n }\n\n return F.sort((a, b) => a[2] - b[2]);\n }\n\n /** Initializes TopoMap. Sets all projcted points to zero, and computes a minimum spanning tree. */\n init() {\n const { metric } = this._parameters;\n this.Y = new Matrix(this._N, 2, 0);\n this._Emst = this._make_minimum_spanning_tree(metric);\n this._is_initialized = true;\n return this;\n }\n\n /**\n * Returns true if Point C is left of line AB.\n *\n * @private\n * @param {Float64Array} PointA - Point A of line AB\n * @param {Float64Array} PointB - Point B of line AB\n * @param {Float64Array} PointC - Point C\n * @returns {boolean}\n */\n __hull_cross([ax, ay], [bx, by], [sx, sy]) {\n return (bx - ax) * (sy - ay) - (by - ay) * (sx - ax) <= 0;\n }\n\n /**\n * Computes the convex hull of the set of Points S\n *\n * @private\n * @param {Float64Array[]} S - Set of Points.\n * @returns {Float64Array[]} Convex hull of S. Starts at the bottom-most point and continues counter-clockwise.\n * @see {@link https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain#JavaScript}\n */\n __hull(S) {\n const points = S.sort(([x1, y1], [x2, y2]) => y1 - y2 || x1 - x2);\n const N = points.length;\n if (N <= 2) return points;\n\n const lower = [];\n for (let i = 0; i < N; ++i) {\n while (\n lower.length >= 2 &&\n this.__hull_cross(lower[lower.length - 2], lower[lower.length - 1], points[i])\n ) {\n lower.pop();\n }\n lower.push(points[i]);\n }\n const upper = [];\n for (let i = N - 1; i >= 0; --i) {\n while (\n upper.length >= 2 &&\n this.__hull_cross(upper[upper.length - 2], upper[upper.length - 1], points[i])\n ) {\n upper.pop();\n }\n upper.push(points[i]);\n }\n upper.pop();\n lower.pop();\n return lower.concat(upper);\n }\n\n /**\n * Finds the angle to rotate Point A and B to lie on a line parallel to the x-axis.\n *\n * @private\n * @param {Float64Array} PointA\n * @param {Float64Array} PointB\n * @returns {{ sin: number; cos: number }} Object containing the sinus- and cosinus-values for a rotation.\n */\n __findAngle([p1x, p1y], [p2x, p2y]) {\n const n = euclidean([p1x, p1y], [p2x, p2y]);\n if (n === 0)\n return {\n sin: 0,\n cos: 1,\n };\n const vec = [(p2x - p1x) / n, (p2y - p1y) / n];\n const cos = vec[0];\n let sin = Math.sqrt(1 - cos * cos);\n sin = vec[1] >= 0 ? -sin : sin;\n return {\n sin: sin,\n cos: cos,\n };\n }\n\n /**\n * @private\n * @param {Float64Array[]} hull\n * @param {Float64Array} p\n * @param {boolean} topEdge\n * @returns {{ sin: number; cos: number; tx: number; ty: number }}\n */\n __align_hull(hull, p, topEdge) {\n let v = -1;\n /** @type {number} */\n let d2 = -Infinity;\n for (let i = 0; i < hull.length; ++i) {\n const d = euclidean(hull[i], p);\n if (v === -1) {\n d2 = d;\n v = i;\n } else {\n if (d2 > d) {\n d2 = d;\n v = i;\n }\n }\n }\n\n const v1 = hull[v];\n let v2;\n if (topEdge) {\n v2 = hull[(v + 1) % hull.length];\n } else {\n v2 = hull[(v - 1 + hull.length) % hull.length];\n }\n\n /** @type {{ sin?: number; cos?: number; tx: number; ty: number }} */\n const transformation = {\n tx: -v1[0],\n ty: -v1[1],\n };\n\n if (hull.length >= 2) {\n const { sin, cos } = this.__findAngle(v1, v2);\n transformation.sin = sin;\n transformation.cos = cos;\n } else {\n transformation.sin = 0;\n transformation.cos = 1;\n }\n\n return /** @type {{ sin: number; cos: number; tx: number; ty: number }} */ (transformation);\n }\n\n /**\n * @private\n * @param {Float64Array} Point - The point which should get transformed.\n * @param {{ sin: number; cos: number; tx: number; ty: number }} Transformation - Contains the values for\n * translation and rotation.\n */\n __transform([px, py], { tx, ty, sin, cos }) {\n const x = px + tx;\n const y = py + ty;\n const xx = x * cos - y * sin;\n const yy = x * sin + y * cos;\n return [xx, yy];\n }\n\n /**\n * Calls `__transform` for each point in Set C\n *\n * @private\n * @param {Float64Array[]} C - Set of points.\n * @param {{ sin: number; cos: number; tx: number; ty: number }} t - Transform object.\n * @param {number} yOffset - Value to offset set C.\n */\n __transform_component(C, t, yOffset) {\n const N = C.length;\n for (let i = 0; i < N; ++i) {\n const c = C[i];\n const [cx, cy] = this.__transform(c, t);\n c[0] = cx;\n c[1] = cy + yOffset;\n }\n }\n\n /**\n * @private\n * @param {Float64Array} root_u - Root of component u\n * @param {Float64Array} root_v - Root of component v\n * @param {Float64Array} p_u - Point u\n * @param {Float64Array} p_v - Point v\n * @param {number} w - Edge weight w\n * @param {DisjointSet} components - The disjoint set containing the components\n */\n __align_components(root_u, root_v, p_u, p_v, w, components) {\n if (!components) throw new Error(\"components not provided!\");\n const u_children = components.get_children(root_u);\n const v_children = components.get_children(root_v);\n if (!u_children || !v_children) throw new Error(\"should not happen!\");\n\n const points_u = [...u_children];\n const points_v = [...v_children];\n\n const hull_u = this.__hull(points_u);\n const hull_v = this.__hull(points_v);\n\n const t_u = this.__align_hull(hull_u, p_u, false);\n const t_v = this.__align_hull(hull_v, p_v, true);\n\n this.__transform_component(points_u, t_u, 0);\n this.__transform_component(points_v, t_v, w);\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality 2.\n *\n * @returns {T}\n */\n transform() {\n if (!this._is_initialized) this.init();\n if (!this._Emst) throw new Error(\"Call init() first!\");\n const Emst = this._Emst;\n const Y = this.Y.to2dArray();\n /** @type {DisjointSet} */\n const components = new DisjointSet(\n Y,\n // Y.map((y, i) => {\n // y.i = i;\n // return y;\n // }),\n );\n\n for (const [u, v, w] of Emst) {\n const p_u = Y[u];\n const p_v = Y[v];\n const component_u = components.find(p_u);\n const component_v = components.find(p_v);\n if (!component_u || !component_v) throw new Error(\"Should not happen!\");\n if (component_u === component_v) continue;\n this.__align_components(component_u, component_v, p_u, p_v, w, components);\n components.union(component_u, component_v);\n }\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality 2.\n *\n * @returns {Generator}\n */\n *generator() {\n if (!this._is_initialized) this.init();\n if (!this._Emst) throw new Error(\"call init() first!\");\n const Emst = this._Emst;\n const Y = this.Y.to2dArray();\n const components = new DisjointSet(\n Y,\n // Y.map((y, i) => {\n // y.i = i;\n // return y;\n // }),\n );\n\n for (const [u, v, w] of Emst) {\n const p_u = Y[u];\n const p_v = Y[v];\n const component_u = components.find(p_u);\n const component_v = components.find(p_v);\n if (!component_u || !component_v) throw new Error(\"should not happen!\");\n if (component_u === component_v) continue;\n this.__align_components(component_u, component_v, p_u, p_v, w, components);\n components.union(component_u, component_v);\n yield this.projection;\n }\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new TopoMap(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new TopoMap(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new TopoMap(X, parameters);\n return dr.transform_async();\n }\n}\n","import { BallTree } from \"../knn/index.js\";\nimport { linspace, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\nimport { PCA } from \"./PCA.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersTriMap} from \"./index.js\" */\n/** @import {KNN} from \"../knn/KNN.js\" */\n\n/**\n * TriMap\n *\n * A dimensionality reduction technique that preserves both local and global\n * structure using triplets. It is designed to be a more robust alternative\n * to t-SNE and UMAP.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class TriMap extends DR {\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n * @see {@link https://arxiv.org/pdf/1910.00204v1.pdf}\n * @see {@link https://github.com/eamid/trimap}\n */\n constructor(X, parameters) {\n super(\n X,\n {\n weight_adj: 500,\n n_inliers: 10,\n n_outliers: 5,\n n_random: 5,\n d: 2,\n metric: euclidean,\n tol: 1e-8,\n seed: 1212,\n },\n parameters,\n );\n }\n\n /**\n * @param {Matrix | null} [pca=null] - Initial Embedding (if null then PCA gets used). Default is `null`\n * @param {import(\"../knn/KNN.js\").KNN | null} [knn=null] - KNN Object (if null then BallTree gets used). Default is `null`\n */\n init(pca = null, knn = null) {\n const X = this.X;\n const N = X.shape[0];\n //const c = /** @type {number} */ (this._parameters.c);\n const d = /** @type {number} */ (this._parameters.d);\n const metric = /** @type {Metric} */ (this._parameters.metric);\n const seed = /** @type {number} */ (this._parameters.seed);\n this.n_inliers = /** @type {number} */ (this._parameters.n_inliers);\n this.n_outliers = /** @type {number} */ (this._parameters.n_outliers);\n this.n_random = /** @type {number} */ (this._parameters.n_random);\n this.Y = pca ?? PCA.transform(X, { d, seed });\n this.knn = knn ?? new BallTree(X.to2dArray(), { metric, seed });\n const { triplets, weights } = this._generate_triplets(this.n_inliers, this.n_outliers, this.n_random);\n this.triplets = triplets;\n this.weights = weights;\n this.lr = (1000 * N) / triplets.shape[0];\n this.C = Infinity;\n this.vel = new Matrix(N, d, 0);\n this.gain = new Matrix(N, d, 1);\n return this;\n }\n\n /**\n * Generates {@link n_inliers} x {@link n_outliers} x {@link n_random} triplets.\n *\n * @param {number} n_inliers\n * @param {number} n_outliers\n * @param {number} n_random\n */\n _generate_triplets(n_inliers, n_outliers, n_random) {\n const metric = /** @type {Metric} */ (this._parameters.metric);\n const weight_adj = /** @type {number} */ (this._parameters.weight_adj);\n const X = this.X;\n const N = X.shape[0];\n const knn = this.knn;\n if (!knn) throw new Error(\"Call init() first!\");\n const n_extra = Math.min(n_inliers + 20, N);\n const nbrs = new Matrix(N, n_extra);\n const knn_distances = new Matrix(N, n_extra);\n for (let i = 0; i < N; ++i) {\n const results = knn\n .search(X.row(i), n_extra + 1)\n .filter((d) => d.distance !== 0)\n .sort((a, b) => a.distance - b.distance);\n\n results.forEach((d, j) => {\n if (j < n_extra) {\n nbrs.set_entry(i, j, d.index);\n knn_distances.set_entry(i, j, d.distance);\n }\n });\n }\n // scale parameter\n const sig = new Float64Array(N);\n for (let i = 0; i < N; ++i) {\n sig[i] = Math.max(\n (knn_distances.entry(i, 3) + knn_distances.entry(i, 4) + knn_distances.entry(i, 5)) / 3,\n 1e-10,\n );\n }\n\n const P = this._find_p(knn_distances, sig, nbrs);\n\n let triplets = this._sample_knn_triplets(P, nbrs, n_inliers, n_outliers);\n let n_triplets = triplets.shape[0];\n const outlier_distances = new Float64Array(n_triplets);\n for (let i = 0; i < n_triplets; ++i) {\n const j = triplets.entry(i, 0);\n const k = triplets.entry(i, 2);\n outlier_distances[i] = metric(X.row(j), X.row(k));\n }\n let weights = this._find_weights(triplets, P, nbrs, outlier_distances, sig);\n\n if (n_random > 0) {\n const { random_triplets, random_weights } = this._sample_random_triplets(X, n_random, sig);\n triplets = triplets.concat(random_triplets, \"vertical\");\n weights = Float64Array.from([...weights, ...random_weights]);\n }\n n_triplets = triplets.shape[0];\n let max_weight = -Infinity;\n for (let i = 0; i < n_triplets; ++i) {\n if (Number.isNaN(weights[i])) {\n weights[i] = 0;\n }\n if (max_weight < weights[i]) max_weight = weights[i];\n }\n let max_weight_2 = -Infinity;\n for (let i = 0; i < n_triplets; ++i) {\n weights[i] /= max_weight;\n weights[i] += 0.0001;\n weights[i] = Math.log(1 + weight_adj * weights[i]);\n if (max_weight_2 < weights[i]) max_weight_2 = weights[i];\n }\n for (let i = 0; i < n_triplets; ++i) {\n weights[i] /= max_weight_2;\n }\n return {\n triplets: triplets,\n weights: weights,\n };\n }\n\n /**\n * Calculates the similarity matrix P\n *\n * @private\n * @param {Matrix} knn_distances - Matrix of pairwise knn distances\n * @param {Float64Array} sig - Scaling factor for the distances\n * @param {Matrix} nbrs - Nearest neighbors\n * @returns {Matrix} Pairwise similarity matrix\n */\n _find_p(knn_distances, sig, nbrs) {\n const [N, n_neighbors] = knn_distances.shape;\n return new Matrix(N, n_neighbors, (i, j) => {\n return Math.exp(-(knn_distances.entry(i, j) ** 2 / sig[i] / sig[nbrs.entry(i, j)]));\n });\n }\n\n /**\n * Sample nearest neighbors triplets based on the similarity values given in P.\n *\n * @private\n * @param {Matrix} P - Matrix of pairwise similarities between each point and its neighbors given in matrix nbrs.\n * @param {Matrix} nbrs - Nearest neighbors indices for each point. The similarity values are given in matrix\n * {@link P}. Row i corresponds to the i-th point.\n * @param {number} n_inliers - Number of inlier points.\n * @param {number} n_outliers - Number of outlier points.\n */\n _sample_knn_triplets(P, nbrs, n_inliers, n_outliers) {\n const N = nbrs.shape[0];\n const triplets_list = [];\n for (let i = 0; i < N; ++i) {\n const sort_indices = this.__argsort(P.row(i));\n for (let j = 0; j < n_inliers; ++j) {\n const sim = nbrs.entry(i, sort_indices[sort_indices[j] === i ? j + 1 : j]);\n const rejects = [i, ...Array.from(sort_indices.slice(0, j + 2)).map((idx) => nbrs.entry(i, idx))];\n const samples = this._rejection_sample(n_outliers, N, rejects);\n for (let k = 0; k < samples.length; ++k) {\n const out = samples[k];\n triplets_list.push([i, sim, out]);\n }\n }\n }\n const triplets = new Matrix(triplets_list.length, 3);\n for (let t = 0; t < triplets_list.length; ++t) {\n triplets.set_entry(t, 0, triplets_list[t][0]);\n triplets.set_entry(t, 1, triplets_list[t][1]);\n triplets.set_entry(t, 2, triplets_list[t][2]);\n }\n return triplets;\n }\n\n /**\n * Should do the same as np.argsort()\n *\n * @private\n * @param {Float64Array | number[]} A\n */\n __argsort(A) {\n return linspace(0, A.length - 1).sort((i, j) => A[j] - A[i]);\n }\n\n /**\n * Samples {@link n_samples} integers from a given interval [0, {@link max_int}] while rejection the values that are\n * in the {@link rejects}.\n *\n * @private\n * @param {number} n_samples\n * @param {number} max_int\n * @param {number[]} rejects\n */\n _rejection_sample(n_samples, max_int, rejects) {\n const randomizer = this._randomizer;\n const interval = linspace(0, max_int - 1).filter((d) => rejects.indexOf(d) < 0);\n return randomizer.choice(interval, Math.min(n_samples, interval.length));\n }\n\n /**\n * Calculates the weights for the sampled nearest neighbors triplets\n *\n * @private\n * @param {Matrix} triplets - Sampled Triplets.\n * @param {Matrix} P - Pairwise similarity matrix.\n * @param {Matrix} nbrs - Nearest Neighbors\n * @param {Float64Array} outlier_distances - Matrix of pairwise outlier distances\n * @param {Float64Array} sig - Scaling factor for the distances.\n */\n _find_weights(triplets, P, nbrs, outlier_distances, sig) {\n const n_triplets = triplets.shape[0];\n const weights = new Float64Array(n_triplets);\n for (let t = 0; t < n_triplets; ++t) {\n const i = triplets.entry(t, 0);\n const sim = nbrs.row(i).indexOf(triplets.entry(t, 1));\n const p_sim = P.entry(i, sim);\n let p_out = Math.exp(-(outlier_distances[t] ** 2 / (sig[i] * sig[triplets.entry(t, 2)])));\n if (p_out < 1e-20) p_out = 1e-20;\n weights[t] = p_sim / p_out;\n }\n return weights;\n }\n\n /**\n * Sample uniformly ranom triplets\n *\n * @private\n * @param {Matrix} X - Data matrix.\n * @param {number} n_random - Number of random triplets per point\n * @param {Float64Array} sig - Scaling factor for the distances\n */\n _sample_random_triplets(X, n_random, sig) {\n const metric = /** @type {Metric} */ (this.parameter(\"metric\"));\n const randomizer = this._randomizer;\n const N = X.shape[0];\n const random_triplets = new Matrix(N * n_random, 3);\n const random_weights = new Float64Array(N * n_random);\n for (let i = 0; i < N; ++i) {\n const n_i = i * n_random;\n const indices = Array.from({ length: N }, (_, idx) => idx).filter((idx) => idx !== i);\n for (let j = 0; j < n_random; ++j) {\n let [sim, out] = randomizer.choice(indices, 2);\n let p_sim = Math.exp(-(metric(X.row(i), X.row(sim)) ** 2 / (sig[i] * sig[sim])));\n if (p_sim < 1e-20) p_sim = 1e-20;\n let p_out = Math.exp(-(metric(X.row(i), X.row(out)) ** 2 / (sig[i] * sig[out])));\n if (p_out < 1e-20) p_out = 1e-20;\n\n if (p_sim < p_out) {\n [sim, out] = [out, sim];\n [p_sim, p_out] = [p_out, p_sim];\n }\n const index = n_i + j;\n random_triplets.set_entry(index, 0, i);\n random_triplets.set_entry(index, 1, sim);\n random_triplets.set_entry(index, 2, out);\n random_weights[index] = 0.1 * (p_sim / p_out);\n }\n }\n return {\n random_triplets: random_triplets,\n random_weights: random_weights,\n };\n }\n\n /**\n * Computes the gradient for updating the embedding.\n *\n * @param {Matrix} Y - The embedding\n */\n _grad(Y) {\n const n_inliers = this.n_inliers;\n const n_outliers = this.n_outliers;\n const triplets = this.triplets;\n const weights = this.weights;\n if (!triplets || n_inliers === undefined || n_outliers === undefined || !weights)\n throw new Error(\"Call init() first!\");\n const [N, dim] = Y.shape;\n const n_triplets = triplets.shape[0];\n const grad = new Matrix(N, dim, 0);\n const y_ij = new Float64Array(dim);\n const y_ik = new Float64Array(dim);\n let d_ij = 1;\n let d_ik = 1;\n let n_viol = 0;\n let loss = 0;\n const n_knn_triplets = N * n_inliers * n_outliers;\n\n for (let t = 0; t < n_triplets; ++t) {\n const [i, j, k] = triplets.row(t);\n // update y_ij, y_ik, d_ij, d_ik\n if (t % n_outliers === 0 || t >= n_knn_triplets) {\n d_ij = 1;\n d_ik = 1;\n for (let d = 0; d < dim; ++d) {\n const Y_id = Y.entry(i, d);\n const Y_jd = Y.entry(j, d);\n const Y_kd = Y.entry(k, d);\n y_ij[d] = Y_id - Y_jd;\n y_ik[d] = Y_id - Y_kd;\n d_ij += y_ij[d] ** 2;\n d_ik += y_ik[d] ** 2;\n }\n // update y_ik and d_ik only\n } else {\n d_ik = 1;\n for (let d = 0; d < dim; ++d) {\n const Y_id = Y.entry(i, d);\n const Y_kd = Y.entry(k, d);\n y_ik[d] = Y_id - Y_kd;\n d_ik += y_ik[d] ** 2;\n }\n }\n\n if (d_ij > d_ik) ++n_viol;\n loss += weights[t] / (1 + d_ik / d_ij);\n const w = weights[t] / (d_ij + d_ik) ** 2;\n for (let d = 0; d < dim; ++d) {\n const gs = y_ij[d] * d_ik * w;\n const go = y_ik[d] * d_ij * w;\n grad.add_entry(i, d, gs - go);\n grad.sub_entry(j, d, gs);\n grad.add_entry(k, d, go);\n }\n }\n return { grad, loss, n_viol };\n }\n\n /**\n * @param {number} max_iteration\n * @returns {T}\n */\n transform(max_iteration = 800) {\n this.check_init();\n for (let iter = 0; iter < max_iteration; ++iter) {\n this._next(iter);\n }\n return this.projection;\n }\n\n /**\n * @param {number} max_iteration\n * @returns {Generator}\n */\n *generator(max_iteration = 800) {\n this.check_init();\n for (let iter = 0; iter < max_iteration; ++iter) {\n this._next(iter);\n yield this.projection;\n }\n return this.projection;\n }\n\n /**\n * Does the iteration step.\n *\n * @private\n * @param {number} iter\n */\n _next(iter) {\n const gamma = iter > 250 ? 0.5 : 0.3;\n const old_C = this.C;\n const vel = this.vel;\n if (!vel || old_C === undefined || this.lr === undefined) throw new Error(\"Call init() first!\");\n const Y = this.Y.add(vel.mult(gamma));\n const { grad, loss } = this._grad(Y);\n this.C = loss;\n this.Y = this._update_embedding(Y, iter, grad);\n const tol = /** @type {number} */ (this.parameter(\"tol\"));\n this.lr *= old_C > loss + tol ? 1.01 : 0.9;\n return this.Y;\n }\n\n /**\n * Updates the embedding.\n *\n * @private\n * @param {Matrix} Y\n * @param {number} iter\n * @param {Matrix} grad\n */\n _update_embedding(Y, iter, grad) {\n const [N, dim] = Y.shape;\n const gamma = iter > 250 ? 0.8 : 0.5; // moment parameter\n const min_gain = 0.01;\n const gain = this.gain;\n const vel = this.vel;\n const lr = this.lr;\n if (!vel || !gain || lr === undefined) throw new Error(\"Call init() first!\");\n for (let i = 0; i < N; ++i) {\n for (let d = 0; d < dim; ++d) {\n const new_gain =\n Math.sign(vel.entry(i, d)) !== Math.sign(grad.entry(i, d))\n ? gain.entry(i, d) + 0.2\n : Math.max(gain.entry(i, d) * 0.8, min_gain);\n gain.set_entry(i, d, new_gain);\n vel.set_entry(i, d, gamma * vel.entry(i, d) - lr * gain.entry(i, d) * grad.entry(i, d));\n Y.set_entry(i, d, Y.entry(i, d) + vel.entry(i, d));\n }\n }\n return Y;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new TriMap(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new TriMap(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new TriMap(X, parameters);\n return dr.transform_async();\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { euclidean_squared } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersTSNE} from \"./index.js\" */\n/**\n * t-SNE (t-Distributed Stochastic Neighbor Embedding)\n *\n * A nonlinear dimensionality reduction technique particularly well-suited\n * for visualizing high-dimensional data in 2D or 3D. Preserves local\n * structure while revealing global patterns.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link https://lvdmaaten.github.io/tsne/|t-SNE Paper}\n * @see {@link UMAP} for faster alternative with similar results\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];\n * const tsne = new druid.TSNE(X, {\n * perplexity: 30,\n * epsilon: 10,\n * d: 2,\n * seed: 42\n * });\n *\n * const Y = tsne.transform(500); // 500 iterations\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class TSNE extends DR {\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X, parameters) {\n super(\n X,\n {\n perplexity: 50,\n epsilon: 10,\n d: 2,\n metric: euclidean_squared,\n seed: 1212,\n },\n parameters,\n );\n [this._N, this._D] = this.X.shape;\n this._iter = 0;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n this.Y = new Matrix(this._N, d, () => this._randomizer.gauss_random() * 1e-4);\n }\n\n init() {\n // init\n const perplexity = /** @type {number} */ (this.parameter(\"perplexity\"));\n const Htarget = Math.log(perplexity);\n const N = this._N;\n const D = this._D;\n const metric = /** @type {Metric | \"precomputed\"} */ (this._parameters.metric);\n const X = this.X;\n let Delta;\n if (metric === \"precomputed\") {\n Delta = Matrix.from(X);\n } else {\n Delta = new Matrix(N, N);\n for (let i = 0; i < N; ++i) {\n const X_i = X.row(i);\n for (let j = i + 1; j < N; ++j) {\n const distance = metric(X_i, X.row(j));\n Delta.set_entry(i, j, distance);\n Delta.set_entry(j, i, distance);\n }\n }\n }\n\n const P = new Matrix(N, N, 0);\n\n this._ystep = new Matrix(N, D, 0);\n this._gains = new Matrix(N, D, 1);\n\n // search for fitting sigma\n const tol = 1e-4;\n const maxtries = 50;\n for (let i = 0; i < N; ++i) {\n const dist_i = Delta.row(i);\n const prow = P.row(i);\n let betamin = -Infinity;\n let betamax = Infinity;\n let beta = 1;\n let cnt = maxtries;\n let done = false;\n let psum = 0;\n\n while (!done && cnt--) {\n // compute entropy and kernel row with beta precision\n psum = 0;\n let dp_sum = 0;\n for (let j = 0; j < N; ++j) {\n const dist = dist_i[j];\n const pj = i !== j ? Math.exp(-dist * beta) : 0;\n dp_sum += dist * pj;\n prow[j] = pj;\n psum += pj;\n }\n // compute entropy\n const H = psum > 0 ? Math.log(psum) + (beta * dp_sum) / psum : 0;\n if (H > Htarget) {\n betamin = beta;\n beta = betamax === Infinity ? beta * 2 : (beta + betamax) / 2;\n } else {\n betamax = beta;\n beta = betamin === -Infinity ? beta / 2 : (beta + betamin) / 2;\n }\n done = Math.abs(H - Htarget) < tol;\n }\n // normalize p\n for (let j = 0; j < N; ++j) {\n prow[j] /= psum;\n }\n }\n\n // compute probabilities\n const N2 = N * 2;\n for (let i = 0; i < N; ++i) {\n for (let j = i; j < N; ++j) {\n const p = Math.max((P.entry(i, j) + P.entry(j, i)) / N2, 1e-100);\n P.set_entry(i, j, p);\n P.set_entry(j, i, p);\n }\n }\n this._P = P;\n return this;\n }\n\n /**\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {T} The projection.\n */\n transform(iterations = 500) {\n this.check_init();\n for (let i = 0; i < iterations; ++i) {\n this.next();\n }\n return this.projection;\n }\n\n /**\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {Generator} - The projection.\n */\n *generator(iterations = 500) {\n this.check_init();\n for (let i = 0; i < iterations; ++i) {\n this.next();\n yield this.projection;\n }\n return this.projection;\n }\n\n /**\n * Performs a optimization step\n *\n * @private\n * @returns {Matrix}\n */\n next() {\n const iter = ++this._iter;\n if (!this._P || !this._ystep || !this._gains) throw new Error(\"Call init() first!\");\n const P = this._P;\n const ystep = this._ystep;\n const gains = this._gains;\n const N = this._N;\n const dim = /** @type {number} */ (this._parameters.d);\n const epsilon = /** @type {number} */ (this._parameters.epsilon);\n const Y = this.Y;\n\n //calc cost gradient;\n const pmul = iter < 100 ? 4 : 1;\n\n // compute Q dist (unnormalized)\n const Qu = new Matrix(N, N, \"zeros\");\n let qsum = 0;\n for (let i = 0; i < N; ++i) {\n for (let j = i + 1; j < N; ++j) {\n let dsum = 0;\n for (let d = 0; d < dim; ++d) {\n const dhere = Y.entry(i, d) - Y.entry(j, d);\n dsum += dhere * dhere;\n }\n const qu = 1 / (1 + dsum);\n Qu.set_entry(i, j, qu);\n Qu.set_entry(j, i, qu);\n qsum += 2 * qu;\n }\n }\n\n // normalize Q dist\n const Q = new Matrix(N, N, 0);\n for (let i = 0; i < N; ++i) {\n for (let j = i + 1; j < N; ++j) {\n const val = Math.max(Qu.entry(i, j) / qsum, 1e-100);\n Q.set_entry(i, j, val);\n Q.set_entry(j, i, val);\n }\n }\n\n const grad = new Matrix(N, dim, \"zeros\");\n for (let i = 0; i < N; ++i) {\n for (let j = 0; j < N; ++j) {\n const premult = 4 * (pmul * P.entry(i, j) - Q.entry(i, j)) * Qu.entry(i, j);\n for (let d = 0; d < dim; ++d) {\n grad.add_entry(i, d, premult * (Y.entry(i, d) - Y.entry(j, d)));\n }\n }\n }\n\n // perform gradient step\n const ymean = new Float64Array(dim);\n for (let i = 0; i < N; ++i) {\n for (let d = 0; d < dim; ++d) {\n const gid = grad.entry(i, d);\n const sid = ystep.entry(i, d);\n const gainid = gains.entry(i, d);\n\n let newgain = Math.sign(gid) === Math.sign(sid) ? gainid * 0.8 : gainid + 0.2;\n if (newgain < 0.01) newgain = 0.01;\n gains.set_entry(i, d, newgain);\n\n const momval = iter < 250 ? 0.5 : 0.8;\n const newsid = momval * sid - epsilon * newgain * gid;\n ystep.set_entry(i, d, newsid);\n\n Y.add_entry(i, d, newsid);\n ymean[d] += Y.entry(i, d);\n }\n }\n\n for (let i = 0; i < N; ++i) {\n for (let d = 0; d < dim; ++d) {\n Y.sub_entry(i, d, ymean[d] / N);\n }\n }\n\n return this.Y;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new TSNE(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new TSNE(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new TSNE(X, parameters);\n return dr.transform_async();\n }\n}\n","/**\n * @template {Float64Array | number[]} T\n * @category Optimization\n * @param {(d: T) => number} f\n * @param {T} x0\n * @param {number} [max_iter=300] Default is `300`\n * @returns {T}\n * @see http://optimization-js.github.io/optimization-js/optimization.js.html#line438\n */\nexport function powell(f, x0, max_iter = 300) {\n const epsilon = 1e-2;\n const n = x0.length;\n let alpha = 1e-3;\n let pfx = 10000;\n const x = /** @type {T} */ (x0.slice());\n let fx = f(x);\n let convergence = false;\n\n while (max_iter-- >= 0 && !convergence) {\n convergence = true;\n for (let i = 0; i < n; ++i) {\n x[i] += 1e-6;\n const fxi = f(x);\n x[i] -= 1e-6;\n const dx = (fxi - fx) / 1e-6;\n if (Math.abs(dx) > epsilon) {\n convergence = false;\n }\n x[i] -= alpha * dx;\n fx = f(x);\n }\n alpha *= pfx >= fx ? 1.05 : 0.4;\n pfx = fx;\n }\n return x;\n}\n","import { BallTree, NaiveKNN } from \"../knn/index.js\";\nimport { linspace, Matrix } from \"../matrix/index.js\";\nimport { euclidean, euclidean_squared } from \"../metrics/index.js\";\nimport { neumair_sum } from \"../numerical/index.js\";\nimport { powell } from \"../optimization/index.js\";\nimport { max } from \"../util/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersUMAP} from \"./index.js\" */\n\n/**\n * Uniform Manifold Approximation and Projection (UMAP)\n *\n * A novel manifold learning technique for dimensionality reduction. UMAP is constructed\n * from a theoretical framework based on Riemannian geometry and algebraic topology.\n * It is often faster than t-SNE while preserving more of the global structure.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link https://arxiv.org/abs/1802.03426|UMAP Paper}\n * @see {@link TSNE} for a similar visualization technique\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];\n * const umap = new druid.UMAP(X, {\n * n_neighbors: 15,\n * min_dist: 0.1,\n * d: 2,\n * seed: 42\n * });\n *\n * const Y = umap.transform(500); // 500 iterations\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class UMAP extends DR {\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X, parameters) {\n super(\n X,\n {\n n_neighbors: 15,\n local_connectivity: 1,\n min_dist: 1,\n d: 2,\n metric: euclidean,\n seed: 1212,\n _spread: 1,\n _set_op_mix_ratio: 1,\n _repulsion_strength: 1,\n _negative_sample_rate: 5,\n _n_epochs: 350,\n _initial_alpha: 1,\n },\n parameters,\n );\n [this._N, this._D] = this.X.shape;\n const n_neighbors = /** @type {number} */ (this.parameter(\"n_neighbors\"));\n const local_connectivity = /** @type {number} */ (this.parameter(\"local_connectivity\"));\n const d = /** @type {number} */ (this.parameter(\"d\"));\n /* let n_neighbors = Math.min(this._N - 1, parameters.n_neighbors);\n this.parameter(\"n_neighbors\", n_neighbors);\n this.parameter(\"local_connectivity\", Math.min(this.parameter(\"local_connectivity\"), n_neighbors - 1)); */\n if (n_neighbors > this._N) {\n throw new Error(\n `Parameter n_neighbors (=${n_neighbors}) needs to be smaller than dataset size (N=${this._N})!`,\n );\n }\n if (local_connectivity > n_neighbors) {\n throw new Error(\n `Parameter local_connectivity (=${local_connectivity}) needs to be smaller than parameter n_neighbors (=${n_neighbors})`,\n );\n }\n this._iter = 0;\n const randomizer = this._randomizer;\n this.Y = new Matrix(this._N, d, () => randomizer.random);\n }\n\n /**\n * @private\n * @param {number} spread\n * @param {number} min_dist\n * @returns {number[]}\n */\n _find_ab_params(spread, min_dist) {\n /** @type {(x: number, a: number, b: number) => number} */\n const curve = (x, a, b) => 1 / (1 + a * x ** (2 * b));\n const xv = linspace(0, spread * 3, 300);\n const yv = linspace(0, spread * 3, 300);\n\n for (let i = 0, n = xv.length; i < n; ++i) {\n const xv_i = xv[i];\n yv[i] = xv_i < min_dist ? 1 : Math.exp(-(xv_i - min_dist) / spread);\n }\n\n /** @type {(p: [number, number]) => number} */\n const err = (p) => {\n const error = linspace(1, 300).map((_, i) => yv[i] - curve(xv[i], p[0], p[1]));\n return Math.sqrt(neumair_sum(error.map((e) => e * e)));\n };\n\n return powell(err, [1, 1]);\n }\n\n /**\n * @private\n * @param {{ element: Float64Array; index: number; distance: number }[][]} distances\n * @param {number[]} sigmas\n * @param {number[]} rhos\n * @returns {{ element: Float64Array; index: number; distance: number }[][]}\n */\n _compute_membership_strengths(distances, sigmas, rhos) {\n for (let i = 0, n = distances.length; i < n; ++i) {\n const rho = rhos[i];\n const curr_dist = distances[i];\n for (let j = 0, m = curr_dist.length; j < m; ++j) {\n const v = curr_dist[j].distance - rho;\n curr_dist[j].distance = v > 0 ? Math.exp(-v / sigmas[i]) : 1.0;\n }\n }\n return distances;\n }\n\n /**\n * @private\n * @param {NaiveKNN | BallTree} knn\n * @param {number} k\n * @returns {{\n * distances: { element: Float64Array; index: number; distance: number }[][];\n * sigmas: number[];\n * rhos: number[];\n * }}\n */\n _smooth_knn_dist(knn, k) {\n const SMOOTH_K_TOLERANCE = 1e-5;\n const MIN_K_DIST_SCALE = 1e-3;\n const n_iter = 64;\n const local_connectivity = /** @type {number} */ (this._parameters.local_connectivity);\n const metric = /** @type {Metric | \"precomputed\"} */ (this._parameters.metric);\n const target = Math.log2(k);\n const rhos = [];\n const sigmas = [];\n const X = this.X;\n const N = X.shape[0];\n //const distances = [...X].map(x_i => knn.search(x_i, k).raw_data().reverse());\n\n /** @type {{ element: Float64Array; index: number; distance: number }[][]} */\n const distances = [];\n if (metric === \"precomputed\" || knn instanceof NaiveKNN) {\n for (let i = 0; i < N; ++i) {\n distances.push(knn.search_by_index(i, k).reverse());\n }\n } else {\n for (const x_i of X) {\n distances.push(knn.search(x_i, k).reverse());\n }\n }\n\n const index = Math.floor(local_connectivity);\n const interpolation = local_connectivity - index;\n for (let i = 0; i < N; ++i) {\n let lo = 0;\n let hi = Infinity;\n let mid = 1;\n let rho = 0;\n\n const search_result = distances[i];\n const non_zero_dist = search_result.filter((d) => d.distance > 0);\n const non_zero_dist_length = non_zero_dist.length;\n if (non_zero_dist_length >= local_connectivity) {\n if (index > 0) {\n rho = non_zero_dist[index - 1].distance;\n if (interpolation > SMOOTH_K_TOLERANCE) {\n rho += interpolation * (non_zero_dist[index].distance - non_zero_dist[index - 1].distance);\n }\n } else {\n rho = interpolation * non_zero_dist[0].distance;\n }\n } else if (non_zero_dist_length > 0) {\n rho = non_zero_dist[non_zero_dist_length - 1].distance;\n }\n for (let x = 0; x < n_iter; ++x) {\n let psum = 0;\n for (let j = 0; j < k; ++j) {\n const d = search_result[j].distance - rho;\n psum += d > 0 ? Math.exp(-(d / mid)) : 1;\n }\n if (Math.abs(psum - target) < SMOOTH_K_TOLERANCE) {\n break;\n }\n if (psum > target) {\n [hi, mid] = [mid, (lo + hi) / 2];\n } else {\n if (hi === Infinity) {\n [lo, mid] = [mid, mid * 2];\n } else {\n [lo, mid] = [mid, (lo + hi) / 2];\n }\n }\n }\n\n //let mean_d = null;\n if (rho > 0) {\n const mean_ithd = search_result.reduce((a, b) => a + b.distance, 0) / search_result.length;\n if (mid < MIN_K_DIST_SCALE * mean_ithd) {\n mid = MIN_K_DIST_SCALE * mean_ithd;\n }\n } else {\n const mean_d = distances.reduce(\n (acc, res) => acc + res.reduce((a, b) => a + b.distance, 0) / res.length,\n 0,\n );\n if (mid < MIN_K_DIST_SCALE * mean_d) {\n mid = MIN_K_DIST_SCALE * mean_d;\n }\n }\n rhos[i] = rho;\n sigmas[i] = mid;\n }\n return {\n distances: distances,\n sigmas: sigmas,\n rhos: rhos,\n };\n }\n\n /**\n * @private\n * @param {Matrix} X\n * @param {number} n_neighbors\n * @returns {Matrix}\n */\n _fuzzy_simplicial_set(X, n_neighbors) {\n const N = X.shape[0];\n const metric = /** @type {Metric | \"precomputed\"} */ (this._parameters.metric);\n const _set_op_mix_ratio = /** @type {number} */ (this._parameters._set_op_mix_ratio);\n\n const knn =\n metric === \"precomputed\"\n ? new NaiveKNN(X.to2dArray(), {\n metric: \"precomputed\",\n seed: /** @type {number} */ (this._parameters.seed),\n })\n : new BallTree(X.to2dArray(), {\n metric,\n seed: /** @type {number} */ (this._parameters.seed),\n });\n let { distances, sigmas, rhos } = this._smooth_knn_dist(knn, n_neighbors);\n distances = this._compute_membership_strengths(distances, sigmas, rhos);\n const result = new Matrix(N, N, \"zeros\");\n for (let i = 0; i < N; ++i) {\n const distances_i = distances[i];\n for (let j = 0; j < distances_i.length; ++j) {\n result.set_entry(i, distances_i[j].index, distances_i[j].distance);\n }\n }\n\n const transposed_result = result.T;\n const prod_matrix = result.mult(transposed_result);\n return result\n .add(transposed_result)\n .sub(prod_matrix)\n .mult(_set_op_mix_ratio)\n .add(prod_matrix.mult(1 - _set_op_mix_ratio));\n }\n\n /**\n * @private\n * @param {number} n_epochs\n * @returns {Float32Array}\n */\n _make_epochs_per_sample(n_epochs) {\n if (!this._weights) throw new Error(\"Call init() first!\");\n const weights = this._weights;\n const result = new Float32Array(weights.length).fill(-1);\n const weight_scl = n_epochs / max(weights);\n weights.forEach((w, i) => {\n const sample = w * weight_scl;\n if (sample > 0) result[i] = Math.round(n_epochs / sample);\n });\n return result;\n }\n\n /**\n * @private\n * @param {Matrix} graph\n * @returns {{ rows: number[]; cols: number[]; data: number[] }}\n */\n _tocoo(graph) {\n const rows = [];\n const cols = [];\n const data = [];\n const [rows_n, cols_n] = graph.shape;\n for (let row = 0; row < rows_n; ++row) {\n for (let col = 0; col < cols_n; ++col) {\n const entry = graph.entry(row, col);\n if (entry !== 0) {\n rows.push(row);\n cols.push(col);\n data.push(entry);\n }\n }\n }\n return {\n rows: rows,\n cols: cols,\n data: data,\n };\n }\n\n /**\n * Computes all necessary\n *\n * @returns {UMAP}\n */\n init() {\n const _spread = /** @type {number} */ (this._parameters._spread);\n const min_dist = /** @type {number} */ (this._parameters.min_dist);\n const n_neighbors = /** @type {number} */ (this._parameters.n_neighbors);\n const _n_epochs = /** @type {number} */ (this._parameters._n_epochs);\n const _negative_sample_rate = /** @type {number} */ (this._parameters._negative_sample_rate);\n const [a, b] = this._find_ab_params(_spread, min_dist);\n this._a = a;\n this._b = b;\n this._graph = this._fuzzy_simplicial_set(this.X, n_neighbors);\n const { rows, cols, data: weights } = this._tocoo(this._graph);\n this._head = rows;\n this._tail = cols;\n this._weights = weights;\n this._epochs_per_sample = this._make_epochs_per_sample(_n_epochs);\n this._epochs_per_negative_sample = this._epochs_per_sample.map((d) => d * _negative_sample_rate);\n this._epoch_of_next_sample = this._epochs_per_sample.slice();\n this._epoch_of_next_negative_sample = this._epochs_per_negative_sample.slice();\n return this;\n }\n\n graph() {\n this.check_init();\n return { cols: this._head, rows: this._tail, weights: this._weights };\n }\n\n /**\n * @param {number} [iterations=350] - Number of iterations. Default is `350`\n * @returns {T}\n */\n transform(iterations = 350) {\n if (this.parameter(\"_n_epochs\") !== iterations) {\n this.parameter(\"_n_epochs\", iterations);\n this.init();\n }\n this.check_init();\n for (let i = 0; i < iterations; ++i) {\n this.next();\n }\n return this.projection;\n }\n\n /**\n * @param {number} [iterations=350] - Number of iterations. Default is `350`\n * @returns {Generator}\n */\n *generator(iterations = 350) {\n if (this.parameter(\"_n_epochs\") !== iterations) {\n this.parameter(\"_n_epochs\", iterations);\n this.init();\n }\n this.check_init();\n for (let i = 0; i < iterations; ++i) {\n this.next();\n yield this.projection;\n }\n return this.projection;\n }\n\n /**\n * @private\n * @param {number} x\n * @returns {number}\n */\n _clip(x) {\n if (x > 4) return 4;\n if (x < -4) return -4;\n return x;\n }\n\n /**\n * Performs the optimization step.\n *\n * @private\n * @param {Matrix} head_embedding\n * @param {Matrix} tail_embedding\n * @param {number[]} head\n * @param {number[]} tail\n * @returns {Matrix}\n */\n _optimize_layout(head_embedding, tail_embedding, head, tail) {\n const randomizer = this._randomizer;\n const _repulsion_strength = /** @type {number} */ (this.parameter(\"_repulsion_strength\"));\n const dim = /** @type {number} */ (this.parameter(\"d\"));\n const {\n _alpha: alpha,\n _a: a,\n _b: b,\n _epochs_per_sample: epochs_per_sample,\n _epochs_per_negative_sample: epochs_per_negative_sample,\n _epoch_of_next_negative_sample: epoch_of_next_negative_sample,\n _epoch_of_next_sample: epoch_of_next_sample,\n _clip: clip,\n } = this;\n if (\n alpha === undefined ||\n a === undefined ||\n b === undefined ||\n epochs_per_sample === undefined ||\n epochs_per_negative_sample === undefined ||\n epoch_of_next_negative_sample === undefined ||\n epoch_of_next_sample === undefined ||\n clip === undefined\n ) {\n throw new Error(\"call init() first!\");\n }\n const tail_length = tail.length;\n\n for (let i = 0, n = epochs_per_sample.length; i < n; ++i) {\n if (epoch_of_next_sample[i] <= this._iter) {\n const j = head[i];\n const k = tail[i];\n const current = head_embedding.row(j);\n const other = tail_embedding.row(k);\n const dist = euclidean_squared(current, other);\n if (dist > 0) {\n const grad_coeff = (-2 * a * b * dist ** (b - 1)) / (a * dist ** b + 1);\n for (let d = 0; d < dim; ++d) {\n const grad_d = clip(grad_coeff * (current[d] - other[d])) * alpha;\n current[d] += grad_d;\n other[d] -= grad_d;\n }\n }\n epoch_of_next_sample[i] += epochs_per_sample[i];\n const n_neg_samples = (this._iter - epoch_of_next_negative_sample[i]) / epochs_per_negative_sample[i];\n for (let p = 0; p < n_neg_samples; ++p) {\n const k = randomizer.random_int % tail_length;\n const other = tail_embedding.row(tail[k]);\n const dist = euclidean_squared(current, other);\n if (dist > 0) {\n const grad_coeff = (2 * _repulsion_strength * b) / ((0.01 + dist) * (a * dist ** b + 1));\n for (let d = 0; d < dim; ++d) {\n const grad_d = clip(grad_coeff * (current[d] - other[d])) * alpha;\n current[d] += grad_d;\n other[d] -= grad_d;\n }\n } else if (j === k) {\n }\n }\n epoch_of_next_negative_sample[i] += n_neg_samples * epochs_per_negative_sample[i];\n }\n }\n return head_embedding;\n }\n\n /**\n * @private\n * @returns {Matrix}\n */\n next() {\n if (!this._head || !this._tail) throw new Error(\"Call init() first!\");\n const iter = ++this._iter;\n const Y = this.Y;\n const _initial_alpha = /** @type {number} */ (this._parameters._initial_alpha);\n const _n_epochs = /** @type {number} */ (this._parameters._n_epochs);\n this._alpha = _initial_alpha * (1 - iter / _n_epochs);\n this.Y = this._optimize_layout(Y, Y, this._head, this._tail);\n\n return this.Y;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new UMAP(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new UMAP(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new UMAP(X, parameters);\n return dr.transform_async();\n }\n}\n","import pkg from \"../package.json\" with { type: \"json\" };\n\nconst version = pkg.version;\nexport { version };\n\n/** @import {Matrix} from \"./matrix/index.js\" */\n/** @typedef {Matrix | Float64Array[] | number[][]} InputType*/\n\n//export { version } from \"../package.json\" with { type: \"json\" };\nexport * from \"./clustering/index.js\";\nexport * from \"./datastructure/index.js\";\nexport * from \"./dimred/index.js\";\nexport * from \"./knn/index.js\";\nexport * from \"./linear_algebra/index.js\";\nexport * from \"./matrix/index.js\";\nexport * from \"./metrics/index.js\";\nexport * from \"./numerical/index.js\";\nexport * from \"./optimization/index.js\";\nexport * from \"./util/index.js\";\n"],"names":["qr","qr_gramschmidt"],"mappings":"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"} \ No newline at end of file diff --git a/dist/druid.d.cts b/dist/druid.d.cts index c4b4022..98a599a 100644 --- a/dist/druid.d.cts +++ b/dist/druid.d.cts @@ -172,14 +172,10 @@ declare function distance_matrix(A: Matrix | Float64Array[] | number[][], metric * @param {Metric | "precomputed"} [metric=euclidean] Default is `euclidean` * @returns {{ i: number; j: number; distance: number }[][]} The kNN graph. */ -declare function k_nearest_neighbors( - A: Matrix, - k: number, - metric?: Metric | "precomputed", -): { - i: number; - j: number; - distance: number; +declare function k_nearest_neighbors(A: Matrix, k: number, metric?: Metric | "precomputed"): { + i: number; + j: number; + distance: number; }[][]; /** @@ -216,62 +212,62 @@ declare function min(values: Iterable): number; * @class */ declare class Randomizer { - /** - * @template T Returns samples from an input Matrix or Array. - * @param {T[]} A - The input Matrix or Array. - * @param {number} n - The number of samples. - * @param {number} seed - The seed for the random number generator. - * @returns {T[]} - A random selection form `A` of `n` samples. - */ - static choice(A: T[], n: number, seed?: number): T[]; - /** - * Mersenne Twister random number generator. - * - * @param {number} [_seed=new Date().getTime()] - The seed for the random number generator. If `_seed == null` then - * the actual time gets used as seed. Default is `new Date().getTime()` - * @see https://github.com/bmurray7/mersenne-twister-examples/blob/master/javascript-mersenne-twister.js - */ - constructor(_seed?: number); - _N: number; - _M: number; - _MATRIX_A: number; - _UPPER_MASK: number; - _LOWER_MASK: number; - /** @type {number[]} */ - _mt: number[]; - /** @type {number} */ - _mti: number; - /** @type {number} */ - _seed: number; - /** @type {number} seed */ - set seed(_seed: number); - /** - * Returns the seed of the random number generator. - * - * @returns {number} - The seed. - */ - get seed(): number; - /** - * Returns a float between 0 and 1. - * - * @returns {number} - A random number between [0, 1] - */ - get random(): number; - /** - * Returns an integer between 0 and MAX_INTEGER. - * - * @returns {number} - A random integer. - */ - get random_int(): number; - gauss_random(): number; - _val: number | null | undefined; - /** - * @template T Returns samples from an input Matrix or Array. - * @param {T[]} A - The input Matrix or Array. - * @param {number} n - The number of samples. - * @returns {T[]} A random selection form `A` of `n` samples. - */ - choice(A: T[], n: number): T[]; + /** + * @template T Returns samples from an input Matrix or Array. + * @param {T[]} A - The input Matrix or Array. + * @param {number} n - The number of samples. + * @param {number} seed - The seed for the random number generator. + * @returns {T[]} - A random selection form `A` of `n` samples. + */ + static choice(A: T[], n: number, seed?: number): T[]; + /** + * Mersenne Twister random number generator. + * + * @param {number} [_seed=new Date().getTime()] - The seed for the random number generator. If `_seed == null` then + * the actual time gets used as seed. Default is `new Date().getTime()` + * @see https://github.com/bmurray7/mersenne-twister-examples/blob/master/javascript-mersenne-twister.js + */ + constructor(_seed?: number); + _N: number; + _M: number; + _MATRIX_A: number; + _UPPER_MASK: number; + _LOWER_MASK: number; + /** @type {number[]} */ + _mt: number[]; + /** @type {number} */ + _mti: number; + /** @type {number} */ + _seed: number; + /** @type {number} seed */ + set seed(_seed: number); + /** + * Returns the seed of the random number generator. + * + * @returns {number} - The seed. + */ + get seed(): number; + /** + * Returns a float between 0 and 1. + * + * @returns {number} - A random number between [0, 1] + */ + get random(): number; + /** + * Returns an integer between 0 and MAX_INTEGER. + * + * @returns {number} - A random integer. + */ + get random_int(): number; + gauss_random(): number; + _val: number | null | undefined; + /** + * @template T Returns samples from an input Matrix or Array. + * @param {T[]} A - The input Matrix or Array. + * @param {number} n - The number of samples. + * @returns {T[]} A random selection form `A` of `n` samples. + */ + choice(A: T[], n: number): T[]; } /** @typedef {(i: number, j: number) => number} Accessor */ @@ -280,506 +276,464 @@ declare class Randomizer { * @category Matrix */ declare class Matrix { - /** - * Creates a Matrix out of `A`. - * @param {Matrix | Float64Array[] | number[][]} A - The matrix, array, or number, which should converted to a Matrix. - * @returns {Matrix} - * @example - * let A = Matrix.from([ [1, 0], [0, 1], ]); //creates a two by two identity matrix. - */ - static from(A: Matrix | Float64Array[] | number[][]): Matrix; - /** - * Creates a Matrix with the diagonal being the values of `v`. - * - * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]] - * - * @param {number[] | Float64Array} v - * @returns {Matrix} - */ - static from_diag(v: number[] | Float64Array): Matrix; - /** - * Creates a Matrix with the diagonal being the values of `v`. - * - * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]] - * - * @param {number[] | Float64Array} v - * @param {"col" | "row"} type - * @returns {Matrix} - */ - static from_vector(v: number[] | Float64Array, type: "col" | "row"): Matrix; - /** - * Solves the equation `Ax = b` using the conjugate gradient method. Returns the result `x`. - * - * @param {Matrix} A - Matrix - * @param {Matrix} b - Matrix - * @param {Randomizer | null} [randomizer] - * @param {number} [tol=1e-3] Default is `1e-3` - * @returns {Matrix} - */ - static solve_CG(A: Matrix, b: Matrix, randomizer?: Randomizer | null, tol?: number): Matrix; - /** - * Solves the equation `Ax = b`. Returns the result `x`. - * - * @param {Matrix | { L: Matrix; U: Matrix }} A - Matrix or LU Decomposition - * @param {Matrix} b - Matrix - * @returns {Matrix} - */ - static solve( - A: - | Matrix - | { - L: Matrix; - U: Matrix; - }, - b: Matrix, - ): Matrix; - /** - * `LU` decomposition of the Matrix `A`. Creates two matrices, so that the dot product `LU` equals `A`. - * - * @param {Matrix} A - * @returns {{ L: Matrix; U: Matrix }} The left triangle matrix `L` and the upper triangle matrix `U`. - */ - static LU(A: Matrix): { - L: Matrix; - U: Matrix; - }; - /** - * Computes the determinante of `A`, by using the `LU` decomposition of `A`. - * - * @param {Matrix} A - * @returns {number} The determinate of the Matrix `A`. - */ - static det(A: Matrix): number; - /** - * Computes the `k` components of the SVD decomposition of the matrix `M`. - * - * @param {Matrix} M - * @param {number} [k=2] Default is `2` - * @returns {{ U: Float64Array[]; Sigma: Float64Array; V: Float64Array[] }} - */ - static SVD( - M: Matrix, - k?: number, - ): { - U: Float64Array[]; - Sigma: Float64Array; - V: Float64Array[]; - }; - /** - * @param {unknown} A - * @returns {A is unknown[]|number[]|Float64Array|Float32Array} - */ - static isArray(A: unknown): A is unknown[] | number[] | Float64Array | Float32Array; - /** - * @param {any[]} A - * @returns {A is number[][]|Float64Array[]} - */ - static is2dArray(A: any[]): A is number[][] | Float64Array[]; - /** - * Creates a new Matrix. Entries are stored in a Float64Array. - * - * @example let A = new Matrix(10, 10, () => Math.random()); //creates a 10 times 10 random matrix. let B = new - * Matrix(3, 3, "I"); // creates a 3 times 3 identity matrix. - * - * @param {number} rows - The amount of rows of the matrix. - * @param {number} cols - The amount of columns of the matrix. - * @param {Accessor | string | number} value - Can be a function with row and col as parameters, a number, or - * "zeros", "identity" or "I", or "center". - * - * - **function**: for each entry the function gets called with the parameters for the actual row and column. - * - **string**: allowed are - * - * - "zero", creates a zero matrix. - * - "identity" or "I", creates an identity matrix. - * - "center", creates an center matrix. - * - **number**: create a matrix filled with the given value. - */ - constructor(rows: number, cols: number, value?: Accessor | string | number); - /** @type {number} */ _rows: number; - /** @type {number} */ _cols: number; - /** @type {Float64Array} */ _data: Float64Array; - /** - * Returns the `row`th row from the Matrix. - * - * @param {number} row - * @returns {Float64Array} - */ - row(row: number): Float64Array; - /** - * Returns an generator yielding each row of the Matrix. - * - * @yields {Float64Array} - */ - iterate_rows(): Generator, void, unknown>; - /** - * Sets the entries of `row`th row from the Matrix to the entries from `values`. - * - * @param {number} row - * @param {number[]} values - * @returns {Matrix} - */ - set_row(row: number, values: number[]): Matrix; - /** - * Swaps the rows `row1` and `row2` of the Matrix. - * - * @param {number} row1 - * @param {number} row2 - * @returns {Matrix} - */ - swap_rows(row1: number, row2: number): Matrix; - /** - * Returns the colth column from the Matrix. - * - * @param {number} col - * @returns {Float64Array} - */ - col(col: number): Float64Array; - /** - * Returns the `col`th entry from the `row`th row of the Matrix. - * - * @param {number} row - * @param {number} col - * @returns {number} - */ - entry(row: number, col: number): number; - /** - * Sets the {@link col}th entry from the {@link row}th row of the Matrix to the given - * {@link value}. - * - * @param {number} row - * @param {number} col - * @param {number} value - * @returns {Matrix} - */ - set_entry(row: number, col: number, value: number): Matrix; - /** - * Adds a given {@link value} to the {@link col}th entry from the {@link row}th row of the - * Matrix. - * - * @param {number} row - * @param {number} col - * @param {number} value - * @returns {Matrix} - */ - add_entry(row: number, col: number, value: number): Matrix; - /** - * Subtracts a given {@link value} from the {@link col}th entry from the {@link row}th row of the - * Matrix. - * - * @param {number} row - * @param {number} col - * @param {number} value - * @returns {Matrix} - */ - sub_entry(row: number, col: number, value: number): Matrix; - /** - * Returns a new transposed Matrix. - * - * @returns {Matrix} - */ - transpose(): Matrix; - /** - * Returns a new transposed Matrix. Short-form of `transpose`. - * - * @returns {Matrix} - */ - get T(): Matrix; - /** - * Returns the inverse of the Matrix. - * - * @returns {Matrix} - */ - inverse(): Matrix; - /** - * Returns the dot product. If `B` is an Array or Float64Array then an Array gets returned. If `B` is a Matrix then - * a Matrix gets returned. - * - * @param {Matrix | number[] | Float64Array} B The right side - * @returns {Matrix} - */ - dot(B: Matrix | number[] | Float64Array): Matrix; - /** - * Transposes the current matrix and returns the dot product with `B`. If `B` is an Array or Float64Array then an - * Array gets returned. If `B` is a Matrix then a Matrix gets returned. - * - * @param {Matrix | number[] | Float64Array} B The right side - * @returns {Matrix} - */ - transDot(B: Matrix | number[] | Float64Array): Matrix; - /** - * Returns the dot product with the transposed version of `B`. If `B` is an Array or Float64Array then an Array gets - * returned. If `B` is a Matrix then a Matrix gets returned. - * - * @param {Matrix | number[] | Float64Array} B The right side - * @returns {Matrix} - */ - dotTrans(B: Matrix | number[] | Float64Array): Matrix; - /** - * Computes the outer product from `this` and `B`. - * - * @param {Matrix} B - * @returns {Matrix} - */ - outer(B: Matrix): Matrix; - /** - * Appends matrix `B` to the matrix. - * - * @example let A = Matrix.from([ [1, 1], [1, 1], ]); // 2 by 2 matrix filled with ones. let B = Matrix.from([ [2, - * 2], [2, 2], ]); // 2 by 2 matrix filled with twos. - * - * A.concat(B, "horizontal"); // 2 by 4 matrix. [[1, 1, 2, 2], [1, 1, 2, 2]] - * A.concat(B, "vertical"); // 4 by 2 matrix. [[1, 1], [1, 1], [2, 2], [2, 2]] - * A.concat(B, "diag"); // 4 by 4 matrix. [[1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 2, 2], [0, 0, 2, 2]] - * - * @param {Matrix} B - Matrix to append. - * @param {"horizontal" | "vertical" | "diag"} [type="horizontal"] - Type of concatenation. Default is - * `"horizontal"` - * @returns {Matrix} - */ - concat(B: Matrix, type?: "horizontal" | "vertical" | "diag"): Matrix; - /** - * Writes the entries of B in A at an offset position given by `offset_row` and `offset_col`. - * - * @param {number} offset_row - * @param {number} offset_col - * @param {Matrix} B - * @returns {Matrix} - */ - set_block(offset_row: number, offset_col: number, B: Matrix): Matrix; - /** - * Extracts the entries from the `start_row`th row to the `end_row`th row, the - * `start_col`th column to the `end_col`th column of the matrix. If `end_row` or `end_col` is - * empty, the respective value is set to `this.rows` or `this.cols`. - * - * @example let A = Matrix.from([ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]); // a 3 by 3 matrix. - * - * A.get_block(1, 1); // [[5, 6], [8, 9]] - * A.get_block(0, 0, 1, 1); // [[1]] - * A.get_block(1, 1, 2, 2); // [[5]] - * A.get_block(0, 0, 2, 2); // [[1, 2], [4, 5]] - * - * @param {number} start_row - * @param {number} start_col - * @param {number | null} [end_row] - * @param {number | null} [end_col] - * @returns {Matrix} Returns a `end_row` - `start_row` times `end_col` - `start_col` matrix, with respective entries - * from the matrix. - */ - get_block( - start_row: number, - start_col: number, - end_row?: number | null, - end_col?: number | null, - ): Matrix; - /** - * Returns a new array gathering entries defined by the indices given by argument. - * - * @param {number[]} row_indices - Array consists of indices of rows for gathering entries of this matrix - * @param {number[]} col_indices - Array consists of indices of cols for gathering entries of this matrix - * @returns {Matrix} - */ - gather(row_indices: number[], col_indices: number[]): Matrix; - /** - * Applies a function to each entry of the matrix. - * - * @private - * @param {(d: number, v: number) => number} f Function takes 2 parameters, the value of the actual entry and a - * value given by the function `v`. The result of `f` gets writen to the Matrix. - * @param {Accessor} v Function takes 2 parameters for `row` and `col`, and returns a value witch should be applied - * to the `col`th entry of the `row`th row of the matrix. - * @returns {Matrix} - */ - private _apply_array; - /** - * @param {number[] | Float64Array} values - * @param {(d: number, v: number) => number} f - * @returns {Matrix} - */ - _apply_rowwise_array( - values: number[] | Float64Array, - f: (d: number, v: number) => number, - ): Matrix; - /** - * @param {number[] | Float64Array} values - * @param {(d: number, v: number) => number} f - * @returns {Matrix} - */ - _apply_colwise_array( - values: number[] | Float64Array, - f: (d: number, v: number) => number, - ): Matrix; - /** - * @param {Matrix | number[] | Float64Array | number} value - * @param {(d: number, v: number) => number} f - * @returns {Matrix} - */ - _apply( - value: Matrix | number[] | Float64Array | number, - f: (d: number, v: number) => number, - ): Matrix; - /** - * Clones the Matrix. - * - * @returns {Matrix} - */ - clone(): Matrix; - /** - * Entrywise multiplication with `value`. - * - * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; - * - * A.mult(2); // [[2, 4], [6, 8]]; - * A.mult(B); // [[1, 4], [9, 16]]; - * - * @param {Matrix | Float64Array | number[] | number} value - * @param {Object} [options] - * @param {boolean} [options.inline=false] - If true, applies multiplication to the element, otherwise it creates - * first a copy and applies the multiplication on the copy. Default is `false` - * @returns {Matrix} - */ - mult( - value: Matrix | Float64Array | number[] | number, - { - inline, - }?: { - inline?: boolean | undefined; - }, - ): Matrix; - /** - * Entrywise division with `value`. - * - * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; - * - * A.divide(2); // [[0.5, 1], [1.5, 2]]; - * A.divide(B); // [[1, 1], [1, 1]]; - * - * @param {Matrix | Float64Array | number[] | number} value - * @param {Object} [options] - * @param {Boolean} [options.inline=false] - If true, applies division to the element, otherwise it creates first a - * copy and applies the division on the copy. Default is `false` - * @returns {Matrix} - */ - divide( - value: Matrix | Float64Array | number[] | number, - { - inline, - }?: { - inline?: boolean | undefined; - }, - ): Matrix; - /** - * Entrywise addition with `value`. - * - * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; - * - * A.add(2); // [[3, 4], [5, 6]]; - * A.add(B); // [[2, 4], [6, 8]]; - * - * @param {Matrix | Float64Array | number[] | number} value - * @param {Object} [options] - * @param {boolean} [options.inline=false] - If true, applies addition to the element, otherwise it creates first a - * copy and applies the addition on the copy. Default is `false` - * @returns {Matrix} - */ - add( - value: Matrix | Float64Array | number[] | number, - { - inline, - }?: { - inline?: boolean | undefined; - }, - ): Matrix; - /** - * Entrywise subtraction with `value`. - * - * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; - * - * A.sub(2); // [[-1, 0], [1, 2]]; - * A.sub(B); // [[0, 0], [0, 0]]; - * - * @param {Matrix | Float64Array | number[] | number} value - * @param {Object} [options] - * @param {boolean} [options.inline=false] - If true, applies subtraction to the element, otherwise it creates first - * a copy and applies the subtraction on the copy. Default is `false` - * @returns {Matrix} - */ - sub( - value: Matrix | Float64Array | number[] | number, - { - inline, - }?: { - inline?: boolean | undefined; - }, - ): Matrix; - /** - * Returns the matrix in the given shape with the given function which returns values for the entries of the matrix. - * - * @param {[number, number, Accessor]} parameter - Takes an Array in the form [rows, cols, value], where rows and - * cols are the number of rows and columns of the matrix, and value is a function which takes two parameters (row - * and col) which has to return a value for the colth entry of the rowth row. - * @returns {Matrix} - */ - set shape([rows, cols, value]: [number, number, Accessor]); - /** - * Returns the number of rows and columns of the Matrix. - * - * @returns {number[]} An Array in the form [rows, columns]. - */ - get shape(): number[]; - /** - * Returns the Matrix as a Array of Float64Arrays. - * - * @returns {Float64Array[]} - */ - to2dArray(): Float64Array[]; - /** - * Returns the Matrix as a Array of Arrays. - * - * @returns {number[][]} - */ - asArray(): number[][]; - /** - * Returns the diagonal of the Matrix. - * - * @returns {Float64Array} - */ - diag(): Float64Array; - /** - * Returns the mean of all entries of the Matrix. - * - * @returns {number} - */ - mean(): number; - /** - * Returns the sum oof all entries of the Matrix. - * - * @returns {number} - */ - sum(): number; - /** - * Returns the entries of the Matrix. - * - * @returns {Float64Array} - */ - get values(): Float64Array; - /** - * Returns the mean of each row of the matrix. - * - * @returns {Float64Array} - */ - meanRows(): Float64Array; - /** - * Returns the mean of each column of the matrix. - * - * @returns {Float64Array} - */ - meanCols(): Float64Array; - /** - * Makes a `Matrix` object an iterable object. - * - * @yields {Float64Array} - */ - [Symbol.iterator](): Generator, void, unknown>; + /** + * Creates a Matrix out of `A`. + * @param {Matrix | Float64Array[] | number[][]} A - The matrix, array, or number, which should converted to a Matrix. + * @returns {Matrix} + * @example + * let A = Matrix.from([ [1, 0], [0, 1], ]); //creates a two by two identity matrix. + */ + static from(A: Matrix | Float64Array[] | number[][]): Matrix; + /** + * Creates a Matrix with the diagonal being the values of `v`. + * + * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]] + * + * @param {number[] | Float64Array} v + * @returns {Matrix} + */ + static from_diag(v: number[] | Float64Array): Matrix; + /** + * Creates a Matrix with the diagonal being the values of `v`. + * + * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]] + * + * @param {number[] | Float64Array} v + * @param {"col" | "row"} type + * @returns {Matrix} + */ + static from_vector(v: number[] | Float64Array, type: "col" | "row"): Matrix; + /** + * Solves the equation `Ax = b` using the conjugate gradient method. Returns the result `x`. + * + * @param {Matrix} A - Matrix + * @param {Matrix} b - Matrix + * @param {Randomizer | null} [randomizer] + * @param {number} [tol=1e-3] Default is `1e-3` + * @returns {Matrix} + */ + static solve_CG(A: Matrix, b: Matrix, randomizer?: Randomizer | null, tol?: number): Matrix; + /** + * Solves the equation `Ax = b`. Returns the result `x`. + * + * @param {Matrix | { L: Matrix; U: Matrix }} A - Matrix or LU Decomposition + * @param {Matrix} b - Matrix + * @returns {Matrix} + */ + static solve(A: Matrix | { + L: Matrix; + U: Matrix; + }, b: Matrix): Matrix; + /** + * `LU` decomposition of the Matrix `A`. Creates two matrices, so that the dot product `LU` equals `A`. + * + * @param {Matrix} A + * @returns {{ L: Matrix; U: Matrix }} The left triangle matrix `L` and the upper triangle matrix `U`. + */ + static LU(A: Matrix): { + L: Matrix; + U: Matrix; + }; + /** + * Computes the determinante of `A`, by using the `LU` decomposition of `A`. + * + * @param {Matrix} A + * @returns {number} The determinate of the Matrix `A`. + */ + static det(A: Matrix): number; + /** + * Computes the `k` components of the SVD decomposition of the matrix `M`. + * + * @param {Matrix} M + * @param {number} [k=2] Default is `2` + * @returns {{ U: Float64Array[]; Sigma: Float64Array; V: Float64Array[] }} + */ + static SVD(M: Matrix, k?: number): { + U: Float64Array[]; + Sigma: Float64Array; + V: Float64Array[]; + }; + /** + * @param {unknown} A + * @returns {A is unknown[]|number[]|Float64Array|Float32Array} + */ + static isArray(A: unknown): A is unknown[] | number[] | Float64Array | Float32Array; + /** + * @param {any[]} A + * @returns {A is number[][]|Float64Array[]} + */ + static is2dArray(A: any[]): A is number[][] | Float64Array[]; + /** + * Creates a new Matrix. Entries are stored in a Float64Array. + * + * @example let A = new Matrix(10, 10, () => Math.random()); //creates a 10 times 10 random matrix. let B = new + * Matrix(3, 3, "I"); // creates a 3 times 3 identity matrix. + * + * @param {number} rows - The amount of rows of the matrix. + * @param {number} cols - The amount of columns of the matrix. + * @param {Accessor | string | number} value - Can be a function with row and col as parameters, a number, or + * "zeros", "identity" or "I", or "center". + * + * - **function**: for each entry the function gets called with the parameters for the actual row and column. + * - **string**: allowed are + * + * - "zero", creates a zero matrix. + * - "identity" or "I", creates an identity matrix. + * - "center", creates an center matrix. + * - **number**: create a matrix filled with the given value. + */ + constructor(rows: number, cols: number, value?: Accessor | string | number); + /** @type {number} */ _rows: number; + /** @type {number} */ _cols: number; + /** @type {Float64Array} */ _data: Float64Array; + /** + * Returns the `row`th row from the Matrix. + * + * @param {number} row + * @returns {Float64Array} + */ + row(row: number): Float64Array; + /** + * Returns an generator yielding each row of the Matrix. + * + * @yields {Float64Array} + */ + iterate_rows(): Generator, void, unknown>; + /** + * Sets the entries of `row`th row from the Matrix to the entries from `values`. + * + * @param {number} row + * @param {number[]} values + * @returns {Matrix} + */ + set_row(row: number, values: number[]): Matrix; + /** + * Swaps the rows `row1` and `row2` of the Matrix. + * + * @param {number} row1 + * @param {number} row2 + * @returns {Matrix} + */ + swap_rows(row1: number, row2: number): Matrix; + /** + * Returns the colth column from the Matrix. + * + * @param {number} col + * @returns {Float64Array} + */ + col(col: number): Float64Array; + /** + * Returns the `col`th entry from the `row`th row of the Matrix. + * + * @param {number} row + * @param {number} col + * @returns {number} + */ + entry(row: number, col: number): number; + /** + * Sets the {@link col}th entry from the {@link row}th row of the Matrix to the given + * {@link value}. + * + * @param {number} row + * @param {number} col + * @param {number} value + * @returns {Matrix} + */ + set_entry(row: number, col: number, value: number): Matrix; + /** + * Adds a given {@link value} to the {@link col}th entry from the {@link row}th row of the + * Matrix. + * + * @param {number} row + * @param {number} col + * @param {number} value + * @returns {Matrix} + */ + add_entry(row: number, col: number, value: number): Matrix; + /** + * Subtracts a given {@link value} from the {@link col}th entry from the {@link row}th row of the + * Matrix. + * + * @param {number} row + * @param {number} col + * @param {number} value + * @returns {Matrix} + */ + sub_entry(row: number, col: number, value: number): Matrix; + /** + * Returns a new transposed Matrix. + * + * @returns {Matrix} + */ + transpose(): Matrix; + /** + * Returns a new transposed Matrix. Short-form of `transpose`. + * + * @returns {Matrix} + */ + get T(): Matrix; + /** + * Returns the inverse of the Matrix. + * + * @returns {Matrix} + */ + inverse(): Matrix; + /** + * Returns the dot product. If `B` is an Array or Float64Array then an Array gets returned. If `B` is a Matrix then + * a Matrix gets returned. + * + * @param {Matrix | number[] | Float64Array} B The right side + * @returns {Matrix} + */ + dot(B: Matrix | number[] | Float64Array): Matrix; + /** + * Transposes the current matrix and returns the dot product with `B`. If `B` is an Array or Float64Array then an + * Array gets returned. If `B` is a Matrix then a Matrix gets returned. + * + * @param {Matrix | number[] | Float64Array} B The right side + * @returns {Matrix} + */ + transDot(B: Matrix | number[] | Float64Array): Matrix; + /** + * Returns the dot product with the transposed version of `B`. If `B` is an Array or Float64Array then an Array gets + * returned. If `B` is a Matrix then a Matrix gets returned. + * + * @param {Matrix | number[] | Float64Array} B The right side + * @returns {Matrix} + */ + dotTrans(B: Matrix | number[] | Float64Array): Matrix; + /** + * Computes the outer product from `this` and `B`. + * + * @param {Matrix} B + * @returns {Matrix} + */ + outer(B: Matrix): Matrix; + /** + * Appends matrix `B` to the matrix. + * + * @example let A = Matrix.from([ [1, 1], [1, 1], ]); // 2 by 2 matrix filled with ones. let B = Matrix.from([ [2, + * 2], [2, 2], ]); // 2 by 2 matrix filled with twos. + * + * A.concat(B, "horizontal"); // 2 by 4 matrix. [[1, 1, 2, 2], [1, 1, 2, 2]] + * A.concat(B, "vertical"); // 4 by 2 matrix. [[1, 1], [1, 1], [2, 2], [2, 2]] + * A.concat(B, "diag"); // 4 by 4 matrix. [[1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 2, 2], [0, 0, 2, 2]] + * + * @param {Matrix} B - Matrix to append. + * @param {"horizontal" | "vertical" | "diag"} [type="horizontal"] - Type of concatenation. Default is + * `"horizontal"` + * @returns {Matrix} + */ + concat(B: Matrix, type?: "horizontal" | "vertical" | "diag"): Matrix; + /** + * Writes the entries of B in A at an offset position given by `offset_row` and `offset_col`. + * + * @param {number} offset_row + * @param {number} offset_col + * @param {Matrix} B + * @returns {Matrix} + */ + set_block(offset_row: number, offset_col: number, B: Matrix): Matrix; + /** + * Extracts the entries from the `start_row`th row to the `end_row`th row, the + * `start_col`th column to the `end_col`th column of the matrix. If `end_row` or `end_col` is + * empty, the respective value is set to `this.rows` or `this.cols`. + * + * @example let A = Matrix.from([ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]); // a 3 by 3 matrix. + * + * A.get_block(1, 1); // [[5, 6], [8, 9]] + * A.get_block(0, 0, 1, 1); // [[1]] + * A.get_block(1, 1, 2, 2); // [[5]] + * A.get_block(0, 0, 2, 2); // [[1, 2], [4, 5]] + * + * @param {number} start_row + * @param {number} start_col + * @param {number | null} [end_row] + * @param {number | null} [end_col] + * @returns {Matrix} Returns a `end_row` - `start_row` times `end_col` - `start_col` matrix, with respective entries + * from the matrix. + */ + get_block(start_row: number, start_col: number, end_row?: number | null, end_col?: number | null): Matrix; + /** + * Returns a new array gathering entries defined by the indices given by argument. + * + * @param {number[]} row_indices - Array consists of indices of rows for gathering entries of this matrix + * @param {number[]} col_indices - Array consists of indices of cols for gathering entries of this matrix + * @returns {Matrix} + */ + gather(row_indices: number[], col_indices: number[]): Matrix; + /** + * Applies a function to each entry of the matrix. + * + * @private + * @param {(d: number, v: number) => number} f Function takes 2 parameters, the value of the actual entry and a + * value given by the function `v`. The result of `f` gets writen to the Matrix. + * @param {Accessor} v Function takes 2 parameters for `row` and `col`, and returns a value witch should be applied + * to the `col`th entry of the `row`th row of the matrix. + * @returns {Matrix} + */ + private _apply_array; + /** + * @param {number[] | Float64Array} values + * @param {(d: number, v: number) => number} f + * @returns {Matrix} + */ + _apply_rowwise_array(values: number[] | Float64Array, f: (d: number, v: number) => number): Matrix; + /** + * @param {number[] | Float64Array} values + * @param {(d: number, v: number) => number} f + * @returns {Matrix} + */ + _apply_colwise_array(values: number[] | Float64Array, f: (d: number, v: number) => number): Matrix; + /** + * @param {Matrix | number[] | Float64Array | number} value + * @param {(d: number, v: number) => number} f + * @returns {Matrix} + */ + _apply(value: Matrix | number[] | Float64Array | number, f: (d: number, v: number) => number): Matrix; + /** + * Clones the Matrix. + * + * @returns {Matrix} + */ + clone(): Matrix; + /** + * Entrywise multiplication with `value`. + * + * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; + * + * A.mult(2); // [[2, 4], [6, 8]]; + * A.mult(B); // [[1, 4], [9, 16]]; + * + * @param {Matrix | Float64Array | number[] | number} value + * @param {Object} [options] + * @param {boolean} [options.inline=false] - If true, applies multiplication to the element, otherwise it creates + * first a copy and applies the multiplication on the copy. Default is `false` + * @returns {Matrix} + */ + mult(value: Matrix | Float64Array | number[] | number, { inline }?: { + inline?: boolean | undefined; + }): Matrix; + /** + * Entrywise division with `value`. + * + * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; + * + * A.divide(2); // [[0.5, 1], [1.5, 2]]; + * A.divide(B); // [[1, 1], [1, 1]]; + * + * @param {Matrix | Float64Array | number[] | number} value + * @param {Object} [options] + * @param {Boolean} [options.inline=false] - If true, applies division to the element, otherwise it creates first a + * copy and applies the division on the copy. Default is `false` + * @returns {Matrix} + */ + divide(value: Matrix | Float64Array | number[] | number, { inline }?: { + inline?: boolean | undefined; + }): Matrix; + /** + * Entrywise addition with `value`. + * + * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; + * + * A.add(2); // [[3, 4], [5, 6]]; + * A.add(B); // [[2, 4], [6, 8]]; + * + * @param {Matrix | Float64Array | number[] | number} value + * @param {Object} [options] + * @param {boolean} [options.inline=false] - If true, applies addition to the element, otherwise it creates first a + * copy and applies the addition on the copy. Default is `false` + * @returns {Matrix} + */ + add(value: Matrix | Float64Array | number[] | number, { inline }?: { + inline?: boolean | undefined; + }): Matrix; + /** + * Entrywise subtraction with `value`. + * + * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; + * + * A.sub(2); // [[-1, 0], [1, 2]]; + * A.sub(B); // [[0, 0], [0, 0]]; + * + * @param {Matrix | Float64Array | number[] | number} value + * @param {Object} [options] + * @param {boolean} [options.inline=false] - If true, applies subtraction to the element, otherwise it creates first + * a copy and applies the subtraction on the copy. Default is `false` + * @returns {Matrix} + */ + sub(value: Matrix | Float64Array | number[] | number, { inline }?: { + inline?: boolean | undefined; + }): Matrix; + /** + * Returns the matrix in the given shape with the given function which returns values for the entries of the matrix. + * + * @param {[number, number, Accessor]} parameter - Takes an Array in the form [rows, cols, value], where rows and + * cols are the number of rows and columns of the matrix, and value is a function which takes two parameters (row + * and col) which has to return a value for the colth entry of the rowth row. + * @returns {Matrix} + */ + set shape([rows, cols, value]: [number, number, Accessor]); + /** + * Returns the number of rows and columns of the Matrix. + * + * @returns {number[]} An Array in the form [rows, columns]. + */ + get shape(): number[]; + /** + * Returns the Matrix as a Array of Float64Arrays. + * + * @returns {Float64Array[]} + */ + to2dArray(): Float64Array[]; + /** + * Returns the Matrix as a Array of Arrays. + * + * @returns {number[][]} + */ + asArray(): number[][]; + /** + * Returns the diagonal of the Matrix. + * + * @returns {Float64Array} + */ + diag(): Float64Array; + /** + * Returns the mean of all entries of the Matrix. + * + * @returns {number} + */ + mean(): number; + /** + * Returns the sum oof all entries of the Matrix. + * + * @returns {number} + */ + sum(): number; + /** + * Returns the entries of the Matrix. + * + * @returns {Float64Array} + */ + get values(): Float64Array; + /** + * Returns the mean of each row of the matrix. + * + * @returns {Float64Array} + */ + meanRows(): Float64Array; + /** + * Returns the mean of each column of the matrix. + * + * @returns {Float64Array} + */ + meanCols(): Float64Array; + /** + * Makes a `Matrix` object an iterable object. + * + * @yields {Float64Array} + */ + [Symbol.iterator](): Generator, void, unknown>; } type Accessor = (i: number, j: number) => number; @@ -811,34 +765,34 @@ declare function normalize(v: number[] | Float64Array, metric?: Metric): number[ * @template Para */ declare class Clustering { - /** - * Compute the respective Clustering with given parameters - * @param {InputType} points - * @param {Para} parameters - */ - constructor(points: InputType, parameters: Para); - /** @type {InputType} */ - _points: InputType; - /** @type {Para} */ - _parameters: Para; - /** @type {Matrix} */ - _matrix: Matrix; - /** @type {number} */ - _N: number; - /** @type {number} */ - _D: number; - /** - * @abstract - * @param {...unknown} args - * @returns {number[][]} An array with the indices of the clusters. - */ - get_clusters(...args: unknown[]): number[][]; - /** - * @abstract - * @param {...unknown} args - * @returns {number[]} An array with the clusters id's for each point. - */ - get_cluster_list(...args: unknown[]): number[]; + /** + * Compute the respective Clustering with given parameters + * @param {InputType} points + * @param {Para} parameters + */ + constructor(points: InputType, parameters: Para); + /** @type {InputType} */ + _points: InputType; + /** @type {Para} */ + _parameters: Para; + /** @type {Matrix} */ + _matrix: Matrix; + /** @type {number} */ + _N: number; + /** @type {number} */ + _D: number; + /** + * @abstract + * @param {...unknown} args + * @returns {number[][]} An array with the indices of the clusters. + */ + get_clusters(...args: unknown[]): number[][]; + /** + * @abstract + * @param {...unknown} args + * @returns {number[]} An array with the clusters id's for each point. + */ + get_cluster_list(...args: unknown[]): number[]; } /** @import { InputType } from "../index.js" */ @@ -854,69 +808,69 @@ declare class Clustering { * @category Clustering */ declare class CURE extends Clustering { - /** - * @param {InputType} points - * @param {Partial} parameters - */ - constructor(points: InputType, parameters?: Partial); - /** @type {number} */ - _K: number; - /** @type {number} */ - _num_representatives: number; - /** @type {number} */ - _shrink_factor: number; - /** - * @private - * @type {CURECluster[]} - */ - private _clusters; - /** @type {number[]} */ - _cluster_ids: number[]; - /** - * Initialize each point as its own cluster - * @private - */ - private _initialize_clusters; - /** - * Compute distance between two clusters using representative points - * @private - * @param {CURECluster} cluster1 - * @param {CURECluster} cluster2 - * @returns {number} - */ - private _cluster_distance; - /** - * Find the closest pair of clusters - * @private - * @returns {[number, number, number]} [index1, index2, distance] - */ - private _find_closest_clusters; - /** - * Merge two clusters - * @private - * @param {CURECluster} cluster1 - * @param {CURECluster} cluster2 - * @returns {CURECluster} - */ - private _merge_clusters; - /** - * Run CURE clustering algorithm - * @private - */ - private _cure; - /** - * Build the cluster list (point -> cluster assignment) - * @private - */ - private _build_cluster_ids; - /** - * @returns {number[][]} - */ - get_clusters(): number[][]; - /** - * @returns {number[]} - */ - get_cluster_list(): number[]; + /** + * @param {InputType} points + * @param {Partial} parameters + */ + constructor(points: InputType, parameters?: Partial); + /** @type {number} */ + _K: number; + /** @type {number} */ + _num_representatives: number; + /** @type {number} */ + _shrink_factor: number; + /** + * @private + * @type {CURECluster[]} + */ + private _clusters; + /** @type {number[]} */ + _cluster_ids: number[]; + /** + * Initialize each point as its own cluster + * @private + */ + private _initialize_clusters; + /** + * Compute distance between two clusters using representative points + * @private + * @param {CURECluster} cluster1 + * @param {CURECluster} cluster2 + * @returns {number} + */ + private _cluster_distance; + /** + * Find the closest pair of clusters + * @private + * @returns {[number, number, number]} [index1, index2, distance] + */ + private _find_closest_clusters; + /** + * Merge two clusters + * @private + * @param {CURECluster} cluster1 + * @param {CURECluster} cluster2 + * @returns {CURECluster} + */ + private _merge_clusters; + /** + * Run CURE clustering algorithm + * @private + */ + private _cure; + /** + * Build the cluster list (point -> cluster assignment) + * @private + */ + private _build_cluster_ids; + /** + * @returns {number[][]} + */ + get_clusters(): number[][]; + /** + * @returns {number[]} + */ + get_cluster_list(): number[]; } /** @import { InputType } from "../index.js" */ @@ -932,99 +886,90 @@ declare class CURE extends Clustering { * @category Clustering */ declare class HierarchicalClustering extends Clustering { - /** - * @param {InputType} points - Data or distance matrix if metric is 'precomputed' - * @param {Partial} parameters - */ - constructor(points: InputType, parameters?: Partial); - /** @type {Cluster | null} */ - root: Cluster | null; - _id: number; - _d_min: Float64Array; - _distance_matrix: Matrix; - _clusters: any[]; - _c_size: Uint16Array; - /** - * @param {number} value - Value where to cut the tree. - * @param {"distance" | "depth"} [type="distance"] - Type of value. Default is `"distance"` - * @returns {Cluster[][]} - Array of clusters with the indices of the rows in given points. - */ - get_clusters_raw(value: number, type?: "distance" | "depth"): Cluster[][]; - /** - * @param {number} value - Value where to cut the tree. - * @param {"distance" | "depth"} [type="distance"] - Type of value. Default is `"distance"` - * @returns {number[][]} - Array of clusters with the indices of the rows in given points. - */ - get_clusters(value: number, type?: "distance" | "depth"): number[][]; - /** - * @param {number} value - Value where to cut the tree. - * @param {"distance" | "depth"} [type="distance"] - Type of value. Default is `"distance"` - * @returns {number[]} - Array of clusters with the indices of the rows in given points. - */ - get_cluster_list(value: number, type?: "distance" | "depth"): number[]; - /** - * @private - * @param {Cluster} node - * @param {(d: {dist: number, depth: number}) => number} f - * @param {number} value - * @param {Cluster[][]} result - */ - private _traverse; + /** + * @param {InputType} points - Data or distance matrix if metric is 'precomputed' + * @param {Partial} parameters + */ + constructor(points: InputType, parameters?: Partial); + /** @type {Cluster | null} */ + root: Cluster | null; + _id: number; + _d_min: Float64Array; + _distance_matrix: Matrix; + _clusters: any[]; + _c_size: Uint16Array; + /** + * @param {number} value - Value where to cut the tree. + * @param {"distance" | "depth"} [type="distance"] - Type of value. Default is `"distance"` + * @returns {Cluster[][]} - Array of clusters with the indices of the rows in given points. + */ + get_clusters_raw(value: number, type?: "distance" | "depth"): Cluster[][]; + /** + * @param {number} value - Value where to cut the tree. + * @param {"distance" | "depth"} [type="distance"] - Type of value. Default is `"distance"` + * @returns {number[][]} - Array of clusters with the indices of the rows in given points. + */ + get_clusters(value: number, type?: "distance" | "depth"): number[][]; + /** + * @param {number} value - Value where to cut the tree. + * @param {"distance" | "depth"} [type="distance"] - Type of value. Default is `"distance"` + * @returns {number[]} - Array of clusters with the indices of the rows in given points. + */ + get_cluster_list(value: number, type?: "distance" | "depth"): number[]; + /** + * @private + * @param {Cluster} node + * @param {(d: {dist: number, depth: number}) => number} f + * @param {number} value + * @param {Cluster[][]} result + */ + private _traverse; } /** @private */ declare class Cluster { - /** - * - * @param {number} id - * @param {Cluster?} left - * @param {Cluster?} right - * @param {number} dist - * @param {Float64Array?} centroid - * @param {number} index - * @param {number} [size] - * @param {number} [depth] - */ - constructor( - id: number, - left: Cluster | null, - right: Cluster | null, - dist: number, - centroid: Float64Array | null, - index: number, - size?: number, - depth?: number, - ); - /**@type {number} */ - size: number; - /**@type {number} */ - depth: number; - /**@type {Cluster | null} */ - parent: Cluster | null; - id: number; - left: Cluster | null; - right: Cluster | null; - dist: number; - index: number; - centroid: Float64Array; - /** - * - * @param {Cluster} left - * @param {Cluster} right - * @returns {Float64Array} - */ - _calculate_centroid(left: Cluster, right: Cluster): Float64Array; - get isLeaf(): boolean; - /** - * - * @returns {Cluster[]} - */ - leaves(): Cluster[]; - /** - * - * @returns {Cluster[]} - */ - descendants(): Cluster[]; + /** + * + * @param {number} id + * @param {Cluster?} left + * @param {Cluster?} right + * @param {number} dist + * @param {Float64Array?} centroid + * @param {number} index + * @param {number} [size] + * @param {number} [depth] + */ + constructor(id: number, left: Cluster | null, right: Cluster | null, dist: number, centroid: Float64Array | null, index: number, size?: number, depth?: number); + /**@type {number} */ + size: number; + /**@type {number} */ + depth: number; + /**@type {Cluster | null} */ + parent: Cluster | null; + id: number; + left: Cluster | null; + right: Cluster | null; + dist: number; + index: number; + centroid: Float64Array; + /** + * + * @param {Cluster} left + * @param {Cluster} right + * @returns {Float64Array} + */ + _calculate_centroid(left: Cluster, right: Cluster): Float64Array; + get isLeaf(): boolean; + /** + * + * @returns {Cluster[]} + */ + leaves(): Cluster[]; + /** + * + * @returns {Cluster[]} + */ + descendants(): Cluster[]; } /** @import { InputType } from "../index.js" */ @@ -1050,49 +995,49 @@ declare class Cluster { * const centroids = kmeans.centroids; // center points */ declare class KMeans extends Clustering { - /** - * @param {InputType} points - * @param {Partial} parameters - */ - constructor(points: InputType, parameters?: Partial); - _K: number; - _randomizer: Randomizer; - /** @type {number[]} */ - _clusters: number[]; - _cluster_centroids: Float64Array[]; - /** @returns {number} The number of clusters */ - get k(): number; - /** @returns {Float64Array[]} The cluster centroids */ - get centroids(): Float64Array[]; - /** @returns {number[]} The cluster list */ - get_cluster_list(): number[]; - /** @returns {number[][]} An Array of clusters with the indices of the points. */ - get_clusters(): number[][]; - /** - * @private - * @param {number[]} point_indices - * @param {number[]} candidates - * @returns {number} - */ - private _furthest_point; - /** - * @private - * @param {number} K - * @returns {Float64Array[]} - */ - private _get_random_centroids; - /** - * @private - * @param {Float64Array[]} cluster_centroids - * @returns {{ clusters_changed: boolean; cluster_centroids: Float64Array[] }} - */ - private _iteration; - /** - * @private - * @param {number} K - * @returns {Float64Array[]} - */ - private _compute_centroid; + /** + * @param {InputType} points + * @param {Partial} parameters + */ + constructor(points: InputType, parameters?: Partial); + _K: number; + _randomizer: Randomizer; + /** @type {number[]} */ + _clusters: number[]; + _cluster_centroids: Float64Array[]; + /** @returns {number} The number of clusters */ + get k(): number; + /** @returns {Float64Array[]} The cluster centroids */ + get centroids(): Float64Array[]; + /** @returns {number[]} The cluster list */ + get_cluster_list(): number[]; + /** @returns {number[][]} An Array of clusters with the indices of the points. */ + get_clusters(): number[][]; + /** + * @private + * @param {number[]} point_indices + * @param {number[]} candidates + * @returns {number} + */ + private _furthest_point; + /** + * @private + * @param {number} K + * @returns {Float64Array[]} + */ + private _get_random_centroids; + /** + * @private + * @param {Float64Array[]} cluster_centroids + * @returns {{ clusters_changed: boolean; cluster_centroids: Float64Array[] }} + */ + private _iteration; + /** + * @private + * @param {number} K + * @returns {Float64Array[]} + */ + private _compute_centroid; } /** @import {InputType} from "../index.js" */ @@ -1109,71 +1054,71 @@ declare class KMeans extends Clustering { * @see {@link KMeans} for a faster but less robust alternative */ declare class KMedoids extends Clustering { - /** - * @param {InputType} points - Data matrix - * @param {Partial} parameters - * @see {@link https://link.springer.com/chapter/10.1007/978-3-030-32047-8_16} Faster k-Medoids Clustering: Improving the PAM, CLARA, and CLARANS Algorithms - */ - constructor(points: InputType, parameters?: Partial); - _A: Float64Array[]; - _max_iter: number; - _distance_matrix: Matrix; - _randomizer: Randomizer; - _clusters: any[]; - _cluster_medoids: number[]; - _is_initialized: boolean; - /** @returns {number[]} The cluster list */ - get_cluster_list(): number[]; - /** @returns {number[][]} - Array of clusters with the indices of the rows in given points. */ - get_clusters(): number[][]; - /** @returns {number} */ - get k(): number; - /** @returns {number[]} */ - get medoids(): number[]; - /** @returns {number[]} */ - get_medoids(): number[]; - generator(): AsyncGenerator; - /** Algorithm 1. FastPAM1: Improved SWAP algorithm */ - /** FastPAM1: One best swap per iteration */ - _iteration(): boolean; - /** - * - * @param {number} i - * @param {number} j - * @param {Float64Array?} x_i - * @param {Float64Array?} x_j - * @returns - */ - _get_distance(i: number, j: number, x_i?: Float64Array | null, x_j?: Float64Array | null): number; - /** - * - * @param {Float64Array} x_j - * @param {number} j - * @returns - */ - _nearest_medoid( - x_j: Float64Array, - j: number, - ): { - distance_nearest: number; - index_nearest: number; - distance_second: number; - index_second: number; - }; - _update_clusters(): void; - /** - * Computes `K` clusters out of the `matrix`. - * @param {number} K - Number of clusters. - * @param {number[]} cluster_medoids - */ - init(K: number, cluster_medoids: number[]): this; - /** - * Algorithm 3. FastPAM LAB: Linear Approximate BUILD initialization. - * - * @param {number} K - Number of clusters - * @returns {number[]} - */ - _get_random_medoids(K: number): number[]; + /** + * @param {InputType} points - Data matrix + * @param {Partial} parameters + * @see {@link https://link.springer.com/chapter/10.1007/978-3-030-32047-8_16} Faster k-Medoids Clustering: Improving the PAM, CLARA, and CLARANS Algorithms + */ + constructor(points: InputType, parameters?: Partial); + _A: Float64Array[]; + _max_iter: number; + _distance_matrix: Matrix; + _randomizer: Randomizer; + _clusters: any[]; + _cluster_medoids: number[]; + _is_initialized: boolean; + /** @returns {number[]} The cluster list */ + get_cluster_list(): number[]; + /** @returns {number[][]} - Array of clusters with the indices of the rows in given points. */ + get_clusters(): number[][]; + /** @returns {number} */ + get k(): number; + /** @returns {number[]} */ + get medoids(): number[]; + /** @returns {number[]} */ + get_medoids(): number[]; + generator(): AsyncGenerator; + /** Algorithm 1. FastPAM1: Improved SWAP algorithm */ + /** + * FastPAM1: One best swap per iteration + * @private + * @returns {boolean} + */ + private _iteration; + /** + * @private + * Get distance between two points + * @param {number} i + * @param {number} j + * @param {Float64Array?} x_i + * @param {Float64Array?} x_j + * @returns {number} + */ + private _get_distance; + /** + * @private + * @param {Float64Array} x_j + * @param {number} j + * @returns + */ + private _nearest_medoid; + /** + * @private + */ + private _update_clusters; + /** + * Computes `K` clusters out of the `matrix`. + * @param {number} K - Number of clusters. + * @param {number[]} cluster_medoids + */ + init(K: number, cluster_medoids: number[]): this; + /** + * Algorithm 3. FastPAM LAB: Linear Approximate BUILD initialization. + * @private + * @param {number} K - Number of clusters + * @returns {number[]} + */ + private _get_random_medoids; } /** @import { ParametersMeanShift } from "./index.js" */ @@ -1189,47 +1134,79 @@ declare class KMedoids extends Clustering { * @category Clustering */ declare class MeanShift extends Clustering { - /** - * - * @param {InputType} points - * @param {Partial} parameters - */ - constructor(points: InputType, parameters?: Partial); - /** @type {number} */ - _bandwidth: number; - /** @type {number} */ - _max_iter: number; - /** @type {number} */ - _tolerance: number; - /** @type {(dist: number) => number} */ - _kernel: (dist: number) => number; - /** @type {Matrix} */ - _points: Matrix; - /** @type {number[] | undefined} */ - _clusters: number[] | undefined; - /** @type {number[][] | undefined} */ - _cluster_list: number[][] | undefined; - /** - * @param {Matrix} matrix - * @returns {number} - */ - _compute_bandwidth(matrix: Matrix): number; - /** - * @param {number} dist - * @returns {number} - */ - _kernel_weight(dist: number): number; - _mean_shift(): void; - _assign_clusters(): void; - /** - * @returns {number[][]} - */ - get_clusters(): number[][]; - /** - * - * @returns {number[]} - */ - get_cluster_list(): number[]; + /** + * + * @param {InputType} points + * @param {Partial} parameters + */ + constructor(points: InputType, parameters?: Partial); + /** + * @private + * @type {number} + */ + private _bandwidth; + /** + * @private + * @type {number} + */ + private _max_iter; + /** + * @private + * @type {number} + */ + private _tolerance; + /** + * @private + * @type {(dist: number) => number} + */ + private _kernel; + /** + * @type {Matrix} + */ + _points: Matrix; + /** + * @private + * @type {number[] | undefined} + */ + private _clusters; + /** + * @private + * @type {number[][] | undefined} + */ + private _cluster_list; + /** + * Helper to compute bandwidth if not provided + * @private + * @param {Matrix} matrix + * @returns {number} + */ + private _compute_bandwidth; + /** + * Compute kernel weight + * @private + * @param {number} dist + * @returns {number} + */ + private _kernel_weight; + /** + * Perform mean shift iterations + * @private + */ + private _mean_shift; + /** + * After convergence, assign clusters based on nearest mode + * @private + */ + private _assign_clusters; + /** + * @returns {number[][]} + */ + get_clusters(): number[][]; + /** + * + * @returns {number[]} + */ + get_cluster_list(): number[]; } /** @import { InputType } from "../index.js" */ @@ -1252,68 +1229,68 @@ declare class MeanShift extends Clustering { * @category Clustering */ declare class OPTICS extends Clustering { - /** - * **O**rdering **P**oints **T**o **I**dentify the **C**lustering **S**tructure. - * - * @param {InputType} points - The data. - * @param {Partial} [parameters={}] - * @see {@link https://www.dbs.ifi.lmu.de/Publikationen/Papers/OPTICS.pdf} - * @see {@link https://en.wikipedia.org/wiki/OPTICS_algorithm} - */ - constructor(points: InputType, parameters?: Partial); - /** - * @private - * @type {DBEntry[]} - */ - private _ordered_list; - /** @type {number[][]} */ - _clusters: number[][]; - /** - * @private - * @type {DBEntry[]} - */ - private _DB; - _cluster_index: number; - /** - * @private - * @param {DBEntry} p - A point of the data. - * @returns {DBEntry[]} An array consisting of the `epsilon`-neighborhood of `p`. - */ - private _get_neighbors; - /** - * @private - * @param {DBEntry} p - A point of `matrix`. - * @returns {number|undefined} The distance to the `min_points`-th nearest point of `p`, or undefined if the - * `epsilon`-neighborhood has fewer elements than `min_points`. - */ - private _core_distance; - /** - * Updates the reachability distance of the points. - * - * @private - * @param {DBEntry} p - * @param {Heap} seeds - */ - private _update; - /** - * Expands the `cluster` with points in `seeds`. - * - * @private - * @param {Heap} seeds - * @param {number[]} cluster - */ - private _expand_cluster; - /** - * Returns an array of clusters. - * - * @returns {number[][]} Array of clusters with the indices of the rows in given `matrix`. - */ - get_clusters(): number[][]; - /** - * @returns {number[]} Returns an array, where the ith entry defines the cluster affirmation of the ith point of - * given data. (-1 stands for outlier) - */ - get_cluster_list(): number[]; + /** + * **O**rdering **P**oints **T**o **I**dentify the **C**lustering **S**tructure. + * + * @param {InputType} points - The data. + * @param {Partial} [parameters={}] + * @see {@link https://www.dbs.ifi.lmu.de/Publikationen/Papers/OPTICS.pdf} + * @see {@link https://en.wikipedia.org/wiki/OPTICS_algorithm} + */ + constructor(points: InputType, parameters?: Partial); + /** + * @private + * @type {DBEntry[]} + */ + private _ordered_list; + /** @type {number[][]} */ + _clusters: number[][]; + /** + * @private + * @type {DBEntry[]} + */ + private _DB; + _cluster_index: number; + /** + * @private + * @param {DBEntry} p - A point of the data. + * @returns {DBEntry[]} An array consisting of the `epsilon`-neighborhood of `p`. + */ + private _get_neighbors; + /** + * @private + * @param {DBEntry} p - A point of `matrix`. + * @returns {number|undefined} The distance to the `min_points`-th nearest point of `p`, or undefined if the + * `epsilon`-neighborhood has fewer elements than `min_points`. + */ + private _core_distance; + /** + * Updates the reachability distance of the points. + * + * @private + * @param {DBEntry} p + * @param {Heap} seeds + */ + private _update; + /** + * Expands the `cluster` with points in `seeds`. + * + * @private + * @param {Heap} seeds + * @param {number[]} cluster + */ + private _expand_cluster; + /** + * Returns an array of clusters. + * + * @returns {number[][]} Array of clusters with the indices of the rows in given `matrix`. + */ + get_clusters(): number[][]; + /** + * @returns {number[]} Returns an array, where the ith entry defines the cluster affirmation of the ith point of + * given data. (-1 stands for outlier) + */ + get_cluster_list(): number[]; } /** @import { InputType } from "../index.js" */ @@ -1342,206 +1319,206 @@ declare class OPTICS extends Clustering { * @category Clustering */ declare class XMeans extends Clustering { - /** - * XMeans clustering algorithm that automatically determines the optimal number of clusters. - * - * X-Means extends K-Means by starting with a minimum number of clusters and iteratively - * splitting clusters to improve the Bayesian Information Criterion (BIC). - * - * Algorithm: - * 1. Start with K_min clusters using KMeans - * 2. For each cluster, try splitting it into 2 sub-clusters - * 3. If BIC improves after splitting, keep the split - * 4. Run KMeans again with all (old + new) centroids - * 5. Repeat until K_max is reached or no more improvements - * - * @param {InputType} points - The data points to cluster - * @param {Partial} [parameters={}] - Configuration parameters - * @see {@link https://www.cs.cmu.edu/~dpelleg/download/xmeans.pdf} - * @see {@link https://github.com/annoviko/pyclustering/blob/master/pyclustering/cluster/xmeans.py} - * @see {@link https://github.com/haifengl/smile/blob/master/core/src/main/java/smile/clustering/XMeans.java} - */ - constructor(points: InputType, parameters?: Partial); - _randomizer: Randomizer; - /** @type {KMeans | null} */ - _best_kmeans: KMeans | null; - /** - * Run the XMeans algorithm - * - * @private - */ - private _run; - /** - * Select the best candidate based on BIC score - * - * @private - * @param {Map} candidates - * @returns {KMeans} - */ - private _select_best_candidate; - /** - * Calculate Bayesian Information Criterion for a set of clusters. - * - * Uses Kass's formula for BIC calculation: - * BIC(θ) = L(D) - 0.5 * p * ln(N) - * - * Where: - * - L(D) is the log-likelihood of the data - * - p is the number of free parameters: (K-1) + D*K + 1 - * - N is the total number of points - * - * @private - * @param {number[][]} clusters - Array of clusters with point indices - * @param {Float64Array[]} centroids - Array of centroids - * @returns {number} BIC score (higher is better) - */ - private _bic; - /** - * Get the computed clusters - * - * @returns {number[][]} Array of clusters, each containing indices of points - */ - get_clusters(): number[][]; - /** @returns {number[]} The cluster list */ - get_cluster_list(): number[]; - /** - * Get the final centroids - * - * @returns {Float64Array[]} Array of centroids - */ - get centroids(): Float64Array[]; - /** - * Get the optimal number of clusters found - * - * @returns {number} The number of clusters - */ - get k(): number; + /** + * XMeans clustering algorithm that automatically determines the optimal number of clusters. + * + * X-Means extends K-Means by starting with a minimum number of clusters and iteratively + * splitting clusters to improve the Bayesian Information Criterion (BIC). + * + * Algorithm: + * 1. Start with K_min clusters using KMeans + * 2. For each cluster, try splitting it into 2 sub-clusters + * 3. If BIC improves after splitting, keep the split + * 4. Run KMeans again with all (old + new) centroids + * 5. Repeat until K_max is reached or no more improvements + * + * @param {InputType} points - The data points to cluster + * @param {Partial} [parameters={}] - Configuration parameters + * @see {@link https://www.cs.cmu.edu/~dpelleg/download/xmeans.pdf} + * @see {@link https://github.com/annoviko/pyclustering/blob/master/pyclustering/cluster/xmeans.py} + * @see {@link https://github.com/haifengl/smile/blob/master/core/src/main/java/smile/clustering/XMeans.java} + */ + constructor(points: InputType, parameters?: Partial); + _randomizer: Randomizer; + /** @type {KMeans | null} */ + _best_kmeans: KMeans | null; + /** + * Run the XMeans algorithm + * + * @private + */ + private _run; + /** + * Select the best candidate based on BIC score + * + * @private + * @param {Map} candidates + * @returns {KMeans} + */ + private _select_best_candidate; + /** + * Calculate Bayesian Information Criterion for a set of clusters. + * + * Uses Kass's formula for BIC calculation: + * BIC(θ) = L(D) - 0.5 * p * ln(N) + * + * Where: + * - L(D) is the log-likelihood of the data + * - p is the number of free parameters: (K-1) + D*K + 1 + * - N is the total number of points + * + * @private + * @param {number[][]} clusters - Array of clusters with point indices + * @param {Float64Array[]} centroids - Array of centroids + * @returns {number} BIC score (higher is better) + */ + private _bic; + /** + * Get the computed clusters + * + * @returns {number[][]} Array of clusters, each containing indices of points + */ + get_clusters(): number[][]; + /** @returns {number[]} The cluster list */ + get_cluster_list(): number[]; + /** + * Get the final centroids + * + * @returns {Float64Array[]} Array of centroids + */ + get centroids(): Float64Array[]; + /** + * Get the optimal number of clusters found + * + * @returns {number} The number of clusters + */ + get k(): number; } type ParametersHierarchicalClustering = { - linkage: "single" | "complete" | "average"; - metric: Metric | "precomputed"; + linkage: "single" | "complete" | "average"; + metric: Metric | "precomputed"; }; type ParametersKMeans = { - K: number; - /** - * Default is `euclidean` - */ - metric: Metric; - /** - * Default is `1212` - */ - seed: number; - /** - * - Initial centroids. Default is `null` - */ - initial_centroids?: Float64Array[] | number[][] | undefined; + K: number; + /** + * Default is `euclidean` + */ + metric: Metric; + /** + * Default is `1212` + */ + seed: number; + /** + * - Initial centroids. Default is `null` + */ + initial_centroids?: Float64Array[] | number[][] | undefined; }; type ParametersKMedoids = { - /** - * - Number of clusters - */ - K: number; - /** - * - Maximum number of iterations. Default is 10 * Math.log10(N). Default is `null` - */ - max_iter: number | null; - /** - * - Metric defining the dissimilarity. Default is `euclidean` - */ - metric: Metric; - /** - * - Seed value for random number generator. Default is `1212` - */ - seed: number; + /** + * - Number of clusters + */ + K: number; + /** + * - Maximum number of iterations. Default is 10 * Math.log10(N). Default is `null` + */ + max_iter: number | null; + /** + * - Metric defining the dissimilarity. Default is `euclidean` + */ + metric: Metric; + /** + * - Seed value for random number generator. Default is `1212` + */ + seed: number; }; type ParametersOptics = { - /** - * - The minimum distance which defines whether a point is a neighbor or not. - */ - epsilon: number; - /** - * - The minimum number of points which a point needs to create a cluster. (Should be higher than 1, else each point creates a cluster.) - */ - min_points: number; - /** - * - The distance metric which defines the distance between two points of the points. Default is `euclidean` - */ - metric: Metric; + /** + * - The minimum distance which defines whether a point is a neighbor or not. + */ + epsilon: number; + /** + * - The minimum number of points which a point needs to create a cluster. (Should be higher than 1, else each point creates a cluster.) + */ + min_points: number; + /** + * - The distance metric which defines the distance between two points of the points. Default is `euclidean` + */ + metric: Metric; }; type ParametersXMeans = { - /** - * - Minimum number of clusters. Default is `2` - */ - K_min: number; - /** - * - Maximum number of clusters. Default is `10` - */ - K_max: number; - /** - * - Distance metric function. Default is `euclidean` - */ - metric: Metric; - /** - * - Random seed. Default is `1212` - */ - seed: number; - /** - * - Minimum points required to consider splitting a cluster. Default is `25` - */ - min_cluster_size: number; - /** - * - Convergence tolerance for KMeans. Default is `0.001` - */ - tolerance: number; + /** + * - Minimum number of clusters. Default is `2` + */ + K_min: number; + /** + * - Maximum number of clusters. Default is `10` + */ + K_max: number; + /** + * - Distance metric function. Default is `euclidean` + */ + metric: Metric; + /** + * - Random seed. Default is `1212` + */ + seed: number; + /** + * - Minimum points required to consider splitting a cluster. Default is `25` + */ + min_cluster_size: number; + /** + * - Convergence tolerance for KMeans. Default is `0.001` + */ + tolerance: number; }; type ParametersMeanShift = { - /** - * - bandwidth - */ - bandwidth: number; - /** - * - Metric defining the dissimilarity. Default is `euclidean` - */ - metric: Metric; - /** - * - Seed value for random number generator. Default is `1212` - */ - seed: number; - /** - * - Kernel function. Default is `gaussian` - */ - kernel: "flat" | "gaussian" | ((dist: number) => number); - /** - * - Maximum number of iterations. Default is `Math.max(10, Math.floor(10 * Math.log10(N)))` - */ - max_iter?: number | undefined; - /** - * - Convergence tolerance. Default is `1e-3` - */ - tolerance?: number | undefined; + /** + * - bandwidth + */ + bandwidth: number; + /** + * - Metric defining the dissimilarity. Default is `euclidean` + */ + metric: Metric; + /** + * - Seed value for random number generator. Default is `1212` + */ + seed: number; + /** + * - Kernel function. Default is `gaussian` + */ + kernel: "flat" | "gaussian" | ((dist: number) => number); + /** + * - Maximum number of iterations. Default is `Math.max(10, Math.floor(10 * Math.log10(N)))` + */ + max_iter?: number | undefined; + /** + * - Convergence tolerance. Default is `1e-3` + */ + tolerance?: number | undefined; }; type ParametersCURE = { - /** - * - Target number of clusters. Default is `2` - */ - K: number; - /** - * - Number of representative points per cluster. Default is `5` - */ - num_representatives: number; - /** - * - Factor to shrink representatives toward centroid (0-1). Default is `0.5` - */ - shrink_factor: number; - /** - * - Distance metric function. Default is `euclidean` - */ - metric: Metric; - /** - * - Random seed. Default is `1212` - */ - seed: number; + /** + * - Target number of clusters. Default is `2` + */ + K: number; + /** + * - Number of representative points per cluster. Default is `5` + */ + num_representatives: number; + /** + * - Factor to shrink representatives toward centroid (0-1). Default is `0.5` + */ + shrink_factor: number; + /** + * - Distance metric function. Default is `euclidean` + */ + metric: Metric; + /** + * - Random seed. Default is `1212` + */ + seed: number; }; /** @@ -1558,34 +1535,34 @@ type ParametersCURE = { * @see {@link https://en.wikipedia.org/wiki/Disjoint-set_data_structure} */ declare class DisjointSet { - /** - * @param {T[]?} elements - */ - constructor(elements?: T[] | null); - /** - * @private - * @type {Map>} - */ - private _list; - /** - * @private - * @param {T} x - * @returns {DisjointSet} - */ - private make_set; - /** - * @param {T} x - * @returns - */ - find(x: T): T | null; - /** - * @param {T} x - * @param {T} y - * @returns - */ - union(x: T, y: T): this; - /** @param {T} x */ - get_children(x: T): Set | null; + /** + * @param {T[]?} elements + */ + constructor(elements?: T[] | null); + /** + * @private + * @type {Map>} + */ + private _list; + /** + * @private + * @param {T} x + * @returns {DisjointSet} + */ + private make_set; + /** + * @param {T} x + * @returns + */ + find(x: T): T | null; + /** + * @param {T} x + * @param {T} y + * @returns + */ + union(x: T, y: T): this; + /** @param {T} x */ + get_children(x: T): Set | null; } /** @import { Comparator } from "./index.js" */ @@ -1595,128 +1572,120 @@ declare class DisjointSet { * @category Data Structures */ declare class Heap { - /** - * Creates a Heap from an Array - * - * @template T - * @param {T[]} elements - Contains the elements for the Heap. - * @param {(d: T) => number} accessor - Function returns the value of the element. - * @param {"min" | "max" | Comparator} [comparator="min"] - Function returning true or false - * defining the wished order of the Heap, or String for predefined function. ("min" for a Min-Heap, "max" for a - * Max_heap). Default is `"min"` - * @returns {Heap} - */ - static heapify( - elements: T_1[], - accessor: (d: T_1) => number, - comparator?: "min" | "max" | Comparator, - ): Heap; - /** - * A heap is a datastructure holding its elements in a specific way, so that the top element would be the first - * entry of an ordered list. - * - * @param {T[]?} elements - Contains the elements for the Heap. `elements` can be null. - * @param {(d: T) => number} accessor - Function returns the value of the element. - * @param {"min" | "max" | Comparator} [comparator="min"] - Function returning true or false - * defining the wished order of the Heap, or String for predefined function. ("min" for a Min-Heap, "max" for a - * Max_heap). Default is `"min"` - * @see {@link https://en.wikipedia.org/wiki/Binary_heap} - */ - constructor( - elements: (T[] | null) | undefined, - accessor: (d: T) => number, - comparator?: "min" | "max" | Comparator, - ); - /** @type {{ element: T; value: number }[]} */ - _container: { - element: T; - value: number; - }[]; - /** @type {Comparator} */ - _comparator: Comparator; - /** @type {(d: T) => number} */ - _accessor: (d: T) => number; - /** - * Swaps elements of container array. - * - * @private - * @param {number} index_a - * @param {number} index_b - */ - private _swap; - /** @private */ - private _heapify_up; - /** - * Pushes the element to the heap. - * - * @param {T} element - * @returns {Heap} - */ - push(element: T): Heap; - /** - * @private - * @param {Number} [start_index=0] Default is `0` - */ - private _heapify_down; - /** - * Removes and returns the top entry of the heap. - * - * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by - * `accessor`}). - */ - pop(): { - element: T; - value: number; - } | null; - /** - * Returns the top entry of the heap without removing it. - * - * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by - * `accessor`). - */ - get first(): { - element: T; - value: number; - } | null; - /** - * Yields the raw data - * - * @yields {T} Object consists of the element and its value (computed by `accessor`}). - */ - iterate(): Generator; - /** - * Returns the heap as ordered array. - * - * @returns {T[]} Array consisting the elements ordered by `comparator`. - */ - toArray(): T[]; - /** - * Returns elements of container array. - * - * @returns {T[]} Array consisting the elements. - */ - data(): T[]; - /** - * Returns the container array. - * - * @returns {{ element: T; value: number }[]} The container array. - */ - raw_data(): { - element: T; - value: number; - }[]; - /** - * The size of the heap. - * - * @returns {number} - */ - get length(): number; - /** - * Returns false if the the heap has entries, true if the heap has no entries. - * - * @returns {boolean} - */ - get empty(): boolean; + /** + * Creates a Heap from an Array + * + * @template T + * @param {T[]} elements - Contains the elements for the Heap. + * @param {(d: T) => number} accessor - Function returns the value of the element. + * @param {"min" | "max" | Comparator} [comparator="min"] - Function returning true or false + * defining the wished order of the Heap, or String for predefined function. ("min" for a Min-Heap, "max" for a + * Max_heap). Default is `"min"` + * @returns {Heap} + */ + static heapify(elements: T_1[], accessor: (d: T_1) => number, comparator?: "min" | "max" | Comparator): Heap; + /** + * A heap is a datastructure holding its elements in a specific way, so that the top element would be the first + * entry of an ordered list. + * + * @param {T[]?} elements - Contains the elements for the Heap. `elements` can be null. + * @param {(d: T) => number} accessor - Function returns the value of the element. + * @param {"min" | "max" | Comparator} [comparator="min"] - Function returning true or false + * defining the wished order of the Heap, or String for predefined function. ("min" for a Min-Heap, "max" for a + * Max_heap). Default is `"min"` + * @see {@link https://en.wikipedia.org/wiki/Binary_heap} + */ + constructor(elements: (T[] | null) | undefined, accessor: (d: T) => number, comparator?: "min" | "max" | Comparator); + /** @type {{ element: T; value: number }[]} */ + _container: { + element: T; + value: number; + }[]; + /** @type {Comparator} */ + _comparator: Comparator; + /** @type {(d: T) => number} */ + _accessor: (d: T) => number; + /** + * Swaps elements of container array. + * + * @private + * @param {number} index_a + * @param {number} index_b + */ + private _swap; + /** @private */ + private _heapify_up; + /** + * Pushes the element to the heap. + * + * @param {T} element + * @returns {Heap} + */ + push(element: T): Heap; + /** + * @private + * @param {Number} [start_index=0] Default is `0` + */ + private _heapify_down; + /** + * Removes and returns the top entry of the heap. + * + * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by + * `accessor`}). + */ + pop(): { + element: T; + value: number; + } | null; + /** + * Returns the top entry of the heap without removing it. + * + * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by + * `accessor`). + */ + get first(): { + element: T; + value: number; + } | null; + /** + * Yields the raw data + * + * @yields {T} Object consists of the element and its value (computed by `accessor`}). + */ + iterate(): Generator; + /** + * Returns the heap as ordered array. + * + * @returns {T[]} Array consisting the elements ordered by `comparator`. + */ + toArray(): T[]; + /** + * Returns elements of container array. + * + * @returns {T[]} Array consisting the elements. + */ + data(): T[]; + /** + * Returns the container array. + * + * @returns {{ element: T; value: number }[]} The container array. + */ + raw_data(): { + element: T; + value: number; + }[]; + /** + * The size of the heap. + * + * @returns {number} + */ + get length(): number; + /** + * Returns false if the the heap has entries, true if the heap has no entries. + * + * @returns {boolean} + */ + get empty(): boolean; } type Comparator = (a: number, b: number) => boolean; @@ -1734,143 +1703,133 @@ type Comparator = (a: number, b: number) => boolean; * * @class */ -declare class DR< - T extends InputType, - Para extends { +declare class DR { - /** - * Computes the projection. - * - * @template {InputType} T - * @template {{ seed?: number }} Para - * @param {T} X - * @param {Para} parameters - * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method. - * @returns {T} The dimensionality reduced dataset. - */ - static transform< - T_1 extends InputType, - Para_1 extends { - seed?: number; - }, - >(X: T_1, parameters: Para_1, ...args: unknown[]): T_1; - /** - * Computes the projection. - * - * @template {{ seed?: number }} Para - * @param {InputType} X - * @param {Para} parameters - * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method. - * @returns {Generator} A generator yielding the intermediate steps of the dimensionality - * reduction method. - */ - static generator< - Para_1 extends { - seed?: number; - }, - >(X: InputType, parameters: Para_1, ...args: unknown[]): Generator; - /** - * Computes the projection. - * - * @template {{ seed?: number }} Para - * @param {InputType} X - * @param {Para} parameters - * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method. - * @returns {Promise} A promise yielding the dimensionality reduced dataset. - */ - static transform_async< - Para_1 extends { - seed?: number; - }, - >(X: InputType, parameters: Para_1, ...args: unknown[]): Promise; - /** - * Takes the default parameters and seals them, remembers the type of input `X`, and initializes the random number - * generator. - * - * @param {T} X - The high-dimensional data. - * @param {Para} default_parameters - Object containing default parameterization of the DR method. - * @param {Partial} parameters - Object containing parameterization of the DR method to override defaults. - */ - constructor(X: T, default_parameters: Para, parameters?: Partial); - /** @type {number} */ - _D: number; - /** @type {number} */ - _N: number; - /** @type {Randomizer} */ - _randomizer: Randomizer; - /** @type {boolean} */ - _is_initialized: boolean; - /** @type {T} */ - __input: T; - /** @type {Para} */ - _parameters: Para; - /** @type {"array" | "matrix" | "typed"} */ - _type: "array" | "matrix" | "typed"; - /** @type {Matrix} */ - X: Matrix; - /** @type {Matrix} */ - Y: Matrix; - /** - * Get all Parameters. - * @overload - * @returns {Para} - */ - parameter(): Para; - /** - * Get value of given parameter. - * @template {keyof Para} K - * @overload - * @param {K} name - Name of the parameter. - * @returns {Para[K]} - */ - parameter(name: K): Para[K]; - /** - * Set value of given parameter. - * @template {keyof Para} K - * @overload - * @param {K} name - Name of the parameter. - * @param {Para[K]} value - Value of the parameter to set. - * @returns {this} - */ - parameter(name: K, value: Para[K]): this; - /** - * Computes the projection. - * - * @abstract - * @param {...unknown} args - * @returns {T} The projection. - */ - transform(...args: unknown[]): T; - /** - * Computes the projection. - * - * @abstract - * @param {...unknown} args - * @returns {Generator} The intermediate steps of the projection. - */ - generator(...args: unknown[]): Generator; - /** - * @abstract - * @param {...unknown} args - */ - init(...args: unknown[]): void; - /** - * If the respective DR method has an `init` function, call it before `transform`. - * - * @returns {DR} - */ - check_init(): DR; - /** @returns {T} The projection in the type of input `X`. */ - get projection(): T; - /** - * Computes the projection. - * - * @param {...unknown} args - Arguments the transform method of the respective DR method takes. - * @returns {Promise} The dimensionality reduced dataset. - */ - transform_async(...args: unknown[]): Promise; +}> { + /** + * Computes the projection. + * + * @template {InputType} T + * @template {{ seed?: number }} Para + * @param {T} X + * @param {Para} parameters + * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method. + * @returns {T} The dimensionality reduced dataset. + */ + static transform(X: T_1, parameters: Para_1, ...args: unknown[]): T_1; + /** + * Computes the projection. + * + * @template {{ seed?: number }} Para + * @param {InputType} X + * @param {Para} parameters + * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method. + * @returns {Generator} A generator yielding the intermediate steps of the dimensionality + * reduction method. + */ + static generator(X: InputType, parameters: Para_1, ...args: unknown[]): Generator; + /** + * Computes the projection. + * + * @template {{ seed?: number }} Para + * @param {InputType} X + * @param {Para} parameters + * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method. + * @returns {Promise} A promise yielding the dimensionality reduced dataset. + */ + static transform_async(X: InputType, parameters: Para_1, ...args: unknown[]): Promise; + /** + * Takes the default parameters and seals them, remembers the type of input `X`, and initializes the random number + * generator. + * + * @param {T} X - The high-dimensional data. + * @param {Para} default_parameters - Object containing default parameterization of the DR method. + * @param {Partial} parameters - Object containing parameterization of the DR method to override defaults. + */ + constructor(X: T, default_parameters: Para, parameters?: Partial); + /** @type {number} */ + _D: number; + /** @type {number} */ + _N: number; + /** @type {Randomizer} */ + _randomizer: Randomizer; + /** @type {boolean} */ + _is_initialized: boolean; + /** @type {T} */ + __input: T; + /** @type {Para} */ + _parameters: Para; + /** @type {"array" | "matrix" | "typed"} */ + _type: "array" | "matrix" | "typed"; + /** @type {Matrix} */ + X: Matrix; + /** @type {Matrix} */ + Y: Matrix; + /** + * Get all Parameters. + * @overload + * @returns {Para} + */ + parameter(): Para; + /** + * Get value of given parameter. + * @template {keyof Para} K + * @overload + * @param {K} name - Name of the parameter. + * @returns {Para[K]} + */ + parameter(name: K): Para[K]; + /** + * Set value of given parameter. + * @template {keyof Para} K + * @overload + * @param {K} name - Name of the parameter. + * @param {Para[K]} value - Value of the parameter to set. + * @returns {this} + */ + parameter(name: K, value: Para[K]): this; + /** + * Computes the projection. + * + * @abstract + * @param {...unknown} args + * @returns {T} The projection. + */ + transform(...args: unknown[]): T; + /** + * Computes the projection. + * + * @abstract + * @param {...unknown} args + * @returns {Generator} The intermediate steps of the projection. + */ + generator(...args: unknown[]): Generator; + /** + * @abstract + * @param {...unknown} args + */ + init(...args: unknown[]): void; + /** + * If the respective DR method has an `init` function, call it before `transform`. + * + * @returns {DR} + */ + check_init(): DR; + /** @returns {T} The projection in the type of input `X`. */ + get projection(): T; + /** + * Computes the projection. + * + * @param {...unknown} args - Arguments the transform method of the respective DR method takes. + * @returns {Promise} The dimensionality reduced dataset. + */ + transform_async(...args: unknown[]): Promise; } /** @import { InputType } from "../index.js" */ @@ -1888,56 +1847,270 @@ declare class DR< * @category Dimensionality Reduction */ declare class FASTMAP extends DR { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {T} - */ - static transform(X: T_1, parameters: Partial): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Generator} - */ - static generator( - X: T_1, - parameters: Partial, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters: Partial, - ): Promise; - /** - * FastMap: a fast algorithm for indexing, data-mining and visualization of traditional and multimedia datasets. - * @param {T} X - The high-dimensional data. - * @param {Partial} parameters - Object containing parameterization of the DR method. - * @see {@link https://doi.org/10.1145/223784.223812} - */ - constructor(X: T, parameters: Partial); - /** - * Chooses two points which are the most distant in the actual projection. - * - * @private - * @param {(a: number, b: number) => number} dist - * @returns {[number, number, number]} An array consisting of first index, second index, and distance between the - * two points. - */ - private _choose_distant_objects; - /** - * Computes the projection. - * - * @returns {T} The `d`-dimensional projection of the data matrix `X`. - */ - transform(): T; - generator(): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {T} + */ + static transform(X: T_1, parameters: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Generator} + */ + static generator(X: T_1, parameters: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Promise} + */ + static transform_async(X: T_1, parameters: Partial): Promise; + /** + * FastMap: a fast algorithm for indexing, data-mining and visualization of traditional and multimedia datasets. + * @param {T} X - The high-dimensional data. + * @param {Partial} parameters - Object containing parameterization of the DR method. + * @see {@link https://doi.org/10.1145/223784.223812} + */ + constructor(X: T, parameters: Partial); + /** + * Chooses two points which are the most distant in the actual projection. + * + * @private + * @param {(a: number, b: number) => number} dist + * @returns {[number, number, number]} An array consisting of first index, second index, and distance between the + * two points. + */ + private _choose_distant_objects; + /** + * Computes the projection. + * + * @returns {T} The `d`-dimensional projection of the data matrix `X`. + */ + transform(): T; + generator(): Generator; +} + +/** @import {InputType} from "../index.js" */ +/** @import {Metric} from "../metrics/index.js" */ +/** @import {ParametersPaCMAP} from "./index.js" */ +/** + * Pairwise Controlled Manifold Approximation Projection (PaCMAP) + * + * A dimensionality reduction technique that uses three types of point pairs — + * nearest neighbor (NN), mid-near (MN), and further (FP) pairs — with a + * dynamic three-phase weight schedule and Adam optimization to preserve both + * local and global structure. + * + * @class + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction + * @see {@link https://arxiv.org/abs/2012.04456|PaCMAP Paper} + * @see {@link https://github.com/YingfanWang/PaCMAP|PaCMAP GitHub} + * @see {@link UMAP} for a related graph-based technique + * @see {@link LocalMAP} for the local-refinement variant + * + * @example + * import * as druid from "@saehrimnir/druidjs"; + * + * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]; + * const pacmap = new druid.PaCMAP(X, { + * n_neighbors: 10, + * MN_ratio: 0.5, + * FP_ratio: 2.0, + * seed: 42 + * }); + * + * const Y = pacmap.transform(); // 450 iterations (default) + * // [[x1, y1], [x2, y2], [x3, y3]] + */ +declare class PaCMAP extends DR { + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X: T_1, parameters?: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static generator(X: T_1, parameters?: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static transform_async(X: T_1, parameters?: Partial): Promise; + /** + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + */ + constructor(X: T, parameters?: Partial); + _iter: number; + /** + * Samples mid-near pairs for each point. + * For each point i, repeats n_MN times: samples 6 random non-neighbor + * candidates, picks the 2nd closest by high-dim distance. + * + * @protected + * @param {Set[]} nn_sets - Array of neighbor index sets per point + * @param {number} n_MN - Number of mid-near pairs per point + * @returns {Int32Array} Flat array of [i, j] pairs + */ + protected _sample_mn_pairs(nn_sets: Set[], n_MN: number): Int32Array; + /** + * Samples further pairs for each point (random non-neighbors). + * + * @protected + * @param {Set[]} nn_sets - Array of neighbor index sets per point + * @param {number} n_FP - Number of further pairs per point + * @returns {Int32Array} Flat array of [i, j] pairs + */ + protected _sample_fp_pairs(nn_sets: Set[], n_FP: number): Int32Array; + /** + * Computes gradient coefficients and updates the gradient matrix for one pair type. + * + * @protected + * @param {Float64Array} grad_flat - Flat N×d gradient accumulator (modified in place) + * @param {Int32Array} pairs - Flat [i, j, i, j, ...] pair array + * @param {number} w - Weight for this pair type + * @param {number} attr_num - Numerator constant for attractive (10 for NN, 10000 for MN); 0 for repulsive + * @param {boolean} repulsive - Whether this is a repulsive pair type + */ + protected _accumulate_gradients(grad_flat: Float64Array, pairs: Int32Array, w: number, attr_num: number, repulsive: boolean): void; + /** + * Returns the weight schedule for the current iteration. + * + * @protected + * @param {number} iter - Current iteration (0-indexed) + * @returns {{ w_nn: number; w_mn: number; w_fp: number }} + */ + protected _get_weights(iter: number): { + w_nn: number; + w_mn: number; + w_fp: number; + }; + /** + * Applies Adam optimizer update to Y using accumulated gradients. + * + * @protected + * @param {Float64Array} grad_flat - Flat N×d gradient + */ + protected _adam_update(grad_flat: Float64Array): void; + _adam_t: any; + /** + * Initializes PaCMAP: PCA embedding, KNN pairs, MN pairs, FP pairs, Adam state. + * + * @returns {PaCMAP} + */ + init(): PaCMAP; + _nn_pairs: Int32Array | undefined; + _mn_pairs: Int32Array | undefined; + _fp_pairs: Int32Array | undefined; + _adam_m: Float64Array | undefined; + _adam_v: Float64Array | undefined; + /** + * Performs one optimization step. + * + * @returns {Matrix} + */ + next(): Matrix; + /** + * @param {number} [iterations] - Total number of iterations. Defaults to sum of `num_iters`. + * @returns {T} + */ + transform(iterations?: number): T; + /** + * @param {number} [iterations] - Total number of iterations. Defaults to sum of `num_iters`. + * @returns {Generator} + */ + generator(iterations?: number): Generator; +} + +/** @import {InputType} from "../index.js" */ +/** @import {ParametersLocalMAP} from "./index.js" */ +/** + * LocalMAP + * + * A variant of PaCMAP that improves local cluster separation by dynamically + * resampling further pairs (FP) in phase 3 using nearby points in the current + * low-dimensional embedding space, rather than randomly sampled non-neighbors. + * + * @class + * @template {InputType} T + * @extends PaCMAP + * @category Dimensionality Reduction + * @see {@link https://arxiv.org/abs/2012.04456|PaCMAP Paper} + * @see {@link PaCMAP} for the base algorithm + * + * @example + * import * as druid from "@saehrimnir/druidjs"; + * + * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]; + * const localmap = new druid.LocalMAP(X, { + * n_neighbors: 10, + * low_dist_thres: 10, + * seed: 42 + * }); + * + * const Y = localmap.transform(); // 450 iterations (default) + * // [[x1, y1], [x2, y2], [x3, y3]] + */ +declare class LocalMAP extends PaCMAP { + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X: T_1, parameters?: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static generator(X: T_1, parameters?: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static transform_async(X: T_1, parameters?: Partial): Promise; + /** + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + */ + constructor(X: T, parameters?: Partial); + /** + * Accumulates FP gradients with LocalMAP's distance-based weight scaling. + * For pairs within low_dist_thres, scales w_fp by low_dist_thres / (2 * sqrt(d_ij)). + * + * @private + * @param {Float64Array} grad_flat - Flat N×d gradient accumulator (modified in place) + * @param {Int32Array} pairs - Flat [i, j, i, j, ...] pair array + * @param {number} w_fp - Base FP weight + * @param {number} low_dist_thres - Distance threshold + * @param {number} low_dist_thres_sq - Squared distance threshold + */ + private _accumulate_gradients_local_fp; + /** + * Initializes LocalMAP (same as PaCMAP, but caches nn_sets for phase 3 resampling). + * + * @returns {LocalMAP} + */ + init(): LocalMAP; + _low_dist_thres: number | undefined; + _nn_sets_cache: Set[] | undefined; } /** @import {InputType} from "../index.js" */ @@ -1957,52 +2130,46 @@ declare class FASTMAP extends DR { * @see {@link LLE} for another nonlinear alternative */ declare class ISOMAP extends DR { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X: T_1, parameters?: Partial): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static generator( - X: T_1, - parameters?: Partial, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters?: Partial, - ): Promise; - /** - * Isometric feature mapping (ISOMAP). - * - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - * @see {@link https://doi.org/10.1126/science.290.5500.2319} - */ - constructor(X: T, parameters?: Partial); - defaults: ParametersISOMAP; - /** - * Computes the projection. - * - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - generator(): Generator; - /** - * @returns {T} - */ - transform(): T; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X: T_1, parameters?: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static generator(X: T_1, parameters?: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static transform_async(X: T_1, parameters?: Partial): Promise; + /** + * Isometric feature mapping (ISOMAP). + * + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + * @see {@link https://doi.org/10.1126/science.290.5500.2319} + */ + constructor(X: T, parameters?: Partial); + defaults: ParametersISOMAP; + /** + * Computes the projection. + * + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + generator(): Generator; + /** + * @returns {T} + */ + transform(): T; } /** @import {InputType} from "../index.js" */ @@ -2020,70 +2187,58 @@ declare class ISOMAP extends DR { * @category Dimensionality Reduction */ declare class LDA extends DR { - /** - * @template {InputType} T - * @template {{ seed?: number }} Para - * @param {T} X - * @param {Para} parameters - * @returns {T} - */ - static transform< - T_1 extends InputType, - Para extends { - seed?: number; - }, - >(X: T_1, parameters: Para): T_1; - /** - * @template {InputType} T - * @template {{ seed?: number }} Para - * @param {T} X - * @param {Para} parameters - * @returns {Generator} - */ - static generator< - T_1 extends InputType, - Para extends { - seed?: number; - }, - >(X: T_1, parameters: Para): Generator; - /** - * @template {InputType} T - * @template {{ seed?: number }} Para - * @param {T} X - * @param {Para} parameters - * @returns {Promise} - */ - static transform_async< - T_1 extends InputType, - Para extends { - seed?: number; - }, - >(X: T_1, parameters: Para): Promise; - /** - * Linear Discriminant Analysis. - * - * @param {T} X - The high-dimensional data. - * @param {Partial & { labels: any[] | Float64Array }} parameters - Object containing parameterization of the DR method. - * @see {@link https://onlinelibrary.wiley.com/doi/10.1111/j.1469-1809.1936.tb02137.x} - */ - constructor( - X: T, - parameters: Partial & { - labels: any[] | Float64Array; - }, - ); - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - generator(): Generator; - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {T} - The projected data. - */ - transform(): T; + /** + * @template {InputType} T + * @template {{ seed?: number }} Para + * @param {T} X + * @param {Para} parameters + * @returns {T} + */ + static transform(X: T_1, parameters: Para): T_1; + /** + * @template {InputType} T + * @template {{ seed?: number }} Para + * @param {T} X + * @param {Para} parameters + * @returns {Generator} + */ + static generator(X: T_1, parameters: Para): Generator; + /** + * @template {InputType} T + * @template {{ seed?: number }} Para + * @param {T} X + * @param {Para} parameters + * @returns {Promise} + */ + static transform_async(X: T_1, parameters: Para): Promise; + /** + * Linear Discriminant Analysis. + * + * @param {T} X - The high-dimensional data. + * @param {Partial & { labels: any[] | Float64Array }} parameters - Object containing parameterization of the DR method. + * @see {@link https://onlinelibrary.wiley.com/doi/10.1111/j.1469-1809.1936.tb02137.x} + */ + constructor(X: T, parameters: Partial & { + labels: any[] | Float64Array; + }); + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + generator(): Generator; + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {T} - The projected data. + */ + transform(): T; } /** @import {InputType} from "../index.js" */ @@ -2103,53 +2258,47 @@ declare class LDA extends DR { * @see {@link ISOMAP} for another nonlinear alternative */ declare class LLE extends DR { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {T} - */ - static transform(X: T_1, parameters: Partial): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Generator} - */ - static generator( - X: T_1, - parameters: Partial, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters: Partial, - ): Promise; - /** - * Locally Linear Embedding. - * - * @param {T} X - The high-dimensional data. - * @param {Partial} parameters - Object containing parameterization of the DR method. - * @see {@link https://doi.org/10.1126/science.290.5500.2323} - */ - constructor(X: T, parameters: Partial); - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - generator(): Generator; - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {T} - */ - transform(): T; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {T} + */ + static transform(X: T_1, parameters: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Generator} + */ + static generator(X: T_1, parameters: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Promise} + */ + static transform_async(X: T_1, parameters: Partial): Promise; + /** + * Locally Linear Embedding. + * + * @param {T} X - The high-dimensional data. + * @param {Partial} parameters - Object containing parameterization of the DR method. + * @see {@link https://doi.org/10.1126/science.290.5500.2323} + */ + constructor(X: T, parameters: Partial); + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + generator(): Generator; + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {T} + */ + transform(): T; } /** @import {InputType} from "../index.js" */ @@ -2167,53 +2316,47 @@ declare class LLE extends DR { * @category Dimensionality Reduction */ declare class LSP extends DR { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X: T_1, parameters?: Partial): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static generator( - X: T_1, - parameters?: Partial, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters?: Partial, - ): Promise; - /** - * Least Squares Projection. - * - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - * @see {@link https://ieeexplore.ieee.org/document/4378370} - */ - constructor(X: T, parameters?: Partial); - /** - * @returns {LSP} - */ - init(): LSP; - _A: Matrix | undefined; - _b: Matrix | undefined; - /** - * Computes the projection. - * - * @returns {T} Returns the projection. - */ - transform(): T; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X: T_1, parameters?: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static generator(X: T_1, parameters?: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static transform_async(X: T_1, parameters?: Partial): Promise; + /** + * Least Squares Projection. + * + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + * @see {@link https://ieeexplore.ieee.org/document/4378370} + */ + constructor(X: T, parameters?: Partial); + /** + * @returns {LSP} + */ + init(): LSP; + _A: Matrix | undefined; + _b: Matrix | undefined; + /** + * Computes the projection. + * + * @returns {T} Returns the projection. + */ + transform(): T; } /** @import {InputType} from "../index.js" */ @@ -2232,53 +2375,47 @@ declare class LSP extends DR { * @category Dimensionality Reduction */ declare class LTSA extends DR { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {T} - */ - static transform(X: T_1, parameters: Partial): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Generator} - */ - static generator( - X: T_1, - parameters: Partial, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters: Partial, - ): Promise; - /** - * Local Tangent Space Alignment - * - * @param {T} X - The high-dimensional data. - * @param {Partial} parameters - Object containing parameterization of the DR method. - * @see {@link https://epubs.siam.org/doi/abs/10.1137/S1064827502419154} - */ - constructor(X: T, parameters: Partial); - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - generator(): Generator; - /** - * Transforms the inputdata `X` to dimenionality `d`. - * - * @returns {T} - */ - transform(): T; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {T} + */ + static transform(X: T_1, parameters: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Generator} + */ + static generator(X: T_1, parameters: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Promise} + */ + static transform_async(X: T_1, parameters: Partial): Promise; + /** + * Local Tangent Space Alignment + * + * @param {T} X - The high-dimensional data. + * @param {Partial} parameters - Object containing parameterization of the DR method. + * @see {@link https://epubs.siam.org/doi/abs/10.1137/S1064827502419154} + */ + constructor(X: T, parameters: Partial); + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + generator(): Generator; + /** + * Transforms the inputdata `X` to dimenionality `d`. + * + * @returns {T} + */ + transform(): T; } /** @import {InputType} from "../index.js" */ @@ -2298,55 +2435,49 @@ declare class LTSA extends DR { * @see {@link PCA} for another linear alternative */ declare class MDS extends DR { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X: T_1, parameters?: Partial): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static generator( - X: T_1, - parameters?: Partial, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters?: Partial, - ): Promise; - /** - * Classical MDS. - * - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - */ - constructor(X: T, parameters?: Partial); - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - generator(): Generator; - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {T} - */ - transform(): T; - _d_X: Matrix | undefined; - /** @returns {number} - The stress of the projection. */ - stress(): number; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X: T_1, parameters?: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static generator(X: T_1, parameters?: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static transform_async(X: T_1, parameters?: Partial): Promise; + /** + * Classical MDS. + * + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + */ + constructor(X: T, parameters?: Partial); + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + generator(): Generator; + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {T} + */ + transform(): T; + _d_X: Matrix | undefined; + /** @returns {number} - The stress of the projection. */ + stress(): number; } /** @import {InputType} from "../index.js" */ @@ -2373,67 +2504,58 @@ declare class MDS extends DR { * // [[x1, y1], [x2, y2], [x3, y3]] */ declare class PCA extends DR { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {T} - */ - static transform(X: T_1, parameters: Partial): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Matrix} - */ - static principal_components( - X: T_1, - parameters: Partial, - ): Matrix; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static generator( - X: T_1, - parameters?: Partial, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters?: Partial, - ): Promise; - /** - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - */ - constructor(X: T, parameters?: Partial); - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - generator(): Generator; - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {T} - The projected data. - */ - transform(): T; - /** - * Computes the `d` principal components of Matrix `X`. - * - * @returns {Matrix} - */ - principal_components(): Matrix; - V: Matrix | undefined; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {T} + */ + static transform(X: T_1, parameters: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Matrix} + */ + static principal_components(X: T_1, parameters: Partial): Matrix; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static generator(X: T_1, parameters?: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static transform_async(X: T_1, parameters?: Partial): Promise; + /** + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + */ + constructor(X: T, parameters?: Partial); + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + generator(): Generator; + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {T} - The projected data. + */ + transform(): T; + /** + * Computes the `d` principal components of Matrix `X`. + * + * @returns {Matrix} + */ + principal_components(): Matrix; + V: Matrix | undefined; } /** @import {InputType} from "../index.js" */ @@ -2452,76 +2574,67 @@ declare class PCA extends DR { * @category Dimensionality Reduction */ declare class SAMMON extends DR> { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial>} [parameters] - * @returns {T} - */ - static transform( - X: T_1, - parameters?: Partial>, - ): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial>} [parameters] - * @returns {Generator} - */ - static generator( - X: T_1, - parameters?: Partial>, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial>} [parameters] - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters?: Partial>, - ): Promise; - /** - * SAMMON's Mapping - * - * @param {T} X - The high-dimensional data. - * @param {Partial>} [parameters] - Object containing parameterization of the DR - * method. - * @see {@link https://arxiv.org/pdf/2009.01512.pdf} - */ - constructor(X: T, parameters?: Partial>); - /** @type {Matrix | undefined} */ - distance_matrix: Matrix | undefined; - /** - * Initializes the projection. - * - * @param {Matrix | undefined} D - * @returns {asserts D is Matrix} - */ - init(D: Matrix | undefined): asserts D is Matrix; - /** - * Transforms the inputdata `X` to dimensionality 2. - * - * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200` - * @returns {T} The projection of `X`. - */ - transform(max_iter?: number): T; - /** - * Transforms the inputdata `X` to dimenionality 2. - * - * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200` - * @returns {Generator} A generator yielding the intermediate steps of the projection of - * `X`. - */ - generator(max_iter?: number): Generator; - _step(): Matrix; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial>} [parameters] + * @returns {T} + */ + static transform(X: T_1, parameters?: Partial>): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial>} [parameters] + * @returns {Generator} + */ + static generator(X: T_1, parameters?: Partial>): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial>} [parameters] + * @returns {Promise} + */ + static transform_async(X: T_1, parameters?: Partial>): Promise; + /** + * SAMMON's Mapping + * + * @param {T} X - The high-dimensional data. + * @param {Partial>} [parameters] - Object containing parameterization of the DR + * method. + * @see {@link https://arxiv.org/pdf/2009.01512.pdf} + */ + constructor(X: T, parameters?: Partial>); + /** @type {Matrix | undefined} */ + distance_matrix: Matrix | undefined; + /** + * Initializes the projection. + * + * @param {Matrix | undefined} D + * @returns {asserts D is Matrix} + */ + init(D: Matrix | undefined): asserts D is Matrix; + /** + * Transforms the inputdata `X` to dimensionality 2. + * + * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200` + * @returns {T} The projection of `X`. + */ + transform(max_iter?: number): T; + /** + * Transforms the inputdata `X` to dimenionality 2. + * + * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200` + * @returns {Generator} A generator yielding the intermediate steps of the projection of + * `X`. + */ + generator(max_iter?: number): Generator; + _step(): Matrix; } type AvailableInit = "PCA" | "MDS" | "random"; type ChooseDR = { - PCA: ParametersPCA; - MDS: ParametersMDS; - random: {}; + PCA: ParametersPCA; + MDS: ParametersMDS; + random: {}; }; /** @import {InputType} from "../index.js" */ @@ -2540,48 +2653,42 @@ type ChooseDR = { * @see {@link MDS} for the classical approach. */ declare class SMACOF extends DR { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X: T_1, parameters?: Partial): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static generator( - X: T_1, - parameters?: Partial, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters?: Partial, - ): Promise; - /** - * SMACOF for MDS. - * - * @param {T} X - The high-dimensional data or precomputed distance matrix. - * @param {Partial} [parameters] - Object containing parameterization. - */ - constructor(X: T, parameters?: Partial); - /** - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - generator(): Generator; - /** - * @returns {T} - */ - transform(): T; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X: T_1, parameters?: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static generator(X: T_1, parameters?: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static transform_async(X: T_1, parameters?: Partial): Promise; + /** + * SMACOF for MDS. + * + * @param {T} X - The high-dimensional data or precomputed distance matrix. + * @param {Partial} [parameters] - Object containing parameterization. + */ + constructor(X: T, parameters?: Partial); + /** + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + generator(): Generator; + /** + * @returns {T} + */ + transform(): T; } /** @import {InputType} from "../index.js" */ @@ -2599,174 +2706,152 @@ declare class SMACOF extends DR { * @category Dimensionality Reduction */ declare class SQDMDS extends DR { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X: T_1, parameters?: Partial): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static generator( - X: T_1, - parameters?: Partial, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters?: Partial, - ): Promise; - /** - * SQuadMDS: a lean Stochastic Quartet MDS improving global structure preservation in neighbor embedding like t-SNE - * and UMAP. - * - * @param {T} X - * @param {Partial} [parameters] - * @see {@link https://arxiv.org/pdf/2202.12087.pdf} - */ - constructor(X: T, parameters?: Partial); - init(): void; - _add: ((...summands: Float64Array[]) => Float64Array) | undefined; - _sub_div: - | (( - x: Float64Array, - y: Float64Array, - div: number, - ) => Float64Array) - | undefined; - _minus: - | ((a: Float64Array, b: Float64Array) => Float64Array) - | undefined; - _mult: ((a: Float64Array, v: number) => Float64Array) | undefined; - _LR_init: number | undefined; - _LR: number | undefined; - _offset: number | undefined; - _momentums: Matrix | undefined; - _grads: Matrix | undefined; - _indices: number[] | undefined; - /** @type {(i: number, j: number, X: Matrix) => number} */ - _HD_metric: ((i: number, j: number, X: Matrix) => number) | undefined; - /** @type {(i: number, j: number, X: Matrix) => number} */ - _HD_metric_exaggeration: ((i: number, j: number, X: Matrix) => number) | undefined; - /** - * Computes the projection. - * - * @param {number} [iterations=500] - Number of iterations. Default is `500` - * @returns {T} The projection. - */ - transform(iterations?: number): T; - _decay_start: number | undefined; - /** - * Computes the projection. - * - * @param {number} [iterations=500] - Number of iterations. Default is `500` - * @returns {Generator} The intermediate steps of the projection. - */ - generator(iterations?: number): Generator; - /** - * Performs an optimization step. - * - * @private - * @param {number} i - Acutal iteration. - * @param {number} iterations - Number of iterations. - */ - private _step; - _distance_exaggeration: boolean | undefined; - /** - * Creates quartets of non overlapping indices. - * - * @private - * @returns {Uint32Array[]} - */ - private __quartets; - /** - * Computes and applies gradients, and updates momentum. - * - * @private - * @param {boolean} distance_exaggeration - */ - private _nestrov_iteration; - /** - * Computes the gradients. - * - * @param {Matrix} Y - The Projection. - * @param {Matrix} grads - The gradients. - * @param {boolean} [exaggeration=false] - Whether or not to use early exaggeration. Default is `false` - * @param {boolean} [zero_grad=true] - Whether or not to reset the gradient in the beginning. Default is `true` - * @returns {Matrix} The gradients. - */ - _fill_MDS_grads(Y: Matrix, grads: Matrix, exaggeration?: boolean, zero_grad?: boolean): Matrix; - /** - * Quartet gradients for a projection. - * - * @private - * @param {Matrix} Y - The acutal projection. - * @param {number[]} quartet - The indices of the quartet. - * @param {Float64Array} D_hd - The high-dimensional distances of the quartet. - * @returns {Float64Array[]} The gradients for the quartet. - */ - private _compute_quartet_grads; - /** - * Gradients for one element of the loss function's sum. - * - * @private - * @param {Float64Array} a - * @param {Float64Array} b - * @param {Float64Array} c - * @param {Float64Array} d - * @param {number} d_ab - * @param {number} d_ac - * @param {number} d_ad - * @param {number} d_bc - * @param {number} d_bd - * @param {number} d_cd - * @param {number} p_ab - * @param {number} sum_LD_dist - * @returns {Float64Array[]} - */ - private _ABCD_grads; - /** - * Inline! - * - * @param {number} d - */ - __minus( - d: number, - ): (a: Float64Array, b: Float64Array) => Float64Array; - /** - * Inline! - * - * @param {number} d - */ - __add(d: number): (...summands: Float64Array[]) => Float64Array; - /** - * Inline! - * - * @param {number} d - */ - __mult(d: number): (a: Float64Array, v: number) => Float64Array; - /** - * Creates a new array `(x - y) / div`. - * - * @param {number} d - */ - __sub_div( - d: number, - ): ( - x: Float64Array, - y: Float64Array, - div: number, - ) => Float64Array; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X: T_1, parameters?: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static generator(X: T_1, parameters?: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static transform_async(X: T_1, parameters?: Partial): Promise; + /** + * SQuadMDS: a lean Stochastic Quartet MDS improving global structure preservation in neighbor embedding like t-SNE + * and UMAP. + * + * @param {T} X + * @param {Partial} [parameters] + * @see {@link https://arxiv.org/pdf/2202.12087.pdf} + */ + constructor(X: T, parameters?: Partial); + init(): void; + _add: ((...summands: Float64Array[]) => Float64Array) | undefined; + _sub_div: ((x: Float64Array, y: Float64Array, div: number) => Float64Array) | undefined; + _minus: ((a: Float64Array, b: Float64Array) => Float64Array) | undefined; + _mult: ((a: Float64Array, v: number) => Float64Array) | undefined; + _LR_init: number | undefined; + _LR: number | undefined; + _offset: number | undefined; + _momentums: Matrix | undefined; + _grads: Matrix | undefined; + _indices: number[] | undefined; + /** @type {(i: number, j: number, X: Matrix) => number} */ + _HD_metric: ((i: number, j: number, X: Matrix) => number) | undefined; + /** @type {(i: number, j: number, X: Matrix) => number} */ + _HD_metric_exaggeration: ((i: number, j: number, X: Matrix) => number) | undefined; + /** + * Computes the projection. + * + * @param {number} [iterations=500] - Number of iterations. Default is `500` + * @returns {T} The projection. + */ + transform(iterations?: number): T; + _decay_start: number | undefined; + /** + * Computes the projection. + * + * @param {number} [iterations=500] - Number of iterations. Default is `500` + * @returns {Generator} The intermediate steps of the projection. + */ + generator(iterations?: number): Generator; + /** + * Performs an optimization step. + * + * @private + * @param {number} i - Acutal iteration. + * @param {number} iterations - Number of iterations. + */ + private _step; + _distance_exaggeration: boolean | undefined; + /** + * Creates quartets of non overlapping indices. + * + * @private + * @returns {Uint32Array[]} + */ + private __quartets; + /** + * Computes and applies gradients, and updates momentum. + * + * @private + * @param {boolean} distance_exaggeration + */ + private _nestrov_iteration; + /** + * Computes the gradients. + * + * @param {Matrix} Y - The Projection. + * @param {Matrix} grads - The gradients. + * @param {boolean} [exaggeration=false] - Whether or not to use early exaggeration. Default is `false` + * @param {boolean} [zero_grad=true] - Whether or not to reset the gradient in the beginning. Default is `true` + * @returns {Matrix} The gradients. + */ + _fill_MDS_grads(Y: Matrix, grads: Matrix, exaggeration?: boolean, zero_grad?: boolean): Matrix; + /** + * Quartet gradients for a projection. + * + * @private + * @param {Matrix} Y - The acutal projection. + * @param {number[]} quartet - The indices of the quartet. + * @param {Float64Array} D_hd - The high-dimensional distances of the quartet. + * @returns {Float64Array[]} The gradients for the quartet. + */ + private _compute_quartet_grads; + /** + * Gradients for one element of the loss function's sum. + * + * @private + * @param {Float64Array} a + * @param {Float64Array} b + * @param {Float64Array} c + * @param {Float64Array} d + * @param {number} d_ab + * @param {number} d_ac + * @param {number} d_ad + * @param {number} d_bc + * @param {number} d_bd + * @param {number} d_cd + * @param {number} p_ab + * @param {number} sum_LD_dist + * @returns {Float64Array[]} + */ + private _ABCD_grads; + /** + * Inline! + * + * @param {number} d + */ + __minus(d: number): (a: Float64Array, b: Float64Array) => Float64Array; + /** + * Inline! + * + * @param {number} d + */ + __add(d: number): (...summands: Float64Array[]) => Float64Array; + /** + * Inline! + * + * @param {number} d + */ + __mult(d: number): (a: Float64Array, v: number) => Float64Array; + /** + * Creates a new array `(x - y) / div`. + * + * @param {number} d + */ + __sub_div(d: number): (x: Float64Array, y: Float64Array, div: number) => Float64Array; } /** @import {InputType} from "../index.js" */ @@ -2784,136 +2869,130 @@ declare class SQDMDS extends DR { * @category Dimensionality Reduction */ declare class TopoMap extends DR { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {T} - */ - static transform(X: T_1, parameters: Partial): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Generator} - */ - static generator( - X: T_1, - parameters: Partial, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters: Partial, - ): Promise; - /** - * TopoMap: A 0-dimensional Homology Preserving Projection of High-Dimensional Data. - * - * @param {T} X - The high-dimensional data. - * @param {Partial} parameters - Object containing parameterization of the DR method. - * @see {@link https://arxiv.org/pdf/2009.01512.pdf} - */ - constructor(X: T, parameters: Partial); - _distance_matrix: Matrix; - /** - * @private - * @param {number} i - * @param {number} j - * @param {import("../metrics/index.js").Metric} metric - * @returns {number} - */ - private __lazy_distance_matrix; - /** - * Computes the minimum spanning tree, using a given metric - * - * @private - * @param {import("../metrics/index.js").Metric} metric - * @see {@link https://en.wikipedia.org/wiki/Kruskal%27s_algorithm} - */ - private _make_minimum_spanning_tree; - _disjoint_set: DisjointSet> | undefined; - /** Initializes TopoMap. Sets all projcted points to zero, and computes a minimum spanning tree. */ - init(): this; - _Emst: number[][] | undefined; - /** - * Returns true if Point C is left of line AB. - * - * @private - * @param {Float64Array} PointA - Point A of line AB - * @param {Float64Array} PointB - Point B of line AB - * @param {Float64Array} PointC - Point C - * @returns {boolean} - */ - private __hull_cross; - /** - * Computes the convex hull of the set of Points S - * - * @private - * @param {Float64Array[]} S - Set of Points. - * @returns {Float64Array[]} Convex hull of S. Starts at the bottom-most point and continues counter-clockwise. - * @see {@link https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain#JavaScript} - */ - private __hull; - /** - * Finds the angle to rotate Point A and B to lie on a line parallel to the x-axis. - * - * @private - * @param {Float64Array} PointA - * @param {Float64Array} PointB - * @returns {{ sin: number; cos: number }} Object containing the sinus- and cosinus-values for a rotation. - */ - private __findAngle; - /** - * @private - * @param {Float64Array[]} hull - * @param {Float64Array} p - * @param {boolean} topEdge - * @returns {{ sin: number; cos: number; tx: number; ty: number }} - */ - private __align_hull; - /** - * @private - * @param {Float64Array} Point - The point which should get transformed. - * @param {{ sin: number; cos: number; tx: number; ty: number }} Transformation - Contains the values for - * translation and rotation. - */ - private __transform; - /** - * Calls `__transform` for each point in Set C - * - * @private - * @param {Float64Array[]} C - Set of points. - * @param {{ sin: number; cos: number; tx: number; ty: number }} t - Transform object. - * @param {number} yOffset - Value to offset set C. - */ - private __transform_component; - /** - * @private - * @param {Float64Array} root_u - Root of component u - * @param {Float64Array} root_v - Root of component v - * @param {Float64Array} p_u - Point u - * @param {Float64Array} p_v - Point v - * @param {number} w - Edge weight w - * @param {DisjointSet} components - The disjoint set containing the components - */ - private __align_components; - /** - * Transforms the inputdata `X` to dimensionality 2. - * - * @returns {T} - */ - transform(): T; - /** - * Transforms the inputdata `X` to dimensionality 2. - * - * @returns {Generator} - */ - generator(): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {T} + */ + static transform(X: T_1, parameters: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Generator} + */ + static generator(X: T_1, parameters: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Promise} + */ + static transform_async(X: T_1, parameters: Partial): Promise; + /** + * TopoMap: A 0-dimensional Homology Preserving Projection of High-Dimensional Data. + * + * @param {T} X - The high-dimensional data. + * @param {Partial} parameters - Object containing parameterization of the DR method. + * @see {@link https://arxiv.org/pdf/2009.01512.pdf} + */ + constructor(X: T, parameters: Partial); + _distance_matrix: Matrix; + /** + * @private + * @param {number} i + * @param {number} j + * @param {import("../metrics/index.js").Metric} metric + * @returns {number} + */ + private __lazy_distance_matrix; + /** + * Computes the minimum spanning tree, using a given metric + * + * @private + * @param {import("../metrics/index.js").Metric} metric + * @see {@link https://en.wikipedia.org/wiki/Kruskal%27s_algorithm} + */ + private _make_minimum_spanning_tree; + _disjoint_set: DisjointSet> | undefined; + /** Initializes TopoMap. Sets all projcted points to zero, and computes a minimum spanning tree. */ + init(): this; + _Emst: number[][] | undefined; + /** + * Returns true if Point C is left of line AB. + * + * @private + * @param {Float64Array} PointA - Point A of line AB + * @param {Float64Array} PointB - Point B of line AB + * @param {Float64Array} PointC - Point C + * @returns {boolean} + */ + private __hull_cross; + /** + * Computes the convex hull of the set of Points S + * + * @private + * @param {Float64Array[]} S - Set of Points. + * @returns {Float64Array[]} Convex hull of S. Starts at the bottom-most point and continues counter-clockwise. + * @see {@link https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain#JavaScript} + */ + private __hull; + /** + * Finds the angle to rotate Point A and B to lie on a line parallel to the x-axis. + * + * @private + * @param {Float64Array} PointA + * @param {Float64Array} PointB + * @returns {{ sin: number; cos: number }} Object containing the sinus- and cosinus-values for a rotation. + */ + private __findAngle; + /** + * @private + * @param {Float64Array[]} hull + * @param {Float64Array} p + * @param {boolean} topEdge + * @returns {{ sin: number; cos: number; tx: number; ty: number }} + */ + private __align_hull; + /** + * @private + * @param {Float64Array} Point - The point which should get transformed. + * @param {{ sin: number; cos: number; tx: number; ty: number }} Transformation - Contains the values for + * translation and rotation. + */ + private __transform; + /** + * Calls `__transform` for each point in Set C + * + * @private + * @param {Float64Array[]} C - Set of points. + * @param {{ sin: number; cos: number; tx: number; ty: number }} t - Transform object. + * @param {number} yOffset - Value to offset set C. + */ + private __transform_component; + /** + * @private + * @param {Float64Array} root_u - Root of component u + * @param {Float64Array} root_v - Root of component v + * @param {Float64Array} p_u - Point u + * @param {Float64Array} p_v - Point v + * @param {number} w - Edge weight w + * @param {DisjointSet} components - The disjoint set containing the components + */ + private __align_components; + /** + * Transforms the inputdata `X` to dimensionality 2. + * + * @returns {T} + */ + transform(): T; + /** + * Transforms the inputdata `X` to dimensionality 2. + * + * @returns {Generator} + */ + generator(): Generator; } /** @@ -2928,45 +3007,39 @@ declare class TopoMap extends DR { * @class */ declare class KNN { - /** - * @param {T[]} elements - * @param {Para} parameters - */ - constructor(elements: T[], parameters: Para); - /** @type {T[]} */ - _elements: T[]; - /** @type {Para} */ - _parameters: Para; - /** @type {"typed" | "array"} */ - _type: "typed" | "array"; - /** - * @abstract - * @param {T} t - * @param {number} k - * @returns {{ element: T; index: number; distance: number }[]} - */ - search( - t: T, - k: number, - ): { - element: T; - index: number; - distance: number; - }[]; - /** - * @abstract - * @param {number} i - * @param {number} k - * @returns {{ element: T; index: number; distance: number }[]} - */ - search_by_index( - i: number, - k: number, - ): { - element: T; - index: number; - distance: number; - }[]; + /** + * @param {T[]} elements + * @param {Para} parameters + */ + constructor(elements: T[], parameters: Para); + /** @type {T[]} */ + _elements: T[]; + /** @type {Para} */ + _parameters: Para; + /** @type {"typed" | "array"} */ + _type: "typed" | "array"; + /** + * @abstract + * @param {T} t + * @param {number} k + * @returns {{ element: T; index: number; distance: number }[]} + */ + search(t: T, k: number): { + element: T; + index: number; + distance: number; + }[]; + /** + * @abstract + * @param {number} i + * @param {number} k + * @returns {{ element: T; index: number; distance: number }[]} + */ + search_by_index(i: number, k: number): { + element: T; + index: number; + distance: number; + }[]; } /** @import {InputType} from "../index.js" */ @@ -2986,164 +3059,154 @@ declare class KNN { * @category Dimensionality Reduction */ declare class TriMap extends DR { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X: T_1, parameters?: Partial): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static generator( - X: T_1, - parameters?: Partial, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters?: Partial, - ): Promise; - /** - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - * @see {@link https://arxiv.org/pdf/1910.00204v1.pdf} - * @see {@link https://github.com/eamid/trimap} - */ - constructor(X: T, parameters?: Partial); - /** - * @param {Matrix | null} [pca=null] - Initial Embedding (if null then PCA gets used). Default is `null` - * @param {import("../knn/KNN.js").KNN | null} [knn=null] - KNN Object (if null then BallTree gets used). Default is `null` - */ - init(pca?: Matrix | null, knn?: KNN | null): this; - n_inliers: number | undefined; - n_outliers: number | undefined; - n_random: number | undefined; - knn: KNN, any> | undefined; - triplets: Matrix | undefined; - weights: Float64Array | undefined; - lr: number | undefined; - C: number | undefined; - vel: Matrix | undefined; - gain: Matrix | undefined; - /** - * Generates {@link n_inliers} x {@link n_outliers} x {@link n_random} triplets. - * - * @param {number} n_inliers - * @param {number} n_outliers - * @param {number} n_random - */ - _generate_triplets( - n_inliers: number, - n_outliers: number, - n_random: number, - ): { - triplets: Matrix; - weights: Float64Array; - }; - /** - * Calculates the similarity matrix P - * - * @private - * @param {Matrix} knn_distances - Matrix of pairwise knn distances - * @param {Float64Array} sig - Scaling factor for the distances - * @param {Matrix} nbrs - Nearest neighbors - * @returns {Matrix} Pairwise similarity matrix - */ - private _find_p; - /** - * Sample nearest neighbors triplets based on the similarity values given in P. - * - * @private - * @param {Matrix} P - Matrix of pairwise similarities between each point and its neighbors given in matrix nbrs. - * @param {Matrix} nbrs - Nearest neighbors indices for each point. The similarity values are given in matrix - * {@link P}. Row i corresponds to the i-th point. - * @param {number} n_inliers - Number of inlier points. - * @param {number} n_outliers - Number of outlier points. - */ - private _sample_knn_triplets; - /** - * Should do the same as np.argsort() - * - * @private - * @param {Float64Array | number[]} A - */ - private __argsort; - /** - * Samples {@link n_samples} integers from a given interval [0, {@link max_int}] while rejection the values that are - * in the {@link rejects}. - * - * @private - * @param {number} n_samples - * @param {number} max_int - * @param {number[]} rejects - */ - private _rejection_sample; - /** - * Calculates the weights for the sampled nearest neighbors triplets - * - * @private - * @param {Matrix} triplets - Sampled Triplets. - * @param {Matrix} P - Pairwise similarity matrix. - * @param {Matrix} nbrs - Nearest Neighbors - * @param {Float64Array} outlier_distances - Matrix of pairwise outlier distances - * @param {Float64Array} sig - Scaling factor for the distances. - */ - private _find_weights; - /** - * Sample uniformly ranom triplets - * - * @private - * @param {Matrix} X - Data matrix. - * @param {number} n_random - Number of random triplets per point - * @param {Float64Array} sig - Scaling factor for the distances - */ - private _sample_random_triplets; - /** - * Computes the gradient for updating the embedding. - * - * @param {Matrix} Y - The embedding - */ - _grad(Y: Matrix): { - grad: Matrix; - loss: number; - n_viol: number; - }; - /** - * @param {number} max_iteration - * @returns {T} - */ - transform(max_iteration?: number): T; - /** - * @param {number} max_iteration - * @returns {Generator} - */ - generator(max_iteration?: number): Generator; - /** - * Does the iteration step. - * - * @private - * @param {number} iter - */ - private _next; - /** - * Updates the embedding. - * - * @private - * @param {Matrix} Y - * @param {number} iter - * @param {Matrix} grad - */ - private _update_embedding; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X: T_1, parameters?: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static generator(X: T_1, parameters?: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static transform_async(X: T_1, parameters?: Partial): Promise; + /** + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + * @see {@link https://arxiv.org/pdf/1910.00204v1.pdf} + * @see {@link https://github.com/eamid/trimap} + */ + constructor(X: T, parameters?: Partial); + /** + * @param {Matrix | null} [pca=null] - Initial Embedding (if null then PCA gets used). Default is `null` + * @param {import("../knn/KNN.js").KNN | null} [knn=null] - KNN Object (if null then BallTree gets used). Default is `null` + */ + init(pca?: Matrix | null, knn?: KNN | null): this; + n_inliers: number | undefined; + n_outliers: number | undefined; + n_random: number | undefined; + knn: KNN, any> | undefined; + triplets: Matrix | undefined; + weights: Float64Array | undefined; + lr: number | undefined; + C: number | undefined; + vel: Matrix | undefined; + gain: Matrix | undefined; + /** + * Generates {@link n_inliers} x {@link n_outliers} x {@link n_random} triplets. + * + * @param {number} n_inliers + * @param {number} n_outliers + * @param {number} n_random + */ + _generate_triplets(n_inliers: number, n_outliers: number, n_random: number): { + triplets: Matrix; + weights: Float64Array; + }; + /** + * Calculates the similarity matrix P + * + * @private + * @param {Matrix} knn_distances - Matrix of pairwise knn distances + * @param {Float64Array} sig - Scaling factor for the distances + * @param {Matrix} nbrs - Nearest neighbors + * @returns {Matrix} Pairwise similarity matrix + */ + private _find_p; + /** + * Sample nearest neighbors triplets based on the similarity values given in P. + * + * @private + * @param {Matrix} P - Matrix of pairwise similarities between each point and its neighbors given in matrix nbrs. + * @param {Matrix} nbrs - Nearest neighbors indices for each point. The similarity values are given in matrix + * {@link P}. Row i corresponds to the i-th point. + * @param {number} n_inliers - Number of inlier points. + * @param {number} n_outliers - Number of outlier points. + */ + private _sample_knn_triplets; + /** + * Should do the same as np.argsort() + * + * @private + * @param {Float64Array | number[]} A + */ + private __argsort; + /** + * Samples {@link n_samples} integers from a given interval [0, {@link max_int}] while rejection the values that are + * in the {@link rejects}. + * + * @private + * @param {number} n_samples + * @param {number} max_int + * @param {number[]} rejects + */ + private _rejection_sample; + /** + * Calculates the weights for the sampled nearest neighbors triplets + * + * @private + * @param {Matrix} triplets - Sampled Triplets. + * @param {Matrix} P - Pairwise similarity matrix. + * @param {Matrix} nbrs - Nearest Neighbors + * @param {Float64Array} outlier_distances - Matrix of pairwise outlier distances + * @param {Float64Array} sig - Scaling factor for the distances. + */ + private _find_weights; + /** + * Sample uniformly ranom triplets + * + * @private + * @param {Matrix} X - Data matrix. + * @param {number} n_random - Number of random triplets per point + * @param {Float64Array} sig - Scaling factor for the distances + */ + private _sample_random_triplets; + /** + * Computes the gradient for updating the embedding. + * + * @param {Matrix} Y - The embedding + */ + _grad(Y: Matrix): { + grad: Matrix; + loss: number; + n_viol: number; + }; + /** + * @param {number} max_iteration + * @returns {T} + */ + transform(max_iteration?: number): T; + /** + * @param {number} max_iteration + * @returns {Generator} + */ + generator(max_iteration?: number): Generator; + /** + * Does the iteration step. + * + * @private + * @param {number} iter + */ + private _next; + /** + * Updates the embedding. + * + * @private + * @param {Matrix} Y + * @param {number} iter + * @param {Matrix} grad + */ + private _update_embedding; } /** @import {InputType} from "../index.js" */ @@ -3178,60 +3241,54 @@ declare class TriMap extends DR { * // [[x1, y1], [x2, y2], [x3, y3]] */ declare class TSNE extends DR { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X: T_1, parameters?: Partial): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static generator( - X: T_1, - parameters?: Partial, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters?: Partial, - ): Promise; - /** - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - */ - constructor(X: T, parameters?: Partial); - _iter: number; - init(): this; - _ystep: Matrix | undefined; - _gains: Matrix | undefined; - _P: Matrix | undefined; - /** - * @param {number} [iterations=500] - Number of iterations. Default is `500` - * @returns {T} The projection. - */ - transform(iterations?: number): T; - /** - * @param {number} [iterations=500] - Number of iterations. Default is `500` - * @returns {Generator} - The projection. - */ - generator(iterations?: number): Generator; - /** - * Performs a optimization step - * - * @private - * @returns {Matrix} - */ - private next; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X: T_1, parameters?: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static generator(X: T_1, parameters?: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static transform_async(X: T_1, parameters?: Partial): Promise; + /** + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + */ + constructor(X: T, parameters?: Partial); + _iter: number; + init(): this; + _ystep: Matrix | undefined; + _gains: Matrix | undefined; + _P: Matrix | undefined; + /** + * @param {number} [iterations=500] - Number of iterations. Default is `500` + * @returns {T} The projection. + */ + transform(iterations?: number): T; + /** + * @param {number} [iterations=500] - Number of iterations. Default is `500` + * @returns {Generator} - The projection. + */ + generator(iterations?: number): Generator; + /** + * Performs a optimization step + * + * @private + * @returns {Matrix} + */ + private next; } /** @import {InputType} from "../index.js" */ @@ -3266,138 +3323,132 @@ declare class TSNE extends DR { * // [[x1, y1], [x2, y2], [x3, y3]] */ declare class UMAP extends DR { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X: T_1, parameters?: Partial): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static generator( - X: T_1, - parameters?: Partial, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters?: Partial, - ): Promise; - /** - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - */ - constructor(X: T, parameters?: Partial); - _iter: number; - /** - * @private - * @param {number} spread - * @param {number} min_dist - * @returns {number[]} - */ - private _find_ab_params; - /** - * @private - * @param {{ element: Float64Array; index: number; distance: number }[][]} distances - * @param {number[]} sigmas - * @param {number[]} rhos - * @returns {{ element: Float64Array; index: number; distance: number }[][]} - */ - private _compute_membership_strengths; - /** - * @private - * @param {NaiveKNN | BallTree} knn - * @param {number} k - * @returns {{ - * distances: { element: Float64Array; index: number; distance: number }[][]; - * sigmas: number[]; - * rhos: number[]; - * }} - */ - private _smooth_knn_dist; - /** - * @private - * @param {Matrix} X - * @param {number} n_neighbors - * @returns {Matrix} - */ - private _fuzzy_simplicial_set; - /** - * @private - * @param {number} n_epochs - * @returns {Float32Array} - */ - private _make_epochs_per_sample; - /** - * @private - * @param {Matrix} graph - * @returns {{ rows: number[]; cols: number[]; data: number[] }} - */ - private _tocoo; - /** - * Computes all necessary - * - * @returns {UMAP} - */ - init(): UMAP; - _a: number | undefined; - _b: number | undefined; - _graph: Matrix | undefined; - _head: number[] | undefined; - _tail: number[] | undefined; - _weights: number[] | undefined; - _epochs_per_sample: Float32Array | undefined; - _epochs_per_negative_sample: Float32Array | undefined; - _epoch_of_next_sample: Float32Array | undefined; - _epoch_of_next_negative_sample: Float32Array | undefined; - graph(): { - cols: number[] | undefined; - rows: number[] | undefined; - weights: number[] | undefined; - }; - /** - * @param {number} [iterations=350] - Number of iterations. Default is `350` - * @returns {T} - */ - transform(iterations?: number): T; - /** - * @param {number} [iterations=350] - Number of iterations. Default is `350` - * @returns {Generator} - */ - generator(iterations?: number): Generator; - /** - * @private - * @param {number} x - * @returns {number} - */ - private _clip; - /** - * Performs the optimization step. - * - * @private - * @param {Matrix} head_embedding - * @param {Matrix} tail_embedding - * @param {number[]} head - * @param {number[]} tail - * @returns {Matrix} - */ - private _optimize_layout; - /** - * @private - * @returns {Matrix} - */ - private next; - _alpha: number | undefined; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X: T_1, parameters?: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static generator(X: T_1, parameters?: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static transform_async(X: T_1, parameters?: Partial): Promise; + /** + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + */ + constructor(X: T, parameters?: Partial); + _iter: number; + /** + * @private + * @param {number} spread + * @param {number} min_dist + * @returns {number[]} + */ + private _find_ab_params; + /** + * @private + * @param {{ element: Float64Array; index: number; distance: number }[][]} distances + * @param {number[]} sigmas + * @param {number[]} rhos + * @returns {{ element: Float64Array; index: number; distance: number }[][]} + */ + private _compute_membership_strengths; + /** + * @private + * @param {NaiveKNN | BallTree} knn + * @param {number} k + * @returns {{ + * distances: { element: Float64Array; index: number; distance: number }[][]; + * sigmas: number[]; + * rhos: number[]; + * }} + */ + private _smooth_knn_dist; + /** + * @private + * @param {Matrix} X + * @param {number} n_neighbors + * @returns {Matrix} + */ + private _fuzzy_simplicial_set; + /** + * @private + * @param {number} n_epochs + * @returns {Float32Array} + */ + private _make_epochs_per_sample; + /** + * @private + * @param {Matrix} graph + * @returns {{ rows: number[]; cols: number[]; data: number[] }} + */ + private _tocoo; + /** + * Computes all necessary + * + * @returns {UMAP} + */ + init(): UMAP; + _a: number | undefined; + _b: number | undefined; + _graph: Matrix | undefined; + _head: number[] | undefined; + _tail: number[] | undefined; + _weights: number[] | undefined; + _epochs_per_sample: Float32Array | undefined; + _epochs_per_negative_sample: Float32Array | undefined; + _epoch_of_next_sample: Float32Array | undefined; + _epoch_of_next_negative_sample: Float32Array | undefined; + graph(): { + cols: number[] | undefined; + rows: number[] | undefined; + weights: number[] | undefined; + }; + /** + * @param {number} [iterations=350] - Number of iterations. Default is `350` + * @returns {T} + */ + transform(iterations?: number): T; + /** + * @param {number} [iterations=350] - Number of iterations. Default is `350` + * @returns {Generator} + */ + generator(iterations?: number): Generator; + /** + * @private + * @param {number} x + * @returns {number} + */ + private _clip; + /** + * Performs the optimization step. + * + * @private + * @param {Matrix} head_embedding + * @param {Matrix} tail_embedding + * @param {number[]} head + * @param {number[]} tail + * @returns {Matrix} + */ + private _optimize_layout; + /** + * @private + * @returns {Matrix} + */ + private next; + _alpha: number | undefined; } /** @@ -3419,8 +3470,8 @@ declare function inner_product(a: number[] | Float64Array, b: number[] | Float64 * @see {@link https://en.wikipedia.org/wiki/QR_decomposition#Using_the_Gram%E2%80%93Schmidt_process} */ declare function qr(A: Matrix): { - R: Matrix; - Q: Matrix; + R: Matrix; + Q: Matrix; }; /** @@ -3433,8 +3484,8 @@ declare function qr(A: Matrix): { * @see {@link http://mlwiki.org/index.php/Householder_Transformation} */ declare function qr_householder(A: Matrix): { - R: Matrix; - Q: Matrix; + R: Matrix; + Q: Matrix; }; /** @import { EigenArgs } from "./index.js" */ @@ -3449,371 +3500,439 @@ declare function qr_householder(A: Matrix): { * @returns {{ eigenvalues: Float64Array; eigenvectors: Float64Array[] }} The `k` biggest eigenvectors and eigenvalues * of Matrix `A`. */ -declare function simultaneous_poweriteration( - A: Matrix, - k?: number, - { seed, max_iterations, qr, tol }?: EigenArgs, -): { - eigenvalues: Float64Array; - eigenvectors: Float64Array[]; +declare function simultaneous_poweriteration(A: Matrix, k?: number, { seed, max_iterations, qr, tol }?: EigenArgs): { + eigenvalues: Float64Array; + eigenvectors: Float64Array[]; }; type QRDecomposition = (A: Matrix) => { - R: Matrix; - Q: Matrix; + R: Matrix; + Q: Matrix; }; type EigenArgs = { - /** - * - The number of maxiumum iterations the algorithm should run. Default is `100` - */ - max_iterations?: number | undefined; - /** - * - The seed value or a randomizer used in the algorithm. Default is `1212` - */ - seed?: number | Randomizer | undefined; - /** - * - The QR technique to use. Default is `qr_gramschmidt` - */ - qr?: QRDecomposition | undefined; - /** - * - Tolerated error for stopping criteria. Default is `1e-8` - */ - tol?: number | undefined; + /** + * - The number of maxiumum iterations the algorithm should run. Default is `100` + */ + max_iterations?: number | undefined; + /** + * - The seed value or a randomizer used in the algorithm. Default is `1212` + */ + seed?: number | Randomizer | undefined; + /** + * - The QR technique to use. Default is `qr_gramschmidt` + */ + qr?: QRDecomposition | undefined; + /** + * - Tolerated error for stopping criteria. Default is `1e-8` + */ + tol?: number | undefined; }; type ParametersLSP = { - /** - * - number of neighbors to consider. - */ - neighbors?: number | undefined; - /** - * - number of controlpoints - */ - control_points?: number | undefined; - /** - * - the dimensionality of the projection. - */ - d?: number | undefined; - /** - * - the metric which defines the distance between two points. - */ - metric?: Metric | undefined; - /** - * - the seed for the random number generator. - */ - seed?: number | undefined; + /** + * - number of neighbors to consider. + */ + neighbors?: number | undefined; + /** + * - number of controlpoints + */ + control_points?: number | undefined; + /** + * - the dimensionality of the projection. + */ + d?: number | undefined; + /** + * - the metric which defines the distance between two points. + */ + metric?: Metric | undefined; + /** + * - the seed for the random number generator. + */ + seed?: number | undefined; }; type ParametersFASTMAP = { - /** - * - The dimensionality of the projection - */ - d?: number | undefined; - /** - * - The metric which defines the distance between two points. - */ - metric?: Metric | undefined; - /** - * - The seed for the random number generator. - */ - seed?: number | undefined; + /** + * - The dimensionality of the projection + */ + d?: number | undefined; + /** + * - The metric which defines the distance between two points. + */ + metric?: Metric | undefined; + /** + * - The seed for the random number generator. + */ + seed?: number | undefined; }; type ParametersISOMAP = { - /** - * - The number of neighbors ISOMAP should use to project the data. - */ - neighbors?: number | undefined; - /** - * - the dimensionality of the projection. - */ - d?: number | undefined; - /** - * - the metric which defines the distance between two points. - */ - metric?: Metric | undefined; - /** - * - Whether to use classical MDS or SMACOF for the final DR. - */ - project?: "MDS" | "SMACOF" | undefined; - /** - * - the seed for the random number generator. - */ - seed?: number | undefined; - /** - * - Parameters for the eigendecomposition algorithm. - */ - eig_args?: Partial | undefined; + /** + * - The number of neighbors ISOMAP should use to project the data. + */ + neighbors?: number | undefined; + /** + * - the dimensionality of the projection. + */ + d?: number | undefined; + /** + * - the metric which defines the distance between two points. + */ + metric?: Metric | undefined; + /** + * - Whether to use classical MDS or SMACOF for the final DR. + */ + project?: "MDS" | "SMACOF" | undefined; + /** + * - the seed for the random number generator. + */ + seed?: number | undefined; + /** + * - Parameters for the eigendecomposition algorithm. + */ + eig_args?: Partial | undefined; }; type ParametersLDA = { - /** - * - The labels / classes for each data point. - */ - labels: any[] | Float64Array; - /** - * - The dimensionality of the projection. - */ - d?: number | undefined; - /** - * - The seed for the random number generator. - */ - seed?: number | undefined; - /** - * - Parameters for the eigendecomposition algorithm. - */ - eig_args?: Partial | undefined; + /** + * - The labels / classes for each data point. + */ + labels: any[] | Float64Array; + /** + * - The dimensionality of the projection. + */ + d?: number | undefined; + /** + * - The seed for the random number generator. + */ + seed?: number | undefined; + /** + * - Parameters for the eigendecomposition algorithm. + */ + eig_args?: Partial | undefined; }; type ParametersLLE = { - /** - * - The number of neighbors for LLE. - */ - neighbors?: number | undefined; - /** - * - the dimensionality of the projection. - */ - d?: number | undefined; - /** - * - the metric which defines the distance between two points. - */ - metric?: Metric | undefined; - /** - * - the seed for the random number generator. - */ - seed?: number | undefined; - /** - * - Parameters for the eigendecomposition algorithm. - */ - eig_args?: Partial | undefined; + /** + * - The number of neighbors for LLE. + */ + neighbors?: number | undefined; + /** + * - the dimensionality of the projection. + */ + d?: number | undefined; + /** + * - the metric which defines the distance between two points. + */ + metric?: Metric | undefined; + /** + * - the seed for the random number generator. + */ + seed?: number | undefined; + /** + * - Parameters for the eigendecomposition algorithm. + */ + eig_args?: Partial | undefined; }; type ParametersLTSA = { - /** - * - The number of neighbors for LTSA. - */ - neighbors?: number | undefined; - /** - * - the dimensionality of the projection. - */ - d?: number | undefined; - /** - * - the metric which defines the distance between two points. - */ - metric?: Metric | undefined; - /** - * - the seed for the random number generator. - */ - seed?: number | undefined; - /** - * - Parameters for the eigendecomposition algorithm. - */ - eig_args?: Partial | undefined; + /** + * - The number of neighbors for LTSA. + */ + neighbors?: number | undefined; + /** + * - the dimensionality of the projection. + */ + d?: number | undefined; + /** + * - the metric which defines the distance between two points. + */ + metric?: Metric | undefined; + /** + * - the seed for the random number generator. + */ + seed?: number | undefined; + /** + * - Parameters for the eigendecomposition algorithm. + */ + eig_args?: Partial | undefined; }; type ParametersMDS = { - /** - * - the dimensionality of the projection. - */ - d?: number | undefined; - /** - * - the metric which defines the distance between two points. - */ - metric?: Metric | "precomputed" | undefined; - /** - * - the seed for the random number generator. - */ - seed?: number | undefined; - /** - * - Parameters for the eigendecomposition algorithm. - */ - eig_args?: Partial | undefined; + /** + * - the dimensionality of the projection. + */ + d?: number | undefined; + /** + * - the metric which defines the distance between two points. + */ + metric?: Metric | "precomputed" | undefined; + /** + * - the seed for the random number generator. + */ + seed?: number | undefined; + /** + * - Parameters for the eigendecomposition algorithm. + */ + eig_args?: Partial | undefined; }; type ParametersPCA = { - /** - * - the dimensionality of the projection. - */ - d?: number | undefined; - /** - * - the seed for the random number generator. - */ - seed?: number | undefined; - /** - * - Parameters for the eigendecomposition algorithm. - */ - eig_args?: Partial | undefined; + /** + * - the dimensionality of the projection. + */ + d?: number | undefined; + /** + * - the seed for the random number generator. + */ + seed?: number | undefined; + /** + * - Parameters for the eigendecomposition algorithm. + */ + eig_args?: Partial | undefined; }; type ParametersSAMMON = { - /** - * - the dimensionality of the projection. - */ - d?: number | undefined; - /** - * - the metric which defines the distance between two points. - */ - metric?: Metric | "precomputed" | undefined; - /** - * - Either "PCA" or "MDS", with which SAMMON initialiates the projection. - */ - init_DR?: K | undefined; - /** - * - Parameters for the "init"-DR method. - */ - init_parameters?: ChooseDR[K] | undefined; - /** - * - learning rate for gradient descent. - */ - magic?: number | undefined; - /** - * - the seed for the random number generator. - */ - seed?: number | undefined; + /** + * - the dimensionality of the projection. + */ + d?: number | undefined; + /** + * - the metric which defines the distance between two points. + */ + metric?: Metric | "precomputed" | undefined; + /** + * - Either "PCA" or "MDS", with which SAMMON initialiates the projection. + */ + init_DR?: K | undefined; + /** + * - Parameters for the "init"-DR method. + */ + init_parameters?: ChooseDR[K] | undefined; + /** + * - learning rate for gradient descent. + */ + magic?: number | undefined; + /** + * - the seed for the random number generator. + */ + seed?: number | undefined; }; type ParametersSMACOF = { - /** - * - the dimensionality of the projection. - */ - d?: number | undefined; - /** - * - the metric which defines the distance between two points. - */ - metric?: Metric | "precomputed" | undefined; - /** - * - maximum number of iterations. - */ - iterations?: number | undefined; - /** - * - tolerance for stress difference. - */ - epsilon?: number | undefined; - /** - * - the seed for the random number generator. - */ - seed?: number | undefined; + /** + * - the dimensionality of the projection. + */ + d?: number | undefined; + /** + * - the metric which defines the distance between two points. + */ + metric?: Metric | "precomputed" | undefined; + /** + * - maximum number of iterations. + */ + iterations?: number | undefined; + /** + * - tolerance for stress difference. + */ + epsilon?: number | undefined; + /** + * - the seed for the random number generator. + */ + seed?: number | undefined; }; type ParametersSQDMDS = { - d?: number | undefined; - metric?: Metric | "precomputed" | undefined; - /** - * - Percentage of iterations using exaggeration phase. - */ - decay_start?: number | undefined; - /** - * - Controls the decay of the learning parameter. - */ - decay_cte?: number | undefined; - /** - * - the seed for the random number generator. - */ - seed?: number | undefined; + d?: number | undefined; + metric?: Metric | "precomputed" | undefined; + /** + * - Percentage of iterations using exaggeration phase. + */ + decay_start?: number | undefined; + /** + * - Controls the decay of the learning parameter. + */ + decay_cte?: number | undefined; + /** + * - the seed for the random number generator. + */ + seed?: number | undefined; }; type ParametersTopoMap = { - /** - * = euclidean - The metric which defines the distance between - * two points. - */ - metric: Metric; - /** - * = 1212 - The seed for the random number generator. - */ - seed: number; + /** + * = euclidean - The metric which defines the distance between + * two points. + */ + metric: Metric; + /** + * = 1212 - The seed for the random number generator. + */ + seed: number; }; type ParametersTriMap = { - /** - * - scaling factor. - */ - weight_adj?: number | undefined; - /** - * - number of inliers. - */ - n_inliers?: number | undefined; - /** - * - number of outliers. - */ - n_outliers?: number | undefined; - /** - * - number of random points. - */ - n_random?: number | undefined; - /** - * - the dimensionality of the projection. - */ - d?: number | undefined; - tol?: number | undefined; - /** - * - the metric which defines the distance between two points. - */ - metric?: Metric | undefined; - /** - * - the seed for the random number generator. - */ - seed?: number | undefined; + /** + * - scaling factor. + */ + weight_adj?: number | undefined; + /** + * - number of inliers. + */ + n_inliers?: number | undefined; + /** + * - number of outliers. + */ + n_outliers?: number | undefined; + /** + * - number of random points. + */ + n_random?: number | undefined; + /** + * - the dimensionality of the projection. + */ + d?: number | undefined; + tol?: number | undefined; + /** + * - the metric which defines the distance between two points. + */ + metric?: Metric | undefined; + /** + * - the seed for the random number generator. + */ + seed?: number | undefined; }; type ParametersTSNE = { - /** - * - perplexity. - */ - perplexity?: number | undefined; - /** - * - learning parameter. - */ - epsilon?: number | undefined; - /** - * - the dimensionality of the projection. - */ - d?: number | undefined; - /** - * - the metric which defines the distance between two points. - */ - metric?: Metric | "precomputed" | undefined; - /** - * - the seed for the random number generator. - */ - seed?: number | undefined; + /** + * - perplexity. + */ + perplexity?: number | undefined; + /** + * - learning parameter. + */ + epsilon?: number | undefined; + /** + * - the dimensionality of the projection. + */ + d?: number | undefined; + /** + * - the metric which defines the distance between two points. + */ + metric?: Metric | "precomputed" | undefined; + /** + * - the seed for the random number generator. + */ + seed?: number | undefined; +}; +type ParametersPaCMAP = { + /** + * - Number of nearest neighbors for NN pairs. + */ + n_neighbors?: number | undefined; + /** + * - Ratio of mid-near pairs to n_neighbors. + */ + MN_ratio?: number | undefined; + /** + * - Ratio of further pairs to n_neighbors. + */ + FP_ratio?: number | undefined; + /** + * - The dimensionality of the projection. + */ + d?: number | undefined; + /** + * - The metric which defines the distance between two points. + */ + metric?: Metric | undefined; + /** + * - Learning rate for the Adam optimizer. + */ + lr?: number | undefined; + /** + * - Number of iterations for each of the three phases. + */ + num_iters?: number[] | undefined; + /** + * - The seed for the random number generator. + */ + seed?: number | undefined; +}; +type ParametersLocalMAP = { + /** + * - Number of nearest neighbors for NN pairs. + */ + n_neighbors?: number | undefined; + /** + * - Ratio of mid-near pairs to n_neighbors. + */ + MN_ratio?: number | undefined; + /** + * - Ratio of further pairs to n_neighbors. + */ + FP_ratio?: number | undefined; + /** + * - The dimensionality of the projection. + */ + d?: number | undefined; + /** + * - The metric which defines the distance between two points. + */ + metric?: Metric | undefined; + /** + * - Learning rate for the Adam optimizer. + */ + lr?: number | undefined; + /** + * - Number of iterations for each of the three phases. + */ + num_iters?: number[] | undefined; + /** + * - Distance threshold for local FP pair resampling in phase 3. + */ + low_dist_thres?: number | undefined; + /** + * - The seed for the random number generator. + */ + seed?: number | undefined; }; type ParametersUMAP = { - /** - * - size of the local neighborhood. - */ - n_neighbors?: number | undefined; - /** - * - number of nearest neighbors connected in the local neighborhood. - */ - local_connectivity?: number | undefined; - /** - * - controls how tightly points get packed together. - */ - min_dist?: number | undefined; - /** - * - the dimensionality of the projection. - */ - d?: number | undefined; - /** - * - the metric which defines the distance between two points in the high-dimensional space. - */ - metric?: Metric | "precomputed" | undefined; - /** - * - The effective scale of embedded points. - */ - _spread?: number | undefined; - /** - * - Interpolate between union and intersection. - */ - _set_op_mix_ratio?: number | undefined; - /** - * - Weighting applied to negative samples. - */ - _repulsion_strength?: number | undefined; - /** - * - The number of negative samples per positive sample. - */ - _negative_sample_rate?: number | undefined; - /** - * - The number of training epochs. - */ - _n_epochs?: number | undefined; - /** - * - The initial learning rate for the optimization. - */ - _initial_alpha?: number | undefined; - /** - * - the seed for the random number generator. - */ - seed?: number | undefined; + /** + * - size of the local neighborhood. + */ + n_neighbors?: number | undefined; + /** + * - number of nearest neighbors connected in the local neighborhood. + */ + local_connectivity?: number | undefined; + /** + * - controls how tightly points get packed together. + */ + min_dist?: number | undefined; + /** + * - the dimensionality of the projection. + */ + d?: number | undefined; + /** + * - the metric which defines the distance between two points in the high-dimensional space. + */ + metric?: Metric | "precomputed" | undefined; + /** + * - The effective scale of embedded points. + */ + _spread?: number | undefined; + /** + * - Interpolate between union and intersection. + */ + _set_op_mix_ratio?: number | undefined; + /** + * - Weighting applied to negative samples. + */ + _repulsion_strength?: number | undefined; + /** + * - The number of negative samples per positive sample. + */ + _negative_sample_rate?: number | undefined; + /** + * - The number of training epochs. + */ + _n_epochs?: number | undefined; + /** + * - The initial learning rate for the optimization. + */ + _initial_alpha?: number | undefined; + /** + * - the seed for the random number generator. + */ + seed?: number | undefined; }; /** @import { Metric } from "../metrics/index.js" */ @@ -3854,118 +3973,109 @@ type ParametersUMAP = { * @see {@link https://erikbern.com/2015/09/24/nearest-neighbors-and-vector-models-epilogue-curse-of-dimensionality.html} */ declare class Annoy extends KNN { - /** - * Creates a new Annoy-style index with random projection trees. - * - * @param {T[]} elements - Elements to index - * @param {ParametersAnnoy} [parameters={}] - Configuration parameters - */ - constructor(elements: T[], parameters?: ParametersAnnoy); - _metric: Metric; - _numTrees: number; - _maxPointsPerLeaf: number; - _seed: number; - _randomizer: Randomizer; - /** - * @private - * @type {AnnoyNode[]} - */ - private _trees; - /** - * Get the number of trees in the index. - * @returns {number} - */ - get num_trees(): number; - /** - * Get the total number of nodes in all trees. - * @returns {number} - */ - get num_nodes(): number; - /** - * @private - * @param {any} node - * @returns {number} - */ - private _countNodes; - /** - * Add elements to the Annoy index. - * @param {T[]} elements - * @returns {this} - */ - add(elements: T[]): this; - /** - * Build all random projection trees. - * @private - */ - private _buildTrees; - /** - * Recursively build a random projection tree. - * @private - * @param {number[]} indices - Indices of elements to include - * @returns {AnnoyNode} - */ - private _buildTreeRecursive; - /** - * Compute distance from point to hyperplane. - * @private - * @param {T} point - * @param {number[]} normal - * @param {number} offset - * @returns {number} Signed distance (positive = right side, negative = left side) - */ - private _distanceToHyperplane; - /** - * Search for k approximate nearest neighbors. - * @param {T} query - * @param {number} [k=5] - * @returns {{ element: T; index: number; distance: number }[]} - */ - search( - query: T, - k?: number, - ): { - element: T; - index: number; - distance: number; - }[]; - /** - * Search tree using priority queue for better recall. - * Explores nodes in order of distance to hyperplane. - * @private - * @param {AnnoyNode} node - * @param {T} query - * @param {Set} candidates - * @param {number} maxCandidates - */ - private _searchTreePriority; - /** - * @param {number} i - * @param {number} [k=5] - * @returns {{ element: T; index: number; distance: number }[]} - */ - search_by_index( - i: number, - k?: number, - ): { - element: T; - index: number; - distance: number; - }[]; - /** - * Alias for search_by_index for backward compatibility. - * - * @param {number} i - Index of the query element - * @param {number} [k=5] - Number of nearest neighbors to return - * @returns {{ element: T; index: number; distance: number }[]} - */ - search_index( - i: number, - k?: number, - ): { - element: T; - index: number; - distance: number; - }[]; + /** + * Creates a new Annoy-style index with random projection trees. + * + * @param {T[]} elements - Elements to index + * @param {ParametersAnnoy} [parameters={}] - Configuration parameters + */ + constructor(elements: T[], parameters?: ParametersAnnoy); + _metric: Metric; + _numTrees: number; + _maxPointsPerLeaf: number; + _seed: number; + _randomizer: Randomizer; + /** + * @private + * @type {AnnoyNode[]} + */ + private _trees; + /** + * Get the number of trees in the index. + * @returns {number} + */ + get num_trees(): number; + /** + * Get the total number of nodes in all trees. + * @returns {number} + */ + get num_nodes(): number; + /** + * @private + * @param {any} node + * @returns {number} + */ + private _countNodes; + /** + * Add elements to the Annoy index. + * @param {T[]} elements + * @returns {this} + */ + add(elements: T[]): this; + /** + * Build all random projection trees. + * @private + */ + private _buildTrees; + /** + * Recursively build a random projection tree. + * @private + * @param {number[]} indices - Indices of elements to include + * @returns {AnnoyNode} + */ + private _buildTreeRecursive; + /** + * Compute distance from point to hyperplane. + * @private + * @param {T} point + * @param {number[]} normal + * @param {number} offset + * @returns {number} Signed distance (positive = right side, negative = left side) + */ + private _distanceToHyperplane; + /** + * Search for k approximate nearest neighbors. + * @param {T} query + * @param {number} [k=5] + * @returns {{ element: T; index: number; distance: number }[]} + */ + search(query: T, k?: number): { + element: T; + index: number; + distance: number; + }[]; + /** + * Search tree using priority queue for better recall. + * Explores nodes in order of distance to hyperplane. + * @private + * @param {AnnoyNode} node + * @param {T} query + * @param {Set} candidates + * @param {number} maxCandidates + */ + private _searchTreePriority; + /** + * @param {number} i + * @param {number} [k=5] + * @returns {{ element: T; index: number; distance: number }[]} + */ + search_by_index(i: number, k?: number): { + element: T; + index: number; + distance: number; + }[]; + /** + * Alias for search_by_index for backward compatibility. + * + * @param {number} i - Index of the query element + * @param {number} [k=5] - Number of nearest neighbors to return + * @returns {{ element: T; index: number; distance: number }[]} + */ + search_index(i: number, k?: number): { + element: T; + index: number; + distance: number; + }[]; } /** @import { Metric } from "../metrics/index.js" */ @@ -3989,67 +4099,61 @@ declare class Annoy extends KNN */ declare class BallTree extends KNN { - /** - * Generates a BallTree with given `elements`. - * - * @param {T[]} elements - Elements which should be added to the BallTree - * @param {ParametersBallTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}` - * @see {@link https://en.wikipedia.org/wiki/Ball_tree} - * @see {@link https://github.com/invisal/noobjs/blob/master/src/tree/BallTree.js} - */ - constructor(elements: T[], parameters?: ParametersBallTree); - /** - * @private - * @type {BallTreeNode | BallTreeLeaf} - */ - private _root; - /** @returns {Metric} */ - get _metric(): Metric; - /** - * @private - * @param {ElementWithIndex[]} elements - * @returns {BallTreeNode | BallTreeLeaf} Root of balltree. - */ - private _construct; - /** - * @private - * @param {ElementWithIndex[]} B - * @returns {number} - */ - private _greatest_spread; - /** - * @param {number} i - * @param {number} k - */ - search_by_index( - i: number, - k?: number, - ): { - element: T; - index: number; - distance: number; - }[]; - /** - * @param {T} t - Query element. - * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5` - * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors. - */ - search( - t: T, - k?: number, - ): { - element: T; - index: number; - distance: number; - }[]; - /** - * @private - * @param {T} t - Query element. - * @param {number} k - Number of nearest neighbors to return. - * @param {Heap>} Q - Heap consists of the currently found `k` nearest neighbors. - * @param {BallTreeNode | BallTreeLeaf} B - */ - private _search; + /** + * Generates a BallTree with given `elements`. + * + * @param {T[]} elements - Elements which should be added to the BallTree + * @param {ParametersBallTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}` + * @see {@link https://en.wikipedia.org/wiki/Ball_tree} + * @see {@link https://github.com/invisal/noobjs/blob/master/src/tree/BallTree.js} + */ + constructor(elements: T[], parameters?: ParametersBallTree); + /** + * @private + * @type {BallTreeNode | BallTreeLeaf} + */ + private _root; + /** @returns {Metric} */ + get _metric(): Metric; + /** + * @private + * @param {ElementWithIndex[]} elements + * @returns {BallTreeNode | BallTreeLeaf} Root of balltree. + */ + private _construct; + /** + * @private + * @param {ElementWithIndex[]} B + * @returns {number} + */ + private _greatest_spread; + /** + * @param {number} i + * @param {number} k + */ + search_by_index(i: number, k?: number): { + element: T; + index: number; + distance: number; + }[]; + /** + * @param {T} t - Query element. + * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5` + * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors. + */ + search(t: T, k?: number): { + element: T; + index: number; + distance: number; + }[]; + /** + * @private + * @param {T} t - Query element. + * @param {number} k - Number of nearest neighbors to return. + * @param {Heap>} Q - Heap consists of the currently found `k` nearest neighbors. + * @param {BallTreeNode | BallTreeLeaf} B + */ + private _search; } /** @import { Metric } from "../metrics/index.js" */ @@ -4105,173 +4209,165 @@ declare class BallTree extends KNN extends KNN { - /** - * Creates a new HNSW index. - * - * @param {T[]} points - Initial points to add to the index - * @param {ParametersHNSW} [parameters={}] - Configuration parameters - */ - constructor(points: T[], parameters?: ParametersHNSW); - /** @type {Metric} */ - _metric: Metric; - /** @type {Function} */ - _select: Function; - /** - * @private - * @type {Map} - */ - private _graph; - /** @type {number} */ - _next_index: number; - /** @type {number} */ - _m: number; - /** @type {number} */ - _ef_construction: number; - /** @type {number} */ - _ef: number; - /** @type {number} */ - _m0: number; - /** @type {number} */ - _mL: number; - /** @type {Randomizer} */ - _randomizer: Randomizer; - /** @type {number} - Current maximum layer in the graph */ - _L: number; - /** @type {number[] | null} - Entry point indices for search */ - _ep: number[] | null; - /** - * Add a single element to the index. - * - * @param {T} element - Element to add - * @returns {HNSW} This instance for chaining - */ - addOne(element: T): HNSW; - /** - * Add multiple elements to the index. - * - * @param {T[]} new_elements - Elements to add - * @returns {HNSW} This instance for chaining - */ - add(new_elements: T[]): HNSW; - /** - * Select neighbors using the heuristic approach. - * - * The heuristic extends candidates with their neighbors and selects - * points that are closer to the query than to already selected points. - * This maintains graph connectivity better than simple selection. - * - * @private - * @param {T} q - Query element - * @param {Candidate[]} candidates - Candidate elements with distances - * @param {number} M - Maximum number of neighbors to return - * @param {number} l_c - Layer number - * @param {boolean} [extend_candidates=true] - Whether to extend candidates with their neighbors - * @param {boolean} [keep_pruned_connections=true] - Whether to add pruned connections back if needed - * @returns {number[]} Selected neighbor indices - */ - private _select_heuristic; - /** - * Select neighbors using simple distance-based selection. - * - * Simply returns the M closest candidates to the query. - * - * @private - * @param {T} q - Query element - * @param {Candidate[]} C - Candidate elements with distances - * @param {number} M - Maximum number of neighbors to return - * @returns {number[]} M nearest candidate indices - */ - private _select_simple; - /** - * Search a single layer for nearest neighbors. - * - * Implements the greedy search algorithm: start from entry points, - * always expand the closest unvisited candidate, maintain a list - * of the ef closest found neighbors. - * - * @private - * @param {T} q - Query element - * @param {number[] | null} ep_indices - Entry point indices - * @param {number} ef - Number of nearest neighbors to find - * @param {number} l_c - Layer number to search - * @returns {Candidate[]} ef nearest neighbors found with their distances - */ - private _search_layer; - /** - * Fallback linear search when graph search fails - * @private - * @param {T} q - Query element - * @param {number} K - Number of nearest neighbors to return - * @returns {Candidate[]} - */ - private _linear_search; - /** - * Iterator for searching the HNSW graph layer by layer. - * - * Yields intermediate results at each layer for debugging or visualization. - * - * @param {T} q - Query element - * @param {number} K - Number of nearest neighbors to return - * @param {number?} [ef] - Size of dynamic candidate list - * @yields {{layer: number, candidates: Candidate[]}} - */ - search_iter( - q: T, - K: number, - ef?: number | null, - ): Generator< - { - layer: number; - candidates: { - element: T; - index: number; - distance: number; - }[]; - }, - void, - unknown - >; - /** - * Get the number of elements in the index. - * - * @returns {number} Number of elements - */ - get size(): number; - /** - * Get the number of layers in the graph. - * - * @returns {number} Number of layers - */ - get num_layers(): number; - /** - * Get an element by its index. - * - * @param {number} index - Element index - * @returns {T} The element at the given index - */ - get_element(index: number): T; - /** - * Search for nearest neighbors using an element index as the query. - * - * @param {number} i - Index of the query element - * @param {number} [K=5] - Number of nearest neighbors to return - * @returns {Candidate[]} K nearest neighbors - */ - search_by_index(i: number, K?: number): Candidate[]; + /** + * Creates a new HNSW index. + * + * @param {T[]} points - Initial points to add to the index + * @param {ParametersHNSW} [parameters={}] - Configuration parameters + */ + constructor(points: T[], parameters?: ParametersHNSW); + /** @type {Metric} */ + _metric: Metric; + /** @type {Function} */ + _select: Function; + /** + * @private + * @type {Map} + */ + private _graph; + /** @type {number} */ + _next_index: number; + /** @type {number} */ + _m: number; + /** @type {number} */ + _ef_construction: number; + /** @type {number} */ + _ef: number; + /** @type {number} */ + _m0: number; + /** @type {number} */ + _mL: number; + /** @type {Randomizer} */ + _randomizer: Randomizer; + /** @type {number} - Current maximum layer in the graph */ + _L: number; + /** @type {number[] | null} - Entry point indices for search */ + _ep: number[] | null; + /** + * Add a single element to the index. + * + * @param {T} element - Element to add + * @returns {HNSW} This instance for chaining + */ + addOne(element: T): HNSW; + /** + * Add multiple elements to the index. + * + * @param {T[]} new_elements - Elements to add + * @returns {HNSW} This instance for chaining + */ + add(new_elements: T[]): HNSW; + /** + * Select neighbors using the heuristic approach. + * + * The heuristic extends candidates with their neighbors and selects + * points that are closer to the query than to already selected points. + * This maintains graph connectivity better than simple selection. + * + * @private + * @param {T} q - Query element + * @param {Candidate[]} candidates - Candidate elements with distances + * @param {number} M - Maximum number of neighbors to return + * @param {number} l_c - Layer number + * @param {boolean} [extend_candidates=true] - Whether to extend candidates with their neighbors + * @param {boolean} [keep_pruned_connections=true] - Whether to add pruned connections back if needed + * @returns {number[]} Selected neighbor indices + */ + private _select_heuristic; + /** + * Select neighbors using simple distance-based selection. + * + * Simply returns the M closest candidates to the query. + * + * @private + * @param {T} q - Query element + * @param {Candidate[]} C - Candidate elements with distances + * @param {number} M - Maximum number of neighbors to return + * @returns {number[]} M nearest candidate indices + */ + private _select_simple; + /** + * Search a single layer for nearest neighbors. + * + * Implements the greedy search algorithm: start from entry points, + * always expand the closest unvisited candidate, maintain a list + * of the ef closest found neighbors. + * + * @private + * @param {T} q - Query element + * @param {number[] | null} ep_indices - Entry point indices + * @param {number} ef - Number of nearest neighbors to find + * @param {number} l_c - Layer number to search + * @returns {Candidate[]} ef nearest neighbors found with their distances + */ + private _search_layer; + /** + * Fallback linear search when graph search fails + * @private + * @param {T} q - Query element + * @param {number} K - Number of nearest neighbors to return + * @returns {Candidate[]} + */ + private _linear_search; + /** + * Iterator for searching the HNSW graph layer by layer. + * + * Yields intermediate results at each layer for debugging or visualization. + * + * @param {T} q - Query element + * @param {number} K - Number of nearest neighbors to return + * @param {number?} [ef] - Size of dynamic candidate list + * @yields {{layer: number, candidates: Candidate[]}} + */ + search_iter(q: T, K: number, ef?: number | null): Generator<{ + layer: number; + candidates: { + element: T; + index: number; + distance: number; + }[]; + }, void, unknown>; + /** + * Get the number of elements in the index. + * + * @returns {number} Number of elements + */ + get size(): number; + /** + * Get the number of layers in the graph. + * + * @returns {number} Number of layers + */ + get num_layers(): number; + /** + * Get an element by its index. + * + * @param {number} index - Element index + * @returns {T} The element at the given index + */ + get_element(index: number): T; + /** + * Search for nearest neighbors using an element index as the query. + * + * @param {number} i - Index of the query element + * @param {number} [K=5] - Number of nearest neighbors to return + * @returns {Candidate[]} K nearest neighbors + */ + search_by_index(i: number, K?: number): Candidate[]; } type Candidate = { - /** - * - The actual data point - */ - element: T; - /** - * - Global index in the dataset - */ - index: number; - /** - * - Distance from query - */ - distance: number; + /** + * - The actual data point + */ + element: T; + /** + * - Global index in the dataset + */ + index: number; + /** + * - Distance from query + */ + distance: number; }; /** @import { Metric } from "../metrics/index.js" */ @@ -4304,60 +4400,54 @@ type Candidate = { * @see {@link https://en.wikipedia.org/wiki/K-d_tree} */ declare class KDTree extends KNN { - /** - * Generates a KD-Tree with given `elements`. - * - * @param {T[]} elements - Elements which should be added to the KD-Tree - * @param {ParametersKDTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}` - */ - constructor(elements: T[], parameters?: ParametersKDTree); - /** - * @private - * @type {KDTreeNode | KDTreeLeaf | null} - */ - private _root; - /** @returns {Metric} */ - get _metric(): Metric; - /** - * @private - * @param {ElementWithIndex[]} elements - * @param {number} depth - Current depth in the tree (determines splitting axis) - * @returns {KDTreeNode | KDTreeLeaf | null} Root of KD-Tree. - */ - private _construct; - /** - * @param {number} i - * @param {number} k - */ - search_by_index( - i: number, - k?: number, - ): { - element: T; - index: number; - distance: number; - }[]; - /** - * @param {T} t - Query element. - * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5` - * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors. - */ - search( - t: T, - k?: number, - ): { - element: T; - index: number; - distance: number; - }[]; - /** - * @private - * @param {T} target - Query element. - * @param {number} k - Number of nearest neighbors to return. - * @param {KDTreeNode | KDTreeLeaf | null} node - Current node. - * @param {Heap<{ point: ElementWithIndex; distance: number }>} best - Heap of k best found so far. - */ - private _search_recursive; + /** + * Generates a KD-Tree with given `elements`. + * + * @param {T[]} elements - Elements which should be added to the KD-Tree + * @param {ParametersKDTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}` + */ + constructor(elements: T[], parameters?: ParametersKDTree); + /** + * @private + * @type {KDTreeNode | KDTreeLeaf | null} + */ + private _root; + /** @returns {Metric} */ + get _metric(): Metric; + /** + * @private + * @param {ElementWithIndex[]} elements + * @param {number} depth - Current depth in the tree (determines splitting axis) + * @returns {KDTreeNode | KDTreeLeaf | null} Root of KD-Tree. + */ + private _construct; + /** + * @param {number} i + * @param {number} k + */ + search_by_index(i: number, k?: number): { + element: T; + index: number; + distance: number; + }[]; + /** + * @param {T} t - Query element. + * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5` + * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors. + */ + search(t: T, k?: number): { + element: T; + index: number; + distance: number; + }[]; + /** + * @private + * @param {T} target - Query element. + * @param {number} k - Number of nearest neighbors to return. + * @param {KDTreeNode | KDTreeLeaf | null} node - Current node. + * @param {Heap<{ point: ElementWithIndex; distance: number }>} best - Heap of k best found so far. + */ + private _search_recursive; } /** @import { Metric } from "../metrics/index.js" */ @@ -4388,72 +4478,66 @@ declare class KDTree extends KNN extends KNN { - /** - * Creates a new LSH index. - * - * @param {T[]} elements - Elements to index - * @param {ParametersLSH} [parameters={}] - Configuration parameters - */ - constructor(elements: T[], parameters?: ParametersLSH); - _metric: Metric; - _numHashTables: number; - _numHashFunctions: number; - _seed: number; - _randomizer: Randomizer; - /** @type {Map[]} */ - _hashTables: Map[]; - /** @type {Float64Array[][]} */ - _projections: Float64Array[][]; - /** @type {number[][]} */ - _offsets: number[][]; - /** @type {number} */ - _dim: number; - /** - * Initialize random projection vectors for all hash tables. - * @private - */ - private _initializeHashFunctions; - /** - * Compute hash signature for an element using random projections. - * @private - * @param {T} element - * @param {number} tableIndex - * @returns {string} Hash signature - */ - private _computeHash; - /** - * Add elements to the LSH index. - * @param {T[]} elements - * @returns {this} - */ - add(elements: T[]): this; - /** - * Search for k approximate nearest neighbors. - * @param {T} query - * @param {number} [k=5] - * @returns {{ element: T; index: number; distance: number }[]} - */ - search( - query: T, - k?: number, - ): { - element: T; - index: number; - distance: number; - }[]; - /** - * @param {number} i - * @param {number} [k=5] - * @returns {{ element: T; index: number; distance: number }[]} - */ - search_by_index( - i: number, - k?: number, - ): { - element: T; - index: number; - distance: number; - }[]; + /** + * Creates a new LSH index. + * + * @param {T[]} elements - Elements to index + * @param {ParametersLSH} [parameters={}] - Configuration parameters + */ + constructor(elements: T[], parameters?: ParametersLSH); + _metric: Metric; + _numHashTables: number; + _numHashFunctions: number; + _seed: number; + _randomizer: Randomizer; + /** @type {Map[]} */ + _hashTables: Map[]; + /** @type {Float64Array[][]} */ + _projections: Float64Array[][]; + /** @type {number[][]} */ + _offsets: number[][]; + /** @type {number} */ + _dim: number; + /** + * Initialize random projection vectors for all hash tables. + * @private + */ + private _initializeHashFunctions; + /** + * Compute hash signature for an element using random projections. + * @private + * @param {T} element + * @param {number} tableIndex + * @returns {string} Hash signature + */ + private _computeHash; + /** + * Add elements to the LSH index. + * @param {T[]} elements + * @returns {this} + */ + add(elements: T[]): this; + /** + * Search for k approximate nearest neighbors. + * @param {T} query + * @param {number} [k=5] + * @returns {{ element: T; index: number; distance: number }[]} + */ + search(query: T, k?: number): { + element: T; + index: number; + distance: number; + }[]; + /** + * @param {number} i + * @param {number} [k=5] + * @returns {{ element: T; index: number; distance: number }[]} + */ + search_by_index(i: number, k?: number): { + element: T; + index: number; + distance: number; + }[]; } /** @import { ParametersNaiveKNN } from "./index.js" */ @@ -4470,44 +4554,38 @@ declare class LSH extends KNN */ declare class NaiveKNN extends KNN { - /** - * Generates a KNN list with given `elements`. - * - * @param {T[]} elements - Elements which should be added to the KNN list - * @param {ParametersNaiveKNN} parameters - */ - constructor(elements: T[], parameters?: ParametersNaiveKNN); - _D: Matrix; - /** @type {Heap<{ value: number; index: number }>[]} */ - KNN: Heap<{ - value: number; - index: number; - }>[]; - /** - * @param {number} i - * @param {number} k - */ - search_by_index( - i: number, - k?: number, - ): { - element: T; - index: number; - distance: number; - }[]; - /** - * @param {T} t - Query element. - * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5` - * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors. - */ - search( - t: T, - k?: number, - ): { - element: T; - index: number; - distance: number; - }[]; + /** + * Generates a KNN list with given `elements`. + * + * @param {T[]} elements - Elements which should be added to the KNN list + * @param {ParametersNaiveKNN} parameters + */ + constructor(elements: T[], parameters?: ParametersNaiveKNN); + _D: Matrix; + /** @type {Heap<{ value: number; index: number }>[]} */ + KNN: Heap<{ + value: number; + index: number; + }>[]; + /** + * @param {number} i + * @param {number} k + */ + search_by_index(i: number, k?: number): { + element: T; + index: number; + distance: number; + }[]; + /** + * @param {T} t - Query element. + * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5` + * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors. + */ + search(t: T, k?: number): { + element: T; + index: number; + distance: number; + }[]; } /** @import {ParametersNNDescent} from "./index.js" */ @@ -4541,194 +4619,188 @@ declare class NaiveKNN extends KNN extends KNN { - /** - * @param {T[]} elements - Called V in paper. - * @param {Partial} parameters - * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf} - */ - constructor(elements: T[], parameters?: Partial); - /** - * @private - * @type {KNNHeap[]} - */ - private _B; - /** - * @private - * @type {NNDescentNeighbor[][]} - */ - private nn; - _N: number; - _randomizer: Randomizer; - _sample_size: number; - _nndescent_elements: { - value: T; - index: number; - flag: boolean; - }[]; - /** - * Samples Array A with sample size. - * - * @private - * @template U - * @param {U[]} A - * @returns {U[]} - */ - private _sample; - /** - * @private - * @param {KNNHeap} B - * @param {NNDescentNeighbor} u - * @returns {number} - */ - private _update; - /** - * @private - * @param {(KNNHeap | null)[]} B - * @returns {NNDescentNeighbor[][]} - */ - private _reverse; - /** - * @param {T[]} elements - * @returns {this} - */ - add(elements: T[]): this; - /** - * @param {T} x - * @param {number} [k=5] Default is `5` - * @returns {{ element: T, index: number; distance: number }[]} - */ - search( - x: T, - k?: number, - ): { - element: T; - index: number; - distance: number; - }[]; - /** - * @param {number} i - * @param {number} [k=5] Default is `5` - * @returns {{ element: T; index: number; distance: number }[]} - */ - search_by_index( - i: number, - k?: number, - ): { - element: T; - index: number; - distance: number; - }[]; + /** + * @param {T[]} elements - Called V in paper. + * @param {Partial} parameters + * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf} + */ + constructor(elements: T[], parameters?: Partial); + /** + * @private + * @type {KNNHeap[]} + */ + private _B; + /** + * @private + * @type {NNDescentNeighbor[][]} + */ + private nn; + _N: number; + _randomizer: Randomizer; + _sample_size: number; + _nndescent_elements: { + value: T; + index: number; + flag: boolean; + }[]; + /** + * Samples Array A with sample size. + * + * @private + * @template U + * @param {U[]} A + * @returns {U[]} + */ + private _sample; + /** + * @private + * @param {KNNHeap} B + * @param {NNDescentNeighbor} u + * @returns {number} + */ + private _update; + /** + * @private + * @param {(KNNHeap | null)[]} B + * @returns {NNDescentNeighbor[][]} + */ + private _reverse; + /** + * @param {T[]} elements + * @returns {this} + */ + add(elements: T[]): this; + /** + * @param {T} x + * @param {number} [k=5] Default is `5` + * @returns {{ element: T, index: number; distance: number }[]} + */ + search(x: T, k?: number): { + element: T; + index: number; + distance: number; + }[]; + /** + * @param {number} i + * @param {number} [k=5] Default is `5` + * @returns {{ element: T; index: number; distance: number }[]} + */ + search_by_index(i: number, k?: number): { + element: T; + index: number; + distance: number; + }[]; } type ParametersAnnoy = { - /** - * - Metric to use: (a, b) => distance. Default is `euclidean` - */ - metric: Metric; - /** - * - Number of random projection trees to build. Default is `10` - */ - numTrees: number; - /** - * - Maximum points per leaf node. Default is `10` - */ - maxPointsPerLeaf: number; - /** - * - Seed for random number generator. Default is `1212` - */ - seed: number; + /** + * - Metric to use: (a, b) => distance. Default is `euclidean` + */ + metric: Metric; + /** + * - Number of random projection trees to build. Default is `10` + */ + numTrees: number; + /** + * - Maximum points per leaf node. Default is `10` + */ + maxPointsPerLeaf: number; + /** + * - Seed for random number generator. Default is `1212` + */ + seed: number; }; type ParametersBallTree = { - metric: Metric; - seed: number; + metric: Metric; + seed: number; }; type ParametersHNSW = { - /** - * - Metric to use: (a, b) => distance. Default is `euclidean` - */ - metric: Metric; - /** - * - Use heuristics or naive selection. Default is `true` - */ - heuristic: boolean; - /** - * - Max number of connections per element (excluding ground layer). Default is `16` - */ - m: number; - /** - * - Size of candidate list during construction. Default is `200` - */ - ef_construction: number; - /** - * - Max number of connections for ground layer (layer 0). Default is `2 * m` - */ - m0: number | null; - /** - * - Normalization factor for level generation. Default is `1 / Math.log(m)` - */ - mL: number | null; - /** - * - Seed for random number generator. Default is `1212` - */ - seed: number; - /** - * - Size of candidate list during search. Default is `50` - */ - ef: number; + /** + * - Metric to use: (a, b) => distance. Default is `euclidean` + */ + metric: Metric; + /** + * - Use heuristics or naive selection. Default is `true` + */ + heuristic: boolean; + /** + * - Max number of connections per element (excluding ground layer). Default is `16` + */ + m: number; + /** + * - Size of candidate list during construction. Default is `200` + */ + ef_construction: number; + /** + * - Max number of connections for ground layer (layer 0). Default is `2 * m` + */ + m0: number | null; + /** + * - Normalization factor for level generation. Default is `1 / Math.log(m)` + */ + mL: number | null; + /** + * - Seed for random number generator. Default is `1212` + */ + seed: number; + /** + * - Size of candidate list during search. Default is `50` + */ + ef: number; }; type ParametersKDTree = { - /** - * - Metric to use: (a, b) => distance. Default is `euclidean` - */ - metric: Metric; - seed: number; + /** + * - Metric to use: (a, b) => distance. Default is `euclidean` + */ + metric: Metric; + seed: number; }; type ParametersLSH = { - /** - * - Metric to use: (a, b) => distance. Default is `euclidean` - */ - metric: Metric; - /** - * - Number of hash tables. Default is `10` - */ - numHashTables: number; - /** - * - Number of hash functions per table. Default is `10` - */ - numHashFunctions: number; - /** - * - Seed for random number generator. Default is `1212` - */ - seed: number; + /** + * - Metric to use: (a, b) => distance. Default is `euclidean` + */ + metric: Metric; + /** + * - Number of hash tables. Default is `10` + */ + numHashTables: number; + /** + * - Number of hash functions per table. Default is `10` + */ + numHashFunctions: number; + /** + * - Seed for random number generator. Default is `1212` + */ + seed: number; }; type ParametersNaiveKNN = { - /** - * Is either precomputed or a function to use: (a, b) => distance - */ - metric?: Metric | "precomputed" | undefined; - seed?: number | undefined; + /** + * Is either precomputed or a function to use: (a, b) => distance + */ + metric?: Metric | "precomputed" | undefined; + seed?: number | undefined; }; type ParametersNNDescent = { - /** - * - Called sigma in paper. Default is `euclidean` - */ - metric: Metric; - /** - * =10 - Number of samples. Default is `10` - */ - samples: number; - /** - * = .8 - Sample rate. Default is `.8` - */ - rho: number; - /** - * = 0.0001 - Precision parameter. Default is `0.0001` - */ - delta: number; - /** - * = 1212 - Seed for the random number generator. Default is `1212` - */ - seed: number; + /** + * - Called sigma in paper. Default is `euclidean` + */ + metric: Metric; + /** + * =10 - Number of samples. Default is `10` + */ + samples: number; + /** + * = .8 - Sample rate. Default is `.8` + */ + rho: number; + /** + * = 0.0001 - Precision parameter. Default is `0.0001` + */ + delta: number; + /** + * = 1212 - Seed for the random number generator. Default is `1212` + */ + seed: number; }; /** @@ -4760,113 +4832,11 @@ declare function neumair_sum(summands: number[] | Float64Array): number; * @returns {T} * @see http://optimization-js.github.io/optimization-js/optimization.js.html#line438 */ -declare function powell( - f: (d: T) => number, - x0: T, - max_iter?: number, -): T; +declare function powell(f: (d: T) => number, x0: T, max_iter?: number): T; type InputType = Matrix | Float64Array[] | number[][]; declare const version: string; -export { - Annoy, - BallTree, - CURE, - DisjointSet, - FASTMAP, - HNSW, - Heap, - HierarchicalClustering, - ISOMAP, - KDTree, - KMeans, - KMedoids, - LDA, - LLE, - LSH, - LSP, - LTSA, - MDS, - Matrix, - MeanShift, - NNDescent, - NaiveKNN, - OPTICS, - PCA, - Randomizer, - SAMMON, - SMACOF, - SQDMDS, - TSNE, - TopoMap, - TriMap, - UMAP, - XMeans, - bray_curtis, - canberra, - chebyshev, - cosine, - distance_matrix, - euclidean, - euclidean_squared, - goodman_kruskal, - hamming, - haversine, - inner_product, - jaccard, - k_nearest_neighbors, - kahan_sum, - linspace, - manhattan, - max, - min, - neumair_sum, - norm, - normalize, - powell, - qr, - qr_householder, - simultaneous_poweriteration, - sokal_michener, - version, - wasserstein, - yule, -}; -export type { - Comparator, - EigenArgs, - InputType, - Metric, - ParametersAnnoy, - ParametersBallTree, - ParametersCURE, - ParametersFASTMAP, - ParametersHNSW, - ParametersHierarchicalClustering, - ParametersISOMAP, - ParametersKDTree, - ParametersKMeans, - ParametersKMedoids, - ParametersLDA, - ParametersLLE, - ParametersLSH, - ParametersLSP, - ParametersLTSA, - ParametersMDS, - ParametersMeanShift, - ParametersNNDescent, - ParametersNaiveKNN, - ParametersOptics, - ParametersPCA, - ParametersSAMMON, - ParametersSMACOF, - ParametersSQDMDS, - ParametersTSNE, - ParametersTopoMap, - ParametersTriMap, - ParametersUMAP, - ParametersXMeans, - QRDecomposition, -}; +export { Annoy, BallTree, CURE, DisjointSet, FASTMAP, HNSW, Heap, HierarchicalClustering, ISOMAP, KDTree, KMeans, KMedoids, LDA, LLE, LSH, LSP, LTSA, LocalMAP, MDS, Matrix, MeanShift, NNDescent, NaiveKNN, OPTICS, PCA, PaCMAP, Randomizer, SAMMON, SMACOF, SQDMDS, TSNE, TopoMap, TriMap, UMAP, XMeans, bray_curtis, canberra, chebyshev, cosine, distance_matrix, euclidean, euclidean_squared, goodman_kruskal, hamming, haversine, inner_product, jaccard, k_nearest_neighbors, kahan_sum, linspace, manhattan, max, min, neumair_sum, norm, normalize, powell, qr, qr_householder, simultaneous_poweriteration, sokal_michener, version, wasserstein, yule }; +export type { Comparator, EigenArgs, InputType, Metric, ParametersAnnoy, ParametersBallTree, ParametersCURE, ParametersFASTMAP, ParametersHNSW, ParametersHierarchicalClustering, ParametersISOMAP, ParametersKDTree, ParametersKMeans, ParametersKMedoids, ParametersLDA, ParametersLLE, ParametersLSH, ParametersLSP, ParametersLTSA, ParametersLocalMAP, ParametersMDS, ParametersMeanShift, ParametersNNDescent, ParametersNaiveKNN, ParametersOptics, ParametersPCA, ParametersPaCMAP, ParametersSAMMON, ParametersSMACOF, ParametersSQDMDS, ParametersTSNE, ParametersTopoMap, ParametersTriMap, ParametersUMAP, ParametersXMeans, QRDecomposition }; //# sourceMappingURL=druid.d.cts.map diff --git a/dist/druid.d.cts.map b/dist/druid.d.cts.map index aeaae5b..61ac06f 100644 --- a/dist/druid.d.cts.map +++ b/dist/druid.d.cts.map @@ -1 +1 @@ -{"version":3,"file":"druid.d.cts","sources":["types/metrics/bray_curtis.d.ts","types/metrics/canberra.d.ts","types/metrics/chebyshev.d.ts","types/metrics/cosine.d.ts","types/metrics/euclidean.d.ts","types/metrics/euclidean_squared.d.ts","types/metrics/goodman_kruskal.d.ts","types/metrics/hamming.d.ts","types/metrics/haversine.d.ts","types/metrics/jaccard.d.ts","types/metrics/manhattan.d.ts","types/metrics/sokal_michener.d.ts","types/metrics/wasserstein.d.ts","types/metrics/yule.d.ts","types/metrics/index.d.ts","types/matrix/distance_matrix.d.ts","types/matrix/k_nearest_neighbors.d.ts","types/matrix/linspace.d.ts","types/util/max.d.ts","types/util/min.d.ts","types/util/randomizer.d.ts","types/matrix/Matrix.d.ts","types/matrix/norm.d.ts","types/matrix/normalize.d.ts","types/clustering/Clustering.d.ts","types/clustering/CURE.d.ts","types/clustering/Hierarchical_Clustering.d.ts","types/clustering/KMeans.d.ts","types/clustering/KMedoids.d.ts","types/clustering/MeanShift.d.ts","types/clustering/OPTICS.d.ts","types/clustering/XMeans.d.ts","types/clustering/index.d.ts","types/datastructure/DisjointSet.d.ts","types/datastructure/Heap.d.ts","types/datastructure/index.d.ts","types/dimred/DR.d.ts","types/dimred/FASTMAP.d.ts","types/dimred/ISOMAP.d.ts","types/dimred/LDA.d.ts","types/dimred/LLE.d.ts","types/dimred/LSP.d.ts","types/dimred/LTSA.d.ts","types/dimred/MDS.d.ts","types/dimred/PCA.d.ts","types/dimred/SAMMON.d.ts","types/dimred/SMACOF.d.ts","types/dimred/SQDMDS.d.ts","types/dimred/TopoMap.d.ts","types/knn/KNN.d.ts","types/dimred/TriMap.d.ts","types/dimred/TSNE.d.ts","types/dimred/UMAP.d.ts","types/linear_algebra/inner_product.d.ts","types/linear_algebra/qr.d.ts","types/linear_algebra/qr_householder.d.ts","types/linear_algebra/simultaneous_poweriteration.d.ts","types/linear_algebra/index.d.ts","types/dimred/index.d.ts","types/knn/Annoy.d.ts","types/knn/BallTree.d.ts","types/knn/HNSW.d.ts","types/knn/KDTree.d.ts","types/knn/LSH.d.ts","types/knn/NaiveKNN.d.ts","types/knn/NNDescent.d.ts","types/knn/index.d.ts","types/numerical/kahan_sum.d.ts","types/numerical/neumair_sum.d.ts","types/optimization/powell.d.ts","types/index.d.ts"],"sourcesContent":["/**\n * Computes the Bray-Curtis distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The Bray-Curtis distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Bray%E2%80%93Curtis_dissimilarity}\n */\nexport function bray_curtis(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=bray_curtis.d.ts.map","/**\n * Computes the canberra distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The canberra distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Canberra_distance}\n */\nexport function canberra(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=canberra.d.ts.map","/**\n * Computes the chebyshev distance (L) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The chebyshev distance between `a` and `b`.\n */\nexport function chebyshev(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=chebyshev.d.ts.map","/**\n * Computes the cosine distance (not similarity) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The cosine distance between `a` and `b`.\n * @example\n * import { cosine } from \"@saehrimnir/druidjs\";\n * const a = [1, 2, 3];\n * const b = [4, 5, 6];\n * const distance = cosine(a, b); // 0.9746318461970762\n */\nexport function cosine(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=cosine.d.ts.map","/**\n * Computes the euclidean distance (`l_2`) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The euclidean distance between `a` and `b`.\n */\nexport function euclidean(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=euclidean.d.ts.map","/**\n * Computes the squared euclidean distance (l_2^2) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The squared euclidean distance between `a` and `b`.\n\n */\nexport function euclidean_squared(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=euclidean_squared.d.ts.map","/**\n * Computes the Goodman-Kruskal gamma coefficient for ordinal association.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a - First categorical/ordinal variable\n * @param {number[] | Float64Array} b - Second categorical/ordinal variable\n * @returns {number} The Goodman-Kruskal gamma coefficient between `a` and `b` (-1 to 1).\n * @see {@link https://en.wikipedia.org/wiki/Goodman_and_Kruskal%27s_gamma}\n */\nexport function goodman_kruskal(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=goodman_kruskal.d.ts.map","/**\n * Computes the hamming distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The hamming distance between `a` and `b`.\n */\nexport function hamming(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=hamming.d.ts.map","/**\n * Computes the Haversine distance between two points on a sphere of unit length 1. Multiply the result with the radius of the sphere. (For instance Earth's radius is 6371km)\n *\n * @category Metrics\n * @param {number[] | Float64Array} a - Point [lat1, lon1] in radians\n * @param {number[] | Float64Array} b - Point [lat2, lon2] in radians\n * @returns {number} The Haversine distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Haversine_formula}\n */\nexport function haversine(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=haversine.d.ts.map","/**\n * Computes the jaccard distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The jaccard distance between `a` and `b`.\n */\nexport function jaccard(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=jaccard.d.ts.map","/**\n * Computes the manhattan distance (`l_1`) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The manhattan distance between `a` and `b`.\n */\nexport function manhattan(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=manhattan.d.ts.map","/**\n * Computes the Sokal-Michener distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The Sokal-Michener distance between `a` and `b`.\n\n */\nexport function sokal_michener(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=sokal_michener.d.ts.map","/**\n * Computes the 1D Wasserstein distance (Earth Mover's Distance) between two distributions.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a - First distribution (histogram or probability mass)\n * @param {number[] | Float64Array} b - Second distribution (histogram or probability mass)\n * @returns {number} The Wasserstein/EMD distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Wasserstein_metric}\n */\nexport function wasserstein(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=wasserstein.d.ts.map","/**\n * Computes the yule distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The yule distance between `a` and `b`.\n */\nexport function yule(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=yule.d.ts.map","export { bray_curtis } from \"./bray_curtis.js\";\nexport { canberra } from \"./canberra.js\";\nexport { chebyshev } from \"./chebyshev.js\";\nexport { cosine } from \"./cosine.js\";\nexport { euclidean } from \"./euclidean.js\";\nexport { euclidean_squared } from \"./euclidean_squared.js\";\nexport { goodman_kruskal } from \"./goodman_kruskal.js\";\nexport { hamming } from \"./hamming.js\";\nexport { haversine } from \"./haversine.js\";\nexport { jaccard } from \"./jaccard.js\";\nexport { manhattan } from \"./manhattan.js\";\nexport { sokal_michener } from \"./sokal_michener.js\";\nexport { wasserstein } from \"./wasserstein.js\";\nexport { yule } from \"./yule.js\";\nexport type Metric = (a: number[] | Float64Array, b: number[] | Float64Array) => number;\n//# sourceMappingURL=index.d.ts.map","/**\n * Computes the distance matrix of datamatrix `A`.\n *\n * @category Matrix\n * @param {Matrix | Float64Array[] | number[][]} A - Matrix.\n * @param {Metric} [metric=euclidean] - The diistance metric. Default is `euclidean`\n * @returns {Matrix} The distance matrix of `A`.\n */\nexport function distance_matrix(A: Matrix | Float64Array[] | number[][], metric?: Metric): Matrix;\nimport { Matrix } from \"./index.js\";\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=distance_matrix.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/**\n * Computes the k-nearest neighbors of each row of `A`.\n *\n * @category Matrix\n * @param {Matrix} A - Either the data matrix, or a distance matrix.\n * @param {number} k - The number of neighbors to compute.\n * @param {Metric | \"precomputed\"} [metric=euclidean] Default is `euclidean`\n * @returns {{ i: number; j: number; distance: number }[][]} The kNN graph.\n */\nexport function k_nearest_neighbors(A: Matrix, k: number, metric?: Metric | \"precomputed\"): {\n i: number;\n j: number;\n distance: number;\n}[][];\nimport { Matrix } from \"../matrix/index.js\";\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=k_nearest_neighbors.d.ts.map","/**\n * Creates an Array containing `number` numbers from `start` to `end`. If `number = null`.\n *\n * @category Matrix\n * @param {number} start - Start value.\n * @param {number} end - End value.\n * @param {number} [number] - Number of number between `start` and `end`.\n * @returns {number[]} An array with `number` entries, beginning at `start` ending at `end`.\n */\nexport function linspace(start: number, end: number, number?: number): number[];\n//# sourceMappingURL=linspace.d.ts.map","/**\n * Returns maximum in Array `values`.\n *\n * @category Utils\n * @param {Iterable} values\n * @returns {number}\n */\nexport function max(values: Iterable): number;\n//# sourceMappingURL=max.d.ts.map","/**\n * Returns maximum in Array `values`.\n *\n * @category Utils\n * @param {Iterable} values\n * @returns {number}\n */\nexport function min(values: Iterable): number;\n//# sourceMappingURL=min.d.ts.map","/**\n * @category Utils\n * @class\n */\nexport class Randomizer {\n /**\n * @template T Returns samples from an input Matrix or Array.\n * @param {T[]} A - The input Matrix or Array.\n * @param {number} n - The number of samples.\n * @param {number} seed - The seed for the random number generator.\n * @returns {T[]} - A random selection form `A` of `n` samples.\n */\n static choice(A: T[], n: number, seed?: number): T[];\n /**\n * Mersenne Twister random number generator.\n *\n * @param {number} [_seed=new Date().getTime()] - The seed for the random number generator. If `_seed == null` then\n * the actual time gets used as seed. Default is `new Date().getTime()`\n * @see https://github.com/bmurray7/mersenne-twister-examples/blob/master/javascript-mersenne-twister.js\n */\n constructor(_seed?: number);\n _N: number;\n _M: number;\n _MATRIX_A: number;\n _UPPER_MASK: number;\n _LOWER_MASK: number;\n /** @type {number[]} */\n _mt: number[];\n /** @type {number} */\n _mti: number;\n /** @type {number} */\n _seed: number;\n /** @type {number} seed */\n set seed(_seed: number);\n /**\n * Returns the seed of the random number generator.\n *\n * @returns {number} - The seed.\n */\n get seed(): number;\n /**\n * Returns a float between 0 and 1.\n *\n * @returns {number} - A random number between [0, 1]\n */\n get random(): number;\n /**\n * Returns an integer between 0 and MAX_INTEGER.\n *\n * @returns {number} - A random integer.\n */\n get random_int(): number;\n gauss_random(): number;\n _val: number | null | undefined;\n /**\n * @template T Returns samples from an input Matrix or Array.\n * @param {T[]} A - The input Matrix or Array.\n * @param {number} n - The number of samples.\n * @returns {T[]} A random selection form `A` of `n` samples.\n */\n choice(A: T[], n: number): T[];\n}\n//# sourceMappingURL=randomizer.d.ts.map","/** @typedef {(i: number, j: number) => number} Accessor */\n/**\n * @class\n * @category Matrix\n */\nexport class Matrix {\n /**\n * Creates a Matrix out of `A`.\n * @param {Matrix | Float64Array[] | number[][]} A - The matrix, array, or number, which should converted to a Matrix.\n * @returns {Matrix}\n * @example\n * let A = Matrix.from([ [1, 0], [0, 1], ]); //creates a two by two identity matrix.\n */\n static from(A: Matrix | Float64Array[] | number[][]): Matrix;\n /**\n * Creates a Matrix with the diagonal being the values of `v`.\n *\n * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]]\n *\n * @param {number[] | Float64Array} v\n * @returns {Matrix}\n */\n static from_diag(v: number[] | Float64Array): Matrix;\n /**\n * Creates a Matrix with the diagonal being the values of `v`.\n *\n * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]]\n *\n * @param {number[] | Float64Array} v\n * @param {\"col\" | \"row\"} type\n * @returns {Matrix}\n */\n static from_vector(v: number[] | Float64Array, type: \"col\" | \"row\"): Matrix;\n /**\n * Solves the equation `Ax = b` using the conjugate gradient method. Returns the result `x`.\n *\n * @param {Matrix} A - Matrix\n * @param {Matrix} b - Matrix\n * @param {Randomizer | null} [randomizer]\n * @param {number} [tol=1e-3] Default is `1e-3`\n * @returns {Matrix}\n */\n static solve_CG(A: Matrix, b: Matrix, randomizer?: Randomizer | null, tol?: number): Matrix;\n /**\n * Solves the equation `Ax = b`. Returns the result `x`.\n *\n * @param {Matrix | { L: Matrix; U: Matrix }} A - Matrix or LU Decomposition\n * @param {Matrix} b - Matrix\n * @returns {Matrix}\n */\n static solve(A: Matrix | {\n L: Matrix;\n U: Matrix;\n }, b: Matrix): Matrix;\n /**\n * `LU` decomposition of the Matrix `A`. Creates two matrices, so that the dot product `LU` equals `A`.\n *\n * @param {Matrix} A\n * @returns {{ L: Matrix; U: Matrix }} The left triangle matrix `L` and the upper triangle matrix `U`.\n */\n static LU(A: Matrix): {\n L: Matrix;\n U: Matrix;\n };\n /**\n * Computes the determinante of `A`, by using the `LU` decomposition of `A`.\n *\n * @param {Matrix} A\n * @returns {number} The determinate of the Matrix `A`.\n */\n static det(A: Matrix): number;\n /**\n * Computes the `k` components of the SVD decomposition of the matrix `M`.\n *\n * @param {Matrix} M\n * @param {number} [k=2] Default is `2`\n * @returns {{ U: Float64Array[]; Sigma: Float64Array; V: Float64Array[] }}\n */\n static SVD(M: Matrix, k?: number): {\n U: Float64Array[];\n Sigma: Float64Array;\n V: Float64Array[];\n };\n /**\n * @param {unknown} A\n * @returns {A is unknown[]|number[]|Float64Array|Float32Array}\n */\n static isArray(A: unknown): A is unknown[] | number[] | Float64Array | Float32Array;\n /**\n * @param {any[]} A\n * @returns {A is number[][]|Float64Array[]}\n */\n static is2dArray(A: any[]): A is number[][] | Float64Array[];\n /**\n * Creates a new Matrix. Entries are stored in a Float64Array.\n *\n * @example let A = new Matrix(10, 10, () => Math.random()); //creates a 10 times 10 random matrix. let B = new\n * Matrix(3, 3, \"I\"); // creates a 3 times 3 identity matrix.\n *\n * @param {number} rows - The amount of rows of the matrix.\n * @param {number} cols - The amount of columns of the matrix.\n * @param {Accessor | string | number} value - Can be a function with row and col as parameters, a number, or\n * \"zeros\", \"identity\" or \"I\", or \"center\".\n *\n * - **function**: for each entry the function gets called with the parameters for the actual row and column.\n * - **string**: allowed are\n *\n * - \"zero\", creates a zero matrix.\n * - \"identity\" or \"I\", creates an identity matrix.\n * - \"center\", creates an center matrix.\n * - **number**: create a matrix filled with the given value.\n */\n constructor(rows: number, cols: number, value?: Accessor | string | number);\n /** @type {number} */ _rows: number;\n /** @type {number} */ _cols: number;\n /** @type {Float64Array} */ _data: Float64Array;\n /**\n * Returns the `row`th row from the Matrix.\n *\n * @param {number} row\n * @returns {Float64Array}\n */\n row(row: number): Float64Array;\n /**\n * Returns an generator yielding each row of the Matrix.\n *\n * @yields {Float64Array}\n */\n iterate_rows(): Generator, void, unknown>;\n /**\n * Sets the entries of `row`th row from the Matrix to the entries from `values`.\n *\n * @param {number} row\n * @param {number[]} values\n * @returns {Matrix}\n */\n set_row(row: number, values: number[]): Matrix;\n /**\n * Swaps the rows `row1` and `row2` of the Matrix.\n *\n * @param {number} row1\n * @param {number} row2\n * @returns {Matrix}\n */\n swap_rows(row1: number, row2: number): Matrix;\n /**\n * Returns the colth column from the Matrix.\n *\n * @param {number} col\n * @returns {Float64Array}\n */\n col(col: number): Float64Array;\n /**\n * Returns the `col`th entry from the `row`th row of the Matrix.\n *\n * @param {number} row\n * @param {number} col\n * @returns {number}\n */\n entry(row: number, col: number): number;\n /**\n * Sets the {@link col}th entry from the {@link row}th row of the Matrix to the given\n * {@link value}.\n *\n * @param {number} row\n * @param {number} col\n * @param {number} value\n * @returns {Matrix}\n */\n set_entry(row: number, col: number, value: number): Matrix;\n /**\n * Adds a given {@link value} to the {@link col}th entry from the {@link row}th row of the\n * Matrix.\n *\n * @param {number} row\n * @param {number} col\n * @param {number} value\n * @returns {Matrix}\n */\n add_entry(row: number, col: number, value: number): Matrix;\n /**\n * Subtracts a given {@link value} from the {@link col}th entry from the {@link row}th row of the\n * Matrix.\n *\n * @param {number} row\n * @param {number} col\n * @param {number} value\n * @returns {Matrix}\n */\n sub_entry(row: number, col: number, value: number): Matrix;\n /**\n * Returns a new transposed Matrix.\n *\n * @returns {Matrix}\n */\n transpose(): Matrix;\n /**\n * Returns a new transposed Matrix. Short-form of `transpose`.\n *\n * @returns {Matrix}\n */\n get T(): Matrix;\n /**\n * Returns the inverse of the Matrix.\n *\n * @returns {Matrix}\n */\n inverse(): Matrix;\n /**\n * Returns the dot product. If `B` is an Array or Float64Array then an Array gets returned. If `B` is a Matrix then\n * a Matrix gets returned.\n *\n * @param {Matrix | number[] | Float64Array} B The right side\n * @returns {Matrix}\n */\n dot(B: Matrix | number[] | Float64Array): Matrix;\n /**\n * Transposes the current matrix and returns the dot product with `B`. If `B` is an Array or Float64Array then an\n * Array gets returned. If `B` is a Matrix then a Matrix gets returned.\n *\n * @param {Matrix | number[] | Float64Array} B The right side\n * @returns {Matrix}\n */\n transDot(B: Matrix | number[] | Float64Array): Matrix;\n /**\n * Returns the dot product with the transposed version of `B`. If `B` is an Array or Float64Array then an Array gets\n * returned. If `B` is a Matrix then a Matrix gets returned.\n *\n * @param {Matrix | number[] | Float64Array} B The right side\n * @returns {Matrix}\n */\n dotTrans(B: Matrix | number[] | Float64Array): Matrix;\n /**\n * Computes the outer product from `this` and `B`.\n *\n * @param {Matrix} B\n * @returns {Matrix}\n */\n outer(B: Matrix): Matrix;\n /**\n * Appends matrix `B` to the matrix.\n *\n * @example let A = Matrix.from([ [1, 1], [1, 1], ]); // 2 by 2 matrix filled with ones. let B = Matrix.from([ [2,\n * 2], [2, 2], ]); // 2 by 2 matrix filled with twos.\n *\n * A.concat(B, \"horizontal\"); // 2 by 4 matrix. [[1, 1, 2, 2], [1, 1, 2, 2]]\n * A.concat(B, \"vertical\"); // 4 by 2 matrix. [[1, 1], [1, 1], [2, 2], [2, 2]]\n * A.concat(B, \"diag\"); // 4 by 4 matrix. [[1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 2, 2], [0, 0, 2, 2]]\n *\n * @param {Matrix} B - Matrix to append.\n * @param {\"horizontal\" | \"vertical\" | \"diag\"} [type=\"horizontal\"] - Type of concatenation. Default is\n * `\"horizontal\"`\n * @returns {Matrix}\n */\n concat(B: Matrix, type?: \"horizontal\" | \"vertical\" | \"diag\"): Matrix;\n /**\n * Writes the entries of B in A at an offset position given by `offset_row` and `offset_col`.\n *\n * @param {number} offset_row\n * @param {number} offset_col\n * @param {Matrix} B\n * @returns {Matrix}\n */\n set_block(offset_row: number, offset_col: number, B: Matrix): Matrix;\n /**\n * Extracts the entries from the `start_row`th row to the `end_row`th row, the\n * `start_col`th column to the `end_col`th column of the matrix. If `end_row` or `end_col` is\n * empty, the respective value is set to `this.rows` or `this.cols`.\n *\n * @example let A = Matrix.from([ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]); // a 3 by 3 matrix.\n *\n * A.get_block(1, 1); // [[5, 6], [8, 9]]\n * A.get_block(0, 0, 1, 1); // [[1]]\n * A.get_block(1, 1, 2, 2); // [[5]]\n * A.get_block(0, 0, 2, 2); // [[1, 2], [4, 5]]\n *\n * @param {number} start_row\n * @param {number} start_col\n * @param {number | null} [end_row]\n * @param {number | null} [end_col]\n * @returns {Matrix} Returns a `end_row` - `start_row` times `end_col` - `start_col` matrix, with respective entries\n * from the matrix.\n */\n get_block(start_row: number, start_col: number, end_row?: number | null, end_col?: number | null): Matrix;\n /**\n * Returns a new array gathering entries defined by the indices given by argument.\n *\n * @param {number[]} row_indices - Array consists of indices of rows for gathering entries of this matrix\n * @param {number[]} col_indices - Array consists of indices of cols for gathering entries of this matrix\n * @returns {Matrix}\n */\n gather(row_indices: number[], col_indices: number[]): Matrix;\n /**\n * Applies a function to each entry of the matrix.\n *\n * @private\n * @param {(d: number, v: number) => number} f Function takes 2 parameters, the value of the actual entry and a\n * value given by the function `v`. The result of `f` gets writen to the Matrix.\n * @param {Accessor} v Function takes 2 parameters for `row` and `col`, and returns a value witch should be applied\n * to the `col`th entry of the `row`th row of the matrix.\n * @returns {Matrix}\n */\n private _apply_array;\n /**\n * @param {number[] | Float64Array} values\n * @param {(d: number, v: number) => number} f\n * @returns {Matrix}\n */\n _apply_rowwise_array(values: number[] | Float64Array, f: (d: number, v: number) => number): Matrix;\n /**\n * @param {number[] | Float64Array} values\n * @param {(d: number, v: number) => number} f\n * @returns {Matrix}\n */\n _apply_colwise_array(values: number[] | Float64Array, f: (d: number, v: number) => number): Matrix;\n /**\n * @param {Matrix | number[] | Float64Array | number} value\n * @param {(d: number, v: number) => number} f\n * @returns {Matrix}\n */\n _apply(value: Matrix | number[] | Float64Array | number, f: (d: number, v: number) => number): Matrix;\n /**\n * Clones the Matrix.\n *\n * @returns {Matrix}\n */\n clone(): Matrix;\n /**\n * Entrywise multiplication with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.mult(2); // [[2, 4], [6, 8]];\n * A.mult(B); // [[1, 4], [9, 16]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {boolean} [options.inline=false] - If true, applies multiplication to the element, otherwise it creates\n * first a copy and applies the multiplication on the copy. Default is `false`\n * @returns {Matrix}\n */\n mult(value: Matrix | Float64Array | number[] | number, { inline }?: {\n inline?: boolean | undefined;\n }): Matrix;\n /**\n * Entrywise division with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.divide(2); // [[0.5, 1], [1.5, 2]];\n * A.divide(B); // [[1, 1], [1, 1]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {Boolean} [options.inline=false] - If true, applies division to the element, otherwise it creates first a\n * copy and applies the division on the copy. Default is `false`\n * @returns {Matrix}\n */\n divide(value: Matrix | Float64Array | number[] | number, { inline }?: {\n inline?: boolean | undefined;\n }): Matrix;\n /**\n * Entrywise addition with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.add(2); // [[3, 4], [5, 6]];\n * A.add(B); // [[2, 4], [6, 8]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {boolean} [options.inline=false] - If true, applies addition to the element, otherwise it creates first a\n * copy and applies the addition on the copy. Default is `false`\n * @returns {Matrix}\n */\n add(value: Matrix | Float64Array | number[] | number, { inline }?: {\n inline?: boolean | undefined;\n }): Matrix;\n /**\n * Entrywise subtraction with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.sub(2); // [[-1, 0], [1, 2]];\n * A.sub(B); // [[0, 0], [0, 0]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {boolean} [options.inline=false] - If true, applies subtraction to the element, otherwise it creates first\n * a copy and applies the subtraction on the copy. Default is `false`\n * @returns {Matrix}\n */\n sub(value: Matrix | Float64Array | number[] | number, { inline }?: {\n inline?: boolean | undefined;\n }): Matrix;\n /**\n * Returns the matrix in the given shape with the given function which returns values for the entries of the matrix.\n *\n * @param {[number, number, Accessor]} parameter - Takes an Array in the form [rows, cols, value], where rows and\n * cols are the number of rows and columns of the matrix, and value is a function which takes two parameters (row\n * and col) which has to return a value for the colth entry of the rowth row.\n * @returns {Matrix}\n */\n set shape([rows, cols, value]: [number, number, Accessor]);\n /**\n * Returns the number of rows and columns of the Matrix.\n *\n * @returns {number[]} An Array in the form [rows, columns].\n */\n get shape(): number[];\n /**\n * Returns the Matrix as a Array of Float64Arrays.\n *\n * @returns {Float64Array[]}\n */\n to2dArray(): Float64Array[];\n /**\n * Returns the Matrix as a Array of Arrays.\n *\n * @returns {number[][]}\n */\n asArray(): number[][];\n /**\n * Returns the diagonal of the Matrix.\n *\n * @returns {Float64Array}\n */\n diag(): Float64Array;\n /**\n * Returns the mean of all entries of the Matrix.\n *\n * @returns {number}\n */\n mean(): number;\n /**\n * Returns the sum oof all entries of the Matrix.\n *\n * @returns {number}\n */\n sum(): number;\n /**\n * Returns the entries of the Matrix.\n *\n * @returns {Float64Array}\n */\n get values(): Float64Array;\n /**\n * Returns the mean of each row of the matrix.\n *\n * @returns {Float64Array}\n */\n meanRows(): Float64Array;\n /**\n * Returns the mean of each column of the matrix.\n *\n * @returns {Float64Array}\n */\n meanCols(): Float64Array;\n /**\n * Makes a `Matrix` object an iterable object.\n *\n * @yields {Float64Array}\n */\n [Symbol.iterator](): Generator, void, unknown>;\n}\nexport type Accessor = (i: number, j: number) => number;\nimport { Randomizer } from \"../util/index.js\";\n//# sourceMappingURL=Matrix.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/**\n * Computes the norm of a vector, by computing its distance to **0**.\n *\n * @category Matrix\n * @param {Matrix | number[] | Float64Array} v - Vector.\n * @param {Metric} [metric=euclidean] - Which metric should be used to compute the norm. Default is `euclidean`\n * @returns {number} - The norm of `v`.\n */\nexport function norm(v: Matrix | number[] | Float64Array, metric?: Metric): number;\nimport { Matrix } from \"../matrix/index.js\";\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=norm.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/**\n * Normalizes Vector `v`.\n *\n * @category Matrix\n * @param {number[] | Float64Array} v - Vector\n * @param {Metric} metric\n * @returns {number[] | Float64Array} - The normalized vector with length 1.\n */\nexport function normalize(v: number[] | Float64Array, metric?: Metric): number[] | Float64Array;\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=normalize.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/**\n * Base class for all clustering algorithms.\n * @template Para\n */\nexport class Clustering {\n /**\n * Compute the respective Clustering with given parameters\n * @param {InputType} points\n * @param {Para} parameters\n */\n constructor(points: InputType, parameters: Para);\n /** @type {InputType} */\n _points: InputType;\n /** @type {Para} */\n _parameters: Para;\n /** @type {Matrix} */\n _matrix: Matrix;\n /** @type {number} */\n _N: number;\n /** @type {number} */\n _D: number;\n /**\n * @abstract\n * @param {...unknown} args\n * @returns {number[][]} An array with the indices of the clusters.\n */\n get_clusters(...args: unknown[]): number[][];\n /**\n * @abstract\n * @param {...unknown} args\n * @returns {number[]} An array with the clusters id's for each point.\n */\n get_cluster_list(...args: unknown[]): number[];\n}\nimport type { InputType } from \"../index.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=Clustering.d.ts.map","/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersCURE } from \"./index.js\" */\n/**\n * CURE (Clustering Using REpresentatives)\n *\n * An efficient clustering algorithm for large databases that is robust to outliers\n * and identifies clusters with non-spherical shapes and wide variances in size.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class CURE extends Clustering {\n /**\n * @param {InputType} points\n * @param {Partial} parameters\n */\n constructor(points: InputType, parameters?: Partial);\n /** @type {number} */\n _K: number;\n /** @type {number} */\n _num_representatives: number;\n /** @type {number} */\n _shrink_factor: number;\n /**\n * @private\n * @type {CURECluster[]}\n */\n private _clusters;\n /** @type {number[]} */\n _cluster_ids: number[];\n /**\n * Initialize each point as its own cluster\n * @private\n */\n private _initialize_clusters;\n /**\n * Compute distance between two clusters using representative points\n * @private\n * @param {CURECluster} cluster1\n * @param {CURECluster} cluster2\n * @returns {number}\n */\n private _cluster_distance;\n /**\n * Find the closest pair of clusters\n * @private\n * @returns {[number, number, number]} [index1, index2, distance]\n */\n private _find_closest_clusters;\n /**\n * Merge two clusters\n * @private\n * @param {CURECluster} cluster1\n * @param {CURECluster} cluster2\n * @returns {CURECluster}\n */\n private _merge_clusters;\n /**\n * Run CURE clustering algorithm\n * @private\n */\n private _cure;\n /**\n * Build the cluster list (point -> cluster assignment)\n * @private\n */\n private _build_cluster_ids;\n /**\n * @returns {number[][]}\n */\n get_clusters(): number[][];\n /**\n * @returns {number[]}\n */\n get_cluster_list(): number[];\n}\nimport type { ParametersCURE } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport type { InputType } from \"../index.js\";\n//# sourceMappingURL=CURE.d.ts.map","/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersHierarchicalClustering } from \"./index.js\" */\n/**\n * Hierarchical Clustering\n *\n * A bottom-up approach (agglomerative) to clustering that builds a tree of clusters (dendrogram).\n * Supports different linkage criteria: single, complete, and average.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class HierarchicalClustering extends Clustering {\n /**\n * @param {InputType} points - Data or distance matrix if metric is 'precomputed'\n * @param {Partial} parameters\n */\n constructor(points: InputType, parameters?: Partial);\n /** @type {Cluster | null} */\n root: Cluster | null;\n _id: number;\n _d_min: Float64Array;\n _distance_matrix: Matrix;\n _clusters: any[];\n _c_size: Uint16Array;\n /**\n * @param {number} value - Value where to cut the tree.\n * @param {\"distance\" | \"depth\"} [type=\"distance\"] - Type of value. Default is `\"distance\"`\n * @returns {Cluster[][]} - Array of clusters with the indices of the rows in given points.\n */\n get_clusters_raw(value: number, type?: \"distance\" | \"depth\"): Cluster[][];\n /**\n * @param {number} value - Value where to cut the tree.\n * @param {\"distance\" | \"depth\"} [type=\"distance\"] - Type of value. Default is `\"distance\"`\n * @returns {number[][]} - Array of clusters with the indices of the rows in given points.\n */\n get_clusters(value: number, type?: \"distance\" | \"depth\"): number[][];\n /**\n * @param {number} value - Value where to cut the tree.\n * @param {\"distance\" | \"depth\"} [type=\"distance\"] - Type of value. Default is `\"distance\"`\n * @returns {number[]} - Array of clusters with the indices of the rows in given points.\n */\n get_cluster_list(value: number, type?: \"distance\" | \"depth\"): number[];\n /**\n * @private\n * @param {Cluster} node\n * @param {(d: {dist: number, depth: number}) => number} f\n * @param {number} value\n * @param {Cluster[][]} result\n */\n private _traverse;\n}\nimport type { ParametersHierarchicalClustering } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\n/** @private */\ndeclare class Cluster {\n /**\n *\n * @param {number} id\n * @param {Cluster?} left\n * @param {Cluster?} right\n * @param {number} dist\n * @param {Float64Array?} centroid\n * @param {number} index\n * @param {number} [size]\n * @param {number} [depth]\n */\n constructor(id: number, left: Cluster | null, right: Cluster | null, dist: number, centroid: Float64Array | null, index: number, size?: number, depth?: number);\n /**@type {number} */\n size: number;\n /**@type {number} */\n depth: number;\n /**@type {Cluster | null} */\n parent: Cluster | null;\n id: number;\n left: Cluster | null;\n right: Cluster | null;\n dist: number;\n index: number;\n centroid: Float64Array;\n /**\n *\n * @param {Cluster} left\n * @param {Cluster} right\n * @returns {Float64Array}\n */\n _calculate_centroid(left: Cluster, right: Cluster): Float64Array;\n get isLeaf(): boolean;\n /**\n *\n * @returns {Cluster[]}\n */\n leaves(): Cluster[];\n /**\n *\n * @returns {Cluster[]}\n */\n descendants(): Cluster[];\n}\nimport { Matrix } from \"../matrix/index.js\";\nimport type { InputType } from \"../index.js\";\nexport {};\n//# sourceMappingURL=Hierarchical_Clustering.d.ts.map","/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersKMeans } from \"./index.js\" */\n/**\n * K-Means Clustering\n *\n * A popular clustering algorithm that partitions data into K clusters where each point\n * belongs to the cluster with the nearest mean (centroid).\n *\n * @class\n * @extends Clustering\n * @category Clustering\n * @see {@link KMedoids} for a more robust alternative\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const points = [[1, 1], [1.5, 1.5], [5, 5], [5.5, 5.5]];\n * const kmeans = new druid.KMeans(points, { K: 2 });\n *\n * const clusters = kmeans.get_cluster_list(); // [0, 0, 1, 1]\n * const centroids = kmeans.centroids; // center points\n */\nexport class KMeans extends Clustering {\n /**\n * @param {InputType} points\n * @param {Partial} parameters\n */\n constructor(points: InputType, parameters?: Partial);\n _K: number;\n _randomizer: Randomizer;\n /** @type {number[]} */\n _clusters: number[];\n _cluster_centroids: Float64Array[];\n /** @returns {number} The number of clusters */\n get k(): number;\n /** @returns {Float64Array[]} The cluster centroids */\n get centroids(): Float64Array[];\n /** @returns {number[]} The cluster list */\n get_cluster_list(): number[];\n /** @returns {number[][]} An Array of clusters with the indices of the points. */\n get_clusters(): number[][];\n /**\n * @private\n * @param {number[]} point_indices\n * @param {number[]} candidates\n * @returns {number}\n */\n private _furthest_point;\n /**\n * @private\n * @param {number} K\n * @returns {Float64Array[]}\n */\n private _get_random_centroids;\n /**\n * @private\n * @param {Float64Array[]} cluster_centroids\n * @returns {{ clusters_changed: boolean; cluster_centroids: Float64Array[] }}\n */\n private _iteration;\n /**\n * @private\n * @param {number} K\n * @returns {Float64Array[]}\n */\n private _compute_centroid;\n}\nimport type { ParametersKMeans } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport type { InputType } from \"../index.js\";\n//# sourceMappingURL=KMeans.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import { ParametersKMedoids } from \"./index.js\" */\n/**\n * K-Medoids (PAM - Partitioning Around Medoids)\n *\n * A robust clustering algorithm similar to K-Means, but uses actual data points (medoids)\n * as cluster centers and can work with any distance metric.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n * @see {@link KMeans} for a faster but less robust alternative\n */\nexport class KMedoids extends Clustering {\n /**\n * @param {InputType} points - Data matrix\n * @param {Partial} parameters\n * @see {@link https://link.springer.com/chapter/10.1007/978-3-030-32047-8_16} Faster k-Medoids Clustering: Improving the PAM, CLARA, and CLARANS Algorithms\n */\n constructor(points: InputType, parameters?: Partial);\n _A: Float64Array[];\n _max_iter: number;\n _distance_matrix: Matrix;\n _randomizer: Randomizer;\n _clusters: any[];\n _cluster_medoids: number[];\n _is_initialized: boolean;\n /** @returns {number[]} The cluster list */\n get_cluster_list(): number[];\n /** @returns {number[][]} - Array of clusters with the indices of the rows in given points. */\n get_clusters(): number[][];\n /** @returns {number} */\n get k(): number;\n /** @returns {number[]} */\n get medoids(): number[];\n /** @returns {number[]} */\n get_medoids(): number[];\n generator(): AsyncGenerator;\n /** Algorithm 1. FastPAM1: Improved SWAP algorithm */\n /** FastPAM1: One best swap per iteration */\n _iteration(): boolean;\n /**\n *\n * @param {number} i\n * @param {number} j\n * @param {Float64Array?} x_i\n * @param {Float64Array?} x_j\n * @returns\n */\n _get_distance(i: number, j: number, x_i?: Float64Array | null, x_j?: Float64Array | null): number;\n /**\n *\n * @param {Float64Array} x_j\n * @param {number} j\n * @returns\n */\n _nearest_medoid(x_j: Float64Array, j: number): {\n distance_nearest: number;\n index_nearest: number;\n distance_second: number;\n index_second: number;\n };\n _update_clusters(): void;\n /**\n * Computes `K` clusters out of the `matrix`.\n * @param {number} K - Number of clusters.\n * @param {number[]} cluster_medoids\n */\n init(K: number, cluster_medoids: number[]): this;\n /**\n * Algorithm 3. FastPAM LAB: Linear Approximate BUILD initialization.\n *\n * @param {number} K - Number of clusters\n * @returns {number[]}\n */\n _get_random_medoids(K: number): number[];\n}\nimport type { ParametersKMedoids } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport type { InputType } from \"../index.js\";\n//# sourceMappingURL=KMedoids.d.ts.map","/** @import { ParametersMeanShift } from \"./index.js\" */\n/** @import { InputType } from \"../index.js\" */\n/**\n * Mean Shift Clustering\n *\n * A non-parametric clustering technique that does not require prior knowledge of the\n * number of clusters. It identifies centers of density in the data.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class MeanShift extends Clustering {\n /**\n *\n * @param {InputType} points\n * @param {Partial} parameters\n */\n constructor(points: InputType, parameters?: Partial);\n /** @type {number} */\n _bandwidth: number;\n /** @type {number} */\n _max_iter: number;\n /** @type {number} */\n _tolerance: number;\n /** @type {(dist: number) => number} */\n _kernel: (dist: number) => number;\n /** @type {Matrix} */\n _points: Matrix;\n /** @type {number[] | undefined} */\n _clusters: number[] | undefined;\n /** @type {number[][] | undefined} */\n _cluster_list: number[][] | undefined;\n /**\n * @param {Matrix} matrix\n * @returns {number}\n */\n _compute_bandwidth(matrix: Matrix): number;\n /**\n * @param {number} dist\n * @returns {number}\n */\n _kernel_weight(dist: number): number;\n _mean_shift(): void;\n _assign_clusters(): void;\n /**\n * @returns {number[][]}\n */\n get_clusters(): number[][];\n /**\n *\n * @returns {number[]}\n */\n get_cluster_list(): number[];\n}\nimport type { ParametersMeanShift } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport type { InputType } from \"../index.js\";\n//# sourceMappingURL=MeanShift.d.ts.map","/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersOptics } from \"./index.js\" */\n/** @typedef {Object} DBEntry\n * @property {Float64Array} element\n * @property {number} index\n * @property {number} [reachability_distance]\n * @property {boolean} processed\n * @property {DBEntry[]} [neighbors]\n */\n/**\n * OPTICS (Ordering Points To Identify the Clustering Structure)\n *\n * A density-based clustering algorithm that extends DBSCAN. It handles clusters of varying\n * densities and produces a reachability plot that can be used to extract clusters.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class OPTICS extends Clustering {\n /**\n * **O**rdering **P**oints **T**o **I**dentify the **C**lustering **S**tructure.\n *\n * @param {InputType} points - The data.\n * @param {Partial} [parameters={}]\n * @see {@link https://www.dbs.ifi.lmu.de/Publikationen/Papers/OPTICS.pdf}\n * @see {@link https://en.wikipedia.org/wiki/OPTICS_algorithm}\n */\n constructor(points: InputType, parameters?: Partial);\n /**\n * @private\n * @type {DBEntry[]}\n */\n private _ordered_list;\n /** @type {number[][]} */\n _clusters: number[][];\n /**\n * @private\n * @type {DBEntry[]}\n */\n private _DB;\n _cluster_index: number;\n /**\n * @private\n * @param {DBEntry} p - A point of the data.\n * @returns {DBEntry[]} An array consisting of the `epsilon`-neighborhood of `p`.\n */\n private _get_neighbors;\n /**\n * @private\n * @param {DBEntry} p - A point of `matrix`.\n * @returns {number|undefined} The distance to the `min_points`-th nearest point of `p`, or undefined if the\n * `epsilon`-neighborhood has fewer elements than `min_points`.\n */\n private _core_distance;\n /**\n * Updates the reachability distance of the points.\n *\n * @private\n * @param {DBEntry} p\n * @param {Heap} seeds\n */\n private _update;\n /**\n * Expands the `cluster` with points in `seeds`.\n *\n * @private\n * @param {Heap} seeds\n * @param {number[]} cluster\n */\n private _expand_cluster;\n /**\n * Returns an array of clusters.\n *\n * @returns {number[][]} Array of clusters with the indices of the rows in given `matrix`.\n */\n get_clusters(): number[][];\n /**\n * @returns {number[]} Returns an array, where the ith entry defines the cluster affirmation of the ith point of\n * given data. (-1 stands for outlier)\n */\n get_cluster_list(): number[];\n}\nexport type DBEntry = {\n element: Float64Array;\n index: number;\n reachability_distance?: number | undefined;\n processed: boolean;\n neighbors?: DBEntry[] | undefined;\n};\nimport type { ParametersOptics } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport type { InputType } from \"../index.js\";\n//# sourceMappingURL=OPTICS.d.ts.map","/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersXMeans } from \"./index.js\" */\n/**\n * @typedef SplitResult\n * @property {number} index - Index of the cluster being split\n * @property {number} bic_parent - BIC score of the parent cluster\n * @property {number} bic_children - BIC score of the split children\n * @property {number[][]} child_clusters - Clusters after splitting\n * @property {Float64Array[]} child_centroids - Centroids of child clusters\n */\n/**\n * @typedef CandidateResult\n * @property {KMeans} kmeans - The KMeans instance for this K\n * @property {number} score - BIC score\n */\n/**\n * X-Means Clustering\n *\n * An extension of K-Means that automatically determines the number of clusters (K)\n * using the Bayesian Information Criterion (BIC).\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class XMeans extends Clustering {\n /**\n * XMeans clustering algorithm that automatically determines the optimal number of clusters.\n *\n * X-Means extends K-Means by starting with a minimum number of clusters and iteratively\n * splitting clusters to improve the Bayesian Information Criterion (BIC).\n *\n * Algorithm:\n * 1. Start with K_min clusters using KMeans\n * 2. For each cluster, try splitting it into 2 sub-clusters\n * 3. If BIC improves after splitting, keep the split\n * 4. Run KMeans again with all (old + new) centroids\n * 5. Repeat until K_max is reached or no more improvements\n *\n * @param {InputType} points - The data points to cluster\n * @param {Partial} [parameters={}] - Configuration parameters\n * @see {@link https://www.cs.cmu.edu/~dpelleg/download/xmeans.pdf}\n * @see {@link https://github.com/annoviko/pyclustering/blob/master/pyclustering/cluster/xmeans.py}\n * @see {@link https://github.com/haifengl/smile/blob/master/core/src/main/java/smile/clustering/XMeans.java}\n */\n constructor(points: InputType, parameters?: Partial);\n _randomizer: Randomizer;\n /** @type {KMeans | null} */\n _best_kmeans: KMeans | null;\n /**\n * Run the XMeans algorithm\n *\n * @private\n */\n private _run;\n /**\n * Select the best candidate based on BIC score\n *\n * @private\n * @param {Map} candidates\n * @returns {KMeans}\n */\n private _select_best_candidate;\n /**\n * Calculate Bayesian Information Criterion for a set of clusters.\n *\n * Uses Kass's formula for BIC calculation:\n * BIC(θ) = L(D) - 0.5 * p * ln(N)\n *\n * Where:\n * - L(D) is the log-likelihood of the data\n * - p is the number of free parameters: (K-1) + D*K + 1\n * - N is the total number of points\n *\n * @private\n * @param {number[][]} clusters - Array of clusters with point indices\n * @param {Float64Array[]} centroids - Array of centroids\n * @returns {number} BIC score (higher is better)\n */\n private _bic;\n /**\n * Get the computed clusters\n *\n * @returns {number[][]} Array of clusters, each containing indices of points\n */\n get_clusters(): number[][];\n /** @returns {number[]} The cluster list */\n get_cluster_list(): number[];\n /**\n * Get the final centroids\n *\n * @returns {Float64Array[]} Array of centroids\n */\n get centroids(): Float64Array[];\n /**\n * Get the optimal number of clusters found\n *\n * @returns {number} The number of clusters\n */\n get k(): number;\n}\nexport type SplitResult = {\n /**\n * - Index of the cluster being split\n */\n index: number;\n /**\n * - BIC score of the parent cluster\n */\n bic_parent: number;\n /**\n * - BIC score of the split children\n */\n bic_children: number;\n /**\n * - Clusters after splitting\n */\n child_clusters: number[][];\n /**\n * - Centroids of child clusters\n */\n child_centroids: Float64Array[];\n};\nexport type CandidateResult = {\n /**\n * - The KMeans instance for this K\n */\n kmeans: KMeans;\n /**\n * - BIC score\n */\n score: number;\n};\nimport type { ParametersXMeans } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { KMeans } from \"./KMeans.js\";\nimport type { InputType } from \"../index.js\";\n//# sourceMappingURL=XMeans.d.ts.map","export { CURE } from \"./CURE.js\";\nexport { HierarchicalClustering } from \"./Hierarchical_Clustering.js\";\nexport { KMeans } from \"./KMeans.js\";\nexport { KMedoids } from \"./KMedoids.js\";\nexport { MeanShift } from \"./MeanShift.js\";\nexport { OPTICS } from \"./OPTICS.js\";\nexport { XMeans } from \"./XMeans.js\";\nexport type ParametersHierarchicalClustering = {\n linkage: \"single\" | \"complete\" | \"average\";\n metric: Metric | \"precomputed\";\n};\nexport type ParametersKMeans = {\n K: number;\n /**\n * Default is `euclidean`\n */\n metric: Metric;\n /**\n * Default is `1212`\n */\n seed: number;\n /**\n * - Initial centroids. Default is `null`\n */\n initial_centroids?: Float64Array[] | number[][] | undefined;\n};\nexport type ParametersKMedoids = {\n /**\n * - Number of clusters\n */\n K: number;\n /**\n * - Maximum number of iterations. Default is 10 * Math.log10(N). Default is `null`\n */\n max_iter: number | null;\n /**\n * - Metric defining the dissimilarity. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Seed value for random number generator. Default is `1212`\n */\n seed: number;\n};\nexport type ParametersOptics = {\n /**\n * - The minimum distance which defines whether a point is a neighbor or not.\n */\n epsilon: number;\n /**\n * - The minimum number of points which a point needs to create a cluster. (Should be higher than 1, else each point creates a cluster.)\n */\n min_points: number;\n /**\n * - The distance metric which defines the distance between two points of the points. Default is `euclidean`\n */\n metric: Metric;\n};\nexport type ParametersXMeans = {\n /**\n * - Minimum number of clusters. Default is `2`\n */\n K_min: number;\n /**\n * - Maximum number of clusters. Default is `10`\n */\n K_max: number;\n /**\n * - Distance metric function. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Random seed. Default is `1212`\n */\n seed: number;\n /**\n * - Minimum points required to consider splitting a cluster. Default is `25`\n */\n min_cluster_size: number;\n /**\n * - Convergence tolerance for KMeans. Default is `0.001`\n */\n tolerance: number;\n};\nexport type ParametersMeanShift = {\n /**\n * - bandwidth\n */\n bandwidth: number;\n /**\n * - Metric defining the dissimilarity. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Seed value for random number generator. Default is `1212`\n */\n seed: number;\n /**\n * - Kernel function. Default is `gaussian`\n */\n kernel: \"flat\" | \"gaussian\" | ((dist: number) => number);\n /**\n * - Maximum number of iterations. Default is `Math.max(10, Math.floor(10 * Math.log10(N)))`\n */\n max_iter?: number | undefined;\n /**\n * - Convergence tolerance. Default is `1e-3`\n */\n tolerance?: number | undefined;\n};\nexport type ParametersCURE = {\n /**\n * - Target number of clusters. Default is `2`\n */\n K: number;\n /**\n * - Number of representative points per cluster. Default is `5`\n */\n num_representatives: number;\n /**\n * - Factor to shrink representatives toward centroid (0-1). Default is `0.5`\n */\n shrink_factor: number;\n /**\n * - Distance metric function. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Random seed. Default is `1212`\n */\n seed: number;\n};\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=index.d.ts.map","/**\n * @template T\n * @typedef {Object} DisjointSetPayload\n * @property {T} parent\n * @property {Set} children\n * @property {number} size\n */\n/**\n * @template T\n * @class\n * @category Data Structures\n * @see {@link https://en.wikipedia.org/wiki/Disjoint-set_data_structure}\n */\nexport class DisjointSet {\n /**\n * @param {T[]?} elements\n */\n constructor(elements?: T[] | null);\n /**\n * @private\n * @type {Map>}\n */\n private _list;\n /**\n * @private\n * @param {T} x\n * @returns {DisjointSet}\n */\n private make_set;\n /**\n * @param {T} x\n * @returns\n */\n find(x: T): T | null;\n /**\n * @param {T} x\n * @param {T} y\n * @returns\n */\n union(x: T, y: T): this;\n /** @param {T} x */\n get_children(x: T): Set | null;\n}\nexport type DisjointSetPayload = {\n parent: T;\n children: Set;\n size: number;\n};\n//# sourceMappingURL=DisjointSet.d.ts.map","/** @import { Comparator } from \"./index.js\" */\n/**\n * @template T\n * @class\n * @category Data Structures\n */\nexport class Heap {\n /**\n * Creates a Heap from an Array\n *\n * @template T\n * @param {T[]} elements - Contains the elements for the Heap.\n * @param {(d: T) => number} accessor - Function returns the value of the element.\n * @param {\"min\" | \"max\" | Comparator} [comparator=\"min\"] - Function returning true or false\n * defining the wished order of the Heap, or String for predefined function. (\"min\" for a Min-Heap, \"max\" for a\n * Max_heap). Default is `\"min\"`\n * @returns {Heap}\n */\n static heapify(elements: T_1[], accessor: (d: T_1) => number, comparator?: \"min\" | \"max\" | Comparator): Heap;\n /**\n * A heap is a datastructure holding its elements in a specific way, so that the top element would be the first\n * entry of an ordered list.\n *\n * @param {T[]?} elements - Contains the elements for the Heap. `elements` can be null.\n * @param {(d: T) => number} accessor - Function returns the value of the element.\n * @param {\"min\" | \"max\" | Comparator} [comparator=\"min\"] - Function returning true or false\n * defining the wished order of the Heap, or String for predefined function. (\"min\" for a Min-Heap, \"max\" for a\n * Max_heap). Default is `\"min\"`\n * @see {@link https://en.wikipedia.org/wiki/Binary_heap}\n */\n constructor(elements: (T[] | null) | undefined, accessor: (d: T) => number, comparator?: \"min\" | \"max\" | Comparator);\n /** @type {{ element: T; value: number }[]} */\n _container: {\n element: T;\n value: number;\n }[];\n /** @type {Comparator} */\n _comparator: Comparator;\n /** @type {(d: T) => number} */\n _accessor: (d: T) => number;\n /**\n * Swaps elements of container array.\n *\n * @private\n * @param {number} index_a\n * @param {number} index_b\n */\n private _swap;\n /** @private */\n private _heapify_up;\n /**\n * Pushes the element to the heap.\n *\n * @param {T} element\n * @returns {Heap}\n */\n push(element: T): Heap;\n /**\n * @private\n * @param {Number} [start_index=0] Default is `0`\n */\n private _heapify_down;\n /**\n * Removes and returns the top entry of the heap.\n *\n * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by\n * `accessor`}).\n */\n pop(): {\n element: T;\n value: number;\n } | null;\n /**\n * Returns the top entry of the heap without removing it.\n *\n * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by\n * `accessor`).\n */\n get first(): {\n element: T;\n value: number;\n } | null;\n /**\n * Yields the raw data\n *\n * @yields {T} Object consists of the element and its value (computed by `accessor`}).\n */\n iterate(): Generator;\n /**\n * Returns the heap as ordered array.\n *\n * @returns {T[]} Array consisting the elements ordered by `comparator`.\n */\n toArray(): T[];\n /**\n * Returns elements of container array.\n *\n * @returns {T[]} Array consisting the elements.\n */\n data(): T[];\n /**\n * Returns the container array.\n *\n * @returns {{ element: T; value: number }[]} The container array.\n */\n raw_data(): {\n element: T;\n value: number;\n }[];\n /**\n * The size of the heap.\n *\n * @returns {number}\n */\n get length(): number;\n /**\n * Returns false if the the heap has entries, true if the heap has no entries.\n *\n * @returns {boolean}\n */\n get empty(): boolean;\n}\nimport type { Comparator } from \"./index.js\";\n//# sourceMappingURL=Heap.d.ts.map","export { DisjointSet } from \"./DisjointSet.js\";\nexport { Heap } from \"./Heap.js\";\nexport type Comparator = (a: number, b: number) => boolean;\n//# sourceMappingURL=index.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/**\n * @abstract\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n *\n * Base class for all Dimensionality Reduction (DR) algorithms.\n *\n * Provides a common interface for parameters management, data initialization,\n * and transformation (both synchronous and asynchronous).\n *\n * @class\n */\nexport class DR {\n /**\n * Computes the projection.\n *\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.\n * @returns {T} The dimensionality reduced dataset.\n */\n static transform(X: T_1, parameters: Para_1, ...args: unknown[]): T_1;\n /**\n * Computes the projection.\n *\n * @template {{ seed?: number }} Para\n * @param {InputType} X\n * @param {Para} parameters\n * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.\n * @returns {Generator} A generator yielding the intermediate steps of the dimensionality\n * reduction method.\n */\n static generator(X: InputType, parameters: Para_1, ...args: unknown[]): Generator;\n /**\n * Computes the projection.\n *\n * @template {{ seed?: number }} Para\n * @param {InputType} X\n * @param {Para} parameters\n * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.\n * @returns {Promise} A promise yielding the dimensionality reduced dataset.\n */\n static transform_async(X: InputType, parameters: Para_1, ...args: unknown[]): Promise;\n /**\n * Takes the default parameters and seals them, remembers the type of input `X`, and initializes the random number\n * generator.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Para} default_parameters - Object containing default parameterization of the DR method.\n * @param {Partial} parameters - Object containing parameterization of the DR method to override defaults.\n */\n constructor(X: T, default_parameters: Para, parameters?: Partial);\n /** @type {number} */\n _D: number;\n /** @type {number} */\n _N: number;\n /** @type {Randomizer} */\n _randomizer: Randomizer;\n /** @type {boolean} */\n _is_initialized: boolean;\n /** @type {T} */\n __input: T;\n /** @type {Para} */\n _parameters: Para;\n /** @type {\"array\" | \"matrix\" | \"typed\"} */\n _type: \"array\" | \"matrix\" | \"typed\";\n /** @type {Matrix} */\n X: Matrix;\n /** @type {Matrix} */\n Y: Matrix;\n /**\n * Get all Parameters.\n * @overload\n * @returns {Para}\n */\n parameter(): Para;\n /**\n * Get value of given parameter.\n * @template {keyof Para} K\n * @overload\n * @param {K} name - Name of the parameter.\n * @returns {Para[K]}\n */\n parameter(name: K): Para[K];\n /**\n * Set value of given parameter.\n * @template {keyof Para} K\n * @overload\n * @param {K} name - Name of the parameter.\n * @param {Para[K]} value - Value of the parameter to set.\n * @returns {this}\n */\n parameter(name: K, value: Para[K]): this;\n /**\n * Computes the projection.\n *\n * @abstract\n * @param {...unknown} args\n * @returns {T} The projection.\n */\n transform(...args: unknown[]): T;\n /**\n * Computes the projection.\n *\n * @abstract\n * @param {...unknown} args\n * @returns {Generator} The intermediate steps of the projection.\n */\n generator(...args: unknown[]): Generator;\n /**\n * @abstract\n * @param {...unknown} args\n */\n init(...args: unknown[]): void;\n /**\n * If the respective DR method has an `init` function, call it before `transform`.\n *\n * @returns {DR}\n */\n check_init(): DR;\n /** @returns {T} The projection in the type of input `X`. */\n get projection(): T;\n /**\n * Computes the projection.\n *\n * @param {...unknown} args - Arguments the transform method of the respective DR method takes.\n * @returns {Promise} The dimensionality reduced dataset.\n */\n transform_async(...args: unknown[]): Promise;\n}\nimport type { InputType } from \"../index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=DR.d.ts.map","/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersFASTMAP } from \"./index.js\"; */\n/**\n * FastMap algorithm for dimensionality reduction.\n *\n * A very fast algorithm for projecting high-dimensional data into a lower-dimensional\n * space while preserving pairwise distances. It works similarly to PCA but uses\n * only a subset of the data to find projection axes.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class FASTMAP extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X: T_1, parameters: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static generator(X: T_1, parameters: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters: Partial): Promise;\n /**\n * FastMap: a fast algorithm for indexing, data-mining and visualization of traditional and multimedia datasets.\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://doi.org/10.1145/223784.223812}\n */\n constructor(X: T, parameters: Partial);\n /**\n * Chooses two points which are the most distant in the actual projection.\n *\n * @private\n * @param {(a: number, b: number) => number} dist\n * @returns {[number, number, number]} An array consisting of first index, second index, and distance between the\n * two points.\n */\n private _choose_distant_objects;\n /**\n * Computes the projection.\n *\n * @returns {T} The `d`-dimensional projection of the data matrix `X`.\n */\n transform(): T;\n generator(): Generator;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersFASTMAP } from \"./index.js\";\nimport { DR } from \"./DR.js\";\n//# sourceMappingURL=FASTMAP.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersISOMAP} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n/**\n * Isomap (Isometric Mapping)\n *\n * A nonlinear dimensionality reduction algorithm that uses geodesic distances\n * between points on a manifold to perform embedding. It builds a neighborhood\n * graph and uses MDS on the shortest-path distances.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link LLE} for another nonlinear alternative\n */\nexport class ISOMAP extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * Isometric feature mapping (ISOMAP).\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n * @see {@link https://doi.org/10.1126/science.290.5500.2319}\n */\n constructor(X: T, parameters?: Partial);\n defaults: ParametersISOMAP;\n /**\n * Computes the projection.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * @returns {T}\n */\n transform(): T;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersISOMAP } from \"./index.js\";\nimport { DR } from \"./DR.js\";\n//# sourceMappingURL=ISOMAP.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLDA} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n/**\n * Linear Discriminant Analysis (LDA)\n *\n * A supervised dimensionality reduction technique that finds the axes that\n * maximize the separation between multiple classes.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class LDA extends DR {\n /**\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @returns {T}\n */\n static transform(X: T_1, parameters: Para): T_1;\n /**\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @returns {Generator}\n */\n static generator(X: T_1, parameters: Para): Generator;\n /**\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters: Para): Promise;\n /**\n * Linear Discriminant Analysis.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial & { labels: any[] | Float64Array }} parameters - Object containing parameterization of the DR method.\n * @see {@link https://onlinelibrary.wiley.com/doi/10.1111/j.1469-1809.1936.tb02137.x}\n */\n constructor(X: T, parameters: Partial & {\n labels: any[] | Float64Array;\n });\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T} - The projected data.\n */\n transform(): T;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersLDA } from \"./index.js\";\nimport { DR } from \"./DR.js\";\n//# sourceMappingURL=LDA.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLLE} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n/**\n * Locally Linear Embedding (LLE)\n *\n * A nonlinear dimensionality reduction technique that preserves local\n * linear relationships between points. It represents each point as a linear\n * combination of its neighbors.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link ISOMAP} for another nonlinear alternative\n */\nexport class LLE extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X: T_1, parameters: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static generator(X: T_1, parameters: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters: Partial): Promise;\n /**\n * Locally Linear Embedding.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://doi.org/10.1126/science.290.5500.2323}\n */\n constructor(X: T, parameters: Partial);\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T}\n */\n transform(): T;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersLLE } from \"./index.js\";\nimport { DR } from \"./DR.js\";\n//# sourceMappingURL=LLE.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLSP} from \"./index.js\" */\n/**\n * Least Square Projection (LSP)\n *\n * A dimensionality reduction technique that uses a small set of control points\n * (projected with MDS) to define the projection for the rest of the data\n * using a Laplacian-based optimization.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class LSP extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * Least Squares Projection.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n * @see {@link https://ieeexplore.ieee.org/document/4378370}\n */\n constructor(X: T, parameters?: Partial);\n /**\n * @returns {LSP}\n */\n init(): LSP;\n _A: Matrix | undefined;\n _b: Matrix | undefined;\n /**\n * Computes the projection.\n *\n * @returns {T} Returns the projection.\n */\n transform(): T;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersLSP } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=LSP.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLTSA} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n/**\n * Local Tangent Space Alignment (LTSA)\n *\n * A nonlinear dimensionality reduction algorithm that represents the local\n * geometry of the manifold by tangent spaces and then aligns them to reveal\n * the global structure.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class LTSA extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X: T_1, parameters: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static generator(X: T_1, parameters: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters: Partial): Promise;\n /**\n * Local Tangent Space Alignment\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://epubs.siam.org/doi/abs/10.1137/S1064827502419154}\n */\n constructor(X: T, parameters: Partial);\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * Transforms the inputdata `X` to dimenionality `d`.\n *\n * @returns {T}\n */\n transform(): T;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersLTSA } from \"./index.js\";\nimport { DR } from \"./DR.js\";\n//# sourceMappingURL=LTSA.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersMDS} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n/**\n * Classical Multidimensional Scaling (MDS)\n *\n * A linear dimensionality reduction technique that seeks to preserve the\n * pairwise distances between points as much as possible in the lower-dimensional\n * space.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link PCA} for another linear alternative\n */\nexport class MDS extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * Classical MDS.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X: T, parameters?: Partial);\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T}\n */\n transform(): T;\n _d_X: Matrix | undefined;\n /** @returns {number} - The stress of the projection. */\n stress(): number;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersMDS } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=MDS.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersPCA} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n/**\n * Principal Component Analysis (PCA)\n *\n * A linear dimensionality reduction technique that identifies the axes (principal components)\n * along which the variance of the data is maximized.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link MDS} for another linear alternative\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2], [3, 4], [5, 6]];\n * const pca = new druid.PCA(X, { d: 2 });\n * const Y = pca.transform();\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class PCA extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X: T_1, parameters: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Matrix}\n */\n static principal_components(X: T_1, parameters: Partial): Matrix;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X: T, parameters?: Partial);\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T} - The projected data.\n */\n transform(): T;\n /**\n * Computes the `d` principal components of Matrix `X`.\n *\n * @returns {Matrix}\n */\n principal_components(): Matrix;\n V: Matrix | undefined;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersPCA } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=PCA.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersPCA, ParametersMDS, ParametersSAMMON} from \"./index.js\" */\n/** @typedef {\"PCA\" | \"MDS\" | \"random\"} AvailableInit */\n/** @typedef {{ PCA: ParametersPCA; MDS: ParametersMDS; random: {} }} ChooseDR */\n/**\n * Sammon's Mapping\n *\n * A nonlinear dimensionality reduction technique that minimizes a stress\n * function based on the ratio of pairwise distances in high and low dimensional spaces.\n *\n * @class\n * @template {InputType} T\n * @extends DR>\n * @category Dimensionality Reduction\n */\nexport class SAMMON extends DR> {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial>} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial>): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial>} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial>): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial>} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial>): Promise;\n /**\n * SAMMON's Mapping\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial>} [parameters] - Object containing parameterization of the DR\n * method.\n * @see {@link https://arxiv.org/pdf/2009.01512.pdf}\n */\n constructor(X: T, parameters?: Partial>);\n /** @type {Matrix | undefined} */\n distance_matrix: Matrix | undefined;\n /**\n * Initializes the projection.\n *\n * @param {Matrix | undefined} D\n * @returns {asserts D is Matrix}\n */\n init(D: Matrix | undefined): asserts D is Matrix;\n /**\n * Transforms the inputdata `X` to dimensionality 2.\n *\n * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200`\n * @returns {T} The projection of `X`.\n */\n transform(max_iter?: number): T;\n /**\n * Transforms the inputdata `X` to dimenionality 2.\n *\n * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200`\n * @returns {Generator} A generator yielding the intermediate steps of the projection of\n * `X`.\n */\n generator(max_iter?: number): Generator;\n _step(): Matrix;\n}\nexport type AvailableInit = \"PCA\" | \"MDS\" | \"random\";\nexport type ChooseDR = {\n PCA: ParametersPCA;\n MDS: ParametersMDS;\n random: {};\n};\nimport type { InputType } from \"../index.js\";\nimport type { ParametersSAMMON } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport type { ParametersPCA } from \"./index.js\";\nimport type { ParametersMDS } from \"./index.js\";\n//# sourceMappingURL=SAMMON.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersSMACOF} from \"./index.js\" */\n/**\n * Metric Multidimensional Scaling (MDS) via SMACOF.\n *\n * SMACOF (Scaling by Majorizing a Complicated Function) is an iterative majorization\n * algorithm for solving metric multidimensional scaling problems, which aims to\n * minimize the stress function.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link MDS} for the classical approach.\n */\nexport class SMACOF extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * SMACOF for MDS.\n *\n * @param {T} X - The high-dimensional data or precomputed distance matrix.\n * @param {Partial} [parameters] - Object containing parameterization.\n */\n constructor(X: T, parameters?: Partial);\n /**\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * @returns {T}\n */\n transform(): T;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersSMACOF } from \"./index.js\";\nimport { DR } from \"./DR.js\";\n//# sourceMappingURL=SMACOF.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersSQDMDS} from \"./index.js\" */\n/**\n * SQuadMDS (Stochastic Quartet MDS)\n *\n * A lean Stochastic Quartet MDS improving global structure preservation in\n * neighbor embedding like t-SNE and UMAP.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class SQDMDS extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * SQuadMDS: a lean Stochastic Quartet MDS improving global structure preservation in neighbor embedding like t-SNE\n * and UMAP.\n *\n * @param {T} X\n * @param {Partial} [parameters]\n * @see {@link https://arxiv.org/pdf/2202.12087.pdf}\n */\n constructor(X: T, parameters?: Partial);\n init(): void;\n _add: ((...summands: Float64Array[]) => Float64Array) | undefined;\n _sub_div: ((x: Float64Array, y: Float64Array, div: number) => Float64Array) | undefined;\n _minus: ((a: Float64Array, b: Float64Array) => Float64Array) | undefined;\n _mult: ((a: Float64Array, v: number) => Float64Array) | undefined;\n _LR_init: number | undefined;\n _LR: number | undefined;\n _offset: number | undefined;\n _momentums: Matrix | undefined;\n _grads: Matrix | undefined;\n _indices: number[] | undefined;\n /** @type {(i: number, j: number, X: Matrix) => number} */\n _HD_metric: ((i: number, j: number, X: Matrix) => number) | undefined;\n /** @type {(i: number, j: number, X: Matrix) => number} */\n _HD_metric_exaggeration: ((i: number, j: number, X: Matrix) => number) | undefined;\n /**\n * Computes the projection.\n *\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {T} The projection.\n */\n transform(iterations?: number): T;\n _decay_start: number | undefined;\n /**\n * Computes the projection.\n *\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {Generator} The intermediate steps of the projection.\n */\n generator(iterations?: number): Generator;\n /**\n * Performs an optimization step.\n *\n * @private\n * @param {number} i - Acutal iteration.\n * @param {number} iterations - Number of iterations.\n */\n private _step;\n _distance_exaggeration: boolean | undefined;\n /**\n * Creates quartets of non overlapping indices.\n *\n * @private\n * @returns {Uint32Array[]}\n */\n private __quartets;\n /**\n * Computes and applies gradients, and updates momentum.\n *\n * @private\n * @param {boolean} distance_exaggeration\n */\n private _nestrov_iteration;\n /**\n * Computes the gradients.\n *\n * @param {Matrix} Y - The Projection.\n * @param {Matrix} grads - The gradients.\n * @param {boolean} [exaggeration=false] - Whether or not to use early exaggeration. Default is `false`\n * @param {boolean} [zero_grad=true] - Whether or not to reset the gradient in the beginning. Default is `true`\n * @returns {Matrix} The gradients.\n */\n _fill_MDS_grads(Y: Matrix, grads: Matrix, exaggeration?: boolean, zero_grad?: boolean): Matrix;\n /**\n * Quartet gradients for a projection.\n *\n * @private\n * @param {Matrix} Y - The acutal projection.\n * @param {number[]} quartet - The indices of the quartet.\n * @param {Float64Array} D_hd - The high-dimensional distances of the quartet.\n * @returns {Float64Array[]} The gradients for the quartet.\n */\n private _compute_quartet_grads;\n /**\n * Gradients for one element of the loss function's sum.\n *\n * @private\n * @param {Float64Array} a\n * @param {Float64Array} b\n * @param {Float64Array} c\n * @param {Float64Array} d\n * @param {number} d_ab\n * @param {number} d_ac\n * @param {number} d_ad\n * @param {number} d_bc\n * @param {number} d_bd\n * @param {number} d_cd\n * @param {number} p_ab\n * @param {number} sum_LD_dist\n * @returns {Float64Array[]}\n */\n private _ABCD_grads;\n /**\n * Inline!\n *\n * @param {number} d\n */\n __minus(d: number): (a: Float64Array, b: Float64Array) => Float64Array;\n /**\n * Inline!\n *\n * @param {number} d\n */\n __add(d: number): (...summands: Float64Array[]) => Float64Array;\n /**\n * Inline!\n *\n * @param {number} d\n */\n __mult(d: number): (a: Float64Array, v: number) => Float64Array;\n /**\n * Creates a new array `(x - y) / div`.\n *\n * @param {number} d\n */\n __sub_div(d: number): (x: Float64Array, y: Float64Array, div: number) => Float64Array;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersSQDMDS } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=SQDMDS.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersTopoMap} from \"./index.js\" */\n/**\n * TopoMap\n *\n * A 0-dimensional Homology Preserving Projection of High-Dimensional Data.\n * It aims to preserve the topological structure of the data by maintaining\n * the connectivity of a minimum spanning tree.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class TopoMap extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X: T_1, parameters: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static generator(X: T_1, parameters: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters: Partial): Promise;\n /**\n * TopoMap: A 0-dimensional Homology Preserving Projection of High-Dimensional Data.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://arxiv.org/pdf/2009.01512.pdf}\n */\n constructor(X: T, parameters: Partial);\n _distance_matrix: Matrix;\n /**\n * @private\n * @param {number} i\n * @param {number} j\n * @param {import(\"../metrics/index.js\").Metric} metric\n * @returns {number}\n */\n private __lazy_distance_matrix;\n /**\n * Computes the minimum spanning tree, using a given metric\n *\n * @private\n * @param {import(\"../metrics/index.js\").Metric} metric\n * @see {@link https://en.wikipedia.org/wiki/Kruskal%27s_algorithm}\n */\n private _make_minimum_spanning_tree;\n _disjoint_set: DisjointSet> | undefined;\n /** Initializes TopoMap. Sets all projcted points to zero, and computes a minimum spanning tree. */\n init(): this;\n _Emst: number[][] | undefined;\n /**\n * Returns true if Point C is left of line AB.\n *\n * @private\n * @param {Float64Array} PointA - Point A of line AB\n * @param {Float64Array} PointB - Point B of line AB\n * @param {Float64Array} PointC - Point C\n * @returns {boolean}\n */\n private __hull_cross;\n /**\n * Computes the convex hull of the set of Points S\n *\n * @private\n * @param {Float64Array[]} S - Set of Points.\n * @returns {Float64Array[]} Convex hull of S. Starts at the bottom-most point and continues counter-clockwise.\n * @see {@link https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain#JavaScript}\n */\n private __hull;\n /**\n * Finds the angle to rotate Point A and B to lie on a line parallel to the x-axis.\n *\n * @private\n * @param {Float64Array} PointA\n * @param {Float64Array} PointB\n * @returns {{ sin: number; cos: number }} Object containing the sinus- and cosinus-values for a rotation.\n */\n private __findAngle;\n /**\n * @private\n * @param {Float64Array[]} hull\n * @param {Float64Array} p\n * @param {boolean} topEdge\n * @returns {{ sin: number; cos: number; tx: number; ty: number }}\n */\n private __align_hull;\n /**\n * @private\n * @param {Float64Array} Point - The point which should get transformed.\n * @param {{ sin: number; cos: number; tx: number; ty: number }} Transformation - Contains the values for\n * translation and rotation.\n */\n private __transform;\n /**\n * Calls `__transform` for each point in Set C\n *\n * @private\n * @param {Float64Array[]} C - Set of points.\n * @param {{ sin: number; cos: number; tx: number; ty: number }} t - Transform object.\n * @param {number} yOffset - Value to offset set C.\n */\n private __transform_component;\n /**\n * @private\n * @param {Float64Array} root_u - Root of component u\n * @param {Float64Array} root_v - Root of component v\n * @param {Float64Array} p_u - Point u\n * @param {Float64Array} p_v - Point v\n * @param {number} w - Edge weight w\n * @param {DisjointSet} components - The disjoint set containing the components\n */\n private __align_components;\n /**\n * Transforms the inputdata `X` to dimensionality 2.\n *\n * @returns {T}\n */\n transform(): T;\n /**\n * Transforms the inputdata `X` to dimensionality 2.\n *\n * @returns {Generator}\n */\n generator(): Generator;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersTopoMap } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { DisjointSet } from \"../datastructure/index.js\";\n//# sourceMappingURL=TopoMap.d.ts.map","/**\n * Base class for all K-Nearest Neighbors (KNN) search algorithms.\n *\n * Provides a common interface for elements management and search operations.\n *\n * @abstract\n * @category KNN\n * @template {number[] | Float64Array} T - Type of elements\n * @template {Object} Para - Type of parameters\n * @class\n */\nexport class KNN {\n /**\n * @param {T[]} elements\n * @param {Para} parameters\n */\n constructor(elements: T[], parameters: Para);\n /** @type {T[]} */\n _elements: T[];\n /** @type {Para} */\n _parameters: Para;\n /** @type {\"typed\" | \"array\"} */\n _type: \"typed\" | \"array\";\n /**\n * @abstract\n * @param {T} t\n * @param {number} k\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search(t: T, k: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @abstract\n * @param {number} i\n * @param {number} k\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i: number, k: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n}\n//# sourceMappingURL=KNN.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersTriMap} from \"./index.js\" */\n/** @import {KNN} from \"../knn/KNN.js\" */\n/**\n * TriMap\n *\n * A dimensionality reduction technique that preserves both local and global\n * structure using triplets. It is designed to be a more robust alternative\n * to t-SNE and UMAP.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class TriMap extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n * @see {@link https://arxiv.org/pdf/1910.00204v1.pdf}\n * @see {@link https://github.com/eamid/trimap}\n */\n constructor(X: T, parameters?: Partial);\n /**\n * @param {Matrix | null} [pca=null] - Initial Embedding (if null then PCA gets used). Default is `null`\n * @param {import(\"../knn/KNN.js\").KNN | null} [knn=null] - KNN Object (if null then BallTree gets used). Default is `null`\n */\n init(pca?: Matrix | null, knn?: import(\"../knn/KNN.js\").KNN | null): this;\n n_inliers: number | undefined;\n n_outliers: number | undefined;\n n_random: number | undefined;\n knn: KNN, any> | undefined;\n triplets: Matrix | undefined;\n weights: Float64Array | undefined;\n lr: number | undefined;\n C: number | undefined;\n vel: Matrix | undefined;\n gain: Matrix | undefined;\n /**\n * Generates {@link n_inliers} x {@link n_outliers} x {@link n_random} triplets.\n *\n * @param {number} n_inliers\n * @param {number} n_outliers\n * @param {number} n_random\n */\n _generate_triplets(n_inliers: number, n_outliers: number, n_random: number): {\n triplets: Matrix;\n weights: Float64Array;\n };\n /**\n * Calculates the similarity matrix P\n *\n * @private\n * @param {Matrix} knn_distances - Matrix of pairwise knn distances\n * @param {Float64Array} sig - Scaling factor for the distances\n * @param {Matrix} nbrs - Nearest neighbors\n * @returns {Matrix} Pairwise similarity matrix\n */\n private _find_p;\n /**\n * Sample nearest neighbors triplets based on the similarity values given in P.\n *\n * @private\n * @param {Matrix} P - Matrix of pairwise similarities between each point and its neighbors given in matrix nbrs.\n * @param {Matrix} nbrs - Nearest neighbors indices for each point. The similarity values are given in matrix\n * {@link P}. Row i corresponds to the i-th point.\n * @param {number} n_inliers - Number of inlier points.\n * @param {number} n_outliers - Number of outlier points.\n */\n private _sample_knn_triplets;\n /**\n * Should do the same as np.argsort()\n *\n * @private\n * @param {Float64Array | number[]} A\n */\n private __argsort;\n /**\n * Samples {@link n_samples} integers from a given interval [0, {@link max_int}] while rejection the values that are\n * in the {@link rejects}.\n *\n * @private\n * @param {number} n_samples\n * @param {number} max_int\n * @param {number[]} rejects\n */\n private _rejection_sample;\n /**\n * Calculates the weights for the sampled nearest neighbors triplets\n *\n * @private\n * @param {Matrix} triplets - Sampled Triplets.\n * @param {Matrix} P - Pairwise similarity matrix.\n * @param {Matrix} nbrs - Nearest Neighbors\n * @param {Float64Array} outlier_distances - Matrix of pairwise outlier distances\n * @param {Float64Array} sig - Scaling factor for the distances.\n */\n private _find_weights;\n /**\n * Sample uniformly ranom triplets\n *\n * @private\n * @param {Matrix} X - Data matrix.\n * @param {number} n_random - Number of random triplets per point\n * @param {Float64Array} sig - Scaling factor for the distances\n */\n private _sample_random_triplets;\n /**\n * Computes the gradient for updating the embedding.\n *\n * @param {Matrix} Y - The embedding\n */\n _grad(Y: Matrix): {\n grad: Matrix;\n loss: number;\n n_viol: number;\n };\n /**\n * @param {number} max_iteration\n * @returns {T}\n */\n transform(max_iteration?: number): T;\n /**\n * @param {number} max_iteration\n * @returns {Generator}\n */\n generator(max_iteration?: number): Generator;\n /**\n * Does the iteration step.\n *\n * @private\n * @param {number} iter\n */\n private _next;\n /**\n * Updates the embedding.\n *\n * @private\n * @param {Matrix} Y\n * @param {number} iter\n * @param {Matrix} grad\n */\n private _update_embedding;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersTriMap } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport type { KNN } from \"../knn/KNN.js\";\n//# sourceMappingURL=TriMap.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersTSNE} from \"./index.js\" */\n/**\n * t-SNE (t-Distributed Stochastic Neighbor Embedding)\n *\n * A nonlinear dimensionality reduction technique particularly well-suited\n * for visualizing high-dimensional data in 2D or 3D. Preserves local\n * structure while revealing global patterns.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link https://lvdmaaten.github.io/tsne/|t-SNE Paper}\n * @see {@link UMAP} for faster alternative with similar results\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];\n * const tsne = new druid.TSNE(X, {\n * perplexity: 30,\n * epsilon: 10,\n * d: 2,\n * seed: 42\n * });\n *\n * const Y = tsne.transform(500); // 500 iterations\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class TSNE extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X: T, parameters?: Partial);\n _iter: number;\n init(): this;\n _ystep: Matrix | undefined;\n _gains: Matrix | undefined;\n _P: Matrix | undefined;\n /**\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {T} The projection.\n */\n transform(iterations?: number): T;\n /**\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {Generator} - The projection.\n */\n generator(iterations?: number): Generator;\n /**\n * Performs a optimization step\n *\n * @private\n * @returns {Matrix}\n */\n private next;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersTSNE } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=TSNE.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersUMAP} from \"./index.js\" */\n/**\n * Uniform Manifold Approximation and Projection (UMAP)\n *\n * A novel manifold learning technique for dimensionality reduction. UMAP is constructed\n * from a theoretical framework based on Riemannian geometry and algebraic topology.\n * It is often faster than t-SNE while preserving more of the global structure.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link https://arxiv.org/abs/1802.03426|UMAP Paper}\n * @see {@link TSNE} for a similar visualization technique\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];\n * const umap = new druid.UMAP(X, {\n * n_neighbors: 15,\n * min_dist: 0.1,\n * d: 2,\n * seed: 42\n * });\n *\n * const Y = umap.transform(500); // 500 iterations\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class UMAP extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X: T, parameters?: Partial);\n _iter: number;\n /**\n * @private\n * @param {number} spread\n * @param {number} min_dist\n * @returns {number[]}\n */\n private _find_ab_params;\n /**\n * @private\n * @param {{ element: Float64Array; index: number; distance: number }[][]} distances\n * @param {number[]} sigmas\n * @param {number[]} rhos\n * @returns {{ element: Float64Array; index: number; distance: number }[][]}\n */\n private _compute_membership_strengths;\n /**\n * @private\n * @param {NaiveKNN | BallTree} knn\n * @param {number} k\n * @returns {{\n * distances: { element: Float64Array; index: number; distance: number }[][];\n * sigmas: number[];\n * rhos: number[];\n * }}\n */\n private _smooth_knn_dist;\n /**\n * @private\n * @param {Matrix} X\n * @param {number} n_neighbors\n * @returns {Matrix}\n */\n private _fuzzy_simplicial_set;\n /**\n * @private\n * @param {number} n_epochs\n * @returns {Float32Array}\n */\n private _make_epochs_per_sample;\n /**\n * @private\n * @param {Matrix} graph\n * @returns {{ rows: number[]; cols: number[]; data: number[] }}\n */\n private _tocoo;\n /**\n * Computes all necessary\n *\n * @returns {UMAP}\n */\n init(): UMAP;\n _a: number | undefined;\n _b: number | undefined;\n _graph: Matrix | undefined;\n _head: number[] | undefined;\n _tail: number[] | undefined;\n _weights: number[] | undefined;\n _epochs_per_sample: Float32Array | undefined;\n _epochs_per_negative_sample: Float32Array | undefined;\n _epoch_of_next_sample: Float32Array | undefined;\n _epoch_of_next_negative_sample: Float32Array | undefined;\n graph(): {\n cols: number[] | undefined;\n rows: number[] | undefined;\n weights: number[] | undefined;\n };\n /**\n * @param {number} [iterations=350] - Number of iterations. Default is `350`\n * @returns {T}\n */\n transform(iterations?: number): T;\n /**\n * @param {number} [iterations=350] - Number of iterations. Default is `350`\n * @returns {Generator}\n */\n generator(iterations?: number): Generator;\n /**\n * @private\n * @param {number} x\n * @returns {number}\n */\n private _clip;\n /**\n * Performs the optimization step.\n *\n * @private\n * @param {Matrix} head_embedding\n * @param {Matrix} tail_embedding\n * @param {number[]} head\n * @param {number[]} tail\n * @returns {Matrix}\n */\n private _optimize_layout;\n /**\n * @private\n * @returns {Matrix}\n */\n private next;\n _alpha: number | undefined;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersUMAP } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=UMAP.d.ts.map","/**\n * Computes the inner product between two arrays of the same length.\n *\n * @category Linear Algebra\n * @param {number[] | Float64Array} a - Array a.\n * @param {number[] | Float64Array} b - Array b.\n * @returns The inner product between `a` and `b`.\n */\nexport function inner_product(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=inner_product.d.ts.map","/**\n * Computes the QR Decomposition of the Matrix `A` using Gram-Schmidt process.\n *\n * @category Linear Algebra\n * @param {Matrix} A\n * @returns {{ R: Matrix; Q: Matrix }}\n * @see {@link https://en.wikipedia.org/wiki/QR_decomposition#Using_the_Gram%E2%80%93Schmidt_process}\n */\nexport function qr(A: Matrix): {\n R: Matrix;\n Q: Matrix;\n};\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=qr.d.ts.map","/**\n * Computes the QR Decomposition of the Matrix `A` with householder transformations.\n *\n * @category Linear Algebra\n * @param {Matrix} A\n * @returns {{ R: Matrix; Q: Matrix }}\n * @see {@link https://en.wikipedia.org/wiki/QR_decomposition#Using_Householder_reflections}\n * @see {@link http://mlwiki.org/index.php/Householder_Transformation}\n */\nexport function qr_householder(A: Matrix): {\n R: Matrix;\n Q: Matrix;\n};\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=qr_householder.d.ts.map","/** @import { EigenArgs } from \"./index.js\" */\n/**\n * Computes the `k` biggest Eigenvectors and Eigenvalues from Matrix `A` with the QR-Algorithm.\n *\n * @category Linear Algebra\n * @param {Matrix} A - The Matrix\n * @param {number} k - The number of eigenvectors and eigenvalues to compute.\n * @param {EigenArgs} parameters - Object containing parameterization of the simultanious\n * poweriteration method.\n * @returns {{ eigenvalues: Float64Array; eigenvectors: Float64Array[] }} The `k` biggest eigenvectors and eigenvalues\n * of Matrix `A`.\n */\nexport function simultaneous_poweriteration(A: Matrix, k?: number, { seed, max_iterations, qr, tol }?: EigenArgs): {\n eigenvalues: Float64Array;\n eigenvectors: Float64Array[];\n};\nimport { Matrix } from \"../matrix/index.js\";\nimport type { EigenArgs } from \"./index.js\";\n//# sourceMappingURL=simultaneous_poweriteration.d.ts.map","export { inner_product } from \"./inner_product.js\";\nexport { qr } from \"./qr.js\";\nexport { qr_householder } from \"./qr_householder.js\";\nexport { simultaneous_poweriteration } from \"./simultaneous_poweriteration.js\";\nexport type QRDecomposition = (A: import(\"../matrix/index.js\").Matrix) => {\n R: import(\"../matrix/index.js\").Matrix;\n Q: import(\"../matrix/index.js\").Matrix;\n};\nexport type EigenArgs = {\n /**\n * - The number of maxiumum iterations the algorithm should run. Default is `100`\n */\n max_iterations?: number | undefined;\n /**\n * - The seed value or a randomizer used in the algorithm. Default is `1212`\n */\n seed?: number | Randomizer | undefined;\n /**\n * - The QR technique to use. Default is `qr_gramschmidt`\n */\n qr?: QRDecomposition | undefined;\n /**\n * - Tolerated error for stopping criteria. Default is `1e-8`\n */\n tol?: number | undefined;\n};\nimport type { Randomizer } from \"../util/index.js\";\n//# sourceMappingURL=index.d.ts.map","export { FASTMAP } from \"./FASTMAP.js\";\nexport { ISOMAP } from \"./ISOMAP.js\";\nexport { LDA } from \"./LDA.js\";\nexport { LLE } from \"./LLE.js\";\nexport { LSP } from \"./LSP.js\";\nexport { LTSA } from \"./LTSA.js\";\nexport { MDS } from \"./MDS.js\";\nexport { PCA } from \"./PCA.js\";\nexport { SAMMON } from \"./SAMMON.js\";\nexport { SMACOF } from \"./SMACOF.js\";\nexport { SQDMDS } from \"./SQDMDS.js\";\nexport { TopoMap } from \"./TopoMap.js\";\nexport { TriMap } from \"./TriMap.js\";\nexport { TSNE } from \"./TSNE.js\";\nexport { UMAP } from \"./UMAP.js\";\nexport type ParametersLSP = {\n /**\n * - number of neighbors to consider.\n */\n neighbors?: number | undefined;\n /**\n * - number of controlpoints\n */\n control_points?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersFASTMAP = {\n /**\n * - The dimensionality of the projection\n */\n d?: number | undefined;\n /**\n * - The metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - The seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersISOMAP = {\n /**\n * - The number of neighbors ISOMAP should use to project the data.\n */\n neighbors?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - Whether to use classical MDS or SMACOF for the final DR.\n */\n project?: \"MDS\" | \"SMACOF\" | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n /**\n * - Parameters for the eigendecomposition algorithm.\n */\n eig_args?: Partial | undefined;\n};\nexport type ParametersLDA = {\n /**\n * - The labels / classes for each data point.\n */\n labels: any[] | Float64Array;\n /**\n * - The dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - The seed for the random number generator.\n */\n seed?: number | undefined;\n /**\n * - Parameters for the eigendecomposition algorithm.\n */\n eig_args?: Partial | undefined;\n};\nexport type ParametersLLE = {\n /**\n * - The number of neighbors for LLE.\n */\n neighbors?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n /**\n * - Parameters for the eigendecomposition algorithm.\n */\n eig_args?: Partial | undefined;\n};\nexport type ParametersLTSA = {\n /**\n * - The number of neighbors for LTSA.\n */\n neighbors?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n /**\n * - Parameters for the eigendecomposition algorithm.\n */\n eig_args?: Partial | undefined;\n};\nexport type ParametersMDS = {\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | \"precomputed\" | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n /**\n * - Parameters for the eigendecomposition algorithm.\n */\n eig_args?: Partial | undefined;\n};\nexport type ParametersPCA = {\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n /**\n * - Parameters for the eigendecomposition algorithm.\n */\n eig_args?: Partial | undefined;\n};\nexport type ParametersSAMMON = {\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | \"precomputed\" | undefined;\n /**\n * - Either \"PCA\" or \"MDS\", with which SAMMON initialiates the projection.\n */\n init_DR?: K | undefined;\n /**\n * - Parameters for the \"init\"-DR method.\n */\n init_parameters?: ChooseDR[K] | undefined;\n /**\n * - learning rate for gradient descent.\n */\n magic?: number | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersSMACOF = {\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | \"precomputed\" | undefined;\n /**\n * - maximum number of iterations.\n */\n iterations?: number | undefined;\n /**\n * - tolerance for stress difference.\n */\n epsilon?: number | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersSQDMDS = {\n d?: number | undefined;\n metric?: Metric | \"precomputed\" | undefined;\n /**\n * - Percentage of iterations using exaggeration phase.\n */\n decay_start?: number | undefined;\n /**\n * - Controls the decay of the learning parameter.\n */\n decay_cte?: number | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersTopoMap = {\n /**\n * = euclidean - The metric which defines the distance between\n * two points.\n */\n metric: Metric;\n /**\n * = 1212 - The seed for the random number generator.\n */\n seed: number;\n};\nexport type ParametersTriMap = {\n /**\n * - scaling factor.\n */\n weight_adj?: number | undefined;\n /**\n * - number of inliers.\n */\n n_inliers?: number | undefined;\n /**\n * - number of outliers.\n */\n n_outliers?: number | undefined;\n /**\n * - number of random points.\n */\n n_random?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n tol?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersTSNE = {\n /**\n * - perplexity.\n */\n perplexity?: number | undefined;\n /**\n * - learning parameter.\n */\n epsilon?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | \"precomputed\" | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersUMAP = {\n /**\n * - size of the local neighborhood.\n */\n n_neighbors?: number | undefined;\n /**\n * - number of nearest neighbors connected in the local neighborhood.\n */\n local_connectivity?: number | undefined;\n /**\n * - controls how tightly points get packed together.\n */\n min_dist?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points in the high-dimensional space.\n */\n metric?: Metric | \"precomputed\" | undefined;\n /**\n * - The effective scale of embedded points.\n */\n _spread?: number | undefined;\n /**\n * - Interpolate between union and intersection.\n */\n _set_op_mix_ratio?: number | undefined;\n /**\n * - Weighting applied to negative samples.\n */\n _repulsion_strength?: number | undefined;\n /**\n * - The number of negative samples per positive sample.\n */\n _negative_sample_rate?: number | undefined;\n /**\n * - The number of training epochs.\n */\n _n_epochs?: number | undefined;\n /**\n * - The initial learning rate for the optimization.\n */\n _initial_alpha?: number | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nimport type { Metric } from \"../metrics/index.js\";\nimport type { EigenArgs } from \"../linear_algebra/index.js\";\nimport type { ChooseDR } from \"./SAMMON.js\";\n//# sourceMappingURL=index.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersAnnoy } from \"./index.js\" */\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} AnnoyNode\n * @property {boolean} isLeaf - Whether this is a leaf node\n * @property {number[]} indices - Indices of points in this node (leaf) or children (internal)\n * @property {number[]} normal - Hyperplane normal vector (internal nodes only)\n * @property {number} offset - Hyperplane offset (internal nodes only)\n * @property {AnnoyNode | null} left - Left child (internal nodes only)\n * @property {AnnoyNode | null} right - Right child (internal nodes only)\n */\n/**\n * Annoy-style (Approximate Nearest Neighbors Oh Yeah) implementation using Random Projection Trees.\n *\n * This implementation builds multiple random projection trees where each tree randomly selects\n * two points and splits the space based on a hyperplane equidistant between them.\n *\n * Key features:\n * - Multiple random projection trees for better recall\n * - Each tree uses random hyperplanes for splitting\n * - Priority queue search for better recall\n * - Combines results from all trees\n *\n * Best suited for:\n * - High-dimensional data\n * - Approximate nearest neighbor search\n * - Large datasets\n * - When high recall is needed with approximate methods\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link https://github.com/spotify/annoy}\n * @see {@link https://erikbern.com/2015/09/24/nearest-neighbors-and-vector-models-epilogue-curse-of-dimensionality.html}\n */\nexport class Annoy extends KNN {\n /**\n * Creates a new Annoy-style index with random projection trees.\n *\n * @param {T[]} elements - Elements to index\n * @param {ParametersAnnoy} [parameters={}] - Configuration parameters\n */\n constructor(elements: T[], parameters?: ParametersAnnoy);\n _metric: Metric;\n _numTrees: number;\n _maxPointsPerLeaf: number;\n _seed: number;\n _randomizer: Randomizer;\n /**\n * @private\n * @type {AnnoyNode[]}\n */\n private _trees;\n /**\n * Get the number of trees in the index.\n * @returns {number}\n */\n get num_trees(): number;\n /**\n * Get the total number of nodes in all trees.\n * @returns {number}\n */\n get num_nodes(): number;\n /**\n * @private\n * @param {any} node\n * @returns {number}\n */\n private _countNodes;\n /**\n * Add elements to the Annoy index.\n * @param {T[]} elements\n * @returns {this}\n */\n add(elements: T[]): this;\n /**\n * Build all random projection trees.\n * @private\n */\n private _buildTrees;\n /**\n * Recursively build a random projection tree.\n * @private\n * @param {number[]} indices - Indices of elements to include\n * @returns {AnnoyNode}\n */\n private _buildTreeRecursive;\n /**\n * Compute distance from point to hyperplane.\n * @private\n * @param {T} point\n * @param {number[]} normal\n * @param {number} offset\n * @returns {number} Signed distance (positive = right side, negative = left side)\n */\n private _distanceToHyperplane;\n /**\n * Search for k approximate nearest neighbors.\n * @param {T} query\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search(query: T, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * Search tree using priority queue for better recall.\n * Explores nodes in order of distance to hyperplane.\n * @private\n * @param {AnnoyNode} node\n * @param {T} query\n * @param {Set} candidates\n * @param {number} maxCandidates\n */\n private _searchTreePriority;\n /**\n * @param {number} i\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * Alias for search_by_index for backward compatibility.\n *\n * @param {number} i - Index of the query element\n * @param {number} [k=5] - Number of nearest neighbors to return\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n}\nexport type AnnoyNode = {\n /**\n * - Whether this is a leaf node\n */\n isLeaf: boolean;\n /**\n * - Indices of points in this node (leaf) or children (internal)\n */\n indices: number[];\n /**\n * - Hyperplane normal vector (internal nodes only)\n */\n normal: number[];\n /**\n * - Hyperplane offset (internal nodes only)\n */\n offset: number;\n /**\n * - Left child (internal nodes only)\n */\n left: AnnoyNode | null;\n /**\n * - Right child (internal nodes only)\n */\n right: AnnoyNode | null;\n};\nimport type { ParametersAnnoy } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport type { Metric } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\n//# sourceMappingURL=Annoy.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersBallTree } from \"./index.js\" */\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} ElementWithIndex\n * @property {number} index\n * @property {T} element\n */\n/**\n * Ball Tree for efficient nearest neighbor search.\n *\n * A Ball Tree is a metric tree that partitions points into a nested set of\n * hyperspheres (balls). It is particularly effective for high-dimensional\n * data and supports any valid metric.\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n */\nexport class BallTree extends KNN {\n /**\n * Generates a BallTree with given `elements`.\n *\n * @param {T[]} elements - Elements which should be added to the BallTree\n * @param {ParametersBallTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}`\n * @see {@link https://en.wikipedia.org/wiki/Ball_tree}\n * @see {@link https://github.com/invisal/noobjs/blob/master/src/tree/BallTree.js}\n */\n constructor(elements: T[], parameters?: ParametersBallTree);\n /**\n * @private\n * @type {BallTreeNode | BallTreeLeaf}\n */\n private _root;\n /** @returns {Metric} */\n get _metric(): Metric;\n /**\n * @private\n * @param {ElementWithIndex[]} elements\n * @returns {BallTreeNode | BallTreeLeaf} Root of balltree.\n */\n private _construct;\n /**\n * @private\n * @param {ElementWithIndex[]} B\n * @returns {number}\n */\n private _greatest_spread;\n /**\n * @param {number} i\n * @param {number} k\n */\n search_by_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @param {T} t - Query element.\n * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors.\n */\n search(t: T, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @private\n * @param {T} t - Query element.\n * @param {number} k - Number of nearest neighbors to return.\n * @param {Heap>} Q - Heap consists of the currently found `k` nearest neighbors.\n * @param {BallTreeNode | BallTreeLeaf} B\n */\n private _search;\n}\nexport type ElementWithIndex = {\n index: number;\n element: T;\n};\nimport type { ParametersBallTree } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=BallTree.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersHNSW } from \"./index.js\" */\n/**\n * @typedef {Object} Layer\n * @property {number} l_c - Layer number\n * @property {number[]} point_indices - Global indices of points in this layer\n * @property {Map} edges - Global index -> array of connected global indices\n */\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} Candidate\n * @property {T} element - The actual data point\n * @property {number} index - Global index in the dataset\n * @property {number} distance - Distance from query\n */\n/**\n * Hierarchical Navigable Small World (HNSW) graph for approximate nearest neighbor search.\n *\n * HNSW builds a multi-layer graph structure where each layer is a navigable small world graph.\n * The top layers serve as \"highways\" for fast traversal, while lower layers provide accuracy.\n * Each element is assigned to a random level, allowing logarithmic search complexity.\n *\n * Key parameters:\n * - `m`: Controls the number of connections per element (affects accuracy/memory)\n * - `ef_construction`: Controls the quality of the graph during construction (higher = better but slower)\n * - `ef`: Controls the quality of search (higher = better recall but slower)\n *\n * Based on:\n * - \"Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs\"\n * by Malkov & Yashunin (2016)\n * - \"Approximate Nearest Neighbor Search on High Dimensional Data\"\n * by Li et al. (2019)\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const points = [[1, 2], [3, 4], [5, 6], [7, 8]];\n * const hnsw = new druid.HNSW(points, {\n * metric: druid.euclidean,\n * m: 16,\n * ef_construction: 200\n * });\n *\n * const query = [2, 3];\n * const neighbors = hnsw.search(query, 2);\n * // [{ element: [1, 2], index: 0, distance: 1.41 }, ...]\n */\nexport class HNSW extends KNN {\n /**\n * Creates a new HNSW index.\n *\n * @param {T[]} points - Initial points to add to the index\n * @param {ParametersHNSW} [parameters={}] - Configuration parameters\n */\n constructor(points: T[], parameters?: ParametersHNSW);\n /** @type {Metric} */\n _metric: Metric;\n /** @type {Function} */\n _select: Function;\n /**\n * @private\n * @type {Map}\n */\n private _graph;\n /** @type {number} */\n _next_index: number;\n /** @type {number} */\n _m: number;\n /** @type {number} */\n _ef_construction: number;\n /** @type {number} */\n _ef: number;\n /** @type {number} */\n _m0: number;\n /** @type {number} */\n _mL: number;\n /** @type {Randomizer} */\n _randomizer: Randomizer;\n /** @type {number} - Current maximum layer in the graph */\n _L: number;\n /** @type {number[] | null} - Entry point indices for search */\n _ep: number[] | null;\n /**\n * Add a single element to the index.\n *\n * @param {T} element - Element to add\n * @returns {HNSW} This instance for chaining\n */\n addOne(element: T): HNSW;\n /**\n * Add multiple elements to the index.\n *\n * @param {T[]} new_elements - Elements to add\n * @returns {HNSW} This instance for chaining\n */\n add(new_elements: T[]): HNSW;\n /**\n * Select neighbors using the heuristic approach.\n *\n * The heuristic extends candidates with their neighbors and selects\n * points that are closer to the query than to already selected points.\n * This maintains graph connectivity better than simple selection.\n *\n * @private\n * @param {T} q - Query element\n * @param {Candidate[]} candidates - Candidate elements with distances\n * @param {number} M - Maximum number of neighbors to return\n * @param {number} l_c - Layer number\n * @param {boolean} [extend_candidates=true] - Whether to extend candidates with their neighbors\n * @param {boolean} [keep_pruned_connections=true] - Whether to add pruned connections back if needed\n * @returns {number[]} Selected neighbor indices\n */\n private _select_heuristic;\n /**\n * Select neighbors using simple distance-based selection.\n *\n * Simply returns the M closest candidates to the query.\n *\n * @private\n * @param {T} q - Query element\n * @param {Candidate[]} C - Candidate elements with distances\n * @param {number} M - Maximum number of neighbors to return\n * @returns {number[]} M nearest candidate indices\n */\n private _select_simple;\n /**\n * Search a single layer for nearest neighbors.\n *\n * Implements the greedy search algorithm: start from entry points,\n * always expand the closest unvisited candidate, maintain a list\n * of the ef closest found neighbors.\n *\n * @private\n * @param {T} q - Query element\n * @param {number[] | null} ep_indices - Entry point indices\n * @param {number} ef - Number of nearest neighbors to find\n * @param {number} l_c - Layer number to search\n * @returns {Candidate[]} ef nearest neighbors found with their distances\n */\n private _search_layer;\n /**\n * Fallback linear search when graph search fails\n * @private\n * @param {T} q - Query element\n * @param {number} K - Number of nearest neighbors to return\n * @returns {Candidate[]}\n */\n private _linear_search;\n /**\n * Iterator for searching the HNSW graph layer by layer.\n *\n * Yields intermediate results at each layer for debugging or visualization.\n *\n * @param {T} q - Query element\n * @param {number} K - Number of nearest neighbors to return\n * @param {number?} [ef] - Size of dynamic candidate list\n * @yields {{layer: number, candidates: Candidate[]}}\n */\n search_iter(q: T, K: number, ef?: number | null): Generator<{\n layer: number;\n candidates: {\n element: T;\n index: number;\n distance: number;\n }[];\n }, void, unknown>;\n /**\n * Get the number of elements in the index.\n *\n * @returns {number} Number of elements\n */\n get size(): number;\n /**\n * Get the number of layers in the graph.\n *\n * @returns {number} Number of layers\n */\n get num_layers(): number;\n /**\n * Get an element by its index.\n *\n * @param {number} index - Element index\n * @returns {T} The element at the given index\n */\n get_element(index: number): T;\n /**\n * Search for nearest neighbors using an element index as the query.\n *\n * @param {number} i - Index of the query element\n * @param {number} [K=5] - Number of nearest neighbors to return\n * @returns {Candidate[]} K nearest neighbors\n */\n search_by_index(i: number, K?: number): Candidate[];\n}\nexport type Layer = {\n /**\n * - Layer number\n */\n l_c: number;\n /**\n * - Global indices of points in this layer\n */\n point_indices: number[];\n /**\n * - Global index -> array of connected global indices\n */\n edges: Map;\n};\nexport type Candidate = {\n /**\n * - The actual data point\n */\n element: T;\n /**\n * - Global index in the dataset\n */\n index: number;\n /**\n * - Distance from query\n */\n distance: number;\n};\nimport type { ParametersHNSW } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport type { Metric } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\n//# sourceMappingURL=HNSW.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersKDTree } from \"./index.js\" */\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} ElementWithIndex\n * @property {number} index\n * @property {T} element\n */\n/**\n * KD-Tree (K-dimensional Tree) for efficient nearest neighbor search.\n *\n * KD-Trees partition k-dimensional space by recursively splitting along coordinate axes.\n * At each level, the tree splits points based on the median of the coordinate with the largest spread.\n * This creates a balanced binary tree structure that enables efficient O(log n) search on average.\n *\n * Best suited for:\n * - Low to moderate dimensional data (d < 20-30)\n * - When exact nearest neighbors are needed\n * - When dimensionality is not too high\n *\n * Performance degrades in high dimensions (curse of dimensionality) where approximate\n * methods like HNSW or LSH become more effective.\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link https://en.wikipedia.org/wiki/K-d_tree}\n */\nexport class KDTree extends KNN {\n /**\n * Generates a KD-Tree with given `elements`.\n *\n * @param {T[]} elements - Elements which should be added to the KD-Tree\n * @param {ParametersKDTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}`\n */\n constructor(elements: T[], parameters?: ParametersKDTree);\n /**\n * @private\n * @type {KDTreeNode | KDTreeLeaf | null}\n */\n private _root;\n /** @returns {Metric} */\n get _metric(): Metric;\n /**\n * @private\n * @param {ElementWithIndex[]} elements\n * @param {number} depth - Current depth in the tree (determines splitting axis)\n * @returns {KDTreeNode | KDTreeLeaf | null} Root of KD-Tree.\n */\n private _construct;\n /**\n * @param {number} i\n * @param {number} k\n */\n search_by_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @param {T} t - Query element.\n * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors.\n */\n search(t: T, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @private\n * @param {T} target - Query element.\n * @param {number} k - Number of nearest neighbors to return.\n * @param {KDTreeNode | KDTreeLeaf | null} node - Current node.\n * @param {Heap<{ point: ElementWithIndex; distance: number }>} best - Heap of k best found so far.\n */\n private _search_recursive;\n}\nexport type ElementWithIndex = {\n index: number;\n element: T;\n};\nimport type { ParametersKDTree } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=KDTree.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersLSH } from \"./index.js\" */\n/**\n * Locality Sensitive Hashing (LSH) for approximate nearest neighbor search.\n *\n * LSH uses hash functions that map similar items to the same buckets with high probability.\n * This implementation uses Random Projection hashing (SimHash-style) which works well for\n * cosine similarity and Euclidean distance.\n *\n * Key concepts:\n * - Multiple hash tables increase recall probability\n * - Each hash function projects data onto random hyperplanes\n * - Points on the same side of hyperplanes are hashed together\n * - Combines results from all tables for better accuracy\n *\n * Best suited for:\n * - High-dimensional data where exact methods fail\n * - Approximate nearest neighbor needs\n * - Large datasets where linear scan is too slow\n * - When some false positives/negatives are acceptable\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link https://en.wikipedia.org/wiki/Locality-sensitive_hashing}\n */\nexport class LSH extends KNN {\n /**\n * Creates a new LSH index.\n *\n * @param {T[]} elements - Elements to index\n * @param {ParametersLSH} [parameters={}] - Configuration parameters\n */\n constructor(elements: T[], parameters?: ParametersLSH);\n _metric: Metric;\n _numHashTables: number;\n _numHashFunctions: number;\n _seed: number;\n _randomizer: Randomizer;\n /** @type {Map[]} */\n _hashTables: Map[];\n /** @type {Float64Array[][]} */\n _projections: Float64Array[][];\n /** @type {number[][]} */\n _offsets: number[][];\n /** @type {number} */\n _dim: number;\n /**\n * Initialize random projection vectors for all hash tables.\n * @private\n */\n private _initializeHashFunctions;\n /**\n * Compute hash signature for an element using random projections.\n * @private\n * @param {T} element\n * @param {number} tableIndex\n * @returns {string} Hash signature\n */\n private _computeHash;\n /**\n * Add elements to the LSH index.\n * @param {T[]} elements\n * @returns {this}\n */\n add(elements: T[]): this;\n /**\n * Search for k approximate nearest neighbors.\n * @param {T} query\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search(query: T, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @param {number} i\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n}\nimport type { ParametersLSH } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport type { Metric } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\n//# sourceMappingURL=LSH.d.ts.map","/** @import { ParametersNaiveKNN } from \"./index.js\" */\n/**\n * Naive KNN implementation using a distance matrix.\n *\n * This implementation pre-computes the entire distance matrix and performs\n * an exhaustive search. Best suited for small datasets or when a distance\n * matrix is already available.\n *\n * @template {number[] | Float64Array} T\n * @category KNN\n * @class\n * @extends KNN\n */\nexport class NaiveKNN extends KNN {\n /**\n * Generates a KNN list with given `elements`.\n *\n * @param {T[]} elements - Elements which should be added to the KNN list\n * @param {ParametersNaiveKNN} parameters\n */\n constructor(elements: T[], parameters?: ParametersNaiveKNN);\n _D: Matrix;\n /** @type {Heap<{ value: number; index: number }>[]} */\n KNN: Heap<{\n value: number;\n index: number;\n }>[];\n /**\n * @param {number} i\n * @param {number} k\n */\n search_by_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @param {T} t - Query element.\n * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors.\n */\n search(t: T, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n}\nimport type { ParametersNaiveKNN } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { Heap } from \"../datastructure/index.js\";\n//# sourceMappingURL=NaiveKNN.d.ts.map","/** @import {ParametersNNDescent} from \"./index.js\" */\n/**\n *\n * @template {number[] | Float64Array} T\n * @typedef {Object} NNDescentElement\n * @property {T} value\n * @property {number} index\n * @property {boolean} flag\n */\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} NNDescentNeighbor\n * @property {T} value\n * @property {number} index\n * @property {number} distance\n * @property {boolean} [flag]\n */\n/**\n * NN-Descent\n *\n * An efficient graph-based approximate nearest neighbor search algorithm.\n * It works by iteratively improving a neighbor graph using the fact that\n * \"neighbors of neighbors are likely to be neighbors\".\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf|NN-Descent Paper}\n */\nexport class NNDescent extends KNN {\n /**\n * @param {T[]} elements - Called V in paper.\n * @param {Partial} parameters\n * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf}\n */\n constructor(elements: T[], parameters?: Partial);\n /**\n * @private\n * @type {KNNHeap[]}\n */\n private _B;\n /**\n * @private\n * @type {NNDescentNeighbor[][]}\n */\n private nn;\n _N: number;\n _randomizer: Randomizer;\n _sample_size: number;\n _nndescent_elements: {\n value: T;\n index: number;\n flag: boolean;\n }[];\n /**\n * Samples Array A with sample size.\n *\n * @private\n * @template U\n * @param {U[]} A\n * @returns {U[]}\n */\n private _sample;\n /**\n * @private\n * @param {KNNHeap} B\n * @param {NNDescentNeighbor} u\n * @returns {number}\n */\n private _update;\n /**\n * @private\n * @param {(KNNHeap | null)[]} B\n * @returns {NNDescentNeighbor[][]}\n */\n private _reverse;\n /**\n * @param {T[]} elements\n * @returns {this}\n */\n add(elements: T[]): this;\n /**\n * @param {T} x\n * @param {number} [k=5] Default is `5`\n * @returns {{ element: T, index: number; distance: number }[]}\n */\n search(x: T, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @param {number} i\n * @param {number} [k=5] Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n}\nexport type NNDescentElement = {\n value: T;\n index: number;\n flag: boolean;\n};\nexport type NNDescentNeighbor = {\n value: T;\n index: number;\n distance: number;\n flag?: boolean | undefined;\n};\nexport type HeapEntry = {\n element: NNDescentNeighbor;\n value: number;\n};\nimport type { ParametersNNDescent } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport { Randomizer } from \"../util/index.js\";\n//# sourceMappingURL=NNDescent.d.ts.map","export { Annoy } from \"./Annoy.js\";\nexport { BallTree } from \"./BallTree.js\";\nexport { HNSW } from \"./HNSW.js\";\nexport { KDTree } from \"./KDTree.js\";\nexport { LSH } from \"./LSH.js\";\nexport { NaiveKNN } from \"./NaiveKNN.js\";\nexport { NNDescent } from \"./NNDescent.js\";\nexport type ParametersAnnoy = {\n /**\n * - Metric to use: (a, b) => distance. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Number of random projection trees to build. Default is `10`\n */\n numTrees: number;\n /**\n * - Maximum points per leaf node. Default is `10`\n */\n maxPointsPerLeaf: number;\n /**\n * - Seed for random number generator. Default is `1212`\n */\n seed: number;\n};\nexport type ParametersBallTree = {\n metric: Metric;\n seed: number;\n};\nexport type ParametersHNSW = {\n /**\n * - Metric to use: (a, b) => distance. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Use heuristics or naive selection. Default is `true`\n */\n heuristic: boolean;\n /**\n * - Max number of connections per element (excluding ground layer). Default is `16`\n */\n m: number;\n /**\n * - Size of candidate list during construction. Default is `200`\n */\n ef_construction: number;\n /**\n * - Max number of connections for ground layer (layer 0). Default is `2 * m`\n */\n m0: number | null;\n /**\n * - Normalization factor for level generation. Default is `1 / Math.log(m)`\n */\n mL: number | null;\n /**\n * - Seed for random number generator. Default is `1212`\n */\n seed: number;\n /**\n * - Size of candidate list during search. Default is `50`\n */\n ef: number;\n};\nexport type ParametersKDTree = {\n /**\n * - Metric to use: (a, b) => distance. Default is `euclidean`\n */\n metric: Metric;\n seed: number;\n};\nexport type ParametersLSH = {\n /**\n * - Metric to use: (a, b) => distance. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Number of hash tables. Default is `10`\n */\n numHashTables: number;\n /**\n * - Number of hash functions per table. Default is `10`\n */\n numHashFunctions: number;\n /**\n * - Seed for random number generator. Default is `1212`\n */\n seed: number;\n};\nexport type ParametersNaiveKNN = {\n /**\n * Is either precomputed or a function to use: (a, b) => distance\n */\n metric?: Metric | \"precomputed\" | undefined;\n seed?: number | undefined;\n};\nexport type ParametersNNDescent = {\n /**\n * - Called sigma in paper. Default is `euclidean`\n */\n metric: Metric;\n /**\n * =10 - Number of samples. Default is `10`\n */\n samples: number;\n /**\n * = .8 - Sample rate. Default is `.8`\n */\n rho: number;\n /**\n * = 0.0001 - Precision parameter. Default is `0.0001`\n */\n delta: number;\n /**\n * = 1212 - Seed for the random number generator. Default is `1212`\n */\n seed: number;\n};\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=index.d.ts.map","/**\n * Numerical stable summation with the Kahan summation algorithm.\n *\n * @category Numerical\n * @param {number[] | Float64Array} summands - Array of values to sum up.\n * @returns {number} The sum.\n * @see {@link https://en.wikipedia.org/wiki/Kahan_summation_algorithm}\n */\nexport function kahan_sum(summands: number[] | Float64Array): number;\n//# sourceMappingURL=kahan_sum.d.ts.map","/**\n * Numerical stable summation with the Neumair summation algorithm.\n *\n * @category Numerical\n * @param {number[] | Float64Array} summands - Array of values to sum up.\n * @returns {number} The sum.\n * @see {@link https://en.wikipedia.org/wiki/Kahan_summation_algorithm#Further_enhancements}\n */\nexport function neumair_sum(summands: number[] | Float64Array): number;\n//# sourceMappingURL=neumair_sum.d.ts.map","/**\n * @template {Float64Array | number[]} T\n * @category Optimization\n * @param {(d: T) => number} f\n * @param {T} x0\n * @param {number} [max_iter=300] Default is `300`\n * @returns {T}\n * @see http://optimization-js.github.io/optimization-js/optimization.js.html#line438\n */\nexport function powell(f: (d: T) => number, x0: T, max_iter?: number): T;\n//# sourceMappingURL=powell.d.ts.map","export * from \"./clustering/index.js\";\nexport * from \"./datastructure/index.js\";\nexport * from \"./dimred/index.js\";\nexport * from \"./knn/index.js\";\nexport * from \"./linear_algebra/index.js\";\nexport * from \"./matrix/index.js\";\nexport * from \"./metrics/index.js\";\nexport * from \"./numerical/index.js\";\nexport * from \"./optimization/index.js\";\nexport * from \"./util/index.js\";\nexport type InputType = Matrix | Float64Array[] | number[][];\nexport const version: string;\nimport type { Matrix } from \"./matrix/index.js\";\n//# sourceMappingURL=index.d.ts.map"],"names":["___knn_KNN_js.KNN","___matrix_index_js.Matrix"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,WAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,QAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,SAAA,eAAA,YAAA,gBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,MAAA,eAAA,YAAA,gBAAA,YAAA;;ACbP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,SAAA,eAAA,YAAA,gBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACO,iBAAA,iBAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,eAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,OAAA,eAAA,YAAA,gBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,SAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,OAAA,eAAA,YAAA,gBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,SAAA,eAAA,YAAA,gBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACO,iBAAA,cAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,WAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,IAAA,eAAA,YAAA,gBAAA,YAAA;;ACMA,KAAA,MAAA,kBAAA,YAAA,gBAAA,YAAA;;ACdP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,eAAA,IAAA,MAAA,GAAA,YAAA,0BAAA,MAAA,GAAA,MAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,mBAAA,IAAA,MAAA,sBAAA,MAAA;AACP;AACA;AACA;AACA;;ACdA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,QAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,GAAA,SAAA,QAAA;;ACPP;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,GAAA,SAAA,QAAA;;ACPP;AACA;AACA;AACA;AACO,cAAA,UAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7DA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAA,MAAA,GAAA,YAAA,kBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,YAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qCAAA,YAAA,wBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAA,MAAA,KAAA,MAAA,eAAA,UAAA,wBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAA,MAAA;AACA,WAAA,MAAA;AACA,WAAA,MAAA;AACA,UAAA,MAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,MAAA;AACA,WAAA,MAAA;AACA,WAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,MAAA;AACA,WAAA,YAAA;AACA,eAAA,YAAA;AACA,WAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,4DAAA,YAAA,GAAA,YAAA;AACA;AACA;AACA;AACA;AACA,kDAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oDAAA,QAAA;AACA;AACA;AACA,uCAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAA,SAAA,CAAA,YAAA,CAAA,eAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2CAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wDAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wDAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wDAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAA,MAAA,cAAA,YAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAA,MAAA,cAAA,YAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAA,MAAA,cAAA,YAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAA,MAAA,8CAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yDAAA,MAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uGAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0DAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,YAAA,wCAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,YAAA,wCAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,MAAA,cAAA,YAAA,iDAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAA,MAAA,GAAA,YAAA;AACA;AACA,QAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,MAAA,GAAA,YAAA;AACA;AACA,QAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,MAAA,GAAA,YAAA;AACA;AACA,QAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,MAAA,GAAA,YAAA;AACA;AACA,QAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oDAAA,QAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,KAAA,MAAA,CAAA,QAAA,KAAA,SAAA,CAAA,YAAA,CAAA,eAAA;AACA;AACO,KAAA,QAAA;;ACjdP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,IAAA,IAAA,MAAA,cAAA,YAAA,WAAA,MAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,SAAA,eAAA,YAAA,WAAA,MAAA,cAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACO,cAAA,UAAA;AACP;AACA;AACA;AACA;AACA;AACA,wBAAA,SAAA;AACA;AACA,aAAA,SAAA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,IAAA,SAAA,UAAA,CAAA,cAAA;AACP;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,sBAAA,SAAA,UAAA,CAAA,gCAAA;AACP;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,gCAAA;AACA;AACA,UAAA,OAAA;AACA;AACA,YAAA,YAAA,CAAA,WAAA;AACA,sBAAA,MAAA;AACA;AACA,aAAA,WAAA,CAAA,WAAA;AACA;AACA;AACA;AACA;AACA;AACA,kEAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA;AACA,cAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,OAAA,gBAAA,OAAA,iCAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,OAAA;AACA;AACA,UAAA,OAAA;AACA,WAAA,OAAA;AACA;AACA;AACA,cAAA,YAAA,CAAA,eAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8BAAA,OAAA,SAAA,OAAA,GAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,cAAA,OAAA;AACA;AACA;AACA;AACA;AACA,mBAAA,OAAA;AACA;;AClGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,SAAA,UAAA,CAAA,gBAAA;AACP;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,gBAAA;AACA;AACA,iBAAA,UAAA;AACA;AACA;AACA,wBAAA,YAAA,CAAA,eAAA;AACA;AACA;AACA;AACA,qBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,QAAA,SAAA,UAAA,CAAA,kBAAA;AACP;AACA;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,kBAAA;AACA,QAAA,YAAA,CAAA,eAAA;AACA;AACA,sBAAA,MAAA;AACA,iBAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8CAAA,YAAA,eAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,SAAA,SAAA,UAAA,CAAA,mBAAA;AACP;AACA;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,mBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,SAAA,UAAA,CAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,SAAA,UAAA,CAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,gBAAA;AACA,iBAAA,UAAA;AACA;AACA,kBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7FO,KAAA,gCAAA;AACP;AACA,YAAA,MAAA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAA,YAAA,CAAA,eAAA;AACA;AACO,KAAA,kBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,mBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;;ACnIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,WAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAA,GAAA;AACA;;AC1CA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,IAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oGAAA,UAAA,GAAA,IAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6GAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAA,IAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvHO,KAAA,UAAA;;ACFP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,EAAA,WAAA,SAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAA,SAAA,2CAAA,SAAA,CAAA,SAAA,EAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAA,SAAA,2CAAA,OAAA,CAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6DAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAA,MAAA;AACA;AACA,OAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,EAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yCAAA,OAAA;AACA;;AC5IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,OAAA,WAAA,SAAA,UAAA,EAAA,IAAA,iBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,iBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,iBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,sBAAA,OAAA,CAAA,iBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,OAAA,CAAA,iBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;;AC3DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,WAAA,SAAA,UAAA,EAAA,IAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,gBAAA;AACA,cAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;;ACzDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,WAAA,SAAA,UAAA,EAAA,IAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA;AACA;AACA,kCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA;AACA;AACA,kCAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,OAAA,CAAA,aAAA;AACA,wBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,WAAA,SAAA,UAAA,EAAA,IAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,aAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,sBAAA,OAAA,CAAA,aAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,WAAA,SAAA,UAAA,EAAA,IAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA,YAAA,GAAA;AACA,QAAA,MAAA;AACA,QAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,IAAA,WAAA,SAAA,UAAA,EAAA,IAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,cAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,sBAAA,OAAA,CAAA,cAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,WAAA,SAAA,UAAA,EAAA,IAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAA,MAAA;AACA;AACA;AACA;;AC5DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,WAAA,SAAA,UAAA,EAAA,IAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,SAAA,sBAAA,OAAA,CAAA,aAAA,IAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAAA,MAAA;AACA,OAAA,MAAA;AACA;;AC5EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,WAAA,SAAA,UAAA,EAAA,IAAA,gBAAA,CAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,CAAA,aAAA,KAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,CAAA,aAAA,KAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,gBAAA,CAAA,aAAA;AACA;AACA,qBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA,4BAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,SAAA;AACA,aAAA,MAAA;AACA;AACO,KAAA,aAAA;AACA,KAAA,QAAA;AACP,SAAA,aAAA;AACA,SAAA,aAAA;AACA;AACA;;AC7EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,WAAA,SAAA,UAAA,EAAA,IAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;;ACpDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,WAAA,SAAA,UAAA,EAAA,IAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,gBAAA;AACA;AACA,yBAAA,YAAA,CAAA,eAAA,QAAA,YAAA;AACA,mBAAA,YAAA,CAAA,eAAA,MAAA,YAAA,CAAA,eAAA,mBAAA,YAAA;AACA,iBAAA,YAAA,CAAA,eAAA,MAAA,YAAA,CAAA,eAAA,MAAA,YAAA;AACA,gBAAA,YAAA,CAAA,eAAA,iBAAA,YAAA;AACA;AACA;AACA;AACA,gBAAA,MAAA;AACA,YAAA,MAAA;AACA;AACA;AACA,2CAAA,MAAA;AACA;AACA,wDAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAA,MAAA,SAAA,MAAA,gDAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAAA,YAAA,CAAA,eAAA,MAAA,YAAA,CAAA,eAAA,MAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAA,YAAA,CAAA,eAAA,QAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,2BAAA,YAAA,CAAA,eAAA,iBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,8BAAA,YAAA,CAAA,eAAA,MAAA,YAAA,CAAA,eAAA,mBAAA,YAAA;AACA;;ACjKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,OAAA,WAAA,SAAA,UAAA,EAAA,IAAA,iBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,iBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,iBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,sBAAA,OAAA,CAAA,iBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,OAAA,CAAA,iBAAA;AACA,sBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAA,WAAA,CAAA,YAAA,CAAA,eAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;;AC3IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,sBAAA,YAAA,eAAA,MAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,WAAA,SAAA,UAAA,EAAA,IAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA,eAAA,MAAA,eAAoCA,GAAuB,YAAA,YAAA;AAC3D;AACA;AACA;AACA,SAAA,GAAA,YAAA,YAAA,CAAA,eAAA;AACA,cAAA,MAAA;AACA,aAAA,YAAA,CAAA,WAAA;AACA;AACA;AACA,SAAA,MAAA;AACA,UAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,MAAA;AACA,iBAAA,YAAA,CAAA,WAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA,cAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,IAAA,WAAA,SAAA,UAAA,EAAA,IAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,cAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,cAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA,YAAA,MAAA;AACA,YAAA,MAAA;AACA,QAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,IAAA,WAAA,SAAA,UAAA,EAAA,IAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,cAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,cAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,IAAA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA,wBAAA,YAAA,CAAA,eAAA;AACA,iCAAA,YAAA,CAAA,WAAA;AACA,2BAAA,YAAA,CAAA,WAAA;AACA,oCAAA,YAAA,CAAA,WAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,aAAA,eAAA,YAAA,gBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,EAAA,IAAA,MAAA;AACP,OAAA,MAAA;AACA,OAAA,MAAA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,cAAA,IAAA,MAAA;AACP,OAAA,MAAA;AACA,OAAA,MAAA;AACA;;ACZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,2BAAA,IAAA,MAAA,kDAAA,SAAA;AACP,iBAAA,YAAA;AACA,kBAAA,YAAA;AACA;;ACXO,KAAA,eAAA,OAA2BC,MAA4B;AAC9D,OAAOA,MAA4B;AACnC,OAAOA,MAA4B;AACnC;AACO,KAAA,SAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAA,UAAA;AACA;AACA;AACA;AACA,SAAA,eAAA;AACA;AACA;AACA;AACA;AACA;;ACVO,KAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,iBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,OAAA,CAAA,SAAA;AACA;AACO,KAAA,aAAA;AACP;AACA;AACA;AACA,oBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,OAAA,CAAA,SAAA;AACA;AACO,KAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,OAAA,CAAA,SAAA;AACA;AACO,KAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,OAAA,CAAA,SAAA;AACA;AACO,KAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,OAAA,CAAA,SAAA;AACA;AACO,KAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,OAAA,CAAA,SAAA;AACA;AACO,KAAA,gBAAA,iBAAA,QAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAA,QAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,gBAAA;AACP;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,iBAAA;AACP;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5VA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,KAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,eAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,eAAA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA,iBAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,QAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,kBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,kBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,IAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,0CAAA,cAAA;AACA;AACA,aAAA,MAAA;AACA;AACA,aAAA,QAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAA,IAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAAA,IAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sDAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,SAAA;AACA;AAeO,KAAA,SAAA,sBAAA,YAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,aAAA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA,iBAAA,UAAA;AACA;AACA,iBAAA,GAAA;AACA;AACA,kBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,QAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,kBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,kBAAA;AACA,QAAA,MAAA;AACA;AACA,SAAA,IAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,SAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,mBAAA;AACP;AACA;AACA;AACA;AACA;AACA,4CAAA,OAAA,CAAA,mBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/FO,KAAA,eAAA;AACP;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,kBAAA;AACP,YAAA,MAAA;AACA;AACA;AACO,KAAA,cAAA;AACP;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACO,KAAA,aAAA;AACP;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,kBAAA;AACP;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACO,KAAA,mBAAA;AACP;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,SAAA,sBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,WAAA,sBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,MAAA,WAAA,YAAA;;ACCA,KAAA,SAAA,GAAA,MAAA,GAAA,YAAA;AACA,cAAA,OAAA;;;;"} \ No newline at end of file +{"version":3,"file":"druid.d.cts","sources":["types/metrics/bray_curtis.d.ts","types/metrics/canberra.d.ts","types/metrics/chebyshev.d.ts","types/metrics/cosine.d.ts","types/metrics/euclidean.d.ts","types/metrics/euclidean_squared.d.ts","types/metrics/goodman_kruskal.d.ts","types/metrics/hamming.d.ts","types/metrics/haversine.d.ts","types/metrics/jaccard.d.ts","types/metrics/manhattan.d.ts","types/metrics/sokal_michener.d.ts","types/metrics/wasserstein.d.ts","types/metrics/yule.d.ts","types/metrics/index.d.ts","types/matrix/distance_matrix.d.ts","types/matrix/k_nearest_neighbors.d.ts","types/matrix/linspace.d.ts","types/util/max.d.ts","types/util/min.d.ts","types/util/randomizer.d.ts","types/matrix/Matrix.d.ts","types/matrix/norm.d.ts","types/matrix/normalize.d.ts","types/clustering/Clustering.d.ts","types/clustering/CURE.d.ts","types/clustering/Hierarchical_Clustering.d.ts","types/clustering/KMeans.d.ts","types/clustering/KMedoids.d.ts","types/clustering/MeanShift.d.ts","types/clustering/OPTICS.d.ts","types/clustering/XMeans.d.ts","types/clustering/index.d.ts","types/datastructure/DisjointSet.d.ts","types/datastructure/Heap.d.ts","types/datastructure/index.d.ts","types/dimred/DR.d.ts","types/dimred/FASTMAP.d.ts","types/dimred/PaCMAP.d.ts","types/dimred/LocalMAP.d.ts","types/dimred/ISOMAP.d.ts","types/dimred/LDA.d.ts","types/dimred/LLE.d.ts","types/dimred/LSP.d.ts","types/dimred/LTSA.d.ts","types/dimred/MDS.d.ts","types/dimred/PCA.d.ts","types/dimred/SAMMON.d.ts","types/dimred/SMACOF.d.ts","types/dimred/SQDMDS.d.ts","types/dimred/TopoMap.d.ts","types/knn/KNN.d.ts","types/dimred/TriMap.d.ts","types/dimred/TSNE.d.ts","types/dimred/UMAP.d.ts","types/linear_algebra/inner_product.d.ts","types/linear_algebra/qr.d.ts","types/linear_algebra/qr_householder.d.ts","types/linear_algebra/simultaneous_poweriteration.d.ts","types/linear_algebra/index.d.ts","types/dimred/index.d.ts","types/knn/Annoy.d.ts","types/knn/BallTree.d.ts","types/knn/HNSW.d.ts","types/knn/KDTree.d.ts","types/knn/LSH.d.ts","types/knn/NaiveKNN.d.ts","types/knn/NNDescent.d.ts","types/knn/index.d.ts","types/numerical/kahan_sum.d.ts","types/numerical/neumair_sum.d.ts","types/optimization/powell.d.ts","types/index.d.ts"],"sourcesContent":["/**\n * Computes the Bray-Curtis distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The Bray-Curtis distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Bray%E2%80%93Curtis_dissimilarity}\n */\nexport function bray_curtis(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=bray_curtis.d.ts.map","/**\n * Computes the canberra distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The canberra distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Canberra_distance}\n */\nexport function canberra(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=canberra.d.ts.map","/**\n * Computes the chebyshev distance (L) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The chebyshev distance between `a` and `b`.\n */\nexport function chebyshev(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=chebyshev.d.ts.map","/**\n * Computes the cosine distance (not similarity) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The cosine distance between `a` and `b`.\n * @example\n * import { cosine } from \"@saehrimnir/druidjs\";\n * const a = [1, 2, 3];\n * const b = [4, 5, 6];\n * const distance = cosine(a, b); // 0.9746318461970762\n */\nexport function cosine(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=cosine.d.ts.map","/**\n * Computes the euclidean distance (`l_2`) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The euclidean distance between `a` and `b`.\n */\nexport function euclidean(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=euclidean.d.ts.map","/**\n * Computes the squared euclidean distance (l_2^2) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The squared euclidean distance between `a` and `b`.\n\n */\nexport function euclidean_squared(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=euclidean_squared.d.ts.map","/**\n * Computes the Goodman-Kruskal gamma coefficient for ordinal association.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a - First categorical/ordinal variable\n * @param {number[] | Float64Array} b - Second categorical/ordinal variable\n * @returns {number} The Goodman-Kruskal gamma coefficient between `a` and `b` (-1 to 1).\n * @see {@link https://en.wikipedia.org/wiki/Goodman_and_Kruskal%27s_gamma}\n */\nexport function goodman_kruskal(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=goodman_kruskal.d.ts.map","/**\n * Computes the hamming distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The hamming distance between `a` and `b`.\n */\nexport function hamming(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=hamming.d.ts.map","/**\n * Computes the Haversine distance between two points on a sphere of unit length 1. Multiply the result with the radius of the sphere. (For instance Earth's radius is 6371km)\n *\n * @category Metrics\n * @param {number[] | Float64Array} a - Point [lat1, lon1] in radians\n * @param {number[] | Float64Array} b - Point [lat2, lon2] in radians\n * @returns {number} The Haversine distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Haversine_formula}\n */\nexport function haversine(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=haversine.d.ts.map","/**\n * Computes the jaccard distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The jaccard distance between `a` and `b`.\n */\nexport function jaccard(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=jaccard.d.ts.map","/**\n * Computes the manhattan distance (`l_1`) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The manhattan distance between `a` and `b`.\n */\nexport function manhattan(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=manhattan.d.ts.map","/**\n * Computes the Sokal-Michener distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The Sokal-Michener distance between `a` and `b`.\n\n */\nexport function sokal_michener(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=sokal_michener.d.ts.map","/**\n * Computes the 1D Wasserstein distance (Earth Mover's Distance) between two distributions.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a - First distribution (histogram or probability mass)\n * @param {number[] | Float64Array} b - Second distribution (histogram or probability mass)\n * @returns {number} The Wasserstein/EMD distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Wasserstein_metric}\n */\nexport function wasserstein(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=wasserstein.d.ts.map","/**\n * Computes the yule distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The yule distance between `a` and `b`.\n */\nexport function yule(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=yule.d.ts.map","export { bray_curtis } from \"./bray_curtis.js\";\nexport { canberra } from \"./canberra.js\";\nexport { chebyshev } from \"./chebyshev.js\";\nexport { cosine } from \"./cosine.js\";\nexport { euclidean } from \"./euclidean.js\";\nexport { euclidean_squared } from \"./euclidean_squared.js\";\nexport { goodman_kruskal } from \"./goodman_kruskal.js\";\nexport { hamming } from \"./hamming.js\";\nexport { haversine } from \"./haversine.js\";\nexport { jaccard } from \"./jaccard.js\";\nexport { manhattan } from \"./manhattan.js\";\nexport { sokal_michener } from \"./sokal_michener.js\";\nexport { wasserstein } from \"./wasserstein.js\";\nexport { yule } from \"./yule.js\";\nexport type Metric = (a: number[] | Float64Array, b: number[] | Float64Array) => number;\n//# sourceMappingURL=index.d.ts.map","/**\n * Computes the distance matrix of datamatrix `A`.\n *\n * @category Matrix\n * @param {Matrix | Float64Array[] | number[][]} A - Matrix.\n * @param {Metric} [metric=euclidean] - The diistance metric. Default is `euclidean`\n * @returns {Matrix} The distance matrix of `A`.\n */\nexport function distance_matrix(A: Matrix | Float64Array[] | number[][], metric?: Metric): Matrix;\nimport { Matrix } from \"./index.js\";\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=distance_matrix.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/**\n * Computes the k-nearest neighbors of each row of `A`.\n *\n * @category Matrix\n * @param {Matrix} A - Either the data matrix, or a distance matrix.\n * @param {number} k - The number of neighbors to compute.\n * @param {Metric | \"precomputed\"} [metric=euclidean] Default is `euclidean`\n * @returns {{ i: number; j: number; distance: number }[][]} The kNN graph.\n */\nexport function k_nearest_neighbors(A: Matrix, k: number, metric?: Metric | \"precomputed\"): {\n i: number;\n j: number;\n distance: number;\n}[][];\nimport { Matrix } from \"../matrix/index.js\";\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=k_nearest_neighbors.d.ts.map","/**\n * Creates an Array containing `number` numbers from `start` to `end`. If `number = null`.\n *\n * @category Matrix\n * @param {number} start - Start value.\n * @param {number} end - End value.\n * @param {number} [number] - Number of number between `start` and `end`.\n * @returns {number[]} An array with `number` entries, beginning at `start` ending at `end`.\n */\nexport function linspace(start: number, end: number, number?: number): number[];\n//# sourceMappingURL=linspace.d.ts.map","/**\n * Returns maximum in Array `values`.\n *\n * @category Utils\n * @param {Iterable} values\n * @returns {number}\n */\nexport function max(values: Iterable): number;\n//# sourceMappingURL=max.d.ts.map","/**\n * Returns maximum in Array `values`.\n *\n * @category Utils\n * @param {Iterable} values\n * @returns {number}\n */\nexport function min(values: Iterable): number;\n//# sourceMappingURL=min.d.ts.map","/**\n * @category Utils\n * @class\n */\nexport class Randomizer {\n /**\n * @template T Returns samples from an input Matrix or Array.\n * @param {T[]} A - The input Matrix or Array.\n * @param {number} n - The number of samples.\n * @param {number} seed - The seed for the random number generator.\n * @returns {T[]} - A random selection form `A` of `n` samples.\n */\n static choice(A: T[], n: number, seed?: number): T[];\n /**\n * Mersenne Twister random number generator.\n *\n * @param {number} [_seed=new Date().getTime()] - The seed for the random number generator. If `_seed == null` then\n * the actual time gets used as seed. Default is `new Date().getTime()`\n * @see https://github.com/bmurray7/mersenne-twister-examples/blob/master/javascript-mersenne-twister.js\n */\n constructor(_seed?: number);\n _N: number;\n _M: number;\n _MATRIX_A: number;\n _UPPER_MASK: number;\n _LOWER_MASK: number;\n /** @type {number[]} */\n _mt: number[];\n /** @type {number} */\n _mti: number;\n /** @type {number} */\n _seed: number;\n /** @type {number} seed */\n set seed(_seed: number);\n /**\n * Returns the seed of the random number generator.\n *\n * @returns {number} - The seed.\n */\n get seed(): number;\n /**\n * Returns a float between 0 and 1.\n *\n * @returns {number} - A random number between [0, 1]\n */\n get random(): number;\n /**\n * Returns an integer between 0 and MAX_INTEGER.\n *\n * @returns {number} - A random integer.\n */\n get random_int(): number;\n gauss_random(): number;\n _val: number | null | undefined;\n /**\n * @template T Returns samples from an input Matrix or Array.\n * @param {T[]} A - The input Matrix or Array.\n * @param {number} n - The number of samples.\n * @returns {T[]} A random selection form `A` of `n` samples.\n */\n choice(A: T[], n: number): T[];\n}\n//# sourceMappingURL=randomizer.d.ts.map","/** @typedef {(i: number, j: number) => number} Accessor */\n/**\n * @class\n * @category Matrix\n */\nexport class Matrix {\n /**\n * Creates a Matrix out of `A`.\n * @param {Matrix | Float64Array[] | number[][]} A - The matrix, array, or number, which should converted to a Matrix.\n * @returns {Matrix}\n * @example\n * let A = Matrix.from([ [1, 0], [0, 1], ]); //creates a two by two identity matrix.\n */\n static from(A: Matrix | Float64Array[] | number[][]): Matrix;\n /**\n * Creates a Matrix with the diagonal being the values of `v`.\n *\n * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]]\n *\n * @param {number[] | Float64Array} v\n * @returns {Matrix}\n */\n static from_diag(v: number[] | Float64Array): Matrix;\n /**\n * Creates a Matrix with the diagonal being the values of `v`.\n *\n * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]]\n *\n * @param {number[] | Float64Array} v\n * @param {\"col\" | \"row\"} type\n * @returns {Matrix}\n */\n static from_vector(v: number[] | Float64Array, type: \"col\" | \"row\"): Matrix;\n /**\n * Solves the equation `Ax = b` using the conjugate gradient method. Returns the result `x`.\n *\n * @param {Matrix} A - Matrix\n * @param {Matrix} b - Matrix\n * @param {Randomizer | null} [randomizer]\n * @param {number} [tol=1e-3] Default is `1e-3`\n * @returns {Matrix}\n */\n static solve_CG(A: Matrix, b: Matrix, randomizer?: Randomizer | null, tol?: number): Matrix;\n /**\n * Solves the equation `Ax = b`. Returns the result `x`.\n *\n * @param {Matrix | { L: Matrix; U: Matrix }} A - Matrix or LU Decomposition\n * @param {Matrix} b - Matrix\n * @returns {Matrix}\n */\n static solve(A: Matrix | {\n L: Matrix;\n U: Matrix;\n }, b: Matrix): Matrix;\n /**\n * `LU` decomposition of the Matrix `A`. Creates two matrices, so that the dot product `LU` equals `A`.\n *\n * @param {Matrix} A\n * @returns {{ L: Matrix; U: Matrix }} The left triangle matrix `L` and the upper triangle matrix `U`.\n */\n static LU(A: Matrix): {\n L: Matrix;\n U: Matrix;\n };\n /**\n * Computes the determinante of `A`, by using the `LU` decomposition of `A`.\n *\n * @param {Matrix} A\n * @returns {number} The determinate of the Matrix `A`.\n */\n static det(A: Matrix): number;\n /**\n * Computes the `k` components of the SVD decomposition of the matrix `M`.\n *\n * @param {Matrix} M\n * @param {number} [k=2] Default is `2`\n * @returns {{ U: Float64Array[]; Sigma: Float64Array; V: Float64Array[] }}\n */\n static SVD(M: Matrix, k?: number): {\n U: Float64Array[];\n Sigma: Float64Array;\n V: Float64Array[];\n };\n /**\n * @param {unknown} A\n * @returns {A is unknown[]|number[]|Float64Array|Float32Array}\n */\n static isArray(A: unknown): A is unknown[] | number[] | Float64Array | Float32Array;\n /**\n * @param {any[]} A\n * @returns {A is number[][]|Float64Array[]}\n */\n static is2dArray(A: any[]): A is number[][] | Float64Array[];\n /**\n * Creates a new Matrix. Entries are stored in a Float64Array.\n *\n * @example let A = new Matrix(10, 10, () => Math.random()); //creates a 10 times 10 random matrix. let B = new\n * Matrix(3, 3, \"I\"); // creates a 3 times 3 identity matrix.\n *\n * @param {number} rows - The amount of rows of the matrix.\n * @param {number} cols - The amount of columns of the matrix.\n * @param {Accessor | string | number} value - Can be a function with row and col as parameters, a number, or\n * \"zeros\", \"identity\" or \"I\", or \"center\".\n *\n * - **function**: for each entry the function gets called with the parameters for the actual row and column.\n * - **string**: allowed are\n *\n * - \"zero\", creates a zero matrix.\n * - \"identity\" or \"I\", creates an identity matrix.\n * - \"center\", creates an center matrix.\n * - **number**: create a matrix filled with the given value.\n */\n constructor(rows: number, cols: number, value?: Accessor | string | number);\n /** @type {number} */ _rows: number;\n /** @type {number} */ _cols: number;\n /** @type {Float64Array} */ _data: Float64Array;\n /**\n * Returns the `row`th row from the Matrix.\n *\n * @param {number} row\n * @returns {Float64Array}\n */\n row(row: number): Float64Array;\n /**\n * Returns an generator yielding each row of the Matrix.\n *\n * @yields {Float64Array}\n */\n iterate_rows(): Generator, void, unknown>;\n /**\n * Sets the entries of `row`th row from the Matrix to the entries from `values`.\n *\n * @param {number} row\n * @param {number[]} values\n * @returns {Matrix}\n */\n set_row(row: number, values: number[]): Matrix;\n /**\n * Swaps the rows `row1` and `row2` of the Matrix.\n *\n * @param {number} row1\n * @param {number} row2\n * @returns {Matrix}\n */\n swap_rows(row1: number, row2: number): Matrix;\n /**\n * Returns the colth column from the Matrix.\n *\n * @param {number} col\n * @returns {Float64Array}\n */\n col(col: number): Float64Array;\n /**\n * Returns the `col`th entry from the `row`th row of the Matrix.\n *\n * @param {number} row\n * @param {number} col\n * @returns {number}\n */\n entry(row: number, col: number): number;\n /**\n * Sets the {@link col}th entry from the {@link row}th row of the Matrix to the given\n * {@link value}.\n *\n * @param {number} row\n * @param {number} col\n * @param {number} value\n * @returns {Matrix}\n */\n set_entry(row: number, col: number, value: number): Matrix;\n /**\n * Adds a given {@link value} to the {@link col}th entry from the {@link row}th row of the\n * Matrix.\n *\n * @param {number} row\n * @param {number} col\n * @param {number} value\n * @returns {Matrix}\n */\n add_entry(row: number, col: number, value: number): Matrix;\n /**\n * Subtracts a given {@link value} from the {@link col}th entry from the {@link row}th row of the\n * Matrix.\n *\n * @param {number} row\n * @param {number} col\n * @param {number} value\n * @returns {Matrix}\n */\n sub_entry(row: number, col: number, value: number): Matrix;\n /**\n * Returns a new transposed Matrix.\n *\n * @returns {Matrix}\n */\n transpose(): Matrix;\n /**\n * Returns a new transposed Matrix. Short-form of `transpose`.\n *\n * @returns {Matrix}\n */\n get T(): Matrix;\n /**\n * Returns the inverse of the Matrix.\n *\n * @returns {Matrix}\n */\n inverse(): Matrix;\n /**\n * Returns the dot product. If `B` is an Array or Float64Array then an Array gets returned. If `B` is a Matrix then\n * a Matrix gets returned.\n *\n * @param {Matrix | number[] | Float64Array} B The right side\n * @returns {Matrix}\n */\n dot(B: Matrix | number[] | Float64Array): Matrix;\n /**\n * Transposes the current matrix and returns the dot product with `B`. If `B` is an Array or Float64Array then an\n * Array gets returned. If `B` is a Matrix then a Matrix gets returned.\n *\n * @param {Matrix | number[] | Float64Array} B The right side\n * @returns {Matrix}\n */\n transDot(B: Matrix | number[] | Float64Array): Matrix;\n /**\n * Returns the dot product with the transposed version of `B`. If `B` is an Array or Float64Array then an Array gets\n * returned. If `B` is a Matrix then a Matrix gets returned.\n *\n * @param {Matrix | number[] | Float64Array} B The right side\n * @returns {Matrix}\n */\n dotTrans(B: Matrix | number[] | Float64Array): Matrix;\n /**\n * Computes the outer product from `this` and `B`.\n *\n * @param {Matrix} B\n * @returns {Matrix}\n */\n outer(B: Matrix): Matrix;\n /**\n * Appends matrix `B` to the matrix.\n *\n * @example let A = Matrix.from([ [1, 1], [1, 1], ]); // 2 by 2 matrix filled with ones. let B = Matrix.from([ [2,\n * 2], [2, 2], ]); // 2 by 2 matrix filled with twos.\n *\n * A.concat(B, \"horizontal\"); // 2 by 4 matrix. [[1, 1, 2, 2], [1, 1, 2, 2]]\n * A.concat(B, \"vertical\"); // 4 by 2 matrix. [[1, 1], [1, 1], [2, 2], [2, 2]]\n * A.concat(B, \"diag\"); // 4 by 4 matrix. [[1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 2, 2], [0, 0, 2, 2]]\n *\n * @param {Matrix} B - Matrix to append.\n * @param {\"horizontal\" | \"vertical\" | \"diag\"} [type=\"horizontal\"] - Type of concatenation. Default is\n * `\"horizontal\"`\n * @returns {Matrix}\n */\n concat(B: Matrix, type?: \"horizontal\" | \"vertical\" | \"diag\"): Matrix;\n /**\n * Writes the entries of B in A at an offset position given by `offset_row` and `offset_col`.\n *\n * @param {number} offset_row\n * @param {number} offset_col\n * @param {Matrix} B\n * @returns {Matrix}\n */\n set_block(offset_row: number, offset_col: number, B: Matrix): Matrix;\n /**\n * Extracts the entries from the `start_row`th row to the `end_row`th row, the\n * `start_col`th column to the `end_col`th column of the matrix. If `end_row` or `end_col` is\n * empty, the respective value is set to `this.rows` or `this.cols`.\n *\n * @example let A = Matrix.from([ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]); // a 3 by 3 matrix.\n *\n * A.get_block(1, 1); // [[5, 6], [8, 9]]\n * A.get_block(0, 0, 1, 1); // [[1]]\n * A.get_block(1, 1, 2, 2); // [[5]]\n * A.get_block(0, 0, 2, 2); // [[1, 2], [4, 5]]\n *\n * @param {number} start_row\n * @param {number} start_col\n * @param {number | null} [end_row]\n * @param {number | null} [end_col]\n * @returns {Matrix} Returns a `end_row` - `start_row` times `end_col` - `start_col` matrix, with respective entries\n * from the matrix.\n */\n get_block(start_row: number, start_col: number, end_row?: number | null, end_col?: number | null): Matrix;\n /**\n * Returns a new array gathering entries defined by the indices given by argument.\n *\n * @param {number[]} row_indices - Array consists of indices of rows for gathering entries of this matrix\n * @param {number[]} col_indices - Array consists of indices of cols for gathering entries of this matrix\n * @returns {Matrix}\n */\n gather(row_indices: number[], col_indices: number[]): Matrix;\n /**\n * Applies a function to each entry of the matrix.\n *\n * @private\n * @param {(d: number, v: number) => number} f Function takes 2 parameters, the value of the actual entry and a\n * value given by the function `v`. The result of `f` gets writen to the Matrix.\n * @param {Accessor} v Function takes 2 parameters for `row` and `col`, and returns a value witch should be applied\n * to the `col`th entry of the `row`th row of the matrix.\n * @returns {Matrix}\n */\n private _apply_array;\n /**\n * @param {number[] | Float64Array} values\n * @param {(d: number, v: number) => number} f\n * @returns {Matrix}\n */\n _apply_rowwise_array(values: number[] | Float64Array, f: (d: number, v: number) => number): Matrix;\n /**\n * @param {number[] | Float64Array} values\n * @param {(d: number, v: number) => number} f\n * @returns {Matrix}\n */\n _apply_colwise_array(values: number[] | Float64Array, f: (d: number, v: number) => number): Matrix;\n /**\n * @param {Matrix | number[] | Float64Array | number} value\n * @param {(d: number, v: number) => number} f\n * @returns {Matrix}\n */\n _apply(value: Matrix | number[] | Float64Array | number, f: (d: number, v: number) => number): Matrix;\n /**\n * Clones the Matrix.\n *\n * @returns {Matrix}\n */\n clone(): Matrix;\n /**\n * Entrywise multiplication with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.mult(2); // [[2, 4], [6, 8]];\n * A.mult(B); // [[1, 4], [9, 16]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {boolean} [options.inline=false] - If true, applies multiplication to the element, otherwise it creates\n * first a copy and applies the multiplication on the copy. Default is `false`\n * @returns {Matrix}\n */\n mult(value: Matrix | Float64Array | number[] | number, { inline }?: {\n inline?: boolean | undefined;\n }): Matrix;\n /**\n * Entrywise division with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.divide(2); // [[0.5, 1], [1.5, 2]];\n * A.divide(B); // [[1, 1], [1, 1]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {Boolean} [options.inline=false] - If true, applies division to the element, otherwise it creates first a\n * copy and applies the division on the copy. Default is `false`\n * @returns {Matrix}\n */\n divide(value: Matrix | Float64Array | number[] | number, { inline }?: {\n inline?: boolean | undefined;\n }): Matrix;\n /**\n * Entrywise addition with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.add(2); // [[3, 4], [5, 6]];\n * A.add(B); // [[2, 4], [6, 8]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {boolean} [options.inline=false] - If true, applies addition to the element, otherwise it creates first a\n * copy and applies the addition on the copy. Default is `false`\n * @returns {Matrix}\n */\n add(value: Matrix | Float64Array | number[] | number, { inline }?: {\n inline?: boolean | undefined;\n }): Matrix;\n /**\n * Entrywise subtraction with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.sub(2); // [[-1, 0], [1, 2]];\n * A.sub(B); // [[0, 0], [0, 0]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {boolean} [options.inline=false] - If true, applies subtraction to the element, otherwise it creates first\n * a copy and applies the subtraction on the copy. Default is `false`\n * @returns {Matrix}\n */\n sub(value: Matrix | Float64Array | number[] | number, { inline }?: {\n inline?: boolean | undefined;\n }): Matrix;\n /**\n * Returns the matrix in the given shape with the given function which returns values for the entries of the matrix.\n *\n * @param {[number, number, Accessor]} parameter - Takes an Array in the form [rows, cols, value], where rows and\n * cols are the number of rows and columns of the matrix, and value is a function which takes two parameters (row\n * and col) which has to return a value for the colth entry of the rowth row.\n * @returns {Matrix}\n */\n set shape([rows, cols, value]: [number, number, Accessor]);\n /**\n * Returns the number of rows and columns of the Matrix.\n *\n * @returns {number[]} An Array in the form [rows, columns].\n */\n get shape(): number[];\n /**\n * Returns the Matrix as a Array of Float64Arrays.\n *\n * @returns {Float64Array[]}\n */\n to2dArray(): Float64Array[];\n /**\n * Returns the Matrix as a Array of Arrays.\n *\n * @returns {number[][]}\n */\n asArray(): number[][];\n /**\n * Returns the diagonal of the Matrix.\n *\n * @returns {Float64Array}\n */\n diag(): Float64Array;\n /**\n * Returns the mean of all entries of the Matrix.\n *\n * @returns {number}\n */\n mean(): number;\n /**\n * Returns the sum oof all entries of the Matrix.\n *\n * @returns {number}\n */\n sum(): number;\n /**\n * Returns the entries of the Matrix.\n *\n * @returns {Float64Array}\n */\n get values(): Float64Array;\n /**\n * Returns the mean of each row of the matrix.\n *\n * @returns {Float64Array}\n */\n meanRows(): Float64Array;\n /**\n * Returns the mean of each column of the matrix.\n *\n * @returns {Float64Array}\n */\n meanCols(): Float64Array;\n /**\n * Makes a `Matrix` object an iterable object.\n *\n * @yields {Float64Array}\n */\n [Symbol.iterator](): Generator, void, unknown>;\n}\nexport type Accessor = (i: number, j: number) => number;\nimport { Randomizer } from \"../util/index.js\";\n//# sourceMappingURL=Matrix.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/**\n * Computes the norm of a vector, by computing its distance to **0**.\n *\n * @category Matrix\n * @param {Matrix | number[] | Float64Array} v - Vector.\n * @param {Metric} [metric=euclidean] - Which metric should be used to compute the norm. Default is `euclidean`\n * @returns {number} - The norm of `v`.\n */\nexport function norm(v: Matrix | number[] | Float64Array, metric?: Metric): number;\nimport { Matrix } from \"../matrix/index.js\";\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=norm.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/**\n * Normalizes Vector `v`.\n *\n * @category Matrix\n * @param {number[] | Float64Array} v - Vector\n * @param {Metric} metric\n * @returns {number[] | Float64Array} - The normalized vector with length 1.\n */\nexport function normalize(v: number[] | Float64Array, metric?: Metric): number[] | Float64Array;\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=normalize.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/**\n * Base class for all clustering algorithms.\n * @template Para\n */\nexport class Clustering {\n /**\n * Compute the respective Clustering with given parameters\n * @param {InputType} points\n * @param {Para} parameters\n */\n constructor(points: InputType, parameters: Para);\n /** @type {InputType} */\n _points: InputType;\n /** @type {Para} */\n _parameters: Para;\n /** @type {Matrix} */\n _matrix: Matrix;\n /** @type {number} */\n _N: number;\n /** @type {number} */\n _D: number;\n /**\n * @abstract\n * @param {...unknown} args\n * @returns {number[][]} An array with the indices of the clusters.\n */\n get_clusters(...args: unknown[]): number[][];\n /**\n * @abstract\n * @param {...unknown} args\n * @returns {number[]} An array with the clusters id's for each point.\n */\n get_cluster_list(...args: unknown[]): number[];\n}\nimport type { InputType } from \"../index.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=Clustering.d.ts.map","/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersCURE } from \"./index.js\" */\n/**\n * CURE (Clustering Using REpresentatives)\n *\n * An efficient clustering algorithm for large databases that is robust to outliers\n * and identifies clusters with non-spherical shapes and wide variances in size.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class CURE extends Clustering {\n /**\n * @param {InputType} points\n * @param {Partial} parameters\n */\n constructor(points: InputType, parameters?: Partial);\n /** @type {number} */\n _K: number;\n /** @type {number} */\n _num_representatives: number;\n /** @type {number} */\n _shrink_factor: number;\n /**\n * @private\n * @type {CURECluster[]}\n */\n private _clusters;\n /** @type {number[]} */\n _cluster_ids: number[];\n /**\n * Initialize each point as its own cluster\n * @private\n */\n private _initialize_clusters;\n /**\n * Compute distance between two clusters using representative points\n * @private\n * @param {CURECluster} cluster1\n * @param {CURECluster} cluster2\n * @returns {number}\n */\n private _cluster_distance;\n /**\n * Find the closest pair of clusters\n * @private\n * @returns {[number, number, number]} [index1, index2, distance]\n */\n private _find_closest_clusters;\n /**\n * Merge two clusters\n * @private\n * @param {CURECluster} cluster1\n * @param {CURECluster} cluster2\n * @returns {CURECluster}\n */\n private _merge_clusters;\n /**\n * Run CURE clustering algorithm\n * @private\n */\n private _cure;\n /**\n * Build the cluster list (point -> cluster assignment)\n * @private\n */\n private _build_cluster_ids;\n /**\n * @returns {number[][]}\n */\n get_clusters(): number[][];\n /**\n * @returns {number[]}\n */\n get_cluster_list(): number[];\n}\nimport type { ParametersCURE } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport type { InputType } from \"../index.js\";\n//# sourceMappingURL=CURE.d.ts.map","/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersHierarchicalClustering } from \"./index.js\" */\n/**\n * Hierarchical Clustering\n *\n * A bottom-up approach (agglomerative) to clustering that builds a tree of clusters (dendrogram).\n * Supports different linkage criteria: single, complete, and average.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class HierarchicalClustering extends Clustering {\n /**\n * @param {InputType} points - Data or distance matrix if metric is 'precomputed'\n * @param {Partial} parameters\n */\n constructor(points: InputType, parameters?: Partial);\n /** @type {Cluster | null} */\n root: Cluster | null;\n _id: number;\n _d_min: Float64Array;\n _distance_matrix: Matrix;\n _clusters: any[];\n _c_size: Uint16Array;\n /**\n * @param {number} value - Value where to cut the tree.\n * @param {\"distance\" | \"depth\"} [type=\"distance\"] - Type of value. Default is `\"distance\"`\n * @returns {Cluster[][]} - Array of clusters with the indices of the rows in given points.\n */\n get_clusters_raw(value: number, type?: \"distance\" | \"depth\"): Cluster[][];\n /**\n * @param {number} value - Value where to cut the tree.\n * @param {\"distance\" | \"depth\"} [type=\"distance\"] - Type of value. Default is `\"distance\"`\n * @returns {number[][]} - Array of clusters with the indices of the rows in given points.\n */\n get_clusters(value: number, type?: \"distance\" | \"depth\"): number[][];\n /**\n * @param {number} value - Value where to cut the tree.\n * @param {\"distance\" | \"depth\"} [type=\"distance\"] - Type of value. Default is `\"distance\"`\n * @returns {number[]} - Array of clusters with the indices of the rows in given points.\n */\n get_cluster_list(value: number, type?: \"distance\" | \"depth\"): number[];\n /**\n * @private\n * @param {Cluster} node\n * @param {(d: {dist: number, depth: number}) => number} f\n * @param {number} value\n * @param {Cluster[][]} result\n */\n private _traverse;\n}\nimport type { ParametersHierarchicalClustering } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\n/** @private */\ndeclare class Cluster {\n /**\n *\n * @param {number} id\n * @param {Cluster?} left\n * @param {Cluster?} right\n * @param {number} dist\n * @param {Float64Array?} centroid\n * @param {number} index\n * @param {number} [size]\n * @param {number} [depth]\n */\n constructor(id: number, left: Cluster | null, right: Cluster | null, dist: number, centroid: Float64Array | null, index: number, size?: number, depth?: number);\n /**@type {number} */\n size: number;\n /**@type {number} */\n depth: number;\n /**@type {Cluster | null} */\n parent: Cluster | null;\n id: number;\n left: Cluster | null;\n right: Cluster | null;\n dist: number;\n index: number;\n centroid: Float64Array;\n /**\n *\n * @param {Cluster} left\n * @param {Cluster} right\n * @returns {Float64Array}\n */\n _calculate_centroid(left: Cluster, right: Cluster): Float64Array;\n get isLeaf(): boolean;\n /**\n *\n * @returns {Cluster[]}\n */\n leaves(): Cluster[];\n /**\n *\n * @returns {Cluster[]}\n */\n descendants(): Cluster[];\n}\nimport { Matrix } from \"../matrix/index.js\";\nimport type { InputType } from \"../index.js\";\nexport {};\n//# sourceMappingURL=Hierarchical_Clustering.d.ts.map","/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersKMeans } from \"./index.js\" */\n/**\n * K-Means Clustering\n *\n * A popular clustering algorithm that partitions data into K clusters where each point\n * belongs to the cluster with the nearest mean (centroid).\n *\n * @class\n * @extends Clustering\n * @category Clustering\n * @see {@link KMedoids} for a more robust alternative\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const points = [[1, 1], [1.5, 1.5], [5, 5], [5.5, 5.5]];\n * const kmeans = new druid.KMeans(points, { K: 2 });\n *\n * const clusters = kmeans.get_cluster_list(); // [0, 0, 1, 1]\n * const centroids = kmeans.centroids; // center points\n */\nexport class KMeans extends Clustering {\n /**\n * @param {InputType} points\n * @param {Partial} parameters\n */\n constructor(points: InputType, parameters?: Partial);\n _K: number;\n _randomizer: Randomizer;\n /** @type {number[]} */\n _clusters: number[];\n _cluster_centroids: Float64Array[];\n /** @returns {number} The number of clusters */\n get k(): number;\n /** @returns {Float64Array[]} The cluster centroids */\n get centroids(): Float64Array[];\n /** @returns {number[]} The cluster list */\n get_cluster_list(): number[];\n /** @returns {number[][]} An Array of clusters with the indices of the points. */\n get_clusters(): number[][];\n /**\n * @private\n * @param {number[]} point_indices\n * @param {number[]} candidates\n * @returns {number}\n */\n private _furthest_point;\n /**\n * @private\n * @param {number} K\n * @returns {Float64Array[]}\n */\n private _get_random_centroids;\n /**\n * @private\n * @param {Float64Array[]} cluster_centroids\n * @returns {{ clusters_changed: boolean; cluster_centroids: Float64Array[] }}\n */\n private _iteration;\n /**\n * @private\n * @param {number} K\n * @returns {Float64Array[]}\n */\n private _compute_centroid;\n}\nimport type { ParametersKMeans } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport type { InputType } from \"../index.js\";\n//# sourceMappingURL=KMeans.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import { ParametersKMedoids } from \"./index.js\" */\n/**\n * K-Medoids (PAM - Partitioning Around Medoids)\n *\n * A robust clustering algorithm similar to K-Means, but uses actual data points (medoids)\n * as cluster centers and can work with any distance metric.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n * @see {@link KMeans} for a faster but less robust alternative\n */\nexport class KMedoids extends Clustering {\n /**\n * @param {InputType} points - Data matrix\n * @param {Partial} parameters\n * @see {@link https://link.springer.com/chapter/10.1007/978-3-030-32047-8_16} Faster k-Medoids Clustering: Improving the PAM, CLARA, and CLARANS Algorithms\n */\n constructor(points: InputType, parameters?: Partial);\n _A: Float64Array[];\n _max_iter: number;\n _distance_matrix: Matrix;\n _randomizer: Randomizer;\n _clusters: any[];\n _cluster_medoids: number[];\n _is_initialized: boolean;\n /** @returns {number[]} The cluster list */\n get_cluster_list(): number[];\n /** @returns {number[][]} - Array of clusters with the indices of the rows in given points. */\n get_clusters(): number[][];\n /** @returns {number} */\n get k(): number;\n /** @returns {number[]} */\n get medoids(): number[];\n /** @returns {number[]} */\n get_medoids(): number[];\n generator(): AsyncGenerator;\n /** Algorithm 1. FastPAM1: Improved SWAP algorithm */\n /**\n * FastPAM1: One best swap per iteration\n * @private\n * @returns {boolean}\n */\n private _iteration;\n /**\n * @private\n * Get distance between two points\n * @param {number} i\n * @param {number} j\n * @param {Float64Array?} x_i\n * @param {Float64Array?} x_j\n * @returns {number}\n */\n private _get_distance;\n /**\n * @private\n * @param {Float64Array} x_j\n * @param {number} j\n * @returns\n */\n private _nearest_medoid;\n /**\n * @private\n */\n private _update_clusters;\n /**\n * Computes `K` clusters out of the `matrix`.\n * @param {number} K - Number of clusters.\n * @param {number[]} cluster_medoids\n */\n init(K: number, cluster_medoids: number[]): this;\n /**\n * Algorithm 3. FastPAM LAB: Linear Approximate BUILD initialization.\n * @private\n * @param {number} K - Number of clusters\n * @returns {number[]}\n */\n private _get_random_medoids;\n}\nimport type { ParametersKMedoids } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport type { InputType } from \"../index.js\";\n//# sourceMappingURL=KMedoids.d.ts.map","/** @import { ParametersMeanShift } from \"./index.js\" */\n/** @import { InputType } from \"../index.js\" */\n/**\n * Mean Shift Clustering\n *\n * A non-parametric clustering technique that does not require prior knowledge of the\n * number of clusters. It identifies centers of density in the data.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class MeanShift extends Clustering {\n /**\n *\n * @param {InputType} points\n * @param {Partial} parameters\n */\n constructor(points: InputType, parameters?: Partial);\n /**\n * @private\n * @type {number}\n */\n private _bandwidth;\n /**\n * @private\n * @type {number}\n */\n private _max_iter;\n /**\n * @private\n * @type {number}\n */\n private _tolerance;\n /**\n * @private\n * @type {(dist: number) => number}\n */\n private _kernel;\n /**\n * @type {Matrix}\n */\n _points: Matrix;\n /**\n * @private\n * @type {number[] | undefined}\n */\n private _clusters;\n /**\n * @private\n * @type {number[][] | undefined}\n */\n private _cluster_list;\n /**\n * Helper to compute bandwidth if not provided\n * @private\n * @param {Matrix} matrix\n * @returns {number}\n */\n private _compute_bandwidth;\n /**\n * Compute kernel weight\n * @private\n * @param {number} dist\n * @returns {number}\n */\n private _kernel_weight;\n /**\n * Perform mean shift iterations\n * @private\n */\n private _mean_shift;\n /**\n * After convergence, assign clusters based on nearest mode\n * @private\n */\n private _assign_clusters;\n /**\n * @returns {number[][]}\n */\n get_clusters(): number[][];\n /**\n *\n * @returns {number[]}\n */\n get_cluster_list(): number[];\n}\nimport type { ParametersMeanShift } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport type { InputType } from \"../index.js\";\n//# sourceMappingURL=MeanShift.d.ts.map","/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersOptics } from \"./index.js\" */\n/** @typedef {Object} DBEntry\n * @property {Float64Array} element\n * @property {number} index\n * @property {number} [reachability_distance]\n * @property {boolean} processed\n * @property {DBEntry[]} [neighbors]\n */\n/**\n * OPTICS (Ordering Points To Identify the Clustering Structure)\n *\n * A density-based clustering algorithm that extends DBSCAN. It handles clusters of varying\n * densities and produces a reachability plot that can be used to extract clusters.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class OPTICS extends Clustering {\n /**\n * **O**rdering **P**oints **T**o **I**dentify the **C**lustering **S**tructure.\n *\n * @param {InputType} points - The data.\n * @param {Partial} [parameters={}]\n * @see {@link https://www.dbs.ifi.lmu.de/Publikationen/Papers/OPTICS.pdf}\n * @see {@link https://en.wikipedia.org/wiki/OPTICS_algorithm}\n */\n constructor(points: InputType, parameters?: Partial);\n /**\n * @private\n * @type {DBEntry[]}\n */\n private _ordered_list;\n /** @type {number[][]} */\n _clusters: number[][];\n /**\n * @private\n * @type {DBEntry[]}\n */\n private _DB;\n _cluster_index: number;\n /**\n * @private\n * @param {DBEntry} p - A point of the data.\n * @returns {DBEntry[]} An array consisting of the `epsilon`-neighborhood of `p`.\n */\n private _get_neighbors;\n /**\n * @private\n * @param {DBEntry} p - A point of `matrix`.\n * @returns {number|undefined} The distance to the `min_points`-th nearest point of `p`, or undefined if the\n * `epsilon`-neighborhood has fewer elements than `min_points`.\n */\n private _core_distance;\n /**\n * Updates the reachability distance of the points.\n *\n * @private\n * @param {DBEntry} p\n * @param {Heap} seeds\n */\n private _update;\n /**\n * Expands the `cluster` with points in `seeds`.\n *\n * @private\n * @param {Heap} seeds\n * @param {number[]} cluster\n */\n private _expand_cluster;\n /**\n * Returns an array of clusters.\n *\n * @returns {number[][]} Array of clusters with the indices of the rows in given `matrix`.\n */\n get_clusters(): number[][];\n /**\n * @returns {number[]} Returns an array, where the ith entry defines the cluster affirmation of the ith point of\n * given data. (-1 stands for outlier)\n */\n get_cluster_list(): number[];\n}\nexport type DBEntry = {\n element: Float64Array;\n index: number;\n reachability_distance?: number | undefined;\n processed: boolean;\n neighbors?: DBEntry[] | undefined;\n};\nimport type { ParametersOptics } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport type { InputType } from \"../index.js\";\n//# sourceMappingURL=OPTICS.d.ts.map","/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersXMeans } from \"./index.js\" */\n/**\n * @typedef SplitResult\n * @property {number} index - Index of the cluster being split\n * @property {number} bic_parent - BIC score of the parent cluster\n * @property {number} bic_children - BIC score of the split children\n * @property {number[][]} child_clusters - Clusters after splitting\n * @property {Float64Array[]} child_centroids - Centroids of child clusters\n */\n/**\n * @typedef CandidateResult\n * @property {KMeans} kmeans - The KMeans instance for this K\n * @property {number} score - BIC score\n */\n/**\n * X-Means Clustering\n *\n * An extension of K-Means that automatically determines the number of clusters (K)\n * using the Bayesian Information Criterion (BIC).\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class XMeans extends Clustering {\n /**\n * XMeans clustering algorithm that automatically determines the optimal number of clusters.\n *\n * X-Means extends K-Means by starting with a minimum number of clusters and iteratively\n * splitting clusters to improve the Bayesian Information Criterion (BIC).\n *\n * Algorithm:\n * 1. Start with K_min clusters using KMeans\n * 2. For each cluster, try splitting it into 2 sub-clusters\n * 3. If BIC improves after splitting, keep the split\n * 4. Run KMeans again with all (old + new) centroids\n * 5. Repeat until K_max is reached or no more improvements\n *\n * @param {InputType} points - The data points to cluster\n * @param {Partial} [parameters={}] - Configuration parameters\n * @see {@link https://www.cs.cmu.edu/~dpelleg/download/xmeans.pdf}\n * @see {@link https://github.com/annoviko/pyclustering/blob/master/pyclustering/cluster/xmeans.py}\n * @see {@link https://github.com/haifengl/smile/blob/master/core/src/main/java/smile/clustering/XMeans.java}\n */\n constructor(points: InputType, parameters?: Partial);\n _randomizer: Randomizer;\n /** @type {KMeans | null} */\n _best_kmeans: KMeans | null;\n /**\n * Run the XMeans algorithm\n *\n * @private\n */\n private _run;\n /**\n * Select the best candidate based on BIC score\n *\n * @private\n * @param {Map} candidates\n * @returns {KMeans}\n */\n private _select_best_candidate;\n /**\n * Calculate Bayesian Information Criterion for a set of clusters.\n *\n * Uses Kass's formula for BIC calculation:\n * BIC(θ) = L(D) - 0.5 * p * ln(N)\n *\n * Where:\n * - L(D) is the log-likelihood of the data\n * - p is the number of free parameters: (K-1) + D*K + 1\n * - N is the total number of points\n *\n * @private\n * @param {number[][]} clusters - Array of clusters with point indices\n * @param {Float64Array[]} centroids - Array of centroids\n * @returns {number} BIC score (higher is better)\n */\n private _bic;\n /**\n * Get the computed clusters\n *\n * @returns {number[][]} Array of clusters, each containing indices of points\n */\n get_clusters(): number[][];\n /** @returns {number[]} The cluster list */\n get_cluster_list(): number[];\n /**\n * Get the final centroids\n *\n * @returns {Float64Array[]} Array of centroids\n */\n get centroids(): Float64Array[];\n /**\n * Get the optimal number of clusters found\n *\n * @returns {number} The number of clusters\n */\n get k(): number;\n}\nexport type SplitResult = {\n /**\n * - Index of the cluster being split\n */\n index: number;\n /**\n * - BIC score of the parent cluster\n */\n bic_parent: number;\n /**\n * - BIC score of the split children\n */\n bic_children: number;\n /**\n * - Clusters after splitting\n */\n child_clusters: number[][];\n /**\n * - Centroids of child clusters\n */\n child_centroids: Float64Array[];\n};\nexport type CandidateResult = {\n /**\n * - The KMeans instance for this K\n */\n kmeans: KMeans;\n /**\n * - BIC score\n */\n score: number;\n};\nimport type { ParametersXMeans } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { KMeans } from \"./KMeans.js\";\nimport type { InputType } from \"../index.js\";\n//# sourceMappingURL=XMeans.d.ts.map","export { CURE } from \"./CURE.js\";\nexport { HierarchicalClustering } from \"./Hierarchical_Clustering.js\";\nexport { KMeans } from \"./KMeans.js\";\nexport { KMedoids } from \"./KMedoids.js\";\nexport { MeanShift } from \"./MeanShift.js\";\nexport { OPTICS } from \"./OPTICS.js\";\nexport { XMeans } from \"./XMeans.js\";\nexport type ParametersHierarchicalClustering = {\n linkage: \"single\" | \"complete\" | \"average\";\n metric: Metric | \"precomputed\";\n};\nexport type ParametersKMeans = {\n K: number;\n /**\n * Default is `euclidean`\n */\n metric: Metric;\n /**\n * Default is `1212`\n */\n seed: number;\n /**\n * - Initial centroids. Default is `null`\n */\n initial_centroids?: Float64Array[] | number[][] | undefined;\n};\nexport type ParametersKMedoids = {\n /**\n * - Number of clusters\n */\n K: number;\n /**\n * - Maximum number of iterations. Default is 10 * Math.log10(N). Default is `null`\n */\n max_iter: number | null;\n /**\n * - Metric defining the dissimilarity. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Seed value for random number generator. Default is `1212`\n */\n seed: number;\n};\nexport type ParametersOptics = {\n /**\n * - The minimum distance which defines whether a point is a neighbor or not.\n */\n epsilon: number;\n /**\n * - The minimum number of points which a point needs to create a cluster. (Should be higher than 1, else each point creates a cluster.)\n */\n min_points: number;\n /**\n * - The distance metric which defines the distance between two points of the points. Default is `euclidean`\n */\n metric: Metric;\n};\nexport type ParametersXMeans = {\n /**\n * - Minimum number of clusters. Default is `2`\n */\n K_min: number;\n /**\n * - Maximum number of clusters. Default is `10`\n */\n K_max: number;\n /**\n * - Distance metric function. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Random seed. Default is `1212`\n */\n seed: number;\n /**\n * - Minimum points required to consider splitting a cluster. Default is `25`\n */\n min_cluster_size: number;\n /**\n * - Convergence tolerance for KMeans. Default is `0.001`\n */\n tolerance: number;\n};\nexport type ParametersMeanShift = {\n /**\n * - bandwidth\n */\n bandwidth: number;\n /**\n * - Metric defining the dissimilarity. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Seed value for random number generator. Default is `1212`\n */\n seed: number;\n /**\n * - Kernel function. Default is `gaussian`\n */\n kernel: \"flat\" | \"gaussian\" | ((dist: number) => number);\n /**\n * - Maximum number of iterations. Default is `Math.max(10, Math.floor(10 * Math.log10(N)))`\n */\n max_iter?: number | undefined;\n /**\n * - Convergence tolerance. Default is `1e-3`\n */\n tolerance?: number | undefined;\n};\nexport type ParametersCURE = {\n /**\n * - Target number of clusters. Default is `2`\n */\n K: number;\n /**\n * - Number of representative points per cluster. Default is `5`\n */\n num_representatives: number;\n /**\n * - Factor to shrink representatives toward centroid (0-1). Default is `0.5`\n */\n shrink_factor: number;\n /**\n * - Distance metric function. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Random seed. Default is `1212`\n */\n seed: number;\n};\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=index.d.ts.map","/**\n * @template T\n * @typedef {Object} DisjointSetPayload\n * @property {T} parent\n * @property {Set} children\n * @property {number} size\n */\n/**\n * @template T\n * @class\n * @category Data Structures\n * @see {@link https://en.wikipedia.org/wiki/Disjoint-set_data_structure}\n */\nexport class DisjointSet {\n /**\n * @param {T[]?} elements\n */\n constructor(elements?: T[] | null);\n /**\n * @private\n * @type {Map>}\n */\n private _list;\n /**\n * @private\n * @param {T} x\n * @returns {DisjointSet}\n */\n private make_set;\n /**\n * @param {T} x\n * @returns\n */\n find(x: T): T | null;\n /**\n * @param {T} x\n * @param {T} y\n * @returns\n */\n union(x: T, y: T): this;\n /** @param {T} x */\n get_children(x: T): Set | null;\n}\nexport type DisjointSetPayload = {\n parent: T;\n children: Set;\n size: number;\n};\n//# sourceMappingURL=DisjointSet.d.ts.map","/** @import { Comparator } from \"./index.js\" */\n/**\n * @template T\n * @class\n * @category Data Structures\n */\nexport class Heap {\n /**\n * Creates a Heap from an Array\n *\n * @template T\n * @param {T[]} elements - Contains the elements for the Heap.\n * @param {(d: T) => number} accessor - Function returns the value of the element.\n * @param {\"min\" | \"max\" | Comparator} [comparator=\"min\"] - Function returning true or false\n * defining the wished order of the Heap, or String for predefined function. (\"min\" for a Min-Heap, \"max\" for a\n * Max_heap). Default is `\"min\"`\n * @returns {Heap}\n */\n static heapify(elements: T_1[], accessor: (d: T_1) => number, comparator?: \"min\" | \"max\" | Comparator): Heap;\n /**\n * A heap is a datastructure holding its elements in a specific way, so that the top element would be the first\n * entry of an ordered list.\n *\n * @param {T[]?} elements - Contains the elements for the Heap. `elements` can be null.\n * @param {(d: T) => number} accessor - Function returns the value of the element.\n * @param {\"min\" | \"max\" | Comparator} [comparator=\"min\"] - Function returning true or false\n * defining the wished order of the Heap, or String for predefined function. (\"min\" for a Min-Heap, \"max\" for a\n * Max_heap). Default is `\"min\"`\n * @see {@link https://en.wikipedia.org/wiki/Binary_heap}\n */\n constructor(elements: (T[] | null) | undefined, accessor: (d: T) => number, comparator?: \"min\" | \"max\" | Comparator);\n /** @type {{ element: T; value: number }[]} */\n _container: {\n element: T;\n value: number;\n }[];\n /** @type {Comparator} */\n _comparator: Comparator;\n /** @type {(d: T) => number} */\n _accessor: (d: T) => number;\n /**\n * Swaps elements of container array.\n *\n * @private\n * @param {number} index_a\n * @param {number} index_b\n */\n private _swap;\n /** @private */\n private _heapify_up;\n /**\n * Pushes the element to the heap.\n *\n * @param {T} element\n * @returns {Heap}\n */\n push(element: T): Heap;\n /**\n * @private\n * @param {Number} [start_index=0] Default is `0`\n */\n private _heapify_down;\n /**\n * Removes and returns the top entry of the heap.\n *\n * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by\n * `accessor`}).\n */\n pop(): {\n element: T;\n value: number;\n } | null;\n /**\n * Returns the top entry of the heap without removing it.\n *\n * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by\n * `accessor`).\n */\n get first(): {\n element: T;\n value: number;\n } | null;\n /**\n * Yields the raw data\n *\n * @yields {T} Object consists of the element and its value (computed by `accessor`}).\n */\n iterate(): Generator;\n /**\n * Returns the heap as ordered array.\n *\n * @returns {T[]} Array consisting the elements ordered by `comparator`.\n */\n toArray(): T[];\n /**\n * Returns elements of container array.\n *\n * @returns {T[]} Array consisting the elements.\n */\n data(): T[];\n /**\n * Returns the container array.\n *\n * @returns {{ element: T; value: number }[]} The container array.\n */\n raw_data(): {\n element: T;\n value: number;\n }[];\n /**\n * The size of the heap.\n *\n * @returns {number}\n */\n get length(): number;\n /**\n * Returns false if the the heap has entries, true if the heap has no entries.\n *\n * @returns {boolean}\n */\n get empty(): boolean;\n}\nimport type { Comparator } from \"./index.js\";\n//# sourceMappingURL=Heap.d.ts.map","export { DisjointSet } from \"./DisjointSet.js\";\nexport { Heap } from \"./Heap.js\";\nexport type Comparator = (a: number, b: number) => boolean;\n//# sourceMappingURL=index.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/**\n * @abstract\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n *\n * Base class for all Dimensionality Reduction (DR) algorithms.\n *\n * Provides a common interface for parameters management, data initialization,\n * and transformation (both synchronous and asynchronous).\n *\n * @class\n */\nexport class DR {\n /**\n * Computes the projection.\n *\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.\n * @returns {T} The dimensionality reduced dataset.\n */\n static transform(X: T_1, parameters: Para_1, ...args: unknown[]): T_1;\n /**\n * Computes the projection.\n *\n * @template {{ seed?: number }} Para\n * @param {InputType} X\n * @param {Para} parameters\n * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.\n * @returns {Generator} A generator yielding the intermediate steps of the dimensionality\n * reduction method.\n */\n static generator(X: InputType, parameters: Para_1, ...args: unknown[]): Generator;\n /**\n * Computes the projection.\n *\n * @template {{ seed?: number }} Para\n * @param {InputType} X\n * @param {Para} parameters\n * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.\n * @returns {Promise} A promise yielding the dimensionality reduced dataset.\n */\n static transform_async(X: InputType, parameters: Para_1, ...args: unknown[]): Promise;\n /**\n * Takes the default parameters and seals them, remembers the type of input `X`, and initializes the random number\n * generator.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Para} default_parameters - Object containing default parameterization of the DR method.\n * @param {Partial} parameters - Object containing parameterization of the DR method to override defaults.\n */\n constructor(X: T, default_parameters: Para, parameters?: Partial);\n /** @type {number} */\n _D: number;\n /** @type {number} */\n _N: number;\n /** @type {Randomizer} */\n _randomizer: Randomizer;\n /** @type {boolean} */\n _is_initialized: boolean;\n /** @type {T} */\n __input: T;\n /** @type {Para} */\n _parameters: Para;\n /** @type {\"array\" | \"matrix\" | \"typed\"} */\n _type: \"array\" | \"matrix\" | \"typed\";\n /** @type {Matrix} */\n X: Matrix;\n /** @type {Matrix} */\n Y: Matrix;\n /**\n * Get all Parameters.\n * @overload\n * @returns {Para}\n */\n parameter(): Para;\n /**\n * Get value of given parameter.\n * @template {keyof Para} K\n * @overload\n * @param {K} name - Name of the parameter.\n * @returns {Para[K]}\n */\n parameter(name: K): Para[K];\n /**\n * Set value of given parameter.\n * @template {keyof Para} K\n * @overload\n * @param {K} name - Name of the parameter.\n * @param {Para[K]} value - Value of the parameter to set.\n * @returns {this}\n */\n parameter(name: K, value: Para[K]): this;\n /**\n * Computes the projection.\n *\n * @abstract\n * @param {...unknown} args\n * @returns {T} The projection.\n */\n transform(...args: unknown[]): T;\n /**\n * Computes the projection.\n *\n * @abstract\n * @param {...unknown} args\n * @returns {Generator} The intermediate steps of the projection.\n */\n generator(...args: unknown[]): Generator;\n /**\n * @abstract\n * @param {...unknown} args\n */\n init(...args: unknown[]): void;\n /**\n * If the respective DR method has an `init` function, call it before `transform`.\n *\n * @returns {DR}\n */\n check_init(): DR;\n /** @returns {T} The projection in the type of input `X`. */\n get projection(): T;\n /**\n * Computes the projection.\n *\n * @param {...unknown} args - Arguments the transform method of the respective DR method takes.\n * @returns {Promise} The dimensionality reduced dataset.\n */\n transform_async(...args: unknown[]): Promise;\n}\nimport type { InputType } from \"../index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=DR.d.ts.map","/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersFASTMAP } from \"./index.js\"; */\n/**\n * FastMap algorithm for dimensionality reduction.\n *\n * A very fast algorithm for projecting high-dimensional data into a lower-dimensional\n * space while preserving pairwise distances. It works similarly to PCA but uses\n * only a subset of the data to find projection axes.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class FASTMAP extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X: T_1, parameters: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static generator(X: T_1, parameters: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters: Partial): Promise;\n /**\n * FastMap: a fast algorithm for indexing, data-mining and visualization of traditional and multimedia datasets.\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://doi.org/10.1145/223784.223812}\n */\n constructor(X: T, parameters: Partial);\n /**\n * Chooses two points which are the most distant in the actual projection.\n *\n * @private\n * @param {(a: number, b: number) => number} dist\n * @returns {[number, number, number]} An array consisting of first index, second index, and distance between the\n * two points.\n */\n private _choose_distant_objects;\n /**\n * Computes the projection.\n *\n * @returns {T} The `d`-dimensional projection of the data matrix `X`.\n */\n transform(): T;\n generator(): Generator;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersFASTMAP } from \"./index.js\";\nimport { DR } from \"./DR.js\";\n//# sourceMappingURL=FASTMAP.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersPaCMAP} from \"./index.js\" */\n/**\n * Pairwise Controlled Manifold Approximation Projection (PaCMAP)\n *\n * A dimensionality reduction technique that uses three types of point pairs —\n * nearest neighbor (NN), mid-near (MN), and further (FP) pairs — with a\n * dynamic three-phase weight schedule and Adam optimization to preserve both\n * local and global structure.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link https://arxiv.org/abs/2012.04456|PaCMAP Paper}\n * @see {@link https://github.com/YingfanWang/PaCMAP|PaCMAP GitHub}\n * @see {@link UMAP} for a related graph-based technique\n * @see {@link LocalMAP} for the local-refinement variant\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];\n * const pacmap = new druid.PaCMAP(X, {\n * n_neighbors: 10,\n * MN_ratio: 0.5,\n * FP_ratio: 2.0,\n * seed: 42\n * });\n *\n * const Y = pacmap.transform(); // 450 iterations (default)\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class PaCMAP extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X: T, parameters?: Partial);\n _iter: number;\n /**\n * Samples mid-near pairs for each point.\n * For each point i, repeats n_MN times: samples 6 random non-neighbor\n * candidates, picks the 2nd closest by high-dim distance.\n *\n * @protected\n * @param {Set[]} nn_sets - Array of neighbor index sets per point\n * @param {number} n_MN - Number of mid-near pairs per point\n * @returns {Int32Array} Flat array of [i, j] pairs\n */\n protected _sample_mn_pairs(nn_sets: Set[], n_MN: number): Int32Array;\n /**\n * Samples further pairs for each point (random non-neighbors).\n *\n * @protected\n * @param {Set[]} nn_sets - Array of neighbor index sets per point\n * @param {number} n_FP - Number of further pairs per point\n * @returns {Int32Array} Flat array of [i, j] pairs\n */\n protected _sample_fp_pairs(nn_sets: Set[], n_FP: number): Int32Array;\n /**\n * Computes gradient coefficients and updates the gradient matrix for one pair type.\n *\n * @protected\n * @param {Float64Array} grad_flat - Flat N×d gradient accumulator (modified in place)\n * @param {Int32Array} pairs - Flat [i, j, i, j, ...] pair array\n * @param {number} w - Weight for this pair type\n * @param {number} attr_num - Numerator constant for attractive (10 for NN, 10000 for MN); 0 for repulsive\n * @param {boolean} repulsive - Whether this is a repulsive pair type\n */\n protected _accumulate_gradients(grad_flat: Float64Array, pairs: Int32Array, w: number, attr_num: number, repulsive: boolean): void;\n /**\n * Returns the weight schedule for the current iteration.\n *\n * @protected\n * @param {number} iter - Current iteration (0-indexed)\n * @returns {{ w_nn: number; w_mn: number; w_fp: number }}\n */\n protected _get_weights(iter: number): {\n w_nn: number;\n w_mn: number;\n w_fp: number;\n };\n /**\n * Applies Adam optimizer update to Y using accumulated gradients.\n *\n * @protected\n * @param {Float64Array} grad_flat - Flat N×d gradient\n */\n protected _adam_update(grad_flat: Float64Array): void;\n _adam_t: any;\n /**\n * Initializes PaCMAP: PCA embedding, KNN pairs, MN pairs, FP pairs, Adam state.\n *\n * @returns {PaCMAP}\n */\n init(): PaCMAP;\n _nn_pairs: Int32Array | undefined;\n _mn_pairs: Int32Array | undefined;\n _fp_pairs: Int32Array | undefined;\n _adam_m: Float64Array | undefined;\n _adam_v: Float64Array | undefined;\n /**\n * Performs one optimization step.\n *\n * @returns {Matrix}\n */\n next(): Matrix;\n /**\n * @param {number} [iterations] - Total number of iterations. Defaults to sum of `num_iters`.\n * @returns {T}\n */\n transform(iterations?: number): T;\n /**\n * @param {number} [iterations] - Total number of iterations. Defaults to sum of `num_iters`.\n * @returns {Generator}\n */\n generator(iterations?: number): Generator;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersPaCMAP } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=PaCMAP.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLocalMAP} from \"./index.js\" */\n/**\n * LocalMAP\n *\n * A variant of PaCMAP that improves local cluster separation by dynamically\n * resampling further pairs (FP) in phase 3 using nearby points in the current\n * low-dimensional embedding space, rather than randomly sampled non-neighbors.\n *\n * @class\n * @template {InputType} T\n * @extends PaCMAP\n * @category Dimensionality Reduction\n * @see {@link https://arxiv.org/abs/2012.04456|PaCMAP Paper}\n * @see {@link PaCMAP} for the base algorithm\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];\n * const localmap = new druid.LocalMAP(X, {\n * n_neighbors: 10,\n * low_dist_thres: 10,\n * seed: 42\n * });\n *\n * const Y = localmap.transform(); // 450 iterations (default)\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class LocalMAP extends PaCMAP {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X: T, parameters?: Partial);\n /**\n * Accumulates FP gradients with LocalMAP's distance-based weight scaling.\n * For pairs within low_dist_thres, scales w_fp by low_dist_thres / (2 * sqrt(d_ij)).\n *\n * @private\n * @param {Float64Array} grad_flat - Flat N×d gradient accumulator (modified in place)\n * @param {Int32Array} pairs - Flat [i, j, i, j, ...] pair array\n * @param {number} w_fp - Base FP weight\n * @param {number} low_dist_thres - Distance threshold\n * @param {number} low_dist_thres_sq - Squared distance threshold\n */\n private _accumulate_gradients_local_fp;\n /**\n * Initializes LocalMAP (same as PaCMAP, but caches nn_sets for phase 3 resampling).\n *\n * @returns {LocalMAP}\n */\n init(): LocalMAP;\n _low_dist_thres: number | undefined;\n _nn_sets_cache: Set[] | undefined;\n}\nimport type { InputType } from \"../index.js\";\nimport { PaCMAP } from \"./PaCMAP.js\";\nimport type { ParametersLocalMAP } from \"./index.js\";\n//# sourceMappingURL=LocalMAP.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersISOMAP} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n/**\n * Isomap (Isometric Mapping)\n *\n * A nonlinear dimensionality reduction algorithm that uses geodesic distances\n * between points on a manifold to perform embedding. It builds a neighborhood\n * graph and uses MDS on the shortest-path distances.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link LLE} for another nonlinear alternative\n */\nexport class ISOMAP extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * Isometric feature mapping (ISOMAP).\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n * @see {@link https://doi.org/10.1126/science.290.5500.2319}\n */\n constructor(X: T, parameters?: Partial);\n defaults: ParametersISOMAP;\n /**\n * Computes the projection.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * @returns {T}\n */\n transform(): T;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersISOMAP } from \"./index.js\";\nimport { DR } from \"./DR.js\";\n//# sourceMappingURL=ISOMAP.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLDA} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n/**\n * Linear Discriminant Analysis (LDA)\n *\n * A supervised dimensionality reduction technique that finds the axes that\n * maximize the separation between multiple classes.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class LDA extends DR {\n /**\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @returns {T}\n */\n static transform(X: T_1, parameters: Para): T_1;\n /**\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @returns {Generator}\n */\n static generator(X: T_1, parameters: Para): Generator;\n /**\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters: Para): Promise;\n /**\n * Linear Discriminant Analysis.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial & { labels: any[] | Float64Array }} parameters - Object containing parameterization of the DR method.\n * @see {@link https://onlinelibrary.wiley.com/doi/10.1111/j.1469-1809.1936.tb02137.x}\n */\n constructor(X: T, parameters: Partial & {\n labels: any[] | Float64Array;\n });\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T} - The projected data.\n */\n transform(): T;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersLDA } from \"./index.js\";\nimport { DR } from \"./DR.js\";\n//# sourceMappingURL=LDA.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLLE} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n/**\n * Locally Linear Embedding (LLE)\n *\n * A nonlinear dimensionality reduction technique that preserves local\n * linear relationships between points. It represents each point as a linear\n * combination of its neighbors.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link ISOMAP} for another nonlinear alternative\n */\nexport class LLE extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X: T_1, parameters: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static generator(X: T_1, parameters: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters: Partial): Promise;\n /**\n * Locally Linear Embedding.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://doi.org/10.1126/science.290.5500.2323}\n */\n constructor(X: T, parameters: Partial);\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T}\n */\n transform(): T;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersLLE } from \"./index.js\";\nimport { DR } from \"./DR.js\";\n//# sourceMappingURL=LLE.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLSP} from \"./index.js\" */\n/**\n * Least Square Projection (LSP)\n *\n * A dimensionality reduction technique that uses a small set of control points\n * (projected with MDS) to define the projection for the rest of the data\n * using a Laplacian-based optimization.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class LSP extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * Least Squares Projection.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n * @see {@link https://ieeexplore.ieee.org/document/4378370}\n */\n constructor(X: T, parameters?: Partial);\n /**\n * @returns {LSP}\n */\n init(): LSP;\n _A: Matrix | undefined;\n _b: Matrix | undefined;\n /**\n * Computes the projection.\n *\n * @returns {T} Returns the projection.\n */\n transform(): T;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersLSP } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=LSP.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLTSA} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n/**\n * Local Tangent Space Alignment (LTSA)\n *\n * A nonlinear dimensionality reduction algorithm that represents the local\n * geometry of the manifold by tangent spaces and then aligns them to reveal\n * the global structure.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class LTSA extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X: T_1, parameters: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static generator(X: T_1, parameters: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters: Partial): Promise;\n /**\n * Local Tangent Space Alignment\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://epubs.siam.org/doi/abs/10.1137/S1064827502419154}\n */\n constructor(X: T, parameters: Partial);\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * Transforms the inputdata `X` to dimenionality `d`.\n *\n * @returns {T}\n */\n transform(): T;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersLTSA } from \"./index.js\";\nimport { DR } from \"./DR.js\";\n//# sourceMappingURL=LTSA.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersMDS} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n/**\n * Classical Multidimensional Scaling (MDS)\n *\n * A linear dimensionality reduction technique that seeks to preserve the\n * pairwise distances between points as much as possible in the lower-dimensional\n * space.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link PCA} for another linear alternative\n */\nexport class MDS extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * Classical MDS.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X: T, parameters?: Partial);\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T}\n */\n transform(): T;\n _d_X: Matrix | undefined;\n /** @returns {number} - The stress of the projection. */\n stress(): number;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersMDS } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=MDS.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersPCA} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n/**\n * Principal Component Analysis (PCA)\n *\n * A linear dimensionality reduction technique that identifies the axes (principal components)\n * along which the variance of the data is maximized.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link MDS} for another linear alternative\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2], [3, 4], [5, 6]];\n * const pca = new druid.PCA(X, { d: 2 });\n * const Y = pca.transform();\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class PCA extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X: T_1, parameters: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Matrix}\n */\n static principal_components(X: T_1, parameters: Partial): Matrix;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X: T, parameters?: Partial);\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T} - The projected data.\n */\n transform(): T;\n /**\n * Computes the `d` principal components of Matrix `X`.\n *\n * @returns {Matrix}\n */\n principal_components(): Matrix;\n V: Matrix | undefined;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersPCA } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=PCA.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersPCA, ParametersMDS, ParametersSAMMON} from \"./index.js\" */\n/** @typedef {\"PCA\" | \"MDS\" | \"random\"} AvailableInit */\n/** @typedef {{ PCA: ParametersPCA; MDS: ParametersMDS; random: {} }} ChooseDR */\n/**\n * Sammon's Mapping\n *\n * A nonlinear dimensionality reduction technique that minimizes a stress\n * function based on the ratio of pairwise distances in high and low dimensional spaces.\n *\n * @class\n * @template {InputType} T\n * @extends DR>\n * @category Dimensionality Reduction\n */\nexport class SAMMON extends DR> {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial>} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial>): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial>} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial>): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial>} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial>): Promise;\n /**\n * SAMMON's Mapping\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial>} [parameters] - Object containing parameterization of the DR\n * method.\n * @see {@link https://arxiv.org/pdf/2009.01512.pdf}\n */\n constructor(X: T, parameters?: Partial>);\n /** @type {Matrix | undefined} */\n distance_matrix: Matrix | undefined;\n /**\n * Initializes the projection.\n *\n * @param {Matrix | undefined} D\n * @returns {asserts D is Matrix}\n */\n init(D: Matrix | undefined): asserts D is Matrix;\n /**\n * Transforms the inputdata `X` to dimensionality 2.\n *\n * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200`\n * @returns {T} The projection of `X`.\n */\n transform(max_iter?: number): T;\n /**\n * Transforms the inputdata `X` to dimenionality 2.\n *\n * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200`\n * @returns {Generator} A generator yielding the intermediate steps of the projection of\n * `X`.\n */\n generator(max_iter?: number): Generator;\n _step(): Matrix;\n}\nexport type AvailableInit = \"PCA\" | \"MDS\" | \"random\";\nexport type ChooseDR = {\n PCA: ParametersPCA;\n MDS: ParametersMDS;\n random: {};\n};\nimport type { InputType } from \"../index.js\";\nimport type { ParametersSAMMON } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport type { ParametersPCA } from \"./index.js\";\nimport type { ParametersMDS } from \"./index.js\";\n//# sourceMappingURL=SAMMON.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersSMACOF} from \"./index.js\" */\n/**\n * Metric Multidimensional Scaling (MDS) via SMACOF.\n *\n * SMACOF (Scaling by Majorizing a Complicated Function) is an iterative majorization\n * algorithm for solving metric multidimensional scaling problems, which aims to\n * minimize the stress function.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link MDS} for the classical approach.\n */\nexport class SMACOF extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * SMACOF for MDS.\n *\n * @param {T} X - The high-dimensional data or precomputed distance matrix.\n * @param {Partial} [parameters] - Object containing parameterization.\n */\n constructor(X: T, parameters?: Partial);\n /**\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * @returns {T}\n */\n transform(): T;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersSMACOF } from \"./index.js\";\nimport { DR } from \"./DR.js\";\n//# sourceMappingURL=SMACOF.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersSQDMDS} from \"./index.js\" */\n/**\n * SQuadMDS (Stochastic Quartet MDS)\n *\n * A lean Stochastic Quartet MDS improving global structure preservation in\n * neighbor embedding like t-SNE and UMAP.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class SQDMDS extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * SQuadMDS: a lean Stochastic Quartet MDS improving global structure preservation in neighbor embedding like t-SNE\n * and UMAP.\n *\n * @param {T} X\n * @param {Partial} [parameters]\n * @see {@link https://arxiv.org/pdf/2202.12087.pdf}\n */\n constructor(X: T, parameters?: Partial);\n init(): void;\n _add: ((...summands: Float64Array[]) => Float64Array) | undefined;\n _sub_div: ((x: Float64Array, y: Float64Array, div: number) => Float64Array) | undefined;\n _minus: ((a: Float64Array, b: Float64Array) => Float64Array) | undefined;\n _mult: ((a: Float64Array, v: number) => Float64Array) | undefined;\n _LR_init: number | undefined;\n _LR: number | undefined;\n _offset: number | undefined;\n _momentums: Matrix | undefined;\n _grads: Matrix | undefined;\n _indices: number[] | undefined;\n /** @type {(i: number, j: number, X: Matrix) => number} */\n _HD_metric: ((i: number, j: number, X: Matrix) => number) | undefined;\n /** @type {(i: number, j: number, X: Matrix) => number} */\n _HD_metric_exaggeration: ((i: number, j: number, X: Matrix) => number) | undefined;\n /**\n * Computes the projection.\n *\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {T} The projection.\n */\n transform(iterations?: number): T;\n _decay_start: number | undefined;\n /**\n * Computes the projection.\n *\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {Generator} The intermediate steps of the projection.\n */\n generator(iterations?: number): Generator;\n /**\n * Performs an optimization step.\n *\n * @private\n * @param {number} i - Acutal iteration.\n * @param {number} iterations - Number of iterations.\n */\n private _step;\n _distance_exaggeration: boolean | undefined;\n /**\n * Creates quartets of non overlapping indices.\n *\n * @private\n * @returns {Uint32Array[]}\n */\n private __quartets;\n /**\n * Computes and applies gradients, and updates momentum.\n *\n * @private\n * @param {boolean} distance_exaggeration\n */\n private _nestrov_iteration;\n /**\n * Computes the gradients.\n *\n * @param {Matrix} Y - The Projection.\n * @param {Matrix} grads - The gradients.\n * @param {boolean} [exaggeration=false] - Whether or not to use early exaggeration. Default is `false`\n * @param {boolean} [zero_grad=true] - Whether or not to reset the gradient in the beginning. Default is `true`\n * @returns {Matrix} The gradients.\n */\n _fill_MDS_grads(Y: Matrix, grads: Matrix, exaggeration?: boolean, zero_grad?: boolean): Matrix;\n /**\n * Quartet gradients for a projection.\n *\n * @private\n * @param {Matrix} Y - The acutal projection.\n * @param {number[]} quartet - The indices of the quartet.\n * @param {Float64Array} D_hd - The high-dimensional distances of the quartet.\n * @returns {Float64Array[]} The gradients for the quartet.\n */\n private _compute_quartet_grads;\n /**\n * Gradients for one element of the loss function's sum.\n *\n * @private\n * @param {Float64Array} a\n * @param {Float64Array} b\n * @param {Float64Array} c\n * @param {Float64Array} d\n * @param {number} d_ab\n * @param {number} d_ac\n * @param {number} d_ad\n * @param {number} d_bc\n * @param {number} d_bd\n * @param {number} d_cd\n * @param {number} p_ab\n * @param {number} sum_LD_dist\n * @returns {Float64Array[]}\n */\n private _ABCD_grads;\n /**\n * Inline!\n *\n * @param {number} d\n */\n __minus(d: number): (a: Float64Array, b: Float64Array) => Float64Array;\n /**\n * Inline!\n *\n * @param {number} d\n */\n __add(d: number): (...summands: Float64Array[]) => Float64Array;\n /**\n * Inline!\n *\n * @param {number} d\n */\n __mult(d: number): (a: Float64Array, v: number) => Float64Array;\n /**\n * Creates a new array `(x - y) / div`.\n *\n * @param {number} d\n */\n __sub_div(d: number): (x: Float64Array, y: Float64Array, div: number) => Float64Array;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersSQDMDS } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=SQDMDS.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersTopoMap} from \"./index.js\" */\n/**\n * TopoMap\n *\n * A 0-dimensional Homology Preserving Projection of High-Dimensional Data.\n * It aims to preserve the topological structure of the data by maintaining\n * the connectivity of a minimum spanning tree.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class TopoMap extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X: T_1, parameters: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static generator(X: T_1, parameters: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters: Partial): Promise;\n /**\n * TopoMap: A 0-dimensional Homology Preserving Projection of High-Dimensional Data.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://arxiv.org/pdf/2009.01512.pdf}\n */\n constructor(X: T, parameters: Partial);\n _distance_matrix: Matrix;\n /**\n * @private\n * @param {number} i\n * @param {number} j\n * @param {import(\"../metrics/index.js\").Metric} metric\n * @returns {number}\n */\n private __lazy_distance_matrix;\n /**\n * Computes the minimum spanning tree, using a given metric\n *\n * @private\n * @param {import(\"../metrics/index.js\").Metric} metric\n * @see {@link https://en.wikipedia.org/wiki/Kruskal%27s_algorithm}\n */\n private _make_minimum_spanning_tree;\n _disjoint_set: DisjointSet> | undefined;\n /** Initializes TopoMap. Sets all projcted points to zero, and computes a minimum spanning tree. */\n init(): this;\n _Emst: number[][] | undefined;\n /**\n * Returns true if Point C is left of line AB.\n *\n * @private\n * @param {Float64Array} PointA - Point A of line AB\n * @param {Float64Array} PointB - Point B of line AB\n * @param {Float64Array} PointC - Point C\n * @returns {boolean}\n */\n private __hull_cross;\n /**\n * Computes the convex hull of the set of Points S\n *\n * @private\n * @param {Float64Array[]} S - Set of Points.\n * @returns {Float64Array[]} Convex hull of S. Starts at the bottom-most point and continues counter-clockwise.\n * @see {@link https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain#JavaScript}\n */\n private __hull;\n /**\n * Finds the angle to rotate Point A and B to lie on a line parallel to the x-axis.\n *\n * @private\n * @param {Float64Array} PointA\n * @param {Float64Array} PointB\n * @returns {{ sin: number; cos: number }} Object containing the sinus- and cosinus-values for a rotation.\n */\n private __findAngle;\n /**\n * @private\n * @param {Float64Array[]} hull\n * @param {Float64Array} p\n * @param {boolean} topEdge\n * @returns {{ sin: number; cos: number; tx: number; ty: number }}\n */\n private __align_hull;\n /**\n * @private\n * @param {Float64Array} Point - The point which should get transformed.\n * @param {{ sin: number; cos: number; tx: number; ty: number }} Transformation - Contains the values for\n * translation and rotation.\n */\n private __transform;\n /**\n * Calls `__transform` for each point in Set C\n *\n * @private\n * @param {Float64Array[]} C - Set of points.\n * @param {{ sin: number; cos: number; tx: number; ty: number }} t - Transform object.\n * @param {number} yOffset - Value to offset set C.\n */\n private __transform_component;\n /**\n * @private\n * @param {Float64Array} root_u - Root of component u\n * @param {Float64Array} root_v - Root of component v\n * @param {Float64Array} p_u - Point u\n * @param {Float64Array} p_v - Point v\n * @param {number} w - Edge weight w\n * @param {DisjointSet} components - The disjoint set containing the components\n */\n private __align_components;\n /**\n * Transforms the inputdata `X` to dimensionality 2.\n *\n * @returns {T}\n */\n transform(): T;\n /**\n * Transforms the inputdata `X` to dimensionality 2.\n *\n * @returns {Generator}\n */\n generator(): Generator;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersTopoMap } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { DisjointSet } from \"../datastructure/index.js\";\n//# sourceMappingURL=TopoMap.d.ts.map","/**\n * Base class for all K-Nearest Neighbors (KNN) search algorithms.\n *\n * Provides a common interface for elements management and search operations.\n *\n * @abstract\n * @category KNN\n * @template {number[] | Float64Array} T - Type of elements\n * @template {Object} Para - Type of parameters\n * @class\n */\nexport class KNN {\n /**\n * @param {T[]} elements\n * @param {Para} parameters\n */\n constructor(elements: T[], parameters: Para);\n /** @type {T[]} */\n _elements: T[];\n /** @type {Para} */\n _parameters: Para;\n /** @type {\"typed\" | \"array\"} */\n _type: \"typed\" | \"array\";\n /**\n * @abstract\n * @param {T} t\n * @param {number} k\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search(t: T, k: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @abstract\n * @param {number} i\n * @param {number} k\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i: number, k: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n}\n//# sourceMappingURL=KNN.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersTriMap} from \"./index.js\" */\n/** @import {KNN} from \"../knn/KNN.js\" */\n/**\n * TriMap\n *\n * A dimensionality reduction technique that preserves both local and global\n * structure using triplets. It is designed to be a more robust alternative\n * to t-SNE and UMAP.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class TriMap extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n * @see {@link https://arxiv.org/pdf/1910.00204v1.pdf}\n * @see {@link https://github.com/eamid/trimap}\n */\n constructor(X: T, parameters?: Partial);\n /**\n * @param {Matrix | null} [pca=null] - Initial Embedding (if null then PCA gets used). Default is `null`\n * @param {import(\"../knn/KNN.js\").KNN | null} [knn=null] - KNN Object (if null then BallTree gets used). Default is `null`\n */\n init(pca?: Matrix | null, knn?: import(\"../knn/KNN.js\").KNN | null): this;\n n_inliers: number | undefined;\n n_outliers: number | undefined;\n n_random: number | undefined;\n knn: KNN, any> | undefined;\n triplets: Matrix | undefined;\n weights: Float64Array | undefined;\n lr: number | undefined;\n C: number | undefined;\n vel: Matrix | undefined;\n gain: Matrix | undefined;\n /**\n * Generates {@link n_inliers} x {@link n_outliers} x {@link n_random} triplets.\n *\n * @param {number} n_inliers\n * @param {number} n_outliers\n * @param {number} n_random\n */\n _generate_triplets(n_inliers: number, n_outliers: number, n_random: number): {\n triplets: Matrix;\n weights: Float64Array;\n };\n /**\n * Calculates the similarity matrix P\n *\n * @private\n * @param {Matrix} knn_distances - Matrix of pairwise knn distances\n * @param {Float64Array} sig - Scaling factor for the distances\n * @param {Matrix} nbrs - Nearest neighbors\n * @returns {Matrix} Pairwise similarity matrix\n */\n private _find_p;\n /**\n * Sample nearest neighbors triplets based on the similarity values given in P.\n *\n * @private\n * @param {Matrix} P - Matrix of pairwise similarities between each point and its neighbors given in matrix nbrs.\n * @param {Matrix} nbrs - Nearest neighbors indices for each point. The similarity values are given in matrix\n * {@link P}. Row i corresponds to the i-th point.\n * @param {number} n_inliers - Number of inlier points.\n * @param {number} n_outliers - Number of outlier points.\n */\n private _sample_knn_triplets;\n /**\n * Should do the same as np.argsort()\n *\n * @private\n * @param {Float64Array | number[]} A\n */\n private __argsort;\n /**\n * Samples {@link n_samples} integers from a given interval [0, {@link max_int}] while rejection the values that are\n * in the {@link rejects}.\n *\n * @private\n * @param {number} n_samples\n * @param {number} max_int\n * @param {number[]} rejects\n */\n private _rejection_sample;\n /**\n * Calculates the weights for the sampled nearest neighbors triplets\n *\n * @private\n * @param {Matrix} triplets - Sampled Triplets.\n * @param {Matrix} P - Pairwise similarity matrix.\n * @param {Matrix} nbrs - Nearest Neighbors\n * @param {Float64Array} outlier_distances - Matrix of pairwise outlier distances\n * @param {Float64Array} sig - Scaling factor for the distances.\n */\n private _find_weights;\n /**\n * Sample uniformly ranom triplets\n *\n * @private\n * @param {Matrix} X - Data matrix.\n * @param {number} n_random - Number of random triplets per point\n * @param {Float64Array} sig - Scaling factor for the distances\n */\n private _sample_random_triplets;\n /**\n * Computes the gradient for updating the embedding.\n *\n * @param {Matrix} Y - The embedding\n */\n _grad(Y: Matrix): {\n grad: Matrix;\n loss: number;\n n_viol: number;\n };\n /**\n * @param {number} max_iteration\n * @returns {T}\n */\n transform(max_iteration?: number): T;\n /**\n * @param {number} max_iteration\n * @returns {Generator}\n */\n generator(max_iteration?: number): Generator;\n /**\n * Does the iteration step.\n *\n * @private\n * @param {number} iter\n */\n private _next;\n /**\n * Updates the embedding.\n *\n * @private\n * @param {Matrix} Y\n * @param {number} iter\n * @param {Matrix} grad\n */\n private _update_embedding;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersTriMap } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport type { KNN } from \"../knn/KNN.js\";\n//# sourceMappingURL=TriMap.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersTSNE} from \"./index.js\" */\n/**\n * t-SNE (t-Distributed Stochastic Neighbor Embedding)\n *\n * A nonlinear dimensionality reduction technique particularly well-suited\n * for visualizing high-dimensional data in 2D or 3D. Preserves local\n * structure while revealing global patterns.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link https://lvdmaaten.github.io/tsne/|t-SNE Paper}\n * @see {@link UMAP} for faster alternative with similar results\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];\n * const tsne = new druid.TSNE(X, {\n * perplexity: 30,\n * epsilon: 10,\n * d: 2,\n * seed: 42\n * });\n *\n * const Y = tsne.transform(500); // 500 iterations\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class TSNE extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X: T, parameters?: Partial);\n _iter: number;\n init(): this;\n _ystep: Matrix | undefined;\n _gains: Matrix | undefined;\n _P: Matrix | undefined;\n /**\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {T} The projection.\n */\n transform(iterations?: number): T;\n /**\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {Generator} - The projection.\n */\n generator(iterations?: number): Generator;\n /**\n * Performs a optimization step\n *\n * @private\n * @returns {Matrix}\n */\n private next;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersTSNE } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=TSNE.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersUMAP} from \"./index.js\" */\n/**\n * Uniform Manifold Approximation and Projection (UMAP)\n *\n * A novel manifold learning technique for dimensionality reduction. UMAP is constructed\n * from a theoretical framework based on Riemannian geometry and algebraic topology.\n * It is often faster than t-SNE while preserving more of the global structure.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link https://arxiv.org/abs/1802.03426|UMAP Paper}\n * @see {@link TSNE} for a similar visualization technique\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];\n * const umap = new druid.UMAP(X, {\n * n_neighbors: 15,\n * min_dist: 0.1,\n * d: 2,\n * seed: 42\n * });\n *\n * const Y = umap.transform(500); // 500 iterations\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class UMAP extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X: T, parameters?: Partial);\n _iter: number;\n /**\n * @private\n * @param {number} spread\n * @param {number} min_dist\n * @returns {number[]}\n */\n private _find_ab_params;\n /**\n * @private\n * @param {{ element: Float64Array; index: number; distance: number }[][]} distances\n * @param {number[]} sigmas\n * @param {number[]} rhos\n * @returns {{ element: Float64Array; index: number; distance: number }[][]}\n */\n private _compute_membership_strengths;\n /**\n * @private\n * @param {NaiveKNN | BallTree} knn\n * @param {number} k\n * @returns {{\n * distances: { element: Float64Array; index: number; distance: number }[][];\n * sigmas: number[];\n * rhos: number[];\n * }}\n */\n private _smooth_knn_dist;\n /**\n * @private\n * @param {Matrix} X\n * @param {number} n_neighbors\n * @returns {Matrix}\n */\n private _fuzzy_simplicial_set;\n /**\n * @private\n * @param {number} n_epochs\n * @returns {Float32Array}\n */\n private _make_epochs_per_sample;\n /**\n * @private\n * @param {Matrix} graph\n * @returns {{ rows: number[]; cols: number[]; data: number[] }}\n */\n private _tocoo;\n /**\n * Computes all necessary\n *\n * @returns {UMAP}\n */\n init(): UMAP;\n _a: number | undefined;\n _b: number | undefined;\n _graph: Matrix | undefined;\n _head: number[] | undefined;\n _tail: number[] | undefined;\n _weights: number[] | undefined;\n _epochs_per_sample: Float32Array | undefined;\n _epochs_per_negative_sample: Float32Array | undefined;\n _epoch_of_next_sample: Float32Array | undefined;\n _epoch_of_next_negative_sample: Float32Array | undefined;\n graph(): {\n cols: number[] | undefined;\n rows: number[] | undefined;\n weights: number[] | undefined;\n };\n /**\n * @param {number} [iterations=350] - Number of iterations. Default is `350`\n * @returns {T}\n */\n transform(iterations?: number): T;\n /**\n * @param {number} [iterations=350] - Number of iterations. Default is `350`\n * @returns {Generator}\n */\n generator(iterations?: number): Generator;\n /**\n * @private\n * @param {number} x\n * @returns {number}\n */\n private _clip;\n /**\n * Performs the optimization step.\n *\n * @private\n * @param {Matrix} head_embedding\n * @param {Matrix} tail_embedding\n * @param {number[]} head\n * @param {number[]} tail\n * @returns {Matrix}\n */\n private _optimize_layout;\n /**\n * @private\n * @returns {Matrix}\n */\n private next;\n _alpha: number | undefined;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersUMAP } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=UMAP.d.ts.map","/**\n * Computes the inner product between two arrays of the same length.\n *\n * @category Linear Algebra\n * @param {number[] | Float64Array} a - Array a.\n * @param {number[] | Float64Array} b - Array b.\n * @returns The inner product between `a` and `b`.\n */\nexport function inner_product(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=inner_product.d.ts.map","/**\n * Computes the QR Decomposition of the Matrix `A` using Gram-Schmidt process.\n *\n * @category Linear Algebra\n * @param {Matrix} A\n * @returns {{ R: Matrix; Q: Matrix }}\n * @see {@link https://en.wikipedia.org/wiki/QR_decomposition#Using_the_Gram%E2%80%93Schmidt_process}\n */\nexport function qr(A: Matrix): {\n R: Matrix;\n Q: Matrix;\n};\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=qr.d.ts.map","/**\n * Computes the QR Decomposition of the Matrix `A` with householder transformations.\n *\n * @category Linear Algebra\n * @param {Matrix} A\n * @returns {{ R: Matrix; Q: Matrix }}\n * @see {@link https://en.wikipedia.org/wiki/QR_decomposition#Using_Householder_reflections}\n * @see {@link http://mlwiki.org/index.php/Householder_Transformation}\n */\nexport function qr_householder(A: Matrix): {\n R: Matrix;\n Q: Matrix;\n};\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=qr_householder.d.ts.map","/** @import { EigenArgs } from \"./index.js\" */\n/**\n * Computes the `k` biggest Eigenvectors and Eigenvalues from Matrix `A` with the QR-Algorithm.\n *\n * @category Linear Algebra\n * @param {Matrix} A - The Matrix\n * @param {number} k - The number of eigenvectors and eigenvalues to compute.\n * @param {EigenArgs} parameters - Object containing parameterization of the simultanious\n * poweriteration method.\n * @returns {{ eigenvalues: Float64Array; eigenvectors: Float64Array[] }} The `k` biggest eigenvectors and eigenvalues\n * of Matrix `A`.\n */\nexport function simultaneous_poweriteration(A: Matrix, k?: number, { seed, max_iterations, qr, tol }?: EigenArgs): {\n eigenvalues: Float64Array;\n eigenvectors: Float64Array[];\n};\nimport { Matrix } from \"../matrix/index.js\";\nimport type { EigenArgs } from \"./index.js\";\n//# sourceMappingURL=simultaneous_poweriteration.d.ts.map","export { inner_product } from \"./inner_product.js\";\nexport { qr } from \"./qr.js\";\nexport { qr_householder } from \"./qr_householder.js\";\nexport { simultaneous_poweriteration } from \"./simultaneous_poweriteration.js\";\nexport type QRDecomposition = (A: import(\"../matrix/index.js\").Matrix) => {\n R: import(\"../matrix/index.js\").Matrix;\n Q: import(\"../matrix/index.js\").Matrix;\n};\nexport type EigenArgs = {\n /**\n * - The number of maxiumum iterations the algorithm should run. Default is `100`\n */\n max_iterations?: number | undefined;\n /**\n * - The seed value or a randomizer used in the algorithm. Default is `1212`\n */\n seed?: number | Randomizer | undefined;\n /**\n * - The QR technique to use. Default is `qr_gramschmidt`\n */\n qr?: QRDecomposition | undefined;\n /**\n * - Tolerated error for stopping criteria. Default is `1e-8`\n */\n tol?: number | undefined;\n};\nimport type { Randomizer } from \"../util/index.js\";\n//# sourceMappingURL=index.d.ts.map","export { FASTMAP } from \"./FASTMAP.js\";\nexport { LocalMAP } from \"./LocalMAP.js\";\nexport { PaCMAP } from \"./PaCMAP.js\";\nexport { ISOMAP } from \"./ISOMAP.js\";\nexport { LDA } from \"./LDA.js\";\nexport { LLE } from \"./LLE.js\";\nexport { LSP } from \"./LSP.js\";\nexport { LTSA } from \"./LTSA.js\";\nexport { MDS } from \"./MDS.js\";\nexport { PCA } from \"./PCA.js\";\nexport { SAMMON } from \"./SAMMON.js\";\nexport { SMACOF } from \"./SMACOF.js\";\nexport { SQDMDS } from \"./SQDMDS.js\";\nexport { TopoMap } from \"./TopoMap.js\";\nexport { TriMap } from \"./TriMap.js\";\nexport { TSNE } from \"./TSNE.js\";\nexport { UMAP } from \"./UMAP.js\";\nexport type ParametersLSP = {\n /**\n * - number of neighbors to consider.\n */\n neighbors?: number | undefined;\n /**\n * - number of controlpoints\n */\n control_points?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersFASTMAP = {\n /**\n * - The dimensionality of the projection\n */\n d?: number | undefined;\n /**\n * - The metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - The seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersISOMAP = {\n /**\n * - The number of neighbors ISOMAP should use to project the data.\n */\n neighbors?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - Whether to use classical MDS or SMACOF for the final DR.\n */\n project?: \"MDS\" | \"SMACOF\" | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n /**\n * - Parameters for the eigendecomposition algorithm.\n */\n eig_args?: Partial | undefined;\n};\nexport type ParametersLDA = {\n /**\n * - The labels / classes for each data point.\n */\n labels: any[] | Float64Array;\n /**\n * - The dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - The seed for the random number generator.\n */\n seed?: number | undefined;\n /**\n * - Parameters for the eigendecomposition algorithm.\n */\n eig_args?: Partial | undefined;\n};\nexport type ParametersLLE = {\n /**\n * - The number of neighbors for LLE.\n */\n neighbors?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n /**\n * - Parameters for the eigendecomposition algorithm.\n */\n eig_args?: Partial | undefined;\n};\nexport type ParametersLTSA = {\n /**\n * - The number of neighbors for LTSA.\n */\n neighbors?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n /**\n * - Parameters for the eigendecomposition algorithm.\n */\n eig_args?: Partial | undefined;\n};\nexport type ParametersMDS = {\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | \"precomputed\" | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n /**\n * - Parameters for the eigendecomposition algorithm.\n */\n eig_args?: Partial | undefined;\n};\nexport type ParametersPCA = {\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n /**\n * - Parameters for the eigendecomposition algorithm.\n */\n eig_args?: Partial | undefined;\n};\nexport type ParametersSAMMON = {\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | \"precomputed\" | undefined;\n /**\n * - Either \"PCA\" or \"MDS\", with which SAMMON initialiates the projection.\n */\n init_DR?: K | undefined;\n /**\n * - Parameters for the \"init\"-DR method.\n */\n init_parameters?: ChooseDR[K] | undefined;\n /**\n * - learning rate for gradient descent.\n */\n magic?: number | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersSMACOF = {\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | \"precomputed\" | undefined;\n /**\n * - maximum number of iterations.\n */\n iterations?: number | undefined;\n /**\n * - tolerance for stress difference.\n */\n epsilon?: number | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersSQDMDS = {\n d?: number | undefined;\n metric?: Metric | \"precomputed\" | undefined;\n /**\n * - Percentage of iterations using exaggeration phase.\n */\n decay_start?: number | undefined;\n /**\n * - Controls the decay of the learning parameter.\n */\n decay_cte?: number | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersTopoMap = {\n /**\n * = euclidean - The metric which defines the distance between\n * two points.\n */\n metric: Metric;\n /**\n * = 1212 - The seed for the random number generator.\n */\n seed: number;\n};\nexport type ParametersTriMap = {\n /**\n * - scaling factor.\n */\n weight_adj?: number | undefined;\n /**\n * - number of inliers.\n */\n n_inliers?: number | undefined;\n /**\n * - number of outliers.\n */\n n_outliers?: number | undefined;\n /**\n * - number of random points.\n */\n n_random?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n tol?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersTSNE = {\n /**\n * - perplexity.\n */\n perplexity?: number | undefined;\n /**\n * - learning parameter.\n */\n epsilon?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | \"precomputed\" | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersPaCMAP = {\n /**\n * - Number of nearest neighbors for NN pairs.\n */\n n_neighbors?: number | undefined;\n /**\n * - Ratio of mid-near pairs to n_neighbors.\n */\n MN_ratio?: number | undefined;\n /**\n * - Ratio of further pairs to n_neighbors.\n */\n FP_ratio?: number | undefined;\n /**\n * - The dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - The metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - Learning rate for the Adam optimizer.\n */\n lr?: number | undefined;\n /**\n * - Number of iterations for each of the three phases.\n */\n num_iters?: number[] | undefined;\n /**\n * - The seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersLocalMAP = {\n /**\n * - Number of nearest neighbors for NN pairs.\n */\n n_neighbors?: number | undefined;\n /**\n * - Ratio of mid-near pairs to n_neighbors.\n */\n MN_ratio?: number | undefined;\n /**\n * - Ratio of further pairs to n_neighbors.\n */\n FP_ratio?: number | undefined;\n /**\n * - The dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - The metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - Learning rate for the Adam optimizer.\n */\n lr?: number | undefined;\n /**\n * - Number of iterations for each of the three phases.\n */\n num_iters?: number[] | undefined;\n /**\n * - Distance threshold for local FP pair resampling in phase 3.\n */\n low_dist_thres?: number | undefined;\n /**\n * - The seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersUMAP = {\n /**\n * - size of the local neighborhood.\n */\n n_neighbors?: number | undefined;\n /**\n * - number of nearest neighbors connected in the local neighborhood.\n */\n local_connectivity?: number | undefined;\n /**\n * - controls how tightly points get packed together.\n */\n min_dist?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points in the high-dimensional space.\n */\n metric?: Metric | \"precomputed\" | undefined;\n /**\n * - The effective scale of embedded points.\n */\n _spread?: number | undefined;\n /**\n * - Interpolate between union and intersection.\n */\n _set_op_mix_ratio?: number | undefined;\n /**\n * - Weighting applied to negative samples.\n */\n _repulsion_strength?: number | undefined;\n /**\n * - The number of negative samples per positive sample.\n */\n _negative_sample_rate?: number | undefined;\n /**\n * - The number of training epochs.\n */\n _n_epochs?: number | undefined;\n /**\n * - The initial learning rate for the optimization.\n */\n _initial_alpha?: number | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nimport type { Metric } from \"../metrics/index.js\";\nimport type { EigenArgs } from \"../linear_algebra/index.js\";\nimport type { ChooseDR } from \"./SAMMON.js\";\n//# sourceMappingURL=index.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersAnnoy } from \"./index.js\" */\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} AnnoyNode\n * @property {boolean} isLeaf - Whether this is a leaf node\n * @property {number[]} indices - Indices of points in this node (leaf) or children (internal)\n * @property {number[]} normal - Hyperplane normal vector (internal nodes only)\n * @property {number} offset - Hyperplane offset (internal nodes only)\n * @property {AnnoyNode | null} left - Left child (internal nodes only)\n * @property {AnnoyNode | null} right - Right child (internal nodes only)\n */\n/**\n * Annoy-style (Approximate Nearest Neighbors Oh Yeah) implementation using Random Projection Trees.\n *\n * This implementation builds multiple random projection trees where each tree randomly selects\n * two points and splits the space based on a hyperplane equidistant between them.\n *\n * Key features:\n * - Multiple random projection trees for better recall\n * - Each tree uses random hyperplanes for splitting\n * - Priority queue search for better recall\n * - Combines results from all trees\n *\n * Best suited for:\n * - High-dimensional data\n * - Approximate nearest neighbor search\n * - Large datasets\n * - When high recall is needed with approximate methods\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link https://github.com/spotify/annoy}\n * @see {@link https://erikbern.com/2015/09/24/nearest-neighbors-and-vector-models-epilogue-curse-of-dimensionality.html}\n */\nexport class Annoy extends KNN {\n /**\n * Creates a new Annoy-style index with random projection trees.\n *\n * @param {T[]} elements - Elements to index\n * @param {ParametersAnnoy} [parameters={}] - Configuration parameters\n */\n constructor(elements: T[], parameters?: ParametersAnnoy);\n _metric: Metric;\n _numTrees: number;\n _maxPointsPerLeaf: number;\n _seed: number;\n _randomizer: Randomizer;\n /**\n * @private\n * @type {AnnoyNode[]}\n */\n private _trees;\n /**\n * Get the number of trees in the index.\n * @returns {number}\n */\n get num_trees(): number;\n /**\n * Get the total number of nodes in all trees.\n * @returns {number}\n */\n get num_nodes(): number;\n /**\n * @private\n * @param {any} node\n * @returns {number}\n */\n private _countNodes;\n /**\n * Add elements to the Annoy index.\n * @param {T[]} elements\n * @returns {this}\n */\n add(elements: T[]): this;\n /**\n * Build all random projection trees.\n * @private\n */\n private _buildTrees;\n /**\n * Recursively build a random projection tree.\n * @private\n * @param {number[]} indices - Indices of elements to include\n * @returns {AnnoyNode}\n */\n private _buildTreeRecursive;\n /**\n * Compute distance from point to hyperplane.\n * @private\n * @param {T} point\n * @param {number[]} normal\n * @param {number} offset\n * @returns {number} Signed distance (positive = right side, negative = left side)\n */\n private _distanceToHyperplane;\n /**\n * Search for k approximate nearest neighbors.\n * @param {T} query\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search(query: T, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * Search tree using priority queue for better recall.\n * Explores nodes in order of distance to hyperplane.\n * @private\n * @param {AnnoyNode} node\n * @param {T} query\n * @param {Set} candidates\n * @param {number} maxCandidates\n */\n private _searchTreePriority;\n /**\n * @param {number} i\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * Alias for search_by_index for backward compatibility.\n *\n * @param {number} i - Index of the query element\n * @param {number} [k=5] - Number of nearest neighbors to return\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n}\nexport type AnnoyNode = {\n /**\n * - Whether this is a leaf node\n */\n isLeaf: boolean;\n /**\n * - Indices of points in this node (leaf) or children (internal)\n */\n indices: number[];\n /**\n * - Hyperplane normal vector (internal nodes only)\n */\n normal: number[];\n /**\n * - Hyperplane offset (internal nodes only)\n */\n offset: number;\n /**\n * - Left child (internal nodes only)\n */\n left: AnnoyNode | null;\n /**\n * - Right child (internal nodes only)\n */\n right: AnnoyNode | null;\n};\nimport type { ParametersAnnoy } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport type { Metric } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\n//# sourceMappingURL=Annoy.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersBallTree } from \"./index.js\" */\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} ElementWithIndex\n * @property {number} index\n * @property {T} element\n */\n/**\n * Ball Tree for efficient nearest neighbor search.\n *\n * A Ball Tree is a metric tree that partitions points into a nested set of\n * hyperspheres (balls). It is particularly effective for high-dimensional\n * data and supports any valid metric.\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n */\nexport class BallTree extends KNN {\n /**\n * Generates a BallTree with given `elements`.\n *\n * @param {T[]} elements - Elements which should be added to the BallTree\n * @param {ParametersBallTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}`\n * @see {@link https://en.wikipedia.org/wiki/Ball_tree}\n * @see {@link https://github.com/invisal/noobjs/blob/master/src/tree/BallTree.js}\n */\n constructor(elements: T[], parameters?: ParametersBallTree);\n /**\n * @private\n * @type {BallTreeNode | BallTreeLeaf}\n */\n private _root;\n /** @returns {Metric} */\n get _metric(): Metric;\n /**\n * @private\n * @param {ElementWithIndex[]} elements\n * @returns {BallTreeNode | BallTreeLeaf} Root of balltree.\n */\n private _construct;\n /**\n * @private\n * @param {ElementWithIndex[]} B\n * @returns {number}\n */\n private _greatest_spread;\n /**\n * @param {number} i\n * @param {number} k\n */\n search_by_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @param {T} t - Query element.\n * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors.\n */\n search(t: T, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @private\n * @param {T} t - Query element.\n * @param {number} k - Number of nearest neighbors to return.\n * @param {Heap>} Q - Heap consists of the currently found `k` nearest neighbors.\n * @param {BallTreeNode | BallTreeLeaf} B\n */\n private _search;\n}\nexport type ElementWithIndex = {\n index: number;\n element: T;\n};\nimport type { ParametersBallTree } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=BallTree.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersHNSW } from \"./index.js\" */\n/**\n * @typedef {Object} Layer\n * @property {number} l_c - Layer number\n * @property {number[]} point_indices - Global indices of points in this layer\n * @property {Map} edges - Global index -> array of connected global indices\n */\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} Candidate\n * @property {T} element - The actual data point\n * @property {number} index - Global index in the dataset\n * @property {number} distance - Distance from query\n */\n/**\n * Hierarchical Navigable Small World (HNSW) graph for approximate nearest neighbor search.\n *\n * HNSW builds a multi-layer graph structure where each layer is a navigable small world graph.\n * The top layers serve as \"highways\" for fast traversal, while lower layers provide accuracy.\n * Each element is assigned to a random level, allowing logarithmic search complexity.\n *\n * Key parameters:\n * - `m`: Controls the number of connections per element (affects accuracy/memory)\n * - `ef_construction`: Controls the quality of the graph during construction (higher = better but slower)\n * - `ef`: Controls the quality of search (higher = better recall but slower)\n *\n * Based on:\n * - \"Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs\"\n * by Malkov & Yashunin (2016)\n * - \"Approximate Nearest Neighbor Search on High Dimensional Data\"\n * by Li et al. (2019)\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const points = [[1, 2], [3, 4], [5, 6], [7, 8]];\n * const hnsw = new druid.HNSW(points, {\n * metric: druid.euclidean,\n * m: 16,\n * ef_construction: 200\n * });\n *\n * const query = [2, 3];\n * const neighbors = hnsw.search(query, 2);\n * // [{ element: [1, 2], index: 0, distance: 1.41 }, ...]\n */\nexport class HNSW extends KNN {\n /**\n * Creates a new HNSW index.\n *\n * @param {T[]} points - Initial points to add to the index\n * @param {ParametersHNSW} [parameters={}] - Configuration parameters\n */\n constructor(points: T[], parameters?: ParametersHNSW);\n /** @type {Metric} */\n _metric: Metric;\n /** @type {Function} */\n _select: Function;\n /**\n * @private\n * @type {Map}\n */\n private _graph;\n /** @type {number} */\n _next_index: number;\n /** @type {number} */\n _m: number;\n /** @type {number} */\n _ef_construction: number;\n /** @type {number} */\n _ef: number;\n /** @type {number} */\n _m0: number;\n /** @type {number} */\n _mL: number;\n /** @type {Randomizer} */\n _randomizer: Randomizer;\n /** @type {number} - Current maximum layer in the graph */\n _L: number;\n /** @type {number[] | null} - Entry point indices for search */\n _ep: number[] | null;\n /**\n * Add a single element to the index.\n *\n * @param {T} element - Element to add\n * @returns {HNSW} This instance for chaining\n */\n addOne(element: T): HNSW;\n /**\n * Add multiple elements to the index.\n *\n * @param {T[]} new_elements - Elements to add\n * @returns {HNSW} This instance for chaining\n */\n add(new_elements: T[]): HNSW;\n /**\n * Select neighbors using the heuristic approach.\n *\n * The heuristic extends candidates with their neighbors and selects\n * points that are closer to the query than to already selected points.\n * This maintains graph connectivity better than simple selection.\n *\n * @private\n * @param {T} q - Query element\n * @param {Candidate[]} candidates - Candidate elements with distances\n * @param {number} M - Maximum number of neighbors to return\n * @param {number} l_c - Layer number\n * @param {boolean} [extend_candidates=true] - Whether to extend candidates with their neighbors\n * @param {boolean} [keep_pruned_connections=true] - Whether to add pruned connections back if needed\n * @returns {number[]} Selected neighbor indices\n */\n private _select_heuristic;\n /**\n * Select neighbors using simple distance-based selection.\n *\n * Simply returns the M closest candidates to the query.\n *\n * @private\n * @param {T} q - Query element\n * @param {Candidate[]} C - Candidate elements with distances\n * @param {number} M - Maximum number of neighbors to return\n * @returns {number[]} M nearest candidate indices\n */\n private _select_simple;\n /**\n * Search a single layer for nearest neighbors.\n *\n * Implements the greedy search algorithm: start from entry points,\n * always expand the closest unvisited candidate, maintain a list\n * of the ef closest found neighbors.\n *\n * @private\n * @param {T} q - Query element\n * @param {number[] | null} ep_indices - Entry point indices\n * @param {number} ef - Number of nearest neighbors to find\n * @param {number} l_c - Layer number to search\n * @returns {Candidate[]} ef nearest neighbors found with their distances\n */\n private _search_layer;\n /**\n * Fallback linear search when graph search fails\n * @private\n * @param {T} q - Query element\n * @param {number} K - Number of nearest neighbors to return\n * @returns {Candidate[]}\n */\n private _linear_search;\n /**\n * Iterator for searching the HNSW graph layer by layer.\n *\n * Yields intermediate results at each layer for debugging or visualization.\n *\n * @param {T} q - Query element\n * @param {number} K - Number of nearest neighbors to return\n * @param {number?} [ef] - Size of dynamic candidate list\n * @yields {{layer: number, candidates: Candidate[]}}\n */\n search_iter(q: T, K: number, ef?: number | null): Generator<{\n layer: number;\n candidates: {\n element: T;\n index: number;\n distance: number;\n }[];\n }, void, unknown>;\n /**\n * Get the number of elements in the index.\n *\n * @returns {number} Number of elements\n */\n get size(): number;\n /**\n * Get the number of layers in the graph.\n *\n * @returns {number} Number of layers\n */\n get num_layers(): number;\n /**\n * Get an element by its index.\n *\n * @param {number} index - Element index\n * @returns {T} The element at the given index\n */\n get_element(index: number): T;\n /**\n * Search for nearest neighbors using an element index as the query.\n *\n * @param {number} i - Index of the query element\n * @param {number} [K=5] - Number of nearest neighbors to return\n * @returns {Candidate[]} K nearest neighbors\n */\n search_by_index(i: number, K?: number): Candidate[];\n}\nexport type Layer = {\n /**\n * - Layer number\n */\n l_c: number;\n /**\n * - Global indices of points in this layer\n */\n point_indices: number[];\n /**\n * - Global index -> array of connected global indices\n */\n edges: Map;\n};\nexport type Candidate = {\n /**\n * - The actual data point\n */\n element: T;\n /**\n * - Global index in the dataset\n */\n index: number;\n /**\n * - Distance from query\n */\n distance: number;\n};\nimport type { ParametersHNSW } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport type { Metric } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\n//# sourceMappingURL=HNSW.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersKDTree } from \"./index.js\" */\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} ElementWithIndex\n * @property {number} index\n * @property {T} element\n */\n/**\n * KD-Tree (K-dimensional Tree) for efficient nearest neighbor search.\n *\n * KD-Trees partition k-dimensional space by recursively splitting along coordinate axes.\n * At each level, the tree splits points based on the median of the coordinate with the largest spread.\n * This creates a balanced binary tree structure that enables efficient O(log n) search on average.\n *\n * Best suited for:\n * - Low to moderate dimensional data (d < 20-30)\n * - When exact nearest neighbors are needed\n * - When dimensionality is not too high\n *\n * Performance degrades in high dimensions (curse of dimensionality) where approximate\n * methods like HNSW or LSH become more effective.\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link https://en.wikipedia.org/wiki/K-d_tree}\n */\nexport class KDTree extends KNN {\n /**\n * Generates a KD-Tree with given `elements`.\n *\n * @param {T[]} elements - Elements which should be added to the KD-Tree\n * @param {ParametersKDTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}`\n */\n constructor(elements: T[], parameters?: ParametersKDTree);\n /**\n * @private\n * @type {KDTreeNode | KDTreeLeaf | null}\n */\n private _root;\n /** @returns {Metric} */\n get _metric(): Metric;\n /**\n * @private\n * @param {ElementWithIndex[]} elements\n * @param {number} depth - Current depth in the tree (determines splitting axis)\n * @returns {KDTreeNode | KDTreeLeaf | null} Root of KD-Tree.\n */\n private _construct;\n /**\n * @param {number} i\n * @param {number} k\n */\n search_by_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @param {T} t - Query element.\n * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors.\n */\n search(t: T, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @private\n * @param {T} target - Query element.\n * @param {number} k - Number of nearest neighbors to return.\n * @param {KDTreeNode | KDTreeLeaf | null} node - Current node.\n * @param {Heap<{ point: ElementWithIndex; distance: number }>} best - Heap of k best found so far.\n */\n private _search_recursive;\n}\nexport type ElementWithIndex = {\n index: number;\n element: T;\n};\nimport type { ParametersKDTree } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=KDTree.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersLSH } from \"./index.js\" */\n/**\n * Locality Sensitive Hashing (LSH) for approximate nearest neighbor search.\n *\n * LSH uses hash functions that map similar items to the same buckets with high probability.\n * This implementation uses Random Projection hashing (SimHash-style) which works well for\n * cosine similarity and Euclidean distance.\n *\n * Key concepts:\n * - Multiple hash tables increase recall probability\n * - Each hash function projects data onto random hyperplanes\n * - Points on the same side of hyperplanes are hashed together\n * - Combines results from all tables for better accuracy\n *\n * Best suited for:\n * - High-dimensional data where exact methods fail\n * - Approximate nearest neighbor needs\n * - Large datasets where linear scan is too slow\n * - When some false positives/negatives are acceptable\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link https://en.wikipedia.org/wiki/Locality-sensitive_hashing}\n */\nexport class LSH extends KNN {\n /**\n * Creates a new LSH index.\n *\n * @param {T[]} elements - Elements to index\n * @param {ParametersLSH} [parameters={}] - Configuration parameters\n */\n constructor(elements: T[], parameters?: ParametersLSH);\n _metric: Metric;\n _numHashTables: number;\n _numHashFunctions: number;\n _seed: number;\n _randomizer: Randomizer;\n /** @type {Map[]} */\n _hashTables: Map[];\n /** @type {Float64Array[][]} */\n _projections: Float64Array[][];\n /** @type {number[][]} */\n _offsets: number[][];\n /** @type {number} */\n _dim: number;\n /**\n * Initialize random projection vectors for all hash tables.\n * @private\n */\n private _initializeHashFunctions;\n /**\n * Compute hash signature for an element using random projections.\n * @private\n * @param {T} element\n * @param {number} tableIndex\n * @returns {string} Hash signature\n */\n private _computeHash;\n /**\n * Add elements to the LSH index.\n * @param {T[]} elements\n * @returns {this}\n */\n add(elements: T[]): this;\n /**\n * Search for k approximate nearest neighbors.\n * @param {T} query\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search(query: T, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @param {number} i\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n}\nimport type { ParametersLSH } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport type { Metric } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\n//# sourceMappingURL=LSH.d.ts.map","/** @import { ParametersNaiveKNN } from \"./index.js\" */\n/**\n * Naive KNN implementation using a distance matrix.\n *\n * This implementation pre-computes the entire distance matrix and performs\n * an exhaustive search. Best suited for small datasets or when a distance\n * matrix is already available.\n *\n * @template {number[] | Float64Array} T\n * @category KNN\n * @class\n * @extends KNN\n */\nexport class NaiveKNN extends KNN {\n /**\n * Generates a KNN list with given `elements`.\n *\n * @param {T[]} elements - Elements which should be added to the KNN list\n * @param {ParametersNaiveKNN} parameters\n */\n constructor(elements: T[], parameters?: ParametersNaiveKNN);\n _D: Matrix;\n /** @type {Heap<{ value: number; index: number }>[]} */\n KNN: Heap<{\n value: number;\n index: number;\n }>[];\n /**\n * @param {number} i\n * @param {number} k\n */\n search_by_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @param {T} t - Query element.\n * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors.\n */\n search(t: T, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n}\nimport type { ParametersNaiveKNN } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { Heap } from \"../datastructure/index.js\";\n//# sourceMappingURL=NaiveKNN.d.ts.map","/** @import {ParametersNNDescent} from \"./index.js\" */\n/**\n *\n * @template {number[] | Float64Array} T\n * @typedef {Object} NNDescentElement\n * @property {T} value\n * @property {number} index\n * @property {boolean} flag\n */\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} NNDescentNeighbor\n * @property {T} value\n * @property {number} index\n * @property {number} distance\n * @property {boolean} [flag]\n */\n/**\n * NN-Descent\n *\n * An efficient graph-based approximate nearest neighbor search algorithm.\n * It works by iteratively improving a neighbor graph using the fact that\n * \"neighbors of neighbors are likely to be neighbors\".\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf|NN-Descent Paper}\n */\nexport class NNDescent extends KNN {\n /**\n * @param {T[]} elements - Called V in paper.\n * @param {Partial} parameters\n * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf}\n */\n constructor(elements: T[], parameters?: Partial);\n /**\n * @private\n * @type {KNNHeap[]}\n */\n private _B;\n /**\n * @private\n * @type {NNDescentNeighbor[][]}\n */\n private nn;\n _N: number;\n _randomizer: Randomizer;\n _sample_size: number;\n _nndescent_elements: {\n value: T;\n index: number;\n flag: boolean;\n }[];\n /**\n * Samples Array A with sample size.\n *\n * @private\n * @template U\n * @param {U[]} A\n * @returns {U[]}\n */\n private _sample;\n /**\n * @private\n * @param {KNNHeap} B\n * @param {NNDescentNeighbor} u\n * @returns {number}\n */\n private _update;\n /**\n * @private\n * @param {(KNNHeap | null)[]} B\n * @returns {NNDescentNeighbor[][]}\n */\n private _reverse;\n /**\n * @param {T[]} elements\n * @returns {this}\n */\n add(elements: T[]): this;\n /**\n * @param {T} x\n * @param {number} [k=5] Default is `5`\n * @returns {{ element: T, index: number; distance: number }[]}\n */\n search(x: T, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @param {number} i\n * @param {number} [k=5] Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n}\nexport type NNDescentElement = {\n value: T;\n index: number;\n flag: boolean;\n};\nexport type NNDescentNeighbor = {\n value: T;\n index: number;\n distance: number;\n flag?: boolean | undefined;\n};\nexport type HeapEntry = {\n element: NNDescentNeighbor;\n value: number;\n};\nimport type { ParametersNNDescent } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport { Randomizer } from \"../util/index.js\";\n//# sourceMappingURL=NNDescent.d.ts.map","export { Annoy } from \"./Annoy.js\";\nexport { BallTree } from \"./BallTree.js\";\nexport { HNSW } from \"./HNSW.js\";\nexport { KDTree } from \"./KDTree.js\";\nexport { LSH } from \"./LSH.js\";\nexport { NaiveKNN } from \"./NaiveKNN.js\";\nexport { NNDescent } from \"./NNDescent.js\";\nexport type ParametersAnnoy = {\n /**\n * - Metric to use: (a, b) => distance. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Number of random projection trees to build. Default is `10`\n */\n numTrees: number;\n /**\n * - Maximum points per leaf node. Default is `10`\n */\n maxPointsPerLeaf: number;\n /**\n * - Seed for random number generator. Default is `1212`\n */\n seed: number;\n};\nexport type ParametersBallTree = {\n metric: Metric;\n seed: number;\n};\nexport type ParametersHNSW = {\n /**\n * - Metric to use: (a, b) => distance. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Use heuristics or naive selection. Default is `true`\n */\n heuristic: boolean;\n /**\n * - Max number of connections per element (excluding ground layer). Default is `16`\n */\n m: number;\n /**\n * - Size of candidate list during construction. Default is `200`\n */\n ef_construction: number;\n /**\n * - Max number of connections for ground layer (layer 0). Default is `2 * m`\n */\n m0: number | null;\n /**\n * - Normalization factor for level generation. Default is `1 / Math.log(m)`\n */\n mL: number | null;\n /**\n * - Seed for random number generator. Default is `1212`\n */\n seed: number;\n /**\n * - Size of candidate list during search. Default is `50`\n */\n ef: number;\n};\nexport type ParametersKDTree = {\n /**\n * - Metric to use: (a, b) => distance. Default is `euclidean`\n */\n metric: Metric;\n seed: number;\n};\nexport type ParametersLSH = {\n /**\n * - Metric to use: (a, b) => distance. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Number of hash tables. Default is `10`\n */\n numHashTables: number;\n /**\n * - Number of hash functions per table. Default is `10`\n */\n numHashFunctions: number;\n /**\n * - Seed for random number generator. Default is `1212`\n */\n seed: number;\n};\nexport type ParametersNaiveKNN = {\n /**\n * Is either precomputed or a function to use: (a, b) => distance\n */\n metric?: Metric | \"precomputed\" | undefined;\n seed?: number | undefined;\n};\nexport type ParametersNNDescent = {\n /**\n * - Called sigma in paper. Default is `euclidean`\n */\n metric: Metric;\n /**\n * =10 - Number of samples. Default is `10`\n */\n samples: number;\n /**\n * = .8 - Sample rate. Default is `.8`\n */\n rho: number;\n /**\n * = 0.0001 - Precision parameter. Default is `0.0001`\n */\n delta: number;\n /**\n * = 1212 - Seed for the random number generator. Default is `1212`\n */\n seed: number;\n};\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=index.d.ts.map","/**\n * Numerical stable summation with the Kahan summation algorithm.\n *\n * @category Numerical\n * @param {number[] | Float64Array} summands - Array of values to sum up.\n * @returns {number} The sum.\n * @see {@link https://en.wikipedia.org/wiki/Kahan_summation_algorithm}\n */\nexport function kahan_sum(summands: number[] | Float64Array): number;\n//# sourceMappingURL=kahan_sum.d.ts.map","/**\n * Numerical stable summation with the Neumair summation algorithm.\n *\n * @category Numerical\n * @param {number[] | Float64Array} summands - Array of values to sum up.\n * @returns {number} The sum.\n * @see {@link https://en.wikipedia.org/wiki/Kahan_summation_algorithm#Further_enhancements}\n */\nexport function neumair_sum(summands: number[] | Float64Array): number;\n//# sourceMappingURL=neumair_sum.d.ts.map","/**\n * @template {Float64Array | number[]} T\n * @category Optimization\n * @param {(d: T) => number} f\n * @param {T} x0\n * @param {number} [max_iter=300] Default is `300`\n * @returns {T}\n * @see http://optimization-js.github.io/optimization-js/optimization.js.html#line438\n */\nexport function powell(f: (d: T) => number, x0: T, max_iter?: number): T;\n//# sourceMappingURL=powell.d.ts.map","export * from \"./clustering/index.js\";\nexport * from \"./datastructure/index.js\";\nexport * from \"./dimred/index.js\";\nexport * from \"./knn/index.js\";\nexport * from \"./linear_algebra/index.js\";\nexport * from \"./matrix/index.js\";\nexport * from \"./metrics/index.js\";\nexport * from \"./numerical/index.js\";\nexport * from \"./optimization/index.js\";\nexport * from \"./util/index.js\";\nexport type InputType = Matrix | Float64Array[] | number[][];\nexport const version: string;\nimport type { Matrix } from \"./matrix/index.js\";\n//# sourceMappingURL=index.d.ts.map"],"names":["___knn_KNN_js.KNN","___matrix_index_js.Matrix"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,WAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,QAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,SAAA,eAAA,YAAA,gBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,MAAA,eAAA,YAAA,gBAAA,YAAA;;ACbP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,SAAA,eAAA,YAAA,gBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACO,iBAAA,iBAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,eAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,OAAA,eAAA,YAAA,gBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,SAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,OAAA,eAAA,YAAA,gBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,SAAA,eAAA,YAAA,gBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACO,iBAAA,cAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,WAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,IAAA,eAAA,YAAA,gBAAA,YAAA;;ACMA,KAAA,MAAA,kBAAA,YAAA,gBAAA,YAAA;;ACdP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,eAAA,IAAA,MAAA,GAAA,YAAA,0BAAA,MAAA,GAAA,MAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,mBAAA,IAAA,MAAA,sBAAA,MAAA;AACP;AACA;AACA;AACA;;ACdA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,QAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,GAAA,SAAA,QAAA;;ACPP;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,GAAA,SAAA,QAAA;;ACPP;AACA;AACA;AACA;AACO,cAAA,UAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7DA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAA,MAAA,GAAA,YAAA,kBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,YAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qCAAA,YAAA,wBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAA,MAAA,KAAA,MAAA,eAAA,UAAA,wBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAA,MAAA;AACA,WAAA,MAAA;AACA,WAAA,MAAA;AACA,UAAA,MAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,MAAA;AACA,WAAA,MAAA;AACA,WAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,MAAA;AACA,WAAA,YAAA;AACA,eAAA,YAAA;AACA,WAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,4DAAA,YAAA,GAAA,YAAA;AACA;AACA;AACA;AACA;AACA,kDAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oDAAA,QAAA;AACA;AACA;AACA,uCAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAA,SAAA,CAAA,YAAA,CAAA,eAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2CAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wDAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wDAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wDAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAA,MAAA,cAAA,YAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAA,MAAA,cAAA,YAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAA,MAAA,cAAA,YAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAA,MAAA,8CAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yDAAA,MAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uGAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0DAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,YAAA,wCAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,YAAA,wCAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,MAAA,cAAA,YAAA,iDAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAA,MAAA,GAAA,YAAA;AACA;AACA,QAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,MAAA,GAAA,YAAA;AACA;AACA,QAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,MAAA,GAAA,YAAA;AACA;AACA,QAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,MAAA,GAAA,YAAA;AACA;AACA,QAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oDAAA,QAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,KAAA,MAAA,CAAA,QAAA,KAAA,SAAA,CAAA,YAAA,CAAA,eAAA;AACA;AACO,KAAA,QAAA;;ACjdP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,IAAA,IAAA,MAAA,cAAA,YAAA,WAAA,MAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,SAAA,eAAA,YAAA,WAAA,MAAA,cAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACO,cAAA,UAAA;AACP;AACA;AACA;AACA;AACA;AACA,wBAAA,SAAA;AACA;AACA,aAAA,SAAA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,IAAA,SAAA,UAAA,CAAA,cAAA;AACP;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,sBAAA,SAAA,UAAA,CAAA,gCAAA;AACP;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,gCAAA;AACA;AACA,UAAA,OAAA;AACA;AACA,YAAA,YAAA,CAAA,WAAA;AACA,sBAAA,MAAA;AACA;AACA,aAAA,WAAA,CAAA,WAAA;AACA;AACA;AACA;AACA;AACA;AACA,kEAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA;AACA,cAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,OAAA,gBAAA,OAAA,iCAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,OAAA;AACA;AACA,UAAA,OAAA;AACA,WAAA,OAAA;AACA;AACA;AACA,cAAA,YAAA,CAAA,eAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8BAAA,OAAA,SAAA,OAAA,GAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,cAAA,OAAA;AACA;AACA;AACA;AACA;AACA,mBAAA,OAAA;AACA;;AClGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,SAAA,UAAA,CAAA,gBAAA;AACP;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,gBAAA;AACA;AACA,iBAAA,UAAA;AACA;AACA;AACA,wBAAA,YAAA,CAAA,eAAA;AACA;AACA;AACA;AACA,qBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,QAAA,SAAA,UAAA,CAAA,kBAAA;AACP;AACA;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,kBAAA;AACA,QAAA,YAAA,CAAA,eAAA;AACA;AACA,sBAAA,MAAA;AACA,iBAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,SAAA,SAAA,UAAA,CAAA,mBAAA;AACP;AACA;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,mBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,SAAA,UAAA,CAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,SAAA,UAAA,CAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,gBAAA;AACA,iBAAA,UAAA;AACA;AACA,kBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7FO,KAAA,gCAAA;AACP;AACA,YAAA,MAAA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAA,YAAA,CAAA,eAAA;AACA;AACO,KAAA,kBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,mBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;;ACnIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,WAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAA,GAAA;AACA;;AC1CA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,IAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oGAAA,UAAA,GAAA,IAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6GAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAA,IAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvHO,KAAA,UAAA;;ACFP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,EAAA,WAAA,SAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAA,SAAA,2CAAA,SAAA,CAAA,SAAA,EAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAA,SAAA,2CAAA,OAAA,CAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6DAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAA,MAAA;AACA;AACA,OAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,EAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yCAAA,OAAA;AACA;;AC5IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,OAAA,WAAA,SAAA,UAAA,EAAA,IAAA,iBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,iBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,iBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,sBAAA,OAAA,CAAA,iBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,OAAA,CAAA,iBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;;AC3DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,WAAA,SAAA,UAAA,EAAA,IAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wCAAA,GAAA,2BAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wCAAA,GAAA,2BAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+CAAA,YAAA,SAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sCAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA,eAAA,UAAA,CAAA,WAAA;AACA,eAAA,UAAA,CAAA,eAAA;AACA,eAAA,UAAA,CAAA,eAAA;AACA,aAAA,YAAA,CAAA,WAAA;AACA,aAAA,YAAA,CAAA,WAAA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAA,SAAA;AACA;;AC5IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,QAAA,WAAA,SAAA,UAAA,MAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,kBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,kBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,kBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,kBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,QAAA;AACA;AACA,oBAAA,GAAA;AACA;;AC5EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,WAAA,SAAA,UAAA,EAAA,IAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,gBAAA;AACA,cAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;;ACzDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,WAAA,SAAA,UAAA,EAAA,IAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA;AACA;AACA,kCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA;AACA;AACA,kCAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,OAAA,CAAA,aAAA;AACA,wBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,WAAA,SAAA,UAAA,EAAA,IAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,aAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,sBAAA,OAAA,CAAA,aAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,WAAA,SAAA,UAAA,EAAA,IAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA,YAAA,GAAA;AACA,QAAA,MAAA;AACA,QAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,IAAA,WAAA,SAAA,UAAA,EAAA,IAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,cAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,sBAAA,OAAA,CAAA,cAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,WAAA,SAAA,UAAA,EAAA,IAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAA,MAAA;AACA;AACA;AACA;;AC5DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,WAAA,SAAA,UAAA,EAAA,IAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,SAAA,sBAAA,OAAA,CAAA,aAAA,IAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAAA,MAAA;AACA,OAAA,MAAA;AACA;;AC5EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,WAAA,SAAA,UAAA,EAAA,IAAA,gBAAA,CAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,CAAA,aAAA,KAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,CAAA,aAAA,KAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,gBAAA,CAAA,aAAA;AACA;AACA,qBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA,4BAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,SAAA;AACA,aAAA,MAAA;AACA;AACO,KAAA,aAAA;AACA,KAAA,QAAA;AACP,SAAA,aAAA;AACA,SAAA,aAAA;AACA;AACA;;AC7EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,WAAA,SAAA,UAAA,EAAA,IAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;;ACpDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,WAAA,SAAA,UAAA,EAAA,IAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,gBAAA;AACA;AACA,yBAAA,YAAA,CAAA,eAAA,QAAA,YAAA;AACA,mBAAA,YAAA,CAAA,eAAA,MAAA,YAAA,CAAA,eAAA,mBAAA,YAAA;AACA,iBAAA,YAAA,CAAA,eAAA,MAAA,YAAA,CAAA,eAAA,MAAA,YAAA;AACA,gBAAA,YAAA,CAAA,eAAA,iBAAA,YAAA;AACA;AACA;AACA;AACA,gBAAA,MAAA;AACA,YAAA,MAAA;AACA;AACA;AACA,2CAAA,MAAA;AACA;AACA,wDAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAA,MAAA,SAAA,MAAA,gDAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAAA,YAAA,CAAA,eAAA,MAAA,YAAA,CAAA,eAAA,MAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAA,YAAA,CAAA,eAAA,QAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,2BAAA,YAAA,CAAA,eAAA,iBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,8BAAA,YAAA,CAAA,eAAA,MAAA,YAAA,CAAA,eAAA,mBAAA,YAAA;AACA;;ACjKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,OAAA,WAAA,SAAA,UAAA,EAAA,IAAA,iBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,iBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,iBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,sBAAA,OAAA,CAAA,iBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,OAAA,CAAA,iBAAA;AACA,sBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAA,WAAA,CAAA,YAAA,CAAA,eAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;;AC3IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,sBAAA,YAAA,eAAA,MAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,WAAA,SAAA,UAAA,EAAA,IAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA,eAAA,MAAA,eAAoCA,GAAuB,YAAA,YAAA;AAC3D;AACA;AACA;AACA,SAAA,GAAA,YAAA,YAAA,CAAA,eAAA;AACA,cAAA,MAAA;AACA,aAAA,YAAA,CAAA,WAAA;AACA;AACA;AACA,SAAA,MAAA;AACA,UAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,MAAA;AACA,iBAAA,YAAA,CAAA,WAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA,cAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,IAAA,WAAA,SAAA,UAAA,EAAA,IAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,cAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,cAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA,YAAA,MAAA;AACA,YAAA,MAAA;AACA,QAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,IAAA,WAAA,SAAA,UAAA,EAAA,IAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,cAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,cAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,IAAA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA,wBAAA,YAAA,CAAA,eAAA;AACA,iCAAA,YAAA,CAAA,WAAA;AACA,2BAAA,YAAA,CAAA,WAAA;AACA,oCAAA,YAAA,CAAA,WAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,aAAA,eAAA,YAAA,gBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,EAAA,IAAA,MAAA;AACP,OAAA,MAAA;AACA,OAAA,MAAA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,cAAA,IAAA,MAAA;AACP,OAAA,MAAA;AACA,OAAA,MAAA;AACA;;ACZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,2BAAA,IAAA,MAAA,kDAAA,SAAA;AACP,iBAAA,YAAA;AACA,kBAAA,YAAA;AACA;;ACXO,KAAA,eAAA,OAA2BC,MAA4B;AAC9D,OAAOA,MAA4B;AACnC,OAAOA,MAA4B;AACnC;AACO,KAAA,SAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAA,UAAA;AACA;AACA;AACA;AACA,SAAA,eAAA;AACA;AACA;AACA;AACA;AACA;;ACRO,KAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,iBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,OAAA,CAAA,SAAA;AACA;AACO,KAAA,aAAA;AACP;AACA;AACA;AACA,oBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,OAAA,CAAA,SAAA;AACA;AACO,KAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,OAAA,CAAA,SAAA;AACA;AACO,KAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,OAAA,CAAA,SAAA;AACA;AACO,KAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,OAAA,CAAA,SAAA;AACA;AACO,KAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,OAAA,CAAA,SAAA;AACA;AACO,KAAA,gBAAA,iBAAA,QAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAA,QAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,gBAAA;AACP;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,iBAAA;AACP;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,kBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtaA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,KAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,eAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,eAAA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA,iBAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,QAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,kBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,kBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,IAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,0CAAA,cAAA;AACA;AACA,aAAA,MAAA;AACA;AACA,aAAA,QAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAA,IAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAAA,IAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sDAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,SAAA;AACA;AAeO,KAAA,SAAA,sBAAA,YAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,aAAA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA,iBAAA,UAAA;AACA;AACA,iBAAA,GAAA;AACA;AACA,kBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,QAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,kBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,kBAAA;AACA,QAAA,MAAA;AACA;AACA,SAAA,IAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,SAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,mBAAA;AACP;AACA;AACA;AACA;AACA;AACA,4CAAA,OAAA,CAAA,mBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/FO,KAAA,eAAA;AACP;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,kBAAA;AACP,YAAA,MAAA;AACA;AACA;AACO,KAAA,cAAA;AACP;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACO,KAAA,aAAA;AACP;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,kBAAA;AACP;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACO,KAAA,mBAAA;AACP;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,SAAA,sBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,WAAA,sBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,MAAA,WAAA,YAAA;;ACCA,KAAA,SAAA,GAAA,MAAA,GAAA,YAAA;AACA,cAAA,OAAA;;;;"} \ No newline at end of file diff --git a/dist/druid.d.ts b/dist/druid.d.ts index d451669..2eff2e8 100644 --- a/dist/druid.d.ts +++ b/dist/druid.d.ts @@ -172,14 +172,10 @@ declare function distance_matrix(A: Matrix | Float64Array[] | number[][], metric * @param {Metric | "precomputed"} [metric=euclidean] Default is `euclidean` * @returns {{ i: number; j: number; distance: number }[][]} The kNN graph. */ -declare function k_nearest_neighbors( - A: Matrix, - k: number, - metric?: Metric | "precomputed", -): { - i: number; - j: number; - distance: number; +declare function k_nearest_neighbors(A: Matrix, k: number, metric?: Metric | "precomputed"): { + i: number; + j: number; + distance: number; }[][]; /** @@ -216,62 +212,62 @@ declare function min(values: Iterable): number; * @class */ declare class Randomizer { - /** - * @template T Returns samples from an input Matrix or Array. - * @param {T[]} A - The input Matrix or Array. - * @param {number} n - The number of samples. - * @param {number} seed - The seed for the random number generator. - * @returns {T[]} - A random selection form `A` of `n` samples. - */ - static choice(A: T[], n: number, seed?: number): T[]; - /** - * Mersenne Twister random number generator. - * - * @param {number} [_seed=new Date().getTime()] - The seed for the random number generator. If `_seed == null` then - * the actual time gets used as seed. Default is `new Date().getTime()` - * @see https://github.com/bmurray7/mersenne-twister-examples/blob/master/javascript-mersenne-twister.js - */ - constructor(_seed?: number); - _N: number; - _M: number; - _MATRIX_A: number; - _UPPER_MASK: number; - _LOWER_MASK: number; - /** @type {number[]} */ - _mt: number[]; - /** @type {number} */ - _mti: number; - /** @type {number} */ - _seed: number; - /** @type {number} seed */ - set seed(_seed: number); - /** - * Returns the seed of the random number generator. - * - * @returns {number} - The seed. - */ - get seed(): number; - /** - * Returns a float between 0 and 1. - * - * @returns {number} - A random number between [0, 1] - */ - get random(): number; - /** - * Returns an integer between 0 and MAX_INTEGER. - * - * @returns {number} - A random integer. - */ - get random_int(): number; - gauss_random(): number; - _val: number | null | undefined; - /** - * @template T Returns samples from an input Matrix or Array. - * @param {T[]} A - The input Matrix or Array. - * @param {number} n - The number of samples. - * @returns {T[]} A random selection form `A` of `n` samples. - */ - choice(A: T[], n: number): T[]; + /** + * @template T Returns samples from an input Matrix or Array. + * @param {T[]} A - The input Matrix or Array. + * @param {number} n - The number of samples. + * @param {number} seed - The seed for the random number generator. + * @returns {T[]} - A random selection form `A` of `n` samples. + */ + static choice(A: T[], n: number, seed?: number): T[]; + /** + * Mersenne Twister random number generator. + * + * @param {number} [_seed=new Date().getTime()] - The seed for the random number generator. If `_seed == null` then + * the actual time gets used as seed. Default is `new Date().getTime()` + * @see https://github.com/bmurray7/mersenne-twister-examples/blob/master/javascript-mersenne-twister.js + */ + constructor(_seed?: number); + _N: number; + _M: number; + _MATRIX_A: number; + _UPPER_MASK: number; + _LOWER_MASK: number; + /** @type {number[]} */ + _mt: number[]; + /** @type {number} */ + _mti: number; + /** @type {number} */ + _seed: number; + /** @type {number} seed */ + set seed(_seed: number); + /** + * Returns the seed of the random number generator. + * + * @returns {number} - The seed. + */ + get seed(): number; + /** + * Returns a float between 0 and 1. + * + * @returns {number} - A random number between [0, 1] + */ + get random(): number; + /** + * Returns an integer between 0 and MAX_INTEGER. + * + * @returns {number} - A random integer. + */ + get random_int(): number; + gauss_random(): number; + _val: number | null | undefined; + /** + * @template T Returns samples from an input Matrix or Array. + * @param {T[]} A - The input Matrix or Array. + * @param {number} n - The number of samples. + * @returns {T[]} A random selection form `A` of `n` samples. + */ + choice(A: T[], n: number): T[]; } /** @typedef {(i: number, j: number) => number} Accessor */ @@ -280,506 +276,464 @@ declare class Randomizer { * @category Matrix */ declare class Matrix { - /** - * Creates a Matrix out of `A`. - * @param {Matrix | Float64Array[] | number[][]} A - The matrix, array, or number, which should converted to a Matrix. - * @returns {Matrix} - * @example - * let A = Matrix.from([ [1, 0], [0, 1], ]); //creates a two by two identity matrix. - */ - static from(A: Matrix | Float64Array[] | number[][]): Matrix; - /** - * Creates a Matrix with the diagonal being the values of `v`. - * - * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]] - * - * @param {number[] | Float64Array} v - * @returns {Matrix} - */ - static from_diag(v: number[] | Float64Array): Matrix; - /** - * Creates a Matrix with the diagonal being the values of `v`. - * - * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]] - * - * @param {number[] | Float64Array} v - * @param {"col" | "row"} type - * @returns {Matrix} - */ - static from_vector(v: number[] | Float64Array, type: "col" | "row"): Matrix; - /** - * Solves the equation `Ax = b` using the conjugate gradient method. Returns the result `x`. - * - * @param {Matrix} A - Matrix - * @param {Matrix} b - Matrix - * @param {Randomizer | null} [randomizer] - * @param {number} [tol=1e-3] Default is `1e-3` - * @returns {Matrix} - */ - static solve_CG(A: Matrix, b: Matrix, randomizer?: Randomizer | null, tol?: number): Matrix; - /** - * Solves the equation `Ax = b`. Returns the result `x`. - * - * @param {Matrix | { L: Matrix; U: Matrix }} A - Matrix or LU Decomposition - * @param {Matrix} b - Matrix - * @returns {Matrix} - */ - static solve( - A: - | Matrix - | { - L: Matrix; - U: Matrix; - }, - b: Matrix, - ): Matrix; - /** - * `LU` decomposition of the Matrix `A`. Creates two matrices, so that the dot product `LU` equals `A`. - * - * @param {Matrix} A - * @returns {{ L: Matrix; U: Matrix }} The left triangle matrix `L` and the upper triangle matrix `U`. - */ - static LU(A: Matrix): { - L: Matrix; - U: Matrix; - }; - /** - * Computes the determinante of `A`, by using the `LU` decomposition of `A`. - * - * @param {Matrix} A - * @returns {number} The determinate of the Matrix `A`. - */ - static det(A: Matrix): number; - /** - * Computes the `k` components of the SVD decomposition of the matrix `M`. - * - * @param {Matrix} M - * @param {number} [k=2] Default is `2` - * @returns {{ U: Float64Array[]; Sigma: Float64Array; V: Float64Array[] }} - */ - static SVD( - M: Matrix, - k?: number, - ): { - U: Float64Array[]; - Sigma: Float64Array; - V: Float64Array[]; - }; - /** - * @param {unknown} A - * @returns {A is unknown[]|number[]|Float64Array|Float32Array} - */ - static isArray(A: unknown): A is unknown[] | number[] | Float64Array | Float32Array; - /** - * @param {any[]} A - * @returns {A is number[][]|Float64Array[]} - */ - static is2dArray(A: any[]): A is number[][] | Float64Array[]; - /** - * Creates a new Matrix. Entries are stored in a Float64Array. - * - * @example let A = new Matrix(10, 10, () => Math.random()); //creates a 10 times 10 random matrix. let B = new - * Matrix(3, 3, "I"); // creates a 3 times 3 identity matrix. - * - * @param {number} rows - The amount of rows of the matrix. - * @param {number} cols - The amount of columns of the matrix. - * @param {Accessor | string | number} value - Can be a function with row and col as parameters, a number, or - * "zeros", "identity" or "I", or "center". - * - * - **function**: for each entry the function gets called with the parameters for the actual row and column. - * - **string**: allowed are - * - * - "zero", creates a zero matrix. - * - "identity" or "I", creates an identity matrix. - * - "center", creates an center matrix. - * - **number**: create a matrix filled with the given value. - */ - constructor(rows: number, cols: number, value?: Accessor | string | number); - /** @type {number} */ _rows: number; - /** @type {number} */ _cols: number; - /** @type {Float64Array} */ _data: Float64Array; - /** - * Returns the `row`th row from the Matrix. - * - * @param {number} row - * @returns {Float64Array} - */ - row(row: number): Float64Array; - /** - * Returns an generator yielding each row of the Matrix. - * - * @yields {Float64Array} - */ - iterate_rows(): Generator, void, unknown>; - /** - * Sets the entries of `row`th row from the Matrix to the entries from `values`. - * - * @param {number} row - * @param {number[]} values - * @returns {Matrix} - */ - set_row(row: number, values: number[]): Matrix; - /** - * Swaps the rows `row1` and `row2` of the Matrix. - * - * @param {number} row1 - * @param {number} row2 - * @returns {Matrix} - */ - swap_rows(row1: number, row2: number): Matrix; - /** - * Returns the colth column from the Matrix. - * - * @param {number} col - * @returns {Float64Array} - */ - col(col: number): Float64Array; - /** - * Returns the `col`th entry from the `row`th row of the Matrix. - * - * @param {number} row - * @param {number} col - * @returns {number} - */ - entry(row: number, col: number): number; - /** - * Sets the {@link col}th entry from the {@link row}th row of the Matrix to the given - * {@link value}. - * - * @param {number} row - * @param {number} col - * @param {number} value - * @returns {Matrix} - */ - set_entry(row: number, col: number, value: number): Matrix; - /** - * Adds a given {@link value} to the {@link col}th entry from the {@link row}th row of the - * Matrix. - * - * @param {number} row - * @param {number} col - * @param {number} value - * @returns {Matrix} - */ - add_entry(row: number, col: number, value: number): Matrix; - /** - * Subtracts a given {@link value} from the {@link col}th entry from the {@link row}th row of the - * Matrix. - * - * @param {number} row - * @param {number} col - * @param {number} value - * @returns {Matrix} - */ - sub_entry(row: number, col: number, value: number): Matrix; - /** - * Returns a new transposed Matrix. - * - * @returns {Matrix} - */ - transpose(): Matrix; - /** - * Returns a new transposed Matrix. Short-form of `transpose`. - * - * @returns {Matrix} - */ - get T(): Matrix; - /** - * Returns the inverse of the Matrix. - * - * @returns {Matrix} - */ - inverse(): Matrix; - /** - * Returns the dot product. If `B` is an Array or Float64Array then an Array gets returned. If `B` is a Matrix then - * a Matrix gets returned. - * - * @param {Matrix | number[] | Float64Array} B The right side - * @returns {Matrix} - */ - dot(B: Matrix | number[] | Float64Array): Matrix; - /** - * Transposes the current matrix and returns the dot product with `B`. If `B` is an Array or Float64Array then an - * Array gets returned. If `B` is a Matrix then a Matrix gets returned. - * - * @param {Matrix | number[] | Float64Array} B The right side - * @returns {Matrix} - */ - transDot(B: Matrix | number[] | Float64Array): Matrix; - /** - * Returns the dot product with the transposed version of `B`. If `B` is an Array or Float64Array then an Array gets - * returned. If `B` is a Matrix then a Matrix gets returned. - * - * @param {Matrix | number[] | Float64Array} B The right side - * @returns {Matrix} - */ - dotTrans(B: Matrix | number[] | Float64Array): Matrix; - /** - * Computes the outer product from `this` and `B`. - * - * @param {Matrix} B - * @returns {Matrix} - */ - outer(B: Matrix): Matrix; - /** - * Appends matrix `B` to the matrix. - * - * @example let A = Matrix.from([ [1, 1], [1, 1], ]); // 2 by 2 matrix filled with ones. let B = Matrix.from([ [2, - * 2], [2, 2], ]); // 2 by 2 matrix filled with twos. - * - * A.concat(B, "horizontal"); // 2 by 4 matrix. [[1, 1, 2, 2], [1, 1, 2, 2]] - * A.concat(B, "vertical"); // 4 by 2 matrix. [[1, 1], [1, 1], [2, 2], [2, 2]] - * A.concat(B, "diag"); // 4 by 4 matrix. [[1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 2, 2], [0, 0, 2, 2]] - * - * @param {Matrix} B - Matrix to append. - * @param {"horizontal" | "vertical" | "diag"} [type="horizontal"] - Type of concatenation. Default is - * `"horizontal"` - * @returns {Matrix} - */ - concat(B: Matrix, type?: "horizontal" | "vertical" | "diag"): Matrix; - /** - * Writes the entries of B in A at an offset position given by `offset_row` and `offset_col`. - * - * @param {number} offset_row - * @param {number} offset_col - * @param {Matrix} B - * @returns {Matrix} - */ - set_block(offset_row: number, offset_col: number, B: Matrix): Matrix; - /** - * Extracts the entries from the `start_row`th row to the `end_row`th row, the - * `start_col`th column to the `end_col`th column of the matrix. If `end_row` or `end_col` is - * empty, the respective value is set to `this.rows` or `this.cols`. - * - * @example let A = Matrix.from([ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]); // a 3 by 3 matrix. - * - * A.get_block(1, 1); // [[5, 6], [8, 9]] - * A.get_block(0, 0, 1, 1); // [[1]] - * A.get_block(1, 1, 2, 2); // [[5]] - * A.get_block(0, 0, 2, 2); // [[1, 2], [4, 5]] - * - * @param {number} start_row - * @param {number} start_col - * @param {number | null} [end_row] - * @param {number | null} [end_col] - * @returns {Matrix} Returns a `end_row` - `start_row` times `end_col` - `start_col` matrix, with respective entries - * from the matrix. - */ - get_block( - start_row: number, - start_col: number, - end_row?: number | null, - end_col?: number | null, - ): Matrix; - /** - * Returns a new array gathering entries defined by the indices given by argument. - * - * @param {number[]} row_indices - Array consists of indices of rows for gathering entries of this matrix - * @param {number[]} col_indices - Array consists of indices of cols for gathering entries of this matrix - * @returns {Matrix} - */ - gather(row_indices: number[], col_indices: number[]): Matrix; - /** - * Applies a function to each entry of the matrix. - * - * @private - * @param {(d: number, v: number) => number} f Function takes 2 parameters, the value of the actual entry and a - * value given by the function `v`. The result of `f` gets writen to the Matrix. - * @param {Accessor} v Function takes 2 parameters for `row` and `col`, and returns a value witch should be applied - * to the `col`th entry of the `row`th row of the matrix. - * @returns {Matrix} - */ - private _apply_array; - /** - * @param {number[] | Float64Array} values - * @param {(d: number, v: number) => number} f - * @returns {Matrix} - */ - _apply_rowwise_array( - values: number[] | Float64Array, - f: (d: number, v: number) => number, - ): Matrix; - /** - * @param {number[] | Float64Array} values - * @param {(d: number, v: number) => number} f - * @returns {Matrix} - */ - _apply_colwise_array( - values: number[] | Float64Array, - f: (d: number, v: number) => number, - ): Matrix; - /** - * @param {Matrix | number[] | Float64Array | number} value - * @param {(d: number, v: number) => number} f - * @returns {Matrix} - */ - _apply( - value: Matrix | number[] | Float64Array | number, - f: (d: number, v: number) => number, - ): Matrix; - /** - * Clones the Matrix. - * - * @returns {Matrix} - */ - clone(): Matrix; - /** - * Entrywise multiplication with `value`. - * - * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; - * - * A.mult(2); // [[2, 4], [6, 8]]; - * A.mult(B); // [[1, 4], [9, 16]]; - * - * @param {Matrix | Float64Array | number[] | number} value - * @param {Object} [options] - * @param {boolean} [options.inline=false] - If true, applies multiplication to the element, otherwise it creates - * first a copy and applies the multiplication on the copy. Default is `false` - * @returns {Matrix} - */ - mult( - value: Matrix | Float64Array | number[] | number, - { - inline, - }?: { - inline?: boolean | undefined; - }, - ): Matrix; - /** - * Entrywise division with `value`. - * - * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; - * - * A.divide(2); // [[0.5, 1], [1.5, 2]]; - * A.divide(B); // [[1, 1], [1, 1]]; - * - * @param {Matrix | Float64Array | number[] | number} value - * @param {Object} [options] - * @param {Boolean} [options.inline=false] - If true, applies division to the element, otherwise it creates first a - * copy and applies the division on the copy. Default is `false` - * @returns {Matrix} - */ - divide( - value: Matrix | Float64Array | number[] | number, - { - inline, - }?: { - inline?: boolean | undefined; - }, - ): Matrix; - /** - * Entrywise addition with `value`. - * - * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; - * - * A.add(2); // [[3, 4], [5, 6]]; - * A.add(B); // [[2, 4], [6, 8]]; - * - * @param {Matrix | Float64Array | number[] | number} value - * @param {Object} [options] - * @param {boolean} [options.inline=false] - If true, applies addition to the element, otherwise it creates first a - * copy and applies the addition on the copy. Default is `false` - * @returns {Matrix} - */ - add( - value: Matrix | Float64Array | number[] | number, - { - inline, - }?: { - inline?: boolean | undefined; - }, - ): Matrix; - /** - * Entrywise subtraction with `value`. - * - * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; - * - * A.sub(2); // [[-1, 0], [1, 2]]; - * A.sub(B); // [[0, 0], [0, 0]]; - * - * @param {Matrix | Float64Array | number[] | number} value - * @param {Object} [options] - * @param {boolean} [options.inline=false] - If true, applies subtraction to the element, otherwise it creates first - * a copy and applies the subtraction on the copy. Default is `false` - * @returns {Matrix} - */ - sub( - value: Matrix | Float64Array | number[] | number, - { - inline, - }?: { - inline?: boolean | undefined; - }, - ): Matrix; - /** - * Returns the matrix in the given shape with the given function which returns values for the entries of the matrix. - * - * @param {[number, number, Accessor]} parameter - Takes an Array in the form [rows, cols, value], where rows and - * cols are the number of rows and columns of the matrix, and value is a function which takes two parameters (row - * and col) which has to return a value for the colth entry of the rowth row. - * @returns {Matrix} - */ - set shape([rows, cols, value]: [number, number, Accessor]); - /** - * Returns the number of rows and columns of the Matrix. - * - * @returns {number[]} An Array in the form [rows, columns]. - */ - get shape(): number[]; - /** - * Returns the Matrix as a Array of Float64Arrays. - * - * @returns {Float64Array[]} - */ - to2dArray(): Float64Array[]; - /** - * Returns the Matrix as a Array of Arrays. - * - * @returns {number[][]} - */ - asArray(): number[][]; - /** - * Returns the diagonal of the Matrix. - * - * @returns {Float64Array} - */ - diag(): Float64Array; - /** - * Returns the mean of all entries of the Matrix. - * - * @returns {number} - */ - mean(): number; - /** - * Returns the sum oof all entries of the Matrix. - * - * @returns {number} - */ - sum(): number; - /** - * Returns the entries of the Matrix. - * - * @returns {Float64Array} - */ - get values(): Float64Array; - /** - * Returns the mean of each row of the matrix. - * - * @returns {Float64Array} - */ - meanRows(): Float64Array; - /** - * Returns the mean of each column of the matrix. - * - * @returns {Float64Array} - */ - meanCols(): Float64Array; - /** - * Makes a `Matrix` object an iterable object. - * - * @yields {Float64Array} - */ - [Symbol.iterator](): Generator, void, unknown>; + /** + * Creates a Matrix out of `A`. + * @param {Matrix | Float64Array[] | number[][]} A - The matrix, array, or number, which should converted to a Matrix. + * @returns {Matrix} + * @example + * let A = Matrix.from([ [1, 0], [0, 1], ]); //creates a two by two identity matrix. + */ + static from(A: Matrix | Float64Array[] | number[][]): Matrix; + /** + * Creates a Matrix with the diagonal being the values of `v`. + * + * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]] + * + * @param {number[] | Float64Array} v + * @returns {Matrix} + */ + static from_diag(v: number[] | Float64Array): Matrix; + /** + * Creates a Matrix with the diagonal being the values of `v`. + * + * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]] + * + * @param {number[] | Float64Array} v + * @param {"col" | "row"} type + * @returns {Matrix} + */ + static from_vector(v: number[] | Float64Array, type: "col" | "row"): Matrix; + /** + * Solves the equation `Ax = b` using the conjugate gradient method. Returns the result `x`. + * + * @param {Matrix} A - Matrix + * @param {Matrix} b - Matrix + * @param {Randomizer | null} [randomizer] + * @param {number} [tol=1e-3] Default is `1e-3` + * @returns {Matrix} + */ + static solve_CG(A: Matrix, b: Matrix, randomizer?: Randomizer | null, tol?: number): Matrix; + /** + * Solves the equation `Ax = b`. Returns the result `x`. + * + * @param {Matrix | { L: Matrix; U: Matrix }} A - Matrix or LU Decomposition + * @param {Matrix} b - Matrix + * @returns {Matrix} + */ + static solve(A: Matrix | { + L: Matrix; + U: Matrix; + }, b: Matrix): Matrix; + /** + * `LU` decomposition of the Matrix `A`. Creates two matrices, so that the dot product `LU` equals `A`. + * + * @param {Matrix} A + * @returns {{ L: Matrix; U: Matrix }} The left triangle matrix `L` and the upper triangle matrix `U`. + */ + static LU(A: Matrix): { + L: Matrix; + U: Matrix; + }; + /** + * Computes the determinante of `A`, by using the `LU` decomposition of `A`. + * + * @param {Matrix} A + * @returns {number} The determinate of the Matrix `A`. + */ + static det(A: Matrix): number; + /** + * Computes the `k` components of the SVD decomposition of the matrix `M`. + * + * @param {Matrix} M + * @param {number} [k=2] Default is `2` + * @returns {{ U: Float64Array[]; Sigma: Float64Array; V: Float64Array[] }} + */ + static SVD(M: Matrix, k?: number): { + U: Float64Array[]; + Sigma: Float64Array; + V: Float64Array[]; + }; + /** + * @param {unknown} A + * @returns {A is unknown[]|number[]|Float64Array|Float32Array} + */ + static isArray(A: unknown): A is unknown[] | number[] | Float64Array | Float32Array; + /** + * @param {any[]} A + * @returns {A is number[][]|Float64Array[]} + */ + static is2dArray(A: any[]): A is number[][] | Float64Array[]; + /** + * Creates a new Matrix. Entries are stored in a Float64Array. + * + * @example let A = new Matrix(10, 10, () => Math.random()); //creates a 10 times 10 random matrix. let B = new + * Matrix(3, 3, "I"); // creates a 3 times 3 identity matrix. + * + * @param {number} rows - The amount of rows of the matrix. + * @param {number} cols - The amount of columns of the matrix. + * @param {Accessor | string | number} value - Can be a function with row and col as parameters, a number, or + * "zeros", "identity" or "I", or "center". + * + * - **function**: for each entry the function gets called with the parameters for the actual row and column. + * - **string**: allowed are + * + * - "zero", creates a zero matrix. + * - "identity" or "I", creates an identity matrix. + * - "center", creates an center matrix. + * - **number**: create a matrix filled with the given value. + */ + constructor(rows: number, cols: number, value?: Accessor | string | number); + /** @type {number} */ _rows: number; + /** @type {number} */ _cols: number; + /** @type {Float64Array} */ _data: Float64Array; + /** + * Returns the `row`th row from the Matrix. + * + * @param {number} row + * @returns {Float64Array} + */ + row(row: number): Float64Array; + /** + * Returns an generator yielding each row of the Matrix. + * + * @yields {Float64Array} + */ + iterate_rows(): Generator, void, unknown>; + /** + * Sets the entries of `row`th row from the Matrix to the entries from `values`. + * + * @param {number} row + * @param {number[]} values + * @returns {Matrix} + */ + set_row(row: number, values: number[]): Matrix; + /** + * Swaps the rows `row1` and `row2` of the Matrix. + * + * @param {number} row1 + * @param {number} row2 + * @returns {Matrix} + */ + swap_rows(row1: number, row2: number): Matrix; + /** + * Returns the colth column from the Matrix. + * + * @param {number} col + * @returns {Float64Array} + */ + col(col: number): Float64Array; + /** + * Returns the `col`th entry from the `row`th row of the Matrix. + * + * @param {number} row + * @param {number} col + * @returns {number} + */ + entry(row: number, col: number): number; + /** + * Sets the {@link col}th entry from the {@link row}th row of the Matrix to the given + * {@link value}. + * + * @param {number} row + * @param {number} col + * @param {number} value + * @returns {Matrix} + */ + set_entry(row: number, col: number, value: number): Matrix; + /** + * Adds a given {@link value} to the {@link col}th entry from the {@link row}th row of the + * Matrix. + * + * @param {number} row + * @param {number} col + * @param {number} value + * @returns {Matrix} + */ + add_entry(row: number, col: number, value: number): Matrix; + /** + * Subtracts a given {@link value} from the {@link col}th entry from the {@link row}th row of the + * Matrix. + * + * @param {number} row + * @param {number} col + * @param {number} value + * @returns {Matrix} + */ + sub_entry(row: number, col: number, value: number): Matrix; + /** + * Returns a new transposed Matrix. + * + * @returns {Matrix} + */ + transpose(): Matrix; + /** + * Returns a new transposed Matrix. Short-form of `transpose`. + * + * @returns {Matrix} + */ + get T(): Matrix; + /** + * Returns the inverse of the Matrix. + * + * @returns {Matrix} + */ + inverse(): Matrix; + /** + * Returns the dot product. If `B` is an Array or Float64Array then an Array gets returned. If `B` is a Matrix then + * a Matrix gets returned. + * + * @param {Matrix | number[] | Float64Array} B The right side + * @returns {Matrix} + */ + dot(B: Matrix | number[] | Float64Array): Matrix; + /** + * Transposes the current matrix and returns the dot product with `B`. If `B` is an Array or Float64Array then an + * Array gets returned. If `B` is a Matrix then a Matrix gets returned. + * + * @param {Matrix | number[] | Float64Array} B The right side + * @returns {Matrix} + */ + transDot(B: Matrix | number[] | Float64Array): Matrix; + /** + * Returns the dot product with the transposed version of `B`. If `B` is an Array or Float64Array then an Array gets + * returned. If `B` is a Matrix then a Matrix gets returned. + * + * @param {Matrix | number[] | Float64Array} B The right side + * @returns {Matrix} + */ + dotTrans(B: Matrix | number[] | Float64Array): Matrix; + /** + * Computes the outer product from `this` and `B`. + * + * @param {Matrix} B + * @returns {Matrix} + */ + outer(B: Matrix): Matrix; + /** + * Appends matrix `B` to the matrix. + * + * @example let A = Matrix.from([ [1, 1], [1, 1], ]); // 2 by 2 matrix filled with ones. let B = Matrix.from([ [2, + * 2], [2, 2], ]); // 2 by 2 matrix filled with twos. + * + * A.concat(B, "horizontal"); // 2 by 4 matrix. [[1, 1, 2, 2], [1, 1, 2, 2]] + * A.concat(B, "vertical"); // 4 by 2 matrix. [[1, 1], [1, 1], [2, 2], [2, 2]] + * A.concat(B, "diag"); // 4 by 4 matrix. [[1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 2, 2], [0, 0, 2, 2]] + * + * @param {Matrix} B - Matrix to append. + * @param {"horizontal" | "vertical" | "diag"} [type="horizontal"] - Type of concatenation. Default is + * `"horizontal"` + * @returns {Matrix} + */ + concat(B: Matrix, type?: "horizontal" | "vertical" | "diag"): Matrix; + /** + * Writes the entries of B in A at an offset position given by `offset_row` and `offset_col`. + * + * @param {number} offset_row + * @param {number} offset_col + * @param {Matrix} B + * @returns {Matrix} + */ + set_block(offset_row: number, offset_col: number, B: Matrix): Matrix; + /** + * Extracts the entries from the `start_row`th row to the `end_row`th row, the + * `start_col`th column to the `end_col`th column of the matrix. If `end_row` or `end_col` is + * empty, the respective value is set to `this.rows` or `this.cols`. + * + * @example let A = Matrix.from([ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]); // a 3 by 3 matrix. + * + * A.get_block(1, 1); // [[5, 6], [8, 9]] + * A.get_block(0, 0, 1, 1); // [[1]] + * A.get_block(1, 1, 2, 2); // [[5]] + * A.get_block(0, 0, 2, 2); // [[1, 2], [4, 5]] + * + * @param {number} start_row + * @param {number} start_col + * @param {number | null} [end_row] + * @param {number | null} [end_col] + * @returns {Matrix} Returns a `end_row` - `start_row` times `end_col` - `start_col` matrix, with respective entries + * from the matrix. + */ + get_block(start_row: number, start_col: number, end_row?: number | null, end_col?: number | null): Matrix; + /** + * Returns a new array gathering entries defined by the indices given by argument. + * + * @param {number[]} row_indices - Array consists of indices of rows for gathering entries of this matrix + * @param {number[]} col_indices - Array consists of indices of cols for gathering entries of this matrix + * @returns {Matrix} + */ + gather(row_indices: number[], col_indices: number[]): Matrix; + /** + * Applies a function to each entry of the matrix. + * + * @private + * @param {(d: number, v: number) => number} f Function takes 2 parameters, the value of the actual entry and a + * value given by the function `v`. The result of `f` gets writen to the Matrix. + * @param {Accessor} v Function takes 2 parameters for `row` and `col`, and returns a value witch should be applied + * to the `col`th entry of the `row`th row of the matrix. + * @returns {Matrix} + */ + private _apply_array; + /** + * @param {number[] | Float64Array} values + * @param {(d: number, v: number) => number} f + * @returns {Matrix} + */ + _apply_rowwise_array(values: number[] | Float64Array, f: (d: number, v: number) => number): Matrix; + /** + * @param {number[] | Float64Array} values + * @param {(d: number, v: number) => number} f + * @returns {Matrix} + */ + _apply_colwise_array(values: number[] | Float64Array, f: (d: number, v: number) => number): Matrix; + /** + * @param {Matrix | number[] | Float64Array | number} value + * @param {(d: number, v: number) => number} f + * @returns {Matrix} + */ + _apply(value: Matrix | number[] | Float64Array | number, f: (d: number, v: number) => number): Matrix; + /** + * Clones the Matrix. + * + * @returns {Matrix} + */ + clone(): Matrix; + /** + * Entrywise multiplication with `value`. + * + * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; + * + * A.mult(2); // [[2, 4], [6, 8]]; + * A.mult(B); // [[1, 4], [9, 16]]; + * + * @param {Matrix | Float64Array | number[] | number} value + * @param {Object} [options] + * @param {boolean} [options.inline=false] - If true, applies multiplication to the element, otherwise it creates + * first a copy and applies the multiplication on the copy. Default is `false` + * @returns {Matrix} + */ + mult(value: Matrix | Float64Array | number[] | number, { inline }?: { + inline?: boolean | undefined; + }): Matrix; + /** + * Entrywise division with `value`. + * + * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; + * + * A.divide(2); // [[0.5, 1], [1.5, 2]]; + * A.divide(B); // [[1, 1], [1, 1]]; + * + * @param {Matrix | Float64Array | number[] | number} value + * @param {Object} [options] + * @param {Boolean} [options.inline=false] - If true, applies division to the element, otherwise it creates first a + * copy and applies the division on the copy. Default is `false` + * @returns {Matrix} + */ + divide(value: Matrix | Float64Array | number[] | number, { inline }?: { + inline?: boolean | undefined; + }): Matrix; + /** + * Entrywise addition with `value`. + * + * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; + * + * A.add(2); // [[3, 4], [5, 6]]; + * A.add(B); // [[2, 4], [6, 8]]; + * + * @param {Matrix | Float64Array | number[] | number} value + * @param {Object} [options] + * @param {boolean} [options.inline=false] - If true, applies addition to the element, otherwise it creates first a + * copy and applies the addition on the copy. Default is `false` + * @returns {Matrix} + */ + add(value: Matrix | Float64Array | number[] | number, { inline }?: { + inline?: boolean | undefined; + }): Matrix; + /** + * Entrywise subtraction with `value`. + * + * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; + * + * A.sub(2); // [[-1, 0], [1, 2]]; + * A.sub(B); // [[0, 0], [0, 0]]; + * + * @param {Matrix | Float64Array | number[] | number} value + * @param {Object} [options] + * @param {boolean} [options.inline=false] - If true, applies subtraction to the element, otherwise it creates first + * a copy and applies the subtraction on the copy. Default is `false` + * @returns {Matrix} + */ + sub(value: Matrix | Float64Array | number[] | number, { inline }?: { + inline?: boolean | undefined; + }): Matrix; + /** + * Returns the matrix in the given shape with the given function which returns values for the entries of the matrix. + * + * @param {[number, number, Accessor]} parameter - Takes an Array in the form [rows, cols, value], where rows and + * cols are the number of rows and columns of the matrix, and value is a function which takes two parameters (row + * and col) which has to return a value for the colth entry of the rowth row. + * @returns {Matrix} + */ + set shape([rows, cols, value]: [number, number, Accessor]); + /** + * Returns the number of rows and columns of the Matrix. + * + * @returns {number[]} An Array in the form [rows, columns]. + */ + get shape(): number[]; + /** + * Returns the Matrix as a Array of Float64Arrays. + * + * @returns {Float64Array[]} + */ + to2dArray(): Float64Array[]; + /** + * Returns the Matrix as a Array of Arrays. + * + * @returns {number[][]} + */ + asArray(): number[][]; + /** + * Returns the diagonal of the Matrix. + * + * @returns {Float64Array} + */ + diag(): Float64Array; + /** + * Returns the mean of all entries of the Matrix. + * + * @returns {number} + */ + mean(): number; + /** + * Returns the sum oof all entries of the Matrix. + * + * @returns {number} + */ + sum(): number; + /** + * Returns the entries of the Matrix. + * + * @returns {Float64Array} + */ + get values(): Float64Array; + /** + * Returns the mean of each row of the matrix. + * + * @returns {Float64Array} + */ + meanRows(): Float64Array; + /** + * Returns the mean of each column of the matrix. + * + * @returns {Float64Array} + */ + meanCols(): Float64Array; + /** + * Makes a `Matrix` object an iterable object. + * + * @yields {Float64Array} + */ + [Symbol.iterator](): Generator, void, unknown>; } type Accessor = (i: number, j: number) => number; @@ -811,34 +765,34 @@ declare function normalize(v: number[] | Float64Array, metric?: Metric): number[ * @template Para */ declare class Clustering { - /** - * Compute the respective Clustering with given parameters - * @param {InputType} points - * @param {Para} parameters - */ - constructor(points: InputType, parameters: Para); - /** @type {InputType} */ - _points: InputType; - /** @type {Para} */ - _parameters: Para; - /** @type {Matrix} */ - _matrix: Matrix; - /** @type {number} */ - _N: number; - /** @type {number} */ - _D: number; - /** - * @abstract - * @param {...unknown} args - * @returns {number[][]} An array with the indices of the clusters. - */ - get_clusters(...args: unknown[]): number[][]; - /** - * @abstract - * @param {...unknown} args - * @returns {number[]} An array with the clusters id's for each point. - */ - get_cluster_list(...args: unknown[]): number[]; + /** + * Compute the respective Clustering with given parameters + * @param {InputType} points + * @param {Para} parameters + */ + constructor(points: InputType, parameters: Para); + /** @type {InputType} */ + _points: InputType; + /** @type {Para} */ + _parameters: Para; + /** @type {Matrix} */ + _matrix: Matrix; + /** @type {number} */ + _N: number; + /** @type {number} */ + _D: number; + /** + * @abstract + * @param {...unknown} args + * @returns {number[][]} An array with the indices of the clusters. + */ + get_clusters(...args: unknown[]): number[][]; + /** + * @abstract + * @param {...unknown} args + * @returns {number[]} An array with the clusters id's for each point. + */ + get_cluster_list(...args: unknown[]): number[]; } /** @import { InputType } from "../index.js" */ @@ -854,69 +808,69 @@ declare class Clustering { * @category Clustering */ declare class CURE extends Clustering { - /** - * @param {InputType} points - * @param {Partial} parameters - */ - constructor(points: InputType, parameters?: Partial); - /** @type {number} */ - _K: number; - /** @type {number} */ - _num_representatives: number; - /** @type {number} */ - _shrink_factor: number; - /** - * @private - * @type {CURECluster[]} - */ - private _clusters; - /** @type {number[]} */ - _cluster_ids: number[]; - /** - * Initialize each point as its own cluster - * @private - */ - private _initialize_clusters; - /** - * Compute distance between two clusters using representative points - * @private - * @param {CURECluster} cluster1 - * @param {CURECluster} cluster2 - * @returns {number} - */ - private _cluster_distance; - /** - * Find the closest pair of clusters - * @private - * @returns {[number, number, number]} [index1, index2, distance] - */ - private _find_closest_clusters; - /** - * Merge two clusters - * @private - * @param {CURECluster} cluster1 - * @param {CURECluster} cluster2 - * @returns {CURECluster} - */ - private _merge_clusters; - /** - * Run CURE clustering algorithm - * @private - */ - private _cure; - /** - * Build the cluster list (point -> cluster assignment) - * @private - */ - private _build_cluster_ids; - /** - * @returns {number[][]} - */ - get_clusters(): number[][]; - /** - * @returns {number[]} - */ - get_cluster_list(): number[]; + /** + * @param {InputType} points + * @param {Partial} parameters + */ + constructor(points: InputType, parameters?: Partial); + /** @type {number} */ + _K: number; + /** @type {number} */ + _num_representatives: number; + /** @type {number} */ + _shrink_factor: number; + /** + * @private + * @type {CURECluster[]} + */ + private _clusters; + /** @type {number[]} */ + _cluster_ids: number[]; + /** + * Initialize each point as its own cluster + * @private + */ + private _initialize_clusters; + /** + * Compute distance between two clusters using representative points + * @private + * @param {CURECluster} cluster1 + * @param {CURECluster} cluster2 + * @returns {number} + */ + private _cluster_distance; + /** + * Find the closest pair of clusters + * @private + * @returns {[number, number, number]} [index1, index2, distance] + */ + private _find_closest_clusters; + /** + * Merge two clusters + * @private + * @param {CURECluster} cluster1 + * @param {CURECluster} cluster2 + * @returns {CURECluster} + */ + private _merge_clusters; + /** + * Run CURE clustering algorithm + * @private + */ + private _cure; + /** + * Build the cluster list (point -> cluster assignment) + * @private + */ + private _build_cluster_ids; + /** + * @returns {number[][]} + */ + get_clusters(): number[][]; + /** + * @returns {number[]} + */ + get_cluster_list(): number[]; } /** @import { InputType } from "../index.js" */ @@ -932,99 +886,90 @@ declare class CURE extends Clustering { * @category Clustering */ declare class HierarchicalClustering extends Clustering { - /** - * @param {InputType} points - Data or distance matrix if metric is 'precomputed' - * @param {Partial} parameters - */ - constructor(points: InputType, parameters?: Partial); - /** @type {Cluster | null} */ - root: Cluster | null; - _id: number; - _d_min: Float64Array; - _distance_matrix: Matrix; - _clusters: any[]; - _c_size: Uint16Array; - /** - * @param {number} value - Value where to cut the tree. - * @param {"distance" | "depth"} [type="distance"] - Type of value. Default is `"distance"` - * @returns {Cluster[][]} - Array of clusters with the indices of the rows in given points. - */ - get_clusters_raw(value: number, type?: "distance" | "depth"): Cluster[][]; - /** - * @param {number} value - Value where to cut the tree. - * @param {"distance" | "depth"} [type="distance"] - Type of value. Default is `"distance"` - * @returns {number[][]} - Array of clusters with the indices of the rows in given points. - */ - get_clusters(value: number, type?: "distance" | "depth"): number[][]; - /** - * @param {number} value - Value where to cut the tree. - * @param {"distance" | "depth"} [type="distance"] - Type of value. Default is `"distance"` - * @returns {number[]} - Array of clusters with the indices of the rows in given points. - */ - get_cluster_list(value: number, type?: "distance" | "depth"): number[]; - /** - * @private - * @param {Cluster} node - * @param {(d: {dist: number, depth: number}) => number} f - * @param {number} value - * @param {Cluster[][]} result - */ - private _traverse; + /** + * @param {InputType} points - Data or distance matrix if metric is 'precomputed' + * @param {Partial} parameters + */ + constructor(points: InputType, parameters?: Partial); + /** @type {Cluster | null} */ + root: Cluster | null; + _id: number; + _d_min: Float64Array; + _distance_matrix: Matrix; + _clusters: any[]; + _c_size: Uint16Array; + /** + * @param {number} value - Value where to cut the tree. + * @param {"distance" | "depth"} [type="distance"] - Type of value. Default is `"distance"` + * @returns {Cluster[][]} - Array of clusters with the indices of the rows in given points. + */ + get_clusters_raw(value: number, type?: "distance" | "depth"): Cluster[][]; + /** + * @param {number} value - Value where to cut the tree. + * @param {"distance" | "depth"} [type="distance"] - Type of value. Default is `"distance"` + * @returns {number[][]} - Array of clusters with the indices of the rows in given points. + */ + get_clusters(value: number, type?: "distance" | "depth"): number[][]; + /** + * @param {number} value - Value where to cut the tree. + * @param {"distance" | "depth"} [type="distance"] - Type of value. Default is `"distance"` + * @returns {number[]} - Array of clusters with the indices of the rows in given points. + */ + get_cluster_list(value: number, type?: "distance" | "depth"): number[]; + /** + * @private + * @param {Cluster} node + * @param {(d: {dist: number, depth: number}) => number} f + * @param {number} value + * @param {Cluster[][]} result + */ + private _traverse; } /** @private */ declare class Cluster { - /** - * - * @param {number} id - * @param {Cluster?} left - * @param {Cluster?} right - * @param {number} dist - * @param {Float64Array?} centroid - * @param {number} index - * @param {number} [size] - * @param {number} [depth] - */ - constructor( - id: number, - left: Cluster | null, - right: Cluster | null, - dist: number, - centroid: Float64Array | null, - index: number, - size?: number, - depth?: number, - ); - /**@type {number} */ - size: number; - /**@type {number} */ - depth: number; - /**@type {Cluster | null} */ - parent: Cluster | null; - id: number; - left: Cluster | null; - right: Cluster | null; - dist: number; - index: number; - centroid: Float64Array; - /** - * - * @param {Cluster} left - * @param {Cluster} right - * @returns {Float64Array} - */ - _calculate_centroid(left: Cluster, right: Cluster): Float64Array; - get isLeaf(): boolean; - /** - * - * @returns {Cluster[]} - */ - leaves(): Cluster[]; - /** - * - * @returns {Cluster[]} - */ - descendants(): Cluster[]; + /** + * + * @param {number} id + * @param {Cluster?} left + * @param {Cluster?} right + * @param {number} dist + * @param {Float64Array?} centroid + * @param {number} index + * @param {number} [size] + * @param {number} [depth] + */ + constructor(id: number, left: Cluster | null, right: Cluster | null, dist: number, centroid: Float64Array | null, index: number, size?: number, depth?: number); + /**@type {number} */ + size: number; + /**@type {number} */ + depth: number; + /**@type {Cluster | null} */ + parent: Cluster | null; + id: number; + left: Cluster | null; + right: Cluster | null; + dist: number; + index: number; + centroid: Float64Array; + /** + * + * @param {Cluster} left + * @param {Cluster} right + * @returns {Float64Array} + */ + _calculate_centroid(left: Cluster, right: Cluster): Float64Array; + get isLeaf(): boolean; + /** + * + * @returns {Cluster[]} + */ + leaves(): Cluster[]; + /** + * + * @returns {Cluster[]} + */ + descendants(): Cluster[]; } /** @import { InputType } from "../index.js" */ @@ -1050,49 +995,49 @@ declare class Cluster { * const centroids = kmeans.centroids; // center points */ declare class KMeans extends Clustering { - /** - * @param {InputType} points - * @param {Partial} parameters - */ - constructor(points: InputType, parameters?: Partial); - _K: number; - _randomizer: Randomizer; - /** @type {number[]} */ - _clusters: number[]; - _cluster_centroids: Float64Array[]; - /** @returns {number} The number of clusters */ - get k(): number; - /** @returns {Float64Array[]} The cluster centroids */ - get centroids(): Float64Array[]; - /** @returns {number[]} The cluster list */ - get_cluster_list(): number[]; - /** @returns {number[][]} An Array of clusters with the indices of the points. */ - get_clusters(): number[][]; - /** - * @private - * @param {number[]} point_indices - * @param {number[]} candidates - * @returns {number} - */ - private _furthest_point; - /** - * @private - * @param {number} K - * @returns {Float64Array[]} - */ - private _get_random_centroids; - /** - * @private - * @param {Float64Array[]} cluster_centroids - * @returns {{ clusters_changed: boolean; cluster_centroids: Float64Array[] }} - */ - private _iteration; - /** - * @private - * @param {number} K - * @returns {Float64Array[]} - */ - private _compute_centroid; + /** + * @param {InputType} points + * @param {Partial} parameters + */ + constructor(points: InputType, parameters?: Partial); + _K: number; + _randomizer: Randomizer; + /** @type {number[]} */ + _clusters: number[]; + _cluster_centroids: Float64Array[]; + /** @returns {number} The number of clusters */ + get k(): number; + /** @returns {Float64Array[]} The cluster centroids */ + get centroids(): Float64Array[]; + /** @returns {number[]} The cluster list */ + get_cluster_list(): number[]; + /** @returns {number[][]} An Array of clusters with the indices of the points. */ + get_clusters(): number[][]; + /** + * @private + * @param {number[]} point_indices + * @param {number[]} candidates + * @returns {number} + */ + private _furthest_point; + /** + * @private + * @param {number} K + * @returns {Float64Array[]} + */ + private _get_random_centroids; + /** + * @private + * @param {Float64Array[]} cluster_centroids + * @returns {{ clusters_changed: boolean; cluster_centroids: Float64Array[] }} + */ + private _iteration; + /** + * @private + * @param {number} K + * @returns {Float64Array[]} + */ + private _compute_centroid; } /** @import {InputType} from "../index.js" */ @@ -1109,71 +1054,71 @@ declare class KMeans extends Clustering { * @see {@link KMeans} for a faster but less robust alternative */ declare class KMedoids extends Clustering { - /** - * @param {InputType} points - Data matrix - * @param {Partial} parameters - * @see {@link https://link.springer.com/chapter/10.1007/978-3-030-32047-8_16} Faster k-Medoids Clustering: Improving the PAM, CLARA, and CLARANS Algorithms - */ - constructor(points: InputType, parameters?: Partial); - _A: Float64Array[]; - _max_iter: number; - _distance_matrix: Matrix; - _randomizer: Randomizer; - _clusters: any[]; - _cluster_medoids: number[]; - _is_initialized: boolean; - /** @returns {number[]} The cluster list */ - get_cluster_list(): number[]; - /** @returns {number[][]} - Array of clusters with the indices of the rows in given points. */ - get_clusters(): number[][]; - /** @returns {number} */ - get k(): number; - /** @returns {number[]} */ - get medoids(): number[]; - /** @returns {number[]} */ - get_medoids(): number[]; - generator(): AsyncGenerator; - /** Algorithm 1. FastPAM1: Improved SWAP algorithm */ - /** FastPAM1: One best swap per iteration */ - _iteration(): boolean; - /** - * - * @param {number} i - * @param {number} j - * @param {Float64Array?} x_i - * @param {Float64Array?} x_j - * @returns - */ - _get_distance(i: number, j: number, x_i?: Float64Array | null, x_j?: Float64Array | null): number; - /** - * - * @param {Float64Array} x_j - * @param {number} j - * @returns - */ - _nearest_medoid( - x_j: Float64Array, - j: number, - ): { - distance_nearest: number; - index_nearest: number; - distance_second: number; - index_second: number; - }; - _update_clusters(): void; - /** - * Computes `K` clusters out of the `matrix`. - * @param {number} K - Number of clusters. - * @param {number[]} cluster_medoids - */ - init(K: number, cluster_medoids: number[]): this; - /** - * Algorithm 3. FastPAM LAB: Linear Approximate BUILD initialization. - * - * @param {number} K - Number of clusters - * @returns {number[]} - */ - _get_random_medoids(K: number): number[]; + /** + * @param {InputType} points - Data matrix + * @param {Partial} parameters + * @see {@link https://link.springer.com/chapter/10.1007/978-3-030-32047-8_16} Faster k-Medoids Clustering: Improving the PAM, CLARA, and CLARANS Algorithms + */ + constructor(points: InputType, parameters?: Partial); + _A: Float64Array[]; + _max_iter: number; + _distance_matrix: Matrix; + _randomizer: Randomizer; + _clusters: any[]; + _cluster_medoids: number[]; + _is_initialized: boolean; + /** @returns {number[]} The cluster list */ + get_cluster_list(): number[]; + /** @returns {number[][]} - Array of clusters with the indices of the rows in given points. */ + get_clusters(): number[][]; + /** @returns {number} */ + get k(): number; + /** @returns {number[]} */ + get medoids(): number[]; + /** @returns {number[]} */ + get_medoids(): number[]; + generator(): AsyncGenerator; + /** Algorithm 1. FastPAM1: Improved SWAP algorithm */ + /** + * FastPAM1: One best swap per iteration + * @private + * @returns {boolean} + */ + private _iteration; + /** + * @private + * Get distance between two points + * @param {number} i + * @param {number} j + * @param {Float64Array?} x_i + * @param {Float64Array?} x_j + * @returns {number} + */ + private _get_distance; + /** + * @private + * @param {Float64Array} x_j + * @param {number} j + * @returns + */ + private _nearest_medoid; + /** + * @private + */ + private _update_clusters; + /** + * Computes `K` clusters out of the `matrix`. + * @param {number} K - Number of clusters. + * @param {number[]} cluster_medoids + */ + init(K: number, cluster_medoids: number[]): this; + /** + * Algorithm 3. FastPAM LAB: Linear Approximate BUILD initialization. + * @private + * @param {number} K - Number of clusters + * @returns {number[]} + */ + private _get_random_medoids; } /** @import { ParametersMeanShift } from "./index.js" */ @@ -1189,47 +1134,79 @@ declare class KMedoids extends Clustering { * @category Clustering */ declare class MeanShift extends Clustering { - /** - * - * @param {InputType} points - * @param {Partial} parameters - */ - constructor(points: InputType, parameters?: Partial); - /** @type {number} */ - _bandwidth: number; - /** @type {number} */ - _max_iter: number; - /** @type {number} */ - _tolerance: number; - /** @type {(dist: number) => number} */ - _kernel: (dist: number) => number; - /** @type {Matrix} */ - _points: Matrix; - /** @type {number[] | undefined} */ - _clusters: number[] | undefined; - /** @type {number[][] | undefined} */ - _cluster_list: number[][] | undefined; - /** - * @param {Matrix} matrix - * @returns {number} - */ - _compute_bandwidth(matrix: Matrix): number; - /** - * @param {number} dist - * @returns {number} - */ - _kernel_weight(dist: number): number; - _mean_shift(): void; - _assign_clusters(): void; - /** - * @returns {number[][]} - */ - get_clusters(): number[][]; - /** - * - * @returns {number[]} - */ - get_cluster_list(): number[]; + /** + * + * @param {InputType} points + * @param {Partial} parameters + */ + constructor(points: InputType, parameters?: Partial); + /** + * @private + * @type {number} + */ + private _bandwidth; + /** + * @private + * @type {number} + */ + private _max_iter; + /** + * @private + * @type {number} + */ + private _tolerance; + /** + * @private + * @type {(dist: number) => number} + */ + private _kernel; + /** + * @type {Matrix} + */ + _points: Matrix; + /** + * @private + * @type {number[] | undefined} + */ + private _clusters; + /** + * @private + * @type {number[][] | undefined} + */ + private _cluster_list; + /** + * Helper to compute bandwidth if not provided + * @private + * @param {Matrix} matrix + * @returns {number} + */ + private _compute_bandwidth; + /** + * Compute kernel weight + * @private + * @param {number} dist + * @returns {number} + */ + private _kernel_weight; + /** + * Perform mean shift iterations + * @private + */ + private _mean_shift; + /** + * After convergence, assign clusters based on nearest mode + * @private + */ + private _assign_clusters; + /** + * @returns {number[][]} + */ + get_clusters(): number[][]; + /** + * + * @returns {number[]} + */ + get_cluster_list(): number[]; } /** @import { InputType } from "../index.js" */ @@ -1252,68 +1229,68 @@ declare class MeanShift extends Clustering { * @category Clustering */ declare class OPTICS extends Clustering { - /** - * **O**rdering **P**oints **T**o **I**dentify the **C**lustering **S**tructure. - * - * @param {InputType} points - The data. - * @param {Partial} [parameters={}] - * @see {@link https://www.dbs.ifi.lmu.de/Publikationen/Papers/OPTICS.pdf} - * @see {@link https://en.wikipedia.org/wiki/OPTICS_algorithm} - */ - constructor(points: InputType, parameters?: Partial); - /** - * @private - * @type {DBEntry[]} - */ - private _ordered_list; - /** @type {number[][]} */ - _clusters: number[][]; - /** - * @private - * @type {DBEntry[]} - */ - private _DB; - _cluster_index: number; - /** - * @private - * @param {DBEntry} p - A point of the data. - * @returns {DBEntry[]} An array consisting of the `epsilon`-neighborhood of `p`. - */ - private _get_neighbors; - /** - * @private - * @param {DBEntry} p - A point of `matrix`. - * @returns {number|undefined} The distance to the `min_points`-th nearest point of `p`, or undefined if the - * `epsilon`-neighborhood has fewer elements than `min_points`. - */ - private _core_distance; - /** - * Updates the reachability distance of the points. - * - * @private - * @param {DBEntry} p - * @param {Heap} seeds - */ - private _update; - /** - * Expands the `cluster` with points in `seeds`. - * - * @private - * @param {Heap} seeds - * @param {number[]} cluster - */ - private _expand_cluster; - /** - * Returns an array of clusters. - * - * @returns {number[][]} Array of clusters with the indices of the rows in given `matrix`. - */ - get_clusters(): number[][]; - /** - * @returns {number[]} Returns an array, where the ith entry defines the cluster affirmation of the ith point of - * given data. (-1 stands for outlier) - */ - get_cluster_list(): number[]; + /** + * **O**rdering **P**oints **T**o **I**dentify the **C**lustering **S**tructure. + * + * @param {InputType} points - The data. + * @param {Partial} [parameters={}] + * @see {@link https://www.dbs.ifi.lmu.de/Publikationen/Papers/OPTICS.pdf} + * @see {@link https://en.wikipedia.org/wiki/OPTICS_algorithm} + */ + constructor(points: InputType, parameters?: Partial); + /** + * @private + * @type {DBEntry[]} + */ + private _ordered_list; + /** @type {number[][]} */ + _clusters: number[][]; + /** + * @private + * @type {DBEntry[]} + */ + private _DB; + _cluster_index: number; + /** + * @private + * @param {DBEntry} p - A point of the data. + * @returns {DBEntry[]} An array consisting of the `epsilon`-neighborhood of `p`. + */ + private _get_neighbors; + /** + * @private + * @param {DBEntry} p - A point of `matrix`. + * @returns {number|undefined} The distance to the `min_points`-th nearest point of `p`, or undefined if the + * `epsilon`-neighborhood has fewer elements than `min_points`. + */ + private _core_distance; + /** + * Updates the reachability distance of the points. + * + * @private + * @param {DBEntry} p + * @param {Heap} seeds + */ + private _update; + /** + * Expands the `cluster` with points in `seeds`. + * + * @private + * @param {Heap} seeds + * @param {number[]} cluster + */ + private _expand_cluster; + /** + * Returns an array of clusters. + * + * @returns {number[][]} Array of clusters with the indices of the rows in given `matrix`. + */ + get_clusters(): number[][]; + /** + * @returns {number[]} Returns an array, where the ith entry defines the cluster affirmation of the ith point of + * given data. (-1 stands for outlier) + */ + get_cluster_list(): number[]; } /** @import { InputType } from "../index.js" */ @@ -1342,206 +1319,206 @@ declare class OPTICS extends Clustering { * @category Clustering */ declare class XMeans extends Clustering { - /** - * XMeans clustering algorithm that automatically determines the optimal number of clusters. - * - * X-Means extends K-Means by starting with a minimum number of clusters and iteratively - * splitting clusters to improve the Bayesian Information Criterion (BIC). - * - * Algorithm: - * 1. Start with K_min clusters using KMeans - * 2. For each cluster, try splitting it into 2 sub-clusters - * 3. If BIC improves after splitting, keep the split - * 4. Run KMeans again with all (old + new) centroids - * 5. Repeat until K_max is reached or no more improvements - * - * @param {InputType} points - The data points to cluster - * @param {Partial} [parameters={}] - Configuration parameters - * @see {@link https://www.cs.cmu.edu/~dpelleg/download/xmeans.pdf} - * @see {@link https://github.com/annoviko/pyclustering/blob/master/pyclustering/cluster/xmeans.py} - * @see {@link https://github.com/haifengl/smile/blob/master/core/src/main/java/smile/clustering/XMeans.java} - */ - constructor(points: InputType, parameters?: Partial); - _randomizer: Randomizer; - /** @type {KMeans | null} */ - _best_kmeans: KMeans | null; - /** - * Run the XMeans algorithm - * - * @private - */ - private _run; - /** - * Select the best candidate based on BIC score - * - * @private - * @param {Map} candidates - * @returns {KMeans} - */ - private _select_best_candidate; - /** - * Calculate Bayesian Information Criterion for a set of clusters. - * - * Uses Kass's formula for BIC calculation: - * BIC(θ) = L(D) - 0.5 * p * ln(N) - * - * Where: - * - L(D) is the log-likelihood of the data - * - p is the number of free parameters: (K-1) + D*K + 1 - * - N is the total number of points - * - * @private - * @param {number[][]} clusters - Array of clusters with point indices - * @param {Float64Array[]} centroids - Array of centroids - * @returns {number} BIC score (higher is better) - */ - private _bic; - /** - * Get the computed clusters - * - * @returns {number[][]} Array of clusters, each containing indices of points - */ - get_clusters(): number[][]; - /** @returns {number[]} The cluster list */ - get_cluster_list(): number[]; - /** - * Get the final centroids - * - * @returns {Float64Array[]} Array of centroids - */ - get centroids(): Float64Array[]; - /** - * Get the optimal number of clusters found - * - * @returns {number} The number of clusters - */ - get k(): number; + /** + * XMeans clustering algorithm that automatically determines the optimal number of clusters. + * + * X-Means extends K-Means by starting with a minimum number of clusters and iteratively + * splitting clusters to improve the Bayesian Information Criterion (BIC). + * + * Algorithm: + * 1. Start with K_min clusters using KMeans + * 2. For each cluster, try splitting it into 2 sub-clusters + * 3. If BIC improves after splitting, keep the split + * 4. Run KMeans again with all (old + new) centroids + * 5. Repeat until K_max is reached or no more improvements + * + * @param {InputType} points - The data points to cluster + * @param {Partial} [parameters={}] - Configuration parameters + * @see {@link https://www.cs.cmu.edu/~dpelleg/download/xmeans.pdf} + * @see {@link https://github.com/annoviko/pyclustering/blob/master/pyclustering/cluster/xmeans.py} + * @see {@link https://github.com/haifengl/smile/blob/master/core/src/main/java/smile/clustering/XMeans.java} + */ + constructor(points: InputType, parameters?: Partial); + _randomizer: Randomizer; + /** @type {KMeans | null} */ + _best_kmeans: KMeans | null; + /** + * Run the XMeans algorithm + * + * @private + */ + private _run; + /** + * Select the best candidate based on BIC score + * + * @private + * @param {Map} candidates + * @returns {KMeans} + */ + private _select_best_candidate; + /** + * Calculate Bayesian Information Criterion for a set of clusters. + * + * Uses Kass's formula for BIC calculation: + * BIC(θ) = L(D) - 0.5 * p * ln(N) + * + * Where: + * - L(D) is the log-likelihood of the data + * - p is the number of free parameters: (K-1) + D*K + 1 + * - N is the total number of points + * + * @private + * @param {number[][]} clusters - Array of clusters with point indices + * @param {Float64Array[]} centroids - Array of centroids + * @returns {number} BIC score (higher is better) + */ + private _bic; + /** + * Get the computed clusters + * + * @returns {number[][]} Array of clusters, each containing indices of points + */ + get_clusters(): number[][]; + /** @returns {number[]} The cluster list */ + get_cluster_list(): number[]; + /** + * Get the final centroids + * + * @returns {Float64Array[]} Array of centroids + */ + get centroids(): Float64Array[]; + /** + * Get the optimal number of clusters found + * + * @returns {number} The number of clusters + */ + get k(): number; } type ParametersHierarchicalClustering = { - linkage: "single" | "complete" | "average"; - metric: Metric | "precomputed"; + linkage: "single" | "complete" | "average"; + metric: Metric | "precomputed"; }; type ParametersKMeans = { - K: number; - /** - * Default is `euclidean` - */ - metric: Metric; - /** - * Default is `1212` - */ - seed: number; - /** - * - Initial centroids. Default is `null` - */ - initial_centroids?: Float64Array[] | number[][] | undefined; + K: number; + /** + * Default is `euclidean` + */ + metric: Metric; + /** + * Default is `1212` + */ + seed: number; + /** + * - Initial centroids. Default is `null` + */ + initial_centroids?: Float64Array[] | number[][] | undefined; }; type ParametersKMedoids = { - /** - * - Number of clusters - */ - K: number; - /** - * - Maximum number of iterations. Default is 10 * Math.log10(N). Default is `null` - */ - max_iter: number | null; - /** - * - Metric defining the dissimilarity. Default is `euclidean` - */ - metric: Metric; - /** - * - Seed value for random number generator. Default is `1212` - */ - seed: number; + /** + * - Number of clusters + */ + K: number; + /** + * - Maximum number of iterations. Default is 10 * Math.log10(N). Default is `null` + */ + max_iter: number | null; + /** + * - Metric defining the dissimilarity. Default is `euclidean` + */ + metric: Metric; + /** + * - Seed value for random number generator. Default is `1212` + */ + seed: number; }; type ParametersOptics = { - /** - * - The minimum distance which defines whether a point is a neighbor or not. - */ - epsilon: number; - /** - * - The minimum number of points which a point needs to create a cluster. (Should be higher than 1, else each point creates a cluster.) - */ - min_points: number; - /** - * - The distance metric which defines the distance between two points of the points. Default is `euclidean` - */ - metric: Metric; + /** + * - The minimum distance which defines whether a point is a neighbor or not. + */ + epsilon: number; + /** + * - The minimum number of points which a point needs to create a cluster. (Should be higher than 1, else each point creates a cluster.) + */ + min_points: number; + /** + * - The distance metric which defines the distance between two points of the points. Default is `euclidean` + */ + metric: Metric; }; type ParametersXMeans = { - /** - * - Minimum number of clusters. Default is `2` - */ - K_min: number; - /** - * - Maximum number of clusters. Default is `10` - */ - K_max: number; - /** - * - Distance metric function. Default is `euclidean` - */ - metric: Metric; - /** - * - Random seed. Default is `1212` - */ - seed: number; - /** - * - Minimum points required to consider splitting a cluster. Default is `25` - */ - min_cluster_size: number; - /** - * - Convergence tolerance for KMeans. Default is `0.001` - */ - tolerance: number; + /** + * - Minimum number of clusters. Default is `2` + */ + K_min: number; + /** + * - Maximum number of clusters. Default is `10` + */ + K_max: number; + /** + * - Distance metric function. Default is `euclidean` + */ + metric: Metric; + /** + * - Random seed. Default is `1212` + */ + seed: number; + /** + * - Minimum points required to consider splitting a cluster. Default is `25` + */ + min_cluster_size: number; + /** + * - Convergence tolerance for KMeans. Default is `0.001` + */ + tolerance: number; }; type ParametersMeanShift = { - /** - * - bandwidth - */ - bandwidth: number; - /** - * - Metric defining the dissimilarity. Default is `euclidean` - */ - metric: Metric; - /** - * - Seed value for random number generator. Default is `1212` - */ - seed: number; - /** - * - Kernel function. Default is `gaussian` - */ - kernel: "flat" | "gaussian" | ((dist: number) => number); - /** - * - Maximum number of iterations. Default is `Math.max(10, Math.floor(10 * Math.log10(N)))` - */ - max_iter?: number | undefined; - /** - * - Convergence tolerance. Default is `1e-3` - */ - tolerance?: number | undefined; + /** + * - bandwidth + */ + bandwidth: number; + /** + * - Metric defining the dissimilarity. Default is `euclidean` + */ + metric: Metric; + /** + * - Seed value for random number generator. Default is `1212` + */ + seed: number; + /** + * - Kernel function. Default is `gaussian` + */ + kernel: "flat" | "gaussian" | ((dist: number) => number); + /** + * - Maximum number of iterations. Default is `Math.max(10, Math.floor(10 * Math.log10(N)))` + */ + max_iter?: number | undefined; + /** + * - Convergence tolerance. Default is `1e-3` + */ + tolerance?: number | undefined; }; type ParametersCURE = { - /** - * - Target number of clusters. Default is `2` - */ - K: number; - /** - * - Number of representative points per cluster. Default is `5` - */ - num_representatives: number; - /** - * - Factor to shrink representatives toward centroid (0-1). Default is `0.5` - */ - shrink_factor: number; - /** - * - Distance metric function. Default is `euclidean` - */ - metric: Metric; - /** - * - Random seed. Default is `1212` - */ - seed: number; + /** + * - Target number of clusters. Default is `2` + */ + K: number; + /** + * - Number of representative points per cluster. Default is `5` + */ + num_representatives: number; + /** + * - Factor to shrink representatives toward centroid (0-1). Default is `0.5` + */ + shrink_factor: number; + /** + * - Distance metric function. Default is `euclidean` + */ + metric: Metric; + /** + * - Random seed. Default is `1212` + */ + seed: number; }; /** @@ -1558,34 +1535,34 @@ type ParametersCURE = { * @see {@link https://en.wikipedia.org/wiki/Disjoint-set_data_structure} */ declare class DisjointSet { - /** - * @param {T[]?} elements - */ - constructor(elements?: T[] | null); - /** - * @private - * @type {Map>} - */ - private _list; - /** - * @private - * @param {T} x - * @returns {DisjointSet} - */ - private make_set; - /** - * @param {T} x - * @returns - */ - find(x: T): T | null; - /** - * @param {T} x - * @param {T} y - * @returns - */ - union(x: T, y: T): this; - /** @param {T} x */ - get_children(x: T): Set | null; + /** + * @param {T[]?} elements + */ + constructor(elements?: T[] | null); + /** + * @private + * @type {Map>} + */ + private _list; + /** + * @private + * @param {T} x + * @returns {DisjointSet} + */ + private make_set; + /** + * @param {T} x + * @returns + */ + find(x: T): T | null; + /** + * @param {T} x + * @param {T} y + * @returns + */ + union(x: T, y: T): this; + /** @param {T} x */ + get_children(x: T): Set | null; } /** @import { Comparator } from "./index.js" */ @@ -1595,128 +1572,120 @@ declare class DisjointSet { * @category Data Structures */ declare class Heap { - /** - * Creates a Heap from an Array - * - * @template T - * @param {T[]} elements - Contains the elements for the Heap. - * @param {(d: T) => number} accessor - Function returns the value of the element. - * @param {"min" | "max" | Comparator} [comparator="min"] - Function returning true or false - * defining the wished order of the Heap, or String for predefined function. ("min" for a Min-Heap, "max" for a - * Max_heap). Default is `"min"` - * @returns {Heap} - */ - static heapify( - elements: T_1[], - accessor: (d: T_1) => number, - comparator?: "min" | "max" | Comparator, - ): Heap; - /** - * A heap is a datastructure holding its elements in a specific way, so that the top element would be the first - * entry of an ordered list. - * - * @param {T[]?} elements - Contains the elements for the Heap. `elements` can be null. - * @param {(d: T) => number} accessor - Function returns the value of the element. - * @param {"min" | "max" | Comparator} [comparator="min"] - Function returning true or false - * defining the wished order of the Heap, or String for predefined function. ("min" for a Min-Heap, "max" for a - * Max_heap). Default is `"min"` - * @see {@link https://en.wikipedia.org/wiki/Binary_heap} - */ - constructor( - elements: (T[] | null) | undefined, - accessor: (d: T) => number, - comparator?: "min" | "max" | Comparator, - ); - /** @type {{ element: T; value: number }[]} */ - _container: { - element: T; - value: number; - }[]; - /** @type {Comparator} */ - _comparator: Comparator; - /** @type {(d: T) => number} */ - _accessor: (d: T) => number; - /** - * Swaps elements of container array. - * - * @private - * @param {number} index_a - * @param {number} index_b - */ - private _swap; - /** @private */ - private _heapify_up; - /** - * Pushes the element to the heap. - * - * @param {T} element - * @returns {Heap} - */ - push(element: T): Heap; - /** - * @private - * @param {Number} [start_index=0] Default is `0` - */ - private _heapify_down; - /** - * Removes and returns the top entry of the heap. - * - * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by - * `accessor`}). - */ - pop(): { - element: T; - value: number; - } | null; - /** - * Returns the top entry of the heap without removing it. - * - * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by - * `accessor`). - */ - get first(): { - element: T; - value: number; - } | null; - /** - * Yields the raw data - * - * @yields {T} Object consists of the element and its value (computed by `accessor`}). - */ - iterate(): Generator; - /** - * Returns the heap as ordered array. - * - * @returns {T[]} Array consisting the elements ordered by `comparator`. - */ - toArray(): T[]; - /** - * Returns elements of container array. - * - * @returns {T[]} Array consisting the elements. - */ - data(): T[]; - /** - * Returns the container array. - * - * @returns {{ element: T; value: number }[]} The container array. - */ - raw_data(): { - element: T; - value: number; - }[]; - /** - * The size of the heap. - * - * @returns {number} - */ - get length(): number; - /** - * Returns false if the the heap has entries, true if the heap has no entries. - * - * @returns {boolean} - */ - get empty(): boolean; + /** + * Creates a Heap from an Array + * + * @template T + * @param {T[]} elements - Contains the elements for the Heap. + * @param {(d: T) => number} accessor - Function returns the value of the element. + * @param {"min" | "max" | Comparator} [comparator="min"] - Function returning true or false + * defining the wished order of the Heap, or String for predefined function. ("min" for a Min-Heap, "max" for a + * Max_heap). Default is `"min"` + * @returns {Heap} + */ + static heapify(elements: T_1[], accessor: (d: T_1) => number, comparator?: "min" | "max" | Comparator): Heap; + /** + * A heap is a datastructure holding its elements in a specific way, so that the top element would be the first + * entry of an ordered list. + * + * @param {T[]?} elements - Contains the elements for the Heap. `elements` can be null. + * @param {(d: T) => number} accessor - Function returns the value of the element. + * @param {"min" | "max" | Comparator} [comparator="min"] - Function returning true or false + * defining the wished order of the Heap, or String for predefined function. ("min" for a Min-Heap, "max" for a + * Max_heap). Default is `"min"` + * @see {@link https://en.wikipedia.org/wiki/Binary_heap} + */ + constructor(elements: (T[] | null) | undefined, accessor: (d: T) => number, comparator?: "min" | "max" | Comparator); + /** @type {{ element: T; value: number }[]} */ + _container: { + element: T; + value: number; + }[]; + /** @type {Comparator} */ + _comparator: Comparator; + /** @type {(d: T) => number} */ + _accessor: (d: T) => number; + /** + * Swaps elements of container array. + * + * @private + * @param {number} index_a + * @param {number} index_b + */ + private _swap; + /** @private */ + private _heapify_up; + /** + * Pushes the element to the heap. + * + * @param {T} element + * @returns {Heap} + */ + push(element: T): Heap; + /** + * @private + * @param {Number} [start_index=0] Default is `0` + */ + private _heapify_down; + /** + * Removes and returns the top entry of the heap. + * + * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by + * `accessor`}). + */ + pop(): { + element: T; + value: number; + } | null; + /** + * Returns the top entry of the heap without removing it. + * + * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by + * `accessor`). + */ + get first(): { + element: T; + value: number; + } | null; + /** + * Yields the raw data + * + * @yields {T} Object consists of the element and its value (computed by `accessor`}). + */ + iterate(): Generator; + /** + * Returns the heap as ordered array. + * + * @returns {T[]} Array consisting the elements ordered by `comparator`. + */ + toArray(): T[]; + /** + * Returns elements of container array. + * + * @returns {T[]} Array consisting the elements. + */ + data(): T[]; + /** + * Returns the container array. + * + * @returns {{ element: T; value: number }[]} The container array. + */ + raw_data(): { + element: T; + value: number; + }[]; + /** + * The size of the heap. + * + * @returns {number} + */ + get length(): number; + /** + * Returns false if the the heap has entries, true if the heap has no entries. + * + * @returns {boolean} + */ + get empty(): boolean; } type Comparator = (a: number, b: number) => boolean; @@ -1734,143 +1703,133 @@ type Comparator = (a: number, b: number) => boolean; * * @class */ -declare class DR< - T extends InputType, - Para extends { +declare class DR { - /** - * Computes the projection. - * - * @template {InputType} T - * @template {{ seed?: number }} Para - * @param {T} X - * @param {Para} parameters - * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method. - * @returns {T} The dimensionality reduced dataset. - */ - static transform< - T_1 extends InputType, - Para_1 extends { - seed?: number; - }, - >(X: T_1, parameters: Para_1, ...args: unknown[]): T_1; - /** - * Computes the projection. - * - * @template {{ seed?: number }} Para - * @param {InputType} X - * @param {Para} parameters - * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method. - * @returns {Generator} A generator yielding the intermediate steps of the dimensionality - * reduction method. - */ - static generator< - Para_1 extends { - seed?: number; - }, - >(X: InputType, parameters: Para_1, ...args: unknown[]): Generator; - /** - * Computes the projection. - * - * @template {{ seed?: number }} Para - * @param {InputType} X - * @param {Para} parameters - * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method. - * @returns {Promise} A promise yielding the dimensionality reduced dataset. - */ - static transform_async< - Para_1 extends { - seed?: number; - }, - >(X: InputType, parameters: Para_1, ...args: unknown[]): Promise; - /** - * Takes the default parameters and seals them, remembers the type of input `X`, and initializes the random number - * generator. - * - * @param {T} X - The high-dimensional data. - * @param {Para} default_parameters - Object containing default parameterization of the DR method. - * @param {Partial} parameters - Object containing parameterization of the DR method to override defaults. - */ - constructor(X: T, default_parameters: Para, parameters?: Partial); - /** @type {number} */ - _D: number; - /** @type {number} */ - _N: number; - /** @type {Randomizer} */ - _randomizer: Randomizer; - /** @type {boolean} */ - _is_initialized: boolean; - /** @type {T} */ - __input: T; - /** @type {Para} */ - _parameters: Para; - /** @type {"array" | "matrix" | "typed"} */ - _type: "array" | "matrix" | "typed"; - /** @type {Matrix} */ - X: Matrix; - /** @type {Matrix} */ - Y: Matrix; - /** - * Get all Parameters. - * @overload - * @returns {Para} - */ - parameter(): Para; - /** - * Get value of given parameter. - * @template {keyof Para} K - * @overload - * @param {K} name - Name of the parameter. - * @returns {Para[K]} - */ - parameter(name: K): Para[K]; - /** - * Set value of given parameter. - * @template {keyof Para} K - * @overload - * @param {K} name - Name of the parameter. - * @param {Para[K]} value - Value of the parameter to set. - * @returns {this} - */ - parameter(name: K, value: Para[K]): this; - /** - * Computes the projection. - * - * @abstract - * @param {...unknown} args - * @returns {T} The projection. - */ - transform(...args: unknown[]): T; - /** - * Computes the projection. - * - * @abstract - * @param {...unknown} args - * @returns {Generator} The intermediate steps of the projection. - */ - generator(...args: unknown[]): Generator; - /** - * @abstract - * @param {...unknown} args - */ - init(...args: unknown[]): void; - /** - * If the respective DR method has an `init` function, call it before `transform`. - * - * @returns {DR} - */ - check_init(): DR; - /** @returns {T} The projection in the type of input `X`. */ - get projection(): T; - /** - * Computes the projection. - * - * @param {...unknown} args - Arguments the transform method of the respective DR method takes. - * @returns {Promise} The dimensionality reduced dataset. - */ - transform_async(...args: unknown[]): Promise; +}> { + /** + * Computes the projection. + * + * @template {InputType} T + * @template {{ seed?: number }} Para + * @param {T} X + * @param {Para} parameters + * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method. + * @returns {T} The dimensionality reduced dataset. + */ + static transform(X: T_1, parameters: Para_1, ...args: unknown[]): T_1; + /** + * Computes the projection. + * + * @template {{ seed?: number }} Para + * @param {InputType} X + * @param {Para} parameters + * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method. + * @returns {Generator} A generator yielding the intermediate steps of the dimensionality + * reduction method. + */ + static generator(X: InputType, parameters: Para_1, ...args: unknown[]): Generator; + /** + * Computes the projection. + * + * @template {{ seed?: number }} Para + * @param {InputType} X + * @param {Para} parameters + * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method. + * @returns {Promise} A promise yielding the dimensionality reduced dataset. + */ + static transform_async(X: InputType, parameters: Para_1, ...args: unknown[]): Promise; + /** + * Takes the default parameters and seals them, remembers the type of input `X`, and initializes the random number + * generator. + * + * @param {T} X - The high-dimensional data. + * @param {Para} default_parameters - Object containing default parameterization of the DR method. + * @param {Partial} parameters - Object containing parameterization of the DR method to override defaults. + */ + constructor(X: T, default_parameters: Para, parameters?: Partial); + /** @type {number} */ + _D: number; + /** @type {number} */ + _N: number; + /** @type {Randomizer} */ + _randomizer: Randomizer; + /** @type {boolean} */ + _is_initialized: boolean; + /** @type {T} */ + __input: T; + /** @type {Para} */ + _parameters: Para; + /** @type {"array" | "matrix" | "typed"} */ + _type: "array" | "matrix" | "typed"; + /** @type {Matrix} */ + X: Matrix; + /** @type {Matrix} */ + Y: Matrix; + /** + * Get all Parameters. + * @overload + * @returns {Para} + */ + parameter(): Para; + /** + * Get value of given parameter. + * @template {keyof Para} K + * @overload + * @param {K} name - Name of the parameter. + * @returns {Para[K]} + */ + parameter(name: K): Para[K]; + /** + * Set value of given parameter. + * @template {keyof Para} K + * @overload + * @param {K} name - Name of the parameter. + * @param {Para[K]} value - Value of the parameter to set. + * @returns {this} + */ + parameter(name: K, value: Para[K]): this; + /** + * Computes the projection. + * + * @abstract + * @param {...unknown} args + * @returns {T} The projection. + */ + transform(...args: unknown[]): T; + /** + * Computes the projection. + * + * @abstract + * @param {...unknown} args + * @returns {Generator} The intermediate steps of the projection. + */ + generator(...args: unknown[]): Generator; + /** + * @abstract + * @param {...unknown} args + */ + init(...args: unknown[]): void; + /** + * If the respective DR method has an `init` function, call it before `transform`. + * + * @returns {DR} + */ + check_init(): DR; + /** @returns {T} The projection in the type of input `X`. */ + get projection(): T; + /** + * Computes the projection. + * + * @param {...unknown} args - Arguments the transform method of the respective DR method takes. + * @returns {Promise} The dimensionality reduced dataset. + */ + transform_async(...args: unknown[]): Promise; } /** @import { InputType } from "../index.js" */ @@ -1888,56 +1847,270 @@ declare class DR< * @category Dimensionality Reduction */ declare class FASTMAP extends DR { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {T} - */ - static transform(X: T_1, parameters: Partial): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Generator} - */ - static generator( - X: T_1, - parameters: Partial, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters: Partial, - ): Promise; - /** - * FastMap: a fast algorithm for indexing, data-mining and visualization of traditional and multimedia datasets. - * @param {T} X - The high-dimensional data. - * @param {Partial} parameters - Object containing parameterization of the DR method. - * @see {@link https://doi.org/10.1145/223784.223812} - */ - constructor(X: T, parameters: Partial); - /** - * Chooses two points which are the most distant in the actual projection. - * - * @private - * @param {(a: number, b: number) => number} dist - * @returns {[number, number, number]} An array consisting of first index, second index, and distance between the - * two points. - */ - private _choose_distant_objects; - /** - * Computes the projection. - * - * @returns {T} The `d`-dimensional projection of the data matrix `X`. - */ - transform(): T; - generator(): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {T} + */ + static transform(X: T_1, parameters: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Generator} + */ + static generator(X: T_1, parameters: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Promise} + */ + static transform_async(X: T_1, parameters: Partial): Promise; + /** + * FastMap: a fast algorithm for indexing, data-mining and visualization of traditional and multimedia datasets. + * @param {T} X - The high-dimensional data. + * @param {Partial} parameters - Object containing parameterization of the DR method. + * @see {@link https://doi.org/10.1145/223784.223812} + */ + constructor(X: T, parameters: Partial); + /** + * Chooses two points which are the most distant in the actual projection. + * + * @private + * @param {(a: number, b: number) => number} dist + * @returns {[number, number, number]} An array consisting of first index, second index, and distance between the + * two points. + */ + private _choose_distant_objects; + /** + * Computes the projection. + * + * @returns {T} The `d`-dimensional projection of the data matrix `X`. + */ + transform(): T; + generator(): Generator; +} + +/** @import {InputType} from "../index.js" */ +/** @import {Metric} from "../metrics/index.js" */ +/** @import {ParametersPaCMAP} from "./index.js" */ +/** + * Pairwise Controlled Manifold Approximation Projection (PaCMAP) + * + * A dimensionality reduction technique that uses three types of point pairs — + * nearest neighbor (NN), mid-near (MN), and further (FP) pairs — with a + * dynamic three-phase weight schedule and Adam optimization to preserve both + * local and global structure. + * + * @class + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction + * @see {@link https://arxiv.org/abs/2012.04456|PaCMAP Paper} + * @see {@link https://github.com/YingfanWang/PaCMAP|PaCMAP GitHub} + * @see {@link UMAP} for a related graph-based technique + * @see {@link LocalMAP} for the local-refinement variant + * + * @example + * import * as druid from "@saehrimnir/druidjs"; + * + * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]; + * const pacmap = new druid.PaCMAP(X, { + * n_neighbors: 10, + * MN_ratio: 0.5, + * FP_ratio: 2.0, + * seed: 42 + * }); + * + * const Y = pacmap.transform(); // 450 iterations (default) + * // [[x1, y1], [x2, y2], [x3, y3]] + */ +declare class PaCMAP extends DR { + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X: T_1, parameters?: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static generator(X: T_1, parameters?: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static transform_async(X: T_1, parameters?: Partial): Promise; + /** + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + */ + constructor(X: T, parameters?: Partial); + _iter: number; + /** + * Samples mid-near pairs for each point. + * For each point i, repeats n_MN times: samples 6 random non-neighbor + * candidates, picks the 2nd closest by high-dim distance. + * + * @protected + * @param {Set[]} nn_sets - Array of neighbor index sets per point + * @param {number} n_MN - Number of mid-near pairs per point + * @returns {Int32Array} Flat array of [i, j] pairs + */ + protected _sample_mn_pairs(nn_sets: Set[], n_MN: number): Int32Array; + /** + * Samples further pairs for each point (random non-neighbors). + * + * @protected + * @param {Set[]} nn_sets - Array of neighbor index sets per point + * @param {number} n_FP - Number of further pairs per point + * @returns {Int32Array} Flat array of [i, j] pairs + */ + protected _sample_fp_pairs(nn_sets: Set[], n_FP: number): Int32Array; + /** + * Computes gradient coefficients and updates the gradient matrix for one pair type. + * + * @protected + * @param {Float64Array} grad_flat - Flat N×d gradient accumulator (modified in place) + * @param {Int32Array} pairs - Flat [i, j, i, j, ...] pair array + * @param {number} w - Weight for this pair type + * @param {number} attr_num - Numerator constant for attractive (10 for NN, 10000 for MN); 0 for repulsive + * @param {boolean} repulsive - Whether this is a repulsive pair type + */ + protected _accumulate_gradients(grad_flat: Float64Array, pairs: Int32Array, w: number, attr_num: number, repulsive: boolean): void; + /** + * Returns the weight schedule for the current iteration. + * + * @protected + * @param {number} iter - Current iteration (0-indexed) + * @returns {{ w_nn: number; w_mn: number; w_fp: number }} + */ + protected _get_weights(iter: number): { + w_nn: number; + w_mn: number; + w_fp: number; + }; + /** + * Applies Adam optimizer update to Y using accumulated gradients. + * + * @protected + * @param {Float64Array} grad_flat - Flat N×d gradient + */ + protected _adam_update(grad_flat: Float64Array): void; + _adam_t: any; + /** + * Initializes PaCMAP: PCA embedding, KNN pairs, MN pairs, FP pairs, Adam state. + * + * @returns {PaCMAP} + */ + init(): PaCMAP; + _nn_pairs: Int32Array | undefined; + _mn_pairs: Int32Array | undefined; + _fp_pairs: Int32Array | undefined; + _adam_m: Float64Array | undefined; + _adam_v: Float64Array | undefined; + /** + * Performs one optimization step. + * + * @returns {Matrix} + */ + next(): Matrix; + /** + * @param {number} [iterations] - Total number of iterations. Defaults to sum of `num_iters`. + * @returns {T} + */ + transform(iterations?: number): T; + /** + * @param {number} [iterations] - Total number of iterations. Defaults to sum of `num_iters`. + * @returns {Generator} + */ + generator(iterations?: number): Generator; +} + +/** @import {InputType} from "../index.js" */ +/** @import {ParametersLocalMAP} from "./index.js" */ +/** + * LocalMAP + * + * A variant of PaCMAP that improves local cluster separation by dynamically + * resampling further pairs (FP) in phase 3 using nearby points in the current + * low-dimensional embedding space, rather than randomly sampled non-neighbors. + * + * @class + * @template {InputType} T + * @extends PaCMAP + * @category Dimensionality Reduction + * @see {@link https://arxiv.org/abs/2012.04456|PaCMAP Paper} + * @see {@link PaCMAP} for the base algorithm + * + * @example + * import * as druid from "@saehrimnir/druidjs"; + * + * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]; + * const localmap = new druid.LocalMAP(X, { + * n_neighbors: 10, + * low_dist_thres: 10, + * seed: 42 + * }); + * + * const Y = localmap.transform(); // 450 iterations (default) + * // [[x1, y1], [x2, y2], [x3, y3]] + */ +declare class LocalMAP extends PaCMAP { + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X: T_1, parameters?: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static generator(X: T_1, parameters?: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static transform_async(X: T_1, parameters?: Partial): Promise; + /** + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + */ + constructor(X: T, parameters?: Partial); + /** + * Accumulates FP gradients with LocalMAP's distance-based weight scaling. + * For pairs within low_dist_thres, scales w_fp by low_dist_thres / (2 * sqrt(d_ij)). + * + * @private + * @param {Float64Array} grad_flat - Flat N×d gradient accumulator (modified in place) + * @param {Int32Array} pairs - Flat [i, j, i, j, ...] pair array + * @param {number} w_fp - Base FP weight + * @param {number} low_dist_thres - Distance threshold + * @param {number} low_dist_thres_sq - Squared distance threshold + */ + private _accumulate_gradients_local_fp; + /** + * Initializes LocalMAP (same as PaCMAP, but caches nn_sets for phase 3 resampling). + * + * @returns {LocalMAP} + */ + init(): LocalMAP; + _low_dist_thres: number | undefined; + _nn_sets_cache: Set[] | undefined; } /** @import {InputType} from "../index.js" */ @@ -1957,52 +2130,46 @@ declare class FASTMAP extends DR { * @see {@link LLE} for another nonlinear alternative */ declare class ISOMAP extends DR { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X: T_1, parameters?: Partial): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static generator( - X: T_1, - parameters?: Partial, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters?: Partial, - ): Promise; - /** - * Isometric feature mapping (ISOMAP). - * - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - * @see {@link https://doi.org/10.1126/science.290.5500.2319} - */ - constructor(X: T, parameters?: Partial); - defaults: ParametersISOMAP; - /** - * Computes the projection. - * - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - generator(): Generator; - /** - * @returns {T} - */ - transform(): T; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X: T_1, parameters?: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static generator(X: T_1, parameters?: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static transform_async(X: T_1, parameters?: Partial): Promise; + /** + * Isometric feature mapping (ISOMAP). + * + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + * @see {@link https://doi.org/10.1126/science.290.5500.2319} + */ + constructor(X: T, parameters?: Partial); + defaults: ParametersISOMAP; + /** + * Computes the projection. + * + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + generator(): Generator; + /** + * @returns {T} + */ + transform(): T; } /** @import {InputType} from "../index.js" */ @@ -2020,70 +2187,58 @@ declare class ISOMAP extends DR { * @category Dimensionality Reduction */ declare class LDA extends DR { - /** - * @template {InputType} T - * @template {{ seed?: number }} Para - * @param {T} X - * @param {Para} parameters - * @returns {T} - */ - static transform< - T_1 extends InputType, - Para extends { - seed?: number; - }, - >(X: T_1, parameters: Para): T_1; - /** - * @template {InputType} T - * @template {{ seed?: number }} Para - * @param {T} X - * @param {Para} parameters - * @returns {Generator} - */ - static generator< - T_1 extends InputType, - Para extends { - seed?: number; - }, - >(X: T_1, parameters: Para): Generator; - /** - * @template {InputType} T - * @template {{ seed?: number }} Para - * @param {T} X - * @param {Para} parameters - * @returns {Promise} - */ - static transform_async< - T_1 extends InputType, - Para extends { - seed?: number; - }, - >(X: T_1, parameters: Para): Promise; - /** - * Linear Discriminant Analysis. - * - * @param {T} X - The high-dimensional data. - * @param {Partial & { labels: any[] | Float64Array }} parameters - Object containing parameterization of the DR method. - * @see {@link https://onlinelibrary.wiley.com/doi/10.1111/j.1469-1809.1936.tb02137.x} - */ - constructor( - X: T, - parameters: Partial & { - labels: any[] | Float64Array; - }, - ); - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - generator(): Generator; - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {T} - The projected data. - */ - transform(): T; + /** + * @template {InputType} T + * @template {{ seed?: number }} Para + * @param {T} X + * @param {Para} parameters + * @returns {T} + */ + static transform(X: T_1, parameters: Para): T_1; + /** + * @template {InputType} T + * @template {{ seed?: number }} Para + * @param {T} X + * @param {Para} parameters + * @returns {Generator} + */ + static generator(X: T_1, parameters: Para): Generator; + /** + * @template {InputType} T + * @template {{ seed?: number }} Para + * @param {T} X + * @param {Para} parameters + * @returns {Promise} + */ + static transform_async(X: T_1, parameters: Para): Promise; + /** + * Linear Discriminant Analysis. + * + * @param {T} X - The high-dimensional data. + * @param {Partial & { labels: any[] | Float64Array }} parameters - Object containing parameterization of the DR method. + * @see {@link https://onlinelibrary.wiley.com/doi/10.1111/j.1469-1809.1936.tb02137.x} + */ + constructor(X: T, parameters: Partial & { + labels: any[] | Float64Array; + }); + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + generator(): Generator; + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {T} - The projected data. + */ + transform(): T; } /** @import {InputType} from "../index.js" */ @@ -2103,53 +2258,47 @@ declare class LDA extends DR { * @see {@link ISOMAP} for another nonlinear alternative */ declare class LLE extends DR { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {T} - */ - static transform(X: T_1, parameters: Partial): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Generator} - */ - static generator( - X: T_1, - parameters: Partial, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters: Partial, - ): Promise; - /** - * Locally Linear Embedding. - * - * @param {T} X - The high-dimensional data. - * @param {Partial} parameters - Object containing parameterization of the DR method. - * @see {@link https://doi.org/10.1126/science.290.5500.2323} - */ - constructor(X: T, parameters: Partial); - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - generator(): Generator; - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {T} - */ - transform(): T; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {T} + */ + static transform(X: T_1, parameters: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Generator} + */ + static generator(X: T_1, parameters: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Promise} + */ + static transform_async(X: T_1, parameters: Partial): Promise; + /** + * Locally Linear Embedding. + * + * @param {T} X - The high-dimensional data. + * @param {Partial} parameters - Object containing parameterization of the DR method. + * @see {@link https://doi.org/10.1126/science.290.5500.2323} + */ + constructor(X: T, parameters: Partial); + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + generator(): Generator; + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {T} + */ + transform(): T; } /** @import {InputType} from "../index.js" */ @@ -2167,53 +2316,47 @@ declare class LLE extends DR { * @category Dimensionality Reduction */ declare class LSP extends DR { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X: T_1, parameters?: Partial): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static generator( - X: T_1, - parameters?: Partial, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters?: Partial, - ): Promise; - /** - * Least Squares Projection. - * - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - * @see {@link https://ieeexplore.ieee.org/document/4378370} - */ - constructor(X: T, parameters?: Partial); - /** - * @returns {LSP} - */ - init(): LSP; - _A: Matrix | undefined; - _b: Matrix | undefined; - /** - * Computes the projection. - * - * @returns {T} Returns the projection. - */ - transform(): T; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X: T_1, parameters?: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static generator(X: T_1, parameters?: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static transform_async(X: T_1, parameters?: Partial): Promise; + /** + * Least Squares Projection. + * + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + * @see {@link https://ieeexplore.ieee.org/document/4378370} + */ + constructor(X: T, parameters?: Partial); + /** + * @returns {LSP} + */ + init(): LSP; + _A: Matrix | undefined; + _b: Matrix | undefined; + /** + * Computes the projection. + * + * @returns {T} Returns the projection. + */ + transform(): T; } /** @import {InputType} from "../index.js" */ @@ -2232,53 +2375,47 @@ declare class LSP extends DR { * @category Dimensionality Reduction */ declare class LTSA extends DR { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {T} - */ - static transform(X: T_1, parameters: Partial): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Generator} - */ - static generator( - X: T_1, - parameters: Partial, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters: Partial, - ): Promise; - /** - * Local Tangent Space Alignment - * - * @param {T} X - The high-dimensional data. - * @param {Partial} parameters - Object containing parameterization of the DR method. - * @see {@link https://epubs.siam.org/doi/abs/10.1137/S1064827502419154} - */ - constructor(X: T, parameters: Partial); - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - generator(): Generator; - /** - * Transforms the inputdata `X` to dimenionality `d`. - * - * @returns {T} - */ - transform(): T; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {T} + */ + static transform(X: T_1, parameters: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Generator} + */ + static generator(X: T_1, parameters: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Promise} + */ + static transform_async(X: T_1, parameters: Partial): Promise; + /** + * Local Tangent Space Alignment + * + * @param {T} X - The high-dimensional data. + * @param {Partial} parameters - Object containing parameterization of the DR method. + * @see {@link https://epubs.siam.org/doi/abs/10.1137/S1064827502419154} + */ + constructor(X: T, parameters: Partial); + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + generator(): Generator; + /** + * Transforms the inputdata `X` to dimenionality `d`. + * + * @returns {T} + */ + transform(): T; } /** @import {InputType} from "../index.js" */ @@ -2298,55 +2435,49 @@ declare class LTSA extends DR { * @see {@link PCA} for another linear alternative */ declare class MDS extends DR { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X: T_1, parameters?: Partial): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static generator( - X: T_1, - parameters?: Partial, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters?: Partial, - ): Promise; - /** - * Classical MDS. - * - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - */ - constructor(X: T, parameters?: Partial); - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - generator(): Generator; - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {T} - */ - transform(): T; - _d_X: Matrix | undefined; - /** @returns {number} - The stress of the projection. */ - stress(): number; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X: T_1, parameters?: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static generator(X: T_1, parameters?: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static transform_async(X: T_1, parameters?: Partial): Promise; + /** + * Classical MDS. + * + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + */ + constructor(X: T, parameters?: Partial); + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + generator(): Generator; + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {T} + */ + transform(): T; + _d_X: Matrix | undefined; + /** @returns {number} - The stress of the projection. */ + stress(): number; } /** @import {InputType} from "../index.js" */ @@ -2373,67 +2504,58 @@ declare class MDS extends DR { * // [[x1, y1], [x2, y2], [x3, y3]] */ declare class PCA extends DR { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {T} - */ - static transform(X: T_1, parameters: Partial): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Matrix} - */ - static principal_components( - X: T_1, - parameters: Partial, - ): Matrix; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static generator( - X: T_1, - parameters?: Partial, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters?: Partial, - ): Promise; - /** - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - */ - constructor(X: T, parameters?: Partial); - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - generator(): Generator; - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {T} - The projected data. - */ - transform(): T; - /** - * Computes the `d` principal components of Matrix `X`. - * - * @returns {Matrix} - */ - principal_components(): Matrix; - V: Matrix | undefined; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {T} + */ + static transform(X: T_1, parameters: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Matrix} + */ + static principal_components(X: T_1, parameters: Partial): Matrix; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static generator(X: T_1, parameters?: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static transform_async(X: T_1, parameters?: Partial): Promise; + /** + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + */ + constructor(X: T, parameters?: Partial); + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + generator(): Generator; + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {T} - The projected data. + */ + transform(): T; + /** + * Computes the `d` principal components of Matrix `X`. + * + * @returns {Matrix} + */ + principal_components(): Matrix; + V: Matrix | undefined; } /** @import {InputType} from "../index.js" */ @@ -2452,76 +2574,67 @@ declare class PCA extends DR { * @category Dimensionality Reduction */ declare class SAMMON extends DR> { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial>} [parameters] - * @returns {T} - */ - static transform( - X: T_1, - parameters?: Partial>, - ): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial>} [parameters] - * @returns {Generator} - */ - static generator( - X: T_1, - parameters?: Partial>, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial>} [parameters] - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters?: Partial>, - ): Promise; - /** - * SAMMON's Mapping - * - * @param {T} X - The high-dimensional data. - * @param {Partial>} [parameters] - Object containing parameterization of the DR - * method. - * @see {@link https://arxiv.org/pdf/2009.01512.pdf} - */ - constructor(X: T, parameters?: Partial>); - /** @type {Matrix | undefined} */ - distance_matrix: Matrix | undefined; - /** - * Initializes the projection. - * - * @param {Matrix | undefined} D - * @returns {asserts D is Matrix} - */ - init(D: Matrix | undefined): asserts D is Matrix; - /** - * Transforms the inputdata `X` to dimensionality 2. - * - * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200` - * @returns {T} The projection of `X`. - */ - transform(max_iter?: number): T; - /** - * Transforms the inputdata `X` to dimenionality 2. - * - * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200` - * @returns {Generator} A generator yielding the intermediate steps of the projection of - * `X`. - */ - generator(max_iter?: number): Generator; - _step(): Matrix; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial>} [parameters] + * @returns {T} + */ + static transform(X: T_1, parameters?: Partial>): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial>} [parameters] + * @returns {Generator} + */ + static generator(X: T_1, parameters?: Partial>): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial>} [parameters] + * @returns {Promise} + */ + static transform_async(X: T_1, parameters?: Partial>): Promise; + /** + * SAMMON's Mapping + * + * @param {T} X - The high-dimensional data. + * @param {Partial>} [parameters] - Object containing parameterization of the DR + * method. + * @see {@link https://arxiv.org/pdf/2009.01512.pdf} + */ + constructor(X: T, parameters?: Partial>); + /** @type {Matrix | undefined} */ + distance_matrix: Matrix | undefined; + /** + * Initializes the projection. + * + * @param {Matrix | undefined} D + * @returns {asserts D is Matrix} + */ + init(D: Matrix | undefined): asserts D is Matrix; + /** + * Transforms the inputdata `X` to dimensionality 2. + * + * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200` + * @returns {T} The projection of `X`. + */ + transform(max_iter?: number): T; + /** + * Transforms the inputdata `X` to dimenionality 2. + * + * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200` + * @returns {Generator} A generator yielding the intermediate steps of the projection of + * `X`. + */ + generator(max_iter?: number): Generator; + _step(): Matrix; } type AvailableInit = "PCA" | "MDS" | "random"; type ChooseDR = { - PCA: ParametersPCA; - MDS: ParametersMDS; - random: {}; + PCA: ParametersPCA; + MDS: ParametersMDS; + random: {}; }; /** @import {InputType} from "../index.js" */ @@ -2540,48 +2653,42 @@ type ChooseDR = { * @see {@link MDS} for the classical approach. */ declare class SMACOF extends DR { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X: T_1, parameters?: Partial): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static generator( - X: T_1, - parameters?: Partial, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters?: Partial, - ): Promise; - /** - * SMACOF for MDS. - * - * @param {T} X - The high-dimensional data or precomputed distance matrix. - * @param {Partial} [parameters] - Object containing parameterization. - */ - constructor(X: T, parameters?: Partial); - /** - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - generator(): Generator; - /** - * @returns {T} - */ - transform(): T; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X: T_1, parameters?: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static generator(X: T_1, parameters?: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static transform_async(X: T_1, parameters?: Partial): Promise; + /** + * SMACOF for MDS. + * + * @param {T} X - The high-dimensional data or precomputed distance matrix. + * @param {Partial} [parameters] - Object containing parameterization. + */ + constructor(X: T, parameters?: Partial); + /** + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + generator(): Generator; + /** + * @returns {T} + */ + transform(): T; } /** @import {InputType} from "../index.js" */ @@ -2599,174 +2706,152 @@ declare class SMACOF extends DR { * @category Dimensionality Reduction */ declare class SQDMDS extends DR { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X: T_1, parameters?: Partial): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static generator( - X: T_1, - parameters?: Partial, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters?: Partial, - ): Promise; - /** - * SQuadMDS: a lean Stochastic Quartet MDS improving global structure preservation in neighbor embedding like t-SNE - * and UMAP. - * - * @param {T} X - * @param {Partial} [parameters] - * @see {@link https://arxiv.org/pdf/2202.12087.pdf} - */ - constructor(X: T, parameters?: Partial); - init(): void; - _add: ((...summands: Float64Array[]) => Float64Array) | undefined; - _sub_div: - | (( - x: Float64Array, - y: Float64Array, - div: number, - ) => Float64Array) - | undefined; - _minus: - | ((a: Float64Array, b: Float64Array) => Float64Array) - | undefined; - _mult: ((a: Float64Array, v: number) => Float64Array) | undefined; - _LR_init: number | undefined; - _LR: number | undefined; - _offset: number | undefined; - _momentums: Matrix | undefined; - _grads: Matrix | undefined; - _indices: number[] | undefined; - /** @type {(i: number, j: number, X: Matrix) => number} */ - _HD_metric: ((i: number, j: number, X: Matrix) => number) | undefined; - /** @type {(i: number, j: number, X: Matrix) => number} */ - _HD_metric_exaggeration: ((i: number, j: number, X: Matrix) => number) | undefined; - /** - * Computes the projection. - * - * @param {number} [iterations=500] - Number of iterations. Default is `500` - * @returns {T} The projection. - */ - transform(iterations?: number): T; - _decay_start: number | undefined; - /** - * Computes the projection. - * - * @param {number} [iterations=500] - Number of iterations. Default is `500` - * @returns {Generator} The intermediate steps of the projection. - */ - generator(iterations?: number): Generator; - /** - * Performs an optimization step. - * - * @private - * @param {number} i - Acutal iteration. - * @param {number} iterations - Number of iterations. - */ - private _step; - _distance_exaggeration: boolean | undefined; - /** - * Creates quartets of non overlapping indices. - * - * @private - * @returns {Uint32Array[]} - */ - private __quartets; - /** - * Computes and applies gradients, and updates momentum. - * - * @private - * @param {boolean} distance_exaggeration - */ - private _nestrov_iteration; - /** - * Computes the gradients. - * - * @param {Matrix} Y - The Projection. - * @param {Matrix} grads - The gradients. - * @param {boolean} [exaggeration=false] - Whether or not to use early exaggeration. Default is `false` - * @param {boolean} [zero_grad=true] - Whether or not to reset the gradient in the beginning. Default is `true` - * @returns {Matrix} The gradients. - */ - _fill_MDS_grads(Y: Matrix, grads: Matrix, exaggeration?: boolean, zero_grad?: boolean): Matrix; - /** - * Quartet gradients for a projection. - * - * @private - * @param {Matrix} Y - The acutal projection. - * @param {number[]} quartet - The indices of the quartet. - * @param {Float64Array} D_hd - The high-dimensional distances of the quartet. - * @returns {Float64Array[]} The gradients for the quartet. - */ - private _compute_quartet_grads; - /** - * Gradients for one element of the loss function's sum. - * - * @private - * @param {Float64Array} a - * @param {Float64Array} b - * @param {Float64Array} c - * @param {Float64Array} d - * @param {number} d_ab - * @param {number} d_ac - * @param {number} d_ad - * @param {number} d_bc - * @param {number} d_bd - * @param {number} d_cd - * @param {number} p_ab - * @param {number} sum_LD_dist - * @returns {Float64Array[]} - */ - private _ABCD_grads; - /** - * Inline! - * - * @param {number} d - */ - __minus( - d: number, - ): (a: Float64Array, b: Float64Array) => Float64Array; - /** - * Inline! - * - * @param {number} d - */ - __add(d: number): (...summands: Float64Array[]) => Float64Array; - /** - * Inline! - * - * @param {number} d - */ - __mult(d: number): (a: Float64Array, v: number) => Float64Array; - /** - * Creates a new array `(x - y) / div`. - * - * @param {number} d - */ - __sub_div( - d: number, - ): ( - x: Float64Array, - y: Float64Array, - div: number, - ) => Float64Array; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X: T_1, parameters?: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static generator(X: T_1, parameters?: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static transform_async(X: T_1, parameters?: Partial): Promise; + /** + * SQuadMDS: a lean Stochastic Quartet MDS improving global structure preservation in neighbor embedding like t-SNE + * and UMAP. + * + * @param {T} X + * @param {Partial} [parameters] + * @see {@link https://arxiv.org/pdf/2202.12087.pdf} + */ + constructor(X: T, parameters?: Partial); + init(): void; + _add: ((...summands: Float64Array[]) => Float64Array) | undefined; + _sub_div: ((x: Float64Array, y: Float64Array, div: number) => Float64Array) | undefined; + _minus: ((a: Float64Array, b: Float64Array) => Float64Array) | undefined; + _mult: ((a: Float64Array, v: number) => Float64Array) | undefined; + _LR_init: number | undefined; + _LR: number | undefined; + _offset: number | undefined; + _momentums: Matrix | undefined; + _grads: Matrix | undefined; + _indices: number[] | undefined; + /** @type {(i: number, j: number, X: Matrix) => number} */ + _HD_metric: ((i: number, j: number, X: Matrix) => number) | undefined; + /** @type {(i: number, j: number, X: Matrix) => number} */ + _HD_metric_exaggeration: ((i: number, j: number, X: Matrix) => number) | undefined; + /** + * Computes the projection. + * + * @param {number} [iterations=500] - Number of iterations. Default is `500` + * @returns {T} The projection. + */ + transform(iterations?: number): T; + _decay_start: number | undefined; + /** + * Computes the projection. + * + * @param {number} [iterations=500] - Number of iterations. Default is `500` + * @returns {Generator} The intermediate steps of the projection. + */ + generator(iterations?: number): Generator; + /** + * Performs an optimization step. + * + * @private + * @param {number} i - Acutal iteration. + * @param {number} iterations - Number of iterations. + */ + private _step; + _distance_exaggeration: boolean | undefined; + /** + * Creates quartets of non overlapping indices. + * + * @private + * @returns {Uint32Array[]} + */ + private __quartets; + /** + * Computes and applies gradients, and updates momentum. + * + * @private + * @param {boolean} distance_exaggeration + */ + private _nestrov_iteration; + /** + * Computes the gradients. + * + * @param {Matrix} Y - The Projection. + * @param {Matrix} grads - The gradients. + * @param {boolean} [exaggeration=false] - Whether or not to use early exaggeration. Default is `false` + * @param {boolean} [zero_grad=true] - Whether or not to reset the gradient in the beginning. Default is `true` + * @returns {Matrix} The gradients. + */ + _fill_MDS_grads(Y: Matrix, grads: Matrix, exaggeration?: boolean, zero_grad?: boolean): Matrix; + /** + * Quartet gradients for a projection. + * + * @private + * @param {Matrix} Y - The acutal projection. + * @param {number[]} quartet - The indices of the quartet. + * @param {Float64Array} D_hd - The high-dimensional distances of the quartet. + * @returns {Float64Array[]} The gradients for the quartet. + */ + private _compute_quartet_grads; + /** + * Gradients for one element of the loss function's sum. + * + * @private + * @param {Float64Array} a + * @param {Float64Array} b + * @param {Float64Array} c + * @param {Float64Array} d + * @param {number} d_ab + * @param {number} d_ac + * @param {number} d_ad + * @param {number} d_bc + * @param {number} d_bd + * @param {number} d_cd + * @param {number} p_ab + * @param {number} sum_LD_dist + * @returns {Float64Array[]} + */ + private _ABCD_grads; + /** + * Inline! + * + * @param {number} d + */ + __minus(d: number): (a: Float64Array, b: Float64Array) => Float64Array; + /** + * Inline! + * + * @param {number} d + */ + __add(d: number): (...summands: Float64Array[]) => Float64Array; + /** + * Inline! + * + * @param {number} d + */ + __mult(d: number): (a: Float64Array, v: number) => Float64Array; + /** + * Creates a new array `(x - y) / div`. + * + * @param {number} d + */ + __sub_div(d: number): (x: Float64Array, y: Float64Array, div: number) => Float64Array; } /** @import {InputType} from "../index.js" */ @@ -2784,136 +2869,130 @@ declare class SQDMDS extends DR { * @category Dimensionality Reduction */ declare class TopoMap extends DR { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {T} - */ - static transform(X: T_1, parameters: Partial): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Generator} - */ - static generator( - X: T_1, - parameters: Partial, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters: Partial, - ): Promise; - /** - * TopoMap: A 0-dimensional Homology Preserving Projection of High-Dimensional Data. - * - * @param {T} X - The high-dimensional data. - * @param {Partial} parameters - Object containing parameterization of the DR method. - * @see {@link https://arxiv.org/pdf/2009.01512.pdf} - */ - constructor(X: T, parameters: Partial); - _distance_matrix: Matrix; - /** - * @private - * @param {number} i - * @param {number} j - * @param {import("../metrics/index.js").Metric} metric - * @returns {number} - */ - private __lazy_distance_matrix; - /** - * Computes the minimum spanning tree, using a given metric - * - * @private - * @param {import("../metrics/index.js").Metric} metric - * @see {@link https://en.wikipedia.org/wiki/Kruskal%27s_algorithm} - */ - private _make_minimum_spanning_tree; - _disjoint_set: DisjointSet> | undefined; - /** Initializes TopoMap. Sets all projcted points to zero, and computes a minimum spanning tree. */ - init(): this; - _Emst: number[][] | undefined; - /** - * Returns true if Point C is left of line AB. - * - * @private - * @param {Float64Array} PointA - Point A of line AB - * @param {Float64Array} PointB - Point B of line AB - * @param {Float64Array} PointC - Point C - * @returns {boolean} - */ - private __hull_cross; - /** - * Computes the convex hull of the set of Points S - * - * @private - * @param {Float64Array[]} S - Set of Points. - * @returns {Float64Array[]} Convex hull of S. Starts at the bottom-most point and continues counter-clockwise. - * @see {@link https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain#JavaScript} - */ - private __hull; - /** - * Finds the angle to rotate Point A and B to lie on a line parallel to the x-axis. - * - * @private - * @param {Float64Array} PointA - * @param {Float64Array} PointB - * @returns {{ sin: number; cos: number }} Object containing the sinus- and cosinus-values for a rotation. - */ - private __findAngle; - /** - * @private - * @param {Float64Array[]} hull - * @param {Float64Array} p - * @param {boolean} topEdge - * @returns {{ sin: number; cos: number; tx: number; ty: number }} - */ - private __align_hull; - /** - * @private - * @param {Float64Array} Point - The point which should get transformed. - * @param {{ sin: number; cos: number; tx: number; ty: number }} Transformation - Contains the values for - * translation and rotation. - */ - private __transform; - /** - * Calls `__transform` for each point in Set C - * - * @private - * @param {Float64Array[]} C - Set of points. - * @param {{ sin: number; cos: number; tx: number; ty: number }} t - Transform object. - * @param {number} yOffset - Value to offset set C. - */ - private __transform_component; - /** - * @private - * @param {Float64Array} root_u - Root of component u - * @param {Float64Array} root_v - Root of component v - * @param {Float64Array} p_u - Point u - * @param {Float64Array} p_v - Point v - * @param {number} w - Edge weight w - * @param {DisjointSet} components - The disjoint set containing the components - */ - private __align_components; - /** - * Transforms the inputdata `X` to dimensionality 2. - * - * @returns {T} - */ - transform(): T; - /** - * Transforms the inputdata `X` to dimensionality 2. - * - * @returns {Generator} - */ - generator(): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {T} + */ + static transform(X: T_1, parameters: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Generator} + */ + static generator(X: T_1, parameters: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Promise} + */ + static transform_async(X: T_1, parameters: Partial): Promise; + /** + * TopoMap: A 0-dimensional Homology Preserving Projection of High-Dimensional Data. + * + * @param {T} X - The high-dimensional data. + * @param {Partial} parameters - Object containing parameterization of the DR method. + * @see {@link https://arxiv.org/pdf/2009.01512.pdf} + */ + constructor(X: T, parameters: Partial); + _distance_matrix: Matrix; + /** + * @private + * @param {number} i + * @param {number} j + * @param {import("../metrics/index.js").Metric} metric + * @returns {number} + */ + private __lazy_distance_matrix; + /** + * Computes the minimum spanning tree, using a given metric + * + * @private + * @param {import("../metrics/index.js").Metric} metric + * @see {@link https://en.wikipedia.org/wiki/Kruskal%27s_algorithm} + */ + private _make_minimum_spanning_tree; + _disjoint_set: DisjointSet> | undefined; + /** Initializes TopoMap. Sets all projcted points to zero, and computes a minimum spanning tree. */ + init(): this; + _Emst: number[][] | undefined; + /** + * Returns true if Point C is left of line AB. + * + * @private + * @param {Float64Array} PointA - Point A of line AB + * @param {Float64Array} PointB - Point B of line AB + * @param {Float64Array} PointC - Point C + * @returns {boolean} + */ + private __hull_cross; + /** + * Computes the convex hull of the set of Points S + * + * @private + * @param {Float64Array[]} S - Set of Points. + * @returns {Float64Array[]} Convex hull of S. Starts at the bottom-most point and continues counter-clockwise. + * @see {@link https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain#JavaScript} + */ + private __hull; + /** + * Finds the angle to rotate Point A and B to lie on a line parallel to the x-axis. + * + * @private + * @param {Float64Array} PointA + * @param {Float64Array} PointB + * @returns {{ sin: number; cos: number }} Object containing the sinus- and cosinus-values for a rotation. + */ + private __findAngle; + /** + * @private + * @param {Float64Array[]} hull + * @param {Float64Array} p + * @param {boolean} topEdge + * @returns {{ sin: number; cos: number; tx: number; ty: number }} + */ + private __align_hull; + /** + * @private + * @param {Float64Array} Point - The point which should get transformed. + * @param {{ sin: number; cos: number; tx: number; ty: number }} Transformation - Contains the values for + * translation and rotation. + */ + private __transform; + /** + * Calls `__transform` for each point in Set C + * + * @private + * @param {Float64Array[]} C - Set of points. + * @param {{ sin: number; cos: number; tx: number; ty: number }} t - Transform object. + * @param {number} yOffset - Value to offset set C. + */ + private __transform_component; + /** + * @private + * @param {Float64Array} root_u - Root of component u + * @param {Float64Array} root_v - Root of component v + * @param {Float64Array} p_u - Point u + * @param {Float64Array} p_v - Point v + * @param {number} w - Edge weight w + * @param {DisjointSet} components - The disjoint set containing the components + */ + private __align_components; + /** + * Transforms the inputdata `X` to dimensionality 2. + * + * @returns {T} + */ + transform(): T; + /** + * Transforms the inputdata `X` to dimensionality 2. + * + * @returns {Generator} + */ + generator(): Generator; } /** @@ -2928,45 +3007,39 @@ declare class TopoMap extends DR { * @class */ declare class KNN { - /** - * @param {T[]} elements - * @param {Para} parameters - */ - constructor(elements: T[], parameters: Para); - /** @type {T[]} */ - _elements: T[]; - /** @type {Para} */ - _parameters: Para; - /** @type {"typed" | "array"} */ - _type: "typed" | "array"; - /** - * @abstract - * @param {T} t - * @param {number} k - * @returns {{ element: T; index: number; distance: number }[]} - */ - search( - t: T, - k: number, - ): { - element: T; - index: number; - distance: number; - }[]; - /** - * @abstract - * @param {number} i - * @param {number} k - * @returns {{ element: T; index: number; distance: number }[]} - */ - search_by_index( - i: number, - k: number, - ): { - element: T; - index: number; - distance: number; - }[]; + /** + * @param {T[]} elements + * @param {Para} parameters + */ + constructor(elements: T[], parameters: Para); + /** @type {T[]} */ + _elements: T[]; + /** @type {Para} */ + _parameters: Para; + /** @type {"typed" | "array"} */ + _type: "typed" | "array"; + /** + * @abstract + * @param {T} t + * @param {number} k + * @returns {{ element: T; index: number; distance: number }[]} + */ + search(t: T, k: number): { + element: T; + index: number; + distance: number; + }[]; + /** + * @abstract + * @param {number} i + * @param {number} k + * @returns {{ element: T; index: number; distance: number }[]} + */ + search_by_index(i: number, k: number): { + element: T; + index: number; + distance: number; + }[]; } /** @import {InputType} from "../index.js" */ @@ -2986,164 +3059,154 @@ declare class KNN { * @category Dimensionality Reduction */ declare class TriMap extends DR { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X: T_1, parameters?: Partial): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static generator( - X: T_1, - parameters?: Partial, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters?: Partial, - ): Promise; - /** - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - * @see {@link https://arxiv.org/pdf/1910.00204v1.pdf} - * @see {@link https://github.com/eamid/trimap} - */ - constructor(X: T, parameters?: Partial); - /** - * @param {Matrix | null} [pca=null] - Initial Embedding (if null then PCA gets used). Default is `null` - * @param {import("../knn/KNN.js").KNN | null} [knn=null] - KNN Object (if null then BallTree gets used). Default is `null` - */ - init(pca?: Matrix | null, knn?: KNN | null): this; - n_inliers: number | undefined; - n_outliers: number | undefined; - n_random: number | undefined; - knn: KNN, any> | undefined; - triplets: Matrix | undefined; - weights: Float64Array | undefined; - lr: number | undefined; - C: number | undefined; - vel: Matrix | undefined; - gain: Matrix | undefined; - /** - * Generates {@link n_inliers} x {@link n_outliers} x {@link n_random} triplets. - * - * @param {number} n_inliers - * @param {number} n_outliers - * @param {number} n_random - */ - _generate_triplets( - n_inliers: number, - n_outliers: number, - n_random: number, - ): { - triplets: Matrix; - weights: Float64Array; - }; - /** - * Calculates the similarity matrix P - * - * @private - * @param {Matrix} knn_distances - Matrix of pairwise knn distances - * @param {Float64Array} sig - Scaling factor for the distances - * @param {Matrix} nbrs - Nearest neighbors - * @returns {Matrix} Pairwise similarity matrix - */ - private _find_p; - /** - * Sample nearest neighbors triplets based on the similarity values given in P. - * - * @private - * @param {Matrix} P - Matrix of pairwise similarities between each point and its neighbors given in matrix nbrs. - * @param {Matrix} nbrs - Nearest neighbors indices for each point. The similarity values are given in matrix - * {@link P}. Row i corresponds to the i-th point. - * @param {number} n_inliers - Number of inlier points. - * @param {number} n_outliers - Number of outlier points. - */ - private _sample_knn_triplets; - /** - * Should do the same as np.argsort() - * - * @private - * @param {Float64Array | number[]} A - */ - private __argsort; - /** - * Samples {@link n_samples} integers from a given interval [0, {@link max_int}] while rejection the values that are - * in the {@link rejects}. - * - * @private - * @param {number} n_samples - * @param {number} max_int - * @param {number[]} rejects - */ - private _rejection_sample; - /** - * Calculates the weights for the sampled nearest neighbors triplets - * - * @private - * @param {Matrix} triplets - Sampled Triplets. - * @param {Matrix} P - Pairwise similarity matrix. - * @param {Matrix} nbrs - Nearest Neighbors - * @param {Float64Array} outlier_distances - Matrix of pairwise outlier distances - * @param {Float64Array} sig - Scaling factor for the distances. - */ - private _find_weights; - /** - * Sample uniformly ranom triplets - * - * @private - * @param {Matrix} X - Data matrix. - * @param {number} n_random - Number of random triplets per point - * @param {Float64Array} sig - Scaling factor for the distances - */ - private _sample_random_triplets; - /** - * Computes the gradient for updating the embedding. - * - * @param {Matrix} Y - The embedding - */ - _grad(Y: Matrix): { - grad: Matrix; - loss: number; - n_viol: number; - }; - /** - * @param {number} max_iteration - * @returns {T} - */ - transform(max_iteration?: number): T; - /** - * @param {number} max_iteration - * @returns {Generator} - */ - generator(max_iteration?: number): Generator; - /** - * Does the iteration step. - * - * @private - * @param {number} iter - */ - private _next; - /** - * Updates the embedding. - * - * @private - * @param {Matrix} Y - * @param {number} iter - * @param {Matrix} grad - */ - private _update_embedding; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X: T_1, parameters?: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static generator(X: T_1, parameters?: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static transform_async(X: T_1, parameters?: Partial): Promise; + /** + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + * @see {@link https://arxiv.org/pdf/1910.00204v1.pdf} + * @see {@link https://github.com/eamid/trimap} + */ + constructor(X: T, parameters?: Partial); + /** + * @param {Matrix | null} [pca=null] - Initial Embedding (if null then PCA gets used). Default is `null` + * @param {import("../knn/KNN.js").KNN | null} [knn=null] - KNN Object (if null then BallTree gets used). Default is `null` + */ + init(pca?: Matrix | null, knn?: KNN | null): this; + n_inliers: number | undefined; + n_outliers: number | undefined; + n_random: number | undefined; + knn: KNN, any> | undefined; + triplets: Matrix | undefined; + weights: Float64Array | undefined; + lr: number | undefined; + C: number | undefined; + vel: Matrix | undefined; + gain: Matrix | undefined; + /** + * Generates {@link n_inliers} x {@link n_outliers} x {@link n_random} triplets. + * + * @param {number} n_inliers + * @param {number} n_outliers + * @param {number} n_random + */ + _generate_triplets(n_inliers: number, n_outliers: number, n_random: number): { + triplets: Matrix; + weights: Float64Array; + }; + /** + * Calculates the similarity matrix P + * + * @private + * @param {Matrix} knn_distances - Matrix of pairwise knn distances + * @param {Float64Array} sig - Scaling factor for the distances + * @param {Matrix} nbrs - Nearest neighbors + * @returns {Matrix} Pairwise similarity matrix + */ + private _find_p; + /** + * Sample nearest neighbors triplets based on the similarity values given in P. + * + * @private + * @param {Matrix} P - Matrix of pairwise similarities between each point and its neighbors given in matrix nbrs. + * @param {Matrix} nbrs - Nearest neighbors indices for each point. The similarity values are given in matrix + * {@link P}. Row i corresponds to the i-th point. + * @param {number} n_inliers - Number of inlier points. + * @param {number} n_outliers - Number of outlier points. + */ + private _sample_knn_triplets; + /** + * Should do the same as np.argsort() + * + * @private + * @param {Float64Array | number[]} A + */ + private __argsort; + /** + * Samples {@link n_samples} integers from a given interval [0, {@link max_int}] while rejection the values that are + * in the {@link rejects}. + * + * @private + * @param {number} n_samples + * @param {number} max_int + * @param {number[]} rejects + */ + private _rejection_sample; + /** + * Calculates the weights for the sampled nearest neighbors triplets + * + * @private + * @param {Matrix} triplets - Sampled Triplets. + * @param {Matrix} P - Pairwise similarity matrix. + * @param {Matrix} nbrs - Nearest Neighbors + * @param {Float64Array} outlier_distances - Matrix of pairwise outlier distances + * @param {Float64Array} sig - Scaling factor for the distances. + */ + private _find_weights; + /** + * Sample uniformly ranom triplets + * + * @private + * @param {Matrix} X - Data matrix. + * @param {number} n_random - Number of random triplets per point + * @param {Float64Array} sig - Scaling factor for the distances + */ + private _sample_random_triplets; + /** + * Computes the gradient for updating the embedding. + * + * @param {Matrix} Y - The embedding + */ + _grad(Y: Matrix): { + grad: Matrix; + loss: number; + n_viol: number; + }; + /** + * @param {number} max_iteration + * @returns {T} + */ + transform(max_iteration?: number): T; + /** + * @param {number} max_iteration + * @returns {Generator} + */ + generator(max_iteration?: number): Generator; + /** + * Does the iteration step. + * + * @private + * @param {number} iter + */ + private _next; + /** + * Updates the embedding. + * + * @private + * @param {Matrix} Y + * @param {number} iter + * @param {Matrix} grad + */ + private _update_embedding; } /** @import {InputType} from "../index.js" */ @@ -3178,60 +3241,54 @@ declare class TriMap extends DR { * // [[x1, y1], [x2, y2], [x3, y3]] */ declare class TSNE extends DR { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X: T_1, parameters?: Partial): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static generator( - X: T_1, - parameters?: Partial, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters?: Partial, - ): Promise; - /** - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - */ - constructor(X: T, parameters?: Partial); - _iter: number; - init(): this; - _ystep: Matrix | undefined; - _gains: Matrix | undefined; - _P: Matrix | undefined; - /** - * @param {number} [iterations=500] - Number of iterations. Default is `500` - * @returns {T} The projection. - */ - transform(iterations?: number): T; - /** - * @param {number} [iterations=500] - Number of iterations. Default is `500` - * @returns {Generator} - The projection. - */ - generator(iterations?: number): Generator; - /** - * Performs a optimization step - * - * @private - * @returns {Matrix} - */ - private next; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X: T_1, parameters?: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static generator(X: T_1, parameters?: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static transform_async(X: T_1, parameters?: Partial): Promise; + /** + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + */ + constructor(X: T, parameters?: Partial); + _iter: number; + init(): this; + _ystep: Matrix | undefined; + _gains: Matrix | undefined; + _P: Matrix | undefined; + /** + * @param {number} [iterations=500] - Number of iterations. Default is `500` + * @returns {T} The projection. + */ + transform(iterations?: number): T; + /** + * @param {number} [iterations=500] - Number of iterations. Default is `500` + * @returns {Generator} - The projection. + */ + generator(iterations?: number): Generator; + /** + * Performs a optimization step + * + * @private + * @returns {Matrix} + */ + private next; } /** @import {InputType} from "../index.js" */ @@ -3266,138 +3323,132 @@ declare class TSNE extends DR { * // [[x1, y1], [x2, y2], [x3, y3]] */ declare class UMAP extends DR { - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X: T_1, parameters?: Partial): T_1; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static generator( - X: T_1, - parameters?: Partial, - ): Generator; - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static transform_async( - X: T_1, - parameters?: Partial, - ): Promise; - /** - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - */ - constructor(X: T, parameters?: Partial); - _iter: number; - /** - * @private - * @param {number} spread - * @param {number} min_dist - * @returns {number[]} - */ - private _find_ab_params; - /** - * @private - * @param {{ element: Float64Array; index: number; distance: number }[][]} distances - * @param {number[]} sigmas - * @param {number[]} rhos - * @returns {{ element: Float64Array; index: number; distance: number }[][]} - */ - private _compute_membership_strengths; - /** - * @private - * @param {NaiveKNN | BallTree} knn - * @param {number} k - * @returns {{ - * distances: { element: Float64Array; index: number; distance: number }[][]; - * sigmas: number[]; - * rhos: number[]; - * }} - */ - private _smooth_knn_dist; - /** - * @private - * @param {Matrix} X - * @param {number} n_neighbors - * @returns {Matrix} - */ - private _fuzzy_simplicial_set; - /** - * @private - * @param {number} n_epochs - * @returns {Float32Array} - */ - private _make_epochs_per_sample; - /** - * @private - * @param {Matrix} graph - * @returns {{ rows: number[]; cols: number[]; data: number[] }} - */ - private _tocoo; - /** - * Computes all necessary - * - * @returns {UMAP} - */ - init(): UMAP; - _a: number | undefined; - _b: number | undefined; - _graph: Matrix | undefined; - _head: number[] | undefined; - _tail: number[] | undefined; - _weights: number[] | undefined; - _epochs_per_sample: Float32Array | undefined; - _epochs_per_negative_sample: Float32Array | undefined; - _epoch_of_next_sample: Float32Array | undefined; - _epoch_of_next_negative_sample: Float32Array | undefined; - graph(): { - cols: number[] | undefined; - rows: number[] | undefined; - weights: number[] | undefined; - }; - /** - * @param {number} [iterations=350] - Number of iterations. Default is `350` - * @returns {T} - */ - transform(iterations?: number): T; - /** - * @param {number} [iterations=350] - Number of iterations. Default is `350` - * @returns {Generator} - */ - generator(iterations?: number): Generator; - /** - * @private - * @param {number} x - * @returns {number} - */ - private _clip; - /** - * Performs the optimization step. - * - * @private - * @param {Matrix} head_embedding - * @param {Matrix} tail_embedding - * @param {number[]} head - * @param {number[]} tail - * @returns {Matrix} - */ - private _optimize_layout; - /** - * @private - * @returns {Matrix} - */ - private next; - _alpha: number | undefined; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X: T_1, parameters?: Partial): T_1; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static generator(X: T_1, parameters?: Partial): Generator; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static transform_async(X: T_1, parameters?: Partial): Promise; + /** + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + */ + constructor(X: T, parameters?: Partial); + _iter: number; + /** + * @private + * @param {number} spread + * @param {number} min_dist + * @returns {number[]} + */ + private _find_ab_params; + /** + * @private + * @param {{ element: Float64Array; index: number; distance: number }[][]} distances + * @param {number[]} sigmas + * @param {number[]} rhos + * @returns {{ element: Float64Array; index: number; distance: number }[][]} + */ + private _compute_membership_strengths; + /** + * @private + * @param {NaiveKNN | BallTree} knn + * @param {number} k + * @returns {{ + * distances: { element: Float64Array; index: number; distance: number }[][]; + * sigmas: number[]; + * rhos: number[]; + * }} + */ + private _smooth_knn_dist; + /** + * @private + * @param {Matrix} X + * @param {number} n_neighbors + * @returns {Matrix} + */ + private _fuzzy_simplicial_set; + /** + * @private + * @param {number} n_epochs + * @returns {Float32Array} + */ + private _make_epochs_per_sample; + /** + * @private + * @param {Matrix} graph + * @returns {{ rows: number[]; cols: number[]; data: number[] }} + */ + private _tocoo; + /** + * Computes all necessary + * + * @returns {UMAP} + */ + init(): UMAP; + _a: number | undefined; + _b: number | undefined; + _graph: Matrix | undefined; + _head: number[] | undefined; + _tail: number[] | undefined; + _weights: number[] | undefined; + _epochs_per_sample: Float32Array | undefined; + _epochs_per_negative_sample: Float32Array | undefined; + _epoch_of_next_sample: Float32Array | undefined; + _epoch_of_next_negative_sample: Float32Array | undefined; + graph(): { + cols: number[] | undefined; + rows: number[] | undefined; + weights: number[] | undefined; + }; + /** + * @param {number} [iterations=350] - Number of iterations. Default is `350` + * @returns {T} + */ + transform(iterations?: number): T; + /** + * @param {number} [iterations=350] - Number of iterations. Default is `350` + * @returns {Generator} + */ + generator(iterations?: number): Generator; + /** + * @private + * @param {number} x + * @returns {number} + */ + private _clip; + /** + * Performs the optimization step. + * + * @private + * @param {Matrix} head_embedding + * @param {Matrix} tail_embedding + * @param {number[]} head + * @param {number[]} tail + * @returns {Matrix} + */ + private _optimize_layout; + /** + * @private + * @returns {Matrix} + */ + private next; + _alpha: number | undefined; } /** @@ -3419,8 +3470,8 @@ declare function inner_product(a: number[] | Float64Array, b: number[] | Float64 * @see {@link https://en.wikipedia.org/wiki/QR_decomposition#Using_the_Gram%E2%80%93Schmidt_process} */ declare function qr(A: Matrix): { - R: Matrix; - Q: Matrix; + R: Matrix; + Q: Matrix; }; /** @@ -3433,8 +3484,8 @@ declare function qr(A: Matrix): { * @see {@link http://mlwiki.org/index.php/Householder_Transformation} */ declare function qr_householder(A: Matrix): { - R: Matrix; - Q: Matrix; + R: Matrix; + Q: Matrix; }; /** @import { EigenArgs } from "./index.js" */ @@ -3449,371 +3500,439 @@ declare function qr_householder(A: Matrix): { * @returns {{ eigenvalues: Float64Array; eigenvectors: Float64Array[] }} The `k` biggest eigenvectors and eigenvalues * of Matrix `A`. */ -declare function simultaneous_poweriteration( - A: Matrix, - k?: number, - { seed, max_iterations, qr, tol }?: EigenArgs, -): { - eigenvalues: Float64Array; - eigenvectors: Float64Array[]; +declare function simultaneous_poweriteration(A: Matrix, k?: number, { seed, max_iterations, qr, tol }?: EigenArgs): { + eigenvalues: Float64Array; + eigenvectors: Float64Array[]; }; type QRDecomposition = (A: Matrix) => { - R: Matrix; - Q: Matrix; + R: Matrix; + Q: Matrix; }; type EigenArgs = { - /** - * - The number of maxiumum iterations the algorithm should run. Default is `100` - */ - max_iterations?: number | undefined; - /** - * - The seed value or a randomizer used in the algorithm. Default is `1212` - */ - seed?: number | Randomizer | undefined; - /** - * - The QR technique to use. Default is `qr_gramschmidt` - */ - qr?: QRDecomposition | undefined; - /** - * - Tolerated error for stopping criteria. Default is `1e-8` - */ - tol?: number | undefined; + /** + * - The number of maxiumum iterations the algorithm should run. Default is `100` + */ + max_iterations?: number | undefined; + /** + * - The seed value or a randomizer used in the algorithm. Default is `1212` + */ + seed?: number | Randomizer | undefined; + /** + * - The QR technique to use. Default is `qr_gramschmidt` + */ + qr?: QRDecomposition | undefined; + /** + * - Tolerated error for stopping criteria. Default is `1e-8` + */ + tol?: number | undefined; }; type ParametersLSP = { - /** - * - number of neighbors to consider. - */ - neighbors?: number | undefined; - /** - * - number of controlpoints - */ - control_points?: number | undefined; - /** - * - the dimensionality of the projection. - */ - d?: number | undefined; - /** - * - the metric which defines the distance between two points. - */ - metric?: Metric | undefined; - /** - * - the seed for the random number generator. - */ - seed?: number | undefined; + /** + * - number of neighbors to consider. + */ + neighbors?: number | undefined; + /** + * - number of controlpoints + */ + control_points?: number | undefined; + /** + * - the dimensionality of the projection. + */ + d?: number | undefined; + /** + * - the metric which defines the distance between two points. + */ + metric?: Metric | undefined; + /** + * - the seed for the random number generator. + */ + seed?: number | undefined; }; type ParametersFASTMAP = { - /** - * - The dimensionality of the projection - */ - d?: number | undefined; - /** - * - The metric which defines the distance between two points. - */ - metric?: Metric | undefined; - /** - * - The seed for the random number generator. - */ - seed?: number | undefined; + /** + * - The dimensionality of the projection + */ + d?: number | undefined; + /** + * - The metric which defines the distance between two points. + */ + metric?: Metric | undefined; + /** + * - The seed for the random number generator. + */ + seed?: number | undefined; }; type ParametersISOMAP = { - /** - * - The number of neighbors ISOMAP should use to project the data. - */ - neighbors?: number | undefined; - /** - * - the dimensionality of the projection. - */ - d?: number | undefined; - /** - * - the metric which defines the distance between two points. - */ - metric?: Metric | undefined; - /** - * - Whether to use classical MDS or SMACOF for the final DR. - */ - project?: "MDS" | "SMACOF" | undefined; - /** - * - the seed for the random number generator. - */ - seed?: number | undefined; - /** - * - Parameters for the eigendecomposition algorithm. - */ - eig_args?: Partial | undefined; + /** + * - The number of neighbors ISOMAP should use to project the data. + */ + neighbors?: number | undefined; + /** + * - the dimensionality of the projection. + */ + d?: number | undefined; + /** + * - the metric which defines the distance between two points. + */ + metric?: Metric | undefined; + /** + * - Whether to use classical MDS or SMACOF for the final DR. + */ + project?: "MDS" | "SMACOF" | undefined; + /** + * - the seed for the random number generator. + */ + seed?: number | undefined; + /** + * - Parameters for the eigendecomposition algorithm. + */ + eig_args?: Partial | undefined; }; type ParametersLDA = { - /** - * - The labels / classes for each data point. - */ - labels: any[] | Float64Array; - /** - * - The dimensionality of the projection. - */ - d?: number | undefined; - /** - * - The seed for the random number generator. - */ - seed?: number | undefined; - /** - * - Parameters for the eigendecomposition algorithm. - */ - eig_args?: Partial | undefined; + /** + * - The labels / classes for each data point. + */ + labels: any[] | Float64Array; + /** + * - The dimensionality of the projection. + */ + d?: number | undefined; + /** + * - The seed for the random number generator. + */ + seed?: number | undefined; + /** + * - Parameters for the eigendecomposition algorithm. + */ + eig_args?: Partial | undefined; }; type ParametersLLE = { - /** - * - The number of neighbors for LLE. - */ - neighbors?: number | undefined; - /** - * - the dimensionality of the projection. - */ - d?: number | undefined; - /** - * - the metric which defines the distance between two points. - */ - metric?: Metric | undefined; - /** - * - the seed for the random number generator. - */ - seed?: number | undefined; - /** - * - Parameters for the eigendecomposition algorithm. - */ - eig_args?: Partial | undefined; + /** + * - The number of neighbors for LLE. + */ + neighbors?: number | undefined; + /** + * - the dimensionality of the projection. + */ + d?: number | undefined; + /** + * - the metric which defines the distance between two points. + */ + metric?: Metric | undefined; + /** + * - the seed for the random number generator. + */ + seed?: number | undefined; + /** + * - Parameters for the eigendecomposition algorithm. + */ + eig_args?: Partial | undefined; }; type ParametersLTSA = { - /** - * - The number of neighbors for LTSA. - */ - neighbors?: number | undefined; - /** - * - the dimensionality of the projection. - */ - d?: number | undefined; - /** - * - the metric which defines the distance between two points. - */ - metric?: Metric | undefined; - /** - * - the seed for the random number generator. - */ - seed?: number | undefined; - /** - * - Parameters for the eigendecomposition algorithm. - */ - eig_args?: Partial | undefined; + /** + * - The number of neighbors for LTSA. + */ + neighbors?: number | undefined; + /** + * - the dimensionality of the projection. + */ + d?: number | undefined; + /** + * - the metric which defines the distance between two points. + */ + metric?: Metric | undefined; + /** + * - the seed for the random number generator. + */ + seed?: number | undefined; + /** + * - Parameters for the eigendecomposition algorithm. + */ + eig_args?: Partial | undefined; }; type ParametersMDS = { - /** - * - the dimensionality of the projection. - */ - d?: number | undefined; - /** - * - the metric which defines the distance between two points. - */ - metric?: Metric | "precomputed" | undefined; - /** - * - the seed for the random number generator. - */ - seed?: number | undefined; - /** - * - Parameters for the eigendecomposition algorithm. - */ - eig_args?: Partial | undefined; + /** + * - the dimensionality of the projection. + */ + d?: number | undefined; + /** + * - the metric which defines the distance between two points. + */ + metric?: Metric | "precomputed" | undefined; + /** + * - the seed for the random number generator. + */ + seed?: number | undefined; + /** + * - Parameters for the eigendecomposition algorithm. + */ + eig_args?: Partial | undefined; }; type ParametersPCA = { - /** - * - the dimensionality of the projection. - */ - d?: number | undefined; - /** - * - the seed for the random number generator. - */ - seed?: number | undefined; - /** - * - Parameters for the eigendecomposition algorithm. - */ - eig_args?: Partial | undefined; + /** + * - the dimensionality of the projection. + */ + d?: number | undefined; + /** + * - the seed for the random number generator. + */ + seed?: number | undefined; + /** + * - Parameters for the eigendecomposition algorithm. + */ + eig_args?: Partial | undefined; }; type ParametersSAMMON = { - /** - * - the dimensionality of the projection. - */ - d?: number | undefined; - /** - * - the metric which defines the distance between two points. - */ - metric?: Metric | "precomputed" | undefined; - /** - * - Either "PCA" or "MDS", with which SAMMON initialiates the projection. - */ - init_DR?: K | undefined; - /** - * - Parameters for the "init"-DR method. - */ - init_parameters?: ChooseDR[K] | undefined; - /** - * - learning rate for gradient descent. - */ - magic?: number | undefined; - /** - * - the seed for the random number generator. - */ - seed?: number | undefined; + /** + * - the dimensionality of the projection. + */ + d?: number | undefined; + /** + * - the metric which defines the distance between two points. + */ + metric?: Metric | "precomputed" | undefined; + /** + * - Either "PCA" or "MDS", with which SAMMON initialiates the projection. + */ + init_DR?: K | undefined; + /** + * - Parameters for the "init"-DR method. + */ + init_parameters?: ChooseDR[K] | undefined; + /** + * - learning rate for gradient descent. + */ + magic?: number | undefined; + /** + * - the seed for the random number generator. + */ + seed?: number | undefined; }; type ParametersSMACOF = { - /** - * - the dimensionality of the projection. - */ - d?: number | undefined; - /** - * - the metric which defines the distance between two points. - */ - metric?: Metric | "precomputed" | undefined; - /** - * - maximum number of iterations. - */ - iterations?: number | undefined; - /** - * - tolerance for stress difference. - */ - epsilon?: number | undefined; - /** - * - the seed for the random number generator. - */ - seed?: number | undefined; + /** + * - the dimensionality of the projection. + */ + d?: number | undefined; + /** + * - the metric which defines the distance between two points. + */ + metric?: Metric | "precomputed" | undefined; + /** + * - maximum number of iterations. + */ + iterations?: number | undefined; + /** + * - tolerance for stress difference. + */ + epsilon?: number | undefined; + /** + * - the seed for the random number generator. + */ + seed?: number | undefined; }; type ParametersSQDMDS = { - d?: number | undefined; - metric?: Metric | "precomputed" | undefined; - /** - * - Percentage of iterations using exaggeration phase. - */ - decay_start?: number | undefined; - /** - * - Controls the decay of the learning parameter. - */ - decay_cte?: number | undefined; - /** - * - the seed for the random number generator. - */ - seed?: number | undefined; + d?: number | undefined; + metric?: Metric | "precomputed" | undefined; + /** + * - Percentage of iterations using exaggeration phase. + */ + decay_start?: number | undefined; + /** + * - Controls the decay of the learning parameter. + */ + decay_cte?: number | undefined; + /** + * - the seed for the random number generator. + */ + seed?: number | undefined; }; type ParametersTopoMap = { - /** - * = euclidean - The metric which defines the distance between - * two points. - */ - metric: Metric; - /** - * = 1212 - The seed for the random number generator. - */ - seed: number; + /** + * = euclidean - The metric which defines the distance between + * two points. + */ + metric: Metric; + /** + * = 1212 - The seed for the random number generator. + */ + seed: number; }; type ParametersTriMap = { - /** - * - scaling factor. - */ - weight_adj?: number | undefined; - /** - * - number of inliers. - */ - n_inliers?: number | undefined; - /** - * - number of outliers. - */ - n_outliers?: number | undefined; - /** - * - number of random points. - */ - n_random?: number | undefined; - /** - * - the dimensionality of the projection. - */ - d?: number | undefined; - tol?: number | undefined; - /** - * - the metric which defines the distance between two points. - */ - metric?: Metric | undefined; - /** - * - the seed for the random number generator. - */ - seed?: number | undefined; + /** + * - scaling factor. + */ + weight_adj?: number | undefined; + /** + * - number of inliers. + */ + n_inliers?: number | undefined; + /** + * - number of outliers. + */ + n_outliers?: number | undefined; + /** + * - number of random points. + */ + n_random?: number | undefined; + /** + * - the dimensionality of the projection. + */ + d?: number | undefined; + tol?: number | undefined; + /** + * - the metric which defines the distance between two points. + */ + metric?: Metric | undefined; + /** + * - the seed for the random number generator. + */ + seed?: number | undefined; }; type ParametersTSNE = { - /** - * - perplexity. - */ - perplexity?: number | undefined; - /** - * - learning parameter. - */ - epsilon?: number | undefined; - /** - * - the dimensionality of the projection. - */ - d?: number | undefined; - /** - * - the metric which defines the distance between two points. - */ - metric?: Metric | "precomputed" | undefined; - /** - * - the seed for the random number generator. - */ - seed?: number | undefined; + /** + * - perplexity. + */ + perplexity?: number | undefined; + /** + * - learning parameter. + */ + epsilon?: number | undefined; + /** + * - the dimensionality of the projection. + */ + d?: number | undefined; + /** + * - the metric which defines the distance between two points. + */ + metric?: Metric | "precomputed" | undefined; + /** + * - the seed for the random number generator. + */ + seed?: number | undefined; +}; +type ParametersPaCMAP = { + /** + * - Number of nearest neighbors for NN pairs. + */ + n_neighbors?: number | undefined; + /** + * - Ratio of mid-near pairs to n_neighbors. + */ + MN_ratio?: number | undefined; + /** + * - Ratio of further pairs to n_neighbors. + */ + FP_ratio?: number | undefined; + /** + * - The dimensionality of the projection. + */ + d?: number | undefined; + /** + * - The metric which defines the distance between two points. + */ + metric?: Metric | undefined; + /** + * - Learning rate for the Adam optimizer. + */ + lr?: number | undefined; + /** + * - Number of iterations for each of the three phases. + */ + num_iters?: number[] | undefined; + /** + * - The seed for the random number generator. + */ + seed?: number | undefined; +}; +type ParametersLocalMAP = { + /** + * - Number of nearest neighbors for NN pairs. + */ + n_neighbors?: number | undefined; + /** + * - Ratio of mid-near pairs to n_neighbors. + */ + MN_ratio?: number | undefined; + /** + * - Ratio of further pairs to n_neighbors. + */ + FP_ratio?: number | undefined; + /** + * - The dimensionality of the projection. + */ + d?: number | undefined; + /** + * - The metric which defines the distance between two points. + */ + metric?: Metric | undefined; + /** + * - Learning rate for the Adam optimizer. + */ + lr?: number | undefined; + /** + * - Number of iterations for each of the three phases. + */ + num_iters?: number[] | undefined; + /** + * - Distance threshold for local FP pair resampling in phase 3. + */ + low_dist_thres?: number | undefined; + /** + * - The seed for the random number generator. + */ + seed?: number | undefined; }; type ParametersUMAP = { - /** - * - size of the local neighborhood. - */ - n_neighbors?: number | undefined; - /** - * - number of nearest neighbors connected in the local neighborhood. - */ - local_connectivity?: number | undefined; - /** - * - controls how tightly points get packed together. - */ - min_dist?: number | undefined; - /** - * - the dimensionality of the projection. - */ - d?: number | undefined; - /** - * - the metric which defines the distance between two points in the high-dimensional space. - */ - metric?: Metric | "precomputed" | undefined; - /** - * - The effective scale of embedded points. - */ - _spread?: number | undefined; - /** - * - Interpolate between union and intersection. - */ - _set_op_mix_ratio?: number | undefined; - /** - * - Weighting applied to negative samples. - */ - _repulsion_strength?: number | undefined; - /** - * - The number of negative samples per positive sample. - */ - _negative_sample_rate?: number | undefined; - /** - * - The number of training epochs. - */ - _n_epochs?: number | undefined; - /** - * - The initial learning rate for the optimization. - */ - _initial_alpha?: number | undefined; - /** - * - the seed for the random number generator. - */ - seed?: number | undefined; + /** + * - size of the local neighborhood. + */ + n_neighbors?: number | undefined; + /** + * - number of nearest neighbors connected in the local neighborhood. + */ + local_connectivity?: number | undefined; + /** + * - controls how tightly points get packed together. + */ + min_dist?: number | undefined; + /** + * - the dimensionality of the projection. + */ + d?: number | undefined; + /** + * - the metric which defines the distance between two points in the high-dimensional space. + */ + metric?: Metric | "precomputed" | undefined; + /** + * - The effective scale of embedded points. + */ + _spread?: number | undefined; + /** + * - Interpolate between union and intersection. + */ + _set_op_mix_ratio?: number | undefined; + /** + * - Weighting applied to negative samples. + */ + _repulsion_strength?: number | undefined; + /** + * - The number of negative samples per positive sample. + */ + _negative_sample_rate?: number | undefined; + /** + * - The number of training epochs. + */ + _n_epochs?: number | undefined; + /** + * - The initial learning rate for the optimization. + */ + _initial_alpha?: number | undefined; + /** + * - the seed for the random number generator. + */ + seed?: number | undefined; }; /** @import { Metric } from "../metrics/index.js" */ @@ -3854,118 +3973,109 @@ type ParametersUMAP = { * @see {@link https://erikbern.com/2015/09/24/nearest-neighbors-and-vector-models-epilogue-curse-of-dimensionality.html} */ declare class Annoy extends KNN { - /** - * Creates a new Annoy-style index with random projection trees. - * - * @param {T[]} elements - Elements to index - * @param {ParametersAnnoy} [parameters={}] - Configuration parameters - */ - constructor(elements: T[], parameters?: ParametersAnnoy); - _metric: Metric; - _numTrees: number; - _maxPointsPerLeaf: number; - _seed: number; - _randomizer: Randomizer; - /** - * @private - * @type {AnnoyNode[]} - */ - private _trees; - /** - * Get the number of trees in the index. - * @returns {number} - */ - get num_trees(): number; - /** - * Get the total number of nodes in all trees. - * @returns {number} - */ - get num_nodes(): number; - /** - * @private - * @param {any} node - * @returns {number} - */ - private _countNodes; - /** - * Add elements to the Annoy index. - * @param {T[]} elements - * @returns {this} - */ - add(elements: T[]): this; - /** - * Build all random projection trees. - * @private - */ - private _buildTrees; - /** - * Recursively build a random projection tree. - * @private - * @param {number[]} indices - Indices of elements to include - * @returns {AnnoyNode} - */ - private _buildTreeRecursive; - /** - * Compute distance from point to hyperplane. - * @private - * @param {T} point - * @param {number[]} normal - * @param {number} offset - * @returns {number} Signed distance (positive = right side, negative = left side) - */ - private _distanceToHyperplane; - /** - * Search for k approximate nearest neighbors. - * @param {T} query - * @param {number} [k=5] - * @returns {{ element: T; index: number; distance: number }[]} - */ - search( - query: T, - k?: number, - ): { - element: T; - index: number; - distance: number; - }[]; - /** - * Search tree using priority queue for better recall. - * Explores nodes in order of distance to hyperplane. - * @private - * @param {AnnoyNode} node - * @param {T} query - * @param {Set} candidates - * @param {number} maxCandidates - */ - private _searchTreePriority; - /** - * @param {number} i - * @param {number} [k=5] - * @returns {{ element: T; index: number; distance: number }[]} - */ - search_by_index( - i: number, - k?: number, - ): { - element: T; - index: number; - distance: number; - }[]; - /** - * Alias for search_by_index for backward compatibility. - * - * @param {number} i - Index of the query element - * @param {number} [k=5] - Number of nearest neighbors to return - * @returns {{ element: T; index: number; distance: number }[]} - */ - search_index( - i: number, - k?: number, - ): { - element: T; - index: number; - distance: number; - }[]; + /** + * Creates a new Annoy-style index with random projection trees. + * + * @param {T[]} elements - Elements to index + * @param {ParametersAnnoy} [parameters={}] - Configuration parameters + */ + constructor(elements: T[], parameters?: ParametersAnnoy); + _metric: Metric; + _numTrees: number; + _maxPointsPerLeaf: number; + _seed: number; + _randomizer: Randomizer; + /** + * @private + * @type {AnnoyNode[]} + */ + private _trees; + /** + * Get the number of trees in the index. + * @returns {number} + */ + get num_trees(): number; + /** + * Get the total number of nodes in all trees. + * @returns {number} + */ + get num_nodes(): number; + /** + * @private + * @param {any} node + * @returns {number} + */ + private _countNodes; + /** + * Add elements to the Annoy index. + * @param {T[]} elements + * @returns {this} + */ + add(elements: T[]): this; + /** + * Build all random projection trees. + * @private + */ + private _buildTrees; + /** + * Recursively build a random projection tree. + * @private + * @param {number[]} indices - Indices of elements to include + * @returns {AnnoyNode} + */ + private _buildTreeRecursive; + /** + * Compute distance from point to hyperplane. + * @private + * @param {T} point + * @param {number[]} normal + * @param {number} offset + * @returns {number} Signed distance (positive = right side, negative = left side) + */ + private _distanceToHyperplane; + /** + * Search for k approximate nearest neighbors. + * @param {T} query + * @param {number} [k=5] + * @returns {{ element: T; index: number; distance: number }[]} + */ + search(query: T, k?: number): { + element: T; + index: number; + distance: number; + }[]; + /** + * Search tree using priority queue for better recall. + * Explores nodes in order of distance to hyperplane. + * @private + * @param {AnnoyNode} node + * @param {T} query + * @param {Set} candidates + * @param {number} maxCandidates + */ + private _searchTreePriority; + /** + * @param {number} i + * @param {number} [k=5] + * @returns {{ element: T; index: number; distance: number }[]} + */ + search_by_index(i: number, k?: number): { + element: T; + index: number; + distance: number; + }[]; + /** + * Alias for search_by_index for backward compatibility. + * + * @param {number} i - Index of the query element + * @param {number} [k=5] - Number of nearest neighbors to return + * @returns {{ element: T; index: number; distance: number }[]} + */ + search_index(i: number, k?: number): { + element: T; + index: number; + distance: number; + }[]; } /** @import { Metric } from "../metrics/index.js" */ @@ -3989,67 +4099,61 @@ declare class Annoy extends KNN */ declare class BallTree extends KNN { - /** - * Generates a BallTree with given `elements`. - * - * @param {T[]} elements - Elements which should be added to the BallTree - * @param {ParametersBallTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}` - * @see {@link https://en.wikipedia.org/wiki/Ball_tree} - * @see {@link https://github.com/invisal/noobjs/blob/master/src/tree/BallTree.js} - */ - constructor(elements: T[], parameters?: ParametersBallTree); - /** - * @private - * @type {BallTreeNode | BallTreeLeaf} - */ - private _root; - /** @returns {Metric} */ - get _metric(): Metric; - /** - * @private - * @param {ElementWithIndex[]} elements - * @returns {BallTreeNode | BallTreeLeaf} Root of balltree. - */ - private _construct; - /** - * @private - * @param {ElementWithIndex[]} B - * @returns {number} - */ - private _greatest_spread; - /** - * @param {number} i - * @param {number} k - */ - search_by_index( - i: number, - k?: number, - ): { - element: T; - index: number; - distance: number; - }[]; - /** - * @param {T} t - Query element. - * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5` - * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors. - */ - search( - t: T, - k?: number, - ): { - element: T; - index: number; - distance: number; - }[]; - /** - * @private - * @param {T} t - Query element. - * @param {number} k - Number of nearest neighbors to return. - * @param {Heap>} Q - Heap consists of the currently found `k` nearest neighbors. - * @param {BallTreeNode | BallTreeLeaf} B - */ - private _search; + /** + * Generates a BallTree with given `elements`. + * + * @param {T[]} elements - Elements which should be added to the BallTree + * @param {ParametersBallTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}` + * @see {@link https://en.wikipedia.org/wiki/Ball_tree} + * @see {@link https://github.com/invisal/noobjs/blob/master/src/tree/BallTree.js} + */ + constructor(elements: T[], parameters?: ParametersBallTree); + /** + * @private + * @type {BallTreeNode | BallTreeLeaf} + */ + private _root; + /** @returns {Metric} */ + get _metric(): Metric; + /** + * @private + * @param {ElementWithIndex[]} elements + * @returns {BallTreeNode | BallTreeLeaf} Root of balltree. + */ + private _construct; + /** + * @private + * @param {ElementWithIndex[]} B + * @returns {number} + */ + private _greatest_spread; + /** + * @param {number} i + * @param {number} k + */ + search_by_index(i: number, k?: number): { + element: T; + index: number; + distance: number; + }[]; + /** + * @param {T} t - Query element. + * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5` + * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors. + */ + search(t: T, k?: number): { + element: T; + index: number; + distance: number; + }[]; + /** + * @private + * @param {T} t - Query element. + * @param {number} k - Number of nearest neighbors to return. + * @param {Heap>} Q - Heap consists of the currently found `k` nearest neighbors. + * @param {BallTreeNode | BallTreeLeaf} B + */ + private _search; } /** @import { Metric } from "../metrics/index.js" */ @@ -4105,173 +4209,165 @@ declare class BallTree extends KNN extends KNN { - /** - * Creates a new HNSW index. - * - * @param {T[]} points - Initial points to add to the index - * @param {ParametersHNSW} [parameters={}] - Configuration parameters - */ - constructor(points: T[], parameters?: ParametersHNSW); - /** @type {Metric} */ - _metric: Metric; - /** @type {Function} */ - _select: Function; - /** - * @private - * @type {Map} - */ - private _graph; - /** @type {number} */ - _next_index: number; - /** @type {number} */ - _m: number; - /** @type {number} */ - _ef_construction: number; - /** @type {number} */ - _ef: number; - /** @type {number} */ - _m0: number; - /** @type {number} */ - _mL: number; - /** @type {Randomizer} */ - _randomizer: Randomizer; - /** @type {number} - Current maximum layer in the graph */ - _L: number; - /** @type {number[] | null} - Entry point indices for search */ - _ep: number[] | null; - /** - * Add a single element to the index. - * - * @param {T} element - Element to add - * @returns {HNSW} This instance for chaining - */ - addOne(element: T): HNSW; - /** - * Add multiple elements to the index. - * - * @param {T[]} new_elements - Elements to add - * @returns {HNSW} This instance for chaining - */ - add(new_elements: T[]): HNSW; - /** - * Select neighbors using the heuristic approach. - * - * The heuristic extends candidates with their neighbors and selects - * points that are closer to the query than to already selected points. - * This maintains graph connectivity better than simple selection. - * - * @private - * @param {T} q - Query element - * @param {Candidate[]} candidates - Candidate elements with distances - * @param {number} M - Maximum number of neighbors to return - * @param {number} l_c - Layer number - * @param {boolean} [extend_candidates=true] - Whether to extend candidates with their neighbors - * @param {boolean} [keep_pruned_connections=true] - Whether to add pruned connections back if needed - * @returns {number[]} Selected neighbor indices - */ - private _select_heuristic; - /** - * Select neighbors using simple distance-based selection. - * - * Simply returns the M closest candidates to the query. - * - * @private - * @param {T} q - Query element - * @param {Candidate[]} C - Candidate elements with distances - * @param {number} M - Maximum number of neighbors to return - * @returns {number[]} M nearest candidate indices - */ - private _select_simple; - /** - * Search a single layer for nearest neighbors. - * - * Implements the greedy search algorithm: start from entry points, - * always expand the closest unvisited candidate, maintain a list - * of the ef closest found neighbors. - * - * @private - * @param {T} q - Query element - * @param {number[] | null} ep_indices - Entry point indices - * @param {number} ef - Number of nearest neighbors to find - * @param {number} l_c - Layer number to search - * @returns {Candidate[]} ef nearest neighbors found with their distances - */ - private _search_layer; - /** - * Fallback linear search when graph search fails - * @private - * @param {T} q - Query element - * @param {number} K - Number of nearest neighbors to return - * @returns {Candidate[]} - */ - private _linear_search; - /** - * Iterator for searching the HNSW graph layer by layer. - * - * Yields intermediate results at each layer for debugging or visualization. - * - * @param {T} q - Query element - * @param {number} K - Number of nearest neighbors to return - * @param {number?} [ef] - Size of dynamic candidate list - * @yields {{layer: number, candidates: Candidate[]}} - */ - search_iter( - q: T, - K: number, - ef?: number | null, - ): Generator< - { - layer: number; - candidates: { - element: T; - index: number; - distance: number; - }[]; - }, - void, - unknown - >; - /** - * Get the number of elements in the index. - * - * @returns {number} Number of elements - */ - get size(): number; - /** - * Get the number of layers in the graph. - * - * @returns {number} Number of layers - */ - get num_layers(): number; - /** - * Get an element by its index. - * - * @param {number} index - Element index - * @returns {T} The element at the given index - */ - get_element(index: number): T; - /** - * Search for nearest neighbors using an element index as the query. - * - * @param {number} i - Index of the query element - * @param {number} [K=5] - Number of nearest neighbors to return - * @returns {Candidate[]} K nearest neighbors - */ - search_by_index(i: number, K?: number): Candidate[]; + /** + * Creates a new HNSW index. + * + * @param {T[]} points - Initial points to add to the index + * @param {ParametersHNSW} [parameters={}] - Configuration parameters + */ + constructor(points: T[], parameters?: ParametersHNSW); + /** @type {Metric} */ + _metric: Metric; + /** @type {Function} */ + _select: Function; + /** + * @private + * @type {Map} + */ + private _graph; + /** @type {number} */ + _next_index: number; + /** @type {number} */ + _m: number; + /** @type {number} */ + _ef_construction: number; + /** @type {number} */ + _ef: number; + /** @type {number} */ + _m0: number; + /** @type {number} */ + _mL: number; + /** @type {Randomizer} */ + _randomizer: Randomizer; + /** @type {number} - Current maximum layer in the graph */ + _L: number; + /** @type {number[] | null} - Entry point indices for search */ + _ep: number[] | null; + /** + * Add a single element to the index. + * + * @param {T} element - Element to add + * @returns {HNSW} This instance for chaining + */ + addOne(element: T): HNSW; + /** + * Add multiple elements to the index. + * + * @param {T[]} new_elements - Elements to add + * @returns {HNSW} This instance for chaining + */ + add(new_elements: T[]): HNSW; + /** + * Select neighbors using the heuristic approach. + * + * The heuristic extends candidates with their neighbors and selects + * points that are closer to the query than to already selected points. + * This maintains graph connectivity better than simple selection. + * + * @private + * @param {T} q - Query element + * @param {Candidate[]} candidates - Candidate elements with distances + * @param {number} M - Maximum number of neighbors to return + * @param {number} l_c - Layer number + * @param {boolean} [extend_candidates=true] - Whether to extend candidates with their neighbors + * @param {boolean} [keep_pruned_connections=true] - Whether to add pruned connections back if needed + * @returns {number[]} Selected neighbor indices + */ + private _select_heuristic; + /** + * Select neighbors using simple distance-based selection. + * + * Simply returns the M closest candidates to the query. + * + * @private + * @param {T} q - Query element + * @param {Candidate[]} C - Candidate elements with distances + * @param {number} M - Maximum number of neighbors to return + * @returns {number[]} M nearest candidate indices + */ + private _select_simple; + /** + * Search a single layer for nearest neighbors. + * + * Implements the greedy search algorithm: start from entry points, + * always expand the closest unvisited candidate, maintain a list + * of the ef closest found neighbors. + * + * @private + * @param {T} q - Query element + * @param {number[] | null} ep_indices - Entry point indices + * @param {number} ef - Number of nearest neighbors to find + * @param {number} l_c - Layer number to search + * @returns {Candidate[]} ef nearest neighbors found with their distances + */ + private _search_layer; + /** + * Fallback linear search when graph search fails + * @private + * @param {T} q - Query element + * @param {number} K - Number of nearest neighbors to return + * @returns {Candidate[]} + */ + private _linear_search; + /** + * Iterator for searching the HNSW graph layer by layer. + * + * Yields intermediate results at each layer for debugging or visualization. + * + * @param {T} q - Query element + * @param {number} K - Number of nearest neighbors to return + * @param {number?} [ef] - Size of dynamic candidate list + * @yields {{layer: number, candidates: Candidate[]}} + */ + search_iter(q: T, K: number, ef?: number | null): Generator<{ + layer: number; + candidates: { + element: T; + index: number; + distance: number; + }[]; + }, void, unknown>; + /** + * Get the number of elements in the index. + * + * @returns {number} Number of elements + */ + get size(): number; + /** + * Get the number of layers in the graph. + * + * @returns {number} Number of layers + */ + get num_layers(): number; + /** + * Get an element by its index. + * + * @param {number} index - Element index + * @returns {T} The element at the given index + */ + get_element(index: number): T; + /** + * Search for nearest neighbors using an element index as the query. + * + * @param {number} i - Index of the query element + * @param {number} [K=5] - Number of nearest neighbors to return + * @returns {Candidate[]} K nearest neighbors + */ + search_by_index(i: number, K?: number): Candidate[]; } type Candidate = { - /** - * - The actual data point - */ - element: T; - /** - * - Global index in the dataset - */ - index: number; - /** - * - Distance from query - */ - distance: number; + /** + * - The actual data point + */ + element: T; + /** + * - Global index in the dataset + */ + index: number; + /** + * - Distance from query + */ + distance: number; }; /** @import { Metric } from "../metrics/index.js" */ @@ -4304,60 +4400,54 @@ type Candidate = { * @see {@link https://en.wikipedia.org/wiki/K-d_tree} */ declare class KDTree extends KNN { - /** - * Generates a KD-Tree with given `elements`. - * - * @param {T[]} elements - Elements which should be added to the KD-Tree - * @param {ParametersKDTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}` - */ - constructor(elements: T[], parameters?: ParametersKDTree); - /** - * @private - * @type {KDTreeNode | KDTreeLeaf | null} - */ - private _root; - /** @returns {Metric} */ - get _metric(): Metric; - /** - * @private - * @param {ElementWithIndex[]} elements - * @param {number} depth - Current depth in the tree (determines splitting axis) - * @returns {KDTreeNode | KDTreeLeaf | null} Root of KD-Tree. - */ - private _construct; - /** - * @param {number} i - * @param {number} k - */ - search_by_index( - i: number, - k?: number, - ): { - element: T; - index: number; - distance: number; - }[]; - /** - * @param {T} t - Query element. - * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5` - * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors. - */ - search( - t: T, - k?: number, - ): { - element: T; - index: number; - distance: number; - }[]; - /** - * @private - * @param {T} target - Query element. - * @param {number} k - Number of nearest neighbors to return. - * @param {KDTreeNode | KDTreeLeaf | null} node - Current node. - * @param {Heap<{ point: ElementWithIndex; distance: number }>} best - Heap of k best found so far. - */ - private _search_recursive; + /** + * Generates a KD-Tree with given `elements`. + * + * @param {T[]} elements - Elements which should be added to the KD-Tree + * @param {ParametersKDTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}` + */ + constructor(elements: T[], parameters?: ParametersKDTree); + /** + * @private + * @type {KDTreeNode | KDTreeLeaf | null} + */ + private _root; + /** @returns {Metric} */ + get _metric(): Metric; + /** + * @private + * @param {ElementWithIndex[]} elements + * @param {number} depth - Current depth in the tree (determines splitting axis) + * @returns {KDTreeNode | KDTreeLeaf | null} Root of KD-Tree. + */ + private _construct; + /** + * @param {number} i + * @param {number} k + */ + search_by_index(i: number, k?: number): { + element: T; + index: number; + distance: number; + }[]; + /** + * @param {T} t - Query element. + * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5` + * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors. + */ + search(t: T, k?: number): { + element: T; + index: number; + distance: number; + }[]; + /** + * @private + * @param {T} target - Query element. + * @param {number} k - Number of nearest neighbors to return. + * @param {KDTreeNode | KDTreeLeaf | null} node - Current node. + * @param {Heap<{ point: ElementWithIndex; distance: number }>} best - Heap of k best found so far. + */ + private _search_recursive; } /** @import { Metric } from "../metrics/index.js" */ @@ -4388,72 +4478,66 @@ declare class KDTree extends KNN extends KNN { - /** - * Creates a new LSH index. - * - * @param {T[]} elements - Elements to index - * @param {ParametersLSH} [parameters={}] - Configuration parameters - */ - constructor(elements: T[], parameters?: ParametersLSH); - _metric: Metric; - _numHashTables: number; - _numHashFunctions: number; - _seed: number; - _randomizer: Randomizer; - /** @type {Map[]} */ - _hashTables: Map[]; - /** @type {Float64Array[][]} */ - _projections: Float64Array[][]; - /** @type {number[][]} */ - _offsets: number[][]; - /** @type {number} */ - _dim: number; - /** - * Initialize random projection vectors for all hash tables. - * @private - */ - private _initializeHashFunctions; - /** - * Compute hash signature for an element using random projections. - * @private - * @param {T} element - * @param {number} tableIndex - * @returns {string} Hash signature - */ - private _computeHash; - /** - * Add elements to the LSH index. - * @param {T[]} elements - * @returns {this} - */ - add(elements: T[]): this; - /** - * Search for k approximate nearest neighbors. - * @param {T} query - * @param {number} [k=5] - * @returns {{ element: T; index: number; distance: number }[]} - */ - search( - query: T, - k?: number, - ): { - element: T; - index: number; - distance: number; - }[]; - /** - * @param {number} i - * @param {number} [k=5] - * @returns {{ element: T; index: number; distance: number }[]} - */ - search_by_index( - i: number, - k?: number, - ): { - element: T; - index: number; - distance: number; - }[]; + /** + * Creates a new LSH index. + * + * @param {T[]} elements - Elements to index + * @param {ParametersLSH} [parameters={}] - Configuration parameters + */ + constructor(elements: T[], parameters?: ParametersLSH); + _metric: Metric; + _numHashTables: number; + _numHashFunctions: number; + _seed: number; + _randomizer: Randomizer; + /** @type {Map[]} */ + _hashTables: Map[]; + /** @type {Float64Array[][]} */ + _projections: Float64Array[][]; + /** @type {number[][]} */ + _offsets: number[][]; + /** @type {number} */ + _dim: number; + /** + * Initialize random projection vectors for all hash tables. + * @private + */ + private _initializeHashFunctions; + /** + * Compute hash signature for an element using random projections. + * @private + * @param {T} element + * @param {number} tableIndex + * @returns {string} Hash signature + */ + private _computeHash; + /** + * Add elements to the LSH index. + * @param {T[]} elements + * @returns {this} + */ + add(elements: T[]): this; + /** + * Search for k approximate nearest neighbors. + * @param {T} query + * @param {number} [k=5] + * @returns {{ element: T; index: number; distance: number }[]} + */ + search(query: T, k?: number): { + element: T; + index: number; + distance: number; + }[]; + /** + * @param {number} i + * @param {number} [k=5] + * @returns {{ element: T; index: number; distance: number }[]} + */ + search_by_index(i: number, k?: number): { + element: T; + index: number; + distance: number; + }[]; } /** @import { ParametersNaiveKNN } from "./index.js" */ @@ -4470,44 +4554,38 @@ declare class LSH extends KNN */ declare class NaiveKNN extends KNN { - /** - * Generates a KNN list with given `elements`. - * - * @param {T[]} elements - Elements which should be added to the KNN list - * @param {ParametersNaiveKNN} parameters - */ - constructor(elements: T[], parameters?: ParametersNaiveKNN); - _D: Matrix; - /** @type {Heap<{ value: number; index: number }>[]} */ - KNN: Heap<{ - value: number; - index: number; - }>[]; - /** - * @param {number} i - * @param {number} k - */ - search_by_index( - i: number, - k?: number, - ): { - element: T; - index: number; - distance: number; - }[]; - /** - * @param {T} t - Query element. - * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5` - * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors. - */ - search( - t: T, - k?: number, - ): { - element: T; - index: number; - distance: number; - }[]; + /** + * Generates a KNN list with given `elements`. + * + * @param {T[]} elements - Elements which should be added to the KNN list + * @param {ParametersNaiveKNN} parameters + */ + constructor(elements: T[], parameters?: ParametersNaiveKNN); + _D: Matrix; + /** @type {Heap<{ value: number; index: number }>[]} */ + KNN: Heap<{ + value: number; + index: number; + }>[]; + /** + * @param {number} i + * @param {number} k + */ + search_by_index(i: number, k?: number): { + element: T; + index: number; + distance: number; + }[]; + /** + * @param {T} t - Query element. + * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5` + * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors. + */ + search(t: T, k?: number): { + element: T; + index: number; + distance: number; + }[]; } /** @import {ParametersNNDescent} from "./index.js" */ @@ -4541,194 +4619,188 @@ declare class NaiveKNN extends KNN extends KNN { - /** - * @param {T[]} elements - Called V in paper. - * @param {Partial} parameters - * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf} - */ - constructor(elements: T[], parameters?: Partial); - /** - * @private - * @type {KNNHeap[]} - */ - private _B; - /** - * @private - * @type {NNDescentNeighbor[][]} - */ - private nn; - _N: number; - _randomizer: Randomizer; - _sample_size: number; - _nndescent_elements: { - value: T; - index: number; - flag: boolean; - }[]; - /** - * Samples Array A with sample size. - * - * @private - * @template U - * @param {U[]} A - * @returns {U[]} - */ - private _sample; - /** - * @private - * @param {KNNHeap} B - * @param {NNDescentNeighbor} u - * @returns {number} - */ - private _update; - /** - * @private - * @param {(KNNHeap | null)[]} B - * @returns {NNDescentNeighbor[][]} - */ - private _reverse; - /** - * @param {T[]} elements - * @returns {this} - */ - add(elements: T[]): this; - /** - * @param {T} x - * @param {number} [k=5] Default is `5` - * @returns {{ element: T, index: number; distance: number }[]} - */ - search( - x: T, - k?: number, - ): { - element: T; - index: number; - distance: number; - }[]; - /** - * @param {number} i - * @param {number} [k=5] Default is `5` - * @returns {{ element: T; index: number; distance: number }[]} - */ - search_by_index( - i: number, - k?: number, - ): { - element: T; - index: number; - distance: number; - }[]; + /** + * @param {T[]} elements - Called V in paper. + * @param {Partial} parameters + * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf} + */ + constructor(elements: T[], parameters?: Partial); + /** + * @private + * @type {KNNHeap[]} + */ + private _B; + /** + * @private + * @type {NNDescentNeighbor[][]} + */ + private nn; + _N: number; + _randomizer: Randomizer; + _sample_size: number; + _nndescent_elements: { + value: T; + index: number; + flag: boolean; + }[]; + /** + * Samples Array A with sample size. + * + * @private + * @template U + * @param {U[]} A + * @returns {U[]} + */ + private _sample; + /** + * @private + * @param {KNNHeap} B + * @param {NNDescentNeighbor} u + * @returns {number} + */ + private _update; + /** + * @private + * @param {(KNNHeap | null)[]} B + * @returns {NNDescentNeighbor[][]} + */ + private _reverse; + /** + * @param {T[]} elements + * @returns {this} + */ + add(elements: T[]): this; + /** + * @param {T} x + * @param {number} [k=5] Default is `5` + * @returns {{ element: T, index: number; distance: number }[]} + */ + search(x: T, k?: number): { + element: T; + index: number; + distance: number; + }[]; + /** + * @param {number} i + * @param {number} [k=5] Default is `5` + * @returns {{ element: T; index: number; distance: number }[]} + */ + search_by_index(i: number, k?: number): { + element: T; + index: number; + distance: number; + }[]; } type ParametersAnnoy = { - /** - * - Metric to use: (a, b) => distance. Default is `euclidean` - */ - metric: Metric; - /** - * - Number of random projection trees to build. Default is `10` - */ - numTrees: number; - /** - * - Maximum points per leaf node. Default is `10` - */ - maxPointsPerLeaf: number; - /** - * - Seed for random number generator. Default is `1212` - */ - seed: number; + /** + * - Metric to use: (a, b) => distance. Default is `euclidean` + */ + metric: Metric; + /** + * - Number of random projection trees to build. Default is `10` + */ + numTrees: number; + /** + * - Maximum points per leaf node. Default is `10` + */ + maxPointsPerLeaf: number; + /** + * - Seed for random number generator. Default is `1212` + */ + seed: number; }; type ParametersBallTree = { - metric: Metric; - seed: number; + metric: Metric; + seed: number; }; type ParametersHNSW = { - /** - * - Metric to use: (a, b) => distance. Default is `euclidean` - */ - metric: Metric; - /** - * - Use heuristics or naive selection. Default is `true` - */ - heuristic: boolean; - /** - * - Max number of connections per element (excluding ground layer). Default is `16` - */ - m: number; - /** - * - Size of candidate list during construction. Default is `200` - */ - ef_construction: number; - /** - * - Max number of connections for ground layer (layer 0). Default is `2 * m` - */ - m0: number | null; - /** - * - Normalization factor for level generation. Default is `1 / Math.log(m)` - */ - mL: number | null; - /** - * - Seed for random number generator. Default is `1212` - */ - seed: number; - /** - * - Size of candidate list during search. Default is `50` - */ - ef: number; + /** + * - Metric to use: (a, b) => distance. Default is `euclidean` + */ + metric: Metric; + /** + * - Use heuristics or naive selection. Default is `true` + */ + heuristic: boolean; + /** + * - Max number of connections per element (excluding ground layer). Default is `16` + */ + m: number; + /** + * - Size of candidate list during construction. Default is `200` + */ + ef_construction: number; + /** + * - Max number of connections for ground layer (layer 0). Default is `2 * m` + */ + m0: number | null; + /** + * - Normalization factor for level generation. Default is `1 / Math.log(m)` + */ + mL: number | null; + /** + * - Seed for random number generator. Default is `1212` + */ + seed: number; + /** + * - Size of candidate list during search. Default is `50` + */ + ef: number; }; type ParametersKDTree = { - /** - * - Metric to use: (a, b) => distance. Default is `euclidean` - */ - metric: Metric; - seed: number; + /** + * - Metric to use: (a, b) => distance. Default is `euclidean` + */ + metric: Metric; + seed: number; }; type ParametersLSH = { - /** - * - Metric to use: (a, b) => distance. Default is `euclidean` - */ - metric: Metric; - /** - * - Number of hash tables. Default is `10` - */ - numHashTables: number; - /** - * - Number of hash functions per table. Default is `10` - */ - numHashFunctions: number; - /** - * - Seed for random number generator. Default is `1212` - */ - seed: number; + /** + * - Metric to use: (a, b) => distance. Default is `euclidean` + */ + metric: Metric; + /** + * - Number of hash tables. Default is `10` + */ + numHashTables: number; + /** + * - Number of hash functions per table. Default is `10` + */ + numHashFunctions: number; + /** + * - Seed for random number generator. Default is `1212` + */ + seed: number; }; type ParametersNaiveKNN = { - /** - * Is either precomputed or a function to use: (a, b) => distance - */ - metric?: Metric | "precomputed" | undefined; - seed?: number | undefined; + /** + * Is either precomputed or a function to use: (a, b) => distance + */ + metric?: Metric | "precomputed" | undefined; + seed?: number | undefined; }; type ParametersNNDescent = { - /** - * - Called sigma in paper. Default is `euclidean` - */ - metric: Metric; - /** - * =10 - Number of samples. Default is `10` - */ - samples: number; - /** - * = .8 - Sample rate. Default is `.8` - */ - rho: number; - /** - * = 0.0001 - Precision parameter. Default is `0.0001` - */ - delta: number; - /** - * = 1212 - Seed for the random number generator. Default is `1212` - */ - seed: number; + /** + * - Called sigma in paper. Default is `euclidean` + */ + metric: Metric; + /** + * =10 - Number of samples. Default is `10` + */ + samples: number; + /** + * = .8 - Sample rate. Default is `.8` + */ + rho: number; + /** + * = 0.0001 - Precision parameter. Default is `0.0001` + */ + delta: number; + /** + * = 1212 - Seed for the random number generator. Default is `1212` + */ + seed: number; }; /** @@ -4760,113 +4832,11 @@ declare function neumair_sum(summands: number[] | Float64Array): number; * @returns {T} * @see http://optimization-js.github.io/optimization-js/optimization.js.html#line438 */ -declare function powell( - f: (d: T) => number, - x0: T, - max_iter?: number, -): T; +declare function powell(f: (d: T) => number, x0: T, max_iter?: number): T; type InputType = Matrix | Float64Array[] | number[][]; declare const version: string; -export { - Annoy, - BallTree, - CURE, - DisjointSet, - FASTMAP, - HNSW, - Heap, - HierarchicalClustering, - ISOMAP, - KDTree, - KMeans, - KMedoids, - LDA, - LLE, - LSH, - LSP, - LTSA, - MDS, - Matrix, - MeanShift, - NNDescent, - NaiveKNN, - OPTICS, - PCA, - Randomizer, - SAMMON, - SMACOF, - SQDMDS, - TSNE, - TopoMap, - TriMap, - UMAP, - XMeans, - bray_curtis, - canberra, - chebyshev, - cosine, - distance_matrix, - euclidean, - euclidean_squared, - goodman_kruskal, - hamming, - haversine, - inner_product, - jaccard, - k_nearest_neighbors, - kahan_sum, - linspace, - manhattan, - max, - min, - neumair_sum, - norm, - normalize, - powell, - qr, - qr_householder, - simultaneous_poweriteration, - sokal_michener, - version, - wasserstein, - yule, -}; -export type { - Comparator, - EigenArgs, - InputType, - Metric, - ParametersAnnoy, - ParametersBallTree, - ParametersCURE, - ParametersFASTMAP, - ParametersHNSW, - ParametersHierarchicalClustering, - ParametersISOMAP, - ParametersKDTree, - ParametersKMeans, - ParametersKMedoids, - ParametersLDA, - ParametersLLE, - ParametersLSH, - ParametersLSP, - ParametersLTSA, - ParametersMDS, - ParametersMeanShift, - ParametersNNDescent, - ParametersNaiveKNN, - ParametersOptics, - ParametersPCA, - ParametersSAMMON, - ParametersSMACOF, - ParametersSQDMDS, - ParametersTSNE, - ParametersTopoMap, - ParametersTriMap, - ParametersUMAP, - ParametersXMeans, - QRDecomposition, -}; +export { Annoy, BallTree, CURE, DisjointSet, FASTMAP, HNSW, Heap, HierarchicalClustering, ISOMAP, KDTree, KMeans, KMedoids, LDA, LLE, LSH, LSP, LTSA, LocalMAP, MDS, Matrix, MeanShift, NNDescent, NaiveKNN, OPTICS, PCA, PaCMAP, Randomizer, SAMMON, SMACOF, SQDMDS, TSNE, TopoMap, TriMap, UMAP, XMeans, bray_curtis, canberra, chebyshev, cosine, distance_matrix, euclidean, euclidean_squared, goodman_kruskal, hamming, haversine, inner_product, jaccard, k_nearest_neighbors, kahan_sum, linspace, manhattan, max, min, neumair_sum, norm, normalize, powell, qr, qr_householder, simultaneous_poweriteration, sokal_michener, version, wasserstein, yule }; +export type { Comparator, EigenArgs, InputType, Metric, ParametersAnnoy, ParametersBallTree, ParametersCURE, ParametersFASTMAP, ParametersHNSW, ParametersHierarchicalClustering, ParametersISOMAP, ParametersKDTree, ParametersKMeans, ParametersKMedoids, ParametersLDA, ParametersLLE, ParametersLSH, ParametersLSP, ParametersLTSA, ParametersLocalMAP, ParametersMDS, ParametersMeanShift, ParametersNNDescent, ParametersNaiveKNN, ParametersOptics, ParametersPCA, ParametersPaCMAP, ParametersSAMMON, ParametersSMACOF, ParametersSQDMDS, ParametersTSNE, ParametersTopoMap, ParametersTriMap, ParametersUMAP, ParametersXMeans, QRDecomposition }; //# sourceMappingURL=druid.d.ts.map diff --git a/dist/druid.d.ts.map b/dist/druid.d.ts.map index 2021664..b6a5b15 100644 --- a/dist/druid.d.ts.map +++ b/dist/druid.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"druid.d.ts","sources":["types/metrics/bray_curtis.d.ts","types/metrics/canberra.d.ts","types/metrics/chebyshev.d.ts","types/metrics/cosine.d.ts","types/metrics/euclidean.d.ts","types/metrics/euclidean_squared.d.ts","types/metrics/goodman_kruskal.d.ts","types/metrics/hamming.d.ts","types/metrics/haversine.d.ts","types/metrics/jaccard.d.ts","types/metrics/manhattan.d.ts","types/metrics/sokal_michener.d.ts","types/metrics/wasserstein.d.ts","types/metrics/yule.d.ts","types/metrics/index.d.ts","types/matrix/distance_matrix.d.ts","types/matrix/k_nearest_neighbors.d.ts","types/matrix/linspace.d.ts","types/util/max.d.ts","types/util/min.d.ts","types/util/randomizer.d.ts","types/matrix/Matrix.d.ts","types/matrix/norm.d.ts","types/matrix/normalize.d.ts","types/clustering/Clustering.d.ts","types/clustering/CURE.d.ts","types/clustering/Hierarchical_Clustering.d.ts","types/clustering/KMeans.d.ts","types/clustering/KMedoids.d.ts","types/clustering/MeanShift.d.ts","types/clustering/OPTICS.d.ts","types/clustering/XMeans.d.ts","types/clustering/index.d.ts","types/datastructure/DisjointSet.d.ts","types/datastructure/Heap.d.ts","types/datastructure/index.d.ts","types/dimred/DR.d.ts","types/dimred/FASTMAP.d.ts","types/dimred/ISOMAP.d.ts","types/dimred/LDA.d.ts","types/dimred/LLE.d.ts","types/dimred/LSP.d.ts","types/dimred/LTSA.d.ts","types/dimred/MDS.d.ts","types/dimred/PCA.d.ts","types/dimred/SAMMON.d.ts","types/dimred/SMACOF.d.ts","types/dimred/SQDMDS.d.ts","types/dimred/TopoMap.d.ts","types/knn/KNN.d.ts","types/dimred/TriMap.d.ts","types/dimred/TSNE.d.ts","types/dimred/UMAP.d.ts","types/linear_algebra/inner_product.d.ts","types/linear_algebra/qr.d.ts","types/linear_algebra/qr_householder.d.ts","types/linear_algebra/simultaneous_poweriteration.d.ts","types/linear_algebra/index.d.ts","types/dimred/index.d.ts","types/knn/Annoy.d.ts","types/knn/BallTree.d.ts","types/knn/HNSW.d.ts","types/knn/KDTree.d.ts","types/knn/LSH.d.ts","types/knn/NaiveKNN.d.ts","types/knn/NNDescent.d.ts","types/knn/index.d.ts","types/numerical/kahan_sum.d.ts","types/numerical/neumair_sum.d.ts","types/optimization/powell.d.ts","types/index.d.ts"],"sourcesContent":["/**\n * Computes the Bray-Curtis distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The Bray-Curtis distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Bray%E2%80%93Curtis_dissimilarity}\n */\nexport function bray_curtis(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=bray_curtis.d.ts.map","/**\n * Computes the canberra distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The canberra distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Canberra_distance}\n */\nexport function canberra(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=canberra.d.ts.map","/**\n * Computes the chebyshev distance (L) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The chebyshev distance between `a` and `b`.\n */\nexport function chebyshev(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=chebyshev.d.ts.map","/**\n * Computes the cosine distance (not similarity) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The cosine distance between `a` and `b`.\n * @example\n * import { cosine } from \"@saehrimnir/druidjs\";\n * const a = [1, 2, 3];\n * const b = [4, 5, 6];\n * const distance = cosine(a, b); // 0.9746318461970762\n */\nexport function cosine(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=cosine.d.ts.map","/**\n * Computes the euclidean distance (`l_2`) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The euclidean distance between `a` and `b`.\n */\nexport function euclidean(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=euclidean.d.ts.map","/**\n * Computes the squared euclidean distance (l_2^2) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The squared euclidean distance between `a` and `b`.\n\n */\nexport function euclidean_squared(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=euclidean_squared.d.ts.map","/**\n * Computes the Goodman-Kruskal gamma coefficient for ordinal association.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a - First categorical/ordinal variable\n * @param {number[] | Float64Array} b - Second categorical/ordinal variable\n * @returns {number} The Goodman-Kruskal gamma coefficient between `a` and `b` (-1 to 1).\n * @see {@link https://en.wikipedia.org/wiki/Goodman_and_Kruskal%27s_gamma}\n */\nexport function goodman_kruskal(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=goodman_kruskal.d.ts.map","/**\n * Computes the hamming distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The hamming distance between `a` and `b`.\n */\nexport function hamming(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=hamming.d.ts.map","/**\n * Computes the Haversine distance between two points on a sphere of unit length 1. Multiply the result with the radius of the sphere. (For instance Earth's radius is 6371km)\n *\n * @category Metrics\n * @param {number[] | Float64Array} a - Point [lat1, lon1] in radians\n * @param {number[] | Float64Array} b - Point [lat2, lon2] in radians\n * @returns {number} The Haversine distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Haversine_formula}\n */\nexport function haversine(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=haversine.d.ts.map","/**\n * Computes the jaccard distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The jaccard distance between `a` and `b`.\n */\nexport function jaccard(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=jaccard.d.ts.map","/**\n * Computes the manhattan distance (`l_1`) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The manhattan distance between `a` and `b`.\n */\nexport function manhattan(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=manhattan.d.ts.map","/**\n * Computes the Sokal-Michener distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The Sokal-Michener distance between `a` and `b`.\n\n */\nexport function sokal_michener(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=sokal_michener.d.ts.map","/**\n * Computes the 1D Wasserstein distance (Earth Mover's Distance) between two distributions.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a - First distribution (histogram or probability mass)\n * @param {number[] | Float64Array} b - Second distribution (histogram or probability mass)\n * @returns {number} The Wasserstein/EMD distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Wasserstein_metric}\n */\nexport function wasserstein(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=wasserstein.d.ts.map","/**\n * Computes the yule distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The yule distance between `a` and `b`.\n */\nexport function yule(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=yule.d.ts.map","export { bray_curtis } from \"./bray_curtis.js\";\nexport { canberra } from \"./canberra.js\";\nexport { chebyshev } from \"./chebyshev.js\";\nexport { cosine } from \"./cosine.js\";\nexport { euclidean } from \"./euclidean.js\";\nexport { euclidean_squared } from \"./euclidean_squared.js\";\nexport { goodman_kruskal } from \"./goodman_kruskal.js\";\nexport { hamming } from \"./hamming.js\";\nexport { haversine } from \"./haversine.js\";\nexport { jaccard } from \"./jaccard.js\";\nexport { manhattan } from \"./manhattan.js\";\nexport { sokal_michener } from \"./sokal_michener.js\";\nexport { wasserstein } from \"./wasserstein.js\";\nexport { yule } from \"./yule.js\";\nexport type Metric = (a: number[] | Float64Array, b: number[] | Float64Array) => number;\n//# sourceMappingURL=index.d.ts.map","/**\n * Computes the distance matrix of datamatrix `A`.\n *\n * @category Matrix\n * @param {Matrix | Float64Array[] | number[][]} A - Matrix.\n * @param {Metric} [metric=euclidean] - The diistance metric. Default is `euclidean`\n * @returns {Matrix} The distance matrix of `A`.\n */\nexport function distance_matrix(A: Matrix | Float64Array[] | number[][], metric?: Metric): Matrix;\nimport { Matrix } from \"./index.js\";\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=distance_matrix.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/**\n * Computes the k-nearest neighbors of each row of `A`.\n *\n * @category Matrix\n * @param {Matrix} A - Either the data matrix, or a distance matrix.\n * @param {number} k - The number of neighbors to compute.\n * @param {Metric | \"precomputed\"} [metric=euclidean] Default is `euclidean`\n * @returns {{ i: number; j: number; distance: number }[][]} The kNN graph.\n */\nexport function k_nearest_neighbors(A: Matrix, k: number, metric?: Metric | \"precomputed\"): {\n i: number;\n j: number;\n distance: number;\n}[][];\nimport { Matrix } from \"../matrix/index.js\";\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=k_nearest_neighbors.d.ts.map","/**\n * Creates an Array containing `number` numbers from `start` to `end`. If `number = null`.\n *\n * @category Matrix\n * @param {number} start - Start value.\n * @param {number} end - End value.\n * @param {number} [number] - Number of number between `start` and `end`.\n * @returns {number[]} An array with `number` entries, beginning at `start` ending at `end`.\n */\nexport function linspace(start: number, end: number, number?: number): number[];\n//# sourceMappingURL=linspace.d.ts.map","/**\n * Returns maximum in Array `values`.\n *\n * @category Utils\n * @param {Iterable} values\n * @returns {number}\n */\nexport function max(values: Iterable): number;\n//# sourceMappingURL=max.d.ts.map","/**\n * Returns maximum in Array `values`.\n *\n * @category Utils\n * @param {Iterable} values\n * @returns {number}\n */\nexport function min(values: Iterable): number;\n//# sourceMappingURL=min.d.ts.map","/**\n * @category Utils\n * @class\n */\nexport class Randomizer {\n /**\n * @template T Returns samples from an input Matrix or Array.\n * @param {T[]} A - The input Matrix or Array.\n * @param {number} n - The number of samples.\n * @param {number} seed - The seed for the random number generator.\n * @returns {T[]} - A random selection form `A` of `n` samples.\n */\n static choice(A: T[], n: number, seed?: number): T[];\n /**\n * Mersenne Twister random number generator.\n *\n * @param {number} [_seed=new Date().getTime()] - The seed for the random number generator. If `_seed == null` then\n * the actual time gets used as seed. Default is `new Date().getTime()`\n * @see https://github.com/bmurray7/mersenne-twister-examples/blob/master/javascript-mersenne-twister.js\n */\n constructor(_seed?: number);\n _N: number;\n _M: number;\n _MATRIX_A: number;\n _UPPER_MASK: number;\n _LOWER_MASK: number;\n /** @type {number[]} */\n _mt: number[];\n /** @type {number} */\n _mti: number;\n /** @type {number} */\n _seed: number;\n /** @type {number} seed */\n set seed(_seed: number);\n /**\n * Returns the seed of the random number generator.\n *\n * @returns {number} - The seed.\n */\n get seed(): number;\n /**\n * Returns a float between 0 and 1.\n *\n * @returns {number} - A random number between [0, 1]\n */\n get random(): number;\n /**\n * Returns an integer between 0 and MAX_INTEGER.\n *\n * @returns {number} - A random integer.\n */\n get random_int(): number;\n gauss_random(): number;\n _val: number | null | undefined;\n /**\n * @template T Returns samples from an input Matrix or Array.\n * @param {T[]} A - The input Matrix or Array.\n * @param {number} n - The number of samples.\n * @returns {T[]} A random selection form `A` of `n` samples.\n */\n choice(A: T[], n: number): T[];\n}\n//# sourceMappingURL=randomizer.d.ts.map","/** @typedef {(i: number, j: number) => number} Accessor */\n/**\n * @class\n * @category Matrix\n */\nexport class Matrix {\n /**\n * Creates a Matrix out of `A`.\n * @param {Matrix | Float64Array[] | number[][]} A - The matrix, array, or number, which should converted to a Matrix.\n * @returns {Matrix}\n * @example\n * let A = Matrix.from([ [1, 0], [0, 1], ]); //creates a two by two identity matrix.\n */\n static from(A: Matrix | Float64Array[] | number[][]): Matrix;\n /**\n * Creates a Matrix with the diagonal being the values of `v`.\n *\n * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]]\n *\n * @param {number[] | Float64Array} v\n * @returns {Matrix}\n */\n static from_diag(v: number[] | Float64Array): Matrix;\n /**\n * Creates a Matrix with the diagonal being the values of `v`.\n *\n * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]]\n *\n * @param {number[] | Float64Array} v\n * @param {\"col\" | \"row\"} type\n * @returns {Matrix}\n */\n static from_vector(v: number[] | Float64Array, type: \"col\" | \"row\"): Matrix;\n /**\n * Solves the equation `Ax = b` using the conjugate gradient method. Returns the result `x`.\n *\n * @param {Matrix} A - Matrix\n * @param {Matrix} b - Matrix\n * @param {Randomizer | null} [randomizer]\n * @param {number} [tol=1e-3] Default is `1e-3`\n * @returns {Matrix}\n */\n static solve_CG(A: Matrix, b: Matrix, randomizer?: Randomizer | null, tol?: number): Matrix;\n /**\n * Solves the equation `Ax = b`. Returns the result `x`.\n *\n * @param {Matrix | { L: Matrix; U: Matrix }} A - Matrix or LU Decomposition\n * @param {Matrix} b - Matrix\n * @returns {Matrix}\n */\n static solve(A: Matrix | {\n L: Matrix;\n U: Matrix;\n }, b: Matrix): Matrix;\n /**\n * `LU` decomposition of the Matrix `A`. Creates two matrices, so that the dot product `LU` equals `A`.\n *\n * @param {Matrix} A\n * @returns {{ L: Matrix; U: Matrix }} The left triangle matrix `L` and the upper triangle matrix `U`.\n */\n static LU(A: Matrix): {\n L: Matrix;\n U: Matrix;\n };\n /**\n * Computes the determinante of `A`, by using the `LU` decomposition of `A`.\n *\n * @param {Matrix} A\n * @returns {number} The determinate of the Matrix `A`.\n */\n static det(A: Matrix): number;\n /**\n * Computes the `k` components of the SVD decomposition of the matrix `M`.\n *\n * @param {Matrix} M\n * @param {number} [k=2] Default is `2`\n * @returns {{ U: Float64Array[]; Sigma: Float64Array; V: Float64Array[] }}\n */\n static SVD(M: Matrix, k?: number): {\n U: Float64Array[];\n Sigma: Float64Array;\n V: Float64Array[];\n };\n /**\n * @param {unknown} A\n * @returns {A is unknown[]|number[]|Float64Array|Float32Array}\n */\n static isArray(A: unknown): A is unknown[] | number[] | Float64Array | Float32Array;\n /**\n * @param {any[]} A\n * @returns {A is number[][]|Float64Array[]}\n */\n static is2dArray(A: any[]): A is number[][] | Float64Array[];\n /**\n * Creates a new Matrix. Entries are stored in a Float64Array.\n *\n * @example let A = new Matrix(10, 10, () => Math.random()); //creates a 10 times 10 random matrix. let B = new\n * Matrix(3, 3, \"I\"); // creates a 3 times 3 identity matrix.\n *\n * @param {number} rows - The amount of rows of the matrix.\n * @param {number} cols - The amount of columns of the matrix.\n * @param {Accessor | string | number} value - Can be a function with row and col as parameters, a number, or\n * \"zeros\", \"identity\" or \"I\", or \"center\".\n *\n * - **function**: for each entry the function gets called with the parameters for the actual row and column.\n * - **string**: allowed are\n *\n * - \"zero\", creates a zero matrix.\n * - \"identity\" or \"I\", creates an identity matrix.\n * - \"center\", creates an center matrix.\n * - **number**: create a matrix filled with the given value.\n */\n constructor(rows: number, cols: number, value?: Accessor | string | number);\n /** @type {number} */ _rows: number;\n /** @type {number} */ _cols: number;\n /** @type {Float64Array} */ _data: Float64Array;\n /**\n * Returns the `row`th row from the Matrix.\n *\n * @param {number} row\n * @returns {Float64Array}\n */\n row(row: number): Float64Array;\n /**\n * Returns an generator yielding each row of the Matrix.\n *\n * @yields {Float64Array}\n */\n iterate_rows(): Generator, void, unknown>;\n /**\n * Sets the entries of `row`th row from the Matrix to the entries from `values`.\n *\n * @param {number} row\n * @param {number[]} values\n * @returns {Matrix}\n */\n set_row(row: number, values: number[]): Matrix;\n /**\n * Swaps the rows `row1` and `row2` of the Matrix.\n *\n * @param {number} row1\n * @param {number} row2\n * @returns {Matrix}\n */\n swap_rows(row1: number, row2: number): Matrix;\n /**\n * Returns the colth column from the Matrix.\n *\n * @param {number} col\n * @returns {Float64Array}\n */\n col(col: number): Float64Array;\n /**\n * Returns the `col`th entry from the `row`th row of the Matrix.\n *\n * @param {number} row\n * @param {number} col\n * @returns {number}\n */\n entry(row: number, col: number): number;\n /**\n * Sets the {@link col}th entry from the {@link row}th row of the Matrix to the given\n * {@link value}.\n *\n * @param {number} row\n * @param {number} col\n * @param {number} value\n * @returns {Matrix}\n */\n set_entry(row: number, col: number, value: number): Matrix;\n /**\n * Adds a given {@link value} to the {@link col}th entry from the {@link row}th row of the\n * Matrix.\n *\n * @param {number} row\n * @param {number} col\n * @param {number} value\n * @returns {Matrix}\n */\n add_entry(row: number, col: number, value: number): Matrix;\n /**\n * Subtracts a given {@link value} from the {@link col}th entry from the {@link row}th row of the\n * Matrix.\n *\n * @param {number} row\n * @param {number} col\n * @param {number} value\n * @returns {Matrix}\n */\n sub_entry(row: number, col: number, value: number): Matrix;\n /**\n * Returns a new transposed Matrix.\n *\n * @returns {Matrix}\n */\n transpose(): Matrix;\n /**\n * Returns a new transposed Matrix. Short-form of `transpose`.\n *\n * @returns {Matrix}\n */\n get T(): Matrix;\n /**\n * Returns the inverse of the Matrix.\n *\n * @returns {Matrix}\n */\n inverse(): Matrix;\n /**\n * Returns the dot product. If `B` is an Array or Float64Array then an Array gets returned. If `B` is a Matrix then\n * a Matrix gets returned.\n *\n * @param {Matrix | number[] | Float64Array} B The right side\n * @returns {Matrix}\n */\n dot(B: Matrix | number[] | Float64Array): Matrix;\n /**\n * Transposes the current matrix and returns the dot product with `B`. If `B` is an Array or Float64Array then an\n * Array gets returned. If `B` is a Matrix then a Matrix gets returned.\n *\n * @param {Matrix | number[] | Float64Array} B The right side\n * @returns {Matrix}\n */\n transDot(B: Matrix | number[] | Float64Array): Matrix;\n /**\n * Returns the dot product with the transposed version of `B`. If `B` is an Array or Float64Array then an Array gets\n * returned. If `B` is a Matrix then a Matrix gets returned.\n *\n * @param {Matrix | number[] | Float64Array} B The right side\n * @returns {Matrix}\n */\n dotTrans(B: Matrix | number[] | Float64Array): Matrix;\n /**\n * Computes the outer product from `this` and `B`.\n *\n * @param {Matrix} B\n * @returns {Matrix}\n */\n outer(B: Matrix): Matrix;\n /**\n * Appends matrix `B` to the matrix.\n *\n * @example let A = Matrix.from([ [1, 1], [1, 1], ]); // 2 by 2 matrix filled with ones. let B = Matrix.from([ [2,\n * 2], [2, 2], ]); // 2 by 2 matrix filled with twos.\n *\n * A.concat(B, \"horizontal\"); // 2 by 4 matrix. [[1, 1, 2, 2], [1, 1, 2, 2]]\n * A.concat(B, \"vertical\"); // 4 by 2 matrix. [[1, 1], [1, 1], [2, 2], [2, 2]]\n * A.concat(B, \"diag\"); // 4 by 4 matrix. [[1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 2, 2], [0, 0, 2, 2]]\n *\n * @param {Matrix} B - Matrix to append.\n * @param {\"horizontal\" | \"vertical\" | \"diag\"} [type=\"horizontal\"] - Type of concatenation. Default is\n * `\"horizontal\"`\n * @returns {Matrix}\n */\n concat(B: Matrix, type?: \"horizontal\" | \"vertical\" | \"diag\"): Matrix;\n /**\n * Writes the entries of B in A at an offset position given by `offset_row` and `offset_col`.\n *\n * @param {number} offset_row\n * @param {number} offset_col\n * @param {Matrix} B\n * @returns {Matrix}\n */\n set_block(offset_row: number, offset_col: number, B: Matrix): Matrix;\n /**\n * Extracts the entries from the `start_row`th row to the `end_row`th row, the\n * `start_col`th column to the `end_col`th column of the matrix. If `end_row` or `end_col` is\n * empty, the respective value is set to `this.rows` or `this.cols`.\n *\n * @example let A = Matrix.from([ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]); // a 3 by 3 matrix.\n *\n * A.get_block(1, 1); // [[5, 6], [8, 9]]\n * A.get_block(0, 0, 1, 1); // [[1]]\n * A.get_block(1, 1, 2, 2); // [[5]]\n * A.get_block(0, 0, 2, 2); // [[1, 2], [4, 5]]\n *\n * @param {number} start_row\n * @param {number} start_col\n * @param {number | null} [end_row]\n * @param {number | null} [end_col]\n * @returns {Matrix} Returns a `end_row` - `start_row` times `end_col` - `start_col` matrix, with respective entries\n * from the matrix.\n */\n get_block(start_row: number, start_col: number, end_row?: number | null, end_col?: number | null): Matrix;\n /**\n * Returns a new array gathering entries defined by the indices given by argument.\n *\n * @param {number[]} row_indices - Array consists of indices of rows for gathering entries of this matrix\n * @param {number[]} col_indices - Array consists of indices of cols for gathering entries of this matrix\n * @returns {Matrix}\n */\n gather(row_indices: number[], col_indices: number[]): Matrix;\n /**\n * Applies a function to each entry of the matrix.\n *\n * @private\n * @param {(d: number, v: number) => number} f Function takes 2 parameters, the value of the actual entry and a\n * value given by the function `v`. The result of `f` gets writen to the Matrix.\n * @param {Accessor} v Function takes 2 parameters for `row` and `col`, and returns a value witch should be applied\n * to the `col`th entry of the `row`th row of the matrix.\n * @returns {Matrix}\n */\n private _apply_array;\n /**\n * @param {number[] | Float64Array} values\n * @param {(d: number, v: number) => number} f\n * @returns {Matrix}\n */\n _apply_rowwise_array(values: number[] | Float64Array, f: (d: number, v: number) => number): Matrix;\n /**\n * @param {number[] | Float64Array} values\n * @param {(d: number, v: number) => number} f\n * @returns {Matrix}\n */\n _apply_colwise_array(values: number[] | Float64Array, f: (d: number, v: number) => number): Matrix;\n /**\n * @param {Matrix | number[] | Float64Array | number} value\n * @param {(d: number, v: number) => number} f\n * @returns {Matrix}\n */\n _apply(value: Matrix | number[] | Float64Array | number, f: (d: number, v: number) => number): Matrix;\n /**\n * Clones the Matrix.\n *\n * @returns {Matrix}\n */\n clone(): Matrix;\n /**\n * Entrywise multiplication with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.mult(2); // [[2, 4], [6, 8]];\n * A.mult(B); // [[1, 4], [9, 16]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {boolean} [options.inline=false] - If true, applies multiplication to the element, otherwise it creates\n * first a copy and applies the multiplication on the copy. Default is `false`\n * @returns {Matrix}\n */\n mult(value: Matrix | Float64Array | number[] | number, { inline }?: {\n inline?: boolean | undefined;\n }): Matrix;\n /**\n * Entrywise division with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.divide(2); // [[0.5, 1], [1.5, 2]];\n * A.divide(B); // [[1, 1], [1, 1]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {Boolean} [options.inline=false] - If true, applies division to the element, otherwise it creates first a\n * copy and applies the division on the copy. Default is `false`\n * @returns {Matrix}\n */\n divide(value: Matrix | Float64Array | number[] | number, { inline }?: {\n inline?: boolean | undefined;\n }): Matrix;\n /**\n * Entrywise addition with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.add(2); // [[3, 4], [5, 6]];\n * A.add(B); // [[2, 4], [6, 8]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {boolean} [options.inline=false] - If true, applies addition to the element, otherwise it creates first a\n * copy and applies the addition on the copy. Default is `false`\n * @returns {Matrix}\n */\n add(value: Matrix | Float64Array | number[] | number, { inline }?: {\n inline?: boolean | undefined;\n }): Matrix;\n /**\n * Entrywise subtraction with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.sub(2); // [[-1, 0], [1, 2]];\n * A.sub(B); // [[0, 0], [0, 0]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {boolean} [options.inline=false] - If true, applies subtraction to the element, otherwise it creates first\n * a copy and applies the subtraction on the copy. Default is `false`\n * @returns {Matrix}\n */\n sub(value: Matrix | Float64Array | number[] | number, { inline }?: {\n inline?: boolean | undefined;\n }): Matrix;\n /**\n * Returns the matrix in the given shape with the given function which returns values for the entries of the matrix.\n *\n * @param {[number, number, Accessor]} parameter - Takes an Array in the form [rows, cols, value], where rows and\n * cols are the number of rows and columns of the matrix, and value is a function which takes two parameters (row\n * and col) which has to return a value for the colth entry of the rowth row.\n * @returns {Matrix}\n */\n set shape([rows, cols, value]: [number, number, Accessor]);\n /**\n * Returns the number of rows and columns of the Matrix.\n *\n * @returns {number[]} An Array in the form [rows, columns].\n */\n get shape(): number[];\n /**\n * Returns the Matrix as a Array of Float64Arrays.\n *\n * @returns {Float64Array[]}\n */\n to2dArray(): Float64Array[];\n /**\n * Returns the Matrix as a Array of Arrays.\n *\n * @returns {number[][]}\n */\n asArray(): number[][];\n /**\n * Returns the diagonal of the Matrix.\n *\n * @returns {Float64Array}\n */\n diag(): Float64Array;\n /**\n * Returns the mean of all entries of the Matrix.\n *\n * @returns {number}\n */\n mean(): number;\n /**\n * Returns the sum oof all entries of the Matrix.\n *\n * @returns {number}\n */\n sum(): number;\n /**\n * Returns the entries of the Matrix.\n *\n * @returns {Float64Array}\n */\n get values(): Float64Array;\n /**\n * Returns the mean of each row of the matrix.\n *\n * @returns {Float64Array}\n */\n meanRows(): Float64Array;\n /**\n * Returns the mean of each column of the matrix.\n *\n * @returns {Float64Array}\n */\n meanCols(): Float64Array;\n /**\n * Makes a `Matrix` object an iterable object.\n *\n * @yields {Float64Array}\n */\n [Symbol.iterator](): Generator, void, unknown>;\n}\nexport type Accessor = (i: number, j: number) => number;\nimport { Randomizer } from \"../util/index.js\";\n//# sourceMappingURL=Matrix.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/**\n * Computes the norm of a vector, by computing its distance to **0**.\n *\n * @category Matrix\n * @param {Matrix | number[] | Float64Array} v - Vector.\n * @param {Metric} [metric=euclidean] - Which metric should be used to compute the norm. Default is `euclidean`\n * @returns {number} - The norm of `v`.\n */\nexport function norm(v: Matrix | number[] | Float64Array, metric?: Metric): number;\nimport { Matrix } from \"../matrix/index.js\";\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=norm.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/**\n * Normalizes Vector `v`.\n *\n * @category Matrix\n * @param {number[] | Float64Array} v - Vector\n * @param {Metric} metric\n * @returns {number[] | Float64Array} - The normalized vector with length 1.\n */\nexport function normalize(v: number[] | Float64Array, metric?: Metric): number[] | Float64Array;\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=normalize.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/**\n * Base class for all clustering algorithms.\n * @template Para\n */\nexport class Clustering {\n /**\n * Compute the respective Clustering with given parameters\n * @param {InputType} points\n * @param {Para} parameters\n */\n constructor(points: InputType, parameters: Para);\n /** @type {InputType} */\n _points: InputType;\n /** @type {Para} */\n _parameters: Para;\n /** @type {Matrix} */\n _matrix: Matrix;\n /** @type {number} */\n _N: number;\n /** @type {number} */\n _D: number;\n /**\n * @abstract\n * @param {...unknown} args\n * @returns {number[][]} An array with the indices of the clusters.\n */\n get_clusters(...args: unknown[]): number[][];\n /**\n * @abstract\n * @param {...unknown} args\n * @returns {number[]} An array with the clusters id's for each point.\n */\n get_cluster_list(...args: unknown[]): number[];\n}\nimport type { InputType } from \"../index.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=Clustering.d.ts.map","/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersCURE } from \"./index.js\" */\n/**\n * CURE (Clustering Using REpresentatives)\n *\n * An efficient clustering algorithm for large databases that is robust to outliers\n * and identifies clusters with non-spherical shapes and wide variances in size.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class CURE extends Clustering {\n /**\n * @param {InputType} points\n * @param {Partial} parameters\n */\n constructor(points: InputType, parameters?: Partial);\n /** @type {number} */\n _K: number;\n /** @type {number} */\n _num_representatives: number;\n /** @type {number} */\n _shrink_factor: number;\n /**\n * @private\n * @type {CURECluster[]}\n */\n private _clusters;\n /** @type {number[]} */\n _cluster_ids: number[];\n /**\n * Initialize each point as its own cluster\n * @private\n */\n private _initialize_clusters;\n /**\n * Compute distance between two clusters using representative points\n * @private\n * @param {CURECluster} cluster1\n * @param {CURECluster} cluster2\n * @returns {number}\n */\n private _cluster_distance;\n /**\n * Find the closest pair of clusters\n * @private\n * @returns {[number, number, number]} [index1, index2, distance]\n */\n private _find_closest_clusters;\n /**\n * Merge two clusters\n * @private\n * @param {CURECluster} cluster1\n * @param {CURECluster} cluster2\n * @returns {CURECluster}\n */\n private _merge_clusters;\n /**\n * Run CURE clustering algorithm\n * @private\n */\n private _cure;\n /**\n * Build the cluster list (point -> cluster assignment)\n * @private\n */\n private _build_cluster_ids;\n /**\n * @returns {number[][]}\n */\n get_clusters(): number[][];\n /**\n * @returns {number[]}\n */\n get_cluster_list(): number[];\n}\nimport type { ParametersCURE } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport type { InputType } from \"../index.js\";\n//# sourceMappingURL=CURE.d.ts.map","/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersHierarchicalClustering } from \"./index.js\" */\n/**\n * Hierarchical Clustering\n *\n * A bottom-up approach (agglomerative) to clustering that builds a tree of clusters (dendrogram).\n * Supports different linkage criteria: single, complete, and average.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class HierarchicalClustering extends Clustering {\n /**\n * @param {InputType} points - Data or distance matrix if metric is 'precomputed'\n * @param {Partial} parameters\n */\n constructor(points: InputType, parameters?: Partial);\n /** @type {Cluster | null} */\n root: Cluster | null;\n _id: number;\n _d_min: Float64Array;\n _distance_matrix: Matrix;\n _clusters: any[];\n _c_size: Uint16Array;\n /**\n * @param {number} value - Value where to cut the tree.\n * @param {\"distance\" | \"depth\"} [type=\"distance\"] - Type of value. Default is `\"distance\"`\n * @returns {Cluster[][]} - Array of clusters with the indices of the rows in given points.\n */\n get_clusters_raw(value: number, type?: \"distance\" | \"depth\"): Cluster[][];\n /**\n * @param {number} value - Value where to cut the tree.\n * @param {\"distance\" | \"depth\"} [type=\"distance\"] - Type of value. Default is `\"distance\"`\n * @returns {number[][]} - Array of clusters with the indices of the rows in given points.\n */\n get_clusters(value: number, type?: \"distance\" | \"depth\"): number[][];\n /**\n * @param {number} value - Value where to cut the tree.\n * @param {\"distance\" | \"depth\"} [type=\"distance\"] - Type of value. Default is `\"distance\"`\n * @returns {number[]} - Array of clusters with the indices of the rows in given points.\n */\n get_cluster_list(value: number, type?: \"distance\" | \"depth\"): number[];\n /**\n * @private\n * @param {Cluster} node\n * @param {(d: {dist: number, depth: number}) => number} f\n * @param {number} value\n * @param {Cluster[][]} result\n */\n private _traverse;\n}\nimport type { ParametersHierarchicalClustering } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\n/** @private */\ndeclare class Cluster {\n /**\n *\n * @param {number} id\n * @param {Cluster?} left\n * @param {Cluster?} right\n * @param {number} dist\n * @param {Float64Array?} centroid\n * @param {number} index\n * @param {number} [size]\n * @param {number} [depth]\n */\n constructor(id: number, left: Cluster | null, right: Cluster | null, dist: number, centroid: Float64Array | null, index: number, size?: number, depth?: number);\n /**@type {number} */\n size: number;\n /**@type {number} */\n depth: number;\n /**@type {Cluster | null} */\n parent: Cluster | null;\n id: number;\n left: Cluster | null;\n right: Cluster | null;\n dist: number;\n index: number;\n centroid: Float64Array;\n /**\n *\n * @param {Cluster} left\n * @param {Cluster} right\n * @returns {Float64Array}\n */\n _calculate_centroid(left: Cluster, right: Cluster): Float64Array;\n get isLeaf(): boolean;\n /**\n *\n * @returns {Cluster[]}\n */\n leaves(): Cluster[];\n /**\n *\n * @returns {Cluster[]}\n */\n descendants(): Cluster[];\n}\nimport { Matrix } from \"../matrix/index.js\";\nimport type { InputType } from \"../index.js\";\nexport {};\n//# sourceMappingURL=Hierarchical_Clustering.d.ts.map","/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersKMeans } from \"./index.js\" */\n/**\n * K-Means Clustering\n *\n * A popular clustering algorithm that partitions data into K clusters where each point\n * belongs to the cluster with the nearest mean (centroid).\n *\n * @class\n * @extends Clustering\n * @category Clustering\n * @see {@link KMedoids} for a more robust alternative\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const points = [[1, 1], [1.5, 1.5], [5, 5], [5.5, 5.5]];\n * const kmeans = new druid.KMeans(points, { K: 2 });\n *\n * const clusters = kmeans.get_cluster_list(); // [0, 0, 1, 1]\n * const centroids = kmeans.centroids; // center points\n */\nexport class KMeans extends Clustering {\n /**\n * @param {InputType} points\n * @param {Partial} parameters\n */\n constructor(points: InputType, parameters?: Partial);\n _K: number;\n _randomizer: Randomizer;\n /** @type {number[]} */\n _clusters: number[];\n _cluster_centroids: Float64Array[];\n /** @returns {number} The number of clusters */\n get k(): number;\n /** @returns {Float64Array[]} The cluster centroids */\n get centroids(): Float64Array[];\n /** @returns {number[]} The cluster list */\n get_cluster_list(): number[];\n /** @returns {number[][]} An Array of clusters with the indices of the points. */\n get_clusters(): number[][];\n /**\n * @private\n * @param {number[]} point_indices\n * @param {number[]} candidates\n * @returns {number}\n */\n private _furthest_point;\n /**\n * @private\n * @param {number} K\n * @returns {Float64Array[]}\n */\n private _get_random_centroids;\n /**\n * @private\n * @param {Float64Array[]} cluster_centroids\n * @returns {{ clusters_changed: boolean; cluster_centroids: Float64Array[] }}\n */\n private _iteration;\n /**\n * @private\n * @param {number} K\n * @returns {Float64Array[]}\n */\n private _compute_centroid;\n}\nimport type { ParametersKMeans } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport type { InputType } from \"../index.js\";\n//# sourceMappingURL=KMeans.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import { ParametersKMedoids } from \"./index.js\" */\n/**\n * K-Medoids (PAM - Partitioning Around Medoids)\n *\n * A robust clustering algorithm similar to K-Means, but uses actual data points (medoids)\n * as cluster centers and can work with any distance metric.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n * @see {@link KMeans} for a faster but less robust alternative\n */\nexport class KMedoids extends Clustering {\n /**\n * @param {InputType} points - Data matrix\n * @param {Partial} parameters\n * @see {@link https://link.springer.com/chapter/10.1007/978-3-030-32047-8_16} Faster k-Medoids Clustering: Improving the PAM, CLARA, and CLARANS Algorithms\n */\n constructor(points: InputType, parameters?: Partial);\n _A: Float64Array[];\n _max_iter: number;\n _distance_matrix: Matrix;\n _randomizer: Randomizer;\n _clusters: any[];\n _cluster_medoids: number[];\n _is_initialized: boolean;\n /** @returns {number[]} The cluster list */\n get_cluster_list(): number[];\n /** @returns {number[][]} - Array of clusters with the indices of the rows in given points. */\n get_clusters(): number[][];\n /** @returns {number} */\n get k(): number;\n /** @returns {number[]} */\n get medoids(): number[];\n /** @returns {number[]} */\n get_medoids(): number[];\n generator(): AsyncGenerator;\n /** Algorithm 1. FastPAM1: Improved SWAP algorithm */\n /** FastPAM1: One best swap per iteration */\n _iteration(): boolean;\n /**\n *\n * @param {number} i\n * @param {number} j\n * @param {Float64Array?} x_i\n * @param {Float64Array?} x_j\n * @returns\n */\n _get_distance(i: number, j: number, x_i?: Float64Array | null, x_j?: Float64Array | null): number;\n /**\n *\n * @param {Float64Array} x_j\n * @param {number} j\n * @returns\n */\n _nearest_medoid(x_j: Float64Array, j: number): {\n distance_nearest: number;\n index_nearest: number;\n distance_second: number;\n index_second: number;\n };\n _update_clusters(): void;\n /**\n * Computes `K` clusters out of the `matrix`.\n * @param {number} K - Number of clusters.\n * @param {number[]} cluster_medoids\n */\n init(K: number, cluster_medoids: number[]): this;\n /**\n * Algorithm 3. FastPAM LAB: Linear Approximate BUILD initialization.\n *\n * @param {number} K - Number of clusters\n * @returns {number[]}\n */\n _get_random_medoids(K: number): number[];\n}\nimport type { ParametersKMedoids } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport type { InputType } from \"../index.js\";\n//# sourceMappingURL=KMedoids.d.ts.map","/** @import { ParametersMeanShift } from \"./index.js\" */\n/** @import { InputType } from \"../index.js\" */\n/**\n * Mean Shift Clustering\n *\n * A non-parametric clustering technique that does not require prior knowledge of the\n * number of clusters. It identifies centers of density in the data.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class MeanShift extends Clustering {\n /**\n *\n * @param {InputType} points\n * @param {Partial} parameters\n */\n constructor(points: InputType, parameters?: Partial);\n /** @type {number} */\n _bandwidth: number;\n /** @type {number} */\n _max_iter: number;\n /** @type {number} */\n _tolerance: number;\n /** @type {(dist: number) => number} */\n _kernel: (dist: number) => number;\n /** @type {Matrix} */\n _points: Matrix;\n /** @type {number[] | undefined} */\n _clusters: number[] | undefined;\n /** @type {number[][] | undefined} */\n _cluster_list: number[][] | undefined;\n /**\n * @param {Matrix} matrix\n * @returns {number}\n */\n _compute_bandwidth(matrix: Matrix): number;\n /**\n * @param {number} dist\n * @returns {number}\n */\n _kernel_weight(dist: number): number;\n _mean_shift(): void;\n _assign_clusters(): void;\n /**\n * @returns {number[][]}\n */\n get_clusters(): number[][];\n /**\n *\n * @returns {number[]}\n */\n get_cluster_list(): number[];\n}\nimport type { ParametersMeanShift } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport type { InputType } from \"../index.js\";\n//# sourceMappingURL=MeanShift.d.ts.map","/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersOptics } from \"./index.js\" */\n/** @typedef {Object} DBEntry\n * @property {Float64Array} element\n * @property {number} index\n * @property {number} [reachability_distance]\n * @property {boolean} processed\n * @property {DBEntry[]} [neighbors]\n */\n/**\n * OPTICS (Ordering Points To Identify the Clustering Structure)\n *\n * A density-based clustering algorithm that extends DBSCAN. It handles clusters of varying\n * densities and produces a reachability plot that can be used to extract clusters.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class OPTICS extends Clustering {\n /**\n * **O**rdering **P**oints **T**o **I**dentify the **C**lustering **S**tructure.\n *\n * @param {InputType} points - The data.\n * @param {Partial} [parameters={}]\n * @see {@link https://www.dbs.ifi.lmu.de/Publikationen/Papers/OPTICS.pdf}\n * @see {@link https://en.wikipedia.org/wiki/OPTICS_algorithm}\n */\n constructor(points: InputType, parameters?: Partial);\n /**\n * @private\n * @type {DBEntry[]}\n */\n private _ordered_list;\n /** @type {number[][]} */\n _clusters: number[][];\n /**\n * @private\n * @type {DBEntry[]}\n */\n private _DB;\n _cluster_index: number;\n /**\n * @private\n * @param {DBEntry} p - A point of the data.\n * @returns {DBEntry[]} An array consisting of the `epsilon`-neighborhood of `p`.\n */\n private _get_neighbors;\n /**\n * @private\n * @param {DBEntry} p - A point of `matrix`.\n * @returns {number|undefined} The distance to the `min_points`-th nearest point of `p`, or undefined if the\n * `epsilon`-neighborhood has fewer elements than `min_points`.\n */\n private _core_distance;\n /**\n * Updates the reachability distance of the points.\n *\n * @private\n * @param {DBEntry} p\n * @param {Heap} seeds\n */\n private _update;\n /**\n * Expands the `cluster` with points in `seeds`.\n *\n * @private\n * @param {Heap} seeds\n * @param {number[]} cluster\n */\n private _expand_cluster;\n /**\n * Returns an array of clusters.\n *\n * @returns {number[][]} Array of clusters with the indices of the rows in given `matrix`.\n */\n get_clusters(): number[][];\n /**\n * @returns {number[]} Returns an array, where the ith entry defines the cluster affirmation of the ith point of\n * given data. (-1 stands for outlier)\n */\n get_cluster_list(): number[];\n}\nexport type DBEntry = {\n element: Float64Array;\n index: number;\n reachability_distance?: number | undefined;\n processed: boolean;\n neighbors?: DBEntry[] | undefined;\n};\nimport type { ParametersOptics } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport type { InputType } from \"../index.js\";\n//# sourceMappingURL=OPTICS.d.ts.map","/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersXMeans } from \"./index.js\" */\n/**\n * @typedef SplitResult\n * @property {number} index - Index of the cluster being split\n * @property {number} bic_parent - BIC score of the parent cluster\n * @property {number} bic_children - BIC score of the split children\n * @property {number[][]} child_clusters - Clusters after splitting\n * @property {Float64Array[]} child_centroids - Centroids of child clusters\n */\n/**\n * @typedef CandidateResult\n * @property {KMeans} kmeans - The KMeans instance for this K\n * @property {number} score - BIC score\n */\n/**\n * X-Means Clustering\n *\n * An extension of K-Means that automatically determines the number of clusters (K)\n * using the Bayesian Information Criterion (BIC).\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class XMeans extends Clustering {\n /**\n * XMeans clustering algorithm that automatically determines the optimal number of clusters.\n *\n * X-Means extends K-Means by starting with a minimum number of clusters and iteratively\n * splitting clusters to improve the Bayesian Information Criterion (BIC).\n *\n * Algorithm:\n * 1. Start with K_min clusters using KMeans\n * 2. For each cluster, try splitting it into 2 sub-clusters\n * 3. If BIC improves after splitting, keep the split\n * 4. Run KMeans again with all (old + new) centroids\n * 5. Repeat until K_max is reached or no more improvements\n *\n * @param {InputType} points - The data points to cluster\n * @param {Partial} [parameters={}] - Configuration parameters\n * @see {@link https://www.cs.cmu.edu/~dpelleg/download/xmeans.pdf}\n * @see {@link https://github.com/annoviko/pyclustering/blob/master/pyclustering/cluster/xmeans.py}\n * @see {@link https://github.com/haifengl/smile/blob/master/core/src/main/java/smile/clustering/XMeans.java}\n */\n constructor(points: InputType, parameters?: Partial);\n _randomizer: Randomizer;\n /** @type {KMeans | null} */\n _best_kmeans: KMeans | null;\n /**\n * Run the XMeans algorithm\n *\n * @private\n */\n private _run;\n /**\n * Select the best candidate based on BIC score\n *\n * @private\n * @param {Map} candidates\n * @returns {KMeans}\n */\n private _select_best_candidate;\n /**\n * Calculate Bayesian Information Criterion for a set of clusters.\n *\n * Uses Kass's formula for BIC calculation:\n * BIC(θ) = L(D) - 0.5 * p * ln(N)\n *\n * Where:\n * - L(D) is the log-likelihood of the data\n * - p is the number of free parameters: (K-1) + D*K + 1\n * - N is the total number of points\n *\n * @private\n * @param {number[][]} clusters - Array of clusters with point indices\n * @param {Float64Array[]} centroids - Array of centroids\n * @returns {number} BIC score (higher is better)\n */\n private _bic;\n /**\n * Get the computed clusters\n *\n * @returns {number[][]} Array of clusters, each containing indices of points\n */\n get_clusters(): number[][];\n /** @returns {number[]} The cluster list */\n get_cluster_list(): number[];\n /**\n * Get the final centroids\n *\n * @returns {Float64Array[]} Array of centroids\n */\n get centroids(): Float64Array[];\n /**\n * Get the optimal number of clusters found\n *\n * @returns {number} The number of clusters\n */\n get k(): number;\n}\nexport type SplitResult = {\n /**\n * - Index of the cluster being split\n */\n index: number;\n /**\n * - BIC score of the parent cluster\n */\n bic_parent: number;\n /**\n * - BIC score of the split children\n */\n bic_children: number;\n /**\n * - Clusters after splitting\n */\n child_clusters: number[][];\n /**\n * - Centroids of child clusters\n */\n child_centroids: Float64Array[];\n};\nexport type CandidateResult = {\n /**\n * - The KMeans instance for this K\n */\n kmeans: KMeans;\n /**\n * - BIC score\n */\n score: number;\n};\nimport type { ParametersXMeans } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { KMeans } from \"./KMeans.js\";\nimport type { InputType } from \"../index.js\";\n//# sourceMappingURL=XMeans.d.ts.map","export { CURE } from \"./CURE.js\";\nexport { HierarchicalClustering } from \"./Hierarchical_Clustering.js\";\nexport { KMeans } from \"./KMeans.js\";\nexport { KMedoids } from \"./KMedoids.js\";\nexport { MeanShift } from \"./MeanShift.js\";\nexport { OPTICS } from \"./OPTICS.js\";\nexport { XMeans } from \"./XMeans.js\";\nexport type ParametersHierarchicalClustering = {\n linkage: \"single\" | \"complete\" | \"average\";\n metric: Metric | \"precomputed\";\n};\nexport type ParametersKMeans = {\n K: number;\n /**\n * Default is `euclidean`\n */\n metric: Metric;\n /**\n * Default is `1212`\n */\n seed: number;\n /**\n * - Initial centroids. Default is `null`\n */\n initial_centroids?: Float64Array[] | number[][] | undefined;\n};\nexport type ParametersKMedoids = {\n /**\n * - Number of clusters\n */\n K: number;\n /**\n * - Maximum number of iterations. Default is 10 * Math.log10(N). Default is `null`\n */\n max_iter: number | null;\n /**\n * - Metric defining the dissimilarity. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Seed value for random number generator. Default is `1212`\n */\n seed: number;\n};\nexport type ParametersOptics = {\n /**\n * - The minimum distance which defines whether a point is a neighbor or not.\n */\n epsilon: number;\n /**\n * - The minimum number of points which a point needs to create a cluster. (Should be higher than 1, else each point creates a cluster.)\n */\n min_points: number;\n /**\n * - The distance metric which defines the distance between two points of the points. Default is `euclidean`\n */\n metric: Metric;\n};\nexport type ParametersXMeans = {\n /**\n * - Minimum number of clusters. Default is `2`\n */\n K_min: number;\n /**\n * - Maximum number of clusters. Default is `10`\n */\n K_max: number;\n /**\n * - Distance metric function. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Random seed. Default is `1212`\n */\n seed: number;\n /**\n * - Minimum points required to consider splitting a cluster. Default is `25`\n */\n min_cluster_size: number;\n /**\n * - Convergence tolerance for KMeans. Default is `0.001`\n */\n tolerance: number;\n};\nexport type ParametersMeanShift = {\n /**\n * - bandwidth\n */\n bandwidth: number;\n /**\n * - Metric defining the dissimilarity. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Seed value for random number generator. Default is `1212`\n */\n seed: number;\n /**\n * - Kernel function. Default is `gaussian`\n */\n kernel: \"flat\" | \"gaussian\" | ((dist: number) => number);\n /**\n * - Maximum number of iterations. Default is `Math.max(10, Math.floor(10 * Math.log10(N)))`\n */\n max_iter?: number | undefined;\n /**\n * - Convergence tolerance. Default is `1e-3`\n */\n tolerance?: number | undefined;\n};\nexport type ParametersCURE = {\n /**\n * - Target number of clusters. Default is `2`\n */\n K: number;\n /**\n * - Number of representative points per cluster. Default is `5`\n */\n num_representatives: number;\n /**\n * - Factor to shrink representatives toward centroid (0-1). Default is `0.5`\n */\n shrink_factor: number;\n /**\n * - Distance metric function. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Random seed. Default is `1212`\n */\n seed: number;\n};\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=index.d.ts.map","/**\n * @template T\n * @typedef {Object} DisjointSetPayload\n * @property {T} parent\n * @property {Set} children\n * @property {number} size\n */\n/**\n * @template T\n * @class\n * @category Data Structures\n * @see {@link https://en.wikipedia.org/wiki/Disjoint-set_data_structure}\n */\nexport class DisjointSet {\n /**\n * @param {T[]?} elements\n */\n constructor(elements?: T[] | null);\n /**\n * @private\n * @type {Map>}\n */\n private _list;\n /**\n * @private\n * @param {T} x\n * @returns {DisjointSet}\n */\n private make_set;\n /**\n * @param {T} x\n * @returns\n */\n find(x: T): T | null;\n /**\n * @param {T} x\n * @param {T} y\n * @returns\n */\n union(x: T, y: T): this;\n /** @param {T} x */\n get_children(x: T): Set | null;\n}\nexport type DisjointSetPayload = {\n parent: T;\n children: Set;\n size: number;\n};\n//# sourceMappingURL=DisjointSet.d.ts.map","/** @import { Comparator } from \"./index.js\" */\n/**\n * @template T\n * @class\n * @category Data Structures\n */\nexport class Heap {\n /**\n * Creates a Heap from an Array\n *\n * @template T\n * @param {T[]} elements - Contains the elements for the Heap.\n * @param {(d: T) => number} accessor - Function returns the value of the element.\n * @param {\"min\" | \"max\" | Comparator} [comparator=\"min\"] - Function returning true or false\n * defining the wished order of the Heap, or String for predefined function. (\"min\" for a Min-Heap, \"max\" for a\n * Max_heap). Default is `\"min\"`\n * @returns {Heap}\n */\n static heapify(elements: T_1[], accessor: (d: T_1) => number, comparator?: \"min\" | \"max\" | Comparator): Heap;\n /**\n * A heap is a datastructure holding its elements in a specific way, so that the top element would be the first\n * entry of an ordered list.\n *\n * @param {T[]?} elements - Contains the elements for the Heap. `elements` can be null.\n * @param {(d: T) => number} accessor - Function returns the value of the element.\n * @param {\"min\" | \"max\" | Comparator} [comparator=\"min\"] - Function returning true or false\n * defining the wished order of the Heap, or String for predefined function. (\"min\" for a Min-Heap, \"max\" for a\n * Max_heap). Default is `\"min\"`\n * @see {@link https://en.wikipedia.org/wiki/Binary_heap}\n */\n constructor(elements: (T[] | null) | undefined, accessor: (d: T) => number, comparator?: \"min\" | \"max\" | Comparator);\n /** @type {{ element: T; value: number }[]} */\n _container: {\n element: T;\n value: number;\n }[];\n /** @type {Comparator} */\n _comparator: Comparator;\n /** @type {(d: T) => number} */\n _accessor: (d: T) => number;\n /**\n * Swaps elements of container array.\n *\n * @private\n * @param {number} index_a\n * @param {number} index_b\n */\n private _swap;\n /** @private */\n private _heapify_up;\n /**\n * Pushes the element to the heap.\n *\n * @param {T} element\n * @returns {Heap}\n */\n push(element: T): Heap;\n /**\n * @private\n * @param {Number} [start_index=0] Default is `0`\n */\n private _heapify_down;\n /**\n * Removes and returns the top entry of the heap.\n *\n * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by\n * `accessor`}).\n */\n pop(): {\n element: T;\n value: number;\n } | null;\n /**\n * Returns the top entry of the heap without removing it.\n *\n * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by\n * `accessor`).\n */\n get first(): {\n element: T;\n value: number;\n } | null;\n /**\n * Yields the raw data\n *\n * @yields {T} Object consists of the element and its value (computed by `accessor`}).\n */\n iterate(): Generator;\n /**\n * Returns the heap as ordered array.\n *\n * @returns {T[]} Array consisting the elements ordered by `comparator`.\n */\n toArray(): T[];\n /**\n * Returns elements of container array.\n *\n * @returns {T[]} Array consisting the elements.\n */\n data(): T[];\n /**\n * Returns the container array.\n *\n * @returns {{ element: T; value: number }[]} The container array.\n */\n raw_data(): {\n element: T;\n value: number;\n }[];\n /**\n * The size of the heap.\n *\n * @returns {number}\n */\n get length(): number;\n /**\n * Returns false if the the heap has entries, true if the heap has no entries.\n *\n * @returns {boolean}\n */\n get empty(): boolean;\n}\nimport type { Comparator } from \"./index.js\";\n//# sourceMappingURL=Heap.d.ts.map","export { DisjointSet } from \"./DisjointSet.js\";\nexport { Heap } from \"./Heap.js\";\nexport type Comparator = (a: number, b: number) => boolean;\n//# sourceMappingURL=index.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/**\n * @abstract\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n *\n * Base class for all Dimensionality Reduction (DR) algorithms.\n *\n * Provides a common interface for parameters management, data initialization,\n * and transformation (both synchronous and asynchronous).\n *\n * @class\n */\nexport class DR {\n /**\n * Computes the projection.\n *\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.\n * @returns {T} The dimensionality reduced dataset.\n */\n static transform(X: T_1, parameters: Para_1, ...args: unknown[]): T_1;\n /**\n * Computes the projection.\n *\n * @template {{ seed?: number }} Para\n * @param {InputType} X\n * @param {Para} parameters\n * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.\n * @returns {Generator} A generator yielding the intermediate steps of the dimensionality\n * reduction method.\n */\n static generator(X: InputType, parameters: Para_1, ...args: unknown[]): Generator;\n /**\n * Computes the projection.\n *\n * @template {{ seed?: number }} Para\n * @param {InputType} X\n * @param {Para} parameters\n * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.\n * @returns {Promise} A promise yielding the dimensionality reduced dataset.\n */\n static transform_async(X: InputType, parameters: Para_1, ...args: unknown[]): Promise;\n /**\n * Takes the default parameters and seals them, remembers the type of input `X`, and initializes the random number\n * generator.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Para} default_parameters - Object containing default parameterization of the DR method.\n * @param {Partial} parameters - Object containing parameterization of the DR method to override defaults.\n */\n constructor(X: T, default_parameters: Para, parameters?: Partial);\n /** @type {number} */\n _D: number;\n /** @type {number} */\n _N: number;\n /** @type {Randomizer} */\n _randomizer: Randomizer;\n /** @type {boolean} */\n _is_initialized: boolean;\n /** @type {T} */\n __input: T;\n /** @type {Para} */\n _parameters: Para;\n /** @type {\"array\" | \"matrix\" | \"typed\"} */\n _type: \"array\" | \"matrix\" | \"typed\";\n /** @type {Matrix} */\n X: Matrix;\n /** @type {Matrix} */\n Y: Matrix;\n /**\n * Get all Parameters.\n * @overload\n * @returns {Para}\n */\n parameter(): Para;\n /**\n * Get value of given parameter.\n * @template {keyof Para} K\n * @overload\n * @param {K} name - Name of the parameter.\n * @returns {Para[K]}\n */\n parameter(name: K): Para[K];\n /**\n * Set value of given parameter.\n * @template {keyof Para} K\n * @overload\n * @param {K} name - Name of the parameter.\n * @param {Para[K]} value - Value of the parameter to set.\n * @returns {this}\n */\n parameter(name: K, value: Para[K]): this;\n /**\n * Computes the projection.\n *\n * @abstract\n * @param {...unknown} args\n * @returns {T} The projection.\n */\n transform(...args: unknown[]): T;\n /**\n * Computes the projection.\n *\n * @abstract\n * @param {...unknown} args\n * @returns {Generator} The intermediate steps of the projection.\n */\n generator(...args: unknown[]): Generator;\n /**\n * @abstract\n * @param {...unknown} args\n */\n init(...args: unknown[]): void;\n /**\n * If the respective DR method has an `init` function, call it before `transform`.\n *\n * @returns {DR}\n */\n check_init(): DR;\n /** @returns {T} The projection in the type of input `X`. */\n get projection(): T;\n /**\n * Computes the projection.\n *\n * @param {...unknown} args - Arguments the transform method of the respective DR method takes.\n * @returns {Promise} The dimensionality reduced dataset.\n */\n transform_async(...args: unknown[]): Promise;\n}\nimport type { InputType } from \"../index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=DR.d.ts.map","/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersFASTMAP } from \"./index.js\"; */\n/**\n * FastMap algorithm for dimensionality reduction.\n *\n * A very fast algorithm for projecting high-dimensional data into a lower-dimensional\n * space while preserving pairwise distances. It works similarly to PCA but uses\n * only a subset of the data to find projection axes.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class FASTMAP extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X: T_1, parameters: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static generator(X: T_1, parameters: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters: Partial): Promise;\n /**\n * FastMap: a fast algorithm for indexing, data-mining and visualization of traditional and multimedia datasets.\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://doi.org/10.1145/223784.223812}\n */\n constructor(X: T, parameters: Partial);\n /**\n * Chooses two points which are the most distant in the actual projection.\n *\n * @private\n * @param {(a: number, b: number) => number} dist\n * @returns {[number, number, number]} An array consisting of first index, second index, and distance between the\n * two points.\n */\n private _choose_distant_objects;\n /**\n * Computes the projection.\n *\n * @returns {T} The `d`-dimensional projection of the data matrix `X`.\n */\n transform(): T;\n generator(): Generator;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersFASTMAP } from \"./index.js\";\nimport { DR } from \"./DR.js\";\n//# sourceMappingURL=FASTMAP.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersISOMAP} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n/**\n * Isomap (Isometric Mapping)\n *\n * A nonlinear dimensionality reduction algorithm that uses geodesic distances\n * between points on a manifold to perform embedding. It builds a neighborhood\n * graph and uses MDS on the shortest-path distances.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link LLE} for another nonlinear alternative\n */\nexport class ISOMAP extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * Isometric feature mapping (ISOMAP).\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n * @see {@link https://doi.org/10.1126/science.290.5500.2319}\n */\n constructor(X: T, parameters?: Partial);\n defaults: ParametersISOMAP;\n /**\n * Computes the projection.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * @returns {T}\n */\n transform(): T;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersISOMAP } from \"./index.js\";\nimport { DR } from \"./DR.js\";\n//# sourceMappingURL=ISOMAP.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLDA} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n/**\n * Linear Discriminant Analysis (LDA)\n *\n * A supervised dimensionality reduction technique that finds the axes that\n * maximize the separation between multiple classes.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class LDA extends DR {\n /**\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @returns {T}\n */\n static transform(X: T_1, parameters: Para): T_1;\n /**\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @returns {Generator}\n */\n static generator(X: T_1, parameters: Para): Generator;\n /**\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters: Para): Promise;\n /**\n * Linear Discriminant Analysis.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial & { labels: any[] | Float64Array }} parameters - Object containing parameterization of the DR method.\n * @see {@link https://onlinelibrary.wiley.com/doi/10.1111/j.1469-1809.1936.tb02137.x}\n */\n constructor(X: T, parameters: Partial & {\n labels: any[] | Float64Array;\n });\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T} - The projected data.\n */\n transform(): T;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersLDA } from \"./index.js\";\nimport { DR } from \"./DR.js\";\n//# sourceMappingURL=LDA.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLLE} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n/**\n * Locally Linear Embedding (LLE)\n *\n * A nonlinear dimensionality reduction technique that preserves local\n * linear relationships between points. It represents each point as a linear\n * combination of its neighbors.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link ISOMAP} for another nonlinear alternative\n */\nexport class LLE extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X: T_1, parameters: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static generator(X: T_1, parameters: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters: Partial): Promise;\n /**\n * Locally Linear Embedding.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://doi.org/10.1126/science.290.5500.2323}\n */\n constructor(X: T, parameters: Partial);\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T}\n */\n transform(): T;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersLLE } from \"./index.js\";\nimport { DR } from \"./DR.js\";\n//# sourceMappingURL=LLE.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLSP} from \"./index.js\" */\n/**\n * Least Square Projection (LSP)\n *\n * A dimensionality reduction technique that uses a small set of control points\n * (projected with MDS) to define the projection for the rest of the data\n * using a Laplacian-based optimization.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class LSP extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * Least Squares Projection.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n * @see {@link https://ieeexplore.ieee.org/document/4378370}\n */\n constructor(X: T, parameters?: Partial);\n /**\n * @returns {LSP}\n */\n init(): LSP;\n _A: Matrix | undefined;\n _b: Matrix | undefined;\n /**\n * Computes the projection.\n *\n * @returns {T} Returns the projection.\n */\n transform(): T;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersLSP } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=LSP.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLTSA} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n/**\n * Local Tangent Space Alignment (LTSA)\n *\n * A nonlinear dimensionality reduction algorithm that represents the local\n * geometry of the manifold by tangent spaces and then aligns them to reveal\n * the global structure.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class LTSA extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X: T_1, parameters: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static generator(X: T_1, parameters: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters: Partial): Promise;\n /**\n * Local Tangent Space Alignment\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://epubs.siam.org/doi/abs/10.1137/S1064827502419154}\n */\n constructor(X: T, parameters: Partial);\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * Transforms the inputdata `X` to dimenionality `d`.\n *\n * @returns {T}\n */\n transform(): T;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersLTSA } from \"./index.js\";\nimport { DR } from \"./DR.js\";\n//# sourceMappingURL=LTSA.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersMDS} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n/**\n * Classical Multidimensional Scaling (MDS)\n *\n * A linear dimensionality reduction technique that seeks to preserve the\n * pairwise distances between points as much as possible in the lower-dimensional\n * space.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link PCA} for another linear alternative\n */\nexport class MDS extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * Classical MDS.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X: T, parameters?: Partial);\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T}\n */\n transform(): T;\n _d_X: Matrix | undefined;\n /** @returns {number} - The stress of the projection. */\n stress(): number;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersMDS } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=MDS.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersPCA} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n/**\n * Principal Component Analysis (PCA)\n *\n * A linear dimensionality reduction technique that identifies the axes (principal components)\n * along which the variance of the data is maximized.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link MDS} for another linear alternative\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2], [3, 4], [5, 6]];\n * const pca = new druid.PCA(X, { d: 2 });\n * const Y = pca.transform();\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class PCA extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X: T_1, parameters: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Matrix}\n */\n static principal_components(X: T_1, parameters: Partial): Matrix;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X: T, parameters?: Partial);\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T} - The projected data.\n */\n transform(): T;\n /**\n * Computes the `d` principal components of Matrix `X`.\n *\n * @returns {Matrix}\n */\n principal_components(): Matrix;\n V: Matrix | undefined;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersPCA } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=PCA.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersPCA, ParametersMDS, ParametersSAMMON} from \"./index.js\" */\n/** @typedef {\"PCA\" | \"MDS\" | \"random\"} AvailableInit */\n/** @typedef {{ PCA: ParametersPCA; MDS: ParametersMDS; random: {} }} ChooseDR */\n/**\n * Sammon's Mapping\n *\n * A nonlinear dimensionality reduction technique that minimizes a stress\n * function based on the ratio of pairwise distances in high and low dimensional spaces.\n *\n * @class\n * @template {InputType} T\n * @extends DR>\n * @category Dimensionality Reduction\n */\nexport class SAMMON extends DR> {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial>} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial>): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial>} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial>): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial>} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial>): Promise;\n /**\n * SAMMON's Mapping\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial>} [parameters] - Object containing parameterization of the DR\n * method.\n * @see {@link https://arxiv.org/pdf/2009.01512.pdf}\n */\n constructor(X: T, parameters?: Partial>);\n /** @type {Matrix | undefined} */\n distance_matrix: Matrix | undefined;\n /**\n * Initializes the projection.\n *\n * @param {Matrix | undefined} D\n * @returns {asserts D is Matrix}\n */\n init(D: Matrix | undefined): asserts D is Matrix;\n /**\n * Transforms the inputdata `X` to dimensionality 2.\n *\n * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200`\n * @returns {T} The projection of `X`.\n */\n transform(max_iter?: number): T;\n /**\n * Transforms the inputdata `X` to dimenionality 2.\n *\n * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200`\n * @returns {Generator} A generator yielding the intermediate steps of the projection of\n * `X`.\n */\n generator(max_iter?: number): Generator;\n _step(): Matrix;\n}\nexport type AvailableInit = \"PCA\" | \"MDS\" | \"random\";\nexport type ChooseDR = {\n PCA: ParametersPCA;\n MDS: ParametersMDS;\n random: {};\n};\nimport type { InputType } from \"../index.js\";\nimport type { ParametersSAMMON } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport type { ParametersPCA } from \"./index.js\";\nimport type { ParametersMDS } from \"./index.js\";\n//# sourceMappingURL=SAMMON.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersSMACOF} from \"./index.js\" */\n/**\n * Metric Multidimensional Scaling (MDS) via SMACOF.\n *\n * SMACOF (Scaling by Majorizing a Complicated Function) is an iterative majorization\n * algorithm for solving metric multidimensional scaling problems, which aims to\n * minimize the stress function.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link MDS} for the classical approach.\n */\nexport class SMACOF extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * SMACOF for MDS.\n *\n * @param {T} X - The high-dimensional data or precomputed distance matrix.\n * @param {Partial} [parameters] - Object containing parameterization.\n */\n constructor(X: T, parameters?: Partial);\n /**\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * @returns {T}\n */\n transform(): T;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersSMACOF } from \"./index.js\";\nimport { DR } from \"./DR.js\";\n//# sourceMappingURL=SMACOF.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersSQDMDS} from \"./index.js\" */\n/**\n * SQuadMDS (Stochastic Quartet MDS)\n *\n * A lean Stochastic Quartet MDS improving global structure preservation in\n * neighbor embedding like t-SNE and UMAP.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class SQDMDS extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * SQuadMDS: a lean Stochastic Quartet MDS improving global structure preservation in neighbor embedding like t-SNE\n * and UMAP.\n *\n * @param {T} X\n * @param {Partial} [parameters]\n * @see {@link https://arxiv.org/pdf/2202.12087.pdf}\n */\n constructor(X: T, parameters?: Partial);\n init(): void;\n _add: ((...summands: Float64Array[]) => Float64Array) | undefined;\n _sub_div: ((x: Float64Array, y: Float64Array, div: number) => Float64Array) | undefined;\n _minus: ((a: Float64Array, b: Float64Array) => Float64Array) | undefined;\n _mult: ((a: Float64Array, v: number) => Float64Array) | undefined;\n _LR_init: number | undefined;\n _LR: number | undefined;\n _offset: number | undefined;\n _momentums: Matrix | undefined;\n _grads: Matrix | undefined;\n _indices: number[] | undefined;\n /** @type {(i: number, j: number, X: Matrix) => number} */\n _HD_metric: ((i: number, j: number, X: Matrix) => number) | undefined;\n /** @type {(i: number, j: number, X: Matrix) => number} */\n _HD_metric_exaggeration: ((i: number, j: number, X: Matrix) => number) | undefined;\n /**\n * Computes the projection.\n *\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {T} The projection.\n */\n transform(iterations?: number): T;\n _decay_start: number | undefined;\n /**\n * Computes the projection.\n *\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {Generator} The intermediate steps of the projection.\n */\n generator(iterations?: number): Generator;\n /**\n * Performs an optimization step.\n *\n * @private\n * @param {number} i - Acutal iteration.\n * @param {number} iterations - Number of iterations.\n */\n private _step;\n _distance_exaggeration: boolean | undefined;\n /**\n * Creates quartets of non overlapping indices.\n *\n * @private\n * @returns {Uint32Array[]}\n */\n private __quartets;\n /**\n * Computes and applies gradients, and updates momentum.\n *\n * @private\n * @param {boolean} distance_exaggeration\n */\n private _nestrov_iteration;\n /**\n * Computes the gradients.\n *\n * @param {Matrix} Y - The Projection.\n * @param {Matrix} grads - The gradients.\n * @param {boolean} [exaggeration=false] - Whether or not to use early exaggeration. Default is `false`\n * @param {boolean} [zero_grad=true] - Whether or not to reset the gradient in the beginning. Default is `true`\n * @returns {Matrix} The gradients.\n */\n _fill_MDS_grads(Y: Matrix, grads: Matrix, exaggeration?: boolean, zero_grad?: boolean): Matrix;\n /**\n * Quartet gradients for a projection.\n *\n * @private\n * @param {Matrix} Y - The acutal projection.\n * @param {number[]} quartet - The indices of the quartet.\n * @param {Float64Array} D_hd - The high-dimensional distances of the quartet.\n * @returns {Float64Array[]} The gradients for the quartet.\n */\n private _compute_quartet_grads;\n /**\n * Gradients for one element of the loss function's sum.\n *\n * @private\n * @param {Float64Array} a\n * @param {Float64Array} b\n * @param {Float64Array} c\n * @param {Float64Array} d\n * @param {number} d_ab\n * @param {number} d_ac\n * @param {number} d_ad\n * @param {number} d_bc\n * @param {number} d_bd\n * @param {number} d_cd\n * @param {number} p_ab\n * @param {number} sum_LD_dist\n * @returns {Float64Array[]}\n */\n private _ABCD_grads;\n /**\n * Inline!\n *\n * @param {number} d\n */\n __minus(d: number): (a: Float64Array, b: Float64Array) => Float64Array;\n /**\n * Inline!\n *\n * @param {number} d\n */\n __add(d: number): (...summands: Float64Array[]) => Float64Array;\n /**\n * Inline!\n *\n * @param {number} d\n */\n __mult(d: number): (a: Float64Array, v: number) => Float64Array;\n /**\n * Creates a new array `(x - y) / div`.\n *\n * @param {number} d\n */\n __sub_div(d: number): (x: Float64Array, y: Float64Array, div: number) => Float64Array;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersSQDMDS } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=SQDMDS.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersTopoMap} from \"./index.js\" */\n/**\n * TopoMap\n *\n * A 0-dimensional Homology Preserving Projection of High-Dimensional Data.\n * It aims to preserve the topological structure of the data by maintaining\n * the connectivity of a minimum spanning tree.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class TopoMap extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X: T_1, parameters: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static generator(X: T_1, parameters: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters: Partial): Promise;\n /**\n * TopoMap: A 0-dimensional Homology Preserving Projection of High-Dimensional Data.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://arxiv.org/pdf/2009.01512.pdf}\n */\n constructor(X: T, parameters: Partial);\n _distance_matrix: Matrix;\n /**\n * @private\n * @param {number} i\n * @param {number} j\n * @param {import(\"../metrics/index.js\").Metric} metric\n * @returns {number}\n */\n private __lazy_distance_matrix;\n /**\n * Computes the minimum spanning tree, using a given metric\n *\n * @private\n * @param {import(\"../metrics/index.js\").Metric} metric\n * @see {@link https://en.wikipedia.org/wiki/Kruskal%27s_algorithm}\n */\n private _make_minimum_spanning_tree;\n _disjoint_set: DisjointSet> | undefined;\n /** Initializes TopoMap. Sets all projcted points to zero, and computes a minimum spanning tree. */\n init(): this;\n _Emst: number[][] | undefined;\n /**\n * Returns true if Point C is left of line AB.\n *\n * @private\n * @param {Float64Array} PointA - Point A of line AB\n * @param {Float64Array} PointB - Point B of line AB\n * @param {Float64Array} PointC - Point C\n * @returns {boolean}\n */\n private __hull_cross;\n /**\n * Computes the convex hull of the set of Points S\n *\n * @private\n * @param {Float64Array[]} S - Set of Points.\n * @returns {Float64Array[]} Convex hull of S. Starts at the bottom-most point and continues counter-clockwise.\n * @see {@link https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain#JavaScript}\n */\n private __hull;\n /**\n * Finds the angle to rotate Point A and B to lie on a line parallel to the x-axis.\n *\n * @private\n * @param {Float64Array} PointA\n * @param {Float64Array} PointB\n * @returns {{ sin: number; cos: number }} Object containing the sinus- and cosinus-values for a rotation.\n */\n private __findAngle;\n /**\n * @private\n * @param {Float64Array[]} hull\n * @param {Float64Array} p\n * @param {boolean} topEdge\n * @returns {{ sin: number; cos: number; tx: number; ty: number }}\n */\n private __align_hull;\n /**\n * @private\n * @param {Float64Array} Point - The point which should get transformed.\n * @param {{ sin: number; cos: number; tx: number; ty: number }} Transformation - Contains the values for\n * translation and rotation.\n */\n private __transform;\n /**\n * Calls `__transform` for each point in Set C\n *\n * @private\n * @param {Float64Array[]} C - Set of points.\n * @param {{ sin: number; cos: number; tx: number; ty: number }} t - Transform object.\n * @param {number} yOffset - Value to offset set C.\n */\n private __transform_component;\n /**\n * @private\n * @param {Float64Array} root_u - Root of component u\n * @param {Float64Array} root_v - Root of component v\n * @param {Float64Array} p_u - Point u\n * @param {Float64Array} p_v - Point v\n * @param {number} w - Edge weight w\n * @param {DisjointSet} components - The disjoint set containing the components\n */\n private __align_components;\n /**\n * Transforms the inputdata `X` to dimensionality 2.\n *\n * @returns {T}\n */\n transform(): T;\n /**\n * Transforms the inputdata `X` to dimensionality 2.\n *\n * @returns {Generator}\n */\n generator(): Generator;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersTopoMap } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { DisjointSet } from \"../datastructure/index.js\";\n//# sourceMappingURL=TopoMap.d.ts.map","/**\n * Base class for all K-Nearest Neighbors (KNN) search algorithms.\n *\n * Provides a common interface for elements management and search operations.\n *\n * @abstract\n * @category KNN\n * @template {number[] | Float64Array} T - Type of elements\n * @template {Object} Para - Type of parameters\n * @class\n */\nexport class KNN {\n /**\n * @param {T[]} elements\n * @param {Para} parameters\n */\n constructor(elements: T[], parameters: Para);\n /** @type {T[]} */\n _elements: T[];\n /** @type {Para} */\n _parameters: Para;\n /** @type {\"typed\" | \"array\"} */\n _type: \"typed\" | \"array\";\n /**\n * @abstract\n * @param {T} t\n * @param {number} k\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search(t: T, k: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @abstract\n * @param {number} i\n * @param {number} k\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i: number, k: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n}\n//# sourceMappingURL=KNN.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersTriMap} from \"./index.js\" */\n/** @import {KNN} from \"../knn/KNN.js\" */\n/**\n * TriMap\n *\n * A dimensionality reduction technique that preserves both local and global\n * structure using triplets. It is designed to be a more robust alternative\n * to t-SNE and UMAP.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class TriMap extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n * @see {@link https://arxiv.org/pdf/1910.00204v1.pdf}\n * @see {@link https://github.com/eamid/trimap}\n */\n constructor(X: T, parameters?: Partial);\n /**\n * @param {Matrix | null} [pca=null] - Initial Embedding (if null then PCA gets used). Default is `null`\n * @param {import(\"../knn/KNN.js\").KNN | null} [knn=null] - KNN Object (if null then BallTree gets used). Default is `null`\n */\n init(pca?: Matrix | null, knn?: import(\"../knn/KNN.js\").KNN | null): this;\n n_inliers: number | undefined;\n n_outliers: number | undefined;\n n_random: number | undefined;\n knn: KNN, any> | undefined;\n triplets: Matrix | undefined;\n weights: Float64Array | undefined;\n lr: number | undefined;\n C: number | undefined;\n vel: Matrix | undefined;\n gain: Matrix | undefined;\n /**\n * Generates {@link n_inliers} x {@link n_outliers} x {@link n_random} triplets.\n *\n * @param {number} n_inliers\n * @param {number} n_outliers\n * @param {number} n_random\n */\n _generate_triplets(n_inliers: number, n_outliers: number, n_random: number): {\n triplets: Matrix;\n weights: Float64Array;\n };\n /**\n * Calculates the similarity matrix P\n *\n * @private\n * @param {Matrix} knn_distances - Matrix of pairwise knn distances\n * @param {Float64Array} sig - Scaling factor for the distances\n * @param {Matrix} nbrs - Nearest neighbors\n * @returns {Matrix} Pairwise similarity matrix\n */\n private _find_p;\n /**\n * Sample nearest neighbors triplets based on the similarity values given in P.\n *\n * @private\n * @param {Matrix} P - Matrix of pairwise similarities between each point and its neighbors given in matrix nbrs.\n * @param {Matrix} nbrs - Nearest neighbors indices for each point. The similarity values are given in matrix\n * {@link P}. Row i corresponds to the i-th point.\n * @param {number} n_inliers - Number of inlier points.\n * @param {number} n_outliers - Number of outlier points.\n */\n private _sample_knn_triplets;\n /**\n * Should do the same as np.argsort()\n *\n * @private\n * @param {Float64Array | number[]} A\n */\n private __argsort;\n /**\n * Samples {@link n_samples} integers from a given interval [0, {@link max_int}] while rejection the values that are\n * in the {@link rejects}.\n *\n * @private\n * @param {number} n_samples\n * @param {number} max_int\n * @param {number[]} rejects\n */\n private _rejection_sample;\n /**\n * Calculates the weights for the sampled nearest neighbors triplets\n *\n * @private\n * @param {Matrix} triplets - Sampled Triplets.\n * @param {Matrix} P - Pairwise similarity matrix.\n * @param {Matrix} nbrs - Nearest Neighbors\n * @param {Float64Array} outlier_distances - Matrix of pairwise outlier distances\n * @param {Float64Array} sig - Scaling factor for the distances.\n */\n private _find_weights;\n /**\n * Sample uniformly ranom triplets\n *\n * @private\n * @param {Matrix} X - Data matrix.\n * @param {number} n_random - Number of random triplets per point\n * @param {Float64Array} sig - Scaling factor for the distances\n */\n private _sample_random_triplets;\n /**\n * Computes the gradient for updating the embedding.\n *\n * @param {Matrix} Y - The embedding\n */\n _grad(Y: Matrix): {\n grad: Matrix;\n loss: number;\n n_viol: number;\n };\n /**\n * @param {number} max_iteration\n * @returns {T}\n */\n transform(max_iteration?: number): T;\n /**\n * @param {number} max_iteration\n * @returns {Generator}\n */\n generator(max_iteration?: number): Generator;\n /**\n * Does the iteration step.\n *\n * @private\n * @param {number} iter\n */\n private _next;\n /**\n * Updates the embedding.\n *\n * @private\n * @param {Matrix} Y\n * @param {number} iter\n * @param {Matrix} grad\n */\n private _update_embedding;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersTriMap } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport type { KNN } from \"../knn/KNN.js\";\n//# sourceMappingURL=TriMap.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersTSNE} from \"./index.js\" */\n/**\n * t-SNE (t-Distributed Stochastic Neighbor Embedding)\n *\n * A nonlinear dimensionality reduction technique particularly well-suited\n * for visualizing high-dimensional data in 2D or 3D. Preserves local\n * structure while revealing global patterns.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link https://lvdmaaten.github.io/tsne/|t-SNE Paper}\n * @see {@link UMAP} for faster alternative with similar results\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];\n * const tsne = new druid.TSNE(X, {\n * perplexity: 30,\n * epsilon: 10,\n * d: 2,\n * seed: 42\n * });\n *\n * const Y = tsne.transform(500); // 500 iterations\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class TSNE extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X: T, parameters?: Partial);\n _iter: number;\n init(): this;\n _ystep: Matrix | undefined;\n _gains: Matrix | undefined;\n _P: Matrix | undefined;\n /**\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {T} The projection.\n */\n transform(iterations?: number): T;\n /**\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {Generator} - The projection.\n */\n generator(iterations?: number): Generator;\n /**\n * Performs a optimization step\n *\n * @private\n * @returns {Matrix}\n */\n private next;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersTSNE } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=TSNE.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersUMAP} from \"./index.js\" */\n/**\n * Uniform Manifold Approximation and Projection (UMAP)\n *\n * A novel manifold learning technique for dimensionality reduction. UMAP is constructed\n * from a theoretical framework based on Riemannian geometry and algebraic topology.\n * It is often faster than t-SNE while preserving more of the global structure.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link https://arxiv.org/abs/1802.03426|UMAP Paper}\n * @see {@link TSNE} for a similar visualization technique\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];\n * const umap = new druid.UMAP(X, {\n * n_neighbors: 15,\n * min_dist: 0.1,\n * d: 2,\n * seed: 42\n * });\n *\n * const Y = umap.transform(500); // 500 iterations\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class UMAP extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X: T, parameters?: Partial);\n _iter: number;\n /**\n * @private\n * @param {number} spread\n * @param {number} min_dist\n * @returns {number[]}\n */\n private _find_ab_params;\n /**\n * @private\n * @param {{ element: Float64Array; index: number; distance: number }[][]} distances\n * @param {number[]} sigmas\n * @param {number[]} rhos\n * @returns {{ element: Float64Array; index: number; distance: number }[][]}\n */\n private _compute_membership_strengths;\n /**\n * @private\n * @param {NaiveKNN | BallTree} knn\n * @param {number} k\n * @returns {{\n * distances: { element: Float64Array; index: number; distance: number }[][];\n * sigmas: number[];\n * rhos: number[];\n * }}\n */\n private _smooth_knn_dist;\n /**\n * @private\n * @param {Matrix} X\n * @param {number} n_neighbors\n * @returns {Matrix}\n */\n private _fuzzy_simplicial_set;\n /**\n * @private\n * @param {number} n_epochs\n * @returns {Float32Array}\n */\n private _make_epochs_per_sample;\n /**\n * @private\n * @param {Matrix} graph\n * @returns {{ rows: number[]; cols: number[]; data: number[] }}\n */\n private _tocoo;\n /**\n * Computes all necessary\n *\n * @returns {UMAP}\n */\n init(): UMAP;\n _a: number | undefined;\n _b: number | undefined;\n _graph: Matrix | undefined;\n _head: number[] | undefined;\n _tail: number[] | undefined;\n _weights: number[] | undefined;\n _epochs_per_sample: Float32Array | undefined;\n _epochs_per_negative_sample: Float32Array | undefined;\n _epoch_of_next_sample: Float32Array | undefined;\n _epoch_of_next_negative_sample: Float32Array | undefined;\n graph(): {\n cols: number[] | undefined;\n rows: number[] | undefined;\n weights: number[] | undefined;\n };\n /**\n * @param {number} [iterations=350] - Number of iterations. Default is `350`\n * @returns {T}\n */\n transform(iterations?: number): T;\n /**\n * @param {number} [iterations=350] - Number of iterations. Default is `350`\n * @returns {Generator}\n */\n generator(iterations?: number): Generator;\n /**\n * @private\n * @param {number} x\n * @returns {number}\n */\n private _clip;\n /**\n * Performs the optimization step.\n *\n * @private\n * @param {Matrix} head_embedding\n * @param {Matrix} tail_embedding\n * @param {number[]} head\n * @param {number[]} tail\n * @returns {Matrix}\n */\n private _optimize_layout;\n /**\n * @private\n * @returns {Matrix}\n */\n private next;\n _alpha: number | undefined;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersUMAP } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=UMAP.d.ts.map","/**\n * Computes the inner product between two arrays of the same length.\n *\n * @category Linear Algebra\n * @param {number[] | Float64Array} a - Array a.\n * @param {number[] | Float64Array} b - Array b.\n * @returns The inner product between `a` and `b`.\n */\nexport function inner_product(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=inner_product.d.ts.map","/**\n * Computes the QR Decomposition of the Matrix `A` using Gram-Schmidt process.\n *\n * @category Linear Algebra\n * @param {Matrix} A\n * @returns {{ R: Matrix; Q: Matrix }}\n * @see {@link https://en.wikipedia.org/wiki/QR_decomposition#Using_the_Gram%E2%80%93Schmidt_process}\n */\nexport function qr(A: Matrix): {\n R: Matrix;\n Q: Matrix;\n};\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=qr.d.ts.map","/**\n * Computes the QR Decomposition of the Matrix `A` with householder transformations.\n *\n * @category Linear Algebra\n * @param {Matrix} A\n * @returns {{ R: Matrix; Q: Matrix }}\n * @see {@link https://en.wikipedia.org/wiki/QR_decomposition#Using_Householder_reflections}\n * @see {@link http://mlwiki.org/index.php/Householder_Transformation}\n */\nexport function qr_householder(A: Matrix): {\n R: Matrix;\n Q: Matrix;\n};\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=qr_householder.d.ts.map","/** @import { EigenArgs } from \"./index.js\" */\n/**\n * Computes the `k` biggest Eigenvectors and Eigenvalues from Matrix `A` with the QR-Algorithm.\n *\n * @category Linear Algebra\n * @param {Matrix} A - The Matrix\n * @param {number} k - The number of eigenvectors and eigenvalues to compute.\n * @param {EigenArgs} parameters - Object containing parameterization of the simultanious\n * poweriteration method.\n * @returns {{ eigenvalues: Float64Array; eigenvectors: Float64Array[] }} The `k` biggest eigenvectors and eigenvalues\n * of Matrix `A`.\n */\nexport function simultaneous_poweriteration(A: Matrix, k?: number, { seed, max_iterations, qr, tol }?: EigenArgs): {\n eigenvalues: Float64Array;\n eigenvectors: Float64Array[];\n};\nimport { Matrix } from \"../matrix/index.js\";\nimport type { EigenArgs } from \"./index.js\";\n//# sourceMappingURL=simultaneous_poweriteration.d.ts.map","export { inner_product } from \"./inner_product.js\";\nexport { qr } from \"./qr.js\";\nexport { qr_householder } from \"./qr_householder.js\";\nexport { simultaneous_poweriteration } from \"./simultaneous_poweriteration.js\";\nexport type QRDecomposition = (A: import(\"../matrix/index.js\").Matrix) => {\n R: import(\"../matrix/index.js\").Matrix;\n Q: import(\"../matrix/index.js\").Matrix;\n};\nexport type EigenArgs = {\n /**\n * - The number of maxiumum iterations the algorithm should run. Default is `100`\n */\n max_iterations?: number | undefined;\n /**\n * - The seed value or a randomizer used in the algorithm. Default is `1212`\n */\n seed?: number | Randomizer | undefined;\n /**\n * - The QR technique to use. Default is `qr_gramschmidt`\n */\n qr?: QRDecomposition | undefined;\n /**\n * - Tolerated error for stopping criteria. Default is `1e-8`\n */\n tol?: number | undefined;\n};\nimport type { Randomizer } from \"../util/index.js\";\n//# sourceMappingURL=index.d.ts.map","export { FASTMAP } from \"./FASTMAP.js\";\nexport { ISOMAP } from \"./ISOMAP.js\";\nexport { LDA } from \"./LDA.js\";\nexport { LLE } from \"./LLE.js\";\nexport { LSP } from \"./LSP.js\";\nexport { LTSA } from \"./LTSA.js\";\nexport { MDS } from \"./MDS.js\";\nexport { PCA } from \"./PCA.js\";\nexport { SAMMON } from \"./SAMMON.js\";\nexport { SMACOF } from \"./SMACOF.js\";\nexport { SQDMDS } from \"./SQDMDS.js\";\nexport { TopoMap } from \"./TopoMap.js\";\nexport { TriMap } from \"./TriMap.js\";\nexport { TSNE } from \"./TSNE.js\";\nexport { UMAP } from \"./UMAP.js\";\nexport type ParametersLSP = {\n /**\n * - number of neighbors to consider.\n */\n neighbors?: number | undefined;\n /**\n * - number of controlpoints\n */\n control_points?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersFASTMAP = {\n /**\n * - The dimensionality of the projection\n */\n d?: number | undefined;\n /**\n * - The metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - The seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersISOMAP = {\n /**\n * - The number of neighbors ISOMAP should use to project the data.\n */\n neighbors?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - Whether to use classical MDS or SMACOF for the final DR.\n */\n project?: \"MDS\" | \"SMACOF\" | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n /**\n * - Parameters for the eigendecomposition algorithm.\n */\n eig_args?: Partial | undefined;\n};\nexport type ParametersLDA = {\n /**\n * - The labels / classes for each data point.\n */\n labels: any[] | Float64Array;\n /**\n * - The dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - The seed for the random number generator.\n */\n seed?: number | undefined;\n /**\n * - Parameters for the eigendecomposition algorithm.\n */\n eig_args?: Partial | undefined;\n};\nexport type ParametersLLE = {\n /**\n * - The number of neighbors for LLE.\n */\n neighbors?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n /**\n * - Parameters for the eigendecomposition algorithm.\n */\n eig_args?: Partial | undefined;\n};\nexport type ParametersLTSA = {\n /**\n * - The number of neighbors for LTSA.\n */\n neighbors?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n /**\n * - Parameters for the eigendecomposition algorithm.\n */\n eig_args?: Partial | undefined;\n};\nexport type ParametersMDS = {\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | \"precomputed\" | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n /**\n * - Parameters for the eigendecomposition algorithm.\n */\n eig_args?: Partial | undefined;\n};\nexport type ParametersPCA = {\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n /**\n * - Parameters for the eigendecomposition algorithm.\n */\n eig_args?: Partial | undefined;\n};\nexport type ParametersSAMMON = {\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | \"precomputed\" | undefined;\n /**\n * - Either \"PCA\" or \"MDS\", with which SAMMON initialiates the projection.\n */\n init_DR?: K | undefined;\n /**\n * - Parameters for the \"init\"-DR method.\n */\n init_parameters?: ChooseDR[K] | undefined;\n /**\n * - learning rate for gradient descent.\n */\n magic?: number | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersSMACOF = {\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | \"precomputed\" | undefined;\n /**\n * - maximum number of iterations.\n */\n iterations?: number | undefined;\n /**\n * - tolerance for stress difference.\n */\n epsilon?: number | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersSQDMDS = {\n d?: number | undefined;\n metric?: Metric | \"precomputed\" | undefined;\n /**\n * - Percentage of iterations using exaggeration phase.\n */\n decay_start?: number | undefined;\n /**\n * - Controls the decay of the learning parameter.\n */\n decay_cte?: number | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersTopoMap = {\n /**\n * = euclidean - The metric which defines the distance between\n * two points.\n */\n metric: Metric;\n /**\n * = 1212 - The seed for the random number generator.\n */\n seed: number;\n};\nexport type ParametersTriMap = {\n /**\n * - scaling factor.\n */\n weight_adj?: number | undefined;\n /**\n * - number of inliers.\n */\n n_inliers?: number | undefined;\n /**\n * - number of outliers.\n */\n n_outliers?: number | undefined;\n /**\n * - number of random points.\n */\n n_random?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n tol?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersTSNE = {\n /**\n * - perplexity.\n */\n perplexity?: number | undefined;\n /**\n * - learning parameter.\n */\n epsilon?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | \"precomputed\" | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersUMAP = {\n /**\n * - size of the local neighborhood.\n */\n n_neighbors?: number | undefined;\n /**\n * - number of nearest neighbors connected in the local neighborhood.\n */\n local_connectivity?: number | undefined;\n /**\n * - controls how tightly points get packed together.\n */\n min_dist?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points in the high-dimensional space.\n */\n metric?: Metric | \"precomputed\" | undefined;\n /**\n * - The effective scale of embedded points.\n */\n _spread?: number | undefined;\n /**\n * - Interpolate between union and intersection.\n */\n _set_op_mix_ratio?: number | undefined;\n /**\n * - Weighting applied to negative samples.\n */\n _repulsion_strength?: number | undefined;\n /**\n * - The number of negative samples per positive sample.\n */\n _negative_sample_rate?: number | undefined;\n /**\n * - The number of training epochs.\n */\n _n_epochs?: number | undefined;\n /**\n * - The initial learning rate for the optimization.\n */\n _initial_alpha?: number | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nimport type { Metric } from \"../metrics/index.js\";\nimport type { EigenArgs } from \"../linear_algebra/index.js\";\nimport type { ChooseDR } from \"./SAMMON.js\";\n//# sourceMappingURL=index.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersAnnoy } from \"./index.js\" */\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} AnnoyNode\n * @property {boolean} isLeaf - Whether this is a leaf node\n * @property {number[]} indices - Indices of points in this node (leaf) or children (internal)\n * @property {number[]} normal - Hyperplane normal vector (internal nodes only)\n * @property {number} offset - Hyperplane offset (internal nodes only)\n * @property {AnnoyNode | null} left - Left child (internal nodes only)\n * @property {AnnoyNode | null} right - Right child (internal nodes only)\n */\n/**\n * Annoy-style (Approximate Nearest Neighbors Oh Yeah) implementation using Random Projection Trees.\n *\n * This implementation builds multiple random projection trees where each tree randomly selects\n * two points and splits the space based on a hyperplane equidistant between them.\n *\n * Key features:\n * - Multiple random projection trees for better recall\n * - Each tree uses random hyperplanes for splitting\n * - Priority queue search for better recall\n * - Combines results from all trees\n *\n * Best suited for:\n * - High-dimensional data\n * - Approximate nearest neighbor search\n * - Large datasets\n * - When high recall is needed with approximate methods\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link https://github.com/spotify/annoy}\n * @see {@link https://erikbern.com/2015/09/24/nearest-neighbors-and-vector-models-epilogue-curse-of-dimensionality.html}\n */\nexport class Annoy extends KNN {\n /**\n * Creates a new Annoy-style index with random projection trees.\n *\n * @param {T[]} elements - Elements to index\n * @param {ParametersAnnoy} [parameters={}] - Configuration parameters\n */\n constructor(elements: T[], parameters?: ParametersAnnoy);\n _metric: Metric;\n _numTrees: number;\n _maxPointsPerLeaf: number;\n _seed: number;\n _randomizer: Randomizer;\n /**\n * @private\n * @type {AnnoyNode[]}\n */\n private _trees;\n /**\n * Get the number of trees in the index.\n * @returns {number}\n */\n get num_trees(): number;\n /**\n * Get the total number of nodes in all trees.\n * @returns {number}\n */\n get num_nodes(): number;\n /**\n * @private\n * @param {any} node\n * @returns {number}\n */\n private _countNodes;\n /**\n * Add elements to the Annoy index.\n * @param {T[]} elements\n * @returns {this}\n */\n add(elements: T[]): this;\n /**\n * Build all random projection trees.\n * @private\n */\n private _buildTrees;\n /**\n * Recursively build a random projection tree.\n * @private\n * @param {number[]} indices - Indices of elements to include\n * @returns {AnnoyNode}\n */\n private _buildTreeRecursive;\n /**\n * Compute distance from point to hyperplane.\n * @private\n * @param {T} point\n * @param {number[]} normal\n * @param {number} offset\n * @returns {number} Signed distance (positive = right side, negative = left side)\n */\n private _distanceToHyperplane;\n /**\n * Search for k approximate nearest neighbors.\n * @param {T} query\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search(query: T, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * Search tree using priority queue for better recall.\n * Explores nodes in order of distance to hyperplane.\n * @private\n * @param {AnnoyNode} node\n * @param {T} query\n * @param {Set} candidates\n * @param {number} maxCandidates\n */\n private _searchTreePriority;\n /**\n * @param {number} i\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * Alias for search_by_index for backward compatibility.\n *\n * @param {number} i - Index of the query element\n * @param {number} [k=5] - Number of nearest neighbors to return\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n}\nexport type AnnoyNode = {\n /**\n * - Whether this is a leaf node\n */\n isLeaf: boolean;\n /**\n * - Indices of points in this node (leaf) or children (internal)\n */\n indices: number[];\n /**\n * - Hyperplane normal vector (internal nodes only)\n */\n normal: number[];\n /**\n * - Hyperplane offset (internal nodes only)\n */\n offset: number;\n /**\n * - Left child (internal nodes only)\n */\n left: AnnoyNode | null;\n /**\n * - Right child (internal nodes only)\n */\n right: AnnoyNode | null;\n};\nimport type { ParametersAnnoy } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport type { Metric } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\n//# sourceMappingURL=Annoy.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersBallTree } from \"./index.js\" */\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} ElementWithIndex\n * @property {number} index\n * @property {T} element\n */\n/**\n * Ball Tree for efficient nearest neighbor search.\n *\n * A Ball Tree is a metric tree that partitions points into a nested set of\n * hyperspheres (balls). It is particularly effective for high-dimensional\n * data and supports any valid metric.\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n */\nexport class BallTree extends KNN {\n /**\n * Generates a BallTree with given `elements`.\n *\n * @param {T[]} elements - Elements which should be added to the BallTree\n * @param {ParametersBallTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}`\n * @see {@link https://en.wikipedia.org/wiki/Ball_tree}\n * @see {@link https://github.com/invisal/noobjs/blob/master/src/tree/BallTree.js}\n */\n constructor(elements: T[], parameters?: ParametersBallTree);\n /**\n * @private\n * @type {BallTreeNode | BallTreeLeaf}\n */\n private _root;\n /** @returns {Metric} */\n get _metric(): Metric;\n /**\n * @private\n * @param {ElementWithIndex[]} elements\n * @returns {BallTreeNode | BallTreeLeaf} Root of balltree.\n */\n private _construct;\n /**\n * @private\n * @param {ElementWithIndex[]} B\n * @returns {number}\n */\n private _greatest_spread;\n /**\n * @param {number} i\n * @param {number} k\n */\n search_by_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @param {T} t - Query element.\n * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors.\n */\n search(t: T, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @private\n * @param {T} t - Query element.\n * @param {number} k - Number of nearest neighbors to return.\n * @param {Heap>} Q - Heap consists of the currently found `k` nearest neighbors.\n * @param {BallTreeNode | BallTreeLeaf} B\n */\n private _search;\n}\nexport type ElementWithIndex = {\n index: number;\n element: T;\n};\nimport type { ParametersBallTree } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=BallTree.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersHNSW } from \"./index.js\" */\n/**\n * @typedef {Object} Layer\n * @property {number} l_c - Layer number\n * @property {number[]} point_indices - Global indices of points in this layer\n * @property {Map} edges - Global index -> array of connected global indices\n */\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} Candidate\n * @property {T} element - The actual data point\n * @property {number} index - Global index in the dataset\n * @property {number} distance - Distance from query\n */\n/**\n * Hierarchical Navigable Small World (HNSW) graph for approximate nearest neighbor search.\n *\n * HNSW builds a multi-layer graph structure where each layer is a navigable small world graph.\n * The top layers serve as \"highways\" for fast traversal, while lower layers provide accuracy.\n * Each element is assigned to a random level, allowing logarithmic search complexity.\n *\n * Key parameters:\n * - `m`: Controls the number of connections per element (affects accuracy/memory)\n * - `ef_construction`: Controls the quality of the graph during construction (higher = better but slower)\n * - `ef`: Controls the quality of search (higher = better recall but slower)\n *\n * Based on:\n * - \"Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs\"\n * by Malkov & Yashunin (2016)\n * - \"Approximate Nearest Neighbor Search on High Dimensional Data\"\n * by Li et al. (2019)\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const points = [[1, 2], [3, 4], [5, 6], [7, 8]];\n * const hnsw = new druid.HNSW(points, {\n * metric: druid.euclidean,\n * m: 16,\n * ef_construction: 200\n * });\n *\n * const query = [2, 3];\n * const neighbors = hnsw.search(query, 2);\n * // [{ element: [1, 2], index: 0, distance: 1.41 }, ...]\n */\nexport class HNSW extends KNN {\n /**\n * Creates a new HNSW index.\n *\n * @param {T[]} points - Initial points to add to the index\n * @param {ParametersHNSW} [parameters={}] - Configuration parameters\n */\n constructor(points: T[], parameters?: ParametersHNSW);\n /** @type {Metric} */\n _metric: Metric;\n /** @type {Function} */\n _select: Function;\n /**\n * @private\n * @type {Map}\n */\n private _graph;\n /** @type {number} */\n _next_index: number;\n /** @type {number} */\n _m: number;\n /** @type {number} */\n _ef_construction: number;\n /** @type {number} */\n _ef: number;\n /** @type {number} */\n _m0: number;\n /** @type {number} */\n _mL: number;\n /** @type {Randomizer} */\n _randomizer: Randomizer;\n /** @type {number} - Current maximum layer in the graph */\n _L: number;\n /** @type {number[] | null} - Entry point indices for search */\n _ep: number[] | null;\n /**\n * Add a single element to the index.\n *\n * @param {T} element - Element to add\n * @returns {HNSW} This instance for chaining\n */\n addOne(element: T): HNSW;\n /**\n * Add multiple elements to the index.\n *\n * @param {T[]} new_elements - Elements to add\n * @returns {HNSW} This instance for chaining\n */\n add(new_elements: T[]): HNSW;\n /**\n * Select neighbors using the heuristic approach.\n *\n * The heuristic extends candidates with their neighbors and selects\n * points that are closer to the query than to already selected points.\n * This maintains graph connectivity better than simple selection.\n *\n * @private\n * @param {T} q - Query element\n * @param {Candidate[]} candidates - Candidate elements with distances\n * @param {number} M - Maximum number of neighbors to return\n * @param {number} l_c - Layer number\n * @param {boolean} [extend_candidates=true] - Whether to extend candidates with their neighbors\n * @param {boolean} [keep_pruned_connections=true] - Whether to add pruned connections back if needed\n * @returns {number[]} Selected neighbor indices\n */\n private _select_heuristic;\n /**\n * Select neighbors using simple distance-based selection.\n *\n * Simply returns the M closest candidates to the query.\n *\n * @private\n * @param {T} q - Query element\n * @param {Candidate[]} C - Candidate elements with distances\n * @param {number} M - Maximum number of neighbors to return\n * @returns {number[]} M nearest candidate indices\n */\n private _select_simple;\n /**\n * Search a single layer for nearest neighbors.\n *\n * Implements the greedy search algorithm: start from entry points,\n * always expand the closest unvisited candidate, maintain a list\n * of the ef closest found neighbors.\n *\n * @private\n * @param {T} q - Query element\n * @param {number[] | null} ep_indices - Entry point indices\n * @param {number} ef - Number of nearest neighbors to find\n * @param {number} l_c - Layer number to search\n * @returns {Candidate[]} ef nearest neighbors found with their distances\n */\n private _search_layer;\n /**\n * Fallback linear search when graph search fails\n * @private\n * @param {T} q - Query element\n * @param {number} K - Number of nearest neighbors to return\n * @returns {Candidate[]}\n */\n private _linear_search;\n /**\n * Iterator for searching the HNSW graph layer by layer.\n *\n * Yields intermediate results at each layer for debugging or visualization.\n *\n * @param {T} q - Query element\n * @param {number} K - Number of nearest neighbors to return\n * @param {number?} [ef] - Size of dynamic candidate list\n * @yields {{layer: number, candidates: Candidate[]}}\n */\n search_iter(q: T, K: number, ef?: number | null): Generator<{\n layer: number;\n candidates: {\n element: T;\n index: number;\n distance: number;\n }[];\n }, void, unknown>;\n /**\n * Get the number of elements in the index.\n *\n * @returns {number} Number of elements\n */\n get size(): number;\n /**\n * Get the number of layers in the graph.\n *\n * @returns {number} Number of layers\n */\n get num_layers(): number;\n /**\n * Get an element by its index.\n *\n * @param {number} index - Element index\n * @returns {T} The element at the given index\n */\n get_element(index: number): T;\n /**\n * Search for nearest neighbors using an element index as the query.\n *\n * @param {number} i - Index of the query element\n * @param {number} [K=5] - Number of nearest neighbors to return\n * @returns {Candidate[]} K nearest neighbors\n */\n search_by_index(i: number, K?: number): Candidate[];\n}\nexport type Layer = {\n /**\n * - Layer number\n */\n l_c: number;\n /**\n * - Global indices of points in this layer\n */\n point_indices: number[];\n /**\n * - Global index -> array of connected global indices\n */\n edges: Map;\n};\nexport type Candidate = {\n /**\n * - The actual data point\n */\n element: T;\n /**\n * - Global index in the dataset\n */\n index: number;\n /**\n * - Distance from query\n */\n distance: number;\n};\nimport type { ParametersHNSW } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport type { Metric } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\n//# sourceMappingURL=HNSW.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersKDTree } from \"./index.js\" */\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} ElementWithIndex\n * @property {number} index\n * @property {T} element\n */\n/**\n * KD-Tree (K-dimensional Tree) for efficient nearest neighbor search.\n *\n * KD-Trees partition k-dimensional space by recursively splitting along coordinate axes.\n * At each level, the tree splits points based on the median of the coordinate with the largest spread.\n * This creates a balanced binary tree structure that enables efficient O(log n) search on average.\n *\n * Best suited for:\n * - Low to moderate dimensional data (d < 20-30)\n * - When exact nearest neighbors are needed\n * - When dimensionality is not too high\n *\n * Performance degrades in high dimensions (curse of dimensionality) where approximate\n * methods like HNSW or LSH become more effective.\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link https://en.wikipedia.org/wiki/K-d_tree}\n */\nexport class KDTree extends KNN {\n /**\n * Generates a KD-Tree with given `elements`.\n *\n * @param {T[]} elements - Elements which should be added to the KD-Tree\n * @param {ParametersKDTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}`\n */\n constructor(elements: T[], parameters?: ParametersKDTree);\n /**\n * @private\n * @type {KDTreeNode | KDTreeLeaf | null}\n */\n private _root;\n /** @returns {Metric} */\n get _metric(): Metric;\n /**\n * @private\n * @param {ElementWithIndex[]} elements\n * @param {number} depth - Current depth in the tree (determines splitting axis)\n * @returns {KDTreeNode | KDTreeLeaf | null} Root of KD-Tree.\n */\n private _construct;\n /**\n * @param {number} i\n * @param {number} k\n */\n search_by_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @param {T} t - Query element.\n * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors.\n */\n search(t: T, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @private\n * @param {T} target - Query element.\n * @param {number} k - Number of nearest neighbors to return.\n * @param {KDTreeNode | KDTreeLeaf | null} node - Current node.\n * @param {Heap<{ point: ElementWithIndex; distance: number }>} best - Heap of k best found so far.\n */\n private _search_recursive;\n}\nexport type ElementWithIndex = {\n index: number;\n element: T;\n};\nimport type { ParametersKDTree } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=KDTree.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersLSH } from \"./index.js\" */\n/**\n * Locality Sensitive Hashing (LSH) for approximate nearest neighbor search.\n *\n * LSH uses hash functions that map similar items to the same buckets with high probability.\n * This implementation uses Random Projection hashing (SimHash-style) which works well for\n * cosine similarity and Euclidean distance.\n *\n * Key concepts:\n * - Multiple hash tables increase recall probability\n * - Each hash function projects data onto random hyperplanes\n * - Points on the same side of hyperplanes are hashed together\n * - Combines results from all tables for better accuracy\n *\n * Best suited for:\n * - High-dimensional data where exact methods fail\n * - Approximate nearest neighbor needs\n * - Large datasets where linear scan is too slow\n * - When some false positives/negatives are acceptable\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link https://en.wikipedia.org/wiki/Locality-sensitive_hashing}\n */\nexport class LSH extends KNN {\n /**\n * Creates a new LSH index.\n *\n * @param {T[]} elements - Elements to index\n * @param {ParametersLSH} [parameters={}] - Configuration parameters\n */\n constructor(elements: T[], parameters?: ParametersLSH);\n _metric: Metric;\n _numHashTables: number;\n _numHashFunctions: number;\n _seed: number;\n _randomizer: Randomizer;\n /** @type {Map[]} */\n _hashTables: Map[];\n /** @type {Float64Array[][]} */\n _projections: Float64Array[][];\n /** @type {number[][]} */\n _offsets: number[][];\n /** @type {number} */\n _dim: number;\n /**\n * Initialize random projection vectors for all hash tables.\n * @private\n */\n private _initializeHashFunctions;\n /**\n * Compute hash signature for an element using random projections.\n * @private\n * @param {T} element\n * @param {number} tableIndex\n * @returns {string} Hash signature\n */\n private _computeHash;\n /**\n * Add elements to the LSH index.\n * @param {T[]} elements\n * @returns {this}\n */\n add(elements: T[]): this;\n /**\n * Search for k approximate nearest neighbors.\n * @param {T} query\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search(query: T, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @param {number} i\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n}\nimport type { ParametersLSH } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport type { Metric } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\n//# sourceMappingURL=LSH.d.ts.map","/** @import { ParametersNaiveKNN } from \"./index.js\" */\n/**\n * Naive KNN implementation using a distance matrix.\n *\n * This implementation pre-computes the entire distance matrix and performs\n * an exhaustive search. Best suited for small datasets or when a distance\n * matrix is already available.\n *\n * @template {number[] | Float64Array} T\n * @category KNN\n * @class\n * @extends KNN\n */\nexport class NaiveKNN extends KNN {\n /**\n * Generates a KNN list with given `elements`.\n *\n * @param {T[]} elements - Elements which should be added to the KNN list\n * @param {ParametersNaiveKNN} parameters\n */\n constructor(elements: T[], parameters?: ParametersNaiveKNN);\n _D: Matrix;\n /** @type {Heap<{ value: number; index: number }>[]} */\n KNN: Heap<{\n value: number;\n index: number;\n }>[];\n /**\n * @param {number} i\n * @param {number} k\n */\n search_by_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @param {T} t - Query element.\n * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors.\n */\n search(t: T, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n}\nimport type { ParametersNaiveKNN } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { Heap } from \"../datastructure/index.js\";\n//# sourceMappingURL=NaiveKNN.d.ts.map","/** @import {ParametersNNDescent} from \"./index.js\" */\n/**\n *\n * @template {number[] | Float64Array} T\n * @typedef {Object} NNDescentElement\n * @property {T} value\n * @property {number} index\n * @property {boolean} flag\n */\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} NNDescentNeighbor\n * @property {T} value\n * @property {number} index\n * @property {number} distance\n * @property {boolean} [flag]\n */\n/**\n * NN-Descent\n *\n * An efficient graph-based approximate nearest neighbor search algorithm.\n * It works by iteratively improving a neighbor graph using the fact that\n * \"neighbors of neighbors are likely to be neighbors\".\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf|NN-Descent Paper}\n */\nexport class NNDescent extends KNN {\n /**\n * @param {T[]} elements - Called V in paper.\n * @param {Partial} parameters\n * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf}\n */\n constructor(elements: T[], parameters?: Partial);\n /**\n * @private\n * @type {KNNHeap[]}\n */\n private _B;\n /**\n * @private\n * @type {NNDescentNeighbor[][]}\n */\n private nn;\n _N: number;\n _randomizer: Randomizer;\n _sample_size: number;\n _nndescent_elements: {\n value: T;\n index: number;\n flag: boolean;\n }[];\n /**\n * Samples Array A with sample size.\n *\n * @private\n * @template U\n * @param {U[]} A\n * @returns {U[]}\n */\n private _sample;\n /**\n * @private\n * @param {KNNHeap} B\n * @param {NNDescentNeighbor} u\n * @returns {number}\n */\n private _update;\n /**\n * @private\n * @param {(KNNHeap | null)[]} B\n * @returns {NNDescentNeighbor[][]}\n */\n private _reverse;\n /**\n * @param {T[]} elements\n * @returns {this}\n */\n add(elements: T[]): this;\n /**\n * @param {T} x\n * @param {number} [k=5] Default is `5`\n * @returns {{ element: T, index: number; distance: number }[]}\n */\n search(x: T, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @param {number} i\n * @param {number} [k=5] Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n}\nexport type NNDescentElement = {\n value: T;\n index: number;\n flag: boolean;\n};\nexport type NNDescentNeighbor = {\n value: T;\n index: number;\n distance: number;\n flag?: boolean | undefined;\n};\nexport type HeapEntry = {\n element: NNDescentNeighbor;\n value: number;\n};\nimport type { ParametersNNDescent } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport { Randomizer } from \"../util/index.js\";\n//# sourceMappingURL=NNDescent.d.ts.map","export { Annoy } from \"./Annoy.js\";\nexport { BallTree } from \"./BallTree.js\";\nexport { HNSW } from \"./HNSW.js\";\nexport { KDTree } from \"./KDTree.js\";\nexport { LSH } from \"./LSH.js\";\nexport { NaiveKNN } from \"./NaiveKNN.js\";\nexport { NNDescent } from \"./NNDescent.js\";\nexport type ParametersAnnoy = {\n /**\n * - Metric to use: (a, b) => distance. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Number of random projection trees to build. Default is `10`\n */\n numTrees: number;\n /**\n * - Maximum points per leaf node. Default is `10`\n */\n maxPointsPerLeaf: number;\n /**\n * - Seed for random number generator. Default is `1212`\n */\n seed: number;\n};\nexport type ParametersBallTree = {\n metric: Metric;\n seed: number;\n};\nexport type ParametersHNSW = {\n /**\n * - Metric to use: (a, b) => distance. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Use heuristics or naive selection. Default is `true`\n */\n heuristic: boolean;\n /**\n * - Max number of connections per element (excluding ground layer). Default is `16`\n */\n m: number;\n /**\n * - Size of candidate list during construction. Default is `200`\n */\n ef_construction: number;\n /**\n * - Max number of connections for ground layer (layer 0). Default is `2 * m`\n */\n m0: number | null;\n /**\n * - Normalization factor for level generation. Default is `1 / Math.log(m)`\n */\n mL: number | null;\n /**\n * - Seed for random number generator. Default is `1212`\n */\n seed: number;\n /**\n * - Size of candidate list during search. Default is `50`\n */\n ef: number;\n};\nexport type ParametersKDTree = {\n /**\n * - Metric to use: (a, b) => distance. Default is `euclidean`\n */\n metric: Metric;\n seed: number;\n};\nexport type ParametersLSH = {\n /**\n * - Metric to use: (a, b) => distance. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Number of hash tables. Default is `10`\n */\n numHashTables: number;\n /**\n * - Number of hash functions per table. Default is `10`\n */\n numHashFunctions: number;\n /**\n * - Seed for random number generator. Default is `1212`\n */\n seed: number;\n};\nexport type ParametersNaiveKNN = {\n /**\n * Is either precomputed or a function to use: (a, b) => distance\n */\n metric?: Metric | \"precomputed\" | undefined;\n seed?: number | undefined;\n};\nexport type ParametersNNDescent = {\n /**\n * - Called sigma in paper. Default is `euclidean`\n */\n metric: Metric;\n /**\n * =10 - Number of samples. Default is `10`\n */\n samples: number;\n /**\n * = .8 - Sample rate. Default is `.8`\n */\n rho: number;\n /**\n * = 0.0001 - Precision parameter. Default is `0.0001`\n */\n delta: number;\n /**\n * = 1212 - Seed for the random number generator. Default is `1212`\n */\n seed: number;\n};\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=index.d.ts.map","/**\n * Numerical stable summation with the Kahan summation algorithm.\n *\n * @category Numerical\n * @param {number[] | Float64Array} summands - Array of values to sum up.\n * @returns {number} The sum.\n * @see {@link https://en.wikipedia.org/wiki/Kahan_summation_algorithm}\n */\nexport function kahan_sum(summands: number[] | Float64Array): number;\n//# sourceMappingURL=kahan_sum.d.ts.map","/**\n * Numerical stable summation with the Neumair summation algorithm.\n *\n * @category Numerical\n * @param {number[] | Float64Array} summands - Array of values to sum up.\n * @returns {number} The sum.\n * @see {@link https://en.wikipedia.org/wiki/Kahan_summation_algorithm#Further_enhancements}\n */\nexport function neumair_sum(summands: number[] | Float64Array): number;\n//# sourceMappingURL=neumair_sum.d.ts.map","/**\n * @template {Float64Array | number[]} T\n * @category Optimization\n * @param {(d: T) => number} f\n * @param {T} x0\n * @param {number} [max_iter=300] Default is `300`\n * @returns {T}\n * @see http://optimization-js.github.io/optimization-js/optimization.js.html#line438\n */\nexport function powell(f: (d: T) => number, x0: T, max_iter?: number): T;\n//# sourceMappingURL=powell.d.ts.map","export * from \"./clustering/index.js\";\nexport * from \"./datastructure/index.js\";\nexport * from \"./dimred/index.js\";\nexport * from \"./knn/index.js\";\nexport * from \"./linear_algebra/index.js\";\nexport * from \"./matrix/index.js\";\nexport * from \"./metrics/index.js\";\nexport * from \"./numerical/index.js\";\nexport * from \"./optimization/index.js\";\nexport * from \"./util/index.js\";\nexport type InputType = Matrix | Float64Array[] | number[][];\nexport const version: string;\nimport type { Matrix } from \"./matrix/index.js\";\n//# sourceMappingURL=index.d.ts.map"],"names":["___knn_KNN_js.KNN","___matrix_index_js.Matrix"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,WAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,QAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,SAAA,eAAA,YAAA,gBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,MAAA,eAAA,YAAA,gBAAA,YAAA;;ACbP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,SAAA,eAAA,YAAA,gBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACO,iBAAA,iBAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,eAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,OAAA,eAAA,YAAA,gBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,SAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,OAAA,eAAA,YAAA,gBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,SAAA,eAAA,YAAA,gBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACO,iBAAA,cAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,WAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,IAAA,eAAA,YAAA,gBAAA,YAAA;;ACMA,KAAA,MAAA,kBAAA,YAAA,gBAAA,YAAA;;ACdP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,eAAA,IAAA,MAAA,GAAA,YAAA,0BAAA,MAAA,GAAA,MAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,mBAAA,IAAA,MAAA,sBAAA,MAAA;AACP;AACA;AACA;AACA;;ACdA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,QAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,GAAA,SAAA,QAAA;;ACPP;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,GAAA,SAAA,QAAA;;ACPP;AACA;AACA;AACA;AACO,cAAA,UAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7DA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAA,MAAA,GAAA,YAAA,kBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,YAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qCAAA,YAAA,wBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAA,MAAA,KAAA,MAAA,eAAA,UAAA,wBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAA,MAAA;AACA,WAAA,MAAA;AACA,WAAA,MAAA;AACA,UAAA,MAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,MAAA;AACA,WAAA,MAAA;AACA,WAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,MAAA;AACA,WAAA,YAAA;AACA,eAAA,YAAA;AACA,WAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,4DAAA,YAAA,GAAA,YAAA;AACA;AACA;AACA;AACA;AACA,kDAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oDAAA,QAAA;AACA;AACA;AACA,uCAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAA,SAAA,CAAA,YAAA,CAAA,eAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2CAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wDAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wDAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wDAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAA,MAAA,cAAA,YAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAA,MAAA,cAAA,YAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAA,MAAA,cAAA,YAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAA,MAAA,8CAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yDAAA,MAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uGAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0DAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,YAAA,wCAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,YAAA,wCAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,MAAA,cAAA,YAAA,iDAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAA,MAAA,GAAA,YAAA;AACA;AACA,QAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,MAAA,GAAA,YAAA;AACA;AACA,QAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,MAAA,GAAA,YAAA;AACA;AACA,QAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,MAAA,GAAA,YAAA;AACA;AACA,QAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oDAAA,QAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,KAAA,MAAA,CAAA,QAAA,KAAA,SAAA,CAAA,YAAA,CAAA,eAAA;AACA;AACO,KAAA,QAAA;;ACjdP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,IAAA,IAAA,MAAA,cAAA,YAAA,WAAA,MAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,SAAA,eAAA,YAAA,WAAA,MAAA,cAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACO,cAAA,UAAA;AACP;AACA;AACA;AACA;AACA;AACA,wBAAA,SAAA;AACA;AACA,aAAA,SAAA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,IAAA,SAAA,UAAA,CAAA,cAAA;AACP;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,sBAAA,SAAA,UAAA,CAAA,gCAAA;AACP;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,gCAAA;AACA;AACA,UAAA,OAAA;AACA;AACA,YAAA,YAAA,CAAA,WAAA;AACA,sBAAA,MAAA;AACA;AACA,aAAA,WAAA,CAAA,WAAA;AACA;AACA;AACA;AACA;AACA;AACA,kEAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA;AACA,cAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,OAAA,gBAAA,OAAA,iCAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,OAAA;AACA;AACA,UAAA,OAAA;AACA,WAAA,OAAA;AACA;AACA;AACA,cAAA,YAAA,CAAA,eAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8BAAA,OAAA,SAAA,OAAA,GAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,cAAA,OAAA;AACA;AACA;AACA;AACA;AACA,mBAAA,OAAA;AACA;;AClGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,SAAA,UAAA,CAAA,gBAAA;AACP;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,gBAAA;AACA;AACA,iBAAA,UAAA;AACA;AACA;AACA,wBAAA,YAAA,CAAA,eAAA;AACA;AACA;AACA;AACA,qBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,QAAA,SAAA,UAAA,CAAA,kBAAA;AACP;AACA;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,kBAAA;AACA,QAAA,YAAA,CAAA,eAAA;AACA;AACA,sBAAA,MAAA;AACA,iBAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8CAAA,YAAA,eAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,SAAA,SAAA,UAAA,CAAA,mBAAA;AACP;AACA;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,mBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,SAAA,UAAA,CAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,SAAA,UAAA,CAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,gBAAA;AACA,iBAAA,UAAA;AACA;AACA,kBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7FO,KAAA,gCAAA;AACP;AACA,YAAA,MAAA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAA,YAAA,CAAA,eAAA;AACA;AACO,KAAA,kBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,mBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;;ACnIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,WAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAA,GAAA;AACA;;AC1CA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,IAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oGAAA,UAAA,GAAA,IAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6GAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAA,IAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvHO,KAAA,UAAA;;ACFP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,EAAA,WAAA,SAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAA,SAAA,2CAAA,SAAA,CAAA,SAAA,EAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAA,SAAA,2CAAA,OAAA,CAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6DAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAA,MAAA;AACA;AACA,OAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,EAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yCAAA,OAAA;AACA;;AC5IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,OAAA,WAAA,SAAA,UAAA,EAAA,IAAA,iBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,iBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,iBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,sBAAA,OAAA,CAAA,iBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,OAAA,CAAA,iBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;;AC3DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,WAAA,SAAA,UAAA,EAAA,IAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,gBAAA;AACA,cAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;;ACzDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,WAAA,SAAA,UAAA,EAAA,IAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA;AACA;AACA,kCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA;AACA;AACA,kCAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,OAAA,CAAA,aAAA;AACA,wBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,WAAA,SAAA,UAAA,EAAA,IAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,aAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,sBAAA,OAAA,CAAA,aAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,WAAA,SAAA,UAAA,EAAA,IAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA,YAAA,GAAA;AACA,QAAA,MAAA;AACA,QAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,IAAA,WAAA,SAAA,UAAA,EAAA,IAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,cAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,sBAAA,OAAA,CAAA,cAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,WAAA,SAAA,UAAA,EAAA,IAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAA,MAAA;AACA;AACA;AACA;;AC5DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,WAAA,SAAA,UAAA,EAAA,IAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,SAAA,sBAAA,OAAA,CAAA,aAAA,IAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAAA,MAAA;AACA,OAAA,MAAA;AACA;;AC5EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,WAAA,SAAA,UAAA,EAAA,IAAA,gBAAA,CAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,CAAA,aAAA,KAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,CAAA,aAAA,KAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,gBAAA,CAAA,aAAA;AACA;AACA,qBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA,4BAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,SAAA;AACA,aAAA,MAAA;AACA;AACO,KAAA,aAAA;AACA,KAAA,QAAA;AACP,SAAA,aAAA;AACA,SAAA,aAAA;AACA;AACA;;AC7EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,WAAA,SAAA,UAAA,EAAA,IAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;;ACpDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,WAAA,SAAA,UAAA,EAAA,IAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,gBAAA;AACA;AACA,yBAAA,YAAA,CAAA,eAAA,QAAA,YAAA;AACA,mBAAA,YAAA,CAAA,eAAA,MAAA,YAAA,CAAA,eAAA,mBAAA,YAAA;AACA,iBAAA,YAAA,CAAA,eAAA,MAAA,YAAA,CAAA,eAAA,MAAA,YAAA;AACA,gBAAA,YAAA,CAAA,eAAA,iBAAA,YAAA;AACA;AACA;AACA;AACA,gBAAA,MAAA;AACA,YAAA,MAAA;AACA;AACA;AACA,2CAAA,MAAA;AACA;AACA,wDAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAA,MAAA,SAAA,MAAA,gDAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAAA,YAAA,CAAA,eAAA,MAAA,YAAA,CAAA,eAAA,MAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAA,YAAA,CAAA,eAAA,QAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,2BAAA,YAAA,CAAA,eAAA,iBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,8BAAA,YAAA,CAAA,eAAA,MAAA,YAAA,CAAA,eAAA,mBAAA,YAAA;AACA;;ACjKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,OAAA,WAAA,SAAA,UAAA,EAAA,IAAA,iBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,iBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,iBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,sBAAA,OAAA,CAAA,iBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,OAAA,CAAA,iBAAA;AACA,sBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAA,WAAA,CAAA,YAAA,CAAA,eAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;;AC3IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,sBAAA,YAAA,eAAA,MAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,WAAA,SAAA,UAAA,EAAA,IAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA,eAAA,MAAA,eAAoCA,GAAuB,YAAA,YAAA;AAC3D;AACA;AACA;AACA,SAAA,GAAA,YAAA,YAAA,CAAA,eAAA;AACA,cAAA,MAAA;AACA,aAAA,YAAA,CAAA,WAAA;AACA;AACA;AACA,SAAA,MAAA;AACA,UAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,MAAA;AACA,iBAAA,YAAA,CAAA,WAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA,cAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,IAAA,WAAA,SAAA,UAAA,EAAA,IAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,cAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,cAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA,YAAA,MAAA;AACA,YAAA,MAAA;AACA,QAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,IAAA,WAAA,SAAA,UAAA,EAAA,IAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,cAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,cAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,IAAA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA,wBAAA,YAAA,CAAA,eAAA;AACA,iCAAA,YAAA,CAAA,WAAA;AACA,2BAAA,YAAA,CAAA,WAAA;AACA,oCAAA,YAAA,CAAA,WAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,aAAA,eAAA,YAAA,gBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,EAAA,IAAA,MAAA;AACP,OAAA,MAAA;AACA,OAAA,MAAA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,cAAA,IAAA,MAAA;AACP,OAAA,MAAA;AACA,OAAA,MAAA;AACA;;ACZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,2BAAA,IAAA,MAAA,kDAAA,SAAA;AACP,iBAAA,YAAA;AACA,kBAAA,YAAA;AACA;;ACXO,KAAA,eAAA,OAA2BC,MAA4B;AAC9D,OAAOA,MAA4B;AACnC,OAAOA,MAA4B;AACnC;AACO,KAAA,SAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAA,UAAA;AACA;AACA;AACA;AACA,SAAA,eAAA;AACA;AACA;AACA;AACA;AACA;;ACVO,KAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,iBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,OAAA,CAAA,SAAA;AACA;AACO,KAAA,aAAA;AACP;AACA;AACA;AACA,oBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,OAAA,CAAA,SAAA;AACA;AACO,KAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,OAAA,CAAA,SAAA;AACA;AACO,KAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,OAAA,CAAA,SAAA;AACA;AACO,KAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,OAAA,CAAA,SAAA;AACA;AACO,KAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,OAAA,CAAA,SAAA;AACA;AACO,KAAA,gBAAA,iBAAA,QAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAA,QAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,gBAAA;AACP;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,iBAAA;AACP;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5VA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,KAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,eAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,eAAA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA,iBAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,QAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,kBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,kBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,IAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,0CAAA,cAAA;AACA;AACA,aAAA,MAAA;AACA;AACA,aAAA,QAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAA,IAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAAA,IAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sDAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,SAAA;AACA;AAeO,KAAA,SAAA,sBAAA,YAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,aAAA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA,iBAAA,UAAA;AACA;AACA,iBAAA,GAAA;AACA;AACA,kBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,QAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,kBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,kBAAA;AACA,QAAA,MAAA;AACA;AACA,SAAA,IAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,SAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,mBAAA;AACP;AACA;AACA;AACA;AACA;AACA,4CAAA,OAAA,CAAA,mBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/FO,KAAA,eAAA;AACP;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,kBAAA;AACP,YAAA,MAAA;AACA;AACA;AACO,KAAA,cAAA;AACP;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACO,KAAA,aAAA;AACP;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,kBAAA;AACP;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACO,KAAA,mBAAA;AACP;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,SAAA,sBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,WAAA,sBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,MAAA,WAAA,YAAA;;ACCA,KAAA,SAAA,GAAA,MAAA,GAAA,YAAA;AACA,cAAA,OAAA;;;;"} \ No newline at end of file +{"version":3,"file":"druid.d.ts","sources":["types/metrics/bray_curtis.d.ts","types/metrics/canberra.d.ts","types/metrics/chebyshev.d.ts","types/metrics/cosine.d.ts","types/metrics/euclidean.d.ts","types/metrics/euclidean_squared.d.ts","types/metrics/goodman_kruskal.d.ts","types/metrics/hamming.d.ts","types/metrics/haversine.d.ts","types/metrics/jaccard.d.ts","types/metrics/manhattan.d.ts","types/metrics/sokal_michener.d.ts","types/metrics/wasserstein.d.ts","types/metrics/yule.d.ts","types/metrics/index.d.ts","types/matrix/distance_matrix.d.ts","types/matrix/k_nearest_neighbors.d.ts","types/matrix/linspace.d.ts","types/util/max.d.ts","types/util/min.d.ts","types/util/randomizer.d.ts","types/matrix/Matrix.d.ts","types/matrix/norm.d.ts","types/matrix/normalize.d.ts","types/clustering/Clustering.d.ts","types/clustering/CURE.d.ts","types/clustering/Hierarchical_Clustering.d.ts","types/clustering/KMeans.d.ts","types/clustering/KMedoids.d.ts","types/clustering/MeanShift.d.ts","types/clustering/OPTICS.d.ts","types/clustering/XMeans.d.ts","types/clustering/index.d.ts","types/datastructure/DisjointSet.d.ts","types/datastructure/Heap.d.ts","types/datastructure/index.d.ts","types/dimred/DR.d.ts","types/dimred/FASTMAP.d.ts","types/dimred/PaCMAP.d.ts","types/dimred/LocalMAP.d.ts","types/dimred/ISOMAP.d.ts","types/dimred/LDA.d.ts","types/dimred/LLE.d.ts","types/dimred/LSP.d.ts","types/dimred/LTSA.d.ts","types/dimred/MDS.d.ts","types/dimred/PCA.d.ts","types/dimred/SAMMON.d.ts","types/dimred/SMACOF.d.ts","types/dimred/SQDMDS.d.ts","types/dimred/TopoMap.d.ts","types/knn/KNN.d.ts","types/dimred/TriMap.d.ts","types/dimred/TSNE.d.ts","types/dimred/UMAP.d.ts","types/linear_algebra/inner_product.d.ts","types/linear_algebra/qr.d.ts","types/linear_algebra/qr_householder.d.ts","types/linear_algebra/simultaneous_poweriteration.d.ts","types/linear_algebra/index.d.ts","types/dimred/index.d.ts","types/knn/Annoy.d.ts","types/knn/BallTree.d.ts","types/knn/HNSW.d.ts","types/knn/KDTree.d.ts","types/knn/LSH.d.ts","types/knn/NaiveKNN.d.ts","types/knn/NNDescent.d.ts","types/knn/index.d.ts","types/numerical/kahan_sum.d.ts","types/numerical/neumair_sum.d.ts","types/optimization/powell.d.ts","types/index.d.ts"],"sourcesContent":["/**\n * Computes the Bray-Curtis distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The Bray-Curtis distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Bray%E2%80%93Curtis_dissimilarity}\n */\nexport function bray_curtis(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=bray_curtis.d.ts.map","/**\n * Computes the canberra distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The canberra distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Canberra_distance}\n */\nexport function canberra(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=canberra.d.ts.map","/**\n * Computes the chebyshev distance (L) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The chebyshev distance between `a` and `b`.\n */\nexport function chebyshev(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=chebyshev.d.ts.map","/**\n * Computes the cosine distance (not similarity) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The cosine distance between `a` and `b`.\n * @example\n * import { cosine } from \"@saehrimnir/druidjs\";\n * const a = [1, 2, 3];\n * const b = [4, 5, 6];\n * const distance = cosine(a, b); // 0.9746318461970762\n */\nexport function cosine(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=cosine.d.ts.map","/**\n * Computes the euclidean distance (`l_2`) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The euclidean distance between `a` and `b`.\n */\nexport function euclidean(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=euclidean.d.ts.map","/**\n * Computes the squared euclidean distance (l_2^2) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The squared euclidean distance between `a` and `b`.\n\n */\nexport function euclidean_squared(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=euclidean_squared.d.ts.map","/**\n * Computes the Goodman-Kruskal gamma coefficient for ordinal association.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a - First categorical/ordinal variable\n * @param {number[] | Float64Array} b - Second categorical/ordinal variable\n * @returns {number} The Goodman-Kruskal gamma coefficient between `a` and `b` (-1 to 1).\n * @see {@link https://en.wikipedia.org/wiki/Goodman_and_Kruskal%27s_gamma}\n */\nexport function goodman_kruskal(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=goodman_kruskal.d.ts.map","/**\n * Computes the hamming distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The hamming distance between `a` and `b`.\n */\nexport function hamming(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=hamming.d.ts.map","/**\n * Computes the Haversine distance between two points on a sphere of unit length 1. Multiply the result with the radius of the sphere. (For instance Earth's radius is 6371km)\n *\n * @category Metrics\n * @param {number[] | Float64Array} a - Point [lat1, lon1] in radians\n * @param {number[] | Float64Array} b - Point [lat2, lon2] in radians\n * @returns {number} The Haversine distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Haversine_formula}\n */\nexport function haversine(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=haversine.d.ts.map","/**\n * Computes the jaccard distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The jaccard distance between `a` and `b`.\n */\nexport function jaccard(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=jaccard.d.ts.map","/**\n * Computes the manhattan distance (`l_1`) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The manhattan distance between `a` and `b`.\n */\nexport function manhattan(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=manhattan.d.ts.map","/**\n * Computes the Sokal-Michener distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The Sokal-Michener distance between `a` and `b`.\n\n */\nexport function sokal_michener(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=sokal_michener.d.ts.map","/**\n * Computes the 1D Wasserstein distance (Earth Mover's Distance) between two distributions.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a - First distribution (histogram or probability mass)\n * @param {number[] | Float64Array} b - Second distribution (histogram or probability mass)\n * @returns {number} The Wasserstein/EMD distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Wasserstein_metric}\n */\nexport function wasserstein(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=wasserstein.d.ts.map","/**\n * Computes the yule distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The yule distance between `a` and `b`.\n */\nexport function yule(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=yule.d.ts.map","export { bray_curtis } from \"./bray_curtis.js\";\nexport { canberra } from \"./canberra.js\";\nexport { chebyshev } from \"./chebyshev.js\";\nexport { cosine } from \"./cosine.js\";\nexport { euclidean } from \"./euclidean.js\";\nexport { euclidean_squared } from \"./euclidean_squared.js\";\nexport { goodman_kruskal } from \"./goodman_kruskal.js\";\nexport { hamming } from \"./hamming.js\";\nexport { haversine } from \"./haversine.js\";\nexport { jaccard } from \"./jaccard.js\";\nexport { manhattan } from \"./manhattan.js\";\nexport { sokal_michener } from \"./sokal_michener.js\";\nexport { wasserstein } from \"./wasserstein.js\";\nexport { yule } from \"./yule.js\";\nexport type Metric = (a: number[] | Float64Array, b: number[] | Float64Array) => number;\n//# sourceMappingURL=index.d.ts.map","/**\n * Computes the distance matrix of datamatrix `A`.\n *\n * @category Matrix\n * @param {Matrix | Float64Array[] | number[][]} A - Matrix.\n * @param {Metric} [metric=euclidean] - The diistance metric. Default is `euclidean`\n * @returns {Matrix} The distance matrix of `A`.\n */\nexport function distance_matrix(A: Matrix | Float64Array[] | number[][], metric?: Metric): Matrix;\nimport { Matrix } from \"./index.js\";\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=distance_matrix.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/**\n * Computes the k-nearest neighbors of each row of `A`.\n *\n * @category Matrix\n * @param {Matrix} A - Either the data matrix, or a distance matrix.\n * @param {number} k - The number of neighbors to compute.\n * @param {Metric | \"precomputed\"} [metric=euclidean] Default is `euclidean`\n * @returns {{ i: number; j: number; distance: number }[][]} The kNN graph.\n */\nexport function k_nearest_neighbors(A: Matrix, k: number, metric?: Metric | \"precomputed\"): {\n i: number;\n j: number;\n distance: number;\n}[][];\nimport { Matrix } from \"../matrix/index.js\";\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=k_nearest_neighbors.d.ts.map","/**\n * Creates an Array containing `number` numbers from `start` to `end`. If `number = null`.\n *\n * @category Matrix\n * @param {number} start - Start value.\n * @param {number} end - End value.\n * @param {number} [number] - Number of number between `start` and `end`.\n * @returns {number[]} An array with `number` entries, beginning at `start` ending at `end`.\n */\nexport function linspace(start: number, end: number, number?: number): number[];\n//# sourceMappingURL=linspace.d.ts.map","/**\n * Returns maximum in Array `values`.\n *\n * @category Utils\n * @param {Iterable} values\n * @returns {number}\n */\nexport function max(values: Iterable): number;\n//# sourceMappingURL=max.d.ts.map","/**\n * Returns maximum in Array `values`.\n *\n * @category Utils\n * @param {Iterable} values\n * @returns {number}\n */\nexport function min(values: Iterable): number;\n//# sourceMappingURL=min.d.ts.map","/**\n * @category Utils\n * @class\n */\nexport class Randomizer {\n /**\n * @template T Returns samples from an input Matrix or Array.\n * @param {T[]} A - The input Matrix or Array.\n * @param {number} n - The number of samples.\n * @param {number} seed - The seed for the random number generator.\n * @returns {T[]} - A random selection form `A` of `n` samples.\n */\n static choice(A: T[], n: number, seed?: number): T[];\n /**\n * Mersenne Twister random number generator.\n *\n * @param {number} [_seed=new Date().getTime()] - The seed for the random number generator. If `_seed == null` then\n * the actual time gets used as seed. Default is `new Date().getTime()`\n * @see https://github.com/bmurray7/mersenne-twister-examples/blob/master/javascript-mersenne-twister.js\n */\n constructor(_seed?: number);\n _N: number;\n _M: number;\n _MATRIX_A: number;\n _UPPER_MASK: number;\n _LOWER_MASK: number;\n /** @type {number[]} */\n _mt: number[];\n /** @type {number} */\n _mti: number;\n /** @type {number} */\n _seed: number;\n /** @type {number} seed */\n set seed(_seed: number);\n /**\n * Returns the seed of the random number generator.\n *\n * @returns {number} - The seed.\n */\n get seed(): number;\n /**\n * Returns a float between 0 and 1.\n *\n * @returns {number} - A random number between [0, 1]\n */\n get random(): number;\n /**\n * Returns an integer between 0 and MAX_INTEGER.\n *\n * @returns {number} - A random integer.\n */\n get random_int(): number;\n gauss_random(): number;\n _val: number | null | undefined;\n /**\n * @template T Returns samples from an input Matrix or Array.\n * @param {T[]} A - The input Matrix or Array.\n * @param {number} n - The number of samples.\n * @returns {T[]} A random selection form `A` of `n` samples.\n */\n choice(A: T[], n: number): T[];\n}\n//# sourceMappingURL=randomizer.d.ts.map","/** @typedef {(i: number, j: number) => number} Accessor */\n/**\n * @class\n * @category Matrix\n */\nexport class Matrix {\n /**\n * Creates a Matrix out of `A`.\n * @param {Matrix | Float64Array[] | number[][]} A - The matrix, array, or number, which should converted to a Matrix.\n * @returns {Matrix}\n * @example\n * let A = Matrix.from([ [1, 0], [0, 1], ]); //creates a two by two identity matrix.\n */\n static from(A: Matrix | Float64Array[] | number[][]): Matrix;\n /**\n * Creates a Matrix with the diagonal being the values of `v`.\n *\n * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]]\n *\n * @param {number[] | Float64Array} v\n * @returns {Matrix}\n */\n static from_diag(v: number[] | Float64Array): Matrix;\n /**\n * Creates a Matrix with the diagonal being the values of `v`.\n *\n * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]]\n *\n * @param {number[] | Float64Array} v\n * @param {\"col\" | \"row\"} type\n * @returns {Matrix}\n */\n static from_vector(v: number[] | Float64Array, type: \"col\" | \"row\"): Matrix;\n /**\n * Solves the equation `Ax = b` using the conjugate gradient method. Returns the result `x`.\n *\n * @param {Matrix} A - Matrix\n * @param {Matrix} b - Matrix\n * @param {Randomizer | null} [randomizer]\n * @param {number} [tol=1e-3] Default is `1e-3`\n * @returns {Matrix}\n */\n static solve_CG(A: Matrix, b: Matrix, randomizer?: Randomizer | null, tol?: number): Matrix;\n /**\n * Solves the equation `Ax = b`. Returns the result `x`.\n *\n * @param {Matrix | { L: Matrix; U: Matrix }} A - Matrix or LU Decomposition\n * @param {Matrix} b - Matrix\n * @returns {Matrix}\n */\n static solve(A: Matrix | {\n L: Matrix;\n U: Matrix;\n }, b: Matrix): Matrix;\n /**\n * `LU` decomposition of the Matrix `A`. Creates two matrices, so that the dot product `LU` equals `A`.\n *\n * @param {Matrix} A\n * @returns {{ L: Matrix; U: Matrix }} The left triangle matrix `L` and the upper triangle matrix `U`.\n */\n static LU(A: Matrix): {\n L: Matrix;\n U: Matrix;\n };\n /**\n * Computes the determinante of `A`, by using the `LU` decomposition of `A`.\n *\n * @param {Matrix} A\n * @returns {number} The determinate of the Matrix `A`.\n */\n static det(A: Matrix): number;\n /**\n * Computes the `k` components of the SVD decomposition of the matrix `M`.\n *\n * @param {Matrix} M\n * @param {number} [k=2] Default is `2`\n * @returns {{ U: Float64Array[]; Sigma: Float64Array; V: Float64Array[] }}\n */\n static SVD(M: Matrix, k?: number): {\n U: Float64Array[];\n Sigma: Float64Array;\n V: Float64Array[];\n };\n /**\n * @param {unknown} A\n * @returns {A is unknown[]|number[]|Float64Array|Float32Array}\n */\n static isArray(A: unknown): A is unknown[] | number[] | Float64Array | Float32Array;\n /**\n * @param {any[]} A\n * @returns {A is number[][]|Float64Array[]}\n */\n static is2dArray(A: any[]): A is number[][] | Float64Array[];\n /**\n * Creates a new Matrix. Entries are stored in a Float64Array.\n *\n * @example let A = new Matrix(10, 10, () => Math.random()); //creates a 10 times 10 random matrix. let B = new\n * Matrix(3, 3, \"I\"); // creates a 3 times 3 identity matrix.\n *\n * @param {number} rows - The amount of rows of the matrix.\n * @param {number} cols - The amount of columns of the matrix.\n * @param {Accessor | string | number} value - Can be a function with row and col as parameters, a number, or\n * \"zeros\", \"identity\" or \"I\", or \"center\".\n *\n * - **function**: for each entry the function gets called with the parameters for the actual row and column.\n * - **string**: allowed are\n *\n * - \"zero\", creates a zero matrix.\n * - \"identity\" or \"I\", creates an identity matrix.\n * - \"center\", creates an center matrix.\n * - **number**: create a matrix filled with the given value.\n */\n constructor(rows: number, cols: number, value?: Accessor | string | number);\n /** @type {number} */ _rows: number;\n /** @type {number} */ _cols: number;\n /** @type {Float64Array} */ _data: Float64Array;\n /**\n * Returns the `row`th row from the Matrix.\n *\n * @param {number} row\n * @returns {Float64Array}\n */\n row(row: number): Float64Array;\n /**\n * Returns an generator yielding each row of the Matrix.\n *\n * @yields {Float64Array}\n */\n iterate_rows(): Generator, void, unknown>;\n /**\n * Sets the entries of `row`th row from the Matrix to the entries from `values`.\n *\n * @param {number} row\n * @param {number[]} values\n * @returns {Matrix}\n */\n set_row(row: number, values: number[]): Matrix;\n /**\n * Swaps the rows `row1` and `row2` of the Matrix.\n *\n * @param {number} row1\n * @param {number} row2\n * @returns {Matrix}\n */\n swap_rows(row1: number, row2: number): Matrix;\n /**\n * Returns the colth column from the Matrix.\n *\n * @param {number} col\n * @returns {Float64Array}\n */\n col(col: number): Float64Array;\n /**\n * Returns the `col`th entry from the `row`th row of the Matrix.\n *\n * @param {number} row\n * @param {number} col\n * @returns {number}\n */\n entry(row: number, col: number): number;\n /**\n * Sets the {@link col}th entry from the {@link row}th row of the Matrix to the given\n * {@link value}.\n *\n * @param {number} row\n * @param {number} col\n * @param {number} value\n * @returns {Matrix}\n */\n set_entry(row: number, col: number, value: number): Matrix;\n /**\n * Adds a given {@link value} to the {@link col}th entry from the {@link row}th row of the\n * Matrix.\n *\n * @param {number} row\n * @param {number} col\n * @param {number} value\n * @returns {Matrix}\n */\n add_entry(row: number, col: number, value: number): Matrix;\n /**\n * Subtracts a given {@link value} from the {@link col}th entry from the {@link row}th row of the\n * Matrix.\n *\n * @param {number} row\n * @param {number} col\n * @param {number} value\n * @returns {Matrix}\n */\n sub_entry(row: number, col: number, value: number): Matrix;\n /**\n * Returns a new transposed Matrix.\n *\n * @returns {Matrix}\n */\n transpose(): Matrix;\n /**\n * Returns a new transposed Matrix. Short-form of `transpose`.\n *\n * @returns {Matrix}\n */\n get T(): Matrix;\n /**\n * Returns the inverse of the Matrix.\n *\n * @returns {Matrix}\n */\n inverse(): Matrix;\n /**\n * Returns the dot product. If `B` is an Array or Float64Array then an Array gets returned. If `B` is a Matrix then\n * a Matrix gets returned.\n *\n * @param {Matrix | number[] | Float64Array} B The right side\n * @returns {Matrix}\n */\n dot(B: Matrix | number[] | Float64Array): Matrix;\n /**\n * Transposes the current matrix and returns the dot product with `B`. If `B` is an Array or Float64Array then an\n * Array gets returned. If `B` is a Matrix then a Matrix gets returned.\n *\n * @param {Matrix | number[] | Float64Array} B The right side\n * @returns {Matrix}\n */\n transDot(B: Matrix | number[] | Float64Array): Matrix;\n /**\n * Returns the dot product with the transposed version of `B`. If `B` is an Array or Float64Array then an Array gets\n * returned. If `B` is a Matrix then a Matrix gets returned.\n *\n * @param {Matrix | number[] | Float64Array} B The right side\n * @returns {Matrix}\n */\n dotTrans(B: Matrix | number[] | Float64Array): Matrix;\n /**\n * Computes the outer product from `this` and `B`.\n *\n * @param {Matrix} B\n * @returns {Matrix}\n */\n outer(B: Matrix): Matrix;\n /**\n * Appends matrix `B` to the matrix.\n *\n * @example let A = Matrix.from([ [1, 1], [1, 1], ]); // 2 by 2 matrix filled with ones. let B = Matrix.from([ [2,\n * 2], [2, 2], ]); // 2 by 2 matrix filled with twos.\n *\n * A.concat(B, \"horizontal\"); // 2 by 4 matrix. [[1, 1, 2, 2], [1, 1, 2, 2]]\n * A.concat(B, \"vertical\"); // 4 by 2 matrix. [[1, 1], [1, 1], [2, 2], [2, 2]]\n * A.concat(B, \"diag\"); // 4 by 4 matrix. [[1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 2, 2], [0, 0, 2, 2]]\n *\n * @param {Matrix} B - Matrix to append.\n * @param {\"horizontal\" | \"vertical\" | \"diag\"} [type=\"horizontal\"] - Type of concatenation. Default is\n * `\"horizontal\"`\n * @returns {Matrix}\n */\n concat(B: Matrix, type?: \"horizontal\" | \"vertical\" | \"diag\"): Matrix;\n /**\n * Writes the entries of B in A at an offset position given by `offset_row` and `offset_col`.\n *\n * @param {number} offset_row\n * @param {number} offset_col\n * @param {Matrix} B\n * @returns {Matrix}\n */\n set_block(offset_row: number, offset_col: number, B: Matrix): Matrix;\n /**\n * Extracts the entries from the `start_row`th row to the `end_row`th row, the\n * `start_col`th column to the `end_col`th column of the matrix. If `end_row` or `end_col` is\n * empty, the respective value is set to `this.rows` or `this.cols`.\n *\n * @example let A = Matrix.from([ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]); // a 3 by 3 matrix.\n *\n * A.get_block(1, 1); // [[5, 6], [8, 9]]\n * A.get_block(0, 0, 1, 1); // [[1]]\n * A.get_block(1, 1, 2, 2); // [[5]]\n * A.get_block(0, 0, 2, 2); // [[1, 2], [4, 5]]\n *\n * @param {number} start_row\n * @param {number} start_col\n * @param {number | null} [end_row]\n * @param {number | null} [end_col]\n * @returns {Matrix} Returns a `end_row` - `start_row` times `end_col` - `start_col` matrix, with respective entries\n * from the matrix.\n */\n get_block(start_row: number, start_col: number, end_row?: number | null, end_col?: number | null): Matrix;\n /**\n * Returns a new array gathering entries defined by the indices given by argument.\n *\n * @param {number[]} row_indices - Array consists of indices of rows for gathering entries of this matrix\n * @param {number[]} col_indices - Array consists of indices of cols for gathering entries of this matrix\n * @returns {Matrix}\n */\n gather(row_indices: number[], col_indices: number[]): Matrix;\n /**\n * Applies a function to each entry of the matrix.\n *\n * @private\n * @param {(d: number, v: number) => number} f Function takes 2 parameters, the value of the actual entry and a\n * value given by the function `v`. The result of `f` gets writen to the Matrix.\n * @param {Accessor} v Function takes 2 parameters for `row` and `col`, and returns a value witch should be applied\n * to the `col`th entry of the `row`th row of the matrix.\n * @returns {Matrix}\n */\n private _apply_array;\n /**\n * @param {number[] | Float64Array} values\n * @param {(d: number, v: number) => number} f\n * @returns {Matrix}\n */\n _apply_rowwise_array(values: number[] | Float64Array, f: (d: number, v: number) => number): Matrix;\n /**\n * @param {number[] | Float64Array} values\n * @param {(d: number, v: number) => number} f\n * @returns {Matrix}\n */\n _apply_colwise_array(values: number[] | Float64Array, f: (d: number, v: number) => number): Matrix;\n /**\n * @param {Matrix | number[] | Float64Array | number} value\n * @param {(d: number, v: number) => number} f\n * @returns {Matrix}\n */\n _apply(value: Matrix | number[] | Float64Array | number, f: (d: number, v: number) => number): Matrix;\n /**\n * Clones the Matrix.\n *\n * @returns {Matrix}\n */\n clone(): Matrix;\n /**\n * Entrywise multiplication with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.mult(2); // [[2, 4], [6, 8]];\n * A.mult(B); // [[1, 4], [9, 16]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {boolean} [options.inline=false] - If true, applies multiplication to the element, otherwise it creates\n * first a copy and applies the multiplication on the copy. Default is `false`\n * @returns {Matrix}\n */\n mult(value: Matrix | Float64Array | number[] | number, { inline }?: {\n inline?: boolean | undefined;\n }): Matrix;\n /**\n * Entrywise division with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.divide(2); // [[0.5, 1], [1.5, 2]];\n * A.divide(B); // [[1, 1], [1, 1]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {Boolean} [options.inline=false] - If true, applies division to the element, otherwise it creates first a\n * copy and applies the division on the copy. Default is `false`\n * @returns {Matrix}\n */\n divide(value: Matrix | Float64Array | number[] | number, { inline }?: {\n inline?: boolean | undefined;\n }): Matrix;\n /**\n * Entrywise addition with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.add(2); // [[3, 4], [5, 6]];\n * A.add(B); // [[2, 4], [6, 8]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {boolean} [options.inline=false] - If true, applies addition to the element, otherwise it creates first a\n * copy and applies the addition on the copy. Default is `false`\n * @returns {Matrix}\n */\n add(value: Matrix | Float64Array | number[] | number, { inline }?: {\n inline?: boolean | undefined;\n }): Matrix;\n /**\n * Entrywise subtraction with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.sub(2); // [[-1, 0], [1, 2]];\n * A.sub(B); // [[0, 0], [0, 0]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {boolean} [options.inline=false] - If true, applies subtraction to the element, otherwise it creates first\n * a copy and applies the subtraction on the copy. Default is `false`\n * @returns {Matrix}\n */\n sub(value: Matrix | Float64Array | number[] | number, { inline }?: {\n inline?: boolean | undefined;\n }): Matrix;\n /**\n * Returns the matrix in the given shape with the given function which returns values for the entries of the matrix.\n *\n * @param {[number, number, Accessor]} parameter - Takes an Array in the form [rows, cols, value], where rows and\n * cols are the number of rows and columns of the matrix, and value is a function which takes two parameters (row\n * and col) which has to return a value for the colth entry of the rowth row.\n * @returns {Matrix}\n */\n set shape([rows, cols, value]: [number, number, Accessor]);\n /**\n * Returns the number of rows and columns of the Matrix.\n *\n * @returns {number[]} An Array in the form [rows, columns].\n */\n get shape(): number[];\n /**\n * Returns the Matrix as a Array of Float64Arrays.\n *\n * @returns {Float64Array[]}\n */\n to2dArray(): Float64Array[];\n /**\n * Returns the Matrix as a Array of Arrays.\n *\n * @returns {number[][]}\n */\n asArray(): number[][];\n /**\n * Returns the diagonal of the Matrix.\n *\n * @returns {Float64Array}\n */\n diag(): Float64Array;\n /**\n * Returns the mean of all entries of the Matrix.\n *\n * @returns {number}\n */\n mean(): number;\n /**\n * Returns the sum oof all entries of the Matrix.\n *\n * @returns {number}\n */\n sum(): number;\n /**\n * Returns the entries of the Matrix.\n *\n * @returns {Float64Array}\n */\n get values(): Float64Array;\n /**\n * Returns the mean of each row of the matrix.\n *\n * @returns {Float64Array}\n */\n meanRows(): Float64Array;\n /**\n * Returns the mean of each column of the matrix.\n *\n * @returns {Float64Array}\n */\n meanCols(): Float64Array;\n /**\n * Makes a `Matrix` object an iterable object.\n *\n * @yields {Float64Array}\n */\n [Symbol.iterator](): Generator, void, unknown>;\n}\nexport type Accessor = (i: number, j: number) => number;\nimport { Randomizer } from \"../util/index.js\";\n//# sourceMappingURL=Matrix.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/**\n * Computes the norm of a vector, by computing its distance to **0**.\n *\n * @category Matrix\n * @param {Matrix | number[] | Float64Array} v - Vector.\n * @param {Metric} [metric=euclidean] - Which metric should be used to compute the norm. Default is `euclidean`\n * @returns {number} - The norm of `v`.\n */\nexport function norm(v: Matrix | number[] | Float64Array, metric?: Metric): number;\nimport { Matrix } from \"../matrix/index.js\";\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=norm.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/**\n * Normalizes Vector `v`.\n *\n * @category Matrix\n * @param {number[] | Float64Array} v - Vector\n * @param {Metric} metric\n * @returns {number[] | Float64Array} - The normalized vector with length 1.\n */\nexport function normalize(v: number[] | Float64Array, metric?: Metric): number[] | Float64Array;\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=normalize.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/**\n * Base class for all clustering algorithms.\n * @template Para\n */\nexport class Clustering {\n /**\n * Compute the respective Clustering with given parameters\n * @param {InputType} points\n * @param {Para} parameters\n */\n constructor(points: InputType, parameters: Para);\n /** @type {InputType} */\n _points: InputType;\n /** @type {Para} */\n _parameters: Para;\n /** @type {Matrix} */\n _matrix: Matrix;\n /** @type {number} */\n _N: number;\n /** @type {number} */\n _D: number;\n /**\n * @abstract\n * @param {...unknown} args\n * @returns {number[][]} An array with the indices of the clusters.\n */\n get_clusters(...args: unknown[]): number[][];\n /**\n * @abstract\n * @param {...unknown} args\n * @returns {number[]} An array with the clusters id's for each point.\n */\n get_cluster_list(...args: unknown[]): number[];\n}\nimport type { InputType } from \"../index.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=Clustering.d.ts.map","/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersCURE } from \"./index.js\" */\n/**\n * CURE (Clustering Using REpresentatives)\n *\n * An efficient clustering algorithm for large databases that is robust to outliers\n * and identifies clusters with non-spherical shapes and wide variances in size.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class CURE extends Clustering {\n /**\n * @param {InputType} points\n * @param {Partial} parameters\n */\n constructor(points: InputType, parameters?: Partial);\n /** @type {number} */\n _K: number;\n /** @type {number} */\n _num_representatives: number;\n /** @type {number} */\n _shrink_factor: number;\n /**\n * @private\n * @type {CURECluster[]}\n */\n private _clusters;\n /** @type {number[]} */\n _cluster_ids: number[];\n /**\n * Initialize each point as its own cluster\n * @private\n */\n private _initialize_clusters;\n /**\n * Compute distance between two clusters using representative points\n * @private\n * @param {CURECluster} cluster1\n * @param {CURECluster} cluster2\n * @returns {number}\n */\n private _cluster_distance;\n /**\n * Find the closest pair of clusters\n * @private\n * @returns {[number, number, number]} [index1, index2, distance]\n */\n private _find_closest_clusters;\n /**\n * Merge two clusters\n * @private\n * @param {CURECluster} cluster1\n * @param {CURECluster} cluster2\n * @returns {CURECluster}\n */\n private _merge_clusters;\n /**\n * Run CURE clustering algorithm\n * @private\n */\n private _cure;\n /**\n * Build the cluster list (point -> cluster assignment)\n * @private\n */\n private _build_cluster_ids;\n /**\n * @returns {number[][]}\n */\n get_clusters(): number[][];\n /**\n * @returns {number[]}\n */\n get_cluster_list(): number[];\n}\nimport type { ParametersCURE } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport type { InputType } from \"../index.js\";\n//# sourceMappingURL=CURE.d.ts.map","/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersHierarchicalClustering } from \"./index.js\" */\n/**\n * Hierarchical Clustering\n *\n * A bottom-up approach (agglomerative) to clustering that builds a tree of clusters (dendrogram).\n * Supports different linkage criteria: single, complete, and average.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class HierarchicalClustering extends Clustering {\n /**\n * @param {InputType} points - Data or distance matrix if metric is 'precomputed'\n * @param {Partial} parameters\n */\n constructor(points: InputType, parameters?: Partial);\n /** @type {Cluster | null} */\n root: Cluster | null;\n _id: number;\n _d_min: Float64Array;\n _distance_matrix: Matrix;\n _clusters: any[];\n _c_size: Uint16Array;\n /**\n * @param {number} value - Value where to cut the tree.\n * @param {\"distance\" | \"depth\"} [type=\"distance\"] - Type of value. Default is `\"distance\"`\n * @returns {Cluster[][]} - Array of clusters with the indices of the rows in given points.\n */\n get_clusters_raw(value: number, type?: \"distance\" | \"depth\"): Cluster[][];\n /**\n * @param {number} value - Value where to cut the tree.\n * @param {\"distance\" | \"depth\"} [type=\"distance\"] - Type of value. Default is `\"distance\"`\n * @returns {number[][]} - Array of clusters with the indices of the rows in given points.\n */\n get_clusters(value: number, type?: \"distance\" | \"depth\"): number[][];\n /**\n * @param {number} value - Value where to cut the tree.\n * @param {\"distance\" | \"depth\"} [type=\"distance\"] - Type of value. Default is `\"distance\"`\n * @returns {number[]} - Array of clusters with the indices of the rows in given points.\n */\n get_cluster_list(value: number, type?: \"distance\" | \"depth\"): number[];\n /**\n * @private\n * @param {Cluster} node\n * @param {(d: {dist: number, depth: number}) => number} f\n * @param {number} value\n * @param {Cluster[][]} result\n */\n private _traverse;\n}\nimport type { ParametersHierarchicalClustering } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\n/** @private */\ndeclare class Cluster {\n /**\n *\n * @param {number} id\n * @param {Cluster?} left\n * @param {Cluster?} right\n * @param {number} dist\n * @param {Float64Array?} centroid\n * @param {number} index\n * @param {number} [size]\n * @param {number} [depth]\n */\n constructor(id: number, left: Cluster | null, right: Cluster | null, dist: number, centroid: Float64Array | null, index: number, size?: number, depth?: number);\n /**@type {number} */\n size: number;\n /**@type {number} */\n depth: number;\n /**@type {Cluster | null} */\n parent: Cluster | null;\n id: number;\n left: Cluster | null;\n right: Cluster | null;\n dist: number;\n index: number;\n centroid: Float64Array;\n /**\n *\n * @param {Cluster} left\n * @param {Cluster} right\n * @returns {Float64Array}\n */\n _calculate_centroid(left: Cluster, right: Cluster): Float64Array;\n get isLeaf(): boolean;\n /**\n *\n * @returns {Cluster[]}\n */\n leaves(): Cluster[];\n /**\n *\n * @returns {Cluster[]}\n */\n descendants(): Cluster[];\n}\nimport { Matrix } from \"../matrix/index.js\";\nimport type { InputType } from \"../index.js\";\nexport {};\n//# sourceMappingURL=Hierarchical_Clustering.d.ts.map","/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersKMeans } from \"./index.js\" */\n/**\n * K-Means Clustering\n *\n * A popular clustering algorithm that partitions data into K clusters where each point\n * belongs to the cluster with the nearest mean (centroid).\n *\n * @class\n * @extends Clustering\n * @category Clustering\n * @see {@link KMedoids} for a more robust alternative\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const points = [[1, 1], [1.5, 1.5], [5, 5], [5.5, 5.5]];\n * const kmeans = new druid.KMeans(points, { K: 2 });\n *\n * const clusters = kmeans.get_cluster_list(); // [0, 0, 1, 1]\n * const centroids = kmeans.centroids; // center points\n */\nexport class KMeans extends Clustering {\n /**\n * @param {InputType} points\n * @param {Partial} parameters\n */\n constructor(points: InputType, parameters?: Partial);\n _K: number;\n _randomizer: Randomizer;\n /** @type {number[]} */\n _clusters: number[];\n _cluster_centroids: Float64Array[];\n /** @returns {number} The number of clusters */\n get k(): number;\n /** @returns {Float64Array[]} The cluster centroids */\n get centroids(): Float64Array[];\n /** @returns {number[]} The cluster list */\n get_cluster_list(): number[];\n /** @returns {number[][]} An Array of clusters with the indices of the points. */\n get_clusters(): number[][];\n /**\n * @private\n * @param {number[]} point_indices\n * @param {number[]} candidates\n * @returns {number}\n */\n private _furthest_point;\n /**\n * @private\n * @param {number} K\n * @returns {Float64Array[]}\n */\n private _get_random_centroids;\n /**\n * @private\n * @param {Float64Array[]} cluster_centroids\n * @returns {{ clusters_changed: boolean; cluster_centroids: Float64Array[] }}\n */\n private _iteration;\n /**\n * @private\n * @param {number} K\n * @returns {Float64Array[]}\n */\n private _compute_centroid;\n}\nimport type { ParametersKMeans } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport type { InputType } from \"../index.js\";\n//# sourceMappingURL=KMeans.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import { ParametersKMedoids } from \"./index.js\" */\n/**\n * K-Medoids (PAM - Partitioning Around Medoids)\n *\n * A robust clustering algorithm similar to K-Means, but uses actual data points (medoids)\n * as cluster centers and can work with any distance metric.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n * @see {@link KMeans} for a faster but less robust alternative\n */\nexport class KMedoids extends Clustering {\n /**\n * @param {InputType} points - Data matrix\n * @param {Partial} parameters\n * @see {@link https://link.springer.com/chapter/10.1007/978-3-030-32047-8_16} Faster k-Medoids Clustering: Improving the PAM, CLARA, and CLARANS Algorithms\n */\n constructor(points: InputType, parameters?: Partial);\n _A: Float64Array[];\n _max_iter: number;\n _distance_matrix: Matrix;\n _randomizer: Randomizer;\n _clusters: any[];\n _cluster_medoids: number[];\n _is_initialized: boolean;\n /** @returns {number[]} The cluster list */\n get_cluster_list(): number[];\n /** @returns {number[][]} - Array of clusters with the indices of the rows in given points. */\n get_clusters(): number[][];\n /** @returns {number} */\n get k(): number;\n /** @returns {number[]} */\n get medoids(): number[];\n /** @returns {number[]} */\n get_medoids(): number[];\n generator(): AsyncGenerator;\n /** Algorithm 1. FastPAM1: Improved SWAP algorithm */\n /**\n * FastPAM1: One best swap per iteration\n * @private\n * @returns {boolean}\n */\n private _iteration;\n /**\n * @private\n * Get distance between two points\n * @param {number} i\n * @param {number} j\n * @param {Float64Array?} x_i\n * @param {Float64Array?} x_j\n * @returns {number}\n */\n private _get_distance;\n /**\n * @private\n * @param {Float64Array} x_j\n * @param {number} j\n * @returns\n */\n private _nearest_medoid;\n /**\n * @private\n */\n private _update_clusters;\n /**\n * Computes `K` clusters out of the `matrix`.\n * @param {number} K - Number of clusters.\n * @param {number[]} cluster_medoids\n */\n init(K: number, cluster_medoids: number[]): this;\n /**\n * Algorithm 3. FastPAM LAB: Linear Approximate BUILD initialization.\n * @private\n * @param {number} K - Number of clusters\n * @returns {number[]}\n */\n private _get_random_medoids;\n}\nimport type { ParametersKMedoids } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport type { InputType } from \"../index.js\";\n//# sourceMappingURL=KMedoids.d.ts.map","/** @import { ParametersMeanShift } from \"./index.js\" */\n/** @import { InputType } from \"../index.js\" */\n/**\n * Mean Shift Clustering\n *\n * A non-parametric clustering technique that does not require prior knowledge of the\n * number of clusters. It identifies centers of density in the data.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class MeanShift extends Clustering {\n /**\n *\n * @param {InputType} points\n * @param {Partial} parameters\n */\n constructor(points: InputType, parameters?: Partial);\n /**\n * @private\n * @type {number}\n */\n private _bandwidth;\n /**\n * @private\n * @type {number}\n */\n private _max_iter;\n /**\n * @private\n * @type {number}\n */\n private _tolerance;\n /**\n * @private\n * @type {(dist: number) => number}\n */\n private _kernel;\n /**\n * @type {Matrix}\n */\n _points: Matrix;\n /**\n * @private\n * @type {number[] | undefined}\n */\n private _clusters;\n /**\n * @private\n * @type {number[][] | undefined}\n */\n private _cluster_list;\n /**\n * Helper to compute bandwidth if not provided\n * @private\n * @param {Matrix} matrix\n * @returns {number}\n */\n private _compute_bandwidth;\n /**\n * Compute kernel weight\n * @private\n * @param {number} dist\n * @returns {number}\n */\n private _kernel_weight;\n /**\n * Perform mean shift iterations\n * @private\n */\n private _mean_shift;\n /**\n * After convergence, assign clusters based on nearest mode\n * @private\n */\n private _assign_clusters;\n /**\n * @returns {number[][]}\n */\n get_clusters(): number[][];\n /**\n *\n * @returns {number[]}\n */\n get_cluster_list(): number[];\n}\nimport type { ParametersMeanShift } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport type { InputType } from \"../index.js\";\n//# sourceMappingURL=MeanShift.d.ts.map","/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersOptics } from \"./index.js\" */\n/** @typedef {Object} DBEntry\n * @property {Float64Array} element\n * @property {number} index\n * @property {number} [reachability_distance]\n * @property {boolean} processed\n * @property {DBEntry[]} [neighbors]\n */\n/**\n * OPTICS (Ordering Points To Identify the Clustering Structure)\n *\n * A density-based clustering algorithm that extends DBSCAN. It handles clusters of varying\n * densities and produces a reachability plot that can be used to extract clusters.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class OPTICS extends Clustering {\n /**\n * **O**rdering **P**oints **T**o **I**dentify the **C**lustering **S**tructure.\n *\n * @param {InputType} points - The data.\n * @param {Partial} [parameters={}]\n * @see {@link https://www.dbs.ifi.lmu.de/Publikationen/Papers/OPTICS.pdf}\n * @see {@link https://en.wikipedia.org/wiki/OPTICS_algorithm}\n */\n constructor(points: InputType, parameters?: Partial);\n /**\n * @private\n * @type {DBEntry[]}\n */\n private _ordered_list;\n /** @type {number[][]} */\n _clusters: number[][];\n /**\n * @private\n * @type {DBEntry[]}\n */\n private _DB;\n _cluster_index: number;\n /**\n * @private\n * @param {DBEntry} p - A point of the data.\n * @returns {DBEntry[]} An array consisting of the `epsilon`-neighborhood of `p`.\n */\n private _get_neighbors;\n /**\n * @private\n * @param {DBEntry} p - A point of `matrix`.\n * @returns {number|undefined} The distance to the `min_points`-th nearest point of `p`, or undefined if the\n * `epsilon`-neighborhood has fewer elements than `min_points`.\n */\n private _core_distance;\n /**\n * Updates the reachability distance of the points.\n *\n * @private\n * @param {DBEntry} p\n * @param {Heap} seeds\n */\n private _update;\n /**\n * Expands the `cluster` with points in `seeds`.\n *\n * @private\n * @param {Heap} seeds\n * @param {number[]} cluster\n */\n private _expand_cluster;\n /**\n * Returns an array of clusters.\n *\n * @returns {number[][]} Array of clusters with the indices of the rows in given `matrix`.\n */\n get_clusters(): number[][];\n /**\n * @returns {number[]} Returns an array, where the ith entry defines the cluster affirmation of the ith point of\n * given data. (-1 stands for outlier)\n */\n get_cluster_list(): number[];\n}\nexport type DBEntry = {\n element: Float64Array;\n index: number;\n reachability_distance?: number | undefined;\n processed: boolean;\n neighbors?: DBEntry[] | undefined;\n};\nimport type { ParametersOptics } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport type { InputType } from \"../index.js\";\n//# sourceMappingURL=OPTICS.d.ts.map","/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersXMeans } from \"./index.js\" */\n/**\n * @typedef SplitResult\n * @property {number} index - Index of the cluster being split\n * @property {number} bic_parent - BIC score of the parent cluster\n * @property {number} bic_children - BIC score of the split children\n * @property {number[][]} child_clusters - Clusters after splitting\n * @property {Float64Array[]} child_centroids - Centroids of child clusters\n */\n/**\n * @typedef CandidateResult\n * @property {KMeans} kmeans - The KMeans instance for this K\n * @property {number} score - BIC score\n */\n/**\n * X-Means Clustering\n *\n * An extension of K-Means that automatically determines the number of clusters (K)\n * using the Bayesian Information Criterion (BIC).\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class XMeans extends Clustering {\n /**\n * XMeans clustering algorithm that automatically determines the optimal number of clusters.\n *\n * X-Means extends K-Means by starting with a minimum number of clusters and iteratively\n * splitting clusters to improve the Bayesian Information Criterion (BIC).\n *\n * Algorithm:\n * 1. Start with K_min clusters using KMeans\n * 2. For each cluster, try splitting it into 2 sub-clusters\n * 3. If BIC improves after splitting, keep the split\n * 4. Run KMeans again with all (old + new) centroids\n * 5. Repeat until K_max is reached or no more improvements\n *\n * @param {InputType} points - The data points to cluster\n * @param {Partial} [parameters={}] - Configuration parameters\n * @see {@link https://www.cs.cmu.edu/~dpelleg/download/xmeans.pdf}\n * @see {@link https://github.com/annoviko/pyclustering/blob/master/pyclustering/cluster/xmeans.py}\n * @see {@link https://github.com/haifengl/smile/blob/master/core/src/main/java/smile/clustering/XMeans.java}\n */\n constructor(points: InputType, parameters?: Partial);\n _randomizer: Randomizer;\n /** @type {KMeans | null} */\n _best_kmeans: KMeans | null;\n /**\n * Run the XMeans algorithm\n *\n * @private\n */\n private _run;\n /**\n * Select the best candidate based on BIC score\n *\n * @private\n * @param {Map} candidates\n * @returns {KMeans}\n */\n private _select_best_candidate;\n /**\n * Calculate Bayesian Information Criterion for a set of clusters.\n *\n * Uses Kass's formula for BIC calculation:\n * BIC(θ) = L(D) - 0.5 * p * ln(N)\n *\n * Where:\n * - L(D) is the log-likelihood of the data\n * - p is the number of free parameters: (K-1) + D*K + 1\n * - N is the total number of points\n *\n * @private\n * @param {number[][]} clusters - Array of clusters with point indices\n * @param {Float64Array[]} centroids - Array of centroids\n * @returns {number} BIC score (higher is better)\n */\n private _bic;\n /**\n * Get the computed clusters\n *\n * @returns {number[][]} Array of clusters, each containing indices of points\n */\n get_clusters(): number[][];\n /** @returns {number[]} The cluster list */\n get_cluster_list(): number[];\n /**\n * Get the final centroids\n *\n * @returns {Float64Array[]} Array of centroids\n */\n get centroids(): Float64Array[];\n /**\n * Get the optimal number of clusters found\n *\n * @returns {number} The number of clusters\n */\n get k(): number;\n}\nexport type SplitResult = {\n /**\n * - Index of the cluster being split\n */\n index: number;\n /**\n * - BIC score of the parent cluster\n */\n bic_parent: number;\n /**\n * - BIC score of the split children\n */\n bic_children: number;\n /**\n * - Clusters after splitting\n */\n child_clusters: number[][];\n /**\n * - Centroids of child clusters\n */\n child_centroids: Float64Array[];\n};\nexport type CandidateResult = {\n /**\n * - The KMeans instance for this K\n */\n kmeans: KMeans;\n /**\n * - BIC score\n */\n score: number;\n};\nimport type { ParametersXMeans } from \"./index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { KMeans } from \"./KMeans.js\";\nimport type { InputType } from \"../index.js\";\n//# sourceMappingURL=XMeans.d.ts.map","export { CURE } from \"./CURE.js\";\nexport { HierarchicalClustering } from \"./Hierarchical_Clustering.js\";\nexport { KMeans } from \"./KMeans.js\";\nexport { KMedoids } from \"./KMedoids.js\";\nexport { MeanShift } from \"./MeanShift.js\";\nexport { OPTICS } from \"./OPTICS.js\";\nexport { XMeans } from \"./XMeans.js\";\nexport type ParametersHierarchicalClustering = {\n linkage: \"single\" | \"complete\" | \"average\";\n metric: Metric | \"precomputed\";\n};\nexport type ParametersKMeans = {\n K: number;\n /**\n * Default is `euclidean`\n */\n metric: Metric;\n /**\n * Default is `1212`\n */\n seed: number;\n /**\n * - Initial centroids. Default is `null`\n */\n initial_centroids?: Float64Array[] | number[][] | undefined;\n};\nexport type ParametersKMedoids = {\n /**\n * - Number of clusters\n */\n K: number;\n /**\n * - Maximum number of iterations. Default is 10 * Math.log10(N). Default is `null`\n */\n max_iter: number | null;\n /**\n * - Metric defining the dissimilarity. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Seed value for random number generator. Default is `1212`\n */\n seed: number;\n};\nexport type ParametersOptics = {\n /**\n * - The minimum distance which defines whether a point is a neighbor or not.\n */\n epsilon: number;\n /**\n * - The minimum number of points which a point needs to create a cluster. (Should be higher than 1, else each point creates a cluster.)\n */\n min_points: number;\n /**\n * - The distance metric which defines the distance between two points of the points. Default is `euclidean`\n */\n metric: Metric;\n};\nexport type ParametersXMeans = {\n /**\n * - Minimum number of clusters. Default is `2`\n */\n K_min: number;\n /**\n * - Maximum number of clusters. Default is `10`\n */\n K_max: number;\n /**\n * - Distance metric function. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Random seed. Default is `1212`\n */\n seed: number;\n /**\n * - Minimum points required to consider splitting a cluster. Default is `25`\n */\n min_cluster_size: number;\n /**\n * - Convergence tolerance for KMeans. Default is `0.001`\n */\n tolerance: number;\n};\nexport type ParametersMeanShift = {\n /**\n * - bandwidth\n */\n bandwidth: number;\n /**\n * - Metric defining the dissimilarity. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Seed value for random number generator. Default is `1212`\n */\n seed: number;\n /**\n * - Kernel function. Default is `gaussian`\n */\n kernel: \"flat\" | \"gaussian\" | ((dist: number) => number);\n /**\n * - Maximum number of iterations. Default is `Math.max(10, Math.floor(10 * Math.log10(N)))`\n */\n max_iter?: number | undefined;\n /**\n * - Convergence tolerance. Default is `1e-3`\n */\n tolerance?: number | undefined;\n};\nexport type ParametersCURE = {\n /**\n * - Target number of clusters. Default is `2`\n */\n K: number;\n /**\n * - Number of representative points per cluster. Default is `5`\n */\n num_representatives: number;\n /**\n * - Factor to shrink representatives toward centroid (0-1). Default is `0.5`\n */\n shrink_factor: number;\n /**\n * - Distance metric function. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Random seed. Default is `1212`\n */\n seed: number;\n};\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=index.d.ts.map","/**\n * @template T\n * @typedef {Object} DisjointSetPayload\n * @property {T} parent\n * @property {Set} children\n * @property {number} size\n */\n/**\n * @template T\n * @class\n * @category Data Structures\n * @see {@link https://en.wikipedia.org/wiki/Disjoint-set_data_structure}\n */\nexport class DisjointSet {\n /**\n * @param {T[]?} elements\n */\n constructor(elements?: T[] | null);\n /**\n * @private\n * @type {Map>}\n */\n private _list;\n /**\n * @private\n * @param {T} x\n * @returns {DisjointSet}\n */\n private make_set;\n /**\n * @param {T} x\n * @returns\n */\n find(x: T): T | null;\n /**\n * @param {T} x\n * @param {T} y\n * @returns\n */\n union(x: T, y: T): this;\n /** @param {T} x */\n get_children(x: T): Set | null;\n}\nexport type DisjointSetPayload = {\n parent: T;\n children: Set;\n size: number;\n};\n//# sourceMappingURL=DisjointSet.d.ts.map","/** @import { Comparator } from \"./index.js\" */\n/**\n * @template T\n * @class\n * @category Data Structures\n */\nexport class Heap {\n /**\n * Creates a Heap from an Array\n *\n * @template T\n * @param {T[]} elements - Contains the elements for the Heap.\n * @param {(d: T) => number} accessor - Function returns the value of the element.\n * @param {\"min\" | \"max\" | Comparator} [comparator=\"min\"] - Function returning true or false\n * defining the wished order of the Heap, or String for predefined function. (\"min\" for a Min-Heap, \"max\" for a\n * Max_heap). Default is `\"min\"`\n * @returns {Heap}\n */\n static heapify(elements: T_1[], accessor: (d: T_1) => number, comparator?: \"min\" | \"max\" | Comparator): Heap;\n /**\n * A heap is a datastructure holding its elements in a specific way, so that the top element would be the first\n * entry of an ordered list.\n *\n * @param {T[]?} elements - Contains the elements for the Heap. `elements` can be null.\n * @param {(d: T) => number} accessor - Function returns the value of the element.\n * @param {\"min\" | \"max\" | Comparator} [comparator=\"min\"] - Function returning true or false\n * defining the wished order of the Heap, or String for predefined function. (\"min\" for a Min-Heap, \"max\" for a\n * Max_heap). Default is `\"min\"`\n * @see {@link https://en.wikipedia.org/wiki/Binary_heap}\n */\n constructor(elements: (T[] | null) | undefined, accessor: (d: T) => number, comparator?: \"min\" | \"max\" | Comparator);\n /** @type {{ element: T; value: number }[]} */\n _container: {\n element: T;\n value: number;\n }[];\n /** @type {Comparator} */\n _comparator: Comparator;\n /** @type {(d: T) => number} */\n _accessor: (d: T) => number;\n /**\n * Swaps elements of container array.\n *\n * @private\n * @param {number} index_a\n * @param {number} index_b\n */\n private _swap;\n /** @private */\n private _heapify_up;\n /**\n * Pushes the element to the heap.\n *\n * @param {T} element\n * @returns {Heap}\n */\n push(element: T): Heap;\n /**\n * @private\n * @param {Number} [start_index=0] Default is `0`\n */\n private _heapify_down;\n /**\n * Removes and returns the top entry of the heap.\n *\n * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by\n * `accessor`}).\n */\n pop(): {\n element: T;\n value: number;\n } | null;\n /**\n * Returns the top entry of the heap without removing it.\n *\n * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by\n * `accessor`).\n */\n get first(): {\n element: T;\n value: number;\n } | null;\n /**\n * Yields the raw data\n *\n * @yields {T} Object consists of the element and its value (computed by `accessor`}).\n */\n iterate(): Generator;\n /**\n * Returns the heap as ordered array.\n *\n * @returns {T[]} Array consisting the elements ordered by `comparator`.\n */\n toArray(): T[];\n /**\n * Returns elements of container array.\n *\n * @returns {T[]} Array consisting the elements.\n */\n data(): T[];\n /**\n * Returns the container array.\n *\n * @returns {{ element: T; value: number }[]} The container array.\n */\n raw_data(): {\n element: T;\n value: number;\n }[];\n /**\n * The size of the heap.\n *\n * @returns {number}\n */\n get length(): number;\n /**\n * Returns false if the the heap has entries, true if the heap has no entries.\n *\n * @returns {boolean}\n */\n get empty(): boolean;\n}\nimport type { Comparator } from \"./index.js\";\n//# sourceMappingURL=Heap.d.ts.map","export { DisjointSet } from \"./DisjointSet.js\";\nexport { Heap } from \"./Heap.js\";\nexport type Comparator = (a: number, b: number) => boolean;\n//# sourceMappingURL=index.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/**\n * @abstract\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n *\n * Base class for all Dimensionality Reduction (DR) algorithms.\n *\n * Provides a common interface for parameters management, data initialization,\n * and transformation (both synchronous and asynchronous).\n *\n * @class\n */\nexport class DR {\n /**\n * Computes the projection.\n *\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.\n * @returns {T} The dimensionality reduced dataset.\n */\n static transform(X: T_1, parameters: Para_1, ...args: unknown[]): T_1;\n /**\n * Computes the projection.\n *\n * @template {{ seed?: number }} Para\n * @param {InputType} X\n * @param {Para} parameters\n * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.\n * @returns {Generator} A generator yielding the intermediate steps of the dimensionality\n * reduction method.\n */\n static generator(X: InputType, parameters: Para_1, ...args: unknown[]): Generator;\n /**\n * Computes the projection.\n *\n * @template {{ seed?: number }} Para\n * @param {InputType} X\n * @param {Para} parameters\n * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.\n * @returns {Promise} A promise yielding the dimensionality reduced dataset.\n */\n static transform_async(X: InputType, parameters: Para_1, ...args: unknown[]): Promise;\n /**\n * Takes the default parameters and seals them, remembers the type of input `X`, and initializes the random number\n * generator.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Para} default_parameters - Object containing default parameterization of the DR method.\n * @param {Partial} parameters - Object containing parameterization of the DR method to override defaults.\n */\n constructor(X: T, default_parameters: Para, parameters?: Partial);\n /** @type {number} */\n _D: number;\n /** @type {number} */\n _N: number;\n /** @type {Randomizer} */\n _randomizer: Randomizer;\n /** @type {boolean} */\n _is_initialized: boolean;\n /** @type {T} */\n __input: T;\n /** @type {Para} */\n _parameters: Para;\n /** @type {\"array\" | \"matrix\" | \"typed\"} */\n _type: \"array\" | \"matrix\" | \"typed\";\n /** @type {Matrix} */\n X: Matrix;\n /** @type {Matrix} */\n Y: Matrix;\n /**\n * Get all Parameters.\n * @overload\n * @returns {Para}\n */\n parameter(): Para;\n /**\n * Get value of given parameter.\n * @template {keyof Para} K\n * @overload\n * @param {K} name - Name of the parameter.\n * @returns {Para[K]}\n */\n parameter(name: K): Para[K];\n /**\n * Set value of given parameter.\n * @template {keyof Para} K\n * @overload\n * @param {K} name - Name of the parameter.\n * @param {Para[K]} value - Value of the parameter to set.\n * @returns {this}\n */\n parameter(name: K, value: Para[K]): this;\n /**\n * Computes the projection.\n *\n * @abstract\n * @param {...unknown} args\n * @returns {T} The projection.\n */\n transform(...args: unknown[]): T;\n /**\n * Computes the projection.\n *\n * @abstract\n * @param {...unknown} args\n * @returns {Generator} The intermediate steps of the projection.\n */\n generator(...args: unknown[]): Generator;\n /**\n * @abstract\n * @param {...unknown} args\n */\n init(...args: unknown[]): void;\n /**\n * If the respective DR method has an `init` function, call it before `transform`.\n *\n * @returns {DR}\n */\n check_init(): DR;\n /** @returns {T} The projection in the type of input `X`. */\n get projection(): T;\n /**\n * Computes the projection.\n *\n * @param {...unknown} args - Arguments the transform method of the respective DR method takes.\n * @returns {Promise} The dimensionality reduced dataset.\n */\n transform_async(...args: unknown[]): Promise;\n}\nimport type { InputType } from \"../index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=DR.d.ts.map","/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersFASTMAP } from \"./index.js\"; */\n/**\n * FastMap algorithm for dimensionality reduction.\n *\n * A very fast algorithm for projecting high-dimensional data into a lower-dimensional\n * space while preserving pairwise distances. It works similarly to PCA but uses\n * only a subset of the data to find projection axes.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class FASTMAP extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X: T_1, parameters: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static generator(X: T_1, parameters: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters: Partial): Promise;\n /**\n * FastMap: a fast algorithm for indexing, data-mining and visualization of traditional and multimedia datasets.\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://doi.org/10.1145/223784.223812}\n */\n constructor(X: T, parameters: Partial);\n /**\n * Chooses two points which are the most distant in the actual projection.\n *\n * @private\n * @param {(a: number, b: number) => number} dist\n * @returns {[number, number, number]} An array consisting of first index, second index, and distance between the\n * two points.\n */\n private _choose_distant_objects;\n /**\n * Computes the projection.\n *\n * @returns {T} The `d`-dimensional projection of the data matrix `X`.\n */\n transform(): T;\n generator(): Generator;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersFASTMAP } from \"./index.js\";\nimport { DR } from \"./DR.js\";\n//# sourceMappingURL=FASTMAP.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersPaCMAP} from \"./index.js\" */\n/**\n * Pairwise Controlled Manifold Approximation Projection (PaCMAP)\n *\n * A dimensionality reduction technique that uses three types of point pairs —\n * nearest neighbor (NN), mid-near (MN), and further (FP) pairs — with a\n * dynamic three-phase weight schedule and Adam optimization to preserve both\n * local and global structure.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link https://arxiv.org/abs/2012.04456|PaCMAP Paper}\n * @see {@link https://github.com/YingfanWang/PaCMAP|PaCMAP GitHub}\n * @see {@link UMAP} for a related graph-based technique\n * @see {@link LocalMAP} for the local-refinement variant\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];\n * const pacmap = new druid.PaCMAP(X, {\n * n_neighbors: 10,\n * MN_ratio: 0.5,\n * FP_ratio: 2.0,\n * seed: 42\n * });\n *\n * const Y = pacmap.transform(); // 450 iterations (default)\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class PaCMAP extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X: T, parameters?: Partial);\n _iter: number;\n /**\n * Samples mid-near pairs for each point.\n * For each point i, repeats n_MN times: samples 6 random non-neighbor\n * candidates, picks the 2nd closest by high-dim distance.\n *\n * @protected\n * @param {Set[]} nn_sets - Array of neighbor index sets per point\n * @param {number} n_MN - Number of mid-near pairs per point\n * @returns {Int32Array} Flat array of [i, j] pairs\n */\n protected _sample_mn_pairs(nn_sets: Set[], n_MN: number): Int32Array;\n /**\n * Samples further pairs for each point (random non-neighbors).\n *\n * @protected\n * @param {Set[]} nn_sets - Array of neighbor index sets per point\n * @param {number} n_FP - Number of further pairs per point\n * @returns {Int32Array} Flat array of [i, j] pairs\n */\n protected _sample_fp_pairs(nn_sets: Set[], n_FP: number): Int32Array;\n /**\n * Computes gradient coefficients and updates the gradient matrix for one pair type.\n *\n * @protected\n * @param {Float64Array} grad_flat - Flat N×d gradient accumulator (modified in place)\n * @param {Int32Array} pairs - Flat [i, j, i, j, ...] pair array\n * @param {number} w - Weight for this pair type\n * @param {number} attr_num - Numerator constant for attractive (10 for NN, 10000 for MN); 0 for repulsive\n * @param {boolean} repulsive - Whether this is a repulsive pair type\n */\n protected _accumulate_gradients(grad_flat: Float64Array, pairs: Int32Array, w: number, attr_num: number, repulsive: boolean): void;\n /**\n * Returns the weight schedule for the current iteration.\n *\n * @protected\n * @param {number} iter - Current iteration (0-indexed)\n * @returns {{ w_nn: number; w_mn: number; w_fp: number }}\n */\n protected _get_weights(iter: number): {\n w_nn: number;\n w_mn: number;\n w_fp: number;\n };\n /**\n * Applies Adam optimizer update to Y using accumulated gradients.\n *\n * @protected\n * @param {Float64Array} grad_flat - Flat N×d gradient\n */\n protected _adam_update(grad_flat: Float64Array): void;\n _adam_t: any;\n /**\n * Initializes PaCMAP: PCA embedding, KNN pairs, MN pairs, FP pairs, Adam state.\n *\n * @returns {PaCMAP}\n */\n init(): PaCMAP;\n _nn_pairs: Int32Array | undefined;\n _mn_pairs: Int32Array | undefined;\n _fp_pairs: Int32Array | undefined;\n _adam_m: Float64Array | undefined;\n _adam_v: Float64Array | undefined;\n /**\n * Performs one optimization step.\n *\n * @returns {Matrix}\n */\n next(): Matrix;\n /**\n * @param {number} [iterations] - Total number of iterations. Defaults to sum of `num_iters`.\n * @returns {T}\n */\n transform(iterations?: number): T;\n /**\n * @param {number} [iterations] - Total number of iterations. Defaults to sum of `num_iters`.\n * @returns {Generator}\n */\n generator(iterations?: number): Generator;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersPaCMAP } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=PaCMAP.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLocalMAP} from \"./index.js\" */\n/**\n * LocalMAP\n *\n * A variant of PaCMAP that improves local cluster separation by dynamically\n * resampling further pairs (FP) in phase 3 using nearby points in the current\n * low-dimensional embedding space, rather than randomly sampled non-neighbors.\n *\n * @class\n * @template {InputType} T\n * @extends PaCMAP\n * @category Dimensionality Reduction\n * @see {@link https://arxiv.org/abs/2012.04456|PaCMAP Paper}\n * @see {@link PaCMAP} for the base algorithm\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];\n * const localmap = new druid.LocalMAP(X, {\n * n_neighbors: 10,\n * low_dist_thres: 10,\n * seed: 42\n * });\n *\n * const Y = localmap.transform(); // 450 iterations (default)\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class LocalMAP extends PaCMAP {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X: T, parameters?: Partial);\n /**\n * Accumulates FP gradients with LocalMAP's distance-based weight scaling.\n * For pairs within low_dist_thres, scales w_fp by low_dist_thres / (2 * sqrt(d_ij)).\n *\n * @private\n * @param {Float64Array} grad_flat - Flat N×d gradient accumulator (modified in place)\n * @param {Int32Array} pairs - Flat [i, j, i, j, ...] pair array\n * @param {number} w_fp - Base FP weight\n * @param {number} low_dist_thres - Distance threshold\n * @param {number} low_dist_thres_sq - Squared distance threshold\n */\n private _accumulate_gradients_local_fp;\n /**\n * Initializes LocalMAP (same as PaCMAP, but caches nn_sets for phase 3 resampling).\n *\n * @returns {LocalMAP}\n */\n init(): LocalMAP;\n _low_dist_thres: number | undefined;\n _nn_sets_cache: Set[] | undefined;\n}\nimport type { InputType } from \"../index.js\";\nimport { PaCMAP } from \"./PaCMAP.js\";\nimport type { ParametersLocalMAP } from \"./index.js\";\n//# sourceMappingURL=LocalMAP.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersISOMAP} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n/**\n * Isomap (Isometric Mapping)\n *\n * A nonlinear dimensionality reduction algorithm that uses geodesic distances\n * between points on a manifold to perform embedding. It builds a neighborhood\n * graph and uses MDS on the shortest-path distances.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link LLE} for another nonlinear alternative\n */\nexport class ISOMAP extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * Isometric feature mapping (ISOMAP).\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n * @see {@link https://doi.org/10.1126/science.290.5500.2319}\n */\n constructor(X: T, parameters?: Partial);\n defaults: ParametersISOMAP;\n /**\n * Computes the projection.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * @returns {T}\n */\n transform(): T;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersISOMAP } from \"./index.js\";\nimport { DR } from \"./DR.js\";\n//# sourceMappingURL=ISOMAP.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLDA} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n/**\n * Linear Discriminant Analysis (LDA)\n *\n * A supervised dimensionality reduction technique that finds the axes that\n * maximize the separation between multiple classes.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class LDA extends DR {\n /**\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @returns {T}\n */\n static transform(X: T_1, parameters: Para): T_1;\n /**\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @returns {Generator}\n */\n static generator(X: T_1, parameters: Para): Generator;\n /**\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters: Para): Promise;\n /**\n * Linear Discriminant Analysis.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial & { labels: any[] | Float64Array }} parameters - Object containing parameterization of the DR method.\n * @see {@link https://onlinelibrary.wiley.com/doi/10.1111/j.1469-1809.1936.tb02137.x}\n */\n constructor(X: T, parameters: Partial & {\n labels: any[] | Float64Array;\n });\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T} - The projected data.\n */\n transform(): T;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersLDA } from \"./index.js\";\nimport { DR } from \"./DR.js\";\n//# sourceMappingURL=LDA.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLLE} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n/**\n * Locally Linear Embedding (LLE)\n *\n * A nonlinear dimensionality reduction technique that preserves local\n * linear relationships between points. It represents each point as a linear\n * combination of its neighbors.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link ISOMAP} for another nonlinear alternative\n */\nexport class LLE extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X: T_1, parameters: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static generator(X: T_1, parameters: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters: Partial): Promise;\n /**\n * Locally Linear Embedding.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://doi.org/10.1126/science.290.5500.2323}\n */\n constructor(X: T, parameters: Partial);\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T}\n */\n transform(): T;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersLLE } from \"./index.js\";\nimport { DR } from \"./DR.js\";\n//# sourceMappingURL=LLE.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLSP} from \"./index.js\" */\n/**\n * Least Square Projection (LSP)\n *\n * A dimensionality reduction technique that uses a small set of control points\n * (projected with MDS) to define the projection for the rest of the data\n * using a Laplacian-based optimization.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class LSP extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * Least Squares Projection.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n * @see {@link https://ieeexplore.ieee.org/document/4378370}\n */\n constructor(X: T, parameters?: Partial);\n /**\n * @returns {LSP}\n */\n init(): LSP;\n _A: Matrix | undefined;\n _b: Matrix | undefined;\n /**\n * Computes the projection.\n *\n * @returns {T} Returns the projection.\n */\n transform(): T;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersLSP } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=LSP.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLTSA} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n/**\n * Local Tangent Space Alignment (LTSA)\n *\n * A nonlinear dimensionality reduction algorithm that represents the local\n * geometry of the manifold by tangent spaces and then aligns them to reveal\n * the global structure.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class LTSA extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X: T_1, parameters: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static generator(X: T_1, parameters: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters: Partial): Promise;\n /**\n * Local Tangent Space Alignment\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://epubs.siam.org/doi/abs/10.1137/S1064827502419154}\n */\n constructor(X: T, parameters: Partial);\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * Transforms the inputdata `X` to dimenionality `d`.\n *\n * @returns {T}\n */\n transform(): T;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersLTSA } from \"./index.js\";\nimport { DR } from \"./DR.js\";\n//# sourceMappingURL=LTSA.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersMDS} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n/**\n * Classical Multidimensional Scaling (MDS)\n *\n * A linear dimensionality reduction technique that seeks to preserve the\n * pairwise distances between points as much as possible in the lower-dimensional\n * space.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link PCA} for another linear alternative\n */\nexport class MDS extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * Classical MDS.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X: T, parameters?: Partial);\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T}\n */\n transform(): T;\n _d_X: Matrix | undefined;\n /** @returns {number} - The stress of the projection. */\n stress(): number;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersMDS } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=MDS.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersPCA} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n/**\n * Principal Component Analysis (PCA)\n *\n * A linear dimensionality reduction technique that identifies the axes (principal components)\n * along which the variance of the data is maximized.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link MDS} for another linear alternative\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2], [3, 4], [5, 6]];\n * const pca = new druid.PCA(X, { d: 2 });\n * const Y = pca.transform();\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class PCA extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X: T_1, parameters: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Matrix}\n */\n static principal_components(X: T_1, parameters: Partial): Matrix;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X: T, parameters?: Partial);\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T} - The projected data.\n */\n transform(): T;\n /**\n * Computes the `d` principal components of Matrix `X`.\n *\n * @returns {Matrix}\n */\n principal_components(): Matrix;\n V: Matrix | undefined;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersPCA } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=PCA.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersPCA, ParametersMDS, ParametersSAMMON} from \"./index.js\" */\n/** @typedef {\"PCA\" | \"MDS\" | \"random\"} AvailableInit */\n/** @typedef {{ PCA: ParametersPCA; MDS: ParametersMDS; random: {} }} ChooseDR */\n/**\n * Sammon's Mapping\n *\n * A nonlinear dimensionality reduction technique that minimizes a stress\n * function based on the ratio of pairwise distances in high and low dimensional spaces.\n *\n * @class\n * @template {InputType} T\n * @extends DR>\n * @category Dimensionality Reduction\n */\nexport class SAMMON extends DR> {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial>} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial>): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial>} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial>): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial>} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial>): Promise;\n /**\n * SAMMON's Mapping\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial>} [parameters] - Object containing parameterization of the DR\n * method.\n * @see {@link https://arxiv.org/pdf/2009.01512.pdf}\n */\n constructor(X: T, parameters?: Partial>);\n /** @type {Matrix | undefined} */\n distance_matrix: Matrix | undefined;\n /**\n * Initializes the projection.\n *\n * @param {Matrix | undefined} D\n * @returns {asserts D is Matrix}\n */\n init(D: Matrix | undefined): asserts D is Matrix;\n /**\n * Transforms the inputdata `X` to dimensionality 2.\n *\n * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200`\n * @returns {T} The projection of `X`.\n */\n transform(max_iter?: number): T;\n /**\n * Transforms the inputdata `X` to dimenionality 2.\n *\n * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200`\n * @returns {Generator} A generator yielding the intermediate steps of the projection of\n * `X`.\n */\n generator(max_iter?: number): Generator;\n _step(): Matrix;\n}\nexport type AvailableInit = \"PCA\" | \"MDS\" | \"random\";\nexport type ChooseDR = {\n PCA: ParametersPCA;\n MDS: ParametersMDS;\n random: {};\n};\nimport type { InputType } from \"../index.js\";\nimport type { ParametersSAMMON } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport type { ParametersPCA } from \"./index.js\";\nimport type { ParametersMDS } from \"./index.js\";\n//# sourceMappingURL=SAMMON.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersSMACOF} from \"./index.js\" */\n/**\n * Metric Multidimensional Scaling (MDS) via SMACOF.\n *\n * SMACOF (Scaling by Majorizing a Complicated Function) is an iterative majorization\n * algorithm for solving metric multidimensional scaling problems, which aims to\n * minimize the stress function.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link MDS} for the classical approach.\n */\nexport class SMACOF extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * SMACOF for MDS.\n *\n * @param {T} X - The high-dimensional data or precomputed distance matrix.\n * @param {Partial} [parameters] - Object containing parameterization.\n */\n constructor(X: T, parameters?: Partial);\n /**\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n generator(): Generator;\n /**\n * @returns {T}\n */\n transform(): T;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersSMACOF } from \"./index.js\";\nimport { DR } from \"./DR.js\";\n//# sourceMappingURL=SMACOF.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersSQDMDS} from \"./index.js\" */\n/**\n * SQuadMDS (Stochastic Quartet MDS)\n *\n * A lean Stochastic Quartet MDS improving global structure preservation in\n * neighbor embedding like t-SNE and UMAP.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class SQDMDS extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * SQuadMDS: a lean Stochastic Quartet MDS improving global structure preservation in neighbor embedding like t-SNE\n * and UMAP.\n *\n * @param {T} X\n * @param {Partial} [parameters]\n * @see {@link https://arxiv.org/pdf/2202.12087.pdf}\n */\n constructor(X: T, parameters?: Partial);\n init(): void;\n _add: ((...summands: Float64Array[]) => Float64Array) | undefined;\n _sub_div: ((x: Float64Array, y: Float64Array, div: number) => Float64Array) | undefined;\n _minus: ((a: Float64Array, b: Float64Array) => Float64Array) | undefined;\n _mult: ((a: Float64Array, v: number) => Float64Array) | undefined;\n _LR_init: number | undefined;\n _LR: number | undefined;\n _offset: number | undefined;\n _momentums: Matrix | undefined;\n _grads: Matrix | undefined;\n _indices: number[] | undefined;\n /** @type {(i: number, j: number, X: Matrix) => number} */\n _HD_metric: ((i: number, j: number, X: Matrix) => number) | undefined;\n /** @type {(i: number, j: number, X: Matrix) => number} */\n _HD_metric_exaggeration: ((i: number, j: number, X: Matrix) => number) | undefined;\n /**\n * Computes the projection.\n *\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {T} The projection.\n */\n transform(iterations?: number): T;\n _decay_start: number | undefined;\n /**\n * Computes the projection.\n *\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {Generator} The intermediate steps of the projection.\n */\n generator(iterations?: number): Generator;\n /**\n * Performs an optimization step.\n *\n * @private\n * @param {number} i - Acutal iteration.\n * @param {number} iterations - Number of iterations.\n */\n private _step;\n _distance_exaggeration: boolean | undefined;\n /**\n * Creates quartets of non overlapping indices.\n *\n * @private\n * @returns {Uint32Array[]}\n */\n private __quartets;\n /**\n * Computes and applies gradients, and updates momentum.\n *\n * @private\n * @param {boolean} distance_exaggeration\n */\n private _nestrov_iteration;\n /**\n * Computes the gradients.\n *\n * @param {Matrix} Y - The Projection.\n * @param {Matrix} grads - The gradients.\n * @param {boolean} [exaggeration=false] - Whether or not to use early exaggeration. Default is `false`\n * @param {boolean} [zero_grad=true] - Whether or not to reset the gradient in the beginning. Default is `true`\n * @returns {Matrix} The gradients.\n */\n _fill_MDS_grads(Y: Matrix, grads: Matrix, exaggeration?: boolean, zero_grad?: boolean): Matrix;\n /**\n * Quartet gradients for a projection.\n *\n * @private\n * @param {Matrix} Y - The acutal projection.\n * @param {number[]} quartet - The indices of the quartet.\n * @param {Float64Array} D_hd - The high-dimensional distances of the quartet.\n * @returns {Float64Array[]} The gradients for the quartet.\n */\n private _compute_quartet_grads;\n /**\n * Gradients for one element of the loss function's sum.\n *\n * @private\n * @param {Float64Array} a\n * @param {Float64Array} b\n * @param {Float64Array} c\n * @param {Float64Array} d\n * @param {number} d_ab\n * @param {number} d_ac\n * @param {number} d_ad\n * @param {number} d_bc\n * @param {number} d_bd\n * @param {number} d_cd\n * @param {number} p_ab\n * @param {number} sum_LD_dist\n * @returns {Float64Array[]}\n */\n private _ABCD_grads;\n /**\n * Inline!\n *\n * @param {number} d\n */\n __minus(d: number): (a: Float64Array, b: Float64Array) => Float64Array;\n /**\n * Inline!\n *\n * @param {number} d\n */\n __add(d: number): (...summands: Float64Array[]) => Float64Array;\n /**\n * Inline!\n *\n * @param {number} d\n */\n __mult(d: number): (a: Float64Array, v: number) => Float64Array;\n /**\n * Creates a new array `(x - y) / div`.\n *\n * @param {number} d\n */\n __sub_div(d: number): (x: Float64Array, y: Float64Array, div: number) => Float64Array;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersSQDMDS } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=SQDMDS.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersTopoMap} from \"./index.js\" */\n/**\n * TopoMap\n *\n * A 0-dimensional Homology Preserving Projection of High-Dimensional Data.\n * It aims to preserve the topological structure of the data by maintaining\n * the connectivity of a minimum spanning tree.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class TopoMap extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X: T_1, parameters: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static generator(X: T_1, parameters: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters: Partial): Promise;\n /**\n * TopoMap: A 0-dimensional Homology Preserving Projection of High-Dimensional Data.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://arxiv.org/pdf/2009.01512.pdf}\n */\n constructor(X: T, parameters: Partial);\n _distance_matrix: Matrix;\n /**\n * @private\n * @param {number} i\n * @param {number} j\n * @param {import(\"../metrics/index.js\").Metric} metric\n * @returns {number}\n */\n private __lazy_distance_matrix;\n /**\n * Computes the minimum spanning tree, using a given metric\n *\n * @private\n * @param {import(\"../metrics/index.js\").Metric} metric\n * @see {@link https://en.wikipedia.org/wiki/Kruskal%27s_algorithm}\n */\n private _make_minimum_spanning_tree;\n _disjoint_set: DisjointSet> | undefined;\n /** Initializes TopoMap. Sets all projcted points to zero, and computes a minimum spanning tree. */\n init(): this;\n _Emst: number[][] | undefined;\n /**\n * Returns true if Point C is left of line AB.\n *\n * @private\n * @param {Float64Array} PointA - Point A of line AB\n * @param {Float64Array} PointB - Point B of line AB\n * @param {Float64Array} PointC - Point C\n * @returns {boolean}\n */\n private __hull_cross;\n /**\n * Computes the convex hull of the set of Points S\n *\n * @private\n * @param {Float64Array[]} S - Set of Points.\n * @returns {Float64Array[]} Convex hull of S. Starts at the bottom-most point and continues counter-clockwise.\n * @see {@link https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain#JavaScript}\n */\n private __hull;\n /**\n * Finds the angle to rotate Point A and B to lie on a line parallel to the x-axis.\n *\n * @private\n * @param {Float64Array} PointA\n * @param {Float64Array} PointB\n * @returns {{ sin: number; cos: number }} Object containing the sinus- and cosinus-values for a rotation.\n */\n private __findAngle;\n /**\n * @private\n * @param {Float64Array[]} hull\n * @param {Float64Array} p\n * @param {boolean} topEdge\n * @returns {{ sin: number; cos: number; tx: number; ty: number }}\n */\n private __align_hull;\n /**\n * @private\n * @param {Float64Array} Point - The point which should get transformed.\n * @param {{ sin: number; cos: number; tx: number; ty: number }} Transformation - Contains the values for\n * translation and rotation.\n */\n private __transform;\n /**\n * Calls `__transform` for each point in Set C\n *\n * @private\n * @param {Float64Array[]} C - Set of points.\n * @param {{ sin: number; cos: number; tx: number; ty: number }} t - Transform object.\n * @param {number} yOffset - Value to offset set C.\n */\n private __transform_component;\n /**\n * @private\n * @param {Float64Array} root_u - Root of component u\n * @param {Float64Array} root_v - Root of component v\n * @param {Float64Array} p_u - Point u\n * @param {Float64Array} p_v - Point v\n * @param {number} w - Edge weight w\n * @param {DisjointSet} components - The disjoint set containing the components\n */\n private __align_components;\n /**\n * Transforms the inputdata `X` to dimensionality 2.\n *\n * @returns {T}\n */\n transform(): T;\n /**\n * Transforms the inputdata `X` to dimensionality 2.\n *\n * @returns {Generator}\n */\n generator(): Generator;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersTopoMap } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { DisjointSet } from \"../datastructure/index.js\";\n//# sourceMappingURL=TopoMap.d.ts.map","/**\n * Base class for all K-Nearest Neighbors (KNN) search algorithms.\n *\n * Provides a common interface for elements management and search operations.\n *\n * @abstract\n * @category KNN\n * @template {number[] | Float64Array} T - Type of elements\n * @template {Object} Para - Type of parameters\n * @class\n */\nexport class KNN {\n /**\n * @param {T[]} elements\n * @param {Para} parameters\n */\n constructor(elements: T[], parameters: Para);\n /** @type {T[]} */\n _elements: T[];\n /** @type {Para} */\n _parameters: Para;\n /** @type {\"typed\" | \"array\"} */\n _type: \"typed\" | \"array\";\n /**\n * @abstract\n * @param {T} t\n * @param {number} k\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search(t: T, k: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @abstract\n * @param {number} i\n * @param {number} k\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i: number, k: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n}\n//# sourceMappingURL=KNN.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersTriMap} from \"./index.js\" */\n/** @import {KNN} from \"../knn/KNN.js\" */\n/**\n * TriMap\n *\n * A dimensionality reduction technique that preserves both local and global\n * structure using triplets. It is designed to be a more robust alternative\n * to t-SNE and UMAP.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class TriMap extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n * @see {@link https://arxiv.org/pdf/1910.00204v1.pdf}\n * @see {@link https://github.com/eamid/trimap}\n */\n constructor(X: T, parameters?: Partial);\n /**\n * @param {Matrix | null} [pca=null] - Initial Embedding (if null then PCA gets used). Default is `null`\n * @param {import(\"../knn/KNN.js\").KNN | null} [knn=null] - KNN Object (if null then BallTree gets used). Default is `null`\n */\n init(pca?: Matrix | null, knn?: import(\"../knn/KNN.js\").KNN | null): this;\n n_inliers: number | undefined;\n n_outliers: number | undefined;\n n_random: number | undefined;\n knn: KNN, any> | undefined;\n triplets: Matrix | undefined;\n weights: Float64Array | undefined;\n lr: number | undefined;\n C: number | undefined;\n vel: Matrix | undefined;\n gain: Matrix | undefined;\n /**\n * Generates {@link n_inliers} x {@link n_outliers} x {@link n_random} triplets.\n *\n * @param {number} n_inliers\n * @param {number} n_outliers\n * @param {number} n_random\n */\n _generate_triplets(n_inliers: number, n_outliers: number, n_random: number): {\n triplets: Matrix;\n weights: Float64Array;\n };\n /**\n * Calculates the similarity matrix P\n *\n * @private\n * @param {Matrix} knn_distances - Matrix of pairwise knn distances\n * @param {Float64Array} sig - Scaling factor for the distances\n * @param {Matrix} nbrs - Nearest neighbors\n * @returns {Matrix} Pairwise similarity matrix\n */\n private _find_p;\n /**\n * Sample nearest neighbors triplets based on the similarity values given in P.\n *\n * @private\n * @param {Matrix} P - Matrix of pairwise similarities between each point and its neighbors given in matrix nbrs.\n * @param {Matrix} nbrs - Nearest neighbors indices for each point. The similarity values are given in matrix\n * {@link P}. Row i corresponds to the i-th point.\n * @param {number} n_inliers - Number of inlier points.\n * @param {number} n_outliers - Number of outlier points.\n */\n private _sample_knn_triplets;\n /**\n * Should do the same as np.argsort()\n *\n * @private\n * @param {Float64Array | number[]} A\n */\n private __argsort;\n /**\n * Samples {@link n_samples} integers from a given interval [0, {@link max_int}] while rejection the values that are\n * in the {@link rejects}.\n *\n * @private\n * @param {number} n_samples\n * @param {number} max_int\n * @param {number[]} rejects\n */\n private _rejection_sample;\n /**\n * Calculates the weights for the sampled nearest neighbors triplets\n *\n * @private\n * @param {Matrix} triplets - Sampled Triplets.\n * @param {Matrix} P - Pairwise similarity matrix.\n * @param {Matrix} nbrs - Nearest Neighbors\n * @param {Float64Array} outlier_distances - Matrix of pairwise outlier distances\n * @param {Float64Array} sig - Scaling factor for the distances.\n */\n private _find_weights;\n /**\n * Sample uniformly ranom triplets\n *\n * @private\n * @param {Matrix} X - Data matrix.\n * @param {number} n_random - Number of random triplets per point\n * @param {Float64Array} sig - Scaling factor for the distances\n */\n private _sample_random_triplets;\n /**\n * Computes the gradient for updating the embedding.\n *\n * @param {Matrix} Y - The embedding\n */\n _grad(Y: Matrix): {\n grad: Matrix;\n loss: number;\n n_viol: number;\n };\n /**\n * @param {number} max_iteration\n * @returns {T}\n */\n transform(max_iteration?: number): T;\n /**\n * @param {number} max_iteration\n * @returns {Generator}\n */\n generator(max_iteration?: number): Generator;\n /**\n * Does the iteration step.\n *\n * @private\n * @param {number} iter\n */\n private _next;\n /**\n * Updates the embedding.\n *\n * @private\n * @param {Matrix} Y\n * @param {number} iter\n * @param {Matrix} grad\n */\n private _update_embedding;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersTriMap } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport type { KNN } from \"../knn/KNN.js\";\n//# sourceMappingURL=TriMap.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersTSNE} from \"./index.js\" */\n/**\n * t-SNE (t-Distributed Stochastic Neighbor Embedding)\n *\n * A nonlinear dimensionality reduction technique particularly well-suited\n * for visualizing high-dimensional data in 2D or 3D. Preserves local\n * structure while revealing global patterns.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link https://lvdmaaten.github.io/tsne/|t-SNE Paper}\n * @see {@link UMAP} for faster alternative with similar results\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];\n * const tsne = new druid.TSNE(X, {\n * perplexity: 30,\n * epsilon: 10,\n * d: 2,\n * seed: 42\n * });\n *\n * const Y = tsne.transform(500); // 500 iterations\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class TSNE extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X: T, parameters?: Partial);\n _iter: number;\n init(): this;\n _ystep: Matrix | undefined;\n _gains: Matrix | undefined;\n _P: Matrix | undefined;\n /**\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {T} The projection.\n */\n transform(iterations?: number): T;\n /**\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {Generator} - The projection.\n */\n generator(iterations?: number): Generator;\n /**\n * Performs a optimization step\n *\n * @private\n * @returns {Matrix}\n */\n private next;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersTSNE } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=TSNE.d.ts.map","/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersUMAP} from \"./index.js\" */\n/**\n * Uniform Manifold Approximation and Projection (UMAP)\n *\n * A novel manifold learning technique for dimensionality reduction. UMAP is constructed\n * from a theoretical framework based on Riemannian geometry and algebraic topology.\n * It is often faster than t-SNE while preserving more of the global structure.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link https://arxiv.org/abs/1802.03426|UMAP Paper}\n * @see {@link TSNE} for a similar visualization technique\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];\n * const umap = new druid.UMAP(X, {\n * n_neighbors: 15,\n * min_dist: 0.1,\n * d: 2,\n * seed: 42\n * });\n *\n * const Y = umap.transform(500); // 500 iterations\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class UMAP extends DR {\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X: T_1, parameters?: Partial): T_1;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static generator(X: T_1, parameters?: Partial): Generator;\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static transform_async(X: T_1, parameters?: Partial): Promise;\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X: T, parameters?: Partial);\n _iter: number;\n /**\n * @private\n * @param {number} spread\n * @param {number} min_dist\n * @returns {number[]}\n */\n private _find_ab_params;\n /**\n * @private\n * @param {{ element: Float64Array; index: number; distance: number }[][]} distances\n * @param {number[]} sigmas\n * @param {number[]} rhos\n * @returns {{ element: Float64Array; index: number; distance: number }[][]}\n */\n private _compute_membership_strengths;\n /**\n * @private\n * @param {NaiveKNN | BallTree} knn\n * @param {number} k\n * @returns {{\n * distances: { element: Float64Array; index: number; distance: number }[][];\n * sigmas: number[];\n * rhos: number[];\n * }}\n */\n private _smooth_knn_dist;\n /**\n * @private\n * @param {Matrix} X\n * @param {number} n_neighbors\n * @returns {Matrix}\n */\n private _fuzzy_simplicial_set;\n /**\n * @private\n * @param {number} n_epochs\n * @returns {Float32Array}\n */\n private _make_epochs_per_sample;\n /**\n * @private\n * @param {Matrix} graph\n * @returns {{ rows: number[]; cols: number[]; data: number[] }}\n */\n private _tocoo;\n /**\n * Computes all necessary\n *\n * @returns {UMAP}\n */\n init(): UMAP;\n _a: number | undefined;\n _b: number | undefined;\n _graph: Matrix | undefined;\n _head: number[] | undefined;\n _tail: number[] | undefined;\n _weights: number[] | undefined;\n _epochs_per_sample: Float32Array | undefined;\n _epochs_per_negative_sample: Float32Array | undefined;\n _epoch_of_next_sample: Float32Array | undefined;\n _epoch_of_next_negative_sample: Float32Array | undefined;\n graph(): {\n cols: number[] | undefined;\n rows: number[] | undefined;\n weights: number[] | undefined;\n };\n /**\n * @param {number} [iterations=350] - Number of iterations. Default is `350`\n * @returns {T}\n */\n transform(iterations?: number): T;\n /**\n * @param {number} [iterations=350] - Number of iterations. Default is `350`\n * @returns {Generator}\n */\n generator(iterations?: number): Generator;\n /**\n * @private\n * @param {number} x\n * @returns {number}\n */\n private _clip;\n /**\n * Performs the optimization step.\n *\n * @private\n * @param {Matrix} head_embedding\n * @param {Matrix} tail_embedding\n * @param {number[]} head\n * @param {number[]} tail\n * @returns {Matrix}\n */\n private _optimize_layout;\n /**\n * @private\n * @returns {Matrix}\n */\n private next;\n _alpha: number | undefined;\n}\nimport type { InputType } from \"../index.js\";\nimport type { ParametersUMAP } from \"./index.js\";\nimport { DR } from \"./DR.js\";\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=UMAP.d.ts.map","/**\n * Computes the inner product between two arrays of the same length.\n *\n * @category Linear Algebra\n * @param {number[] | Float64Array} a - Array a.\n * @param {number[] | Float64Array} b - Array b.\n * @returns The inner product between `a` and `b`.\n */\nexport function inner_product(a: number[] | Float64Array, b: number[] | Float64Array): number;\n//# sourceMappingURL=inner_product.d.ts.map","/**\n * Computes the QR Decomposition of the Matrix `A` using Gram-Schmidt process.\n *\n * @category Linear Algebra\n * @param {Matrix} A\n * @returns {{ R: Matrix; Q: Matrix }}\n * @see {@link https://en.wikipedia.org/wiki/QR_decomposition#Using_the_Gram%E2%80%93Schmidt_process}\n */\nexport function qr(A: Matrix): {\n R: Matrix;\n Q: Matrix;\n};\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=qr.d.ts.map","/**\n * Computes the QR Decomposition of the Matrix `A` with householder transformations.\n *\n * @category Linear Algebra\n * @param {Matrix} A\n * @returns {{ R: Matrix; Q: Matrix }}\n * @see {@link https://en.wikipedia.org/wiki/QR_decomposition#Using_Householder_reflections}\n * @see {@link http://mlwiki.org/index.php/Householder_Transformation}\n */\nexport function qr_householder(A: Matrix): {\n R: Matrix;\n Q: Matrix;\n};\nimport { Matrix } from \"../matrix/index.js\";\n//# sourceMappingURL=qr_householder.d.ts.map","/** @import { EigenArgs } from \"./index.js\" */\n/**\n * Computes the `k` biggest Eigenvectors and Eigenvalues from Matrix `A` with the QR-Algorithm.\n *\n * @category Linear Algebra\n * @param {Matrix} A - The Matrix\n * @param {number} k - The number of eigenvectors and eigenvalues to compute.\n * @param {EigenArgs} parameters - Object containing parameterization of the simultanious\n * poweriteration method.\n * @returns {{ eigenvalues: Float64Array; eigenvectors: Float64Array[] }} The `k` biggest eigenvectors and eigenvalues\n * of Matrix `A`.\n */\nexport function simultaneous_poweriteration(A: Matrix, k?: number, { seed, max_iterations, qr, tol }?: EigenArgs): {\n eigenvalues: Float64Array;\n eigenvectors: Float64Array[];\n};\nimport { Matrix } from \"../matrix/index.js\";\nimport type { EigenArgs } from \"./index.js\";\n//# sourceMappingURL=simultaneous_poweriteration.d.ts.map","export { inner_product } from \"./inner_product.js\";\nexport { qr } from \"./qr.js\";\nexport { qr_householder } from \"./qr_householder.js\";\nexport { simultaneous_poweriteration } from \"./simultaneous_poweriteration.js\";\nexport type QRDecomposition = (A: import(\"../matrix/index.js\").Matrix) => {\n R: import(\"../matrix/index.js\").Matrix;\n Q: import(\"../matrix/index.js\").Matrix;\n};\nexport type EigenArgs = {\n /**\n * - The number of maxiumum iterations the algorithm should run. Default is `100`\n */\n max_iterations?: number | undefined;\n /**\n * - The seed value or a randomizer used in the algorithm. Default is `1212`\n */\n seed?: number | Randomizer | undefined;\n /**\n * - The QR technique to use. Default is `qr_gramschmidt`\n */\n qr?: QRDecomposition | undefined;\n /**\n * - Tolerated error for stopping criteria. Default is `1e-8`\n */\n tol?: number | undefined;\n};\nimport type { Randomizer } from \"../util/index.js\";\n//# sourceMappingURL=index.d.ts.map","export { FASTMAP } from \"./FASTMAP.js\";\nexport { LocalMAP } from \"./LocalMAP.js\";\nexport { PaCMAP } from \"./PaCMAP.js\";\nexport { ISOMAP } from \"./ISOMAP.js\";\nexport { LDA } from \"./LDA.js\";\nexport { LLE } from \"./LLE.js\";\nexport { LSP } from \"./LSP.js\";\nexport { LTSA } from \"./LTSA.js\";\nexport { MDS } from \"./MDS.js\";\nexport { PCA } from \"./PCA.js\";\nexport { SAMMON } from \"./SAMMON.js\";\nexport { SMACOF } from \"./SMACOF.js\";\nexport { SQDMDS } from \"./SQDMDS.js\";\nexport { TopoMap } from \"./TopoMap.js\";\nexport { TriMap } from \"./TriMap.js\";\nexport { TSNE } from \"./TSNE.js\";\nexport { UMAP } from \"./UMAP.js\";\nexport type ParametersLSP = {\n /**\n * - number of neighbors to consider.\n */\n neighbors?: number | undefined;\n /**\n * - number of controlpoints\n */\n control_points?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersFASTMAP = {\n /**\n * - The dimensionality of the projection\n */\n d?: number | undefined;\n /**\n * - The metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - The seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersISOMAP = {\n /**\n * - The number of neighbors ISOMAP should use to project the data.\n */\n neighbors?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - Whether to use classical MDS or SMACOF for the final DR.\n */\n project?: \"MDS\" | \"SMACOF\" | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n /**\n * - Parameters for the eigendecomposition algorithm.\n */\n eig_args?: Partial | undefined;\n};\nexport type ParametersLDA = {\n /**\n * - The labels / classes for each data point.\n */\n labels: any[] | Float64Array;\n /**\n * - The dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - The seed for the random number generator.\n */\n seed?: number | undefined;\n /**\n * - Parameters for the eigendecomposition algorithm.\n */\n eig_args?: Partial | undefined;\n};\nexport type ParametersLLE = {\n /**\n * - The number of neighbors for LLE.\n */\n neighbors?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n /**\n * - Parameters for the eigendecomposition algorithm.\n */\n eig_args?: Partial | undefined;\n};\nexport type ParametersLTSA = {\n /**\n * - The number of neighbors for LTSA.\n */\n neighbors?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n /**\n * - Parameters for the eigendecomposition algorithm.\n */\n eig_args?: Partial | undefined;\n};\nexport type ParametersMDS = {\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | \"precomputed\" | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n /**\n * - Parameters for the eigendecomposition algorithm.\n */\n eig_args?: Partial | undefined;\n};\nexport type ParametersPCA = {\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n /**\n * - Parameters for the eigendecomposition algorithm.\n */\n eig_args?: Partial | undefined;\n};\nexport type ParametersSAMMON = {\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | \"precomputed\" | undefined;\n /**\n * - Either \"PCA\" or \"MDS\", with which SAMMON initialiates the projection.\n */\n init_DR?: K | undefined;\n /**\n * - Parameters for the \"init\"-DR method.\n */\n init_parameters?: ChooseDR[K] | undefined;\n /**\n * - learning rate for gradient descent.\n */\n magic?: number | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersSMACOF = {\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | \"precomputed\" | undefined;\n /**\n * - maximum number of iterations.\n */\n iterations?: number | undefined;\n /**\n * - tolerance for stress difference.\n */\n epsilon?: number | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersSQDMDS = {\n d?: number | undefined;\n metric?: Metric | \"precomputed\" | undefined;\n /**\n * - Percentage of iterations using exaggeration phase.\n */\n decay_start?: number | undefined;\n /**\n * - Controls the decay of the learning parameter.\n */\n decay_cte?: number | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersTopoMap = {\n /**\n * = euclidean - The metric which defines the distance between\n * two points.\n */\n metric: Metric;\n /**\n * = 1212 - The seed for the random number generator.\n */\n seed: number;\n};\nexport type ParametersTriMap = {\n /**\n * - scaling factor.\n */\n weight_adj?: number | undefined;\n /**\n * - number of inliers.\n */\n n_inliers?: number | undefined;\n /**\n * - number of outliers.\n */\n n_outliers?: number | undefined;\n /**\n * - number of random points.\n */\n n_random?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n tol?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersTSNE = {\n /**\n * - perplexity.\n */\n perplexity?: number | undefined;\n /**\n * - learning parameter.\n */\n epsilon?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points.\n */\n metric?: Metric | \"precomputed\" | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersPaCMAP = {\n /**\n * - Number of nearest neighbors for NN pairs.\n */\n n_neighbors?: number | undefined;\n /**\n * - Ratio of mid-near pairs to n_neighbors.\n */\n MN_ratio?: number | undefined;\n /**\n * - Ratio of further pairs to n_neighbors.\n */\n FP_ratio?: number | undefined;\n /**\n * - The dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - The metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - Learning rate for the Adam optimizer.\n */\n lr?: number | undefined;\n /**\n * - Number of iterations for each of the three phases.\n */\n num_iters?: number[] | undefined;\n /**\n * - The seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersLocalMAP = {\n /**\n * - Number of nearest neighbors for NN pairs.\n */\n n_neighbors?: number | undefined;\n /**\n * - Ratio of mid-near pairs to n_neighbors.\n */\n MN_ratio?: number | undefined;\n /**\n * - Ratio of further pairs to n_neighbors.\n */\n FP_ratio?: number | undefined;\n /**\n * - The dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - The metric which defines the distance between two points.\n */\n metric?: Metric | undefined;\n /**\n * - Learning rate for the Adam optimizer.\n */\n lr?: number | undefined;\n /**\n * - Number of iterations for each of the three phases.\n */\n num_iters?: number[] | undefined;\n /**\n * - Distance threshold for local FP pair resampling in phase 3.\n */\n low_dist_thres?: number | undefined;\n /**\n * - The seed for the random number generator.\n */\n seed?: number | undefined;\n};\nexport type ParametersUMAP = {\n /**\n * - size of the local neighborhood.\n */\n n_neighbors?: number | undefined;\n /**\n * - number of nearest neighbors connected in the local neighborhood.\n */\n local_connectivity?: number | undefined;\n /**\n * - controls how tightly points get packed together.\n */\n min_dist?: number | undefined;\n /**\n * - the dimensionality of the projection.\n */\n d?: number | undefined;\n /**\n * - the metric which defines the distance between two points in the high-dimensional space.\n */\n metric?: Metric | \"precomputed\" | undefined;\n /**\n * - The effective scale of embedded points.\n */\n _spread?: number | undefined;\n /**\n * - Interpolate between union and intersection.\n */\n _set_op_mix_ratio?: number | undefined;\n /**\n * - Weighting applied to negative samples.\n */\n _repulsion_strength?: number | undefined;\n /**\n * - The number of negative samples per positive sample.\n */\n _negative_sample_rate?: number | undefined;\n /**\n * - The number of training epochs.\n */\n _n_epochs?: number | undefined;\n /**\n * - The initial learning rate for the optimization.\n */\n _initial_alpha?: number | undefined;\n /**\n * - the seed for the random number generator.\n */\n seed?: number | undefined;\n};\nimport type { Metric } from \"../metrics/index.js\";\nimport type { EigenArgs } from \"../linear_algebra/index.js\";\nimport type { ChooseDR } from \"./SAMMON.js\";\n//# sourceMappingURL=index.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersAnnoy } from \"./index.js\" */\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} AnnoyNode\n * @property {boolean} isLeaf - Whether this is a leaf node\n * @property {number[]} indices - Indices of points in this node (leaf) or children (internal)\n * @property {number[]} normal - Hyperplane normal vector (internal nodes only)\n * @property {number} offset - Hyperplane offset (internal nodes only)\n * @property {AnnoyNode | null} left - Left child (internal nodes only)\n * @property {AnnoyNode | null} right - Right child (internal nodes only)\n */\n/**\n * Annoy-style (Approximate Nearest Neighbors Oh Yeah) implementation using Random Projection Trees.\n *\n * This implementation builds multiple random projection trees where each tree randomly selects\n * two points and splits the space based on a hyperplane equidistant between them.\n *\n * Key features:\n * - Multiple random projection trees for better recall\n * - Each tree uses random hyperplanes for splitting\n * - Priority queue search for better recall\n * - Combines results from all trees\n *\n * Best suited for:\n * - High-dimensional data\n * - Approximate nearest neighbor search\n * - Large datasets\n * - When high recall is needed with approximate methods\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link https://github.com/spotify/annoy}\n * @see {@link https://erikbern.com/2015/09/24/nearest-neighbors-and-vector-models-epilogue-curse-of-dimensionality.html}\n */\nexport class Annoy extends KNN {\n /**\n * Creates a new Annoy-style index with random projection trees.\n *\n * @param {T[]} elements - Elements to index\n * @param {ParametersAnnoy} [parameters={}] - Configuration parameters\n */\n constructor(elements: T[], parameters?: ParametersAnnoy);\n _metric: Metric;\n _numTrees: number;\n _maxPointsPerLeaf: number;\n _seed: number;\n _randomizer: Randomizer;\n /**\n * @private\n * @type {AnnoyNode[]}\n */\n private _trees;\n /**\n * Get the number of trees in the index.\n * @returns {number}\n */\n get num_trees(): number;\n /**\n * Get the total number of nodes in all trees.\n * @returns {number}\n */\n get num_nodes(): number;\n /**\n * @private\n * @param {any} node\n * @returns {number}\n */\n private _countNodes;\n /**\n * Add elements to the Annoy index.\n * @param {T[]} elements\n * @returns {this}\n */\n add(elements: T[]): this;\n /**\n * Build all random projection trees.\n * @private\n */\n private _buildTrees;\n /**\n * Recursively build a random projection tree.\n * @private\n * @param {number[]} indices - Indices of elements to include\n * @returns {AnnoyNode}\n */\n private _buildTreeRecursive;\n /**\n * Compute distance from point to hyperplane.\n * @private\n * @param {T} point\n * @param {number[]} normal\n * @param {number} offset\n * @returns {number} Signed distance (positive = right side, negative = left side)\n */\n private _distanceToHyperplane;\n /**\n * Search for k approximate nearest neighbors.\n * @param {T} query\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search(query: T, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * Search tree using priority queue for better recall.\n * Explores nodes in order of distance to hyperplane.\n * @private\n * @param {AnnoyNode} node\n * @param {T} query\n * @param {Set} candidates\n * @param {number} maxCandidates\n */\n private _searchTreePriority;\n /**\n * @param {number} i\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * Alias for search_by_index for backward compatibility.\n *\n * @param {number} i - Index of the query element\n * @param {number} [k=5] - Number of nearest neighbors to return\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n}\nexport type AnnoyNode = {\n /**\n * - Whether this is a leaf node\n */\n isLeaf: boolean;\n /**\n * - Indices of points in this node (leaf) or children (internal)\n */\n indices: number[];\n /**\n * - Hyperplane normal vector (internal nodes only)\n */\n normal: number[];\n /**\n * - Hyperplane offset (internal nodes only)\n */\n offset: number;\n /**\n * - Left child (internal nodes only)\n */\n left: AnnoyNode | null;\n /**\n * - Right child (internal nodes only)\n */\n right: AnnoyNode | null;\n};\nimport type { ParametersAnnoy } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport type { Metric } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\n//# sourceMappingURL=Annoy.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersBallTree } from \"./index.js\" */\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} ElementWithIndex\n * @property {number} index\n * @property {T} element\n */\n/**\n * Ball Tree for efficient nearest neighbor search.\n *\n * A Ball Tree is a metric tree that partitions points into a nested set of\n * hyperspheres (balls). It is particularly effective for high-dimensional\n * data and supports any valid metric.\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n */\nexport class BallTree extends KNN {\n /**\n * Generates a BallTree with given `elements`.\n *\n * @param {T[]} elements - Elements which should be added to the BallTree\n * @param {ParametersBallTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}`\n * @see {@link https://en.wikipedia.org/wiki/Ball_tree}\n * @see {@link https://github.com/invisal/noobjs/blob/master/src/tree/BallTree.js}\n */\n constructor(elements: T[], parameters?: ParametersBallTree);\n /**\n * @private\n * @type {BallTreeNode | BallTreeLeaf}\n */\n private _root;\n /** @returns {Metric} */\n get _metric(): Metric;\n /**\n * @private\n * @param {ElementWithIndex[]} elements\n * @returns {BallTreeNode | BallTreeLeaf} Root of balltree.\n */\n private _construct;\n /**\n * @private\n * @param {ElementWithIndex[]} B\n * @returns {number}\n */\n private _greatest_spread;\n /**\n * @param {number} i\n * @param {number} k\n */\n search_by_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @param {T} t - Query element.\n * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors.\n */\n search(t: T, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @private\n * @param {T} t - Query element.\n * @param {number} k - Number of nearest neighbors to return.\n * @param {Heap>} Q - Heap consists of the currently found `k` nearest neighbors.\n * @param {BallTreeNode | BallTreeLeaf} B\n */\n private _search;\n}\nexport type ElementWithIndex = {\n index: number;\n element: T;\n};\nimport type { ParametersBallTree } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=BallTree.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersHNSW } from \"./index.js\" */\n/**\n * @typedef {Object} Layer\n * @property {number} l_c - Layer number\n * @property {number[]} point_indices - Global indices of points in this layer\n * @property {Map} edges - Global index -> array of connected global indices\n */\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} Candidate\n * @property {T} element - The actual data point\n * @property {number} index - Global index in the dataset\n * @property {number} distance - Distance from query\n */\n/**\n * Hierarchical Navigable Small World (HNSW) graph for approximate nearest neighbor search.\n *\n * HNSW builds a multi-layer graph structure where each layer is a navigable small world graph.\n * The top layers serve as \"highways\" for fast traversal, while lower layers provide accuracy.\n * Each element is assigned to a random level, allowing logarithmic search complexity.\n *\n * Key parameters:\n * - `m`: Controls the number of connections per element (affects accuracy/memory)\n * - `ef_construction`: Controls the quality of the graph during construction (higher = better but slower)\n * - `ef`: Controls the quality of search (higher = better recall but slower)\n *\n * Based on:\n * - \"Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs\"\n * by Malkov & Yashunin (2016)\n * - \"Approximate Nearest Neighbor Search on High Dimensional Data\"\n * by Li et al. (2019)\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const points = [[1, 2], [3, 4], [5, 6], [7, 8]];\n * const hnsw = new druid.HNSW(points, {\n * metric: druid.euclidean,\n * m: 16,\n * ef_construction: 200\n * });\n *\n * const query = [2, 3];\n * const neighbors = hnsw.search(query, 2);\n * // [{ element: [1, 2], index: 0, distance: 1.41 }, ...]\n */\nexport class HNSW extends KNN {\n /**\n * Creates a new HNSW index.\n *\n * @param {T[]} points - Initial points to add to the index\n * @param {ParametersHNSW} [parameters={}] - Configuration parameters\n */\n constructor(points: T[], parameters?: ParametersHNSW);\n /** @type {Metric} */\n _metric: Metric;\n /** @type {Function} */\n _select: Function;\n /**\n * @private\n * @type {Map}\n */\n private _graph;\n /** @type {number} */\n _next_index: number;\n /** @type {number} */\n _m: number;\n /** @type {number} */\n _ef_construction: number;\n /** @type {number} */\n _ef: number;\n /** @type {number} */\n _m0: number;\n /** @type {number} */\n _mL: number;\n /** @type {Randomizer} */\n _randomizer: Randomizer;\n /** @type {number} - Current maximum layer in the graph */\n _L: number;\n /** @type {number[] | null} - Entry point indices for search */\n _ep: number[] | null;\n /**\n * Add a single element to the index.\n *\n * @param {T} element - Element to add\n * @returns {HNSW} This instance for chaining\n */\n addOne(element: T): HNSW;\n /**\n * Add multiple elements to the index.\n *\n * @param {T[]} new_elements - Elements to add\n * @returns {HNSW} This instance for chaining\n */\n add(new_elements: T[]): HNSW;\n /**\n * Select neighbors using the heuristic approach.\n *\n * The heuristic extends candidates with their neighbors and selects\n * points that are closer to the query than to already selected points.\n * This maintains graph connectivity better than simple selection.\n *\n * @private\n * @param {T} q - Query element\n * @param {Candidate[]} candidates - Candidate elements with distances\n * @param {number} M - Maximum number of neighbors to return\n * @param {number} l_c - Layer number\n * @param {boolean} [extend_candidates=true] - Whether to extend candidates with their neighbors\n * @param {boolean} [keep_pruned_connections=true] - Whether to add pruned connections back if needed\n * @returns {number[]} Selected neighbor indices\n */\n private _select_heuristic;\n /**\n * Select neighbors using simple distance-based selection.\n *\n * Simply returns the M closest candidates to the query.\n *\n * @private\n * @param {T} q - Query element\n * @param {Candidate[]} C - Candidate elements with distances\n * @param {number} M - Maximum number of neighbors to return\n * @returns {number[]} M nearest candidate indices\n */\n private _select_simple;\n /**\n * Search a single layer for nearest neighbors.\n *\n * Implements the greedy search algorithm: start from entry points,\n * always expand the closest unvisited candidate, maintain a list\n * of the ef closest found neighbors.\n *\n * @private\n * @param {T} q - Query element\n * @param {number[] | null} ep_indices - Entry point indices\n * @param {number} ef - Number of nearest neighbors to find\n * @param {number} l_c - Layer number to search\n * @returns {Candidate[]} ef nearest neighbors found with their distances\n */\n private _search_layer;\n /**\n * Fallback linear search when graph search fails\n * @private\n * @param {T} q - Query element\n * @param {number} K - Number of nearest neighbors to return\n * @returns {Candidate[]}\n */\n private _linear_search;\n /**\n * Iterator for searching the HNSW graph layer by layer.\n *\n * Yields intermediate results at each layer for debugging or visualization.\n *\n * @param {T} q - Query element\n * @param {number} K - Number of nearest neighbors to return\n * @param {number?} [ef] - Size of dynamic candidate list\n * @yields {{layer: number, candidates: Candidate[]}}\n */\n search_iter(q: T, K: number, ef?: number | null): Generator<{\n layer: number;\n candidates: {\n element: T;\n index: number;\n distance: number;\n }[];\n }, void, unknown>;\n /**\n * Get the number of elements in the index.\n *\n * @returns {number} Number of elements\n */\n get size(): number;\n /**\n * Get the number of layers in the graph.\n *\n * @returns {number} Number of layers\n */\n get num_layers(): number;\n /**\n * Get an element by its index.\n *\n * @param {number} index - Element index\n * @returns {T} The element at the given index\n */\n get_element(index: number): T;\n /**\n * Search for nearest neighbors using an element index as the query.\n *\n * @param {number} i - Index of the query element\n * @param {number} [K=5] - Number of nearest neighbors to return\n * @returns {Candidate[]} K nearest neighbors\n */\n search_by_index(i: number, K?: number): Candidate[];\n}\nexport type Layer = {\n /**\n * - Layer number\n */\n l_c: number;\n /**\n * - Global indices of points in this layer\n */\n point_indices: number[];\n /**\n * - Global index -> array of connected global indices\n */\n edges: Map;\n};\nexport type Candidate = {\n /**\n * - The actual data point\n */\n element: T;\n /**\n * - Global index in the dataset\n */\n index: number;\n /**\n * - Distance from query\n */\n distance: number;\n};\nimport type { ParametersHNSW } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport type { Metric } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\n//# sourceMappingURL=HNSW.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersKDTree } from \"./index.js\" */\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} ElementWithIndex\n * @property {number} index\n * @property {T} element\n */\n/**\n * KD-Tree (K-dimensional Tree) for efficient nearest neighbor search.\n *\n * KD-Trees partition k-dimensional space by recursively splitting along coordinate axes.\n * At each level, the tree splits points based on the median of the coordinate with the largest spread.\n * This creates a balanced binary tree structure that enables efficient O(log n) search on average.\n *\n * Best suited for:\n * - Low to moderate dimensional data (d < 20-30)\n * - When exact nearest neighbors are needed\n * - When dimensionality is not too high\n *\n * Performance degrades in high dimensions (curse of dimensionality) where approximate\n * methods like HNSW or LSH become more effective.\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link https://en.wikipedia.org/wiki/K-d_tree}\n */\nexport class KDTree extends KNN {\n /**\n * Generates a KD-Tree with given `elements`.\n *\n * @param {T[]} elements - Elements which should be added to the KD-Tree\n * @param {ParametersKDTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}`\n */\n constructor(elements: T[], parameters?: ParametersKDTree);\n /**\n * @private\n * @type {KDTreeNode | KDTreeLeaf | null}\n */\n private _root;\n /** @returns {Metric} */\n get _metric(): Metric;\n /**\n * @private\n * @param {ElementWithIndex[]} elements\n * @param {number} depth - Current depth in the tree (determines splitting axis)\n * @returns {KDTreeNode | KDTreeLeaf | null} Root of KD-Tree.\n */\n private _construct;\n /**\n * @param {number} i\n * @param {number} k\n */\n search_by_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @param {T} t - Query element.\n * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors.\n */\n search(t: T, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @private\n * @param {T} target - Query element.\n * @param {number} k - Number of nearest neighbors to return.\n * @param {KDTreeNode | KDTreeLeaf | null} node - Current node.\n * @param {Heap<{ point: ElementWithIndex; distance: number }>} best - Heap of k best found so far.\n */\n private _search_recursive;\n}\nexport type ElementWithIndex = {\n index: number;\n element: T;\n};\nimport type { ParametersKDTree } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=KDTree.d.ts.map","/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersLSH } from \"./index.js\" */\n/**\n * Locality Sensitive Hashing (LSH) for approximate nearest neighbor search.\n *\n * LSH uses hash functions that map similar items to the same buckets with high probability.\n * This implementation uses Random Projection hashing (SimHash-style) which works well for\n * cosine similarity and Euclidean distance.\n *\n * Key concepts:\n * - Multiple hash tables increase recall probability\n * - Each hash function projects data onto random hyperplanes\n * - Points on the same side of hyperplanes are hashed together\n * - Combines results from all tables for better accuracy\n *\n * Best suited for:\n * - High-dimensional data where exact methods fail\n * - Approximate nearest neighbor needs\n * - Large datasets where linear scan is too slow\n * - When some false positives/negatives are acceptable\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link https://en.wikipedia.org/wiki/Locality-sensitive_hashing}\n */\nexport class LSH extends KNN {\n /**\n * Creates a new LSH index.\n *\n * @param {T[]} elements - Elements to index\n * @param {ParametersLSH} [parameters={}] - Configuration parameters\n */\n constructor(elements: T[], parameters?: ParametersLSH);\n _metric: Metric;\n _numHashTables: number;\n _numHashFunctions: number;\n _seed: number;\n _randomizer: Randomizer;\n /** @type {Map[]} */\n _hashTables: Map[];\n /** @type {Float64Array[][]} */\n _projections: Float64Array[][];\n /** @type {number[][]} */\n _offsets: number[][];\n /** @type {number} */\n _dim: number;\n /**\n * Initialize random projection vectors for all hash tables.\n * @private\n */\n private _initializeHashFunctions;\n /**\n * Compute hash signature for an element using random projections.\n * @private\n * @param {T} element\n * @param {number} tableIndex\n * @returns {string} Hash signature\n */\n private _computeHash;\n /**\n * Add elements to the LSH index.\n * @param {T[]} elements\n * @returns {this}\n */\n add(elements: T[]): this;\n /**\n * Search for k approximate nearest neighbors.\n * @param {T} query\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search(query: T, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @param {number} i\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n}\nimport type { ParametersLSH } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport type { Metric } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\n//# sourceMappingURL=LSH.d.ts.map","/** @import { ParametersNaiveKNN } from \"./index.js\" */\n/**\n * Naive KNN implementation using a distance matrix.\n *\n * This implementation pre-computes the entire distance matrix and performs\n * an exhaustive search. Best suited for small datasets or when a distance\n * matrix is already available.\n *\n * @template {number[] | Float64Array} T\n * @category KNN\n * @class\n * @extends KNN\n */\nexport class NaiveKNN extends KNN {\n /**\n * Generates a KNN list with given `elements`.\n *\n * @param {T[]} elements - Elements which should be added to the KNN list\n * @param {ParametersNaiveKNN} parameters\n */\n constructor(elements: T[], parameters?: ParametersNaiveKNN);\n _D: Matrix;\n /** @type {Heap<{ value: number; index: number }>[]} */\n KNN: Heap<{\n value: number;\n index: number;\n }>[];\n /**\n * @param {number} i\n * @param {number} k\n */\n search_by_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @param {T} t - Query element.\n * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors.\n */\n search(t: T, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n}\nimport type { ParametersNaiveKNN } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { Heap } from \"../datastructure/index.js\";\n//# sourceMappingURL=NaiveKNN.d.ts.map","/** @import {ParametersNNDescent} from \"./index.js\" */\n/**\n *\n * @template {number[] | Float64Array} T\n * @typedef {Object} NNDescentElement\n * @property {T} value\n * @property {number} index\n * @property {boolean} flag\n */\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} NNDescentNeighbor\n * @property {T} value\n * @property {number} index\n * @property {number} distance\n * @property {boolean} [flag]\n */\n/**\n * NN-Descent\n *\n * An efficient graph-based approximate nearest neighbor search algorithm.\n * It works by iteratively improving a neighbor graph using the fact that\n * \"neighbors of neighbors are likely to be neighbors\".\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf|NN-Descent Paper}\n */\nexport class NNDescent extends KNN {\n /**\n * @param {T[]} elements - Called V in paper.\n * @param {Partial} parameters\n * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf}\n */\n constructor(elements: T[], parameters?: Partial);\n /**\n * @private\n * @type {KNNHeap[]}\n */\n private _B;\n /**\n * @private\n * @type {NNDescentNeighbor[][]}\n */\n private nn;\n _N: number;\n _randomizer: Randomizer;\n _sample_size: number;\n _nndescent_elements: {\n value: T;\n index: number;\n flag: boolean;\n }[];\n /**\n * Samples Array A with sample size.\n *\n * @private\n * @template U\n * @param {U[]} A\n * @returns {U[]}\n */\n private _sample;\n /**\n * @private\n * @param {KNNHeap} B\n * @param {NNDescentNeighbor} u\n * @returns {number}\n */\n private _update;\n /**\n * @private\n * @param {(KNNHeap | null)[]} B\n * @returns {NNDescentNeighbor[][]}\n */\n private _reverse;\n /**\n * @param {T[]} elements\n * @returns {this}\n */\n add(elements: T[]): this;\n /**\n * @param {T} x\n * @param {number} [k=5] Default is `5`\n * @returns {{ element: T, index: number; distance: number }[]}\n */\n search(x: T, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n /**\n * @param {number} i\n * @param {number} [k=5] Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i: number, k?: number): {\n element: T;\n index: number;\n distance: number;\n }[];\n}\nexport type NNDescentElement = {\n value: T;\n index: number;\n flag: boolean;\n};\nexport type NNDescentNeighbor = {\n value: T;\n index: number;\n distance: number;\n flag?: boolean | undefined;\n};\nexport type HeapEntry = {\n element: NNDescentNeighbor;\n value: number;\n};\nimport type { ParametersNNDescent } from \"./index.js\";\nimport { KNN } from \"./KNN.js\";\nimport { Randomizer } from \"../util/index.js\";\n//# sourceMappingURL=NNDescent.d.ts.map","export { Annoy } from \"./Annoy.js\";\nexport { BallTree } from \"./BallTree.js\";\nexport { HNSW } from \"./HNSW.js\";\nexport { KDTree } from \"./KDTree.js\";\nexport { LSH } from \"./LSH.js\";\nexport { NaiveKNN } from \"./NaiveKNN.js\";\nexport { NNDescent } from \"./NNDescent.js\";\nexport type ParametersAnnoy = {\n /**\n * - Metric to use: (a, b) => distance. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Number of random projection trees to build. Default is `10`\n */\n numTrees: number;\n /**\n * - Maximum points per leaf node. Default is `10`\n */\n maxPointsPerLeaf: number;\n /**\n * - Seed for random number generator. Default is `1212`\n */\n seed: number;\n};\nexport type ParametersBallTree = {\n metric: Metric;\n seed: number;\n};\nexport type ParametersHNSW = {\n /**\n * - Metric to use: (a, b) => distance. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Use heuristics or naive selection. Default is `true`\n */\n heuristic: boolean;\n /**\n * - Max number of connections per element (excluding ground layer). Default is `16`\n */\n m: number;\n /**\n * - Size of candidate list during construction. Default is `200`\n */\n ef_construction: number;\n /**\n * - Max number of connections for ground layer (layer 0). Default is `2 * m`\n */\n m0: number | null;\n /**\n * - Normalization factor for level generation. Default is `1 / Math.log(m)`\n */\n mL: number | null;\n /**\n * - Seed for random number generator. Default is `1212`\n */\n seed: number;\n /**\n * - Size of candidate list during search. Default is `50`\n */\n ef: number;\n};\nexport type ParametersKDTree = {\n /**\n * - Metric to use: (a, b) => distance. Default is `euclidean`\n */\n metric: Metric;\n seed: number;\n};\nexport type ParametersLSH = {\n /**\n * - Metric to use: (a, b) => distance. Default is `euclidean`\n */\n metric: Metric;\n /**\n * - Number of hash tables. Default is `10`\n */\n numHashTables: number;\n /**\n * - Number of hash functions per table. Default is `10`\n */\n numHashFunctions: number;\n /**\n * - Seed for random number generator. Default is `1212`\n */\n seed: number;\n};\nexport type ParametersNaiveKNN = {\n /**\n * Is either precomputed or a function to use: (a, b) => distance\n */\n metric?: Metric | \"precomputed\" | undefined;\n seed?: number | undefined;\n};\nexport type ParametersNNDescent = {\n /**\n * - Called sigma in paper. Default is `euclidean`\n */\n metric: Metric;\n /**\n * =10 - Number of samples. Default is `10`\n */\n samples: number;\n /**\n * = .8 - Sample rate. Default is `.8`\n */\n rho: number;\n /**\n * = 0.0001 - Precision parameter. Default is `0.0001`\n */\n delta: number;\n /**\n * = 1212 - Seed for the random number generator. Default is `1212`\n */\n seed: number;\n};\nimport type { Metric } from \"../metrics/index.js\";\n//# sourceMappingURL=index.d.ts.map","/**\n * Numerical stable summation with the Kahan summation algorithm.\n *\n * @category Numerical\n * @param {number[] | Float64Array} summands - Array of values to sum up.\n * @returns {number} The sum.\n * @see {@link https://en.wikipedia.org/wiki/Kahan_summation_algorithm}\n */\nexport function kahan_sum(summands: number[] | Float64Array): number;\n//# sourceMappingURL=kahan_sum.d.ts.map","/**\n * Numerical stable summation with the Neumair summation algorithm.\n *\n * @category Numerical\n * @param {number[] | Float64Array} summands - Array of values to sum up.\n * @returns {number} The sum.\n * @see {@link https://en.wikipedia.org/wiki/Kahan_summation_algorithm#Further_enhancements}\n */\nexport function neumair_sum(summands: number[] | Float64Array): number;\n//# sourceMappingURL=neumair_sum.d.ts.map","/**\n * @template {Float64Array | number[]} T\n * @category Optimization\n * @param {(d: T) => number} f\n * @param {T} x0\n * @param {number} [max_iter=300] Default is `300`\n * @returns {T}\n * @see http://optimization-js.github.io/optimization-js/optimization.js.html#line438\n */\nexport function powell(f: (d: T) => number, x0: T, max_iter?: number): T;\n//# sourceMappingURL=powell.d.ts.map","export * from \"./clustering/index.js\";\nexport * from \"./datastructure/index.js\";\nexport * from \"./dimred/index.js\";\nexport * from \"./knn/index.js\";\nexport * from \"./linear_algebra/index.js\";\nexport * from \"./matrix/index.js\";\nexport * from \"./metrics/index.js\";\nexport * from \"./numerical/index.js\";\nexport * from \"./optimization/index.js\";\nexport * from \"./util/index.js\";\nexport type InputType = Matrix | Float64Array[] | number[][];\nexport const version: string;\nimport type { Matrix } from \"./matrix/index.js\";\n//# sourceMappingURL=index.d.ts.map"],"names":["___knn_KNN_js.KNN","___matrix_index_js.Matrix"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,WAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,QAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,SAAA,eAAA,YAAA,gBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,MAAA,eAAA,YAAA,gBAAA,YAAA;;ACbP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,SAAA,eAAA,YAAA,gBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACO,iBAAA,iBAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,eAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,OAAA,eAAA,YAAA,gBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,SAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,OAAA,eAAA,YAAA,gBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,SAAA,eAAA,YAAA,gBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACO,iBAAA,cAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,WAAA,eAAA,YAAA,gBAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,IAAA,eAAA,YAAA,gBAAA,YAAA;;ACMA,KAAA,MAAA,kBAAA,YAAA,gBAAA,YAAA;;ACdP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,eAAA,IAAA,MAAA,GAAA,YAAA,0BAAA,MAAA,GAAA,MAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,mBAAA,IAAA,MAAA,sBAAA,MAAA;AACP;AACA;AACA;AACA;;ACdA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,QAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,GAAA,SAAA,QAAA;;ACPP;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,GAAA,SAAA,QAAA;;ACPP;AACA;AACA;AACA;AACO,cAAA,UAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7DA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAA,MAAA,GAAA,YAAA,kBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,YAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qCAAA,YAAA,wBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAA,MAAA,KAAA,MAAA,eAAA,UAAA,wBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAA,MAAA;AACA,WAAA,MAAA;AACA,WAAA,MAAA;AACA,UAAA,MAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,MAAA;AACA,WAAA,MAAA;AACA,WAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,MAAA;AACA,WAAA,YAAA;AACA,eAAA,YAAA;AACA,WAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,4DAAA,YAAA,GAAA,YAAA;AACA;AACA;AACA;AACA;AACA,kDAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oDAAA,QAAA;AACA;AACA;AACA,uCAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAA,SAAA,CAAA,YAAA,CAAA,eAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2CAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wDAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wDAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wDAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAA,MAAA,cAAA,YAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAA,MAAA,cAAA,YAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAA,MAAA,cAAA,YAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAA,MAAA,8CAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yDAAA,MAAA,GAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uGAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0DAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,YAAA,wCAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,YAAA,wCAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,MAAA,cAAA,YAAA,iDAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAA,MAAA,GAAA,YAAA;AACA;AACA,QAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,MAAA,GAAA,YAAA;AACA;AACA,QAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,MAAA,GAAA,YAAA;AACA;AACA,QAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,MAAA,GAAA,YAAA;AACA;AACA,QAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oDAAA,QAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,KAAA,MAAA,CAAA,QAAA,KAAA,SAAA,CAAA,YAAA,CAAA,eAAA;AACA;AACO,KAAA,QAAA;;ACjdP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,IAAA,IAAA,MAAA,cAAA,YAAA,WAAA,MAAA;;ACTP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,SAAA,eAAA,YAAA,WAAA,MAAA,cAAA,YAAA;;ACTP;AACA;AACA;AACA;AACA;AACO,cAAA,UAAA;AACP;AACA;AACA;AACA;AACA;AACA,wBAAA,SAAA;AACA;AACA,aAAA,SAAA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,IAAA,SAAA,UAAA,CAAA,cAAA;AACP;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,sBAAA,SAAA,UAAA,CAAA,gCAAA;AACP;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,gCAAA;AACA;AACA,UAAA,OAAA;AACA;AACA,YAAA,YAAA,CAAA,WAAA;AACA,sBAAA,MAAA;AACA;AACA,aAAA,WAAA,CAAA,WAAA;AACA;AACA;AACA;AACA;AACA;AACA,kEAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA;AACA,cAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,OAAA,gBAAA,OAAA,iCAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,OAAA;AACA;AACA,UAAA,OAAA;AACA,WAAA,OAAA;AACA;AACA;AACA,cAAA,YAAA,CAAA,eAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8BAAA,OAAA,SAAA,OAAA,GAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,cAAA,OAAA;AACA;AACA;AACA;AACA;AACA,mBAAA,OAAA;AACA;;AClGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,SAAA,UAAA,CAAA,gBAAA;AACP;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,gBAAA;AACA;AACA,iBAAA,UAAA;AACA;AACA;AACA,wBAAA,YAAA,CAAA,eAAA;AACA;AACA;AACA;AACA,qBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,QAAA,SAAA,UAAA,CAAA,kBAAA;AACP;AACA;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,kBAAA;AACA,QAAA,YAAA,CAAA,eAAA;AACA;AACA,sBAAA,MAAA;AACA,iBAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,SAAA,SAAA,UAAA,CAAA,mBAAA;AACP;AACA;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,mBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,SAAA,UAAA,CAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,SAAA,UAAA,CAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAA,SAAA,eAAA,OAAA,CAAA,gBAAA;AACA,iBAAA,UAAA;AACA;AACA,kBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7FO,KAAA,gCAAA;AACP;AACA,YAAA,MAAA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAA,YAAA,CAAA,eAAA;AACA;AACO,KAAA,kBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,mBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;;ACnIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,WAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAA,GAAA;AACA;;AC1CA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,IAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oGAAA,UAAA,GAAA,IAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6GAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAA,IAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvHO,KAAA,UAAA;;ACFP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,EAAA,WAAA,SAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAA,SAAA,2CAAA,SAAA,CAAA,SAAA,EAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAA,SAAA,2CAAA,OAAA,CAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6DAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAA,MAAA;AACA;AACA,OAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,EAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yCAAA,OAAA;AACA;;AC5IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,OAAA,WAAA,SAAA,UAAA,EAAA,IAAA,iBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,iBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,iBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,sBAAA,OAAA,CAAA,iBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,OAAA,CAAA,iBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;;AC3DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,WAAA,SAAA,UAAA,EAAA,IAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wCAAA,GAAA,2BAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wCAAA,GAAA,2BAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+CAAA,YAAA,SAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sCAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA,eAAA,UAAA,CAAA,WAAA;AACA,eAAA,UAAA,CAAA,eAAA;AACA,eAAA,UAAA,CAAA,eAAA;AACA,aAAA,YAAA,CAAA,WAAA;AACA,aAAA,YAAA,CAAA,WAAA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAA,SAAA;AACA;;AC5IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,QAAA,WAAA,SAAA,UAAA,MAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,kBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,kBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,kBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,kBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,QAAA;AACA;AACA,oBAAA,GAAA;AACA;;AC5EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,WAAA,SAAA,UAAA,EAAA,IAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,gBAAA;AACA,cAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;;ACzDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,WAAA,SAAA,UAAA,EAAA,IAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA;AACA;AACA,kCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA;AACA;AACA,kCAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,OAAA,CAAA,aAAA;AACA,wBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,WAAA,SAAA,UAAA,EAAA,IAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,aAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,sBAAA,OAAA,CAAA,aAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,WAAA,SAAA,UAAA,EAAA,IAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA,YAAA,GAAA;AACA,QAAA,MAAA;AACA,QAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,IAAA,WAAA,SAAA,UAAA,EAAA,IAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,cAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,sBAAA,OAAA,CAAA,cAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,WAAA,SAAA,UAAA,EAAA,IAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAA,MAAA;AACA;AACA;AACA;;AC5DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,WAAA,SAAA,UAAA,EAAA,IAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,SAAA,sBAAA,OAAA,CAAA,aAAA,IAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,aAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAAA,MAAA;AACA,OAAA,MAAA;AACA;;AC5EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,WAAA,SAAA,UAAA,EAAA,IAAA,gBAAA,CAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,CAAA,aAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,CAAA,aAAA,KAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,CAAA,aAAA,KAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,gBAAA,CAAA,aAAA;AACA;AACA,qBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,MAAA,4BAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,SAAA;AACA,aAAA,MAAA;AACA;AACO,KAAA,aAAA;AACA,KAAA,QAAA;AACP,SAAA,aAAA;AACA,SAAA,aAAA;AACA;AACA;;AC7EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,WAAA,SAAA,UAAA,EAAA,IAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;AACA;AACA;AACA;AACA;;ACpDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,WAAA,SAAA,UAAA,EAAA,IAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,gBAAA;AACA;AACA,yBAAA,YAAA,CAAA,eAAA,QAAA,YAAA;AACA,mBAAA,YAAA,CAAA,eAAA,MAAA,YAAA,CAAA,eAAA,mBAAA,YAAA;AACA,iBAAA,YAAA,CAAA,eAAA,MAAA,YAAA,CAAA,eAAA,MAAA,YAAA;AACA,gBAAA,YAAA,CAAA,eAAA,iBAAA,YAAA;AACA;AACA;AACA;AACA,gBAAA,MAAA;AACA,YAAA,MAAA;AACA;AACA;AACA,2CAAA,MAAA;AACA;AACA,wDAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAA,MAAA,SAAA,MAAA,gDAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAAA,YAAA,CAAA,eAAA,MAAA,YAAA,CAAA,eAAA,MAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAA,YAAA,CAAA,eAAA,QAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,2BAAA,YAAA,CAAA,eAAA,iBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA,8BAAA,YAAA,CAAA,eAAA,MAAA,YAAA,CAAA,eAAA,mBAAA,YAAA;AACA;;ACjKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,OAAA,WAAA,SAAA,UAAA,EAAA,IAAA,iBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,iBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,sBAAA,OAAA,CAAA,iBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,sBAAA,OAAA,CAAA,iBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAA,OAAA,CAAA,iBAAA;AACA,sBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAA,WAAA,CAAA,YAAA,CAAA,eAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,SAAA;AACA;;AC3IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,sBAAA,YAAA,eAAA,MAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,WAAA,SAAA,UAAA,EAAA,IAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,gBAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA,eAAA,MAAA,eAAoCA,GAAuB,YAAA,YAAA;AAC3D;AACA;AACA;AACA,SAAA,GAAA,YAAA,YAAA,CAAA,eAAA;AACA,cAAA,MAAA;AACA,aAAA,YAAA,CAAA,WAAA;AACA;AACA;AACA,SAAA,MAAA;AACA,UAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAA,MAAA;AACA,iBAAA,YAAA,CAAA,WAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA,cAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,IAAA,WAAA,SAAA,UAAA,EAAA,IAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,cAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,cAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA,YAAA,MAAA;AACA,YAAA,MAAA;AACA,QAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,IAAA,WAAA,SAAA,UAAA,EAAA,IAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAA,SAAA,uBAAA,OAAA,CAAA,cAAA,IAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAA,SAAA,uBAAA,OAAA,CAAA,cAAA,IAAA,OAAA;AACA;AACA;AACA;AACA;AACA,mCAAA,OAAA,CAAA,cAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAA,IAAA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA,wBAAA,YAAA,CAAA,eAAA;AACA,iCAAA,YAAA,CAAA,WAAA;AACA,2BAAA,YAAA,CAAA,WAAA;AACA,oCAAA,YAAA,CAAA,WAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,aAAA,eAAA,YAAA,gBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,EAAA,IAAA,MAAA;AACP,OAAA,MAAA;AACA,OAAA,MAAA;AACA;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,cAAA,IAAA,MAAA;AACP,OAAA,MAAA;AACA,OAAA,MAAA;AACA;;ACZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,2BAAA,IAAA,MAAA,kDAAA,SAAA;AACP,iBAAA,YAAA;AACA,kBAAA,YAAA;AACA;;ACXO,KAAA,eAAA,OAA2BC,MAA4B;AAC9D,OAAOA,MAA4B;AACnC,OAAOA,MAA4B;AACnC;AACO,KAAA,SAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAA,UAAA;AACA;AACA;AACA;AACA,SAAA,eAAA;AACA;AACA;AACA;AACA;AACA;;ACRO,KAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,iBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,OAAA,CAAA,SAAA;AACA;AACO,KAAA,aAAA;AACP;AACA;AACA;AACA,oBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,OAAA,CAAA,SAAA;AACA;AACO,KAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,OAAA,CAAA,SAAA;AACA;AACO,KAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,OAAA,CAAA,SAAA;AACA;AACO,KAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,OAAA,CAAA,SAAA;AACA;AACO,KAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAA,OAAA,CAAA,SAAA;AACA;AACO,KAAA,gBAAA,iBAAA,QAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAA,QAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,gBAAA;AACP;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,iBAAA;AACP;AACA;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,kBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtaA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,KAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,eAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,eAAA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA,iBAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,QAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,kBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,kBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,IAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,cAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,0CAAA,cAAA;AACA;AACA,aAAA,MAAA;AACA;AACA,aAAA,QAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAA,IAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAAA,IAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sDAAA,SAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,SAAA;AACA;AAeO,KAAA,SAAA,sBAAA,YAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,MAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,gBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,gBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,GAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,aAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,aAAA;AACA,aAAA,MAAA;AACA;AACA;AACA;AACA,iBAAA,UAAA;AACA;AACA,iBAAA,GAAA;AACA;AACA,kBAAA,YAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,QAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,kBAAA;AACP;AACA;AACA;AACA;AACA;AACA;AACA,4CAAA,kBAAA;AACA,QAAA,MAAA;AACA;AACA,SAAA,IAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,cAAA,SAAA,sBAAA,YAAA,UAAA,GAAA,IAAA,mBAAA;AACP;AACA;AACA;AACA;AACA;AACA,4CAAA,OAAA,CAAA,mBAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAA,UAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/FO,KAAA,eAAA;AACP;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,kBAAA;AACP,YAAA,MAAA;AACA;AACA;AACO,KAAA,cAAA;AACP;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,gBAAA;AACP;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACO,KAAA,aAAA;AACP;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,KAAA,kBAAA;AACP;AACA;AACA;AACA,aAAA,MAAA;AACA;AACA;AACO,KAAA,mBAAA;AACP;AACA;AACA;AACA,YAAA,MAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,SAAA,sBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,WAAA,sBAAA,YAAA;;ACRP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,iBAAA,MAAA,WAAA,YAAA;;ACCA,KAAA,SAAA,GAAA,MAAA,GAAA,YAAA;AACA,cAAA,OAAA;;;;"} \ No newline at end of file diff --git a/dist/druid.js b/dist/druid.js index a8765d4..b9c66b9 100644 --- a/dist/druid.js +++ b/dist/druid.js @@ -1,7 +1,6 @@ var version$1 = "0.8.0"; var pkg = { - version: version$1, -}; + version: version$1}; /** * Computes the Bray-Curtis distance between `a` and `b`. @@ -13,14 +12,14 @@ var pkg = { * @see {@link https://en.wikipedia.org/wiki/Bray%E2%80%93Curtis_dissimilarity} */ function bray_curtis(a, b) { - if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); - let sum_abs_diff = 0; - let sum_ab = 0; - for (let i = 0; i < a.length; ++i) { - sum_abs_diff += Math.abs(a[i] - b[i]); - sum_ab += a[i] + b[i]; - } - return sum_abs_diff / sum_ab; + if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); + let sum_abs_diff = 0; + let sum_ab = 0; + for (let i = 0; i < a.length; ++i) { + sum_abs_diff += Math.abs(a[i] - b[i]); + sum_ab += a[i] + b[i]; + } + return sum_abs_diff / sum_ab; } /** @@ -33,13 +32,13 @@ function bray_curtis(a, b) { * @see {@link https://en.wikipedia.org/wiki/Canberra_distance} */ function canberra(a, b) { - if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); - const n = a.length; - let sum = 0; - for (let i = 0; i < n; ++i) { - sum += Math.abs(a[i] - b[i]) / (Math.abs(a[i]) + Math.abs(b[i])); - } - return sum; + if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); + const n = a.length; + let sum = 0; + for (let i = 0; i < n; ++i) { + sum += Math.abs(a[i] - b[i]) / (Math.abs(a[i]) + Math.abs(b[i])); + } + return sum; } /** @@ -51,13 +50,13 @@ function canberra(a, b) { * @returns {number} The chebyshev distance between `a` and `b`. */ function chebyshev(a, b) { - if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); - const n = a.length; - const res = []; - for (let i = 0; i < n; ++i) { - res.push(Math.abs(a[i] - b[i])); - } - return Math.max(...res); + if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); + const n = a.length; + const res = []; + for (let i = 0; i < n; ++i) { + res.push(Math.abs(a[i] - b[i])); + } + return Math.max(...res); } /** @@ -74,17 +73,17 @@ function chebyshev(a, b) { * const distance = cosine(a, b); // 0.9746318461970762 */ function cosine(a, b) { - if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); - const n = a.length; - let sum = 0; - let sum_a = 0; - let sum_b = 0; - for (let i = 0; i < n; ++i) { - sum += a[i] * b[i]; - sum_a += a[i] * a[i]; - sum_b += b[i] * b[i]; - } - return Math.acos(sum / (Math.sqrt(sum_a) * Math.sqrt(sum_b))); + if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); + const n = a.length; + let sum = 0; + let sum_a = 0; + let sum_b = 0; + for (let i = 0; i < n; ++i) { + sum += a[i] * b[i]; + sum_a += a[i] * a[i]; + sum_b += b[i] * b[i]; + } + return Math.acos(sum / (Math.sqrt(sum_a) * Math.sqrt(sum_b))); } /** @@ -97,14 +96,14 @@ function cosine(a, b) { */ function euclidean_squared(a, b) { - if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); - const n = a.length; - let sum = 0; - for (let i = 0; i < n; ++i) { - const a_b = a[i] - b[i]; - sum += a_b * a_b; - } - return sum; + if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); + const n = a.length; + let sum = 0; + for (let i = 0; i < n; ++i) { + const a_b = a[i] - b[i]; + sum += a_b * a_b; + } + return sum; } /** @@ -116,7 +115,7 @@ function euclidean_squared(a, b) { * @returns {number} The euclidean distance between `a` and `b`. */ function euclidean(a, b) { - return Math.sqrt(euclidean_squared(a, b)); + return Math.sqrt(euclidean_squared(a, b)); } /** @@ -129,42 +128,41 @@ function euclidean(a, b) { * @see {@link https://en.wikipedia.org/wiki/Goodman_and_Kruskal%27s_gamma} */ function goodman_kruskal(a, b) { - if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); - const n = a.length; - if (n < 2) return 0; - - let concordant = 0; - let discordant = 0; - let tie_a = 0; - let tie_b = 0; - - for (let i = 0; i < n; ++i) { - for (let j = i + 1; j < n; ++j) { - const a_diff = a[i] - a[j]; - const b_diff = b[i] - b[j]; - const a_tied = a_diff === 0; - const b_tied = b_diff === 0; - - if (a_tied && b_tied); - else if (a_tied) { - tie_a++; - } else if (b_tied) { - tie_b++; - } else if (a_diff * b_diff > 0) { - concordant++; - } else { - discordant++; - } - } - } - - const denominator = concordant + discordant + tie_a + tie_b; - if (denominator === 0) return 0; - - const numerator = concordant + discordant; - if (numerator === 0) return 0; - - return (concordant - discordant) / numerator; + if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); + const n = a.length; + if (n < 2) return 0; + + let concordant = 0; + let discordant = 0; + let tie_a = 0; + let tie_b = 0; + + for (let i = 0; i < n; ++i) { + for (let j = i + 1; j < n; ++j) { + const a_diff = a[i] - a[j]; + const b_diff = b[i] - b[j]; + const a_tied = a_diff === 0; + const b_tied = b_diff === 0; + + if (a_tied && b_tied) ; else if (a_tied) { + tie_a++; + } else if (b_tied) { + tie_b++; + } else if (a_diff * b_diff > 0) { + concordant++; + } else { + discordant++; + } + } + } + + const denominator = concordant + discordant + tie_a + tie_b; + if (denominator === 0) return 0; + + const numerator = concordant + discordant; + if (numerator === 0) return 0; + + return (concordant - discordant) / numerator; } /** @@ -176,15 +174,15 @@ function goodman_kruskal(a, b) { * @returns {number} The hamming distance between `a` and `b`. */ function hamming(a, b) { - if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); - const n = a.length; - let disagree = 0; - for (let i = 0; i < n; ++i) { - const x = a[i]; - const y = b[i]; - disagree += x !== y ? 1 : 0; - } - return disagree / n; + if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); + const n = a.length; + let disagree = 0; + for (let i = 0; i < n; ++i) { + const x = a[i]; + const y = b[i]; + disagree += x !== y ? 1 : 0; + } + return disagree / n; } /** @@ -197,23 +195,23 @@ function hamming(a, b) { * @see {@link https://en.wikipedia.org/wiki/Haversine_formula} */ function haversine(a, b) { - if (a.length !== 2 || b.length !== 2) - throw new Error("Haversine distance requires exactly 2 coordinates [lat, lon] for each point!"); - const lat1 = a[0]; - const lon1 = a[1]; - const lat2 = b[0]; - const lon2 = b[1]; + if (a.length !== 2 || b.length !== 2) + throw new Error("Haversine distance requires exactly 2 coordinates [lat, lon] for each point!"); + const lat1 = a[0]; + const lon1 = a[1]; + const lat2 = b[0]; + const lon2 = b[1]; - const dlat = lat2 - lat1; - const dlon = lon2 - lon1; + const dlat = lat2 - lat1; + const dlon = lon2 - lon1; - const sin_dlat2 = Math.sin(dlat / 2); - const sin_dlon2 = Math.sin(dlon / 2); + const sin_dlat2 = Math.sin(dlat / 2); + const sin_dlon2 = Math.sin(dlon / 2); - const x = sin_dlat2 * sin_dlat2 + Math.cos(lat1) * Math.cos(lat2) * sin_dlon2 * sin_dlon2; - const c = 2 * Math.atan2(Math.sqrt(x), Math.sqrt(1 - x)); + const x = sin_dlat2 * sin_dlat2 + Math.cos(lat1) * Math.cos(lat2) * sin_dlon2 * sin_dlon2; + const c = 2 * Math.atan2(Math.sqrt(x), Math.sqrt(1 - x)); - return c; + return c; } /** @@ -225,17 +223,17 @@ function haversine(a, b) { * @returns {number} The jaccard distance between `a` and `b`. */ function jaccard(a, b) { - if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); - const n = a.length; - let num_non_zero = 0; - let num_equal = 0; - for (let i = 0; i < n; ++i) { - const x = a[i] !== 0; - const y = b[i] !== 0; - num_non_zero += x || y ? 1 : 0; - num_equal += x && y ? 1 : 0; - } - return (num_non_zero - num_equal) / num_non_zero; + if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); + const n = a.length; + let num_non_zero = 0; + let num_equal = 0; + for (let i = 0; i < n; ++i) { + const x = a[i] !== 0; + const y = b[i] !== 0; + num_non_zero += x || y ? 1 : 0; + num_equal += x && y ? 1 : 0; + } + return (num_non_zero - num_equal) / num_non_zero; } /** @@ -247,13 +245,13 @@ function jaccard(a, b) { * @returns {number} The manhattan distance between `a` and `b`. */ function manhattan(a, b) { - if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); - const n = a.length; - let sum = 0; - for (let i = 0; i < n; ++i) { - sum += Math.abs(a[i] - b[i]); - } - return sum; + if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); + const n = a.length; + let sum = 0; + for (let i = 0; i < n; ++i) { + sum += Math.abs(a[i] - b[i]); + } + return sum; } /** @@ -266,15 +264,15 @@ function manhattan(a, b) { */ function sokal_michener(a, b) { - if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); - const n = a.length; - let num_not_equal = 0; - for (let i = 0; i < n; ++i) { - const x = a[i] !== 0; - const y = b[i] !== 0; - num_not_equal += x !== y ? 1 : 0; - } - return (2 * num_not_equal) / (n + num_not_equal); + if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); + const n = a.length; + let num_not_equal = 0; + for (let i = 0; i < n; ++i) { + const x = a[i] !== 0; + const y = b[i] !== 0; + num_not_equal += x !== y ? 1 : 0; + } + return (2 * num_not_equal) / (n + num_not_equal); } /** @@ -287,28 +285,28 @@ function sokal_michener(a, b) { * @see {@link https://en.wikipedia.org/wiki/Wasserstein_metric} */ function wasserstein(a, b) { - if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); - const n = a.length; - let sumA = 0; - let sumB = 0; - for (let i = 0; i < n; i++) { - sumA += a[i]; - sumB += b[i]; - } - - // Fallback if sums are 0 - if (sumA === 0 && sumB === 0) return 0; - if (sumA === 0 || sumB === 0) return Infinity; - - let distance = 0; - let cumA = 0; - let cumB = 0; - for (let i = 0; i < n; i++) { - cumA += a[i] / sumA; - cumB += b[i] / sumB; - distance += Math.abs(cumA - cumB); - } - return distance; + if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); + const n = a.length; + let sumA = 0; + let sumB = 0; + for (let i = 0; i < n; i++) { + sumA += a[i]; + sumB += b[i]; + } + + // Fallback if sums are 0 + if (sumA === 0 && sumB === 0) return 0; + if (sumA === 0 || sumB === 0) return Infinity; + + let distance = 0; + let cumA = 0; + let cumB = 0; + for (let i = 0; i < n; i++) { + cumA += a[i] / sumA; + cumB += b[i] / sumB; + distance += Math.abs(cumA - cumB); + } + return distance; } /** @@ -320,23 +318,22 @@ function wasserstein(a, b) { * @returns {number} The yule distance between `a` and `b`. */ function yule(a, b) { - if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); - const n = a.length; - let num_true_true = 0; - let num_true_false = 0; - let num_false_true = 0; - for (let i = 0; i < n; ++i) { - const x = a[i] !== 0; - const y = b[i] !== 0; - num_true_true += x && y ? 1 : 0; - num_true_false += x && !y ? 1 : 0; - num_false_true += !x && y ? 1 : 0; - } - const num_false_false = n - num_true_true - num_true_false - num_false_true; - return num_true_false === 0 || num_false_true === 0 - ? 0 - : (2 * num_true_false * num_false_true) / - (num_true_true * num_false_false + num_true_false * num_false_true); + if (a.length !== b.length) throw new Error("Vector a and b needs to be of the same length!"); + const n = a.length; + let num_true_true = 0; + let num_true_false = 0; + let num_false_true = 0; + for (let i = 0; i < n; ++i) { + const x = a[i] !== 0; + const y = b[i] !== 0; + num_true_true += x && y ? 1 : 0; + num_true_false += x && !y ? 1 : 0; + num_false_true += !x && y ? 1 : 0; + } + const num_false_false = n - num_true_true - num_true_false - num_false_true; + return num_true_false === 0 || num_false_true === 0 + ? 0 + : (2 * num_true_false * num_false_true) / (num_true_true * num_false_false + num_true_false * num_false_true); } /** @import { Metric } from "../metrics/index.js" */ @@ -346,7 +343,7 @@ function yule(a, b) { * @returns {A is Matrix} */ function isMatrix(A) { - return A instanceof Matrix; + return A instanceof Matrix; } /** @@ -358,22 +355,23 @@ function isMatrix(A) { * @returns {Matrix} The distance matrix of `A`. */ function distance_matrix(A, metric = euclidean) { - /** @type {number} */ - const n = isMatrix(A) ? A.shape[0] : A.length; - const D = new Matrix(n, n); - for (let i = 0; i < n; ++i) { - const A_i = isMatrix(A) ? A.row(i) : A[i]; - for (let j = i + 1; j < n; ++j) { - const dist = metric(A_i, isMatrix(A) ? A.row(j) : A[j]); - D.set_entry(i, j, dist); - D.set_entry(j, i, dist); - } - } - return D; + /** @type {number} */ + const n = isMatrix(A) ? A.shape[0] : A.length; + const D = new Matrix(n, n); + for (let i = 0; i < n; ++i) { + const A_i = isMatrix(A) ? A.row(i) : A[i]; + for (let j = i + 1; j < n; ++j) { + const dist = metric(A_i, isMatrix(A) ? A.row(j) : A[j]); + D.set_entry(i, j, dist); + D.set_entry(j, i, dist); + } + } + return D; } //@ts-check + /** @import { Metric } from "../metrics/index.js" */ /** @@ -386,25 +384,25 @@ function distance_matrix(A, metric = euclidean) { * @returns {{ i: number; j: number; distance: number }[][]} The kNN graph. */ function k_nearest_neighbors(A, k, metric = euclidean) { - A = A instanceof Matrix ? A : Matrix.from(A); - const rows = A.shape[0]; - const D = metric === "precomputed" ? A : distance_matrix(A, metric); - /** @type {{ i: number; j: number; distance: number }[][]} */ - const nN = []; - for (let row = 0; row < rows; ++row) { - const res = Array.from(D.row(row)) - .map((distance, col) => { - return { - i: row, - j: col, - distance: distance, - }; - }) - .sort((a, b) => a.distance - b.distance) - .slice(1, k + 1); - nN.push(res); - } - return nN; + A = A instanceof Matrix ? A : Matrix.from(A); + const rows = A.shape[0]; + const D = metric === "precomputed" ? A : distance_matrix(A, metric); + /** @type {{ i: number; j: number; distance: number }[][]} */ + const nN = []; + for (let row = 0; row < rows; ++row) { + const res = Array.from(D.row(row)) + .map((distance, col) => { + return { + i: row, + j: col, + distance: distance, + }; + }) + .sort((a, b) => a.distance - b.distance) + .slice(1, k + 1); + nN.push(res); + } + return nN; } /** @@ -417,18 +415,18 @@ function k_nearest_neighbors(A, k, metric = euclidean) { * @returns {number[]} An array with `number` entries, beginning at `start` ending at `end`. */ function linspace(start, end, number) { - if (number === undefined || number === null) { - number = Math.max(Math.round(end - start) + 1, 1); - } - if (number < 2) { - return number === 1 ? [start] : []; - } - const result = new Array(number); - number -= 1; - for (let i = number; i >= 0; --i) { - result[i] = (i * end + (number - i) * start) / number; - } - return result; + if (number === undefined || number === null) { + number = Math.max(Math.round(end - start) + 1, 1); + } + if (number < 2) { + return number === 1 ? [start] : []; + } + const result = new Array(number); + number -= 1; + for (let i = number; i >= 0; --i) { + result[i] = (i * end + (number - i) * start) / number; + } + return result; } /** @@ -440,15 +438,15 @@ function linspace(start, end, number) { * @returns The inner product between `a` and `b`. */ function inner_product(a, b) { - const N = a.length; - if (N !== b.length) { - throw new Error("Array a and b must have the same length!"); - } - let sum = 0; - for (let i = 0; i < N; ++i) { - sum += a[i] * b[i]; - } - return sum; + const N = a.length; + if (N !== b.length) { + throw new Error("Array a and b must have the same length!"); + } + let sum = 0; + for (let i = 0; i < N; ++i) { + sum += a[i] * b[i]; + } + return sum; } /** @@ -460,18 +458,18 @@ function inner_product(a, b) { * @see {@link https://en.wikipedia.org/wiki/Kahan_summation_algorithm} */ function kahan_sum(summands) { - const n = summands.length; - let sum = 0; - let compensation = 0; - let y, t; - - for (let i = 0; i < n; ++i) { - y = summands[i] - compensation; - t = sum + y; - compensation = t - sum - y; - sum = t; - } - return sum; + const n = summands.length; + let sum = 0; + let compensation = 0; + let y, t; + + for (let i = 0; i < n; ++i) { + y = summands[i] - compensation; + t = sum + y; + compensation = t - sum - y; + sum = t; + } + return sum; } /** @@ -483,21 +481,21 @@ function kahan_sum(summands) { * @see {@link https://en.wikipedia.org/wiki/Kahan_summation_algorithm#Further_enhancements} */ function neumair_sum(summands) { - const n = summands.length; - let sum = 0; - let compensation = 0; - - for (let i = 0; i < n; ++i) { - const summand = summands[i]; - const t = sum + summand; - if (Math.abs(sum) >= Math.abs(summand)) { - compensation += sum - t + summand; - } else { - compensation += summand - t + sum; + const n = summands.length; + let sum = 0; + let compensation = 0; + + for (let i = 0; i < n; ++i) { + const summand = summands[i]; + const t = sum + summand; + if (Math.abs(sum) >= Math.abs(summand)) { + compensation += sum - t + summand; + } else { + compensation += summand - t + sum; + } + sum = t; } - sum = t; - } - return sum + compensation; + return sum + compensation; } /** @@ -509,27 +507,27 @@ function neumair_sum(summands) { * @see {@link https://en.wikipedia.org/wiki/QR_decomposition#Using_the_Gram%E2%80%93Schmidt_process} */ function qr(A) { - const [rows, cols] = A.shape; - const Q = new Matrix(rows, cols, "identity"); - const R = new Matrix(cols, cols, 0); - - for (let j = 0; j < cols; ++j) { - const v = A.col(j); - for (let i = 0; i < j; ++i) { - const q = Q.col(i); - const q_dot_v = neumair_sum(q.map((q_, k) => q_ * v[k])); - for (let k = 0; k < rows; ++k) { - v[k] -= q_dot_v * q[k]; - } - R.set_entry(i, j, q_dot_v); - } - const v_norm = norm(v, euclidean); - for (let k = 0; k < rows; ++k) { - Q.set_entry(k, j, v[k] / v_norm); - } - R.set_entry(j, j, v_norm); - } - return { R, Q }; + const [rows, cols] = A.shape; + const Q = new Matrix(rows, cols, "identity"); + const R = new Matrix(cols, cols, 0); + + for (let j = 0; j < cols; ++j) { + const v = A.col(j); + for (let i = 0; i < j; ++i) { + const q = Q.col(i); + const q_dot_v = neumair_sum(q.map((q_, k) => q_ * v[k])); + for (let k = 0; k < rows; ++k) { + v[k] -= q_dot_v * q[k]; + } + R.set_entry(i, j, q_dot_v); + } + const v_norm = norm(v, euclidean); + for (let k = 0; k < rows; ++k) { + Q.set_entry(k, j, v[k] / v_norm); + } + R.set_entry(j, j, v_norm); + } + return { R, Q }; } /** @@ -542,28 +540,28 @@ function qr(A) { * @see {@link http://mlwiki.org/index.php/Householder_Transformation} */ function qr_householder(A) { - const [rows, cols] = A.shape; - const Q = new Matrix(rows, rows, "I"); - const R = A.clone(); - - for (let j = 0; j < cols; ++j) { - const x = Matrix.from_vector(R.col(j).slice(j), "row"); - const x_norm = norm(x); - const x0 = x.entry(0, 0); - const rho = -Math.sign(x0); - const u1 = x0 - rho * x_norm; - const u = x.divide(u1).set_entry(0, 0, 1); - const beta = (-rho * u1) / x_norm; - - const u_outer_u = u.outer(u); - const R_block = R.get_block(j, 0); - const new_R = R_block.sub(u_outer_u.dot(R_block).mult(beta)); - const Q_block = Q.get_block(0, j); - const new_Q = Q_block.sub(Q_block.dot(u_outer_u).mult(beta)); - R.set_block(j, 0, new_R); - Q.set_block(0, j, new_Q); - } - return { R, Q }; + const [rows, cols] = A.shape; + const Q = new Matrix(rows, rows, "I"); + const R = A.clone(); + + for (let j = 0; j < cols; ++j) { + const x = Matrix.from_vector(R.col(j).slice(j), "row"); + const x_norm = norm(x); + const x0 = x.entry(0, 0); + const rho = -Math.sign(x0); + const u1 = x0 - rho * x_norm; + const u = x.divide(u1).set_entry(0, 0, 1); + const beta = (-rho * u1) / x_norm; + + const u_outer_u = u.outer(u); + const R_block = R.get_block(j, 0); + const new_R = R_block.sub(u_outer_u.dot(R_block).mult(beta)); + const Q_block = Q.get_block(0, j); + const new_Q = Q_block.sub(Q_block.dot(u_outer_u).mult(beta)); + R.set_block(j, 0, new_R); + Q.set_block(0, j, new_Q); + } + return { R, Q }; } /** @@ -574,13 +572,13 @@ function qr_householder(A) { * @returns {number} */ function max(values) { - let max = -Infinity; - for (const value of values) { - if (value !== null && max < value) { - max = value; + let max = -Infinity; + for (const value of values) { + if (value !== null && max < value) { + max = value; + } } - } - return max; + return max; } /** @@ -591,13 +589,13 @@ function max(values) { * @returns {number} */ function min(values) { - let min = Infinity; - for (const value of values) { - if (value !== null && min > value) { - min = value; + let min = Infinity; + for (const value of values) { + if (value !== null && min > value) { + min = value; + } } - } - return min; + return min; } /** @@ -605,174 +603,173 @@ function min(values) { * @class */ class Randomizer { - _N = 624; - _M = 397; - _MATRIX_A = 0x9908b0df; - _UPPER_MASK = 0x80000000; - _LOWER_MASK = 0x7fffffff; - - /** @type {number[]} */ - _mt; - /** @type {number} */ - _mti; - /** @type {number} */ - _seed; - - /** - * Mersenne Twister random number generator. - * - * @param {number} [_seed=new Date().getTime()] - The seed for the random number generator. If `_seed == null` then - * the actual time gets used as seed. Default is `new Date().getTime()` - * @see https://github.com/bmurray7/mersenne-twister-examples/blob/master/javascript-mersenne-twister.js - */ - constructor(_seed) { - this._mt = new Array(this._N); - this._mti = this._N + 1; - this._seed = _seed ?? Date.now(); - this.seed = this._seed; - } - - /** @type {number} seed */ - set seed(_seed) { - this._seed = _seed; - const mt = this._mt; - - mt[0] = _seed >>> 0; - for (this._mti = 1; this._mti < this._N; this._mti += 1) { - const mti = this._mti; - const s = mt[mti - 1] ^ (mt[mti - 1] >>> 30); - mt[mti] = - ((((s & 0xffff0000) >>> 16) * 1812433253) << 16) + (s & 0x0000ffff) * 1812433253 + mti; - mt[mti] >>>= 0; - } - } - - /** - * Returns the seed of the random number generator. - * - * @returns {number} - The seed. - */ - get seed() { - return this._seed; - } - - /** - * Returns a float between 0 and 1. - * - * @returns {number} - A random number between [0, 1] - */ - get random() { - return this.random_int * (1.0 / 4294967296.0); - } - - /** - * Returns an integer between 0 and MAX_INTEGER. - * - * @returns {number} - A random integer. - */ - get random_int() { - let y, - mag01 = [0x0, this._MATRIX_A]; - if (this._mti >= this._N) { - let kk; - - /* if (this._mti == this._N + 1) { + _N = 624; + _M = 397; + _MATRIX_A = 0x9908b0df; + _UPPER_MASK = 0x80000000; + _LOWER_MASK = 0x7fffffff; + + /** @type {number[]} */ + _mt; + /** @type {number} */ + _mti; + /** @type {number} */ + _seed; + + /** + * Mersenne Twister random number generator. + * + * @param {number} [_seed=new Date().getTime()] - The seed for the random number generator. If `_seed == null` then + * the actual time gets used as seed. Default is `new Date().getTime()` + * @see https://github.com/bmurray7/mersenne-twister-examples/blob/master/javascript-mersenne-twister.js + */ + constructor(_seed) { + this._mt = new Array(this._N); + this._mti = this._N + 1; + this._seed = _seed ?? Date.now(); + this.seed = this._seed; + } + + /** @type {number} seed */ + set seed(_seed) { + this._seed = _seed; + const mt = this._mt; + + mt[0] = _seed >>> 0; + for (this._mti = 1; this._mti < this._N; this._mti += 1) { + const mti = this._mti; + const s = mt[mti - 1] ^ (mt[mti - 1] >>> 30); + mt[mti] = ((((s & 0xffff0000) >>> 16) * 1812433253) << 16) + (s & 0x0000ffff) * 1812433253 + mti; + mt[mti] >>>= 0; + } + } + + /** + * Returns the seed of the random number generator. + * + * @returns {number} - The seed. + */ + get seed() { + return this._seed; + } + + /** + * Returns a float between 0 and 1. + * + * @returns {number} - A random number between [0, 1] + */ + get random() { + return this.random_int * (1.0 / 4294967296.0); + } + + /** + * Returns an integer between 0 and MAX_INTEGER. + * + * @returns {number} - A random integer. + */ + get random_int() { + let y, + mag01 = [0x0, this._MATRIX_A]; + if (this._mti >= this._N) { + let kk; + + /* if (this._mti == this._N + 1) { this.seed = 5489; } */ - const N_M = this._N - this._M; - const M_N = this._M - this._N; - - for (kk = 0; kk < N_M; ++kk) { - y = (this._mt[kk] & this._UPPER_MASK) | (this._mt[kk + 1] & this._LOWER_MASK); - this._mt[kk] = this._mt[kk + this._M] ^ (y >>> 1) ^ mag01[y & 0x1]; - } - for (; kk < this._N - 1; ++kk) { - y = (this._mt[kk] & this._UPPER_MASK) | (this._mt[kk + 1] & this._LOWER_MASK); - this._mt[kk] = this._mt[kk + M_N] ^ (y >>> 1) ^ mag01[y & 0x1]; - } - - y = (this._mt[this._N - 1] & this._UPPER_MASK) | (this._mt[0] & this._LOWER_MASK); - this._mt[this._N - 1] = this._mt[this._M - 1] ^ (y >>> 1) ^ mag01[y & 0x1]; - - this._mti = 0; - } - this._mti += 1; - y = this._mt[this._mti]; - y ^= y >>> 11; - y ^= (y << 7) & 0x9d2c5680; - y ^= (y << 15) & 0xefc60000; - y ^= y >>> 18; - - return y >>> 0; - } - - gauss_random() { - let x, y, r; - if (this._val != null) { - x = this._val; - this._val = null; - return x; - } else - do { - x = 2 * this.random - 1; - y = 2 * this.random - 1; - r = x * x + y * y; - } while (!r || r > 1); - const c = Math.sqrt((-2 * Math.log(r)) / r); - this._val = y * c; // cache this for next function call for efficiency - return x * c; - } - - /** - * @template T Returns samples from an input Matrix or Array. - * @param {T[]} A - The input Matrix or Array. - * @param {number} n - The number of samples. - * @returns {T[]} A random selection form `A` of `n` samples. - */ - choice(A, n) { - if (!Array.isArray(A)) throw new Error("A must be an Array!"); - // if (A instanceof Matrix) { - // let rows = A.shape[0]; - // if (n > rows) { - // throw new Error("n bigger than A!"); - // } - // /** @type {number[]} */ - // let sample = new Array(n); - // let index_list = linspace(0, rows - 1); - // for (let i = 0, l = index_list.length; i < n; ++i, --l) { - // let random_index = this.random_int % l; - // sample[i] = index_list.splice(random_index, 1)[0]; - // } - // return sample.map((d) => A.row(d)); - // } else if (Array.isArray(A) || A instanceof Float64Array) { - const rows = A.length; - if (n > rows) { - throw new Error("n bigger than A!"); - } - const sample = new Array(n); - const index_list = linspace(0, rows - 1); - for (let i = 0, l = index_list.length; i < n; ++i, --l) { - const random_index = this.random_int % l; - sample[i] = index_list.splice(random_index, 1)[0]; - } - return sample.map((d) => A[d]); - //} else { - //throw new Error("A must be of type Matrix or Float64Array or number[]!"); - // } - } - - /** - * @template T Returns samples from an input Matrix or Array. - * @param {T[]} A - The input Matrix or Array. - * @param {number} n - The number of samples. - * @param {number} seed - The seed for the random number generator. - * @returns {T[]} - A random selection form `A` of `n` samples. - */ - static choice(A, n, seed = 1212) { - const R = new Randomizer(seed); - return R.choice(A, n); - } + const N_M = this._N - this._M; + const M_N = this._M - this._N; + + for (kk = 0; kk < N_M; ++kk) { + y = (this._mt[kk] & this._UPPER_MASK) | (this._mt[kk + 1] & this._LOWER_MASK); + this._mt[kk] = this._mt[kk + this._M] ^ (y >>> 1) ^ mag01[y & 0x1]; + } + for (; kk < this._N - 1; ++kk) { + y = (this._mt[kk] & this._UPPER_MASK) | (this._mt[kk + 1] & this._LOWER_MASK); + this._mt[kk] = this._mt[kk + M_N] ^ (y >>> 1) ^ mag01[y & 0x1]; + } + + y = (this._mt[this._N - 1] & this._UPPER_MASK) | (this._mt[0] & this._LOWER_MASK); + this._mt[this._N - 1] = this._mt[this._M - 1] ^ (y >>> 1) ^ mag01[y & 0x1]; + + this._mti = 0; + } + this._mti += 1; + y = this._mt[this._mti]; + y ^= y >>> 11; + y ^= (y << 7) & 0x9d2c5680; + y ^= (y << 15) & 0xefc60000; + y ^= y >>> 18; + + return y >>> 0; + } + + gauss_random() { + let x, y, r; + if (this._val != null) { + x = this._val; + this._val = null; + return x; + } else + do { + x = 2 * this.random - 1; + y = 2 * this.random - 1; + r = x * x + y * y; + } while (!r || r > 1); + const c = Math.sqrt((-2 * Math.log(r)) / r); + this._val = y * c; // cache this for next function call for efficiency + return x * c; + } + + /** + * @template T Returns samples from an input Matrix or Array. + * @param {T[]} A - The input Matrix or Array. + * @param {number} n - The number of samples. + * @returns {T[]} A random selection form `A` of `n` samples. + */ + choice(A, n) { + if (!Array.isArray(A)) throw new Error("A must be an Array!"); + // if (A instanceof Matrix) { + // let rows = A.shape[0]; + // if (n > rows) { + // throw new Error("n bigger than A!"); + // } + // /** @type {number[]} */ + // let sample = new Array(n); + // let index_list = linspace(0, rows - 1); + // for (let i = 0, l = index_list.length; i < n; ++i, --l) { + // let random_index = this.random_int % l; + // sample[i] = index_list.splice(random_index, 1)[0]; + // } + // return sample.map((d) => A.row(d)); + // } else if (Array.isArray(A) || A instanceof Float64Array) { + const rows = A.length; + if (n > rows) { + throw new Error("n bigger than A!"); + } + const sample = new Array(n); + const index_list = linspace(0, rows - 1); + for (let i = 0, l = index_list.length; i < n; ++i, --l) { + const random_index = this.random_int % l; + sample[i] = index_list.splice(random_index, 1)[0]; + } + return sample.map((d) => A[d]); + //} else { + //throw new Error("A must be of type Matrix or Float64Array or number[]!"); + // } + } + + /** + * @template T Returns samples from an input Matrix or Array. + * @param {T[]} A - The input Matrix or Array. + * @param {number} n - The number of samples. + * @param {number} seed - The seed for the random number generator. + * @returns {T[]} - A random selection form `A` of `n` samples. + */ + static choice(A, n, seed = 1212) { + const R = new Randomizer(seed); + return R.choice(A, n); + } } /** @import { EigenArgs } from "./index.js" */ @@ -789,29 +786,29 @@ class Randomizer { * of Matrix `A`. */ function simultaneous_poweriteration( - A, - k = 2, - { seed = 1212, max_iterations = 100, qr: qr$1 = qr, tol = 1e-8 } = {}, + A, + k = 2, + { seed = 1212, max_iterations = 100, qr: qr$1 = qr, tol = 1e-8 } = {}, ) { - const randomizer = seed instanceof Randomizer ? seed : new Randomizer(seed); - if (!(A instanceof Matrix)) A = Matrix.from(A); - const n = A.shape[0]; - let { Q, R } = qr$1(new Matrix(n, k, () => (randomizer.random - 0.5) * 2)); - while (max_iterations--) { - const oldQ = Q; - const Z = A.dot(Q); - const QR = qr$1(Z); - Q = QR.Q; - R = QR.R; - const error = euclidean_squared(Q.values, oldQ.values); - if (error < tol) { - break; - } - } - - const eigenvalues = R.diag(); - const eigenvectors = Q.transpose().to2dArray(); - return { eigenvalues, eigenvectors }; + const randomizer = seed instanceof Randomizer ? seed : new Randomizer(seed); + if (!(A instanceof Matrix)) A = Matrix.from(A); + const n = A.shape[0]; + let { Q, R } = qr$1(new Matrix(n, k, () => (randomizer.random - 0.5) * 2)); + while (max_iterations--) { + const oldQ = Q; + const Z = A.dot(Q); + const QR = qr$1(Z); + Q = QR.Q; + R = QR.R; + const error = euclidean_squared(Q.values, oldQ.values); + if (error < tol) { + break; + } + } + + const eigenvalues = R.diag(); + const eigenvectors = Q.transpose().to2dArray(); + return { eigenvalues, eigenvectors }; } /** @typedef {(i: number, j: number) => number} Accessor */ @@ -821,9333 +818,9918 @@ function simultaneous_poweriteration( * @category Matrix */ class Matrix { - /** - * Creates a new Matrix. Entries are stored in a Float64Array. - * - * @example let A = new Matrix(10, 10, () => Math.random()); //creates a 10 times 10 random matrix. let B = new - * Matrix(3, 3, "I"); // creates a 3 times 3 identity matrix. - * - * @param {number} rows - The amount of rows of the matrix. - * @param {number} cols - The amount of columns of the matrix. - * @param {Accessor | string | number} value - Can be a function with row and col as parameters, a number, or - * "zeros", "identity" or "I", or "center". - * - * - **function**: for each entry the function gets called with the parameters for the actual row and column. - * - **string**: allowed are - * - * - "zero", creates a zero matrix. - * - "identity" or "I", creates an identity matrix. - * - "center", creates an center matrix. - * - **number**: create a matrix filled with the given value. - */ - constructor(rows, cols, value = 0) { - /** @type {number} */ this._rows = rows; - /** @type {number} */ this._cols = cols; - /** @type {Float64Array} */ this._data; - - if (rows && cols) { - if (!value) { - this._data = new Float64Array(rows * cols); - } - if (typeof value === "function") { - this._data = new Float64Array(rows * cols); - for (let row = 0; row < rows; ++row) { - for (let col = 0; col < cols; ++col) { - this._data[row * cols + col] = value(row, col); - } - } - } - if (typeof value === "string") { - if (value === "zeros") { - this._data = new Float64Array(rows * cols); - for (let row = 0; row < rows; ++row) { - for (let col = 0; col < cols; ++col) { - this._data[row * cols + col] = 0; + /** + * Creates a new Matrix. Entries are stored in a Float64Array. + * + * @example let A = new Matrix(10, 10, () => Math.random()); //creates a 10 times 10 random matrix. let B = new + * Matrix(3, 3, "I"); // creates a 3 times 3 identity matrix. + * + * @param {number} rows - The amount of rows of the matrix. + * @param {number} cols - The amount of columns of the matrix. + * @param {Accessor | string | number} value - Can be a function with row and col as parameters, a number, or + * "zeros", "identity" or "I", or "center". + * + * - **function**: for each entry the function gets called with the parameters for the actual row and column. + * - **string**: allowed are + * + * - "zero", creates a zero matrix. + * - "identity" or "I", creates an identity matrix. + * - "center", creates an center matrix. + * - **number**: create a matrix filled with the given value. + */ + constructor(rows, cols, value = 0) { + /** @type {number} */ this._rows = rows; + /** @type {number} */ this._cols = cols; + /** @type {Float64Array} */ this._data; + + if (rows && cols) { + if (!value) { + this._data = new Float64Array(rows * cols); } - } - } - if (value === "identity" || value === "I") { - this._data = new Float64Array(rows * cols); - for (let row = 0; row < rows; ++row) { - this._data[row * cols + row] = 1; - } - } - if (value === "center" && rows === cols) { - this._data = new Float64Array(rows * cols); - value = (i, j) => (i === j ? 1 : 0) - 1 / rows; - for (let row = 0; row < rows; ++row) { - for (let col = 0; col < cols; ++col) { - this._data[row * cols + col] = value(row, col); + if (typeof value === "function") { + this._data = new Float64Array(rows * cols); + for (let row = 0; row < rows; ++row) { + for (let col = 0; col < cols; ++col) { + this._data[row * cols + col] = value(row, col); + } + } + } + if (typeof value === "string") { + if (value === "zeros") { + this._data = new Float64Array(rows * cols); + for (let row = 0; row < rows; ++row) { + for (let col = 0; col < cols; ++col) { + this._data[row * cols + col] = 0; + } + } + } + if (value === "identity" || value === "I") { + this._data = new Float64Array(rows * cols); + for (let row = 0; row < rows; ++row) { + this._data[row * cols + row] = 1; + } + } + if (value === "center" && rows === cols) { + this._data = new Float64Array(rows * cols); + value = (i, j) => (i === j ? 1 : 0) - 1 / rows; + for (let row = 0; row < rows; ++row) { + for (let col = 0; col < cols; ++col) { + this._data[row * cols + col] = value(row, col); + } + } + } + } + if (typeof value === "number") { + this._data = new Float64Array(rows * cols); + for (let row = 0; row < rows; ++row) { + for (let col = 0; col < cols; ++col) { + this._data[row * cols + col] = value; + } + } + } + if (Array.isArray(value)) { + this._data = new Float64Array(rows * cols); + for (let row = 0; row < rows; ++row) { + for (let col = 0; col < cols; ++col) { + this._data[row * cols + col] = value[row][col]; + } + } } - } - } - } - if (typeof value === "number") { - this._data = new Float64Array(rows * cols); - for (let row = 0; row < rows; ++row) { - for (let col = 0; col < cols; ++col) { - this._data[row * cols + col] = value; - } } - } - if (Array.isArray(value)) { - this._data = new Float64Array(rows * cols); - for (let row = 0; row < rows; ++row) { - for (let col = 0; col < cols; ++col) { - this._data[row * cols + col] = value[row][col]; - } - } - } - } - } - - /** - * Creates a Matrix out of `A`. - * @param {Matrix | Float64Array[] | number[][]} A - The matrix, array, or number, which should converted to a Matrix. - * @returns {Matrix} - * @example - * let A = Matrix.from([ [1, 0], [0, 1], ]); //creates a two by two identity matrix. - */ - static from(A) { - if (A instanceof Matrix) { - return A.clone(); - } - if (Matrix.is2dArray(A)) { - const m = A.length; - const n = A[0].length; - for (let row = 0; row < m; ++row) { - if (A[row].length !== n) { - throw new Error("various array lengths"); - } - } - return new Matrix(m, n, (i, j) => A[i][j]); - } - throw new Error("error"); - } - - /** - * Creates a Matrix with the diagonal being the values of `v`. - * - * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]] - * - * @param {number[] | Float64Array} v - * @returns {Matrix} - */ - static from_diag(v) { - const N = v.length; - return new Matrix(N, N, (i, j) => (i === j ? v[i] : 0)); - } - - /** - * Creates a Matrix with the diagonal being the values of `v`. - * - * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]] - * - * @param {number[] | Float64Array} v - * @param {"col" | "row"} type - * @returns {Matrix} - */ - static from_vector(v, type) { - const N = v.length; - if (type === "col") { - return new Matrix(N, 1, (i, _) => v[i]); - } else { - return new Matrix(1, N, (_, j) => v[j]); - } - } - - /** - * Returns the `row`th row from the Matrix. - * - * @param {number} row - * @returns {Float64Array} - */ - row(row) { - const data = this.values; - const cols = this._cols; - return data.subarray(row * cols, (row + 1) * cols); - } - - /** - * Returns an generator yielding each row of the Matrix. - * - * @yields {Float64Array} - */ - *iterate_rows() { - const cols = this._cols; - const rows = this._rows; - const data = this.values; - for (let row = 0; row < rows; ++row) { - yield data.subarray(row * cols, (row + 1) * cols); - } - } - - /** - * Makes a `Matrix` object an iterable object. - * - * @yields {Float64Array} - */ - *[Symbol.iterator]() { - for (const row of this.iterate_rows()) { - yield row; - } - } - - /** - * Sets the entries of `row`th row from the Matrix to the entries from `values`. - * - * @param {number} row - * @param {number[]} values - * @returns {Matrix} - */ - set_row(row, values) { - const cols = this._cols; - if (Matrix.isArray(values) && values.length === cols) { - const offset = row * cols; - for (let col = 0; col < cols; ++col) { - this.values[offset + col] = values[col]; - } - } else if (values instanceof Matrix && values.shape[1] === cols && values.shape[0] === 1) { - const offset = row * cols; - for (let col = 0; col < cols; ++col) { - this.values[offset + col] = values._data[col]; - } - } else { - throw new Error( - "Values not valid! Needs to be either an Array, a Float64Array, or a fitting Matrix!", - ); - } - return this; - } - - /** - * Swaps the rows `row1` and `row2` of the Matrix. - * - * @param {number} row1 - * @param {number} row2 - * @returns {Matrix} - */ - swap_rows(row1, row2) { - const cols = this._cols; - const data = this.values; - for (let i = row1 * cols, j = row2 * cols, col = 0; col < cols; ++col, ++i, ++j) { - const t = data[i]; - data[i] = data[j]; - data[j] = t; - } - return this; - } - - /** - * Returns the colth column from the Matrix. - * - * @param {number} col - * @returns {Float64Array} - */ - col(col) { - const result_col = new Float64Array(this._rows); - for (let row = 0; row < this._rows; ++row) { - result_col[row] = this.values[row * this._cols + col]; - } - return result_col; - } - - /** - * Returns the `col`th entry from the `row`th row of the Matrix. - * - * @param {number} row - * @param {number} col - * @returns {number} - */ - entry(row, col) { - return this.values[row * this._cols + col]; - } - - /** - * Sets the {@link col}th entry from the {@link row}th row of the Matrix to the given - * {@link value}. - * - * @param {number} row - * @param {number} col - * @param {number} value - * @returns {Matrix} - */ - set_entry(row, col, value) { - this.values[row * this._cols + col] = value; - return this; - } - - /** - * Adds a given {@link value} to the {@link col}th entry from the {@link row}th row of the - * Matrix. - * - * @param {number} row - * @param {number} col - * @param {number} value - * @returns {Matrix} - */ - add_entry(row, col, value) { - this.values[row * this._cols + col] += value; - return this; - } - - /** - * Subtracts a given {@link value} from the {@link col}th entry from the {@link row}th row of the - * Matrix. - * - * @param {number} row - * @param {number} col - * @param {number} value - * @returns {Matrix} - */ - sub_entry(row, col, value) { - this.values[row * this._cols + col] -= value; - return this; - } - - /** - * Returns a new transposed Matrix. - * - * @returns {Matrix} - */ - transpose() { - const B = new Matrix(this._cols, this._rows, (row, col) => this.entry(col, row)); - return B; - } - - /** - * Returns a new transposed Matrix. Short-form of `transpose`. - * - * @returns {Matrix} - */ - get T() { - return this.transpose(); - } - - /** - * Returns the inverse of the Matrix. - * - * @returns {Matrix} - */ - inverse() { - const rows = this._rows; - const cols = this._cols; - const A = this.clone(); - const B = new Matrix(rows, cols, "I"); - - // foreach column - for (let col = 0; col < cols; ++col) { - // Search for maximum in this column (pivot) - let max_idx = col; - let max_val = Math.abs(A.entry(col, col)); - for (let row = col + 1; row < rows; ++row) { - const val = Math.abs(A.entry(row, col)); - if (max_val < val) { - max_idx = row; - max_val = val; - } - } - if (max_val === 0) { - throw new Error("Cannot compute inverse of Matrix, determinant is zero"); - } - // Swap maximum row with current row - if (max_idx !== col) { - A.swap_rows(col, max_idx); - B.swap_rows(col, max_idx); - } - - // eliminate non-zero values on the other rows at column c - const A_col = A.row(col); - const B_col = B.row(col); - for (let row = 0; row < rows; ++row) { - if (row !== col) { - // eliminate value at column c and row r - const A_row = A.row(row); - const B_row = B.row(row); - if (A_row[col] !== 0) { - const f = A_row[col] / A_col[col]; - // sub (f * row c) from row r to eliminate the value at column c - for (let s = col; s < cols; ++s) { - A_row[s] -= f * A_col[s]; - } - for (let s = 0; s < cols; ++s) { - B_row[s] -= f * B_col[s]; - } - } - } else { - // normalize value at Acc to 1 (diagonal): - // divide each value of row r=c by the value at Acc - const f = A_col[col]; - for (let s = col; s < cols; ++s) { - A_col[s] /= f; - } - for (let s = 0; s < cols; ++s) { - B_col[s] /= f; - } - } - } - } - return B; - } - - /** - * Returns the dot product. If `B` is an Array or Float64Array then an Array gets returned. If `B` is a Matrix then - * a Matrix gets returned. - * - * @param {Matrix | number[] | Float64Array} B The right side - * @returns {Matrix} - */ - dot(B) { - if (B instanceof Matrix) { - const [rows_A, cols_A] = this.shape; - const [rows_B, cols_B] = B.shape; - if (cols_A !== rows_B) { - throw new Error(`A.dot(B): A is a ${this.shape.join(" ⨯ ")}-Matrix, B is a ${B.shape.join(" ⨯ ")}-Matrix: - A has ${cols_A} cols and B ${rows_B} rows. - Must be equal!`); - } - const C = new Matrix(rows_A, cols_B, 0); - const A_val = this.values; - const B_val = B.values; - const C_val = C.values; - - for (let i = 0; i < rows_A; ++i) { - const i_cols_A = i * cols_A; - const i_cols_B = i * cols_B; - for (let k = 0; k < cols_A; ++k) { - const aik = A_val[i_cols_A + k]; - if (aik === 0) continue; - const k_cols_B = k * cols_B; - for (let j = 0; j < cols_B; ++j) { - C_val[i_cols_B + j] += aik * B_val[k_cols_B + j]; - } - } - } - return C; - } else if (Matrix.isArray(B)) { - // TODO: create Matrix directly - const rows = this._rows; - if (B.length !== rows) { - throw new Error(`A.dot(B): A has ${rows} cols and B has ${B.length} rows. Must be equal!`); - } - const C = new Array(rows); - for (let row = 0; row < rows; ++row) { - C[row] = neumair_sum(this.row(row).map((e) => e * B[row])); - } - return Matrix.from(C); - } else { - throw new Error(`B must be Matrix or Array`); - } - } - - /** - * Transposes the current matrix and returns the dot product with `B`. If `B` is an Array or Float64Array then an - * Array gets returned. If `B` is a Matrix then a Matrix gets returned. - * - * @param {Matrix | number[] | Float64Array} B The right side - * @returns {Matrix} - */ - transDot(B) { - if (B instanceof Matrix) { - const [cols_A, rows_A] = this.shape; // transpose matrix - const [rows_B, cols_B] = B.shape; - if (cols_A !== rows_B) { - throw new Error(`A.dot(B): A is a ${[rows_A, cols_A].join(" ⨯ ")}-Matrix, B is a ${B.shape.join(" ⨯ ")}-Matrix: - A has ${cols_A} cols and B ${rows_B} rows, which must be equal!`); - } - // let B = new Matrix(this._cols, this._rows, (row, col) => this.entry(col, row)); - // this.values[row * this._cols + col]; - const C = new Matrix(rows_A, cols_B, 0); - const A_val = this.values; // A is rows_B x rows_A (transposed) - const B_val = B.values; - const C_val = C.values; - - for (let k = 0; k < cols_A; ++k) { - // cols_A is rows_B - const k_rows_A = k * rows_A; - const k_cols_B = k * cols_B; - for (let i = 0; i < rows_A; ++i) { - const aki = A_val[k_rows_A + i]; - if (aki === 0) continue; - for (let j = 0; j < cols_B; ++j) { - C_val[i * cols_B + j] += aki * B_val[k_cols_B + j]; - } - } - } - return C; - } else if (Matrix.isArray(B)) { - // TODO: create Matrix directly - const rows = this._cols; - if (B.length !== rows) { - throw new Error(`A.dot(B): A has ${rows} cols and B has ${B.length} rows. Must be equal!`); - } - const C = new Array(rows); - for (let row = 0; row < rows; ++row) { - C[row] = neumair_sum(this.col(row).map((e) => e * B[row])); - } - return Matrix.from(C); - } else { - throw new Error(`B must be Matrix or Array`); - } - } - - /** - * Returns the dot product with the transposed version of `B`. If `B` is an Array or Float64Array then an Array gets - * returned. If `B` is a Matrix then a Matrix gets returned. - * - * @param {Matrix | number[] | Float64Array} B The right side - * @returns {Matrix} - */ - dotTrans(B) { - if (B instanceof Matrix) { - const [rows_A, cols_A] = this.shape; - const [cols_B, rows_B] = B.shape; - if (cols_A !== rows_B) { - throw new Error(`A.dot(B): A is a ${this.shape.join(" ⨯ ")}-Matrix, B is a ${[rows_B, cols_B].join(" ⨯ ")}-Matrix: - A has ${cols_A} cols and B ${rows_B} rows, which must be equal!`); - } - const C = new Matrix(rows_A, cols_B, (row, col) => { - const A_i = this.row(row); - const B_i = B.row(col); - let sum = 0; - for (let i = 0; i < cols_A; ++i) { - sum += A_i[i] * B_i[i]; - } - return sum; - }); - return C; - } else if (Matrix.isArray(B)) { - // TODO: create Matrix directly - const rows = this._rows; - if (B.length !== rows) { - throw new Error(`A.dot(B): A has ${rows} cols and B has ${B.length} rows. Must be equal!`); - } - const C = new Array(rows); - for (let row = 0; row < rows; ++row) { - C[row] = neumair_sum(this.row(row).map((e) => e * B[row])); - } - return Matrix.from(C); - } else { - throw new Error(`B must be Matrix or Array`); - } - } - - /** - * Computes the outer product from `this` and `B`. - * - * @param {Matrix} B - * @returns {Matrix} - */ - outer(B) { - const l = this._data.length; - const r = B._data.length; - if (l !== r) throw new Error("Matrix A and B needs to be of the same length!"); - const C = new Matrix( - l, - l, - /** @type {Accessor} */ (i, j) => { - if (i <= j) { - return this._data[i] * B._data[j]; - } else { - return this.entry(j, i); - } - }, - ); - - return C; - } - - /** - * Appends matrix `B` to the matrix. - * - * @example let A = Matrix.from([ [1, 1], [1, 1], ]); // 2 by 2 matrix filled with ones. let B = Matrix.from([ [2, - * 2], [2, 2], ]); // 2 by 2 matrix filled with twos. - * - * A.concat(B, "horizontal"); // 2 by 4 matrix. [[1, 1, 2, 2], [1, 1, 2, 2]] - * A.concat(B, "vertical"); // 4 by 2 matrix. [[1, 1], [1, 1], [2, 2], [2, 2]] - * A.concat(B, "diag"); // 4 by 4 matrix. [[1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 2, 2], [0, 0, 2, 2]] - * - * @param {Matrix} B - Matrix to append. - * @param {"horizontal" | "vertical" | "diag"} [type="horizontal"] - Type of concatenation. Default is - * `"horizontal"` - * @returns {Matrix} - */ - concat(B, type = "horizontal") { - const [rows_A, cols_A] = this.shape; - const [rows_B, cols_B] = B.shape; - if (type === "horizontal") { - if (rows_A !== rows_B) { - throw new Error( - `A.concat(B, "horizontal"): A and B need same number of rows, A has ${rows_A} rows, B has ${rows_B} rows.`, - ); - } - const X = new Matrix(rows_A, cols_A + cols_B, "zeros"); - X.set_block(0, 0, this); - X.set_block(0, cols_A, B); - return X; - } else if (type === "vertical") { - if (cols_A !== cols_B) { - throw new Error( - `A.concat(B, "vertical"): A and B need same number of columns, A has ${cols_A} columns, B has ${cols_B} columns.`, - ); - } - const X = new Matrix(rows_A + rows_B, cols_A, "zeros"); - X.set_block(0, 0, this); - X.set_block(rows_A, 0, B); - return X; - } else if (type === "diag") { - const X = new Matrix(rows_A + rows_B, cols_A + cols_B, "zeros"); - X.set_block(0, 0, this); - X.set_block(rows_A, cols_A, B); - return X; - } else { - throw new Error(`type must be "horizontal" or "vertical", but type is ${type}!`); - } - } - - /** - * Writes the entries of B in A at an offset position given by `offset_row` and `offset_col`. - * - * @param {number} offset_row - * @param {number} offset_col - * @param {Matrix} B - * @returns {Matrix} - */ - set_block(offset_row, offset_col, B) { - const rows = Math.min(this._rows - offset_row, B.shape[0]); - const cols = Math.min(this._cols - offset_col, B.shape[1]); - for (let row = 0; row < rows; ++row) { - for (let col = 0; col < cols; ++col) { - this.set_entry(row + offset_row, col + offset_col, B.entry(row, col)); - } - } - return this; - } - - /** - * Extracts the entries from the `start_row`th row to the `end_row`th row, the - * `start_col`th column to the `end_col`th column of the matrix. If `end_row` or `end_col` is - * empty, the respective value is set to `this.rows` or `this.cols`. - * - * @example let A = Matrix.from([ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]); // a 3 by 3 matrix. - * - * A.get_block(1, 1); // [[5, 6], [8, 9]] - * A.get_block(0, 0, 1, 1); // [[1]] - * A.get_block(1, 1, 2, 2); // [[5]] - * A.get_block(0, 0, 2, 2); // [[1, 2], [4, 5]] - * - * @param {number} start_row - * @param {number} start_col - * @param {number | null} [end_row] - * @param {number | null} [end_col] - * @returns {Matrix} Returns a `end_row` - `start_row` times `end_col` - `start_col` matrix, with respective entries - * from the matrix. - */ - get_block(start_row, start_col, end_row, end_col) { - const [rows, cols] = this.shape; - end_row = end_row ?? rows; - end_col = end_col ?? cols; - if (end_row <= start_row || end_col <= start_col) { - throw new Error(` - end_row must be greater than start_row, and - end_col must be greater than start_col, but - end_row = ${end_row}, start_row = ${start_row}, end_col = ${end_col}, and start_col = ${start_col}!`); } - const X = new Matrix(end_row - start_row, end_col - start_col, "zeros"); - for (let row = start_row, new_row = 0; row < end_row; ++row, ++new_row) { - for (let col = start_col, new_col = 0; col < end_col; ++col, ++new_col) { - X.set_entry(new_row, new_col, this.entry(row, col)); - } - } - return X; - } - - /** - * Returns a new array gathering entries defined by the indices given by argument. - * - * @param {number[]} row_indices - Array consists of indices of rows for gathering entries of this matrix - * @param {number[]} col_indices - Array consists of indices of cols for gathering entries of this matrix - * @returns {Matrix} - */ - gather(row_indices, col_indices) { - const N = row_indices.length; - const D = col_indices.length; - - const R = new Matrix(N, D); - for (let i = 0; i < N; ++i) { - const row_index = row_indices[i]; - for (let j = 0; j < D; ++j) { - const col_index = col_indices[j]; - R.set_entry(i, j, this.entry(row_index, col_index)); - } - } - - return R; - } - - /** - * Applies a function to each entry of the matrix. - * - * @private - * @param {(d: number, v: number) => number} f Function takes 2 parameters, the value of the actual entry and a - * value given by the function `v`. The result of `f` gets writen to the Matrix. - * @param {Accessor} v Function takes 2 parameters for `row` and `col`, and returns a value witch should be applied - * to the `col`th entry of the `row`th row of the matrix. - * @returns {Matrix} - */ - _apply_array(f, v) { - const data = this.values; - const [rows, cols] = this.shape; - for (let i = 0, row = 0; row < rows; ++row) { - for (let col = 0; col < cols; ++col, ++i) { - data[i] = f(data[i], v(row, col)); - } - } - return this; - } - - /** - * @param {number[] | Float64Array} values - * @param {(d: number, v: number) => number} f - * @returns {Matrix} - */ - _apply_rowwise_array(values, f) { - return this._apply_array(f, (_, j) => values[j]); - } - /** - * @param {number[] | Float64Array} values - * @param {(d: number, v: number) => number} f - * @returns {Matrix} - */ - _apply_colwise_array(values, f) { - const data = this.values; - const [rows, cols] = this.shape; - for (let i = 0, row = 0; row < rows; ++row) { - const val = values[row]; - for (let col = 0; col < cols; ++col, ++i) { - data[i] = f(data[i], val); - } - } - return this; - } - - /** - * @param {Matrix | number[] | Float64Array | number} value - * @param {(d: number, v: number) => number} f - * @returns {Matrix} - */ - _apply(value, f) { - const data = this.values; - const [rows, cols] = this.shape; - if (value instanceof Matrix) { - const values = value.values; - const [value_rows, value_cols] = value.shape; - if (value_rows === 1) { - if (cols !== value_cols) { - throw new Error(`cols !== value_cols`); - } - for (let i = 0, row = 0; row < rows; ++row) { - for (let col = 0; col < cols; ++col, ++i) { - data[i] = f(data[i], values[col]); - } - } - } else if (value_cols === 1) { - if (rows !== value_rows) { - throw new Error(`rows !== value_rows`); + + /** + * Creates a Matrix out of `A`. + * @param {Matrix | Float64Array[] | number[][]} A - The matrix, array, or number, which should converted to a Matrix. + * @returns {Matrix} + * @example + * let A = Matrix.from([ [1, 0], [0, 1], ]); //creates a two by two identity matrix. + */ + static from(A) { + if (A instanceof Matrix) { + return A.clone(); } - for (let i = 0, row = 0; row < rows; ++row) { - const v = values[row]; - for (let col = 0; col < cols; ++col, ++i) { - data[i] = f(data[i], v); - } - } - } else if (rows === value_rows && cols === value_cols) { - for (let i = 0, n = rows * cols; i < n; ++i) { - data[i] = f(data[i], values[i]); - } - } else { - throw new Error(`error`); - } - } else if (Matrix.isArray(value)) { - if (value.length === rows) { - for (let i = 0, row = 0; row < rows; ++row) { - const v = value[row]; - for (let col = 0; col < cols; ++col, ++i) { - data[i] = f(data[i], v); - } + if (Matrix.is2dArray(A)) { + const m = A.length; + const n = A[0].length; + for (let row = 0; row < m; ++row) { + if (A[row].length !== n) { + throw new Error("various array lengths"); + } + } + return new Matrix(m, n, (i, j) => A[i][j]); } - } else if (value.length === cols) { - for (let i = 0, row = 0; row < rows; ++row) { - for (let col = 0; col < cols; ++col, ++i) { - data[i] = f(data[i], value[col]); - } + throw new Error("error"); + } + + /** + * Creates a Matrix with the diagonal being the values of `v`. + * + * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]] + * + * @param {number[] | Float64Array} v + * @returns {Matrix} + */ + static from_diag(v) { + const N = v.length; + return new Matrix(N, N, (i, j) => (i === j ? v[i] : 0)); + } + + /** + * Creates a Matrix with the diagonal being the values of `v`. + * + * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]] + * + * @param {number[] | Float64Array} v + * @param {"col" | "row"} type + * @returns {Matrix} + */ + static from_vector(v, type) { + const N = v.length; + if (type === "col") { + return new Matrix(N, 1, (i, _) => v[i]); + } else { + return new Matrix(1, N, (_, j) => v[j]); } - } else { - throw new Error(`error`); - } - } else { - // scalar value - for (let i = 0, n = rows * cols; i < n; ++i) { - data[i] = f(data[i], value); - } - } - return this; - } - - /** - * Clones the Matrix. - * - * @returns {Matrix} - */ - clone() { - const B = new Matrix(this._rows, this._cols); - //B._rows = this._rows; - //B._cols = this._cols; - if (this._data) { - B._data = this._data.slice(0); - } - return B; - } - - /** - * Entrywise multiplication with `value`. - * - * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; - * - * A.mult(2); // [[2, 4], [6, 8]]; - * A.mult(B); // [[1, 4], [9, 16]]; - * - * @param {Matrix | Float64Array | number[] | number} value - * @param {Object} [options] - * @param {boolean} [options.inline=false] - If true, applies multiplication to the element, otherwise it creates - * first a copy and applies the multiplication on the copy. Default is `false` - * @returns {Matrix} - */ - mult(value, { inline = false } = {}) { - const A = inline ? this : this.clone(); - return A._apply(value, (a, b) => a * b); - } - - /** - * Entrywise division with `value`. - * - * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; - * - * A.divide(2); // [[0.5, 1], [1.5, 2]]; - * A.divide(B); // [[1, 1], [1, 1]]; - * - * @param {Matrix | Float64Array | number[] | number} value - * @param {Object} [options] - * @param {Boolean} [options.inline=false] - If true, applies division to the element, otherwise it creates first a - * copy and applies the division on the copy. Default is `false` - * @returns {Matrix} - */ - divide(value, { inline = false } = {}) { - const A = inline ? this : this.clone(); - return A._apply(value, (a, b) => a / b); - } - - /** - * Entrywise addition with `value`. - * - * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; - * - * A.add(2); // [[3, 4], [5, 6]]; - * A.add(B); // [[2, 4], [6, 8]]; - * - * @param {Matrix | Float64Array | number[] | number} value - * @param {Object} [options] - * @param {boolean} [options.inline=false] - If true, applies addition to the element, otherwise it creates first a - * copy and applies the addition on the copy. Default is `false` - * @returns {Matrix} - */ - add(value, { inline = false } = {}) { - const A = inline ? this : this.clone(); - return A._apply(value, (a, b) => a + b); - } - - /** - * Entrywise subtraction with `value`. - * - * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; - * - * A.sub(2); // [[-1, 0], [1, 2]]; - * A.sub(B); // [[0, 0], [0, 0]]; - * - * @param {Matrix | Float64Array | number[] | number} value - * @param {Object} [options] - * @param {boolean} [options.inline=false] - If true, applies subtraction to the element, otherwise it creates first - * a copy and applies the subtraction on the copy. Default is `false` - * @returns {Matrix} - */ - sub(value, { inline = false } = {}) { - const A = inline ? this : this.clone(); - return A._apply(value, (a, b) => a - b); - } - - /** - * Returns the number of rows and columns of the Matrix. - * - * @returns {number[]} An Array in the form [rows, columns]. - */ - get shape() { - return [this._rows, this._cols]; - } - - /** - * Returns the matrix in the given shape with the given function which returns values for the entries of the matrix. - * - * @param {[number, number, Accessor]} parameter - Takes an Array in the form [rows, cols, value], where rows and - * cols are the number of rows and columns of the matrix, and value is a function which takes two parameters (row - * and col) which has to return a value for the colth entry of the rowth row. - * @returns {Matrix} - */ - set shape([rows, cols, value = () => 0]) { - this._rows = rows; - this._cols = cols; - this._data = new Float64Array(rows * cols); - for (let i = 0, row = 0; row < rows; ++row) { - for (let col = 0; col < cols; ++col, ++i) { - this._data[i] = value(row, col); - } - } - } - - /** - * Returns the Matrix as a Array of Float64Arrays. - * - * @returns {Float64Array[]} - */ - to2dArray() { - const result = []; - for (const row of this.iterate_rows()) { - result.push(row); } - return result; - } - - /** - * Returns the Matrix as a Array of Arrays. - * - * @returns {number[][]} - */ - asArray() { - const result = []; - for (const row of this.iterate_rows()) { - result.push(Array.from(row)); + + /** + * Returns the `row`th row from the Matrix. + * + * @param {number} row + * @returns {Float64Array} + */ + row(row) { + const data = this.values; + const cols = this._cols; + return data.subarray(row * cols, (row + 1) * cols); } - return result; - } - - /** - * Returns the diagonal of the Matrix. - * - * @returns {Float64Array} - */ - diag() { - const rows = this._rows; - const cols = this._cols; - const min_row_col = Math.min(rows, cols); - const result = new Float64Array(min_row_col); - for (let i = 0; i < min_row_col; ++i) { - result[i] = this.entry(i, i); + + /** + * Returns an generator yielding each row of the Matrix. + * + * @yields {Float64Array} + */ + *iterate_rows() { + const cols = this._cols; + const rows = this._rows; + const data = this.values; + for (let row = 0; row < rows; ++row) { + yield data.subarray(row * cols, (row + 1) * cols); + } } - return result; - } - - /** - * Returns the mean of all entries of the Matrix. - * - * @returns {number} - */ - mean() { - const sum = this.sum(); - const n = this._rows * this._cols; - return sum / n; - } - - /** - * Returns the sum oof all entries of the Matrix. - * - * @returns {number} - */ - sum() { - const data = this.values; - return neumair_sum(data); - } - - /** - * Returns the entries of the Matrix. - * - * @returns {Float64Array} - */ - get values() { - const data = this._data; - return data; - } - - /** - * Returns the mean of each row of the matrix. - * - * @returns {Float64Array} - */ - meanRows() { - const data = this.values; - const rows = this._rows; - const cols = this._cols; - const result = Float64Array.from({ length: rows }); - for (let i = 0, row = 0; row < rows; ++row) { - let sum = 0; - for (let col = 0; col < cols; ++col, ++i) { - sum += data[i]; - } - result[row] = sum / cols; + + /** + * Makes a `Matrix` object an iterable object. + * + * @yields {Float64Array} + */ + *[Symbol.iterator]() { + for (const row of this.iterate_rows()) { + yield row; + } } - return result; - } - - /** - * Returns the mean of each column of the matrix. - * - * @returns {Float64Array} - */ - meanCols() { - const data = this.values; - const rows = this._rows; - const cols = this._cols; - const result = Float64Array.from({ length: cols }); - for (let col = 0; col < cols; ++col) { - let sum = 0; - for (let i = col, row = 0; row < rows; ++row, i += cols) { - sum += data[i]; - } - result[col] = sum / rows; + + /** + * Sets the entries of `row`th row from the Matrix to the entries from `values`. + * + * @param {number} row + * @param {number[]} values + * @returns {Matrix} + */ + set_row(row, values) { + const cols = this._cols; + if (Matrix.isArray(values) && values.length === cols) { + const offset = row * cols; + for (let col = 0; col < cols; ++col) { + this.values[offset + col] = values[col]; + } + } else if (values instanceof Matrix && values.shape[1] === cols && values.shape[0] === 1) { + const offset = row * cols; + for (let col = 0; col < cols; ++col) { + this.values[offset + col] = values._data[col]; + } + } else { + throw new Error("Values not valid! Needs to be either an Array, a Float64Array, or a fitting Matrix!"); + } + return this; } - return result; - } - - /** - * Solves the equation `Ax = b` using the conjugate gradient method. Returns the result `x`. - * - * @param {Matrix} A - Matrix - * @param {Matrix} b - Matrix - * @param {Randomizer | null} [randomizer] - * @param {number} [tol=1e-3] Default is `1e-3` - * @returns {Matrix} - */ - static solve_CG(A, b, randomizer, tol = 1e-3) { - if (!randomizer) { - randomizer = new Randomizer(); + + /** + * Swaps the rows `row1` and `row2` of the Matrix. + * + * @param {number} row1 + * @param {number} row2 + * @returns {Matrix} + */ + swap_rows(row1, row2) { + const cols = this._cols; + const data = this.values; + for (let i = row1 * cols, j = row2 * cols, col = 0; col < cols; ++col, ++i, ++j) { + const t = data[i]; + data[i] = data[j]; + data[j] = t; + } + return this; } - const rows = A.shape[0]; - const cols = b.shape[1]; - let result = new Matrix(rows, 0); - for (let i = 0; i < cols; ++i) { - const b_i = Matrix.from_vector(b.col(i), "col"); - let x = new Matrix(rows, 1, () => randomizer.random); - let r = b_i.sub(A.dot(x)); - let d = r.clone(); - let iter = 0; - const max_iter = rows * 10; // Prevent infinite loops - do { - const z = A.dot(d); - const alpha = r.transDot(r).entry(0, 0) / d.transDot(z).entry(0, 0); - x = x.add(d.mult(alpha)); - const r_next = r.sub(z.mult(alpha)); - const beta = r_next.transDot(r_next).entry(0, 0) / r.transDot(r).entry(0, 0); - d = r_next.add(d.mult(beta)); - r = r_next; - iter++; - } while (Math.abs(r.mean()) > tol && iter < max_iter); - result = result.concat(x, "horizontal"); + + /** + * Returns the colth column from the Matrix. + * + * @param {number} col + * @returns {Float64Array} + */ + col(col) { + const result_col = new Float64Array(this._rows); + for (let row = 0; row < this._rows; ++row) { + result_col[row] = this.values[row * this._cols + col]; + } + return result_col; } - return result; - } - - /** - * Solves the equation `Ax = b`. Returns the result `x`. - * - * @param {Matrix | { L: Matrix; U: Matrix }} A - Matrix or LU Decomposition - * @param {Matrix} b - Matrix - * @returns {Matrix} - */ - static solve(A, b) { - const { L, U } = "L" in A && "U" in A ? A : Matrix.LU(A); - const rows = L.shape[0]; - const x = b.clone(); - - // forward - for (let row = 0; row < rows; ++row) { - for (let col = 0; col < row; ++col) { - x.sub_entry(0, row, L.entry(row, col) * x.entry(0, col)); - } - x.set_entry(0, row, x.entry(0, row) / L.entry(row, row)); + + /** + * Returns the `col`th entry from the `row`th row of the Matrix. + * + * @param {number} row + * @param {number} col + * @returns {number} + */ + entry(row, col) { + return this.values[row * this._cols + col]; } - // backward - for (let row = rows - 1; row >= 0; --row) { - for (let col = rows - 1; col > row; --col) { - x.sub_entry(0, row, U.entry(row, col) * x.entry(0, col)); - } - x.set_entry(0, row, x.entry(0, row) / U.entry(row, row)); + /** + * Sets the {@link col}th entry from the {@link row}th row of the Matrix to the given + * {@link value}. + * + * @param {number} row + * @param {number} col + * @param {number} value + * @returns {Matrix} + */ + set_entry(row, col, value) { + this.values[row * this._cols + col] = value; + return this; } - return x; - } - - /** - * `LU` decomposition of the Matrix `A`. Creates two matrices, so that the dot product `LU` equals `A`. - * - * @param {Matrix} A - * @returns {{ L: Matrix; U: Matrix }} The left triangle matrix `L` and the upper triangle matrix `U`. - */ - static LU(A) { - const rows = A.shape[0]; - const L = new Matrix(rows, rows, "zeros"); - const U = new Matrix(rows, rows, "identity"); - - for (let j = 0; j < rows; ++j) { - for (let i = j; i < rows; ++i) { - let sum = 0; - for (let k = 0; k < j; ++k) { - sum += L.entry(i, k) * U.entry(k, j); - } - L.set_entry(i, j, A.entry(i, j) - sum); - } - for (let i = j; i < rows; ++i) { - if (L.entry(j, j) === 0) { - throw new Error("L's diagonal not supposed to be 0!"); - } - let sum = 0; - for (let k = 0; k < j; ++k) { - sum += L.entry(j, k) * U.entry(k, i); - } - U.set_entry(j, i, (A.entry(j, i) - sum) / L.entry(j, j)); - } - } - - return { L, U }; - } - - /** - * Computes the determinante of `A`, by using the `LU` decomposition of `A`. - * - * @param {Matrix} A - * @returns {number} The determinate of the Matrix `A`. - */ - static det(A) { - const [rows, cols] = A.shape; + /** + * Adds a given {@link value} to the {@link col}th entry from the {@link row}th row of the + * Matrix. + * + * @param {number} row + * @param {number} col + * @param {number} value + * @returns {Matrix} + */ + add_entry(row, col, value) { + this.values[row * this._cols + col] += value; + return this; + } - if (rows === 2 && cols === 2) { - return A.entry(0, 0) * A.entry(1, 1) - A.entry(0, 1) * A.entry(1, 0); - } - if (rows === 3 && cols === 3) { - const a = A.entry(0, 0); - const b = A.entry(0, 1); - const c = A.entry(0, 2); - const d = A.entry(1, 0); - const e = A.entry(1, 1); - const f = A.entry(1, 2); - const g = A.entry(2, 0); - const h = A.entry(2, 1); - const i = A.entry(2, 2); - return a * (e * i - f * h) - b * (d * i - f * g) + c * (d * h - e * g); - } - - const { L, U } = Matrix.LU(A); - const L_diag = L.diag(); - const U_diag = U.diag(); - let det = L_diag[0] * U_diag[0]; - for (let row = 1; row < rows; ++row) { - det *= L_diag[row] * U_diag[row]; - } - return det; - } - - /** - * Computes the `k` components of the SVD decomposition of the matrix `M`. - * - * @param {Matrix} M - * @param {number} [k=2] Default is `2` - * @returns {{ U: Float64Array[]; Sigma: Float64Array; V: Float64Array[] }} - */ - static SVD(M, k = 2) { - const MtM = M.transDot(M); - const MMt = M.dotTrans(M); - const { eigenvectors: V, eigenvalues: Sigma } = simultaneous_poweriteration(MtM, k); - const { eigenvectors: U } = simultaneous_poweriteration(MMt, k); - return { U: U, Sigma: Sigma.map((sigma) => Math.sqrt(sigma)), V: V }; - - //Algorithm 1a: Householder reduction to bidiagonal form: - /* const [m, n] = A.shape; - let U = new Matrix(m, n, (i, j) => i == j ? 1 : 0); - console.log(U.to2dArray) - let V = new Matrix(n, m, (i, j) => i == j ? 1 : 0); - console.log(V.to2dArray) - let B = Matrix.bidiagonal(A.clone(), U, V); - console.log(U,V,B) - return { U: U, "Sigma": B, V: V }; */ - } - - /** - * @param {unknown} A - * @returns {A is unknown[]|number[]|Float64Array|Float32Array} - */ - static isArray(A) { - return Array.isArray(A) || A instanceof Float64Array || A instanceof Float32Array; - } - - /** - * @param {any[]} A - * @returns {A is number[][]|Float64Array[]} - */ - static is2dArray(A) { - if (!Array.isArray(A) || A.length === 0) { - return false; - } - const n = A[0].length; - for (let i = 0; i < A.length; ++i) { - if (!Array.isArray(A[i]) && !(A[i] instanceof Float64Array)) { - return false; - } - if (A[i].length !== n) { - return false; - } - } - return true; - } -} + /** + * Subtracts a given {@link value} from the {@link col}th entry from the {@link row}th row of the + * Matrix. + * + * @param {number} row + * @param {number} col + * @param {number} value + * @returns {Matrix} + */ + sub_entry(row, col, value) { + this.values[row * this._cols + col] -= value; + return this; + } -/** @import { Metric } from "../metrics/index.js" */ + /** + * Returns a new transposed Matrix. + * + * @returns {Matrix} + */ + transpose() { + const B = new Matrix(this._cols, this._rows, (row, col) => this.entry(col, row)); + return B; + } -/** - * Computes the norm of a vector, by computing its distance to **0**. - * - * @category Matrix - * @param {Matrix | number[] | Float64Array} v - Vector. - * @param {Metric} [metric=euclidean] - Which metric should be used to compute the norm. Default is `euclidean` - * @returns {number} - The norm of `v`. - */ -function norm(v, metric = euclidean) { - let vector = null; - if (v instanceof Matrix) { - const [rows, cols] = v.shape; - if (rows === 1) vector = v.row(0); - else if (cols === 1) vector = v.col(0); - else throw new Error("Matrix must be 1d!"); - } else { - vector = v; - } - const n = vector.length; - const zeros = new Float64Array(n); - return metric(vector, zeros); -} + /** + * Returns a new transposed Matrix. Short-form of `transpose`. + * + * @returns {Matrix} + */ + get T() { + return this.transpose(); + } -/** @import { Metric } from "../metrics/index.js" */ + /** + * Returns the inverse of the Matrix. + * + * @returns {Matrix} + */ + inverse() { + const rows = this._rows; + const cols = this._cols; + const A = this.clone(); + const B = new Matrix(rows, cols, "I"); + + // foreach column + for (let col = 0; col < cols; ++col) { + // Search for maximum in this column (pivot) + let max_idx = col; + let max_val = Math.abs(A.entry(col, col)); + for (let row = col + 1; row < rows; ++row) { + const val = Math.abs(A.entry(row, col)); + if (max_val < val) { + max_idx = row; + max_val = val; + } + } + if (max_val === 0) { + throw new Error("Cannot compute inverse of Matrix, determinant is zero"); + } + // Swap maximum row with current row + if (max_idx !== col) { + A.swap_rows(col, max_idx); + B.swap_rows(col, max_idx); + } -/** - * Normalizes Vector `v`. + // eliminate non-zero values on the other rows at column c + const A_col = A.row(col); + const B_col = B.row(col); + for (let row = 0; row < rows; ++row) { + if (row !== col) { + // eliminate value at column c and row r + const A_row = A.row(row); + const B_row = B.row(row); + if (A_row[col] !== 0) { + const f = A_row[col] / A_col[col]; + // sub (f * row c) from row r to eliminate the value at column c + for (let s = col; s < cols; ++s) { + A_row[s] -= f * A_col[s]; + } + for (let s = 0; s < cols; ++s) { + B_row[s] -= f * B_col[s]; + } + } + } else { + // normalize value at Acc to 1 (diagonal): + // divide each value of row r=c by the value at Acc + const f = A_col[col]; + for (let s = col; s < cols; ++s) { + A_col[s] /= f; + } + for (let s = 0; s < cols; ++s) { + B_col[s] /= f; + } + } + } + } + return B; + } + + /** + * Returns the dot product. If `B` is an Array or Float64Array then an Array gets returned. If `B` is a Matrix then + * a Matrix gets returned. + * + * @param {Matrix | number[] | Float64Array} B The right side + * @returns {Matrix} + */ + dot(B) { + if (B instanceof Matrix) { + const [rows_A, cols_A] = this.shape; + const [rows_B, cols_B] = B.shape; + if (cols_A !== rows_B) { + throw new Error(`A.dot(B): A is a ${this.shape.join(" ⨯ ")}-Matrix, B is a ${B.shape.join(" ⨯ ")}-Matrix: + A has ${cols_A} cols and B ${rows_B} rows. + Must be equal!`); + } + const C = new Matrix(rows_A, cols_B, 0); + const A_val = this.values; + const B_val = B.values; + const C_val = C.values; + + for (let i = 0; i < rows_A; ++i) { + const i_cols_A = i * cols_A; + const i_cols_B = i * cols_B; + for (let k = 0; k < cols_A; ++k) { + const aik = A_val[i_cols_A + k]; + if (aik === 0) continue; + const k_cols_B = k * cols_B; + for (let j = 0; j < cols_B; ++j) { + C_val[i_cols_B + j] += aik * B_val[k_cols_B + j]; + } + } + } + return C; + } else if (Matrix.isArray(B)) { + // TODO: create Matrix directly + const rows = this._rows; + if (B.length !== rows) { + throw new Error(`A.dot(B): A has ${rows} cols and B has ${B.length} rows. Must be equal!`); + } + const C = new Array(rows); + for (let row = 0; row < rows; ++row) { + C[row] = neumair_sum(this.row(row).map((e) => e * B[row])); + } + return Matrix.from(C); + } else { + throw new Error(`B must be Matrix or Array`); + } + } + + /** + * Transposes the current matrix and returns the dot product with `B`. If `B` is an Array or Float64Array then an + * Array gets returned. If `B` is a Matrix then a Matrix gets returned. + * + * @param {Matrix | number[] | Float64Array} B The right side + * @returns {Matrix} + */ + transDot(B) { + if (B instanceof Matrix) { + const [cols_A, rows_A] = this.shape; // transpose matrix + const [rows_B, cols_B] = B.shape; + if (cols_A !== rows_B) { + throw new Error(`A.dot(B): A is a ${[rows_A, cols_A].join(" ⨯ ")}-Matrix, B is a ${B.shape.join(" ⨯ ")}-Matrix: + A has ${cols_A} cols and B ${rows_B} rows, which must be equal!`); + } + // let B = new Matrix(this._cols, this._rows, (row, col) => this.entry(col, row)); + // this.values[row * this._cols + col]; + const C = new Matrix(rows_A, cols_B, 0); + const A_val = this.values; // A is rows_B x rows_A (transposed) + const B_val = B.values; + const C_val = C.values; + + for (let k = 0; k < cols_A; ++k) { + // cols_A is rows_B + const k_rows_A = k * rows_A; + const k_cols_B = k * cols_B; + for (let i = 0; i < rows_A; ++i) { + const aki = A_val[k_rows_A + i]; + if (aki === 0) continue; + for (let j = 0; j < cols_B; ++j) { + C_val[i * cols_B + j] += aki * B_val[k_cols_B + j]; + } + } + } + return C; + } else if (Matrix.isArray(B)) { + // TODO: create Matrix directly + const rows = this._cols; + if (B.length !== rows) { + throw new Error(`A.dot(B): A has ${rows} cols and B has ${B.length} rows. Must be equal!`); + } + const C = new Array(rows); + for (let row = 0; row < rows; ++row) { + C[row] = neumair_sum(this.col(row).map((e) => e * B[row])); + } + return Matrix.from(C); + } else { + throw new Error(`B must be Matrix or Array`); + } + } + + /** + * Returns the dot product with the transposed version of `B`. If `B` is an Array or Float64Array then an Array gets + * returned. If `B` is a Matrix then a Matrix gets returned. + * + * @param {Matrix | number[] | Float64Array} B The right side + * @returns {Matrix} + */ + dotTrans(B) { + if (B instanceof Matrix) { + const [rows_A, cols_A] = this.shape; + const [cols_B, rows_B] = B.shape; + if (cols_A !== rows_B) { + throw new Error(`A.dot(B): A is a ${this.shape.join(" ⨯ ")}-Matrix, B is a ${[rows_B, cols_B].join(" ⨯ ")}-Matrix: + A has ${cols_A} cols and B ${rows_B} rows, which must be equal!`); + } + const C = new Matrix(rows_A, cols_B, (row, col) => { + const A_i = this.row(row); + const B_i = B.row(col); + let sum = 0; + for (let i = 0; i < cols_A; ++i) { + sum += A_i[i] * B_i[i]; + } + return sum; + }); + return C; + } else if (Matrix.isArray(B)) { + // TODO: create Matrix directly + const rows = this._rows; + if (B.length !== rows) { + throw new Error(`A.dot(B): A has ${rows} cols and B has ${B.length} rows. Must be equal!`); + } + const C = new Array(rows); + for (let row = 0; row < rows; ++row) { + C[row] = neumair_sum(this.row(row).map((e) => e * B[row])); + } + return Matrix.from(C); + } else { + throw new Error(`B must be Matrix or Array`); + } + } + + /** + * Computes the outer product from `this` and `B`. + * + * @param {Matrix} B + * @returns {Matrix} + */ + outer(B) { + const l = this._data.length; + const r = B._data.length; + if (l !== r) throw new Error("Matrix A and B needs to be of the same length!"); + const C = new Matrix( + l, + l, + /** @type {Accessor} */ (i, j) => { + if (i <= j) { + return this._data[i] * B._data[j]; + } else { + return this.entry(j, i); + } + }, + ); + + return C; + } + + /** + * Appends matrix `B` to the matrix. + * + * @example let A = Matrix.from([ [1, 1], [1, 1], ]); // 2 by 2 matrix filled with ones. let B = Matrix.from([ [2, + * 2], [2, 2], ]); // 2 by 2 matrix filled with twos. + * + * A.concat(B, "horizontal"); // 2 by 4 matrix. [[1, 1, 2, 2], [1, 1, 2, 2]] + * A.concat(B, "vertical"); // 4 by 2 matrix. [[1, 1], [1, 1], [2, 2], [2, 2]] + * A.concat(B, "diag"); // 4 by 4 matrix. [[1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 2, 2], [0, 0, 2, 2]] + * + * @param {Matrix} B - Matrix to append. + * @param {"horizontal" | "vertical" | "diag"} [type="horizontal"] - Type of concatenation. Default is + * `"horizontal"` + * @returns {Matrix} + */ + concat(B, type = "horizontal") { + const [rows_A, cols_A] = this.shape; + const [rows_B, cols_B] = B.shape; + if (type === "horizontal") { + if (rows_A !== rows_B) { + throw new Error( + `A.concat(B, "horizontal"): A and B need same number of rows, A has ${rows_A} rows, B has ${rows_B} rows.`, + ); + } + const X = new Matrix(rows_A, cols_A + cols_B, "zeros"); + X.set_block(0, 0, this); + X.set_block(0, cols_A, B); + return X; + } else if (type === "vertical") { + if (cols_A !== cols_B) { + throw new Error( + `A.concat(B, "vertical"): A and B need same number of columns, A has ${cols_A} columns, B has ${cols_B} columns.`, + ); + } + const X = new Matrix(rows_A + rows_B, cols_A, "zeros"); + X.set_block(0, 0, this); + X.set_block(rows_A, 0, B); + return X; + } else if (type === "diag") { + const X = new Matrix(rows_A + rows_B, cols_A + cols_B, "zeros"); + X.set_block(0, 0, this); + X.set_block(rows_A, cols_A, B); + return X; + } else { + throw new Error(`type must be "horizontal" or "vertical", but type is ${type}!`); + } + } + + /** + * Writes the entries of B in A at an offset position given by `offset_row` and `offset_col`. + * + * @param {number} offset_row + * @param {number} offset_col + * @param {Matrix} B + * @returns {Matrix} + */ + set_block(offset_row, offset_col, B) { + const rows = Math.min(this._rows - offset_row, B.shape[0]); + const cols = Math.min(this._cols - offset_col, B.shape[1]); + for (let row = 0; row < rows; ++row) { + for (let col = 0; col < cols; ++col) { + this.set_entry(row + offset_row, col + offset_col, B.entry(row, col)); + } + } + return this; + } + + /** + * Extracts the entries from the `start_row`th row to the `end_row`th row, the + * `start_col`th column to the `end_col`th column of the matrix. If `end_row` or `end_col` is + * empty, the respective value is set to `this.rows` or `this.cols`. + * + * @example let A = Matrix.from([ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]); // a 3 by 3 matrix. + * + * A.get_block(1, 1); // [[5, 6], [8, 9]] + * A.get_block(0, 0, 1, 1); // [[1]] + * A.get_block(1, 1, 2, 2); // [[5]] + * A.get_block(0, 0, 2, 2); // [[1, 2], [4, 5]] + * + * @param {number} start_row + * @param {number} start_col + * @param {number | null} [end_row] + * @param {number | null} [end_col] + * @returns {Matrix} Returns a `end_row` - `start_row` times `end_col` - `start_col` matrix, with respective entries + * from the matrix. + */ + get_block(start_row, start_col, end_row, end_col) { + const [rows, cols] = this.shape; + end_row = end_row ?? rows; + end_col = end_col ?? cols; + if (end_row <= start_row || end_col <= start_col) { + throw new Error(` + end_row must be greater than start_row, and + end_col must be greater than start_col, but + end_row = ${end_row}, start_row = ${start_row}, end_col = ${end_col}, and start_col = ${start_col}!`); + } + const X = new Matrix(end_row - start_row, end_col - start_col, "zeros"); + for (let row = start_row, new_row = 0; row < end_row; ++row, ++new_row) { + for (let col = start_col, new_col = 0; col < end_col; ++col, ++new_col) { + X.set_entry(new_row, new_col, this.entry(row, col)); + } + } + return X; + } + + /** + * Returns a new array gathering entries defined by the indices given by argument. + * + * @param {number[]} row_indices - Array consists of indices of rows for gathering entries of this matrix + * @param {number[]} col_indices - Array consists of indices of cols for gathering entries of this matrix + * @returns {Matrix} + */ + gather(row_indices, col_indices) { + const N = row_indices.length; + const D = col_indices.length; + + const R = new Matrix(N, D); + for (let i = 0; i < N; ++i) { + const row_index = row_indices[i]; + for (let j = 0; j < D; ++j) { + const col_index = col_indices[j]; + R.set_entry(i, j, this.entry(row_index, col_index)); + } + } + + return R; + } + + /** + * Applies a function to each entry of the matrix. + * + * @private + * @param {(d: number, v: number) => number} f Function takes 2 parameters, the value of the actual entry and a + * value given by the function `v`. The result of `f` gets writen to the Matrix. + * @param {Accessor} v Function takes 2 parameters for `row` and `col`, and returns a value witch should be applied + * to the `col`th entry of the `row`th row of the matrix. + * @returns {Matrix} + */ + _apply_array(f, v) { + const data = this.values; + const [rows, cols] = this.shape; + for (let i = 0, row = 0; row < rows; ++row) { + for (let col = 0; col < cols; ++col, ++i) { + data[i] = f(data[i], v(row, col)); + } + } + return this; + } + + /** + * @param {number[] | Float64Array} values + * @param {(d: number, v: number) => number} f + * @returns {Matrix} + */ + _apply_rowwise_array(values, f) { + return this._apply_array(f, (_, j) => values[j]); + } + /** + * @param {number[] | Float64Array} values + * @param {(d: number, v: number) => number} f + * @returns {Matrix} + */ + _apply_colwise_array(values, f) { + const data = this.values; + const [rows, cols] = this.shape; + for (let i = 0, row = 0; row < rows; ++row) { + const val = values[row]; + for (let col = 0; col < cols; ++col, ++i) { + data[i] = f(data[i], val); + } + } + return this; + } + + /** + * @param {Matrix | number[] | Float64Array | number} value + * @param {(d: number, v: number) => number} f + * @returns {Matrix} + */ + _apply(value, f) { + const data = this.values; + const [rows, cols] = this.shape; + if (value instanceof Matrix) { + const values = value.values; + const [value_rows, value_cols] = value.shape; + if (value_rows === 1) { + if (cols !== value_cols) { + throw new Error(`cols !== value_cols`); + } + for (let i = 0, row = 0; row < rows; ++row) { + for (let col = 0; col < cols; ++col, ++i) { + data[i] = f(data[i], values[col]); + } + } + } else if (value_cols === 1) { + if (rows !== value_rows) { + throw new Error(`rows !== value_rows`); + } + for (let i = 0, row = 0; row < rows; ++row) { + const v = values[row]; + for (let col = 0; col < cols; ++col, ++i) { + data[i] = f(data[i], v); + } + } + } else if (rows === value_rows && cols === value_cols) { + for (let i = 0, n = rows * cols; i < n; ++i) { + data[i] = f(data[i], values[i]); + } + } else { + throw new Error(`error`); + } + } else if (Matrix.isArray(value)) { + if (value.length === rows) { + for (let i = 0, row = 0; row < rows; ++row) { + const v = value[row]; + for (let col = 0; col < cols; ++col, ++i) { + data[i] = f(data[i], v); + } + } + } else if (value.length === cols) { + for (let i = 0, row = 0; row < rows; ++row) { + for (let col = 0; col < cols; ++col, ++i) { + data[i] = f(data[i], value[col]); + } + } + } else { + throw new Error(`error`); + } + } else { + // scalar value + for (let i = 0, n = rows * cols; i < n; ++i) { + data[i] = f(data[i], value); + } + } + return this; + } + + /** + * Clones the Matrix. + * + * @returns {Matrix} + */ + clone() { + const B = new Matrix(this._rows, this._cols); + //B._rows = this._rows; + //B._cols = this._cols; + if (this._data) { + B._data = this._data.slice(0); + } + return B; + } + + /** + * Entrywise multiplication with `value`. + * + * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; + * + * A.mult(2); // [[2, 4], [6, 8]]; + * A.mult(B); // [[1, 4], [9, 16]]; + * + * @param {Matrix | Float64Array | number[] | number} value + * @param {Object} [options] + * @param {boolean} [options.inline=false] - If true, applies multiplication to the element, otherwise it creates + * first a copy and applies the multiplication on the copy. Default is `false` + * @returns {Matrix} + */ + mult(value, { inline = false } = {}) { + const A = inline ? this : this.clone(); + return A._apply(value, (a, b) => a * b); + } + + /** + * Entrywise division with `value`. + * + * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; + * + * A.divide(2); // [[0.5, 1], [1.5, 2]]; + * A.divide(B); // [[1, 1], [1, 1]]; + * + * @param {Matrix | Float64Array | number[] | number} value + * @param {Object} [options] + * @param {Boolean} [options.inline=false] - If true, applies division to the element, otherwise it creates first a + * copy and applies the division on the copy. Default is `false` + * @returns {Matrix} + */ + divide(value, { inline = false } = {}) { + const A = inline ? this : this.clone(); + return A._apply(value, (a, b) => a / b); + } + + /** + * Entrywise addition with `value`. + * + * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; + * + * A.add(2); // [[3, 4], [5, 6]]; + * A.add(B); // [[2, 4], [6, 8]]; + * + * @param {Matrix | Float64Array | number[] | number} value + * @param {Object} [options] + * @param {boolean} [options.inline=false] - If true, applies addition to the element, otherwise it creates first a + * copy and applies the addition on the copy. Default is `false` + * @returns {Matrix} + */ + add(value, { inline = false } = {}) { + const A = inline ? this : this.clone(); + return A._apply(value, (a, b) => a + b); + } + + /** + * Entrywise subtraction with `value`. + * + * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A; + * + * A.sub(2); // [[-1, 0], [1, 2]]; + * A.sub(B); // [[0, 0], [0, 0]]; + * + * @param {Matrix | Float64Array | number[] | number} value + * @param {Object} [options] + * @param {boolean} [options.inline=false] - If true, applies subtraction to the element, otherwise it creates first + * a copy and applies the subtraction on the copy. Default is `false` + * @returns {Matrix} + */ + sub(value, { inline = false } = {}) { + const A = inline ? this : this.clone(); + return A._apply(value, (a, b) => a - b); + } + + /** + * Returns the number of rows and columns of the Matrix. + * + * @returns {number[]} An Array in the form [rows, columns]. + */ + get shape() { + return [this._rows, this._cols]; + } + + /** + * Returns the matrix in the given shape with the given function which returns values for the entries of the matrix. + * + * @param {[number, number, Accessor]} parameter - Takes an Array in the form [rows, cols, value], where rows and + * cols are the number of rows and columns of the matrix, and value is a function which takes two parameters (row + * and col) which has to return a value for the colth entry of the rowth row. + * @returns {Matrix} + */ + set shape([rows, cols, value = () => 0]) { + this._rows = rows; + this._cols = cols; + this._data = new Float64Array(rows * cols); + for (let i = 0, row = 0; row < rows; ++row) { + for (let col = 0; col < cols; ++col, ++i) { + this._data[i] = value(row, col); + } + } + } + + /** + * Returns the Matrix as a Array of Float64Arrays. + * + * @returns {Float64Array[]} + */ + to2dArray() { + const result = []; + for (const row of this.iterate_rows()) { + result.push(row); + } + return result; + } + + /** + * Returns the Matrix as a Array of Arrays. + * + * @returns {number[][]} + */ + asArray() { + const result = []; + for (const row of this.iterate_rows()) { + result.push(Array.from(row)); + } + return result; + } + + /** + * Returns the diagonal of the Matrix. + * + * @returns {Float64Array} + */ + diag() { + const rows = this._rows; + const cols = this._cols; + const min_row_col = Math.min(rows, cols); + const result = new Float64Array(min_row_col); + for (let i = 0; i < min_row_col; ++i) { + result[i] = this.entry(i, i); + } + return result; + } + + /** + * Returns the mean of all entries of the Matrix. + * + * @returns {number} + */ + mean() { + const sum = this.sum(); + const n = this._rows * this._cols; + return sum / n; + } + + /** + * Returns the sum oof all entries of the Matrix. + * + * @returns {number} + */ + sum() { + const data = this.values; + return neumair_sum(data); + } + + /** + * Returns the entries of the Matrix. + * + * @returns {Float64Array} + */ + get values() { + const data = this._data; + return data; + } + + /** + * Returns the mean of each row of the matrix. + * + * @returns {Float64Array} + */ + meanRows() { + const data = this.values; + const rows = this._rows; + const cols = this._cols; + const result = Float64Array.from({ length: rows }); + for (let i = 0, row = 0; row < rows; ++row) { + let sum = 0; + for (let col = 0; col < cols; ++col, ++i) { + sum += data[i]; + } + result[row] = sum / cols; + } + return result; + } + + /** + * Returns the mean of each column of the matrix. + * + * @returns {Float64Array} + */ + meanCols() { + const data = this.values; + const rows = this._rows; + const cols = this._cols; + const result = Float64Array.from({ length: cols }); + for (let col = 0; col < cols; ++col) { + let sum = 0; + for (let i = col, row = 0; row < rows; ++row, i += cols) { + sum += data[i]; + } + result[col] = sum / rows; + } + return result; + } + + /** + * Solves the equation `Ax = b` using the conjugate gradient method. Returns the result `x`. + * + * @param {Matrix} A - Matrix + * @param {Matrix} b - Matrix + * @param {Randomizer | null} [randomizer] + * @param {number} [tol=1e-3] Default is `1e-3` + * @returns {Matrix} + */ + static solve_CG(A, b, randomizer, tol = 1e-3) { + if (!randomizer) { + randomizer = new Randomizer(); + } + const rows = A.shape[0]; + const cols = b.shape[1]; + let result = new Matrix(rows, 0); + for (let i = 0; i < cols; ++i) { + const b_i = Matrix.from_vector(b.col(i), "col"); + let x = new Matrix(rows, 1, () => randomizer.random); + let r = b_i.sub(A.dot(x)); + let d = r.clone(); + let iter = 0; + const max_iter = rows * 10; // Prevent infinite loops + do { + const z = A.dot(d); + const alpha = r.transDot(r).entry(0, 0) / d.transDot(z).entry(0, 0); + x = x.add(d.mult(alpha)); + const r_next = r.sub(z.mult(alpha)); + const beta = r_next.transDot(r_next).entry(0, 0) / r.transDot(r).entry(0, 0); + d = r_next.add(d.mult(beta)); + r = r_next; + iter++; + } while (Math.abs(r.mean()) > tol && iter < max_iter); + result = result.concat(x, "horizontal"); + } + return result; + } + + /** + * Solves the equation `Ax = b`. Returns the result `x`. + * + * @param {Matrix | { L: Matrix; U: Matrix }} A - Matrix or LU Decomposition + * @param {Matrix} b - Matrix + * @returns {Matrix} + */ + static solve(A, b) { + const { L, U } = "L" in A && "U" in A ? A : Matrix.LU(A); + const rows = L.shape[0]; + const x = b.clone(); + + // forward + for (let row = 0; row < rows; ++row) { + for (let col = 0; col < row; ++col) { + x.sub_entry(0, row, L.entry(row, col) * x.entry(0, col)); + } + x.set_entry(0, row, x.entry(0, row) / L.entry(row, row)); + } + + // backward + for (let row = rows - 1; row >= 0; --row) { + for (let col = rows - 1; col > row; --col) { + x.sub_entry(0, row, U.entry(row, col) * x.entry(0, col)); + } + x.set_entry(0, row, x.entry(0, row) / U.entry(row, row)); + } + + return x; + } + + /** + * `LU` decomposition of the Matrix `A`. Creates two matrices, so that the dot product `LU` equals `A`. + * + * @param {Matrix} A + * @returns {{ L: Matrix; U: Matrix }} The left triangle matrix `L` and the upper triangle matrix `U`. + */ + static LU(A) { + const rows = A.shape[0]; + const L = new Matrix(rows, rows, "zeros"); + const U = new Matrix(rows, rows, "identity"); + + for (let j = 0; j < rows; ++j) { + for (let i = j; i < rows; ++i) { + let sum = 0; + for (let k = 0; k < j; ++k) { + sum += L.entry(i, k) * U.entry(k, j); + } + L.set_entry(i, j, A.entry(i, j) - sum); + } + for (let i = j; i < rows; ++i) { + if (L.entry(j, j) === 0) { + throw new Error("L's diagonal not supposed to be 0!"); + } + let sum = 0; + for (let k = 0; k < j; ++k) { + sum += L.entry(j, k) * U.entry(k, i); + } + U.set_entry(j, i, (A.entry(j, i) - sum) / L.entry(j, j)); + } + } + + return { L, U }; + } + + /** + * Computes the determinante of `A`, by using the `LU` decomposition of `A`. + * + * @param {Matrix} A + * @returns {number} The determinate of the Matrix `A`. + */ + static det(A) { + const [rows, cols] = A.shape; + + if (rows === 2 && cols === 2) { + return A.entry(0, 0) * A.entry(1, 1) - A.entry(0, 1) * A.entry(1, 0); + } + if (rows === 3 && cols === 3) { + const a = A.entry(0, 0); + const b = A.entry(0, 1); + const c = A.entry(0, 2); + const d = A.entry(1, 0); + const e = A.entry(1, 1); + const f = A.entry(1, 2); + const g = A.entry(2, 0); + const h = A.entry(2, 1); + const i = A.entry(2, 2); + return a * (e * i - f * h) - b * (d * i - f * g) + c * (d * h - e * g); + } + + const { L, U } = Matrix.LU(A); + const L_diag = L.diag(); + const U_diag = U.diag(); + let det = L_diag[0] * U_diag[0]; + for (let row = 1; row < rows; ++row) { + det *= L_diag[row] * U_diag[row]; + } + return det; + } + + /** + * Computes the `k` components of the SVD decomposition of the matrix `M`. + * + * @param {Matrix} M + * @param {number} [k=2] Default is `2` + * @returns {{ U: Float64Array[]; Sigma: Float64Array; V: Float64Array[] }} + */ + static SVD(M, k = 2) { + const MtM = M.transDot(M); + const MMt = M.dotTrans(M); + const { eigenvectors: V, eigenvalues: Sigma } = simultaneous_poweriteration(MtM, k); + const { eigenvectors: U } = simultaneous_poweriteration(MMt, k); + return { U: U, Sigma: Sigma.map((sigma) => Math.sqrt(sigma)), V: V }; + + //Algorithm 1a: Householder reduction to bidiagonal form: + /* const [m, n] = A.shape; + let U = new Matrix(m, n, (i, j) => i == j ? 1 : 0); + console.log(U.to2dArray) + let V = new Matrix(n, m, (i, j) => i == j ? 1 : 0); + console.log(V.to2dArray) + let B = Matrix.bidiagonal(A.clone(), U, V); + console.log(U,V,B) + return { U: U, "Sigma": B, V: V }; */ + } + + /** + * @param {unknown} A + * @returns {A is unknown[]|number[]|Float64Array|Float32Array} + */ + static isArray(A) { + return Array.isArray(A) || A instanceof Float64Array || A instanceof Float32Array; + } + + /** + * @param {any[]} A + * @returns {A is number[][]|Float64Array[]} + */ + static is2dArray(A) { + if (!Array.isArray(A) || A.length === 0) { + return false; + } + const n = A[0].length; + for (let i = 0; i < A.length; ++i) { + if (!Array.isArray(A[i]) && !(A[i] instanceof Float64Array)) { + return false; + } + if (A[i].length !== n) { + return false; + } + } + return true; + } +} + +/** @import { Metric } from "../metrics/index.js" */ + +/** + * Computes the norm of a vector, by computing its distance to **0**. + * + * @category Matrix + * @param {Matrix | number[] | Float64Array} v - Vector. + * @param {Metric} [metric=euclidean] - Which metric should be used to compute the norm. Default is `euclidean` + * @returns {number} - The norm of `v`. + */ +function norm(v, metric = euclidean) { + let vector = null; + if (v instanceof Matrix) { + const [rows, cols] = v.shape; + if (rows === 1) vector = v.row(0); + else if (cols === 1) vector = v.col(0); + else throw new Error("Matrix must be 1d!"); + } else { + vector = v; + } + const n = vector.length; + const zeros = new Float64Array(n); + return metric(vector, zeros); +} + +/** @import { Metric } from "../metrics/index.js" */ + +/** + * Normalizes Vector `v`. + * + * @category Matrix + * @param {number[] | Float64Array} v - Vector + * @param {Metric} metric + * @returns {number[] | Float64Array} - The normalized vector with length 1. + */ +function normalize(v, metric = euclidean) { + const v_norm = norm(v, metric); + return v.map((value) => value / v_norm); +} + +/** @import {InputType} from "../index.js" */ + +/** + * Base class for all clustering algorithms. + * @template Para + */ +class Clustering { + /** @type {InputType} */ + _points; + /** @type {Para} */ + _parameters; + /** @type {Matrix} */ + _matrix; + /** @type {number} */ + _N; + /** @type {number} */ + _D; + + /** + * Compute the respective Clustering with given parameters + * @param {InputType} points + * @param {Para} parameters + */ + constructor(points, parameters) { + this._points = points; + this._parameters = parameters; + + this._matrix = points instanceof Matrix ? points : Matrix.from(points); + const [N, D] = this._matrix.shape; + this._N = N; + this._D = D; + } + + /** + * @abstract + * @param {...unknown} args + * @returns {number[][]} An array with the indices of the clusters. + */ + get_clusters(...args) { + throw new Error("The function get_clusters must be implemented!"); + } + + /** + * @abstract + * @param {...unknown} args + * @returns {number[]} An array with the clusters id's for each point. + */ + get_cluster_list(...args) { + throw new Error("The function get_cluster_list must be implemented!"); + } +} + +/** @import { InputType } from "../index.js" */ +/** @import { ParametersCURE } from "./index.js" */ + +/** + * CURE (Clustering Using REpresentatives) + * + * An efficient clustering algorithm for large databases that is robust to outliers + * and identifies clusters with non-spherical shapes and wide variances in size. + * + * @class + * @extends Clustering + * @category Clustering + */ +class CURE extends Clustering { + /** @type {number} */ + _K; + /** @type {number} */ + _num_representatives; + /** @type {number} */ + _shrink_factor; + /** + * @private + * @type {CURECluster[]} + */ + _clusters = []; + /** @type {number[]} */ + _cluster_ids = []; + + /** + * @param {InputType} points + * @param {Partial} parameters + */ + constructor(points, parameters = {}) { + super( + points, + /** @type {ParametersCURE} */ ( + Object.assign( + { K: 2, num_representatives: 5, shrink_factor: 0.5, metric: euclidean, seed: 1212 }, + parameters, + ) + ), + ); + + this._K = this._parameters.K ?? 2; + this._num_representatives = this._parameters.num_representatives ?? 5; + this._shrink_factor = this._parameters.shrink_factor ?? 0.5; + + // Initialize clusters + this._initialize_clusters(); + // Run CURE algorithm + this._cure(); + } + + /** + * Initialize each point as its own cluster + * @private + */ + _initialize_clusters() { + const N = this._N; + //const D = this._D; + this._clusters = []; + + for (let i = 0; i < N; ++i) { + const point = this._matrix.row(i); + const centroid = new Float64Array(point); + // For single point, representative is the point itself + const representatives = [new Float64Array(point)]; + + this._clusters.push(new CURECluster([i], centroid, representatives)); + } + } + + /** + * Compute distance between two clusters using representative points + * @private + * @param {CURECluster} cluster1 + * @param {CURECluster} cluster2 + * @returns {number} + */ + _cluster_distance(cluster1, cluster2) { + const reps1 = cluster1.representatives; + const reps2 = cluster2.representatives; + const metric = this._parameters.metric; + + let min_dist = Infinity; + for (const r1 of reps1) { + for (const r2 of reps2) { + const dist = metric(r1, r2); + if (dist < min_dist) { + min_dist = dist; + } + } + } + return min_dist; + } + + /** + * Find the closest pair of clusters + * @private + * @returns {[number, number, number]} [index1, index2, distance] + */ + _find_closest_clusters() { + let min_dist = Infinity; + let min_i = 0; + let min_j = 1; + + for (let i = 0; i < this._clusters.length; ++i) { + for (let j = i + 1; j < this._clusters.length; ++j) { + const dist = this._cluster_distance(this._clusters[i], this._clusters[j]); + if (dist < min_dist) { + min_dist = dist; + min_i = i; + min_j = j; + } + } + } + + return [min_i, min_j, min_dist]; + } + + /** + * Merge two clusters + * @private + * @param {CURECluster} cluster1 + * @param {CURECluster} cluster2 + * @returns {CURECluster} + */ + _merge_clusters(cluster1, cluster2) { + // Merge indices + const merged_indices = [...cluster1.indices, ...cluster2.indices]; + + // Calculate new centroid + const size1 = cluster1.indices.length; + const size2 = cluster2.indices.length; + const total_size = size1 + size2; + const D = this._D; + const new_centroid = new Float64Array(D); + + for (let d = 0; d < D; ++d) { + new_centroid[d] = (size1 * cluster1.centroid[d] + size2 * cluster2.centroid[d]) / total_size; + } + + // Collect all points from both clusters + /** @type {{index: number, point: Float64Array}[]} */ + const all_points = []; + for (const idx of cluster1.indices) { + all_points.push({ index: idx, point: this._matrix.row(idx) }); + } + for (const idx of cluster2.indices) { + all_points.push({ index: idx, point: this._matrix.row(idx) }); + } + + // Select representative points - pick points farthest from centroid + const num_reps = Math.min(this._num_representatives, all_points.length); + const metric = this._parameters.metric; + + // Calculate distances from centroid for all points + const distances = all_points.map(({ point }) => metric(point, new_centroid)); + + // Select num_reps points with maximum distance (farthest from centroid) + const selected_indices = []; + const used = new Set(); + + for (let r = 0; r < num_reps; ++r) { + let max_dist = -1; + let max_idx = -1; + + for (let i = 0; i < distances.length; ++i) { + if (!used.has(i) && distances[i] > max_dist) { + max_dist = distances[i]; + max_idx = i; + } + } + + if (max_idx >= 0) { + used.add(max_idx); + selected_indices.push(max_idx); + } + } + + // Shrink representative points toward centroid + const new_representatives = selected_indices.map((idx) => { + const point = all_points[idx].point; + const shrunk = new Float64Array(D); + const alpha = this._shrink_factor; + + for (let d = 0; d < D; ++d) { + shrunk[d] = point[d] + alpha * (new_centroid[d] - point[d]); + } + + return shrunk; + }); + + return new CURECluster(merged_indices, new_centroid, new_representatives); + } + + /** + * Run CURE clustering algorithm + * @private + */ + _cure() { + // Merge clusters until we have K clusters + while (this._clusters.length > this._K) { + const [i, j] = this._find_closest_clusters(); + + // Merge clusters i and j + const merged = this._merge_clusters(this._clusters[i], this._clusters[j]); + + // Remove the old clusters and add the merged one + // Remove larger index first to maintain correct indices + // min_i < min_j is always true from _find_closest_clusters + this._clusters.splice(j, 1); + this._clusters.splice(i, 1); + + this._clusters.push(merged); + } + + // Build cluster list for get_cluster_list + this._build_cluster_ids(); + } + + /** + * Build the cluster list (point -> cluster assignment) + * @private + */ + _build_cluster_ids() { + const N = this._N; + this._cluster_ids = new Array(N).fill(-1); + + for (let c = 0; c < this._clusters.length; ++c) { + for (const idx of this._clusters[c].indices) { + this._cluster_ids[idx] = c; + } + } + } + + /** + * @returns {number[][]} + */ + get_clusters() { + return this._clusters.map((cluster) => cluster.indices); + } + + /** + * @returns {number[]} + */ + get_cluster_list() { + return this._cluster_ids; + } +} + +/** + * @private + * Represents a cluster in CURE algorithm + */ +class CURECluster { + /** + * @param {number[]} indices - Indices of points in the cluster + * @param {Float64Array} centroid - Centroid of the cluster + * @param {Float64Array[]} representatives - Representative points (shrunk toward centroid) + */ + constructor(indices, centroid, representatives) { + /** @type {number[]} */ + this.indices = indices; + /** @type {Float64Array} */ + this.centroid = centroid; + /** @type {Float64Array[]} */ + this.representatives = representatives; + } +} + +/** @import { InputType } from "../index.js" */ +/** @import { ParametersHierarchicalClustering } from "./index.js" */ + +/** + * Hierarchical Clustering + * + * A bottom-up approach (agglomerative) to clustering that builds a tree of clusters (dendrogram). + * Supports different linkage criteria: single, complete, and average. + * + * @class + * @extends Clustering + * @category Clustering + */ +class HierarchicalClustering extends Clustering { + /** @type {Cluster | null} */ + root = null; + + /** + * @param {InputType} points - Data or distance matrix if metric is 'precomputed' + * @param {Partial} parameters + */ + constructor(points, parameters = {}) { + super( + points, + /** @type {ParametersHierarchicalClustering} */ ( + Object.assign({ linkage: "complete", metric: euclidean }, parameters) + ), + ); + this._id = 0; + if (this._parameters.metric === "precomputed" && this._matrix.shape[0] !== this._matrix.shape[1]) { + throw new Error("If metric is 'precomputed', then matrix has to be square!"); + } + + const metric = this._parameters.metric; + const A = this._matrix; + const N = this._N; + this._d_min = new Float64Array(N); + const d_min = this._d_min; + let distance_matrix; + if (metric !== "precomputed") { + distance_matrix = new Matrix(N, N, Infinity); + for (let i = 0; i < N; ++i) { + distance_matrix.set_entry(i, i, 0); + d_min[i] = i; // temporary + const Ai = A.row(i); + for (let j = i + 1; j < N; ++j) { + const dist = metric(Ai, A.row(j)); + distance_matrix.set_entry(i, j, dist); + distance_matrix.set_entry(j, i, dist); + } + } + for (let i = 0; i < N; i++) { + let min_j = 0; + let min_d = Infinity; + for (let j = 0; j < N; j++) { + if (i === j) continue; + const d = distance_matrix.entry(i, j); + if (d < min_d) { + min_d = d; + min_j = j; + } + } + d_min[i] = min_j; + } + } else { + distance_matrix = this._matrix.clone(); + for (let i = 0; i < N; ++i) { + distance_matrix.set_entry(i, i, 0); + d_min[i] = i === 0 ? 1 : 0; + for (let j = 0; j < N; ++j) { + if (i === j) continue; + if (distance_matrix.entry(i, d_min[i]) > distance_matrix.entry(i, j)) { + d_min[i] = j; + } + } + } + } + this._distance_matrix = distance_matrix; + this._clusters = new Array(N); + const clusters = this._clusters; + this._c_size = new Uint16Array(N); + const c_size = this._c_size; + for (let i = 0; i < N; ++i) { + clusters[i] = []; + clusters[i][0] = new Cluster(this._id++, null, null, 0, A.row(i), i, 1, 0); + c_size[i] = 1; + } + const D = this._distance_matrix; + const linkage = this._parameters.linkage; + const p_max = N - 1; + for (let p = 0; p < p_max; ++p) { + let c1 = -1; + let min_dist = Infinity; + for (let i = 0; i < N; ++i) { + if (D.entry(i, i) === Infinity) continue; + const dist = D.entry(i, d_min[i]); + if (dist < min_dist) { + min_dist = dist; + c1 = i; + } + } + if (c1 === -1) break; + + const c2 = d_min[c1]; + const c1_cluster = clusters[c1][0]; + const c2_cluster = clusters[c2][0]; + const c1_cluster_indices = c1_cluster.isLeaf ? [c1_cluster.index] : c1_cluster.index; + const c2_cluster_indices = c2_cluster.isLeaf ? [c2_cluster.index] : c2_cluster.index; + const indices = c1_cluster_indices.concat(c2_cluster_indices); + const new_cluster = new Cluster(this._id++, c1_cluster, c2_cluster, D.entry(c1, c2), null, indices); + c1_cluster.parent = new_cluster; + c2_cluster.parent = new_cluster; + clusters[c1].unshift(new_cluster); + + const size1 = c_size[c1]; + const size2 = c_size[c2]; + c_size[c1] += size2; + + for (let j = 0; j < N; ++j) { + if (j === c1 || j === c2 || D.entry(j, j) === Infinity) continue; + const D_c1_j = D.entry(c1, j); + const D_c2_j = D.entry(c2, j); + let value; + switch (linkage) { + case "single": + value = Math.min(D_c1_j, D_c2_j); + break; + case "complete": + value = Math.max(D_c1_j, D_c2_j); + break; + case "average": + value = (size1 * D_c1_j + size2 * D_c2_j) / (size1 + size2); + break; + } + D.set_entry(j, c1, value); + D.set_entry(c1, j, value); + } + + D.set_entry(c2, c2, Infinity); + for (let i = 0; i < N; ++i) { + D.set_entry(i, c2, Infinity); + D.set_entry(c2, i, Infinity); + } + + // Update d_min for all rows + for (let i = 0; i < N; i++) { + if (D.entry(i, i) === Infinity) continue; + if (d_min[i] === c1 || d_min[i] === c2 || i === c1) { + let min_j = 0; + let min_d = Infinity; + for (let j = 0; j < N; j++) { + if (i === j || D.entry(j, j) === Infinity) continue; + const d = D.entry(i, j); + if (d < min_d) { + min_d = d; + min_j = j; + } + } + d_min[i] = min_j; + } else { + if (D.entry(i, c1) < D.entry(i, d_min[i])) { + d_min[i] = c1; + } + } + } + + this.root = new_cluster; + } + } + + /** + * @param {number} value - Value where to cut the tree. + * @param {"distance" | "depth"} [type="distance"] - Type of value. Default is `"distance"` + * @returns {Cluster[][]} - Array of clusters with the indices of the rows in given points. + */ + get_clusters_raw(value, type = "distance") { + /** @type {Cluster[][]} */ + const clusters = []; + /** @type {(d: {dist: number, depth: number}) => number} */ + let accessor; + switch (type) { + case "distance": + accessor = (d) => d.dist; + break; + case "depth": + accessor = (d) => d.depth; + break; + default: + throw new Error("invalid type"); + } + this._traverse(/** @type {Cluster} */ (this.root), accessor, value, clusters); + return clusters; + } + + /** + * @param {number} value - Value where to cut the tree. + * @param {"distance" | "depth"} [type="distance"] - Type of value. Default is `"distance"` + * @returns {number[][]} - Array of clusters with the indices of the rows in given points. + */ + get_clusters(value, type = "distance") { + /** @type {Cluster[][]} */ + const clusters = []; + /** @type {(d: {dist: number, depth: number}) => number} */ + let accessor; + switch (type) { + case "distance": + accessor = (d) => d.dist; + break; + case "depth": + accessor = (d) => d.depth; + break; + default: + throw new Error("invalid type"); + } + if (this.root) this._traverse(this.root, accessor, value, clusters); + return clusters.map((cluster) => cluster.map((d) => d.index)); + } + + /** + * @param {number} value - Value where to cut the tree. + * @param {"distance" | "depth"} [type="distance"] - Type of value. Default is `"distance"` + * @returns {number[]} - Array of clusters with the indices of the rows in given points. + */ + get_cluster_list(value, type = "distance") { + const clusters = this.get_clusters(value, type); + /** @type {number[]} */ + const list = new Array(this._N).fill(0); + for (let i = 0; i < clusters.length; ++i) { + const cluster = clusters[i]; + for (let j = 0; j < cluster.length; ++j) { + const index = cluster[j]; + list[index] = i; + } + } + return list; + } + + /** + * @private + * @param {Cluster} node + * @param {(d: {dist: number, depth: number}) => number} f + * @param {number} value + * @param {Cluster[][]} result + */ + _traverse(node, f, value, result) { + if (f(node) <= value) { + result.push(node.leaves()); + } else { + if (node.left) this._traverse(node.left, f, value, result); + if (node.right) this._traverse(node.right, f, value, result); + } + } +} + +/** @private */ +class Cluster { + /**@type {number} */ + size; + /**@type {number} */ + depth; + /**@type {Cluster | null} */ + parent; + + /** + * + * @param {number} id + * @param {Cluster?} left + * @param {Cluster?} right + * @param {number} dist + * @param {Float64Array?} centroid + * @param {number} index + * @param {number} [size] + * @param {number} [depth] + */ + constructor(id, left, right, dist, centroid, index, size, depth) { + this.id = id; + this.left = left; + this.right = right; + this.dist = dist; + this.index = index; + if (size) { + this.size = size; + } else { + if (!left || !right) throw new Error("If size is not given, left & right cannot be null!"); + this.size = left.size + right.size; + } + + if (depth !== undefined) { + this.depth = depth; + } else { + if (!left || !right) throw new Error("If depth is not given, left & right cannot be null!"); + this.depth = Math.max(left.depth, right.depth) + 1; + } + + if (centroid !== undefined && centroid !== null) { + this.centroid = centroid; + } else { + if (!left || !right) throw new Error("If centroid is not given, left & right cannot be null!"); + + this.centroid = this._calculate_centroid(left, right); + } + + this.parent = null; + } + + /** + * + * @param {Cluster} left + * @param {Cluster} right + * @returns {Float64Array} + */ + _calculate_centroid(left, right) { + const l_size = left.size; + const r_size = right.size; + const l_centroid = left.centroid; + const r_centroid = right.centroid; + const size = this.size; + const n = left.centroid.length; + const new_centroid = new Float64Array(n); + for (let i = 0; i < n; ++i) { + new_centroid[i] = (l_size * l_centroid[i] + r_size * r_centroid[i]) / size; + } + return new_centroid; + } + + get isLeaf() { + return this.depth === 0; + } + + /** + * + * @returns {Cluster[]} + */ + leaves() { + if (this.isLeaf) return [this]; + const left = this.left; + const right = this.right; + return (left ? (left.isLeaf ? [left] : left.leaves()) : []).concat( + right ? (right.isLeaf ? [right] : right.leaves()) : [], + ); + } + + /** + * + * @returns {Cluster[]} + */ + descendants() { + if (this.isLeaf) return [this]; + const left_descendants = this.left ? this.left.descendants() : []; + const right_descendants = this.right ? this.right.descendants() : []; + return left_descendants.concat(right_descendants).concat([this]); + } +} + +/** + * @template T + * @typedef {Object} DisjointSetPayload + * @property {T} parent + * @property {Set} children + * @property {number} size + */ + +/** + * @template T + * @class + * @category Data Structures + * @see {@link https://en.wikipedia.org/wiki/Disjoint-set_data_structure} + */ +class DisjointSet { + /** + * @param {T[]?} elements + */ + constructor(elements = null) { + /** + * @private + * @type {Map>} + */ + this._list = new Map(); + if (elements) { + for (const e of elements) { + this.make_set(e); + } + } + } + + /** + * @private + * @param {T} x + * @returns {DisjointSet} + */ + make_set(x) { + const list = this._list; + if (!list.has(x)) { + list.set(x, { parent: x, children: new Set([x]), size: 1 }); + } + return this; + } + + /** + * @param {T} x + * @returns + */ + find(x) { + const list = this._list; + const disjoint_set = list.get(x); + if (disjoint_set) { + if (disjoint_set.parent !== x) { + disjoint_set.children.add(x); + const new_parent = this.find(disjoint_set.parent); + if (!new_parent) throw new Error("should not happen!"); + disjoint_set.parent = new_parent; + return disjoint_set.parent; + } else { + return x; + } + } else { + return null; + } + } + + /** + * @param {T} x + * @param {T} y + * @returns + */ + union(x, y) { + let node_x = this.find(x); + let node_y = this.find(y); + + if (!node_x || !node_y) throw new Error("x or y not found!"); + + let disjoint_set_x = this._list.get(node_x); + let disjoint_set_y = this._list.get(node_y); + + if (!disjoint_set_x || !disjoint_set_y) throw new Error("should not happen!"); + + if (node_x === node_y) return this; + if (disjoint_set_x.size < disjoint_set_y.size) { + [node_x, node_y] = [node_y, node_x]; + [disjoint_set_x, disjoint_set_y] = [disjoint_set_y, disjoint_set_x]; + } + + disjoint_set_y.parent = node_x; + // keep track of children + disjoint_set_y.children.forEach(disjoint_set_x.children.add, disjoint_set_x.children); + disjoint_set_x.size += disjoint_set_y.size; + + return this; + } + + /** @param {T} x */ + get_children(x) { + const node = this._list.get(x); + if (node) { + return node.children; + } else { + return null; + } + } +} + +/** @import { Comparator } from "./index.js" */ + +/** + * @template T + * @class + * @category Data Structures + */ +class Heap { + /** @type {{ element: T; value: number }[]} */ + _container; + + /** @type {Comparator} */ + _comparator; + + /** + * A heap is a datastructure holding its elements in a specific way, so that the top element would be the first + * entry of an ordered list. + * + * @param {T[]?} elements - Contains the elements for the Heap. `elements` can be null. + * @param {(d: T) => number} accessor - Function returns the value of the element. + * @param {"min" | "max" | Comparator} [comparator="min"] - Function returning true or false + * defining the wished order of the Heap, or String for predefined function. ("min" for a Min-Heap, "max" for a + * Max_heap). Default is `"min"` + * @see {@link https://en.wikipedia.org/wiki/Binary_heap} + */ + constructor(elements = null, accessor, comparator = "min") { + /** @type {(d: T) => number} */ + this._accessor = accessor; + this._container = []; + if (comparator === "min") { + this._comparator = (a, b) => a < b; + } else if (comparator === "max") { + this._comparator = (a, b) => a > b; + } else { + this._comparator = comparator; + } + if (elements) { + this._container = []; + for (const e of elements) { + this._container.push({ + element: e, + value: accessor(e), + }); + } + for (let i = Math.floor(elements.length / 2 - 1); i >= 0; --i) { + this._heapify_down(i); + } + } + } + + /** + * Creates a Heap from an Array + * + * @template T + * @param {T[]} elements - Contains the elements for the Heap. + * @param {(d: T) => number} accessor - Function returns the value of the element. + * @param {"min" | "max" | Comparator} [comparator="min"] - Function returning true or false + * defining the wished order of the Heap, or String for predefined function. ("min" for a Min-Heap, "max" for a + * Max_heap). Default is `"min"` + * @returns {Heap} + */ + static heapify(elements, accessor, comparator = "min") { + const heap = new Heap(null, accessor, comparator); + const container = heap._container; + for (const e of elements) { + container.push({ + element: e, + value: accessor(e), + }); + } + for (let i = Math.floor(elements.length / 2 - 1); i >= 0; --i) { + heap._heapify_down(i); + } + return heap; + } + + /** + * Swaps elements of container array. + * + * @private + * @param {number} index_a + * @param {number} index_b + */ + _swap(index_a, index_b) { + const container = this._container; + [container[index_b], container[index_a]] = [container[index_a], container[index_b]]; + return; + } + + /** @private */ + _heapify_up() { + const container = this._container; + let index = container.length - 1; + while (index > 0) { + const parentIndex = Math.floor((index - 1) / 2); + if (!this._comparator(container[index].value, container[parentIndex].value)) { + break; + } else { + this._swap(parentIndex, index); + index = parentIndex; + } + } + } + + /** + * Pushes the element to the heap. + * + * @param {T} element + * @returns {Heap} + */ + push(element) { + const value = this._accessor(element); + //const node = new Node(element, value); + const node = { element: element, value: value }; + this._container.push(node); + this._heapify_up(); + return this; + } + + /** + * @private + * @param {Number} [start_index=0] Default is `0` + */ + _heapify_down(start_index = 0) { + const container = this._container; + const comparator = this._comparator; + const length = container.length; + const left = 2 * start_index + 1; + const right = 2 * start_index + 2; + let index = start_index; + if (index >= length) throw "index higher than length"; + if (left < length && comparator(container[left].value, container[index].value)) { + index = left; + } + if (right < length && comparator(container[right].value, container[index].value)) { + index = right; + } + if (index !== start_index) { + this._swap(start_index, index); + this._heapify_down(index); + } + } + + /** + * Removes and returns the top entry of the heap. + * + * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by + * `accessor`}). + */ + pop() { + const container = this._container; + if (container.length === 0) { + return null; + } else if (container.length === 1) { + const item = container.pop(); + if (!item) throw new Error("Cannot happen!"); + return item; + } + this._swap(0, container.length - 1); + const item = container.pop(); + this._heapify_down(); + return item ?? null; + } + + /** + * Returns the top entry of the heap without removing it. + * + * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by + * `accessor`). + */ + get first() { + return this._container.length > 0 ? this._container[0] : null; + } + + /** + * Yields the raw data + * + * @yields {T} Object consists of the element and its value (computed by `accessor`}). + */ + *iterate() { + for (let i = 0, n = this._container.length; i < n; ++i) { + yield this._container[i].element; + } + } + + /** + * Returns the heap as ordered array. + * + * @returns {T[]} Array consisting the elements ordered by `comparator`. + */ + toArray() { + return this._container.sort((a, b) => (this._comparator(a.value, b.value) ? -1 : 1)).map((d) => d.element); + } + + /** + * Returns elements of container array. + * + * @returns {T[]} Array consisting the elements. + */ + data() { + return this._container.map((d) => d.element); + } + + /** + * Returns the container array. + * + * @returns {{ element: T; value: number }[]} The container array. + */ + raw_data() { + return this._container; + } + + /** + * The size of the heap. + * + * @returns {number} + */ + get length() { + return this._container.length; + } + + /** + * Returns false if the the heap has entries, true if the heap has no entries. + * + * @returns {boolean} + */ + get empty() { + return this.length === 0; + } +} + +/** @import { InputType } from "../index.js" */ +/** @import { ParametersKMeans } from "./index.js" */ +/** + * K-Means Clustering + * + * A popular clustering algorithm that partitions data into K clusters where each point + * belongs to the cluster with the nearest mean (centroid). + * + * @class + * @extends Clustering + * @category Clustering + * @see {@link KMedoids} for a more robust alternative + * + * @example + * import * as druid from "@saehrimnir/druidjs"; + * + * const points = [[1, 1], [1.5, 1.5], [5, 5], [5.5, 5.5]]; + * const kmeans = new druid.KMeans(points, { K: 2 }); + * + * const clusters = kmeans.get_cluster_list(); // [0, 0, 1, 1] + * const centroids = kmeans.centroids; // center points + */ +class KMeans extends Clustering { + /** + * @param {InputType} points + * @param {Partial} parameters + */ + constructor(points, parameters = {}) { + super( + points, + /** @type {ParametersKMeans} */ (Object.assign({ K: 4, metric: euclidean, seed: 1212 }, parameters)), + ); + + const K = this._parameters.K; + const seed = parameters.seed; + + // Convert points to Matrix if needed + if (points instanceof Matrix) { + this._matrix = points; + } else { + this._matrix = Matrix.from(points); + } + + const [N, D] = this._matrix.shape; + this._N = N; + this._D = D; + + this._K = K > N ? N : K; + this._randomizer = new Randomizer(seed); + + /** @type {number[]} */ + this._clusters = new Array(N).fill(0); + + this._cluster_centroids = parameters.initial_centroids + ? parameters.initial_centroids.map((c) => new Float64Array(c)) + : this._get_random_centroids(this._K); + let cluster_centroids = this._cluster_centroids; + let iterations = 0; + const max_iterations = 300; + let clusters_changed = true; + + while (clusters_changed && iterations < max_iterations) { + const iteration_result = this._iteration(cluster_centroids); + cluster_centroids = iteration_result.cluster_centroids; + clusters_changed = iteration_result.clusters_changed; + iterations++; + } + + this._cluster_centroids = cluster_centroids; + } + + /** @returns {number} The number of clusters */ + get k() { + return this._K; + } + + /** @returns {Float64Array[]} The cluster centroids */ + get centroids() { + return this._cluster_centroids; + } + + /** @returns {number[]} The cluster list */ + get_cluster_list() { + return this._clusters; + } + + /** @returns {number[][]} An Array of clusters with the indices of the points. */ + get_clusters() { + const K = this._K; + const clusters = this._clusters; + /** @type {number[][]} */ + const result = new Array(K).fill(0).map(() => []); + clusters.forEach((c, i) => { + if (c >= 0 && c < K) { + result[c].push(i); + } + }); + return result; + } + + /** + * @private + * @param {number[]} point_indices + * @param {number[]} candidates + * @returns {number} + */ + _furthest_point(point_indices, candidates) { + const A = this._matrix; + const metric = this._parameters.metric; + + if (point_indices.length === 0 || candidates.length === 0) { + return candidates[0] ?? 0; + } + + const H = Heap.heapify( + candidates, + (d) => { + const Ad = A.row(d); + let sum = 0; + for (let j = 0; j < point_indices.length; ++j) { + sum += metric(Ad, A.row(point_indices[j])); + } + return sum; + }, + "max", + ); + + const furthest = H.pop(); + if (!furthest) throw new Error("Should not happen!"); + + return furthest.element; + } + + /** + * @private + * @param {number} K + * @returns {Float64Array[]} + */ + _get_random_centroids(K) { + const N = this._N; + const randomizer = this._randomizer; + const A = this._matrix; + /** @type {Float64Array[]} */ + const cluster_centroids = new Array(K); + const indices = linspace(0, N - 1); + + // First centroid: random selection + const random_point = randomizer.random_int % N; + cluster_centroids[0] = A.row(random_point); + const init_points = [random_point]; + + const sample_size = Math.max(1, Math.floor((N - K) / K)); + + for (let i = 1; i < K; ++i) { + const remaining = indices.filter((d) => !init_points.includes(d)); + if (remaining.length === 0) break; + + const sample = randomizer.choice(remaining, Math.min(sample_size, remaining.length)); + const furthest_point = this._furthest_point(init_points, sample); + + init_points.push(furthest_point); + cluster_centroids[i] = A.row(furthest_point); + } + + return cluster_centroids; + } + + /** + * @private + * @param {Float64Array[]} cluster_centroids + * @returns {{ clusters_changed: boolean; cluster_centroids: Float64Array[] }} + */ + _iteration(cluster_centroids) { + const K = cluster_centroids.length; + const N = this._N; + const metric = this._parameters.metric; + const A = this._matrix; + const clusters = this._clusters; + let clusters_changed = false; + + // Find nearest cluster centroid for each point + for (let i = 0; i < N; ++i) { + const Ai = A.row(i); + let min_dist = Infinity; + let min_cluster = 0; + + for (let j = 0; j < K; ++j) { + const d = metric(cluster_centroids[j], Ai); + if (d < min_dist) { + min_dist = d; + min_cluster = j; + } + } + + if (clusters[i] !== min_cluster) { + clusters_changed = true; + clusters[i] = min_cluster; + } + } + + // Update cluster centroids + const new_centroids = this._compute_centroid(K); + + return { + clusters_changed: clusters_changed, + cluster_centroids: new_centroids, + }; + } + + /** + * @private + * @param {number} K + * @returns {Float64Array[]} + */ + _compute_centroid(K) { + const N = this._N; + const D = this._D; + const A = this._matrix; + const clusters = this._clusters; + + // Initialize new centroids and counters + /** @type {Float64Array[]} */ + const new_centroids = new Array(K); + const cluster_counter = new Array(K).fill(0); + + for (let i = 0; i < K; ++i) { + new_centroids[i] = new Float64Array(D); + } + + // Sum up all points in each cluster + for (let i = 0; i < N; ++i) { + const Ai = A.row(i); + const ci = clusters[i]; + if (ci >= 0 && ci < K) { + cluster_counter[ci]++; + const centroid = new_centroids[ci]; + for (let j = 0; j < D; ++j) { + centroid[j] += Ai[j]; + } + } + } + + // Divide by count to get mean + for (let i = 0; i < K; ++i) { + const n = cluster_counter[i]; + if (n > 0) { + const centroid = new_centroids[i]; + for (let j = 0; j < D; ++j) { + centroid[j] /= n; + } + } + } + + return new_centroids; + } +} + +/** @import {InputType} from "../index.js" */ +/** @import { ParametersKMedoids } from "./index.js" */ + +/** + * K-Medoids (PAM - Partitioning Around Medoids) + * + * A robust clustering algorithm similar to K-Means, but uses actual data points (medoids) + * as cluster centers and can work with any distance metric. + * + * @class + * @extends Clustering + * @category Clustering + * @see {@link KMeans} for a faster but less robust alternative + */ +class KMedoids extends Clustering { + /** + * @param {InputType} points - Data matrix + * @param {Partial} parameters + * @see {@link https://link.springer.com/chapter/10.1007/978-3-030-32047-8_16} Faster k-Medoids Clustering: Improving the PAM, CLARA, and CLARANS Algorithms + */ + constructor(points, parameters = {}) { + super(points, Object.assign({ K: 4, max_iter: null, metric: euclidean, seed: 1212 }, parameters)); + this._A = this._matrix.to2dArray(); + let K = this._parameters.K; + const N = this._N; + this._max_iter = this._parameters.max_iter ?? 10 * Math.log10(N); + this._distance_matrix = new Matrix(N, N, "zeros"); + + if (K > N) { + this._parameters.K = K = N; + } + this._randomizer = new Randomizer(this._parameters.seed); + this._clusters = new Array(N).fill(-1); + this._cluster_medoids = this._get_random_medoids(K); + this._is_initialized = false; + } + + /** @returns {number[]} The cluster list */ + get_cluster_list() { + if (!this._is_initialized) { + this.get_clusters(); + } + return this._clusters; + } + + /** @returns {number[][]} - Array of clusters with the indices of the rows in given points. */ + get_clusters() { + const K = this._parameters.K; + const A = this._A; + const N = this._N; + if (!this._is_initialized) { + this.init(K, this._cluster_medoids); + } + /** @type {number[][]} */ + const result = new Array(K).fill(0).map(() => []); + for (let j = 0; j < N; j++) { + const nearest = this._nearest_medoid(A[j], j); + const cluster_idx = nearest.index_nearest; + result[cluster_idx].push(j); + this._clusters[j] = cluster_idx; + } + return result; + } + + /** @returns {number} */ + get k() { + return this._parameters.K; + } + + /** @returns {number[]} */ + get medoids() { + return this.get_medoids(); + } + + /** @returns {number[]} */ + get_medoids() { + const K = this._parameters.K; + if (!this._is_initialized) { + this.init(K, this._cluster_medoids); + } + return this._cluster_medoids; + } + + async *generator() { + const max_iter = this._max_iter; + if (!this._is_initialized) { + this.get_clusters(); + } + yield this.get_clusters(); + let i = 0; + while (i < max_iter) { + const finish = this._iteration(); + this._update_clusters(); + yield this.get_clusters(); + if (finish) break; + i++; + } + } + + /** Algorithm 1. FastPAM1: Improved SWAP algorithm */ + /* _iteration_1() { + const A = this._A; + const N = this._N; + const K = this._K; + const medoids = this._cluster_medoids; + let DeltaTD = 0; + let m0 = null; + let x0 = null; + A.forEach((x_j, j) => { + if (medoids.findIndex(m => m === j) < 0) { + const nearest_medoid = this._nearest_medoid(x_j, j); + const d_j = nearest_medoid.distance_nearest; // distance to current medoid + const deltaTD = new Array(K).fill(-d_j); // change if making j a medoid + A.forEach((x_o, o) => { + // disance to new medoid + const d_oj = this._get_distance(o, j, x_o, x_j); + const { + "index_nearest": n, + "distance_nearest": d_n, + "distance_second": d_s, + } = this._nearest_medoid(x_o, o); + this._clusters[o] = n; // cached values + deltaTD[n] += Math.min(d_oj, d_s) - d_n; // loss change + if (d_oj < d_n) { // reassignment check + deltaTD.forEach((d_i, i) => { + if (n !== i) { + deltaTD[i] = d_i + d_oj - d_n; // update loss change + } + }); + } + }); + // choose best medoid i; + const i = deltaTD + .map((d, i) => [d, i]) + .sort((d1, d2) => d1[0] - d2[0])[0][1]; + const deltaTD_i = deltaTD[i]; + // store + if (deltaTD_i < DeltaTD) { + DeltaTD = deltaTD_i; + m0 = i; + x0 = j; + } + } + }); + + if (DeltaTD >= 0) { + return true // break loop if DeltaTD >= 0 + } + // swap roles of medoid m and non-medoid x; + medoids[m0] = x0; + this._cluster_medoids = medoids; + return false + } */ + + /** + * FastPAM1: One best swap per iteration + * @private + * @returns {boolean} + */ + _iteration() { + const A = this._A; + const K = this._parameters.K; + const medoids = this._cluster_medoids; + const N = this._N; + + // Precompute nearest and second nearest medoid for all points + const cache = new Array(N); + for (let i = 0; i < N; i++) { + cache[i] = this._nearest_medoid(A[i], i); + } + + let best_delta = 0; + let best_swap = null; // { m_idx: index in medoids, x_idx: index in A } + + // For each non-medoid point j, evaluate swapping it with each medoid i + const medoid_set = new Set(medoids); + for (let j = 0; j < N; j++) { + if (medoid_set.has(j)) continue; + + const x_j = A[j]; + const d_j = cache[j].distance_nearest; + + // deltaTD[i] will store the change in total distance if we swap medoid[i] with j + const deltaTD = new Array(K).fill(-d_j); + + for (let o = 0; o < N; o++) { + if (o === j) continue; + const dist_o_j = this._get_distance(o, j, A[o], x_j); + const { index_nearest: n, distance_nearest: d_n, distance_second: d_s } = cache[o]; + + // If o is assigned to the current medoid being swapped out (n) + deltaTD[n] += Math.min(dist_o_j, d_s) - d_n; + + // For all other medoids i != n, if j is closer to o than its current medoid + if (dist_o_j < d_n) { + for (let i = 0; i < K; i++) { + if (i !== n) { + deltaTD[i] += dist_o_j - d_n; + } + } + } + } + + // Find best medoid to swap with j + for (let i = 0; i < K; i++) { + if (deltaTD[i] < best_delta) { + best_delta = deltaTD[i]; + best_swap = { m_idx: i, x_idx: j }; + } + } + } + + if (best_swap && best_delta < 0) { + medoids[best_swap.m_idx] = best_swap.x_idx; + this._cluster_medoids = medoids; + return false; // not finished + } + + return true; // finished + } + + /** + * @private + * Get distance between two points + * @param {number} i + * @param {number} j + * @param {Float64Array?} x_i + * @param {Float64Array?} x_j + * @returns {number} + */ + _get_distance(i, j, x_i = null, x_j = null) { + if (i === j) return 0; + const D = this._distance_matrix; + const A = this._A; + const metric = this._parameters.metric; + let d_ij = D.entry(i, j); + if (d_ij === 0) { + d_ij = metric(x_i || A[i], x_j || A[j]); + D.set_entry(i, j, d_ij); + D.set_entry(j, i, d_ij); + } + return d_ij; + } + + /** + * @private + * @param {Float64Array} x_j + * @param {number} j + * @returns + */ + _nearest_medoid(x_j, j) { + const medoids = this._cluster_medoids; + const A = this._A; + if (medoids.length === 0) { + throw new Error("No medoids available. Initialization failed."); + } + + let d_n = Infinity; + let n = -1; + let d_s = Infinity; + let s = -1; + + for (let i = 0; i < medoids.length; i++) { + const m = medoids[i]; + const d = this._get_distance(j, m, x_j, A[m]); + if (d < d_n) { + d_s = d_n; + s = n; + d_n = d; + n = i; + } else if (d < d_s) { + d_s = d; + s = i; + } + } + + if (s === -1) s = n; + + return { + distance_nearest: d_n, + index_nearest: n, + distance_second: d_s, + index_second: s, + }; + } + + /** + * @private + */ + _update_clusters() { + const N = this._N; + const A = this._A; + for (let j = 0; j < N; j++) { + const nearest = this._nearest_medoid(A[j], j); + this._clusters[j] = nearest.index_nearest; + } + } + + /** + * Computes `K` clusters out of the `matrix`. + * @param {number} K - Number of clusters. + * @param {number[]} cluster_medoids + */ + init(K, cluster_medoids) { + if (!K) K = this._parameters.K; + if (!cluster_medoids) cluster_medoids = this._get_random_medoids(K); + this._cluster_medoids = cluster_medoids; + const max_iter = this._max_iter; + let finish = false; + let i = 0; + do { + finish = this._iteration(); + } while (!finish && ++i < max_iter); + this._update_clusters(); + this._is_initialized = true; + return this; + } + + /** + * Algorithm 3. FastPAM LAB: Linear Approximate BUILD initialization. + * @private + * @param {number} K - Number of clusters + * @returns {number[]} + */ + _get_random_medoids(K) { + const N = this._N; + const A = this._A; + const indices = linspace(0, N - 1); + const randomizer = this._randomizer; + const n = Math.min(N, 10 + Math.ceil(Math.sqrt(N))); + + // Handle case where K >= N + if (K >= N) { + return indices.slice(0, N); + } + + /** @type {number[]} */ + const medoids = []; + + // first medoid: select from a random sample of size n + let best_j = -1; + let min_td = Infinity; + let S = randomizer.choice(indices, n); + for (let j = 0; j < S.length; ++j) { + let td = 0; + const S_j = S[j]; + const x_j = A[S_j]; + for (let o = 0; o < S.length; ++o) { + if (o === j) continue; + td += this._get_distance(S_j, S[o], x_j, A[S[o]]); + } + if (td < min_td) { + min_td = td; + best_j = S_j; + } + } + medoids.push(best_j); + + // other medoids: greedy additive selection (Algorithm LAB) + for (let i = 1; i < K; ++i) { + let best_idx = -1; + let best_delta = Infinity; + + const remainingIndices = indices.filter((idx) => !medoids.includes(idx)); + if (remainingIndices.length === 0) break; + + S = randomizer.choice(remainingIndices, Math.min(n, remainingIndices.length)); + for (let j = 0; j < S.length; ++j) { + let deltaTD = 0; + const S_j = S[j]; + const x_j = A[S_j]; + + // Estimate TD reduction on the sample S + for (let o = 0; o < S.length; ++o) { + if (o === j) continue; + const S_o = S[o]; + const x_o = A[S_o]; + + // Closest distance to current medoids + let min_d_existing = Infinity; + for (let m = 0; m < medoids.length; m++) { + const d = this._get_distance(S_o, medoids[m], x_o, A[medoids[m]]); + if (d < min_d_existing) min_d_existing = d; + } + + const delta = this._get_distance(S_j, S_o, x_j, x_o) - min_d_existing; + if (delta < 0) { + deltaTD += delta; + } + } + + if (deltaTD < best_delta) { + best_delta = deltaTD; + best_idx = S_j; + } + } + if (best_idx !== -1) { + medoids.push(best_idx); + } + } + return medoids; + } +} + +/** @import { ParametersMeanShift } from "./index.js" */ +/** @import { InputType } from "../index.js" */ + +/** + * Mean Shift Clustering + * + * A non-parametric clustering technique that does not require prior knowledge of the + * number of clusters. It identifies centers of density in the data. + * + * @class + * @extends Clustering + * @category Clustering + */ +class MeanShift extends Clustering { + /** + * @private + * @type {number} + */ + _bandwidth; + /** + * @private + * @type {number} + */ + _max_iter; + /** + * @private + * @type {number} + */ + _tolerance; + /** + * @private + * @type {(dist: number) => number} + */ + _kernel; + /** + * @type {Matrix} + */ + _points; + /** + * @private + * @type {number[] | undefined} + */ + _clusters; + /** + * @private + * @type {number[][] | undefined} + */ + _cluster_list; + + /** + * + * @param {InputType} points + * @param {Partial} parameters + */ + constructor(points, parameters = {}) { + super( + points, + /** @type {ParametersMeanShift} */ ( + Object.assign({ seed: 1212, metric: euclidean, bandwidth: 0, kernel: "gaussian" }, parameters) + ), + ); + + // Ensure bandwidth is positive + this._bandwidth = parameters.bandwidth ?? this._compute_bandwidth(this._matrix); + this._max_iter = parameters.max_iter ?? Math.max(10, Math.floor(10 * Math.log10(this._N))); + this._tolerance = parameters.tolerance ?? 1e-3; + const kernel_param = parameters.kernel ?? "gaussian"; + // If kernel is a string, map to function + if (typeof kernel_param === "string") { + if (kernel_param === "flat") { + this._kernel = (dist) => (dist <= this._bandwidth ? 1 : 0); + } else { + // gaussian (default) + this._kernel = (dist) => Math.exp(-(dist * dist) / (2 * this._bandwidth * this._bandwidth)); + } + } else { + // custom function + this._kernel = kernel_param; + } + + // Copy points to a mutable matrix + this._points = this._matrix.clone(); + + this._mean_shift(); + this._assign_clusters(); + } + + /** + * Helper to compute bandwidth if not provided + * @private + * @param {Matrix} matrix + * @returns {number} + */ + _compute_bandwidth(matrix) { + const N = matrix.shape[0]; + //const D = matrix.shape[1]; + // Compute average pairwise distance + let totalDist = 0; + for (let i = 0; i < N; ++i) { + const row_i = matrix.row(i); + for (let j = i + 1; j < N; ++j) { + const row_j = matrix.row(j); + const dist = this._parameters.metric(row_i, row_j); + totalDist += dist; + } + } + const avgDist = totalDist / ((N * (N - 1)) / 2); + // Use a fraction of avgDist as bandwidth + return avgDist / 2; + } + + /** + * Compute kernel weight + * @private + * @param {number} dist + * @returns {number} + */ + _kernel_weight(dist) { + return this._kernel(dist); + } + + /** + * Perform mean shift iterations + * @private + */ + _mean_shift() { + const N = this._N; + const D = this._D; + const points = this._points; + const metric = this._parameters.metric; + //const bandwidth = this._bandwidth; + const kernel = this._kernel_weight.bind(this); + const tolerance = this._tolerance; + + for (let iter = 0; iter < this._max_iter; ++iter) { + let max_shift = 0; + // For each point compute shift + for (let i = 0; i < N; ++i) { + const row_i = points.row(i); + let sum_weights = 0; + const weighted_sum = new Float64Array(D); + for (let j = 0; j < N; ++j) { + const row_j = points.row(j); + const dist = metric(row_i, row_j); + const weight = kernel(dist); + sum_weights += weight; + for (let d = 0; d < D; ++d) { + weighted_sum[d] += weight * row_j[d]; + } + } + if (sum_weights === 0) { + // No neighbors within kernel, shift is zero + //const shift = new Float64Array(D); + // Compute shift magnitude + const shift_norm = Math.sqrt(weighted_sum.reduce((acc, v) => acc + v * v, 0)); + max_shift = Math.max(max_shift, shift_norm); + } else { + const shift = new Float64Array(D); + for (let d = 0; d < D; ++d) { + shift[d] = weighted_sum[d] / sum_weights - row_i[d]; + } + const shift_norm = Math.sqrt(shift.reduce((acc, v) => acc + v * v, 0)); + max_shift = Math.max(max_shift, shift_norm); + // Update point + for (let d = 0; d < D; ++d) { + row_i[d] += shift[d]; + } + } + } + if (max_shift < tolerance) { + // Converged + break; + } + } + } + + /** + * After convergence, assign clusters based on nearest mode + * @private + */ + _assign_clusters() { + const N = this._N; + const metric = this._parameters.metric; + const bandwidth = this._bandwidth; + + // Group points that converged to the same mode + // Two points are in the same mode if they're within bandwidth/2 of each other + const mode_threshold = bandwidth * 0.5; + /** @type {number[][]} */ + const modes = []; // Each mode contains indices of points in that mode + const point_to_mode = new Array(N).fill(-1); + + for (let i = 0; i < N; ++i) { + if (point_to_mode[i] !== -1) continue; // Already assigned to a mode + + const row_i = this._points.row(i); + const mode = [i]; + point_to_mode[i] = modes.length; + + // Find all points close to this mode + for (let j = i + 1; j < N; ++j) { + if (point_to_mode[j] !== -1) continue; + + const row_j = this._points.row(j); + const dist = metric(row_i, row_j); + + if (dist < mode_threshold) { + mode.push(j); + point_to_mode[j] = modes.length; + } + } + + modes.push(mode); + } + + // Build final clusters - each mode becomes a cluster + /** @type {number[][]} */ + const clusters = []; + const cluster_ids = new Array(N).fill(-1); + + for (let mode_idx = 0; mode_idx < modes.length; ++mode_idx) { + const mode = modes[mode_idx]; + clusters.push([...mode]); + for (const point_idx of mode) { + cluster_ids[point_idx] = mode_idx; + } + } + + this._clusters = cluster_ids; + this._cluster_list = clusters; + } + + /** + * @returns {number[][]} + */ + get_clusters() { + // Ensure algorithm has been run + if (!this._cluster_list) { + this._mean_shift(); + this._assign_clusters(); + } + return /** @type {number[][]} */ (this._cluster_list); + } + + /** + * + * @returns {number[]} + */ + get_cluster_list() { + if (!this._clusters) { + this._mean_shift(); + this._assign_clusters(); + } + return /** @type {number[]} */ (this._clusters); + } +} + +/** @import { InputType } from "../index.js" */ +/** @import { ParametersOptics } from "./index.js" */ + +/** @typedef {Object} DBEntry + * @property {Float64Array} element + * @property {number} index + * @property {number} [reachability_distance] + * @property {boolean} processed + * @property {DBEntry[]} [neighbors] + */ + +/** + * OPTICS (Ordering Points To Identify the Clustering Structure) + * + * A density-based clustering algorithm that extends DBSCAN. It handles clusters of varying + * densities and produces a reachability plot that can be used to extract clusters. + * + * @class + * @extends Clustering + * @category Clustering + */ +class OPTICS extends Clustering { + /** + * **O**rdering **P**oints **T**o **I**dentify the **C**lustering **S**tructure. + * + * @param {InputType} points - The data. + * @param {Partial} [parameters={}] + * @see {@link https://www.dbs.ifi.lmu.de/Publikationen/Papers/OPTICS.pdf} + * @see {@link https://en.wikipedia.org/wiki/OPTICS_algorithm} + */ + constructor(points, parameters = {}) { + super( + points, + /** @type {ParametersOptics} */ ( + Object.assign({ epsilon: 1, min_points: 4, metric: euclidean }, parameters) + ), + ); + const matrix = this._matrix; + /** + * @private + * @type {DBEntry[]} + */ + this._ordered_list = []; + const ordered_list = this._ordered_list; + /** @type {number[][]} */ + this._clusters = []; + const clusters = this._clusters; + + const N = this._N; + + /** + * @private + * @type {DBEntry[]} + */ + this._DB = new Array(N).fill(0).map((_, i) => { + return { + element: matrix.row(i), + index: i, + reachability_distance: undefined, + processed: false, + }; + }); + const DB = this._DB; + + this._cluster_index = 0; + let cluster_index = this._cluster_index; + + for (const p of DB) { + if (p.processed) continue; + p.neighbors = this._get_neighbors(p); + p.processed = true; + clusters.push([p.index]); + cluster_index = clusters.length - 1; + ordered_list.push(p); + if (this._core_distance(p) !== undefined) { + const seeds = new Heap(null, (d) => d.reachability_distance, "min"); + this._update(p, seeds); + this._expand_cluster(seeds, clusters[cluster_index]); + } + } + } + + /** + * @private + * @param {DBEntry} p - A point of the data. + * @returns {DBEntry[]} An array consisting of the `epsilon`-neighborhood of `p`. + */ + _get_neighbors(p) { + if (p?.neighbors) return p.neighbors; + const DB = this._DB; + const metric = this._parameters.metric; + const epsilon = this._parameters.epsilon; + const neighbors = []; + for (const q of DB) { + if (q.index === p.index) continue; + if (metric(p.element, q.element) <= epsilon) { + neighbors.push(q); + } + } + return neighbors; + } + + /** + * @private + * @param {DBEntry} p - A point of `matrix`. + * @returns {number|undefined} The distance to the `min_points`-th nearest point of `p`, or undefined if the + * `epsilon`-neighborhood has fewer elements than `min_points`. + */ + _core_distance(p) { + const min_points = this._parameters.min_points; + const metric = this._parameters.metric; + // Need min_points - 1 other points plus the point itself + if (!p.neighbors || p.neighbors.length < min_points - 1) { + return undefined; + } + // Sort neighbors by distance to find the MinPts-th closest + const sortedNeighbors = p.neighbors.toSorted( + (a, b) => metric(p.element, a.element) - metric(p.element, b.element), + ); + // MinPts-th closest is at index min_points - 2 (0-indexed, excluding p itself) + return metric(p.element, sortedNeighbors[min_points - 2].element); + } + + /** + * Updates the reachability distance of the points. + * + * @private + * @param {DBEntry} p + * @param {Heap} seeds + */ + _update(p, seeds) { + const metric = this._parameters.metric; + const core_distance = this._core_distance(p); + // If p is not a core point, don't update seeds + if (core_distance === undefined) { + return; + } + const neighbors = this._get_neighbors(p); //p.neighbors; + for (const q of neighbors) { + if (q.processed) continue; + const new_reachability_distance = Math.max(core_distance, metric(p.element, q.element)); + //if (q.reachability_distance == undefined) { // q is not in seeds + if (seeds.raw_data().findIndex((d) => d.element === q) < 0) { + q.reachability_distance = new_reachability_distance; + seeds.push(q); + } else { + // q is in seeds + if (new_reachability_distance < (q.reachability_distance ?? Infinity)) { + q.reachability_distance = new_reachability_distance; + seeds = Heap.heapify(seeds.data(), (d) => d.reachability_distance ?? Infinity, "min"); // seeds change key =/ + } + } + } + } + + /** + * Expands the `cluster` with points in `seeds`. + * + * @private + * @param {Heap} seeds + * @param {number[]} cluster + */ + _expand_cluster(seeds, cluster) { + const ordered_list = this._ordered_list; + while (!seeds.empty) { + const q = /** @type {{ element: DBEntry, value: number}} */ (seeds.pop()).element; + q.neighbors = this._get_neighbors(q); + q.processed = true; + cluster.push(q.index); + ordered_list.push(q); + if (this._core_distance(q) !== undefined) { + this._update(q, seeds); + // Recursive call removed - while loop handles iteration correctly + } + } + } + + /** + * Returns an array of clusters. + * + * @returns {number[][]} Array of clusters with the indices of the rows in given `matrix`. + */ + get_clusters() { + const clusters = []; + const outliers = []; + const min_points = this._parameters.min_points; + for (const cluster of this._clusters) { + if (cluster.length < min_points) { + outliers.push(...cluster); + } else { + clusters.push(cluster); + } + } + clusters.push(outliers); + return clusters; + } + + /** + * @returns {number[]} Returns an array, where the ith entry defines the cluster affirmation of the ith point of + * given data. (-1 stands for outlier) + */ + get_cluster_list() { + const N = this._matrix.shape[0]; + /** @type {number[]} */ + const result = new Array(N).fill(0); + const clusters = this.get_clusters(); + for (let i = 0, n = clusters.length; i < n; ++i) { + const cluster = clusters[i]; + for (const index of cluster) { + result[index] = i < n - 1 ? i : -1; + } + } + return result; + } +} + +/** @import { InputType } from "../index.js" */ +/** @import { ParametersXMeans } from "./index.js" */ + +/** + * @typedef SplitResult + * @property {number} index - Index of the cluster being split + * @property {number} bic_parent - BIC score of the parent cluster + * @property {number} bic_children - BIC score of the split children + * @property {number[][]} child_clusters - Clusters after splitting + * @property {Float64Array[]} child_centroids - Centroids of child clusters + */ + +/** + * @typedef CandidateResult + * @property {KMeans} kmeans - The KMeans instance for this K + * @property {number} score - BIC score + */ + +/** + * X-Means Clustering + * + * An extension of K-Means that automatically determines the number of clusters (K) + * using the Bayesian Information Criterion (BIC). + * + * @class + * @extends Clustering + * @category Clustering + */ +class XMeans extends Clustering { + /** + * XMeans clustering algorithm that automatically determines the optimal number of clusters. + * + * X-Means extends K-Means by starting with a minimum number of clusters and iteratively + * splitting clusters to improve the Bayesian Information Criterion (BIC). + * + * Algorithm: + * 1. Start with K_min clusters using KMeans + * 2. For each cluster, try splitting it into 2 sub-clusters + * 3. If BIC improves after splitting, keep the split + * 4. Run KMeans again with all (old + new) centroids + * 5. Repeat until K_max is reached or no more improvements + * + * @param {InputType} points - The data points to cluster + * @param {Partial} [parameters={}] - Configuration parameters + * @see {@link https://www.cs.cmu.edu/~dpelleg/download/xmeans.pdf} + * @see {@link https://github.com/annoviko/pyclustering/blob/master/pyclustering/cluster/xmeans.py} + * @see {@link https://github.com/haifengl/smile/blob/master/core/src/main/java/smile/clustering/XMeans.java} + */ + constructor(points, parameters = {}) { + const defaults = { + K_max: 10, + K_min: 2, + metric: euclidean, + seed: 1212, + min_cluster_size: 35, + tolerance: 0.001, + }; + super(points, /** @type {ParametersXMeans} */ (Object.assign(defaults, parameters))); + this._randomizer = new Randomizer(this._parameters.seed); + + /** @type {KMeans | null} */ + this._best_kmeans = null; + + // Run XMeans algorithm + this._run(); + } + + /** + * Run the XMeans algorithm + * + * @private + */ + _run() { + /** @type {Map} */ + const candidates = new Map(); + const A = this._matrix; + + // Initialize with K_min clusters + let current_kmeans = new KMeans(this._points, { + K: this._parameters.K_min, + metric: this._parameters.metric, + seed: this._parameters.seed, + }); + + let K = this._parameters.K_min; + + candidates.set(K, { + kmeans: current_kmeans, + score: -Infinity, + }); + + // Iteratively improve clustering + while (K < this._parameters.K_max) { + const clusters = current_kmeans.get_clusters(); + const centroids = current_kmeans.centroids; + + // Try splitting each cluster + /** @type {SplitResult[]} */ + const split_results = []; + + for (let j = 0; j < clusters.length; ++j) { + const cluster = clusters[j]; + + // Skip small clusters - need enough points for reliable BIC + if (cluster.length < this._parameters.min_cluster_size) { + continue; + } + + // Get subset data for this cluster + /** @type {number[][]} */ + const subset_points = cluster.map((idx) => { + const row = A.row(idx); + return Array.from(row); + }); + + // Calculate BIC for parent (single cluster) + const parent_bic = this._bic([cluster], [centroids[j]]); + + // Run KMeans with K=2 on subset + const subset_kmeans = new KMeans(subset_points, { + K: 2, + metric: this._parameters.metric, + seed: this._randomizer.seed, + }); + + const child_clusters_local = subset_kmeans.get_clusters(); + const child_centroids = subset_kmeans.centroids; + + // Map local indices back to global indices + /** @type {number[][]} */ + const child_clusters_global = child_clusters_local.map((local_cluster) => + local_cluster.map((local_idx) => cluster[local_idx]), + ); + + // Calculate BIC for children (split into 2 clusters) + const children_bic = this._bic(child_clusters_global, child_centroids); + + split_results.push({ + index: j, + bic_parent: parent_bic, + bic_children: children_bic, + child_clusters: child_clusters_global, + child_centroids: child_centroids, + }); + } + + // Keep all splits that improve BIC (BIC_children > BIC_parent) + /** @type {SplitResult[]} */ + const accepted_splits = split_results.filter((result) => result.bic_children > result.bic_parent); + + // If no splits improve BIC, we're done + if (accepted_splits.length === 0) { + break; + } + + // Build new centroids array: keep non-split centroids + add split centroids + /** @type {Float64Array[]} */ + const new_centroids = []; + const split_indices = new Set(); + + // Sort accepted splits by improvement (descending) + accepted_splits.sort((a, b) => b.bic_children - b.bic_parent - (a.bic_children - a.bic_parent)); + + for (const split of accepted_splits) { + if (centroids.length + split_indices.size + 1 <= this._parameters.K_max) { + split_indices.add(split.index); + } else { + break; + } + } + + for (let i = 0; i < centroids.length; ++i) { + if (split_indices.has(i)) { + // This cluster was split - add both child centroids + const split_result = accepted_splits.find((s) => s.index === i); + if (split_result) { + new_centroids.push(...split_result.child_centroids); + } + } else { + // This cluster wasn't split - keep its centroid + new_centroids.push(centroids[i]); + } + } + + // Run KMeans on full dataset with new centroids as initialization + // This is crucial - we need to reassign all points to all clusters + const newK = new_centroids.length; + + // Create a new KMeans instance with K set to new number of clusters + current_kmeans = new KMeans(this._matrix, { + K: newK, + metric: this._parameters.metric, + seed: this._randomizer.seed, + initial_centroids: new_centroids, + }); + + // Store the candidate with the BIC of the FULL dataset + candidates.set(newK, { + kmeans: current_kmeans, + score: this._bic(current_kmeans.get_clusters(), current_kmeans.centroids), + }); + + K = newK; + } + + // Select best candidate based on BIC score + this._best_kmeans = this._select_best_candidate(candidates); + } + + /** + * Select the best candidate based on BIC score + * + * @private + * @param {Map} candidates + * @returns {KMeans} + */ + _select_best_candidate(candidates) { + if (candidates.size === 0) { + throw new Error("No candidates found"); + } + + const first_candidate = candidates.get(this._parameters.K_min); + if (!first_candidate) { + throw new Error("Missing initial candidate"); + } + + let best_score = first_candidate.score; + /** @type {KMeans} */ + let best_kmeans = first_candidate.kmeans; + + for (const candidate of candidates.values()) { + if (candidate.score > best_score) { + best_score = candidate.score; + best_kmeans = candidate.kmeans; + } + } + + return best_kmeans; + } + + /** + * Calculate Bayesian Information Criterion for a set of clusters. + * + * Uses Kass's formula for BIC calculation: + * BIC(θ) = L(D) - 0.5 * p * ln(N) + * + * Where: + * - L(D) is the log-likelihood of the data + * - p is the number of free parameters: (K-1) + D*K + 1 + * - N is the total number of points + * + * @private + * @param {number[][]} clusters - Array of clusters with point indices + * @param {Float64Array[]} centroids - Array of centroids + * @returns {number} BIC score (higher is better) + */ + _bic(clusters, centroids) { + const A = this._matrix; + const D = this._D; + const K = centroids.length; + + let total_variance = 0; + let N = 0; + + // Calculate total variance (sum of squared distances) + for (let i = 0; i < K; ++i) { + const cluster = clusters[i]; + const centroid = centroids[i]; + N += cluster.length; + + for (let j = 0; j < cluster.length; ++j) { + const point_idx = cluster[j]; + const point = A.row(point_idx); + // Sum of squared distances (variance term) + total_variance += euclidean_squared(centroid, point); + } + } + + // Not enough points for meaningful BIC + if (N <= K) { + return -Infinity; + } + + // Estimate variance (ML estimate) + const variance = total_variance / (N - K); + + // Handle case of zero variance (all points identical) + if (variance <= 0) { + return -Infinity; + } + + // Number of free parameters: (K-1) cluster weights + K*D centroid coordinates + 1 variance + const p = K - 1 + D * K + 1; + + // Calculate log-likelihood + let log_likelihood = 0; + const log_2pi = Math.log(2 * Math.PI); + + for (let i = 0; i < K; ++i) { + const n = clusters[i].length; + if (n <= 1) continue; + + // Log-likelihood for cluster i + const cluster_log_likelihood = + n * Math.log(n / N) - 0.5 * n * log_2pi - 0.5 * n * D * Math.log(variance) - 0.5 * (n - 1); + + log_likelihood += cluster_log_likelihood; + } + + // BIC = log_likelihood - 0.5 * p * ln(N) + return log_likelihood - 0.5 * p * Math.log(N); + } + + /** + * Get the computed clusters + * + * @returns {number[][]} Array of clusters, each containing indices of points + */ + get_clusters() { + if (!this._best_kmeans) { + throw new Error("XMeans has not been run"); + } + return this._best_kmeans.get_clusters(); + } + + /** @returns {number[]} The cluster list */ + get_cluster_list() { + if (!this._best_kmeans) { + throw new Error("XMeans has not been run"); + } + return this._best_kmeans.get_cluster_list(); + } + + /** + * Get the final centroids + * + * @returns {Float64Array[]} Array of centroids + */ + get centroids() { + if (!this._best_kmeans) { + throw new Error("XMeans has not been run"); + } + return this._best_kmeans.centroids; + } + + /** + * Get the optimal number of clusters found + * + * @returns {number} The number of clusters + */ + get k() { + if (!this._best_kmeans) { + throw new Error("XMeans has not been run"); + } + return this._best_kmeans.k; + } +} + +/** @import {InputType} from "../index.js" */ + +/** + * @abstract + * @template {InputType} T + * @template {{ seed?: number }} Para + * + * Base class for all Dimensionality Reduction (DR) algorithms. + * + * Provides a common interface for parameters management, data initialization, + * and transformation (both synchronous and asynchronous). + * + * @class + */ +class DR { + /** @type {number} */ + _D; + /** @type {number} */ + _N; + /** @type {Randomizer} */ + _randomizer; + /** @type {boolean} */ + _is_initialized; + + /** + * Takes the default parameters and seals them, remembers the type of input `X`, and initializes the random number + * generator. + * + * @param {T} X - The high-dimensional data. + * @param {Para} default_parameters - Object containing default parameterization of the DR method. + * @param {Partial} parameters - Object containing parameterization of the DR method to override defaults. + */ + constructor(X, default_parameters, parameters = {}) { + /** @type {T} */ + this.__input = X; + + /** @type {Para} */ + this._parameters = /** @type {Para} */ Object.seal({ + ...default_parameters, + ...parameters, + }); + /** @type {"array" | "matrix" | "typed"} */ + this._type; + /** @type {Matrix} */ + this.X; + /** @type {Matrix} */ + this.Y; + + if (Array.isArray(X)) { + if (X[0] instanceof Float64Array) { + this._type = "typed"; + } else { + this._type = "array"; + } + this.X = Matrix.from(X); + } else if (X instanceof Matrix) { + this._type = "matrix"; + this.X = X; + } else { + throw new Error("No valid type for X!"); + } + const [N, D] = this.X.shape; + this._N = N; + this._D = D; + this._randomizer = new Randomizer(this._parameters.seed); + this._is_initialized = false; + } + + /** + * Get all Parameters. + * @overload + * @returns {Para} + */ + /** + * Get value of given parameter. + * @template {keyof Para} K + * @overload + * @param {K} name - Name of the parameter. + * @returns {Para[K]} + */ + /** + * Set value of given parameter. + * @template {keyof Para} K + * @overload + * @param {K} name - Name of the parameter. + * @param {Para[K]} value - Value of the parameter to set. + * @returns {this} + */ + /** + * @param {keyof Para} [name] - Name of the parameter. If null, returns all parameters as an Object. + * @param {Para[keyof Para]} [value] - Value of the parameter to set. If name is set and value is not given, returns the + * current value. + * @returns {Para | Para[keyof Para] | this} On setting a parameter, returns the DR object. If name is set and value is not + * given, returns the parameter value. If name is null, returns all parameters. On setting a parameter, this + * function returns the DR object. If `name` is set and `value == null` then return actual parameter value. If + * `name` is not given, then returns all parameters as an Object. + * @example + * ```js + * const DR = new druid.TSNE(X, {d: 3}); // creates a new DR object, with parameter for `d = 3`. + * DR.parameter("d"); // returns 3 + * DR.parameter("d", 2); // sets parameter `d` to 2 and returns `DR`. + * ``` + * + */ + parameter(name, value) { + if (name === undefined && value === undefined) { + return Object.assign({}, this._parameters); + } + if (name && !Object.hasOwn(this._parameters, name)) { + throw new Error(`${String(name)} is not a valid parameter!`); + } + if (name && value !== undefined) { + this._parameters[name] = value; + this._is_initialized = false; + return this; + } else if (name) { + return this._parameters[name]; + } + throw new Error("Should not happen!"); + } + + /** + * Computes the projection. + * + * @abstract + * @param {...unknown} args + * @returns {T} The projection. + */ + transform(...args) { + this.check_init(); + return this.projection; + } + + /** + * Computes the projection. + * + * @template {InputType} T + * @template {{ seed?: number }} Para + * @param {T} X + * @param {Para} parameters + * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method. + * @returns {T} The dimensionality reduced dataset. + */ + static transform(X, parameters, ...args) { + const dr = new DR(X, parameters, parameters); + return /** @type {T} */ (dr.transform()); + } + + /** + * Computes the projection. + * + * @abstract + * @param {...unknown} args + * @returns {Generator} The intermediate steps of the projection. + */ + *generator(...args) { + const R = this.transform(...args); + yield R; + return R; + } + + /** + * Computes the projection. + * + * @template {{ seed?: number }} Para + * @param {InputType} X + * @param {Para} parameters + * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method. + * @returns {Generator} A generator yielding the intermediate steps of the dimensionality + * reduction method. + */ + static *generator(X, parameters, ...args) { + const dr = new DR(X, parameters, parameters); + const generator = dr.generator(...args); + let result; + do { + result = generator.next(); + yield result.value; + } while (!result.done); + + return result.value; + } + + /** + * @abstract + * @param {...unknown} args + */ + init(...args) { + } + + /** + * If the respective DR method has an `init` function, call it before `transform`. + * + * @returns {DR} + */ + check_init() { + if (!this._is_initialized && typeof this.init === "function") { + this.init(); + this._is_initialized = true; + } + return this; + } + + /** @returns {T} The projection in the type of input `X`. */ + get projection() { + if (Object.hasOwn(this, "Y")) { + this.check_init(); + //return this._type === "matrix" ? this.Y : this.Y.to2dArray(); + if (this._type === "matrix") { + return /** @type {T} */ (/** @type {any} */ (this.Y)); + } else if (this._type === "typed") { + return /** @type {T} */ (/** @type {any} */ (this.Y.to2dArray())); + } else { + return /** @type {T} */ (/** @type {any} */ (this.Y.asArray())); + } + } else { + throw new Error("The dataset is not transformed yet!"); + } + } + + /** + * Computes the projection. + * + * @param {...unknown} args - Arguments the transform method of the respective DR method takes. + * @returns {Promise} The dimensionality reduced dataset. + */ + async transform_async(...args) { + return this.transform(...args); + } + + /** + * Computes the projection. + * + * @template {{ seed?: number }} Para + * @param {InputType} X + * @param {Para} parameters + * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method. + * @returns {Promise} A promise yielding the dimensionality reduced dataset. + */ + static async transform_async(X, parameters, ...args) { + return DR.transform(X, parameters, ...args); + } +} + +/** @import { InputType } from "../index.js" */ +/** @import { ParametersFASTMAP } from "./index.js"; */ + +/** + * FastMap algorithm for dimensionality reduction. + * + * A very fast algorithm for projecting high-dimensional data into a lower-dimensional + * space while preserving pairwise distances. It works similarly to PCA but uses + * only a subset of the data to find projection axes. + * + * @class + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction + */ +class FASTMAP extends DR { + /** + * FastMap: a fast algorithm for indexing, data-mining and visualization of traditional and multimedia datasets. + * @param {T} X - The high-dimensional data. + * @param {Partial} parameters - Object containing parameterization of the DR method. + * @see {@link https://doi.org/10.1145/223784.223812} + */ + constructor(X, parameters) { + super(X, { d: 2, metric: euclidean, seed: 1212 }, parameters); + } + + /** + * Chooses two points which are the most distant in the actual projection. + * + * @private + * @param {(a: number, b: number) => number} dist + * @returns {[number, number, number]} An array consisting of first index, second index, and distance between the + * two points. + */ + _choose_distant_objects(dist) { + const X = this.X; + const N = X.shape[0]; + let a_index = this._randomizer.random_int % N; + /** @type {number | null} */ + let b_index = null; + let max_dist = -Infinity; + for (let i = 0; i < N; ++i) { + const d_ai = dist(a_index, i); + if (d_ai > max_dist) { + max_dist = d_ai; + b_index = i; + } + } + if (b_index === null) throw new Error("should not happen!"); + max_dist = -Infinity; + for (let i = 0; i < N; ++i) { + const d_bi = dist(b_index, i); + if (d_bi > max_dist) { + max_dist = d_bi; + a_index = i; + } + } + return [a_index, b_index, max_dist]; + } + + /** + * Computes the projection. + * + * @returns {T} The `d`-dimensional projection of the data matrix `X`. + */ + transform() { + const X = this.X; + const N = X.shape[0]; + const d = /** @type {number} */ (this._parameters.d); + const metric = /** @type {typeof euclidean} */ (this._parameters.metric); + const Y = new Matrix(N, d, 0); + /** @type {(a: number, b: number) => number} */ + let dist = (a, b) => metric(X.row(a), X.row(b)); + + for (let _col = 0; _col < d; ++_col) { + const old_dist = dist; + // choose pivot objects + const [a_index, b_index, d_ab] = this._choose_distant_objects(dist); + if (d_ab !== 0) { + // project the objects on the line (O_a, O_b) + for (let i = 0; i < N; ++i) { + const d_ai = dist(a_index, i); + const d_bi = dist(b_index, i); + const y_i = (d_ai ** 2 + d_ab ** 2 - d_bi ** 2) / (2 * d_ab); + Y.set_entry(i, _col, y_i); + } + // consider the projections of the objects on a + // hyperplane perpendicluar to the line (a, b); + // the distance function D'() between two + // projections is given by Eq.4 + dist = (a, b) => Math.sqrt(old_dist(a, b) ** 2 - (Y.entry(a, _col) - Y.entry(b, _col)) ** 2); + } + } + // return embedding. + this.Y = Y; + return this.projection; + } + + *generator() { + yield this.transform(); + return this.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {T} + */ + static transform(X, parameters) { + const dr = new FASTMAP(X, parameters); + return dr.transform(); + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new FASTMAP(X, parameters); + yield* dr.generator(); + return dr.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new FASTMAP(X, parameters); + return dr.transform_async(); + } +} + +/** + * Base class for all K-Nearest Neighbors (KNN) search algorithms. + * + * Provides a common interface for elements management and search operations. + * + * @abstract + * @category KNN + * @template {number[] | Float64Array} T - Type of elements + * @template {Object} Para - Type of parameters + * @class + */ +class KNN { + /** @type {T[]} */ + _elements; + /** @type {Para} */ + _parameters; + /** @type {"typed" | "array"} */ + _type; + + /** + * @param {T[]} elements + * @param {Para} parameters + */ + constructor(elements, parameters) { + if (elements.length === 0) throw new Error("Elements needs to contain at least one element!"); + if (elements[0] instanceof Float64Array) { + this._type = "typed"; + } else { + this._type = "array"; + } + this._parameters = parameters; + this._elements = elements; + } + + /** + * @abstract + * @param {T} t + * @param {number} k + * @returns {{ element: T; index: number; distance: number }[]} + */ + search(t, k) { + throw new Error("The function search must be implemented!"); + } + + /** + * @abstract + * @param {number} i + * @param {number} k + * @returns {{ element: T; index: number; distance: number }[]} + */ + search_by_index(i, k) { + throw new Error("The function search_by_index must be implemented!"); + } +} + +/** @import { Metric } from "../metrics/index.js" */ +/** @import { ParametersAnnoy } from "./index.js" */ + +/** + * @template {number[] | Float64Array} T + * @typedef {Object} AnnoyNode + * @property {boolean} isLeaf - Whether this is a leaf node + * @property {number[]} indices - Indices of points in this node (leaf) or children (internal) + * @property {number[]} normal - Hyperplane normal vector (internal nodes only) + * @property {number} offset - Hyperplane offset (internal nodes only) + * @property {AnnoyNode | null} left - Left child (internal nodes only) + * @property {AnnoyNode | null} right - Right child (internal nodes only) + */ + +/** + * Annoy-style (Approximate Nearest Neighbors Oh Yeah) implementation using Random Projection Trees. + * + * This implementation builds multiple random projection trees where each tree randomly selects + * two points and splits the space based on a hyperplane equidistant between them. + * + * Key features: + * - Multiple random projection trees for better recall + * - Each tree uses random hyperplanes for splitting + * - Priority queue search for better recall + * - Combines results from all trees + * + * Best suited for: + * - High-dimensional data + * - Approximate nearest neighbor search + * - Large datasets + * - When high recall is needed with approximate methods + * + * @class + * @category KNN + * @template {number[] | Float64Array} T + * @extends KNN + * @see {@link https://github.com/spotify/annoy} + * @see {@link https://erikbern.com/2015/09/24/nearest-neighbors-and-vector-models-epilogue-curse-of-dimensionality.html} + */ +class Annoy extends KNN { + /** + * Creates a new Annoy-style index with random projection trees. + * + * @param {T[]} elements - Elements to index + * @param {ParametersAnnoy} [parameters={}] - Configuration parameters + */ + constructor( + elements, + parameters = { + metric: euclidean, + numTrees: 10, + maxPointsPerLeaf: 10, + seed: 1212, + }, + ) { + // Handle empty initialization - use dummy element + const hasElements = elements && elements.length > 0; + const firstElement = /** @type {T} */ (hasElements ? elements[0] : new Float64Array([0])); + + super([firstElement], parameters); + + this._metric = this._parameters.metric ?? euclidean; + this._numTrees = this._parameters.numTrees ?? 10; + this._maxPointsPerLeaf = this._parameters.maxPointsPerLeaf ?? 10; + this._seed = this._parameters.seed ?? 1212; + this._randomizer = new Randomizer(this._seed); + + /** + * @private + * @type {AnnoyNode[]} + */ + this._trees = []; + + // Build trees + if (hasElements) { + // Reset elements and rebuild properly + /** @type {T[]} */ + this._elements = []; + this._trees = []; + this.add(elements); + } + } + + /** + * Get the number of trees in the index. + * @returns {number} + */ + get num_trees() { + return this._trees.length; + } + + /** + * Get the total number of nodes in all trees. + * @returns {number} + */ + get num_nodes() { + let total = 0; + for (const tree of this._trees) { + total += this._countNodes(tree); + } + return total; + } + + /** + * @private + * @param {any} node + * @returns {number} + */ + _countNodes(node) { + if (!node) return 0; + return 1 + this._countNodes(node.left) + this._countNodes(node.right); + } + + /** + * Add elements to the Annoy index. + * @param {T[]} elements + * @returns {this} + */ + add(elements) { + // Extend elements array + this._elements = this._elements.concat(elements); + + // Rebuild all trees with new elements + this._trees = []; + this._buildTrees(); + + return this; + } + + /** + * Build all random projection trees. + * @private + */ + _buildTrees() { + const elements = this._elements; + const n = elements.length; + + for (let t = 0; t < this._numTrees; t++) { + // Create index array for this tree + const indices = Array.from({ length: n }, (_, i) => i); + const tree = this._buildTreeRecursive(indices); + this._trees.push(tree); + } + } + + /** + * Recursively build a random projection tree. + * @private + * @param {number[]} indices - Indices of elements to include + * @returns {AnnoyNode} + */ + _buildTreeRecursive(indices) { + const elements = this._elements; + + // Base case: small enough to be a leaf + if (indices.length <= this._maxPointsPerLeaf) { + return { + isLeaf: true, + indices: indices, + normal: [], + offset: 0, + left: null, + right: null, + }; + } + + // Select two random points to define the splitting hyperplane + const idx1 = indices[Math.floor(this._randomizer.random * indices.length)]; + const idx2 = indices[Math.floor(this._randomizer.random * indices.length)]; + + const point1 = elements[idx1]; + const point2 = elements[idx2]; + + // Compute normal vector (point2 - point1) + const dim = point1.length; + /** @type {number[]} */ + const normal = new Array(dim); + for (let i = 0; i < dim; i++) { + normal[i] = point2[i] - point1[i]; + } + + // Normalize + let norm = 0; + for (let i = 0; i < dim; i++) { + norm += normal[i] * normal[i]; + } + norm = Math.sqrt(norm); + + if (norm > 1e-10) { + for (let i = 0; i < dim; i++) { + normal[i] /= norm; + } + } + + // Compute midpoint and offset + /** @type {number[]} */ + const midpoint = new Array(dim); + for (let i = 0; i < dim; i++) { + midpoint[i] = (point1[i] + point2[i]) / 2; + } + + // Compute offset: dot(normal, midpoint) + let offset = 0; + for (let i = 0; i < dim; i++) { + offset += normal[i] * midpoint[i]; + } + + // Split points based on which side of hyperplane they fall + const leftIndices = []; + const rightIndices = []; + + for (const idx of indices) { + const point = elements[idx]; + let dot = 0; + for (let i = 0; i < dim; i++) { + dot += normal[i] * point[i]; + } + + if (dot < offset) { + leftIndices.push(idx); + } else { + rightIndices.push(idx); + } + } + + // Handle edge case where all points fall on one side + if (leftIndices.length === 0 || rightIndices.length === 0) { + return { + isLeaf: true, + indices: indices, + normal: [], + offset: 0, + left: null, + right: null, + }; + } + + // Recursively build subtrees + const left = this._buildTreeRecursive(leftIndices); + const right = this._buildTreeRecursive(rightIndices); + + return { + isLeaf: false, + indices: [], + normal: normal, + offset: offset, + left: left, + right: right, + }; + } + + /** + * Compute distance from point to hyperplane. + * @private + * @param {T} point + * @param {number[]} normal + * @param {number} offset + * @returns {number} Signed distance (positive = right side, negative = left side) + */ + _distanceToHyperplane(point, normal, offset) { + let dot = 0; + for (let i = 0; i < point.length; i++) { + dot += normal[i] * point[i]; + } + return dot - offset; + } + + /** + * Search for k approximate nearest neighbors. + * @param {T} query + * @param {number} [k=5] + * @returns {{ element: T; index: number; distance: number }[]} + */ + search(query, k = 5) { + const metric = this._metric; + const elements = this._elements; + + if (elements.length === 0) return []; + + // Collect candidates from all trees using priority queue + const candidates = new Set(); + + // Collect more candidates for better recall + // Search at least k * numTrees * 2 candidates + const minCandidates = Math.min(k * this._numTrees * 3, elements.length); + + for (const tree of this._trees) { + this._searchTreePriority(tree, query, candidates, minCandidates); + } + + // Compute exact distances for all candidates + /** @type {Heap<{ index: number; distance: number }>} */ + const best = new Heap(null, (d) => d.distance, "max"); + + for (const idx of candidates) { + const element = elements[idx]; + if (!element || element.length !== query.length) continue; + + const dist = metric(query, element); + + if (best.length < k) { + best.push({ index: idx, distance: dist }); + } else if (dist < (best.first?.value ?? Infinity)) { + best.pop(); + best.push({ index: idx, distance: dist }); + } + } + + // If we still don't have enough candidates, do a linear scan fallback + if (best.length < k) { + for (let i = 0; i < elements.length && best.length < k; i++) { + if (candidates.has(i)) continue; + + const element = elements[i]; + if (!element || element.length !== query.length) continue; + + const dist = metric(query, element); + best.push({ index: i, distance: dist }); + } + } + + // Convert to result format + /** @type {{ element: T; index: number; distance: number }[]} */ + const result = []; + while (best.length > 0) { + const item = /** @type {{ element: { index: number; distance: number }; value: number }} */ (best.pop()); + result.push({ + element: elements[item.element.index], + index: item.element.index, + distance: item.value, + }); + } + + return result.reverse(); + } + + /** + * Search tree using priority queue for better recall. + * Explores nodes in order of distance to hyperplane. + * @private + * @param {AnnoyNode} node + * @param {T} query + * @param {Set} candidates + * @param {number} maxCandidates + */ + _searchTreePriority(node, query, candidates, maxCandidates) { + if (!node) return; + + // Priority queue entry: { node, distance } + /** @type {Heap<{ node: AnnoyNode; dist: number }>} */ + const pq = new Heap(null, (d) => d.dist, "min"); + pq.push({ node: node, dist: 0 }); + + while (!pq.empty && candidates.size < maxCandidates) { + const entry = pq.pop(); + if (!entry) continue; + + const currentNode = entry.element.node; + + // Leaf node: add all points + if (currentNode.isLeaf) { + for (const idx of currentNode.indices) { + candidates.add(idx); + if (candidates.size >= maxCandidates) return; + } + continue; + } + + // Internal node: compute distance to hyperplane + const dist = this._distanceToHyperplane(query, currentNode.normal, currentNode.offset); + + // Determine which side is closer + const closerSide = dist < 0 ? currentNode.left : currentNode.right; + const fartherSide = dist < 0 ? currentNode.right : currentNode.left; + + // Add closer side with priority 0 (explore first) + if (closerSide) { + pq.push({ node: closerSide, dist: 0 }); + } + + // Add farther side with priority = |dist| (explore later if needed) + if (fartherSide && candidates.size < maxCandidates) { + pq.push({ node: fartherSide, dist: Math.abs(dist) }); + } + } + } + + /** + * @param {number} i + * @param {number} [k=5] + * @returns {{ element: T; index: number; distance: number }[]} + */ + search_by_index(i, k = 5) { + if (i < 0 || i >= this._elements.length) return []; + return this.search(this._elements[i], k); + } + + /** + * Alias for search_by_index for backward compatibility. + * + * @param {number} i - Index of the query element + * @param {number} [k=5] - Number of nearest neighbors to return + * @returns {{ element: T; index: number; distance: number }[]} + */ + search_index(i, k = 5) { + return this.search_by_index(i, k); + } +} + +/** @import { Metric } from "../metrics/index.js" */ +/** @import { ParametersBallTree } from "./index.js" */ + +/** + * @template {number[] | Float64Array} T + * @typedef {Object} ElementWithIndex + * @property {number} index + * @property {T} element + */ + +/** + * Ball Tree for efficient nearest neighbor search. + * + * A Ball Tree is a metric tree that partitions points into a nested set of + * hyperspheres (balls). It is particularly effective for high-dimensional + * data and supports any valid metric. + * + * @class + * @category KNN + * @template {number[] | Float64Array} T + * @extends KNN + */ +class BallTree extends KNN { + /** + * Generates a BallTree with given `elements`. + * + * @param {T[]} elements - Elements which should be added to the BallTree + * @param {ParametersBallTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}` + * @see {@link https://en.wikipedia.org/wiki/Ball_tree} + * @see {@link https://github.com/invisal/noobjs/blob/master/src/tree/BallTree.js} + */ + constructor(elements, parameters = { metric: euclidean, seed: 1212 }) { + super(elements, Object.assign({ seed: 1212 }, parameters)); + /** + * @private + * @type {BallTreeNode | BallTreeLeaf} + */ + this._root = this._construct(elements.map((element, index) => ({ index, element }))); + } + + /** @returns {Metric} */ + get _metric() { + return this._parameters.metric; + } + + /** + * @private + * @param {ElementWithIndex[]} elements + * @returns {BallTreeNode | BallTreeLeaf} Root of balltree. + */ + _construct(elements) { + if (elements.length === 1) { + return new BallTreeLeaf(elements); + } else { + const c = this._greatest_spread(elements); + const sorted_elements = elements.sort((a, b) => a.element[c] - b.element[c]); + const n = sorted_elements.length; + const p_index = Math.floor(n / 2); + const p = sorted_elements[p_index]; + const L = sorted_elements.slice(0, p_index); + const R = sorted_elements.slice(p_index, n); + const radius = Math.max(...elements.map((d) => this._metric(p.element, d.element))); + let B; + if (L.length > 0 && R.length > 0) { + B = new BallTreeNode(p, this._construct(L), this._construct(R), radius); + } else { + B = new BallTreeLeaf(elements); + } + return B; + } + } + + /** + * @private + * @param {ElementWithIndex[]} B + * @returns {number} + */ + _greatest_spread(B) { + const d = B[0].element.length; + const start = new Array(d); + + for (let i = 0; i < d; ++i) { + start[i] = [Infinity, -Infinity]; + } + + let spread = B.reduce((acc, current) => { + for (let i = 0; i < d; ++i) { + acc[i][0] = Math.min(acc[i][0], current.element[i]); + acc[i][1] = Math.max(acc[i][1], current.element[i]); + } + return acc; + }, start); + spread = spread.map((d) => d[1] - d[0]); + + let c = 0; + for (let i = 0; i < d; ++i) { + c = spread[i] > spread[c] ? i : c; + } + return c; + } + + /** + * @param {number} i + * @param {number} k + */ + search_by_index(i, k = 5) { + return this.search(this._elements[i], k); + } + + /** + * @param {T} t - Query element. + * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5` + * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors. + */ + search(t, k = 5) { + /** @type {Heap>} */ + const heap = new Heap(null, (d) => this._metric(d.element, t), "max"); + this._search(t, k, heap, this._root); + + // Convert heap to result array + /** @type {{ element: T; index: number; distance: number }[]} */ + const result = []; + while (heap.length > 0) { + const item = /** @type {{ element: ElementWithIndex; value: number }} */ (heap.pop()); + result.push({ + element: item.element.element, + index: item.element.index, + distance: item.value, + }); + } + return result.reverse(); // Reverse to get closest first + } + + /** + * @private + * @param {T} t - Query element. + * @param {number} k - Number of nearest neighbors to return. + * @param {Heap>} Q - Heap consists of the currently found `k` nearest neighbors. + * @param {BallTreeNode | BallTreeLeaf} B + */ + _search(t, k, Q, B) { + if (!B) return; + + if (B instanceof BallTreeNode) { + const dist_to_pivot = this._metric(t, B.pivot.element); + if (Q.length >= k && dist_to_pivot - B.radius >= (Q.first?.value ?? -Infinity)) { + return; + } + + const c1 = B.child1; + const c2 = B.child2; + + let d1 = Infinity; + let d2 = Infinity; + + if (c1 instanceof BallTreeNode) d1 = this._metric(t, c1.pivot.element); + else if (c1 instanceof BallTreeLeaf) d1 = this._metric(t, c1.points[0].element); + + if (c2 instanceof BallTreeNode) d2 = this._metric(t, c2.pivot.element); + else if (c2 instanceof BallTreeLeaf) d2 = this._metric(t, c2.points[0].element); + + if (d1 < d2) { + if (c1) this._search(t, k, Q, c1); + if (c2) this._search(t, k, Q, c2); + } else { + if (c2) this._search(t, k, Q, c2); + if (c1) this._search(t, k, Q, c1); + } + } else if (B instanceof BallTreeLeaf) { + for (let i = 0, n = B.points.length; i < n; ++i) { + const p = B.points[i]; + const dist = this._metric(p.element, t); + if (Q.length < k) { + Q.push(p); + } else if (dist < (Q.first?.value ?? Infinity)) { + Q.pop(); + Q.push(p); + } + } + } + } +} + +/** + * @private + * @template {number[] | Float64Array} T + */ +class BallTreeNode { + /** + * @param {ElementWithIndex} pivot + * @param {BallTreeNode | BallTreeLeaf | null} child1 + * @param {BallTreeNode | BallTreeLeaf | null} child2 + * @param {number} radius + */ + constructor(pivot, child1 = null, child2 = null, radius = 0) { + this.pivot = pivot; + this.child1 = child1; + this.child2 = child2; + this.radius = radius; + } +} + +/** + * @private + * @template {number[] | Float64Array} T + */ +class BallTreeLeaf { + /** @param {ElementWithIndex[]} points */ + constructor(points) { + this.points = points; + } +} + +/** @import { Metric } from "../metrics/index.js" */ +/** @import { ParametersHNSW } from "./index.js" */ + +/** + * @typedef {Object} Layer + * @property {number} l_c - Layer number + * @property {number[]} point_indices - Global indices of points in this layer + * @property {Map} edges - Global index -> array of connected global indices + */ + +/** + * @template {number[] | Float64Array} T + * @typedef {Object} Candidate + * @property {T} element - The actual data point + * @property {number} index - Global index in the dataset + * @property {number} distance - Distance from query + */ + +/** + * Hierarchical Navigable Small World (HNSW) graph for approximate nearest neighbor search. + * + * HNSW builds a multi-layer graph structure where each layer is a navigable small world graph. + * The top layers serve as "highways" for fast traversal, while lower layers provide accuracy. + * Each element is assigned to a random level, allowing logarithmic search complexity. + * + * Key parameters: + * - `m`: Controls the number of connections per element (affects accuracy/memory) + * - `ef_construction`: Controls the quality of the graph during construction (higher = better but slower) + * - `ef`: Controls the quality of search (higher = better recall but slower) + * + * Based on: + * - "Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs" + * by Malkov & Yashunin (2016) + * - "Approximate Nearest Neighbor Search on High Dimensional Data" + * by Li et al. (2019) + * + * @class + * @category KNN + * @template {number[] | Float64Array} T + * @extends KNN + * + * @example + * import * as druid from "@saehrimnir/druidjs"; + * + * const points = [[1, 2], [3, 4], [5, 6], [7, 8]]; + * const hnsw = new druid.HNSW(points, { + * metric: druid.euclidean, + * m: 16, + * ef_construction: 200 + * }); + * + * const query = [2, 3]; + * const neighbors = hnsw.search(query, 2); + * // [{ element: [1, 2], index: 0, distance: 1.41 }, ...] + */ +class HNSW extends KNN { + /** + * Creates a new HNSW index. + * + * @param {T[]} points - Initial points to add to the index + * @param {ParametersHNSW} [parameters={}] - Configuration parameters + */ + constructor( + points, + parameters = { + metric: euclidean, + heuristic: true, + m: 16, + ef_construction: 200, + m0: null, + mL: null, + seed: 1212, + ef: 50, + }, + ) { + // Handle empty initialization - use dummy element + const hasElements = points && points.length > 0; + let firstElement = /** @type {T} */ (hasElements ? points[0] : new Float64Array([0])); + + // Validate all points have consistent dimensions + if (hasElements) { + const expected_dim = firstElement.length; + for (let i = 1; i < points.length; i++) { + if (!points[i] || points[i].length !== expected_dim) { + console.warn( + `HNSW: Point ${i} has inconsistent dimensions (expected ${expected_dim}, got ${points[i]?.length})`, + ); + // Remove invalid points + points = points.filter((_, idx) => idx === 0 || points[idx]?.length === expected_dim); + firstElement = points[0]; + } + } + } + + super([firstElement], parameters); + + // Store reference to elements before clearing + const elementsToAdd = hasElements ? [...points] : []; + /** @type {T[]} */ + this._elements = []; + + /** @type {Metric} */ + this._metric = this._parameters.metric || euclidean; + + /** @type {Function} */ + this._select = this._parameters.heuristic ? this._select_heuristic.bind(this) : this._select_simple.bind(this); + + /** + * @private + * @type {Map} + */ + this._graph = new Map(); + + /** @type {number} */ + this._next_index = 0; + + // Validate and set parameters + const m_param = this._parameters.m ?? 16; + if (m_param <= 0 || !Number.isInteger(m_param)) { + throw new Error("HNSW: parameter 'm' must be a positive integer"); + } + /** @type {number} */ + this._m = Math.max(2, m_param); + + const ef_construction_param = this._parameters.ef_construction ?? 200; + if (ef_construction_param <= 0 || !Number.isInteger(ef_construction_param)) { + throw new Error("HNSW: parameter 'ef_construction' must be a positive integer"); + } + /** @type {number} */ + this._ef_construction = ef_construction_param; + + const ef_param = this._parameters.ef ?? 50; + if (ef_param <= 0 || !Number.isInteger(ef_param)) { + throw new Error("HNSW: parameter 'ef' must be a positive integer"); + } + /** @type {number} */ + this._ef = ef_param; + + const m0_param = this._parameters.m0 ?? 2 * this._m; + if (m0_param <= 0 || !Number.isInteger(m0_param)) { + throw new Error("HNSW: parameter 'm0' must be a positive integer"); + } + /** @type {number} */ + this._m0 = m0_param; + + /** @type {number} */ + this._mL = this._parameters.mL ?? 1 / Math.log(this._m); + + /** @type {Randomizer} */ + this._randomizer = new Randomizer(this._parameters.seed); + + /** @type {number} - Current maximum layer in the graph */ + this._L = -1; + + /** @type {number[] | null} - Entry point indices for search */ + this._ep = null; + + // Add initial points + if (elementsToAdd && elementsToAdd.length > 0) { + this.add(elementsToAdd); + } + } + + /** + * Add a single element to the index. + * + * @param {T} element - Element to add + * @returns {HNSW} This instance for chaining + */ + addOne(element) { + return this.add([element]); + } + + /** + * Add multiple elements to the index. + * + * @param {T[]} new_elements - Elements to add + * @returns {HNSW} This instance for chaining + */ + add(new_elements) { + // Handle empty array + if (!new_elements || new_elements.length === 0) { + return this; + } + + const m = this._m; + const ef_construction = this._ef_construction; + const m0 = this._m0; + const mL = this._mL; + const randomizer = this._randomizer; + const graph = this._graph; + + // Ensure _elements is a proper array that supports push + if (!Array.isArray(this._elements)) { + this._elements = Array.from(this._elements); + } + const elements = this._elements; + + // Get expected dimension from first existing element or first new element + const expected_dim = elements.length > 0 ? elements[0].length : new_elements[0]?.length; + + for (const element of new_elements) { + // Validate element + if (!element || (!Array.isArray(element) && !(element instanceof Float64Array))) { + console.warn("HNSW: Skipping invalid element (null, undefined, or not an array)"); + continue; + } + + // Validate dimensions + if (element.length !== expected_dim) { + console.warn( + `HNSW: Skipping element with wrong dimensions (expected ${expected_dim}, got ${element.length})`, + ); + continue; + } + + elements.push(element); + const global_index = elements.length - 1; + + // Assign random level to the element + // Level is drawn from exponential distribution: l = floor(-ln(uniform(0,1)) * mL) + const rand = Math.max(randomizer.random, 1e-10); // Avoid log(0) + const l = Math.min(31, Math.floor(-Math.log(rand) * mL)); + + let ep_indices = this._ep ? [...this._ep] : null; + const L = this._L; + + if (L >= 0) { + // Search from top layer down to min(L, l) + 1 + // These are the layers where element will NOT be inserted + for (let l_c = L; l_c > l; --l_c) { + const search_result = this._search_layer(element, ep_indices, 1, l_c); + if (search_result.length > 0) { + ep_indices = [search_result[0].index]; + } + } + + // Insert element into layers l down to 0 + for (let l_c = Math.min(L, l); l_c >= 0; --l_c) { + const layer = graph.get(l_c); + if (!layer) continue; + + layer.point_indices.push(global_index); + + // Search for ef_construction nearest neighbors + let W = this._search_layer(element, ep_indices, ef_construction, l_c); + + // If graph search returns no results (e.g., graph is empty or disconnected), + // fall back to linear search over all existing elements + if (W.length === 0 && elements.length > 1) { + const fallbackCandidates = []; + for (let i = 0; i < elements.length - 1; i++) { + const elem = elements[i]; + if (elem && elem.length === element.length) { + fallbackCandidates.push({ + element: elem, + index: i, + distance: this._metric(element, elem), + }); + } + } + fallbackCandidates.sort((a, b) => a.distance - b.distance); + W = fallbackCandidates.slice(0, ef_construction); + // Update ep_indices for next layer based on fallback results + if (l_c === Math.min(L, l)) { + ep_indices = W.map((c) => c.index); + } + } + + // Select neighbors using heuristic or simple approach (respect heuristic setting on all layers) + const neighbor_indices = this._select(element, W, l_c === 0 ? m0 : m, l_c); + + // Add bidirectional connections + for (const neighbor_idx of neighbor_indices) { + if (neighbor_idx === global_index) continue; + + // Add connection from element to neighbor + if (!layer.edges.has(global_index)) { + layer.edges.set(global_index, []); + } + layer.edges.get(global_index)?.push(neighbor_idx); + + // Add connection from neighbor to element + if (!layer.edges.has(neighbor_idx)) { + layer.edges.set(neighbor_idx, []); + } + const neighbor_edge_list = layer.edges.get(neighbor_idx); + if (neighbor_edge_list && !neighbor_edge_list.includes(global_index)) { + neighbor_edge_list.push(global_index); + } + + // Prune connections if too many + const max_conn = l_c === 0 ? m0 : m; + const neighbor_edges = layer.edges.get(neighbor_idx); + if (neighbor_edges && neighbor_edges.length > max_conn) { + const neighbor_element = elements[neighbor_idx]; + // Filter out self-connections before pruning + const valid_neighbor_edges = neighbor_edges.filter((idx) => idx !== neighbor_idx); + const neighbor_candidates = valid_neighbor_edges.map((idx) => ({ + element: elements[idx], + index: idx, + distance: this._metric(neighbor_element, elements[idx]), + })); + const pruned = + l_c === 0 + ? this._select_simple(neighbor_element, neighbor_candidates, max_conn) + : this._select(neighbor_element, neighbor_candidates, max_conn, l_c); + layer.edges.set(neighbor_idx, pruned); + } + } + + // Use closest neighbor as entry point for next layer (following HNSW paper) + if (W.length > 0) { + ep_indices = [W[0].index]; + } + } + } + + // If element's level is higher than current max, create new layers + if (l > L) { + for (let i = L + 1; i <= l; ++i) { + graph.set(i, { + l_c: i, + point_indices: [global_index], + edges: new Map(), + }); + } + // Element becomes the new entry point + this._ep = [global_index]; + this._L = l; + } + + // Special case: if this is the first element (L was -1), + // we need to ensure layer 0 has proper structure for future insertions + if (L === -1) { + if (!graph.has(0)) { + graph.set(0, { + l_c: 0, + point_indices: [global_index], + edges: new Map(), + }); + } + const layer0 = graph.get(0); + if (layer0 && !layer0.edges.has(global_index)) { + layer0.edges.set(global_index, []); + } + } + } + + return this; + } + + /** + * Select neighbors using the heuristic approach. + * + * The heuristic extends candidates with their neighbors and selects + * points that are closer to the query than to already selected points. + * This maintains graph connectivity better than simple selection. + * + * @private + * @param {T} q - Query element + * @param {Candidate[]} candidates - Candidate elements with distances + * @param {number} M - Maximum number of neighbors to return + * @param {number} l_c - Layer number + * @param {boolean} [extend_candidates=true] - Whether to extend candidates with their neighbors + * @param {boolean} [keep_pruned_connections=true] - Whether to add pruned connections back if needed + * @returns {number[]} Selected neighbor indices + */ + _select_heuristic(q, candidates, M, l_c, extend_candidates = true, keep_pruned_connections = true) { + if (l_c > this._L) { + return candidates.map((c) => c.index); + } + + const metric = this._metric; + const layer = this._graph.get(l_c); + const elements = this._elements; + + // Extend candidate set with neighbors of candidates + const W_set = new Set(candidates.map((c) => c.index)); + if (extend_candidates) { + for (const c of candidates) { + const edges = layer?.edges.get(c.index); + if (edges) { + for (const neighbor_idx of edges) { + W_set.add(neighbor_idx); + } + } + } + } + + // Create extended candidates with distances + const W = [...W_set] + .map((idx) => ({ + element: elements[idx], + index: idx, + distance: metric(elements[idx], q), + })) + .sort((a, b) => a.distance - b.distance); + + const R = []; + const W_discarded = []; + + // Select neighbors: prefer points closer to query than to already selected points + for (const e of W) { + if (R.length >= M) break; + + let should_add = true; + + // Check if e is closer to query than to any already selected point + for (const r of R) { + const dist_er = metric(e.element, r.element); + if (dist_er < e.distance) { + should_add = false; + break; + } + } + + if (should_add) { + R.push(e); + } else { + W_discarded.push(e); + } + } + + // Add discarded connections if we need more + if (keep_pruned_connections && R.length < M) { + for (const e of W_discarded) { + if (R.length >= M) break; + R.push(e); + } + } + + return R.map((c) => c.index); + } + + /** + * Select neighbors using simple distance-based selection. + * + * Simply returns the M closest candidates to the query. + * + * @private + * @param {T} q - Query element + * @param {Candidate[]} C - Candidate elements with distances + * @param {number} M - Maximum number of neighbors to return + * @returns {number[]} M nearest candidate indices + */ + _select_simple(q, C, M) { + if (C.length <= M) return C.map((c) => c.index); + + // Candidates already have distance computed, use it directly + return C.slice() + .sort((a, b) => a.distance - b.distance) + .slice(0, M) + .map((c) => c.index); + } + + /** + * Search a single layer for nearest neighbors. + * + * Implements the greedy search algorithm: start from entry points, + * always expand the closest unvisited candidate, maintain a list + * of the ef closest found neighbors. + * + * @private + * @param {T} q - Query element + * @param {number[] | null} ep_indices - Entry point indices + * @param {number} ef - Number of nearest neighbors to find + * @param {number} l_c - Layer number to search + * @returns {Candidate[]} ef nearest neighbors found with their distances + */ + _search_layer(q, ep_indices, ef, l_c) { + const metric = this._metric; + const layer = this._graph.get(l_c); + const elements = this._elements; + + if (!layer || layer.edges.size === 0 || !ep_indices || ep_indices.length === 0) { + return []; + } + + // Filter out invalid indices + const valid_ep_indices = ep_indices.filter((idx) => elements[idx] !== undefined); + if (valid_ep_indices.length === 0) { + return []; + } + + // Visited set to avoid cycles + const visited = new Set(valid_ep_indices); + + // Candidate set (min-heap): closest unvisited candidates to expand + const C = new Heap( + valid_ep_indices.map((idx) => ({ + element: elements[idx], + index: idx, + distance: metric(elements[idx], q), + })), + (item) => item.distance, + "min", + ); + + // Result set (max-heap): ef closest found neighbors + const W = new Heap( + valid_ep_indices.map((idx) => ({ + element: elements[idx], + index: idx, + distance: metric(elements[idx], q), + })), + (item) => item.distance, + "max", + ); + + // Algorithm 2 stops when the distance from query to the next candidate is greater + // than the distance to the furthest element in the result set W. + while (!C.empty) { + const c = C.pop(); + if (!c) break; + const furthest_dist = W.first?.value ?? Infinity; + + // Stop if current candidate is farther than furthest result + if (c.value > furthest_dist) { + break; + } + + const edges = layer.edges.get(c.element.index); + if (!edges) continue; + + for (const neighbor_idx of edges) { + if (!visited.has(neighbor_idx)) { + const neighbor_element = elements[neighbor_idx]; + // Skip invalid elements or elements with different dimensions + if (!neighbor_element || neighbor_element.length !== q.length) continue; + + // Skip self-connections + if (neighbor_idx === c.element.index) continue; + + visited.add(neighbor_idx); + const dist_e = metric(neighbor_element, q); + + const current_furthest = W.first?.value ?? Infinity; + if (dist_e < current_furthest || W.length < ef) { + C.push({ + element: neighbor_element, + index: neighbor_idx, + distance: dist_e, + }); + W.push({ + element: neighbor_element, + index: neighbor_idx, + distance: dist_e, + }); + + if (W.length > ef) { + W.pop(); + } + } + } + } + } + + // Return sorted results for consistent entry point selection + return W.data().sort((a, b) => a.distance - b.distance); + } + + /** + * Searches for the K nearest neighbors to a query element in the HNSW graph. + * + * Performs a multi-layer search starting from the entry point and traversing + * each layer as entry points for the next. + * + * @param {T} q - Query element + * @param {number} K - Number of nearest neighbors to return + * @returns {Candidate[]} K nearest neighbors with their distances + */ + search(q, K) { + // Validate K + if (!Number.isInteger(K) || K <= 0) { + throw new Error("HNSW: parameter 'K' must be a positive integer"); + } + + // Validate query dimensions + if (!q || (!Array.isArray(q) && !(q instanceof Float64Array))) { + throw new Error("HNSW: query must be an array"); + } + + const search_ef = this._ef; + + // Fallback to linear search if graph is not properly initialized + if (this._L < 0 || !this._ep || this._elements.length === 0) { + return this._linear_search(q, K); + } + + let ep_indices = [...this._ep]; + + // Search from top layer down to layer 1 + for (let l_c = this._L; l_c > 0; --l_c) { + const result = this._search_layer(q, ep_indices, 1, l_c); + if (result.length > 0) { + ep_indices = [result[0].index]; + } + } + + // Search layer 0 with ef candidates + const result = this._search_layer(q, ep_indices, Math.max(search_ef, K), 0); + + // If graph search returns no results, fallback to linear search + if (result.length === 0) { + return this._linear_search(q, K); + } + + // Return K closest + return result.slice(0, K); + } + + /** + * Fallback linear search when graph search fails + * @private + * @param {T} q - Query element + * @param {number} K - Number of nearest neighbors to return + * @returns {Candidate[]} + */ + _linear_search(q, K) { + const metric = this._metric; + const elements = this._elements; + const N = elements.length; + + if (N === 0) return []; + + /** @type {Candidate[]} */ + const candidates = []; + for (let i = 0; i < N; i++) { + const element = elements[i]; + // Skip elements with different dimensions (can happen with inconsistent data) + if (!element || element.length !== q.length) continue; + + candidates.push({ + element: element, + index: i, + distance: metric(q, element), + }); + } + + candidates.sort((a, b) => a.distance - b.distance); + return candidates.slice(0, K); + } + + /** + * Iterator for searching the HNSW graph layer by layer. + * + * Yields intermediate results at each layer for debugging or visualization. + * + * @param {T} q - Query element + * @param {number} K - Number of nearest neighbors to return + * @param {number?} [ef] - Size of dynamic candidate list + * @yields {{layer: number, candidates: Candidate[]}} + */ + *search_iter(q, K, ef = null) { + const search_ef = ef ?? this._ef; + + if (this._L < 0 || !this._ep) { + return; + } + + let ep_indices = [...this._ep]; + + // Yield entry points at top layer instead of query itself + const top_layer = this._graph.get(this._L); + if (top_layer && this._ep && this._ep.length > 0) { + const entry_candidates = this._ep + .filter((idx) => this._elements[idx] !== undefined) + .map((idx) => ({ + element: this._elements[idx], + index: idx, + distance: this._metric(this._elements[idx], q), + })); + yield { + layer: this._L, + candidates: entry_candidates, + }; + } + + for (let l_c = this._L; l_c > 0; --l_c) { + const result = this._search_layer(q, ep_indices, 1, l_c); + yield { layer: l_c, candidates: result }; + // Use closest candidate as entry point for next layer (following HNSW paper) + ep_indices = result.length > 0 ? [result[0].index] : ep_indices; + } + + const result = this._search_layer(q, ep_indices, Math.max(search_ef, K), 0); + yield { layer: 0, candidates: result }; + } + + /** + * Get the number of elements in the index. + * + * @returns {number} Number of elements + */ + get size() { + return this._elements?.length ?? 0; + } + + /** + * Get the number of layers in the graph. + * + * @returns {number} Number of layers + */ + get num_layers() { + return this._L + 1; + } + + /** + * Get an element by its index. + * + * @param {number} index - Element index + * @returns {T} The element at the given index + */ + get_element(index) { + return this._elements[index]; + } + + /** + * Search for nearest neighbors using an element index as the query. + * + * @param {number} i - Index of the query element + * @param {number} [K=5] - Number of nearest neighbors to return + * @returns {Candidate[]} K nearest neighbors + */ + search_by_index(i, K = 5) { + const elements = this._elements; + if (i < 0 || i >= elements.length) return []; + + const element = elements[i]; + if (!element) return []; + + return this.search(element, K); + } +} + +/** @import { Metric } from "../metrics/index.js" */ +/** @import { ParametersKDTree } from "./index.js" */ + +/** + * @template {number[] | Float64Array} T + * @typedef {Object} ElementWithIndex + * @property {number} index + * @property {T} element + */ + +/** + * KD-Tree (K-dimensional Tree) for efficient nearest neighbor search. + * + * KD-Trees partition k-dimensional space by recursively splitting along coordinate axes. + * At each level, the tree splits points based on the median of the coordinate with the largest spread. + * This creates a balanced binary tree structure that enables efficient O(log n) search on average. + * + * Best suited for: + * - Low to moderate dimensional data (d < 20-30) + * - When exact nearest neighbors are needed + * - When dimensionality is not too high + * + * Performance degrades in high dimensions (curse of dimensionality) where approximate + * methods like HNSW or LSH become more effective. + * + * @class + * @category KNN + * @template {number[] | Float64Array} T + * @extends KNN + * @see {@link https://en.wikipedia.org/wiki/K-d_tree} + */ +class KDTree extends KNN { + /** + * Generates a KD-Tree with given `elements`. + * + * @param {T[]} elements - Elements which should be added to the KD-Tree + * @param {ParametersKDTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}` + */ + constructor(elements, parameters = { metric: euclidean, seed: 1212 }) { + super(elements, Object.assign({ seed: 1212 }, parameters)); + /** + * @private + * @type {KDTreeNode | KDTreeLeaf | null} + */ + this._root = this._construct( + elements.map((element, index) => ({ index, element })), + 0, + ); + } + + /** @returns {Metric} */ + get _metric() { + return this._parameters.metric; + } + + /** + * @private + * @param {ElementWithIndex[]} elements + * @param {number} depth - Current depth in the tree (determines splitting axis) + * @returns {KDTreeNode | KDTreeLeaf | null} Root of KD-Tree. + */ + _construct(elements, depth) { + if (elements.length === 0) { + return null; + } + + if (elements.length === 1) { + return new KDTreeLeaf(elements[0]); + } + + const k = elements[0].element.length; + const axis = depth % k; + + // Sort by the splitting axis and find median + elements.sort((a, b) => a.element[axis] - b.element[axis]); + const medianIndex = Math.floor(elements.length / 2); + const medianPoint = elements[medianIndex]; + + // Recursively build left and right subtrees + const leftElements = elements.slice(0, medianIndex); + const rightElements = elements.slice(medianIndex + 1); + + const left = this._construct(leftElements, depth + 1); + const right = this._construct(rightElements, depth + 1); + + return new KDTreeNode(medianPoint, axis, left, right); + } + + /** + * @param {number} i + * @param {number} k + */ + search_by_index(i, k = 5) { + return this.search(this._elements[i], k); + } + + /** + * @param {T} t - Query element. + * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5` + * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors. + */ + search(t, k = 5) { + /** @type {Heap<{ point: ElementWithIndex; distance: number }>} */ + const best = new Heap(null, (d) => d.distance, "max"); + + this._search_recursive(t, k, this._root, best); + + // Convert heap to result array (closest first) + /** @type {{ element: T; index: number; distance: number }[]} */ + const result = []; + while (best.length > 0) { + const item = /** @type {{ element: { point: ElementWithIndex; distance: number }; value: number }} */ ( + best.pop() + ); + result.push({ + element: item.element.point.element, + index: item.element.point.index, + distance: item.value, + }); + } + return result.reverse(); + } + + /** + * @private + * @param {T} target - Query element. + * @param {number} k - Number of nearest neighbors to return. + * @param {KDTreeNode | KDTreeLeaf | null} node - Current node. + * @param {Heap<{ point: ElementWithIndex; distance: number }>} best - Heap of k best found so far. + */ + _search_recursive(target, k, node, best) { + if (node === null) return; + + if (node instanceof KDTreeLeaf) { + const dist = this._metric(target, node.point.element); + if (best.length < k) { + best.push({ point: node.point, distance: dist }); + } else if (dist < (best.first?.value ?? Infinity)) { + best.pop(); + best.push({ point: node.point, distance: dist }); + } + return; + } + + // Node is an internal node + const axis = node.axis; + const point = node.point; + const pointValue = point.element[axis]; + const targetValue = target[axis]; + + // Determine which subtree to search first + const firstSubtree = targetValue < pointValue ? node.left : node.right; + const secondSubtree = targetValue < pointValue ? node.right : node.left; + + // Search the nearer subtree + this._search_recursive(target, k, firstSubtree, best); + + // Check if we need to search the other subtree + // The hyperplane could contain closer points + const distToHyperplane = Math.abs(targetValue - pointValue); + const currentMaxDist = best.first?.value ?? Infinity; + + // Calculate distance to current point + const distToPoint = this._metric(target, point.element); + if (best.length < k) { + best.push({ point: point, distance: distToPoint }); + } else if (distToPoint < currentMaxDist) { + best.pop(); + best.push({ point: point, distance: distToPoint }); + } + + // Check if we need to explore the other side of the hyperplane + if (best.length < k || distToHyperplane < (best.first?.value ?? Infinity)) { + this._search_recursive(target, k, secondSubtree, best); + } + } +} + +/** + * @private + * @template {number[] | Float64Array} T + */ +class KDTreeNode { + /** + * @param {ElementWithIndex} point + * @param {number} axis - The splitting axis + * @param {KDTreeNode | KDTreeLeaf | null} left + * @param {KDTreeNode | KDTreeLeaf | null} right + */ + constructor(point, axis, left = null, right = null) { + this.point = point; + this.axis = axis; + this.left = left; + this.right = right; + } +} + +/** + * @private + * @template {number[] | Float64Array} T + */ +class KDTreeLeaf { + /** + * @param {ElementWithIndex} point + */ + constructor(point) { + this.point = point; + } +} + +/** @import { Metric } from "../metrics/index.js" */ +/** @import { ParametersLSH } from "./index.js" */ + +/** + * Locality Sensitive Hashing (LSH) for approximate nearest neighbor search. + * + * LSH uses hash functions that map similar items to the same buckets with high probability. + * This implementation uses Random Projection hashing (SimHash-style) which works well for + * cosine similarity and Euclidean distance. + * + * Key concepts: + * - Multiple hash tables increase recall probability + * - Each hash function projects data onto random hyperplanes + * - Points on the same side of hyperplanes are hashed together + * - Combines results from all tables for better accuracy + * + * Best suited for: + * - High-dimensional data where exact methods fail + * - Approximate nearest neighbor needs + * - Large datasets where linear scan is too slow + * - When some false positives/negatives are acceptable + * + * @class + * @category KNN + * @template {number[] | Float64Array} T + * @extends KNN + * @see {@link https://en.wikipedia.org/wiki/Locality-sensitive_hashing} + */ +class LSH extends KNN { + /** + * Creates a new LSH index. + * + * @param {T[]} elements - Elements to index + * @param {ParametersLSH} [parameters={}] - Configuration parameters + */ + constructor( + elements, + parameters = { + metric: euclidean, + numHashTables: 10, + numHashFunctions: 10, + seed: 1212, + }, + ) { + // Handle empty initialization - use dummy element + const hasElements = elements && elements.length > 0; + const firstElement = /** @type {T} */ (hasElements ? elements[0] : new Float64Array([0])); + + super([firstElement], parameters); + + this._metric = this._parameters.metric ?? euclidean; + this._numHashTables = this._parameters.numHashTables ?? 10; + this._numHashFunctions = this._parameters.numHashFunctions ?? 10; + this._seed = this._parameters.seed ?? 1212; + this._randomizer = new Randomizer(this._seed); + + // Hash tables: array of Maps where key is hash bucket, value is array of element indices + /** @type {Map[]} */ + this._hashTables = []; + + // Random projection vectors for each hash table and hash function + /** @type {Float64Array[][]} */ + this._projections = []; + + // Random offsets for each hash table and hash function (for quantization) + /** @type {number[][]} */ + this._offsets = []; + + // Store dimensionality for later + /** @type {number} */ + this._dim = firstElement.length; + + // Initialize hash functions + this._initializeHashFunctions(); + + // Reset elements if we were initialized with dummy + if (!hasElements) { + /** @type {T[]} */ + this._elements = []; + } else { + // Clear and re-add elements properly + /** @type {T[]} */ + this._elements = []; + this._hashTables = []; + this._projections = []; + this._offsets = []; + this._initializeHashFunctions(); + this.add(elements); + } + } + + /** + * Initialize random projection vectors for all hash tables. + * @private + */ + _initializeHashFunctions() { + const dim = this._elements[0]?.length ?? 0; + + for (let t = 0; t < this._numHashTables; t++) { + const tableProjections = []; + const tableOffsets = []; + + for (let h = 0; h < this._numHashFunctions; h++) { + // Generate random projection vector (normalized) + const projection = new Float64Array(dim); + let norm = 0; + for (let i = 0; i < dim; i++) { + // Box-Muller transform for normal distribution + const u1 = this._randomizer.random; + const u2 = this._randomizer.random; + const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2); + projection[i] = z; + norm += z * z; + } + // Normalize + norm = Math.sqrt(norm); + for (let i = 0; i < dim; i++) { + projection[i] /= norm; + } + + tableProjections.push(projection); + // Random offset for quantization buckets + tableOffsets.push(this._randomizer.random); + } + + this._projections.push(tableProjections); + this._offsets.push(tableOffsets); + this._hashTables.push(new Map()); + } + } + + /** + * Compute hash signature for an element using random projections. + * @private + * @param {T} element + * @param {number} tableIndex + * @returns {string} Hash signature + */ + _computeHash(element, tableIndex) { + const projections = this._projections[tableIndex]; + const offsets = this._offsets[tableIndex]; + const bits = []; + + for (let i = 0; i < this._numHashFunctions; i++) { + // Compute dot product + let dot = 0; + const proj = projections[i]; + for (let j = 0; j < element.length; j++) { + dot += element[j] * proj[j]; + } + // Quantize with offset + const bucket = Math.floor(dot + offsets[i]); + bits.push(bucket); + } + + return bits.join(","); + } + + /** + * Add elements to the LSH index. + * @param {T[]} elements + * @returns {this} + */ + add(elements) { + // Extend elements array + const startIndex = this._elements.length; + this._elements = this._elements.concat(elements); + + // Hash each new element and add to tables + for (let i = 0; i < elements.length; i++) { + const globalIndex = startIndex + i; + const element = elements[i]; + + for (let t = 0; t < this._numHashTables; t++) { + const hash = this._computeHash(element, t); + const table = this._hashTables[t]; + + if (!table.has(hash)) { + table.set(hash, []); + } + const bucket = table.get(hash); + if (bucket) { + bucket.push(globalIndex); + } + } + } + + return this; + } + + /** + * Search for k approximate nearest neighbors. + * @param {T} query + * @param {number} [k=5] + * @returns {{ element: T; index: number; distance: number }[]} + */ + search(query, k = 5) { + const metric = this._metric; + const elements = this._elements; + + if (elements.length === 0) return []; + + // Collect candidate indices from all hash tables + const candidates = new Set(); + + for (let t = 0; t < this._numHashTables; t++) { + const hash = this._computeHash(query, t); + const table = this._hashTables[t]; + const bucket = table.get(hash); + + if (bucket) { + for (const idx of bucket) { + if (idx !== undefined) { + candidates.add(idx); + } + } + } + } + + // If insufficient candidates found, fall back to linear search + if (candidates.size < k) { + // Add more candidates from all buckets or entire dataset + //const needed = k - candidates.size; + + // First, try to add from neighboring buckets (different hashes) + for (let t = 0; t < this._numHashTables && candidates.size < k; t++) { + const table = this._hashTables[t]; + for (const [, bucket] of table) { + for (const idx of bucket) { + if (idx !== undefined) { + candidates.add(idx); + if (candidates.size >= k) break; + } + } + if (candidates.size >= k) break; + } + } + + // If still not enough, add from entire dataset + for (let i = 0; i < elements.length && candidates.size < k; i++) { + candidates.add(i); + } + } + + // Compute exact distances for candidates + /** @type {Heap<{ index: number; distance: number }>} */ + const best = new Heap(null, (d) => d.distance, "max"); + + for (const idx of candidates) { + const element = elements[idx]; + if (!element || element.length !== query.length) continue; + + const dist = metric(query, element); + + if (best.length < k) { + best.push({ index: idx, distance: dist }); + } else if (dist < (best.first?.value ?? Infinity)) { + best.pop(); + best.push({ index: idx, distance: dist }); + } + } + + // Convert to result format + /** @type {{ element: T; index: number; distance: number }[]} */ + const result = []; + while (best.length > 0) { + const item = /** @type {{ element: { index: number; distance: number }; value: number }} */ (best.pop()); + result.push({ + element: elements[item.element.index], + index: item.element.index, + distance: item.value, + }); + } + + return result.reverse(); + } + + /** + * @param {number} i + * @param {number} [k=5] + * @returns {{ element: T; index: number; distance: number }[]} + */ + search_by_index(i, k = 5) { + if (i < 0 || i >= this._elements.length) return []; + return this.search(this._elements[i], k); + } +} + +/** @import { ParametersNaiveKNN } from "./index.js" */ + +/** + * Naive KNN implementation using a distance matrix. + * + * This implementation pre-computes the entire distance matrix and performs + * an exhaustive search. Best suited for small datasets or when a distance + * matrix is already available. + * + * @template {number[] | Float64Array} T + * @category KNN + * @class + * @extends KNN + */ +class NaiveKNN extends KNN { + /** + * Generates a KNN list with given `elements`. + * + * @param {T[]} elements - Elements which should be added to the KNN list + * @param {ParametersNaiveKNN} parameters + */ + constructor(elements, parameters = {}) { + const params = Object.assign({ metric: euclidean, seed: 1212 }, parameters); + super(elements, params); + const N = + this._elements instanceof Matrix ? /** @type {any} */ (this._elements).shape[0] : this._elements.length; + if (this._parameters.metric === "precomputed") { + this._D = Matrix.from(/** @type {number[][] | Float64Array[]} */ (/** @type {any} */ (this._elements))); + } else { + this._D = distance_matrix( + /** @type {number[][] | Float64Array[]} */ (this._elements), + this._parameters.metric, + ); + } + + /** @type {Heap<{ value: number; index: number }>[]} */ + this.KNN = []; + for (let row = 0; row < N; ++row) { + const distances = this._D.row(row); + /** @type {Heap<{ value: number; index: number }>} */ + const H = new Heap(null, (d) => d.value, "min"); + for (let j = 0; j < N; ++j) { + H.push({ + value: distances[j], + index: j, + }); + } + this.KNN.push(H); + } + } + + /** + * @param {number} i + * @param {number} k + */ + search_by_index(i, k = 5) { + if (this._parameters.metric === "precomputed") { + const H = this.KNN[i]; + /** @type {{ element: T; index: number; distance: number }[]} */ + const result = []; + const data = H.toArray(); // Get array representation + const temp_heap = new Heap(data, (d) => d.value, "min"); + const N = + this._elements instanceof Matrix ? /** @type {any} */ (this._elements).shape[0] : this._elements.length; + for (let j = 0; j < Math.min(k, N); ++j) { + const node = temp_heap.pop(); + if (!node) break; + result.push({ + element: /** @type {T} */ ( + this._elements instanceof Matrix + ? /** @type {any} */ (this._elements).row(node.element.index) + : this._elements[node.element.index] + ), + index: /** @type {number} */ (node.element.index), + distance: /** @type {number} */ (node.value), + }); + } + return result; + } + return this.search( + /** @type {T} */ ( + this._elements instanceof Matrix ? /** @type {any} */ (this._elements).row(i) : this._elements[i] + ), + k, + ); + } + + /** + * @param {T} t - Query element. + * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5` + * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors. + */ + search(t, k = 5) { + if (this._parameters.metric === "precomputed") { + throw new Error("Search by query element is only possible when not using a precomputed distance matrix!"); + } + /** @type {import("../metrics/index.js").Metric} */ + const metric = /** @type {any} */ (this._parameters.metric); + + const isMatrix = this._elements instanceof Matrix; + const elementsAny = /** @type {any} */ (this._elements); + const N = isMatrix ? elementsAny.shape[0] : this._elements.length; + + // Compute distances from query to ALL points + const distances = []; + for (let i = 0; i < N; i++) { + const element = /** @type {T} */ (isMatrix ? elementsAny.row(i) : this._elements[i]); + distances.push({ + element: element, + index: i, + distance: metric(t, element), + }); + } + + // Sort by distance and return k nearest + distances.sort((a, b) => a.distance - b.distance); + return distances.slice(0, k); + } +} + +/** @import {ParametersNNDescent} from "./index.js" */ +/** * - * @category Matrix - * @param {number[] | Float64Array} v - Vector - * @param {Metric} metric - * @returns {number[] | Float64Array} - The normalized vector with length 1. + * @template {number[] | Float64Array} T + * @typedef {Object} NNDescentElement + * @property {T} value + * @property {number} index + * @property {boolean} flag */ -function normalize(v, metric = euclidean) { - const v_norm = norm(v, metric); - return v.map((value) => value / v_norm); + +/** + * @template {number[] | Float64Array} T + * @typedef {Object} NNDescentNeighbor + * @property {T} value + * @property {number} index + * @property {number} distance + * @property {boolean} [flag] + */ + +/** + * NN-Descent + * + * An efficient graph-based approximate nearest neighbor search algorithm. + * It works by iteratively improving a neighbor graph using the fact that + * "neighbors of neighbors are likely to be neighbors". + * + * @class + * @category KNN + * @template {number[] | Float64Array} T + * @extends KNN + * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf|NN-Descent Paper} + */ +class NNDescent extends KNN { + /** + * @private + * @type {KNNHeap[]} + */ + _B = []; + /** + * @private + * @type {NNDescentNeighbor[][]} + */ + nn = []; + + /** + * @param {T[]} elements - Called V in paper. + * @param {Partial} parameters + * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf} + */ + constructor(elements, parameters = {}) { + super( + elements, + /** @type {ParametersNNDescent} */ ( + Object.assign({ metric: euclidean, K: 10, rho: 1, delta: 1e-3, seed: 1212 }, parameters) + ), + ); + this._N = elements.length; + this._randomizer = new Randomizer(this._parameters.seed); + this._sample_size = this._parameters.samples * this._parameters.rho; + + this._nndescent_elements = elements.map((e, i) => { + return { + value: e, + index: i, + flag: true, + }; + }); + + if (elements) { + this.add(elements); + } + } + + /** + * Samples Array A with sample size. + * + * @private + * @template U + * @param {U[]} A + * @returns {U[]} + */ + _sample(A) { + const n = A.length; + const sample_size = this._sample_size; + if (sample_size > n) { + return A; + } else { + const randomizer = this._randomizer; + return randomizer.choice(A, sample_size); + } + } + + /** + * @private + * @param {KNNHeap} B + * @param {NNDescentNeighbor} u + * @returns {number} + */ + _update(B, u) { + if (B.set.has(u.index)) return 0; + + const worst = B.first; + if (worst && B.length >= this._parameters.samples) { + const dist = B._accessor(u); + const worst_dist = B._accessor(worst.element); + if (dist >= worst_dist) { + return 0; // u is worse than the worst neighbor + } + } + + B.push(u); + u.flag = true; + if (B.length > this._parameters.samples) { + B.pop(); + } + return 1; + } + + /** + * @private + * @param {(KNNHeap | null)[]} B + * @returns {NNDescentNeighbor[][]} + */ + _reverse(B) { + const N = this._N; + const R = new Array(N); + for (let i = 0; i < N; i++) { + R[i] = []; + } + for (let j = 0; j < N; j++) { + const Bi = B[j]; + if (Bi) { + const Bjdata = Bi.data(); + for (const neighbor of Bjdata) { + const v = neighbor.index; + R[v].push(neighbor); + } + } + } + return R; + } + + /** + * @param {T[]} elements + * @returns {this} + */ + add(elements) { + const randomizer = this._randomizer; + const metric = this._parameters.metric; + const K = this._parameters.samples; + const delta = this._parameters.delta; + const N = elements.length; + this._N = N; + /** @type {KNNHeap[]} */ + const B = []; + this._B = B; + for (let i = 0; i < N; i++) { + const e = elements[i]; + const sample = randomizer + .choice( + elements.map((el, idx) => ({ el, idx })), + K, + ) + .map((d) => { + return { index: d.idx, distance: metric(d.el, e), value: d.el }; + }); + const Bi = new KNNHeap(sample, (d) => d.distance, "max"); + B.push(Bi); + } + + let c = Infinity; + let old_c = -Infinity; + while (c > delta * N * K && c !== old_c) { + const old_ = new Array(N); + const new_ = new Array(N); + for (let i = 0; i < N; i++) { + const Bi = B[i].data(); + const falseBs = Bi.filter((d) => !d.flag); + const trueBs = this._sample(Bi.filter((d) => d.flag)); + for (const d of trueBs) { + d.flag = false; + } + old_[i] = new KNNHeap(falseBs, (d) => d.distance, "max"); + new_[i] = new KNNHeap(trueBs, (d) => d.distance, "max"); + } + const old_reverse = this._reverse(old_); + const new_reverse = this._reverse(new_); + old_c = c; + c = 0; + for (let i = 0; i < N; i++) { + for (const o of this._sample(old_reverse[i])) { + old_[i].push(o); + } + for (const n of this._sample(new_reverse[i])) { + new_[i].push(n); + } + + const new_i = new_[i].data(); + const old_i = old_[i].data(); + const n1 = new_i.length; + const n2 = old_i.length; + for (let j = 0; j < n1; j++) { + const u1 = new_i[j]; + const Bu1 = B[u1.index]; + for (let k = 0; k < n1; k++) { + const u2 = new_i[k]; + if (u1.index === u2.index) continue; + const Bu2 = B[u2.index]; + c += this._update(Bu2, u1); + c += this._update(Bu1, u2); + } + for (let k = 0; k < n2; k++) { + const u2 = old_i[k]; + if (u1.index === u2.index) continue; + const Bu2 = B[u2.index]; + c += this._update(Bu2, u1); + c += this._update(Bu1, u2); + } + } + } + } + this.nn = this._B.map((heap) => heap.data()); + return this; + } + + /** + * @param {T} x + * @param {number} [k=5] Default is `5` + * @returns {{ element: T, index: number; distance: number }[]} + */ + search(x, k = 5) { + const metric = this._parameters.metric; + const N = this._N; + const elements = this._elements; + + if (N === 0) return []; + const xLength = x.length; + + // Initialize candidate pool + const visited = new Set(); + /** @type {{index: number, dist: number, evaluated: boolean}[]} */ + let pool = []; + + // Randomly pick initial candidates + const randomizer = this._randomizer; + for (let i = 0; i < Math.min(N, Math.max(k * 10, 50)); i++) { + let rnd; + do { + rnd = randomizer.random_int % N; + } while (visited.has(rnd)); + visited.add(rnd); + + const element = elements[rnd]; + if (!element || element.length !== xLength) continue; + + pool.push({ + index: rnd, + dist: metric(x, element), + evaluated: false, + }); + } + + let searching = true; + while (searching) { + pool.sort((a, b) => a.dist - b.dist); + // keep the top subset for exploration + pool = pool.slice(0, Math.max(k * 5, 50)); + + searching = false; + for (let i = 0; i < pool.length; i++) { + const candidate = pool[i]; + if (candidate.evaluated) continue; + + candidate.evaluated = true; + searching = true; + + // get neighbors of this candidate from graph + const neighbors = this.nn[candidate.index]; + if (!neighbors) continue; + + for (const neighbor of neighbors) { + const n_idx = neighbor.index; + if (!visited.has(n_idx)) { + visited.add(n_idx); + const element = elements[n_idx]; + if (element && element.length === xLength) { + pool.push({ + index: n_idx, + dist: metric(x, element), + evaluated: false, + }); + } + } + } + // Don't break here! Look at more candidates per iteration for better convergence + // break; + } + } + + pool.sort((a, b) => a.dist - b.dist); + + /** @type {{ element: T, index: number; distance: number }[]} */ + const result = []; + for (let i = 0; i < Math.min(k, pool.length); i++) { + const item = pool[i]; + result.push({ + element: elements[item.index], + index: item.index, + distance: item.dist, + }); + } + return result; + } + + /** + * @param {number} i + * @param {number} [k=5] Default is `5` + * @returns {{ element: T; index: number; distance: number }[]} + */ + search_by_index(i, k = 5) { + // Use regular search with the element at index i + const elements = this._elements; + if (i < 0 || i >= elements.length) return []; + + const element = elements[i]; + if (!element) return []; + + return this.search(element, k); + } +} + +/** + * @template {number[] | Float64Array} U + * @typedef {Object} HeapEntry + * @property {NNDescentNeighbor} element + * @property {number} value + */ + +/** + * @template {number[] | Float64Array} U + * @extends {Heap>} + */ +class KNNHeap extends Heap { + /** @type {Set} */ + set; + + /** + * @param {NNDescentNeighbor[]} elements + * @param {(d: NNDescentNeighbor) => number} accessor + * @param {"max" | "min"} comparator + */ + constructor(elements, accessor, comparator) { + super(null, accessor, comparator); + this.set = new Set(); + if (elements) { + for (const element of elements) { + this.push(element); + } + } + } + + /** + * @param {NNDescentNeighbor} element + * @returns {KNNHeap} + */ + push(element) { + const set = this.set; + if (set.has(element.index)) { + return this; + } else { + set.add(element.index); + super.push(element); + return this; + } + } + + /** @returns {{ element: NNDescentNeighbor; value: number } | null} */ + pop() { + const result = super.pop(); + if (result?.element) { + this.set.delete(result.element.index); + return result; + } + return null; + } + + /** @returns {NNDescentNeighbor[]} */ + data() { + return this._container.map((d) => d.element); + } +} + +/** @import {InputType} from "../index.js" */ +/** @import {ParametersPCA} from "./index.js" */ +/** @import {EigenArgs} from "../linear_algebra/index.js" */ + +/** + * Principal Component Analysis (PCA) + * + * A linear dimensionality reduction technique that identifies the axes (principal components) + * along which the variance of the data is maximized. + * + * @class + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction + * @see {@link MDS} for another linear alternative + * + * @example + * import * as druid from "@saehrimnir/druidjs"; + * + * const X = [[1, 2], [3, 4], [5, 6]]; + * const pca = new druid.PCA(X, { d: 2 }); + * const Y = pca.transform(); + * // [[x1, y1], [x2, y2], [x3, y3]] + */ +class PCA extends DR { + /** + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + */ + constructor(X, parameters = {}) { + super(X, { d: 2, seed: 1212, eig_args: {} }, parameters); + const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); + if (!Object.hasOwn(eig_args, "seed")) { + eig_args.seed = this._randomizer; + } + } + + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + *generator() { + yield this.transform(); + return this.projection; + } + + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {T} - The projected data. + */ + transform() { + const V = this.principal_components(); + const X = this.X; + this.Y = X.dot(V); + return this.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {T} + */ + static transform(X, parameters) { + const dr = new PCA(X, parameters); + return dr.transform(); + } + + /** + * Computes the `d` principal components of Matrix `X`. + * + * @returns {Matrix} + */ + principal_components() { + if (this.V) { + return this.V; + } + const d = /** @type {number} */ (this.parameter("d")); + const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); + const X = this.X; + const X_cent = X.sub(X.meanCols()); + const C = X_cent.transDot(X_cent); + const { eigenvectors: V } = simultaneous_poweriteration(C, d, eig_args); + this.V = Matrix.from(V).transpose(); + return this.V; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Matrix} + */ + static principal_components(X, parameters) { + const dr = new PCA(X, parameters); + return dr.principal_components(); + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new PCA(X, parameters); + yield* dr.generator(); + return dr.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new PCA(X, parameters); + return dr.transform_async(); + } +} + +/** @import {InputType} from "../index.js" */ +/** @import {Metric} from "../metrics/index.js" */ +/** @import {ParametersPaCMAP} from "./index.js" */ + +/** + * Pairwise Controlled Manifold Approximation Projection (PaCMAP) + * + * A dimensionality reduction technique that uses three types of point pairs — + * nearest neighbor (NN), mid-near (MN), and further (FP) pairs — with a + * dynamic three-phase weight schedule and Adam optimization to preserve both + * local and global structure. + * + * @class + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction + * @see {@link https://arxiv.org/abs/2012.04456|PaCMAP Paper} + * @see {@link https://github.com/YingfanWang/PaCMAP|PaCMAP GitHub} + * @see {@link UMAP} for a related graph-based technique + * @see {@link LocalMAP} for the local-refinement variant + * + * @example + * import * as druid from "@saehrimnir/druidjs"; + * + * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]; + * const pacmap = new druid.PaCMAP(X, { + * n_neighbors: 10, + * MN_ratio: 0.5, + * FP_ratio: 2.0, + * seed: 42 + * }); + * + * const Y = pacmap.transform(); // 450 iterations (default) + * // [[x1, y1], [x2, y2], [x3, y3]] + */ +class PaCMAP extends DR { + /** + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + */ + constructor(X, parameters) { + super( + X, + { + n_neighbors: 10, + MN_ratio: 0.5, + FP_ratio: 2.0, + d: 2, + metric: euclidean, + lr: 1.0, + num_iters: [100, 100, 250], + seed: 1212, + }, + parameters, + ); + [this._N, this._D] = this.X.shape; + const n_neighbors = /** @type {number} */ (this.parameter("n_neighbors")); + if (n_neighbors >= this._N) { + throw new Error( + `Parameter n_neighbors (=${n_neighbors}) needs to be smaller than dataset size (N=${this._N})!`, + ); + } + this._iter = 0; + } + + /** + * Samples mid-near pairs for each point. + * For each point i, repeats n_MN times: samples 6 random non-neighbor + * candidates, picks the 2nd closest by high-dim distance. + * + * @protected + * @param {Set[]} nn_sets - Array of neighbor index sets per point + * @param {number} n_MN - Number of mid-near pairs per point + * @returns {Int32Array} Flat array of [i, j] pairs + */ + _sample_mn_pairs(nn_sets, n_MN) { + const N = this._N; + const X = this.X; + const randomizer = this._randomizer; + const pairs = new Int32Array(N * n_MN * 2); + let idx = 0; + + for (let i = 0; i < N; ++i) { + const nn_set = nn_sets[i]; + const x_i = X.row(i); + + for (let k = 0; k < n_MN; ++k) { + // Sample 6 random non-neighbor candidates + /** @type {{idx: number, dist: number}[]} */ + const candidates = []; + let attempts = 0; + while (candidates.length < 6 && attempts < N * 2) { + const j = randomizer.random_int % N; + attempts++; + if (j !== i && !nn_set.has(j)) { + candidates.push({ idx: j, dist: euclidean_squared(x_i, X.row(j)) }); + } + } + if (candidates.length < 2) { + // Fallback: use any available non-self point + const j = (i + 1) % N; + pairs[idx++] = i; + pairs[idx++] = j; + continue; + } + candidates.sort((a, b) => a.dist - b.dist); + // Pick the 2nd closest (index 1) + pairs[idx++] = i; + pairs[idx++] = candidates[1].idx; + } + } + return pairs.slice(0, idx); + } + + /** + * Samples further pairs for each point (random non-neighbors). + * + * @protected + * @param {Set[]} nn_sets - Array of neighbor index sets per point + * @param {number} n_FP - Number of further pairs per point + * @returns {Int32Array} Flat array of [i, j] pairs + */ + _sample_fp_pairs(nn_sets, n_FP) { + const N = this._N; + const randomizer = this._randomizer; + const pairs = new Int32Array(N * n_FP * 2); + let idx = 0; + + for (let i = 0; i < N; ++i) { + const nn_set = nn_sets[i]; + let count = 0; + let attempts = 0; + while (count < n_FP && attempts < N * 3) { + const j = randomizer.random_int % N; + attempts++; + if (j !== i && !nn_set.has(j)) { + pairs[idx++] = i; + pairs[idx++] = j; + count++; + } + } + } + return pairs.slice(0, idx); + } + + /** + * Computes gradient coefficients and updates the gradient matrix for one pair type. + * + * @protected + * @param {Float64Array} grad_flat - Flat N×d gradient accumulator (modified in place) + * @param {Int32Array} pairs - Flat [i, j, i, j, ...] pair array + * @param {number} w - Weight for this pair type + * @param {number} attr_num - Numerator constant for attractive (10 for NN, 10000 for MN); 0 for repulsive + * @param {boolean} repulsive - Whether this is a repulsive pair type + */ + _accumulate_gradients(grad_flat, pairs, w, attr_num, repulsive) { + if (w === 0) return; + const Y = this.Y; + const d = /** @type {number} */ (this.parameter("d")); + const n_pairs = pairs.length / 2; + + for (let p = 0; p < n_pairs; ++p) { + const i = pairs[p * 2]; + const j = pairs[p * 2 + 1]; + const y_i = Y.row(i); + const y_j = Y.row(j); + + // d_ij = 1 + ||y_i - y_j||² + let sq_dist = 0; + for (let k = 0; k < d; ++k) { + const diff = y_i[k] - y_j[k]; + sq_dist += diff * diff; + } + const d_ij = 1 + sq_dist; + + /** @type {number} */ + let coeff; + if (repulsive) { + // FP loss: 1/(1+d_ij), gradient: -2/(1+d_ij)² + coeff = (-w * 2) / (d_ij * d_ij); + } else { + // NN loss: d_ij/(attr_num+d_ij), gradient: 2*attr_num/(attr_num+d_ij)² + const denom = attr_num + d_ij; + coeff = (w * 2 * attr_num) / (denom * denom); + } + + const base_i = i * d; + const base_j = j * d; + for (let k = 0; k < d; ++k) { + const diff = y_i[k] - y_j[k]; + const g = coeff * diff; + grad_flat[base_i + k] += g; + grad_flat[base_j + k] -= g; + } + } + } + + /** + * Returns the weight schedule for the current iteration. + * + * @protected + * @param {number} iter - Current iteration (0-indexed) + * @returns {{ w_nn: number; w_mn: number; w_fp: number }} + */ + _get_weights(iter) { + const num_iters = /** @type {number[]} */ (this.parameter("num_iters")); + const [p1, p2] = num_iters; + if (iter < p1) { + // Phase 1: MN weight linearly decays from 1000 to 3 + const t = iter / p1; + return { w_nn: 2.0, w_mn: 1000.0 * (1 - t) + 3.0 * t, w_fp: 1.0 }; + } else if (iter < p1 + p2) { + // Phase 2: fixed weights + return { w_nn: 3.0, w_mn: 3.0, w_fp: 1.0 }; + } else { + // Phase 3: MN disabled + return { w_nn: 1.0, w_mn: 0.0, w_fp: 1.0 }; + } + } + + /** + * Applies Adam optimizer update to Y using accumulated gradients. + * + * @protected + * @param {Float64Array} grad_flat - Flat N×d gradient + */ + _adam_update(grad_flat) { + const lr = /** @type {number} */ (this.parameter("lr")); + const N = this._N; + const d = /** @type {number} */ (this.parameter("d")); + const beta1 = 0.9; + const beta2 = 0.999; + const eps = 1e-7; + this._adam_t = (this._adam_t ?? 0) + 1; + const t = /** @type {number} */ (this._adam_t); + const bc1 = 1 - beta1 ** t; + const bc2 = 1 - beta2 ** t; + const Y = this.Y; + const m = /** @type {Float64Array} */ (this._adam_m); + const v = /** @type {Float64Array} */ (this._adam_v); + + for (let i = 0; i < N; ++i) { + const base = i * d; + const y_i = Y.row(i); + for (let k = 0; k < d; ++k) { + const g = grad_flat[base + k]; + m[base + k] = beta1 * m[base + k] + (1 - beta1) * g; + v[base + k] = beta2 * v[base + k] + (1 - beta2) * g * g; + const m_hat = m[base + k] / bc1; + const v_hat = v[base + k] / bc2; + y_i[k] -= lr * (m_hat / (Math.sqrt(v_hat) + eps)); + } + } + } + + /** + * Initializes PaCMAP: PCA embedding, KNN pairs, MN pairs, FP pairs, Adam state. + * + * @returns {PaCMAP} + */ + init() { + const X = this.X; + const N = this._N; + const d = /** @type {number} */ (this.parameter("d")); + const seed = /** @type {number} */ (this.parameter("seed")); + const metric = /** @type {Metric} */ (this.parameter("metric")); + const n_neighbors = /** @type {number} */ (this.parameter("n_neighbors")); + const MN_ratio = /** @type {number} */ (this.parameter("MN_ratio")); + const FP_ratio = /** @type {number} */ (this.parameter("FP_ratio")); + + // 1. PCA initialization scaled by 0.01 (X is always Matrix here) + const pca_init = /** @type {Matrix} */ (PCA.transform(X, { d, seed })); + this.Y = new Matrix(N, d, (i, j) => pca_init.entry(i, j) * 0.01); + + // 2. Build KNN graph for NN pairs + const knn = new BallTree(X.to2dArray(), { metric, seed }); + const n_MN = Math.max(1, Math.round(n_neighbors * MN_ratio)); + const n_FP = Math.max(1, Math.round(n_neighbors * FP_ratio)); + /** @type {Set[]} */ + const nn_sets = []; + // NN pairs: flat [i, j] pairs + const nn_pairs = new Int32Array(N * n_neighbors * 2); + let nn_idx = 0; + + for (let i = 0; i < N; ++i) { + const neighbors = knn.search(X.row(i), n_neighbors + 1); + /** @type {number[]} */ + const idxs = []; + for (const nb of neighbors) { + if (nb.index !== i) idxs.push(nb.index); + if (idxs.length >= n_neighbors) break; + } + nn_sets[i] = new Set(idxs); + for (const j of idxs) { + nn_pairs[nn_idx++] = i; + nn_pairs[nn_idx++] = j; + } + } + this._nn_pairs = nn_pairs.slice(0, nn_idx); + + // 3. MN pairs (mid-near sampling) + this._mn_pairs = this._sample_mn_pairs(nn_sets, n_MN); + + // 4. FP pairs (random non-neighbors) + this._fp_pairs = this._sample_fp_pairs(nn_sets, n_FP); + + // 5. Adam optimizer state + this._adam_m = new Float64Array(N * d); + this._adam_v = new Float64Array(N * d); + this._adam_t = 0; + + this._iter = 0; + return this; + } + + /** + * Performs one optimization step. + * + * @returns {Matrix} + */ + next() { + if (!this._nn_pairs) throw new Error("Call init() first!"); + const N = this._N; + const d = /** @type {number} */ (this.parameter("d")); + const { w_nn, w_mn, w_fp } = this._get_weights(this._iter); + + const grad_flat = new Float64Array(N * d); + this._accumulate_gradients(grad_flat, /** @type {Int32Array} */ (this._nn_pairs), w_nn, 10, false); + this._accumulate_gradients(grad_flat, /** @type {Int32Array} */ (this._mn_pairs), w_mn, 10000, false); + this._accumulate_gradients(grad_flat, /** @type {Int32Array} */ (this._fp_pairs), w_fp, 0, true); + this._adam_update(grad_flat); + + this._iter++; + return this.Y; + } + + /** + * @param {number} [iterations] - Total number of iterations. Defaults to sum of `num_iters`. + * @returns {T} + */ + transform(iterations) { + const num_iters = /** @type {number[]} */ (this.parameter("num_iters")); + const total = iterations ?? num_iters.reduce((a, b) => a + b, 0); + this.check_init(); + for (let i = 0; i < total; ++i) { + this.next(); + } + return this.projection; + } + + /** + * @param {number} [iterations] - Total number of iterations. Defaults to sum of `num_iters`. + * @returns {Generator} + */ + *generator(iterations) { + const num_iters = /** @type {number[]} */ (this.parameter("num_iters")); + const total = iterations ?? num_iters.reduce((a, b) => a + b, 0); + this.check_init(); + for (let i = 0; i < total; ++i) { + this.next(); + yield this.projection; + } + return this.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X, parameters) { + const dr = new PaCMAP(X, parameters); + return dr.transform(); + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new PaCMAP(X, parameters); + yield* dr.generator(); + return dr.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new PaCMAP(X, parameters); + return dr.transform_async(); + } } /** @import {InputType} from "../index.js" */ +/** @import {ParametersLocalMAP} from "./index.js" */ /** - * Base class for all clustering algorithms. - * @template Para + * LocalMAP + * + * A variant of PaCMAP that improves local cluster separation by dynamically + * resampling further pairs (FP) in phase 3 using nearby points in the current + * low-dimensional embedding space, rather than randomly sampled non-neighbors. + * + * @class + * @template {InputType} T + * @extends PaCMAP + * @category Dimensionality Reduction + * @see {@link https://arxiv.org/abs/2012.04456|PaCMAP Paper} + * @see {@link PaCMAP} for the base algorithm + * + * @example + * import * as druid from "@saehrimnir/druidjs"; + * + * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]; + * const localmap = new druid.LocalMAP(X, { + * n_neighbors: 10, + * low_dist_thres: 10, + * seed: 42 + * }); + * + * const Y = localmap.transform(); // 450 iterations (default) + * // [[x1, y1], [x2, y2], [x3, y3]] */ -class Clustering { - /** @type {InputType} */ - _points; - /** @type {Para} */ - _parameters; - /** @type {Matrix} */ - _matrix; - /** @type {number} */ - _N; - /** @type {number} */ - _D; - - /** - * Compute the respective Clustering with given parameters - * @param {InputType} points - * @param {Para} parameters - */ - constructor(points, parameters) { - this._points = points; - this._parameters = parameters; - - this._matrix = points instanceof Matrix ? points : Matrix.from(points); - const [N, D] = this._matrix.shape; - this._N = N; - this._D = D; - } - - /** - * @abstract - * @param {...unknown} args - * @returns {number[][]} An array with the indices of the clusters. - */ - get_clusters(...args) { - throw new Error("The function get_clusters must be implemented!"); - } - - /** - * @abstract - * @param {...unknown} args - * @returns {number[]} An array with the clusters id's for each point. - */ - get_cluster_list(...args) { - throw new Error("The function get_cluster_list must be implemented!"); - } +class LocalMAP extends PaCMAP { + /** + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + */ + constructor(X, parameters = {}) { + // Merge low_dist_thres into parameters before the seal in DR constructor. + // DR.constructor does Object.seal({ ...defaults, ...parameters }), so + // passing low_dist_thres here ensures it lands in the sealed object. + super(X, { low_dist_thres: 10, ...parameters }); + } + + /** + * Performs one optimization step. + * In phase 3, resamples FP pairs from the current embedding space + * and applies distance-based weight scaling. + * + * @returns {import("../matrix/index.js").Matrix} + */ + next() { + if (!this._nn_pairs) throw new Error("Call init() first!"); + const num_iters = /** @type {number[]} */ (this.parameter("num_iters")); + const phase3_start = num_iters[0] + num_iters[1]; + + if (this._iter < phase3_start) { + // Phases 1 and 2: identical to PaCMAP + return super.next(); + } + + // Phase 3: resample FP pairs from embedding neighbors + const N = this._N; + const d = /** @type {number} */ (this.parameter("d")); + const low_dist_thres = /** @type {number} */ (this._low_dist_thres ?? 10); + const low_dist_thres_sq = low_dist_thres * low_dist_thres; + const { w_nn, w_mn, w_fp } = this._get_weights(this._iter); + const Y = this.Y; + + // Build a KNN structure on the current embedding to find nearby pairs + const y_array = Y.to2dArray(); + const seed = /** @type {number} */ (this.parameter("seed")); + const emb_knn = new BallTree(y_array, { metric: euclidean_squared, seed }); + const n_FP = /** @type {number} */ (this.parameter("FP_ratio")) * + /** @type {number} */ (this.parameter("n_neighbors")); + const n_FP_int = Math.max(1, Math.round(n_FP)); + + // Build local FP pairs by finding nearby embedding neighbors + // (these are not NN neighbors in high-dim space but nearby in low-dim) + const nn_sets = this._nn_sets_cache; + /** @type {Int32Array} */ + let local_fp_pairs; + + if (nn_sets) { + const pair_buf = new Int32Array(N * n_FP_int * 2); + let idx = 0; + for (let i = 0; i < N; ++i) { + const nn_set = nn_sets[i]; + // Search for nearby points in embedding space + const neighbors = emb_knn.search(y_array[i], Math.min(n_FP_int * 3 + 1, N)); + let count = 0; + for (const nb of neighbors) { + if (nb.index === i || (nn_set && nn_set.has(nb.index))) continue; + pair_buf[idx++] = i; + pair_buf[idx++] = nb.index; + count++; + if (count >= n_FP_int) break; + } + } + local_fp_pairs = pair_buf.slice(0, idx); + } else { + local_fp_pairs = /** @type {Int32Array} */ (this._fp_pairs); + } + + // Accumulate gradients with local weight scaling for FP pairs + const grad_flat = new Float64Array(N * d); + this._accumulate_gradients(grad_flat, /** @type {Int32Array} */ (this._nn_pairs), w_nn, 10, false); + this._accumulate_gradients(grad_flat, /** @type {Int32Array} */ (this._mn_pairs), w_mn, 10000, false); + + // FP pairs with local distance-based weight scaling + this._accumulate_gradients_local_fp( + grad_flat, + local_fp_pairs, + w_fp, + low_dist_thres, + low_dist_thres_sq, + ); + + this._adam_update(grad_flat); + this._iter++; + return this.Y; + } + + /** + * Accumulates FP gradients with LocalMAP's distance-based weight scaling. + * For pairs within low_dist_thres, scales w_fp by low_dist_thres / (2 * sqrt(d_ij)). + * + * @private + * @param {Float64Array} grad_flat - Flat N×d gradient accumulator (modified in place) + * @param {Int32Array} pairs - Flat [i, j, i, j, ...] pair array + * @param {number} w_fp - Base FP weight + * @param {number} low_dist_thres - Distance threshold + * @param {number} low_dist_thres_sq - Squared distance threshold + */ + _accumulate_gradients_local_fp(grad_flat, pairs, w_fp, low_dist_thres, low_dist_thres_sq) { + if (w_fp === 0) return; + const Y = this.Y; + const d = /** @type {number} */ (this.parameter("d")); + const n_pairs = pairs.length / 2; + + for (let p = 0; p < n_pairs; ++p) { + const i = pairs[p * 2]; + const j = pairs[p * 2 + 1]; + const y_i = Y.row(i); + const y_j = Y.row(j); + + let sq_dist = 0; + for (let k = 0; k < d; ++k) { + const diff = y_i[k] - y_j[k]; + sq_dist += diff * diff; + } + const d_ij = 1 + sq_dist; + + // Apply local weight scaling when pair is within distance threshold + let w = w_fp; + if (sq_dist < low_dist_thres_sq) { + w *= low_dist_thres / (2 * Math.sqrt(d_ij)); + } + + // FP loss: 1/(1+d_ij), gradient: -2/(1+d_ij)² + const coeff = (-w * 2) / (d_ij * d_ij); + + const base_i = i * d; + const base_j = j * d; + for (let k = 0; k < d; ++k) { + const diff = y_i[k] - y_j[k]; + const g = coeff * diff; + grad_flat[base_i + k] += g; + grad_flat[base_j + k] -= g; + } + } + } + + /** + * Initializes LocalMAP (same as PaCMAP, but caches nn_sets for phase 3 resampling). + * + * @returns {LocalMAP} + */ + init() { + super.init(); + // Cache low_dist_thres from sealed parameters (avoids type indexing issues) + this._low_dist_thres = /** @type {number} */ (/** @type {any} */ (this._parameters)["low_dist_thres"] ?? 10); + // Cache nn_sets for use in phase 3 FP resampling + // We rebuild them from _nn_pairs + const N = this._N; + const nn_pairs = this._nn_pairs; + if (!nn_pairs) return this; + /** @type {Set[]} */ + const nn_sets = Array.from({ length: N }, () => new Set()); + for (let p = 0; p < nn_pairs.length; p += 2) { + nn_sets[nn_pairs[p]].add(nn_pairs[p + 1]); + } + this._nn_sets_cache = nn_sets; + return this; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X, parameters) { + const dr = new LocalMAP(X, parameters); + return dr.transform(); + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new LocalMAP(X, parameters); + yield* dr.generator(); + return dr.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new LocalMAP(X, parameters); + return dr.transform_async(); + } } -/** @import { InputType } from "../index.js" */ -/** @import { ParametersCURE } from "./index.js" */ +/** @import {InputType} from "../index.js" */ +/** @import {ParametersSMACOF} from "./index.js" */ /** - * CURE (Clustering Using REpresentatives) + * Metric Multidimensional Scaling (MDS) via SMACOF. * - * An efficient clustering algorithm for large databases that is robust to outliers - * and identifies clusters with non-spherical shapes and wide variances in size. + * SMACOF (Scaling by Majorizing a Complicated Function) is an iterative majorization + * algorithm for solving metric multidimensional scaling problems, which aims to + * minimize the stress function. * * @class - * @extends Clustering - * @category Clustering + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction + * @see {@link MDS} for the classical approach. */ -class CURE extends Clustering { - /** @type {number} */ - _K; - /** @type {number} */ - _num_representatives; - /** @type {number} */ - _shrink_factor; - /** - * @private - * @type {CURECluster[]} - */ - _clusters = []; - /** @type {number[]} */ - _cluster_ids = []; - - /** - * @param {InputType} points - * @param {Partial} parameters - */ - constructor(points, parameters = {}) { - super( - points, - /** @type {ParametersCURE} */ ( - Object.assign( - { K: 2, num_representatives: 5, shrink_factor: 0.5, metric: euclidean, seed: 1212 }, - parameters, - ) - ), - ); - - this._K = this._parameters.K ?? 2; - this._num_representatives = this._parameters.num_representatives ?? 5; - this._shrink_factor = this._parameters.shrink_factor ?? 0.5; - - // Initialize clusters - this._initialize_clusters(); - // Run CURE algorithm - this._cure(); - } - - /** - * Initialize each point as its own cluster - * @private - */ - _initialize_clusters() { - const N = this._N; - //const D = this._D; - this._clusters = []; +class SMACOF extends DR { + /** + * SMACOF for MDS. + * + * @param {T} X - The high-dimensional data or precomputed distance matrix. + * @param {Partial} [parameters] - Object containing parameterization. + */ + constructor(X, parameters = {}) { + super(X, { d: 2, metric: euclidean, seed: 1212, iterations: 300, epsilon: 1e-4 }, parameters); + } - for (let i = 0; i < N; ++i) { - const point = this._matrix.row(i); - const centroid = new Float64Array(point); - // For single point, representative is the point itself - const representatives = [new Float64Array(point)]; - - this._clusters.push(new CURECluster([i], centroid, representatives)); - } - } - - /** - * Compute distance between two clusters using representative points - * @private - * @param {CURECluster} cluster1 - * @param {CURECluster} cluster2 - * @returns {number} - */ - _cluster_distance(cluster1, cluster2) { - const reps1 = cluster1.representatives; - const reps2 = cluster2.representatives; - const metric = this._parameters.metric; - - let min_dist = Infinity; - for (const r1 of reps1) { - for (const r2 of reps2) { - const dist = metric(r1, r2); - if (dist < min_dist) { - min_dist = dist; - } - } - } - return min_dist; - } - - /** - * Find the closest pair of clusters - * @private - * @returns {[number, number, number]} [index1, index2, distance] - */ - _find_closest_clusters() { - let min_dist = Infinity; - let min_i = 0; - let min_j = 1; - - for (let i = 0; i < this._clusters.length; ++i) { - for (let j = i + 1; j < this._clusters.length; ++j) { - const dist = this._cluster_distance(this._clusters[i], this._clusters[j]); - if (dist < min_dist) { - min_dist = dist; - min_i = i; - min_j = j; - } - } - } - - return [min_i, min_j, min_dist]; - } - - /** - * Merge two clusters - * @private - * @param {CURECluster} cluster1 - * @param {CURECluster} cluster2 - * @returns {CURECluster} - */ - _merge_clusters(cluster1, cluster2) { - // Merge indices - const merged_indices = [...cluster1.indices, ...cluster2.indices]; - - // Calculate new centroid - const size1 = cluster1.indices.length; - const size2 = cluster2.indices.length; - const total_size = size1 + size2; - const D = this._D; - const new_centroid = new Float64Array(D); - - for (let d = 0; d < D; ++d) { - new_centroid[d] = (size1 * cluster1.centroid[d] + size2 * cluster2.centroid[d]) / total_size; - } - - // Collect all points from both clusters - /** @type {{index: number, point: Float64Array}[]} */ - const all_points = []; - for (const idx of cluster1.indices) { - all_points.push({ index: idx, point: this._matrix.row(idx) }); - } - for (const idx of cluster2.indices) { - all_points.push({ index: idx, point: this._matrix.row(idx) }); - } - - // Select representative points - pick points farthest from centroid - const num_reps = Math.min(this._num_representatives, all_points.length); - const metric = this._parameters.metric; - - // Calculate distances from centroid for all points - const distances = all_points.map(({ point }) => metric(point, new_centroid)); - - // Select num_reps points with maximum distance (farthest from centroid) - const selected_indices = []; - const used = new Set(); - - for (let r = 0; r < num_reps; ++r) { - let max_dist = -1; - let max_idx = -1; - - for (let i = 0; i < distances.length; ++i) { - if (!used.has(i) && distances[i] > max_dist) { - max_dist = distances[i]; - max_idx = i; - } - } - - if (max_idx >= 0) { - used.add(max_idx); - selected_indices.push(max_idx); - } - } - - // Shrink representative points toward centroid - const new_representatives = selected_indices.map((idx) => { - const point = all_points[idx].point; - const shrunk = new Float64Array(D); - const alpha = this._shrink_factor; - - for (let d = 0; d < D; ++d) { - shrunk[d] = point[d] + alpha * (new_centroid[d] - point[d]); - } - - return shrunk; - }); - - return new CURECluster(merged_indices, new_centroid, new_representatives); - } - - /** - * Run CURE clustering algorithm - * @private - */ - _cure() { - // Merge clusters until we have K clusters - while (this._clusters.length > this._K) { - const [i, j] = this._find_closest_clusters(); - - // Merge clusters i and j - const merged = this._merge_clusters(this._clusters[i], this._clusters[j]); - - // Remove the old clusters and add the merged one - // Remove larger index first to maintain correct indices - // min_i < min_j is always true from _find_closest_clusters - this._clusters.splice(j, 1); - this._clusters.splice(i, 1); - - this._clusters.push(merged); - } - - // Build cluster list for get_cluster_list - this._build_cluster_ids(); - } - - /** - * Build the cluster list (point -> cluster assignment) - * @private - */ - _build_cluster_ids() { - const N = this._N; - this._cluster_ids = new Array(N).fill(-1); - - for (let c = 0; c < this._clusters.length; ++c) { - for (const idx of this._clusters[c].indices) { - this._cluster_ids[idx] = c; - } - } - } + /** + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + *generator() { + this.check_init(); + const X = this.X; + const rows = this._N; + const d = /** @type {number} */ (this.parameter("d")); + const metric = /** @type {typeof euclidean | "precomputed"} */ (this.parameter("metric")); + const iterations = /** @type {number} */ (this.parameter("iterations")); + const epsilon = /** @type {number} */ (this.parameter("epsilon")); + + const target_distances = metric === "precomputed" ? X : distance_matrix(X, metric); + + let Z = new Matrix(rows, d, () => (this._randomizer.random - 0.5) * 2); + + // Center Z + for (let j = 0; j < d; ++j) { + const col = Z.col(j); + const mean = col.reduce((a, b) => a + b, 0) / rows; + for (let i = 0; i < rows; ++i) { + Z.sub_entry(i, j, mean); + } + } - /** - * @returns {number[][]} - */ - get_clusters() { - return this._clusters.map((cluster) => cluster.indices); - } - - /** - * @returns {number[]} - */ - get_cluster_list() { - return this._cluster_ids; - } -} + this.Y = /** @type {Matrix} */ (Z); // Initial state -/** - * @private - * Represents a cluster in CURE algorithm - */ -class CURECluster { - /** - * @param {number[]} indices - Indices of points in the cluster - * @param {Float64Array} centroid - Centroid of the cluster - * @param {Float64Array[]} representatives - Representative points (shrunk toward centroid) - */ - constructor(indices, centroid, representatives) { - /** @type {number[]} */ - this.indices = indices; - /** @type {Float64Array} */ - this.centroid = centroid; - /** @type {Float64Array[]} */ - this.representatives = representatives; - } + let prev_stress = Infinity; + + if (!(iterations > 0)) { + yield this.projection; + return this.projection; + } + + for (let iter = 0; iter < iterations; ++iter) { + const B = new Matrix(rows, rows, 0); + + for (let i = 0; i < rows; ++i) { + let bii = 0; + const z_i = Z.row(i); + for (let j = 0; j < rows; ++j) { + if (i === j) continue; + const z_j = Z.row(j); + const dist_Z = euclidean(z_i, z_j); + const dist_target = target_distances.entry(i, j); + + let bij = 0; + if (dist_Z > 1e-12) { + bij = -dist_target / dist_Z; + } + B.set_entry(i, j, bij); + bii -= bij; + } + B.set_entry(i, i, bii); + } + + // Z_new = 1/N * B(Z) * Z + const Z_new = B.dot(Z)._apply(rows, (val, n) => val / n); + + this.Y = /** @type {Matrix} */ (Z_new); + Z = /** @type {Matrix} */ (Z_new); + + // Calculate stress + let stress_num = 0; + let stress_den = 0; + for (let i = 0; i < rows; ++i) { + const z_i = Z.row(i); + for (let j = i + 1; j < rows; ++j) { + const z_j = Z.row(j); + const dist_Y = euclidean(z_i, z_j); + const diff = target_distances.entry(i, j) - dist_Y; + stress_num += diff * diff; + stress_den += target_distances.entry(i, j) ** 2; + } + } + const current_stress = Math.sqrt(stress_num / Math.max(stress_den, 1e-12)); + + yield this.projection; + + if (Math.abs(prev_stress - current_stress) < epsilon) { + break; + } + prev_stress = current_stress; + } + return this.projection; + } + + /** + * @returns {T} + */ + transform() { + const gen = this.generator(); + let res = /** @type {T} */ (this.X); + for (const step of gen) { + res = step; + } + return res; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X, parameters) { + const dr = new SMACOF(X, parameters); + return dr.transform(); + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new SMACOF(X, parameters); + yield* dr.generator(); + return dr.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new SMACOF(X, parameters); + return dr.transform_async(); + } } -/** @import { InputType } from "../index.js" */ -/** @import { ParametersHierarchicalClustering } from "./index.js" */ +/** @import {InputType} from "../index.js" */ +/** @import {ParametersISOMAP} from "./index.js" */ +/** @import {EigenArgs} from "../linear_algebra/index.js" */ /** - * Hierarchical Clustering + * Isomap (Isometric Mapping) * - * A bottom-up approach (agglomerative) to clustering that builds a tree of clusters (dendrogram). - * Supports different linkage criteria: single, complete, and average. + * A nonlinear dimensionality reduction algorithm that uses geodesic distances + * between points on a manifold to perform embedding. It builds a neighborhood + * graph and uses MDS on the shortest-path distances. * * @class - * @extends Clustering - * @category Clustering + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction + * @see {@link LLE} for another nonlinear alternative */ -class HierarchicalClustering extends Clustering { - /** @type {Cluster | null} */ - root = null; - - /** - * @param {InputType} points - Data or distance matrix if metric is 'precomputed' - * @param {Partial} parameters - */ - constructor(points, parameters = {}) { - super( - points, - /** @type {ParametersHierarchicalClustering} */ ( - Object.assign({ linkage: "complete", metric: euclidean }, parameters) - ), - ); - this._id = 0; - if ( - this._parameters.metric === "precomputed" && - this._matrix.shape[0] !== this._matrix.shape[1] - ) { - throw new Error("If metric is 'precomputed', then matrix has to be square!"); - } - - const metric = this._parameters.metric; - const A = this._matrix; - const N = this._N; - this._d_min = new Float64Array(N); - const d_min = this._d_min; - let distance_matrix; - if (metric !== "precomputed") { - distance_matrix = new Matrix(N, N, Infinity); - for (let i = 0; i < N; ++i) { - distance_matrix.set_entry(i, i, 0); - d_min[i] = i; // temporary - const Ai = A.row(i); - for (let j = i + 1; j < N; ++j) { - const dist = metric(Ai, A.row(j)); - distance_matrix.set_entry(i, j, dist); - distance_matrix.set_entry(j, i, dist); - } - } - for (let i = 0; i < N; i++) { - let min_j = 0; - let min_d = Infinity; - for (let j = 0; j < N; j++) { - if (i === j) continue; - const d = distance_matrix.entry(i, j); - if (d < min_d) { - min_d = d; - min_j = j; - } - } - d_min[i] = min_j; - } - } else { - distance_matrix = this._matrix.clone(); - for (let i = 0; i < N; ++i) { - distance_matrix.set_entry(i, i, 0); - d_min[i] = i === 0 ? 1 : 0; - for (let j = 0; j < N; ++j) { - if (i === j) continue; - if (distance_matrix.entry(i, d_min[i]) > distance_matrix.entry(i, j)) { - d_min[i] = j; - } - } - } - } - this._distance_matrix = distance_matrix; - this._clusters = new Array(N); - const clusters = this._clusters; - this._c_size = new Uint16Array(N); - const c_size = this._c_size; - for (let i = 0; i < N; ++i) { - clusters[i] = []; - clusters[i][0] = new Cluster(this._id++, null, null, 0, A.row(i), i, 1, 0); - c_size[i] = 1; - } - const D = this._distance_matrix; - const linkage = this._parameters.linkage; - const p_max = N - 1; - for (let p = 0; p < p_max; ++p) { - let c1 = -1; - let min_dist = Infinity; - for (let i = 0; i < N; ++i) { - if (D.entry(i, i) === Infinity) continue; - const dist = D.entry(i, d_min[i]); - if (dist < min_dist) { - min_dist = dist; - c1 = i; - } - } - if (c1 === -1) break; - - const c2 = d_min[c1]; - const c1_cluster = clusters[c1][0]; - const c2_cluster = clusters[c2][0]; - const c1_cluster_indices = c1_cluster.isLeaf ? [c1_cluster.index] : c1_cluster.index; - const c2_cluster_indices = c2_cluster.isLeaf ? [c2_cluster.index] : c2_cluster.index; - const indices = c1_cluster_indices.concat(c2_cluster_indices); - const new_cluster = new Cluster( - this._id++, - c1_cluster, - c2_cluster, - D.entry(c1, c2), - null, - indices, - ); - c1_cluster.parent = new_cluster; - c2_cluster.parent = new_cluster; - clusters[c1].unshift(new_cluster); - - const size1 = c_size[c1]; - const size2 = c_size[c2]; - c_size[c1] += size2; - - for (let j = 0; j < N; ++j) { - if (j === c1 || j === c2 || D.entry(j, j) === Infinity) continue; - const D_c1_j = D.entry(c1, j); - const D_c2_j = D.entry(c2, j); - let value; - switch (linkage) { - case "single": - value = Math.min(D_c1_j, D_c2_j); - break; - case "complete": - value = Math.max(D_c1_j, D_c2_j); - break; - case "average": - value = (size1 * D_c1_j + size2 * D_c2_j) / (size1 + size2); - break; +class ISOMAP extends DR { + /** + * Isometric feature mapping (ISOMAP). + * + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + * @see {@link https://doi.org/10.1126/science.290.5500.2319} + */ + constructor(X, parameters = {}) { + /** @type {ParametersISOMAP} */ + const defaults = { + neighbors: -Infinity, + d: 2, + metric: euclidean, + seed: 1212, + project: "MDS", + eig_args: {}, + }; + super(X, defaults, parameters); + + this.defaults = defaults; + + if (this._parameters.neighbors === -Infinity) { + this.parameter("neighbors", Math.min(Math.max(Math.floor(this.X.shape[0] / 10), 2), this._N - 1)); } - D.set_entry(j, c1, value); - D.set_entry(c1, j, value); - } - - D.set_entry(c2, c2, Infinity); - for (let i = 0; i < N; ++i) { - D.set_entry(i, c2, Infinity); - D.set_entry(c2, i, Infinity); - } - - // Update d_min for all rows - for (let i = 0; i < N; i++) { - if (D.entry(i, i) === Infinity) continue; - if (d_min[i] === c1 || d_min[i] === c2 || i === c1) { - let min_j = 0; - let min_d = Infinity; - for (let j = 0; j < N; j++) { - if (i === j || D.entry(j, j) === Infinity) continue; - const d = D.entry(i, j); - if (d < min_d) { - min_d = d; - min_j = j; - } - } - d_min[i] = min_j; - } else { - if (D.entry(i, c1) < D.entry(i, d_min[i])) { - d_min[i] = c1; - } - } - } - - this.root = new_cluster; - } - } - - /** - * @param {number} value - Value where to cut the tree. - * @param {"distance" | "depth"} [type="distance"] - Type of value. Default is `"distance"` - * @returns {Cluster[][]} - Array of clusters with the indices of the rows in given points. - */ - get_clusters_raw(value, type = "distance") { - /** @type {Cluster[][]} */ - const clusters = []; - /** @type {(d: {dist: number, depth: number}) => number} */ - let accessor; - switch (type) { - case "distance": - accessor = (d) => d.dist; - break; - case "depth": - accessor = (d) => d.depth; - break; - default: - throw new Error("invalid type"); - } - this._traverse(/** @type {Cluster} */ (this.root), accessor, value, clusters); - return clusters; - } - - /** - * @param {number} value - Value where to cut the tree. - * @param {"distance" | "depth"} [type="distance"] - Type of value. Default is `"distance"` - * @returns {number[][]} - Array of clusters with the indices of the rows in given points. - */ - get_clusters(value, type = "distance") { - /** @type {Cluster[][]} */ - const clusters = []; - /** @type {(d: {dist: number, depth: number}) => number} */ - let accessor; - switch (type) { - case "distance": - accessor = (d) => d.dist; - break; - case "depth": - accessor = (d) => d.depth; - break; - default: - throw new Error("invalid type"); - } - if (this.root) this._traverse(this.root, accessor, value, clusters); - return clusters.map((cluster) => cluster.map((d) => d.index)); - } - - /** - * @param {number} value - Value where to cut the tree. - * @param {"distance" | "depth"} [type="distance"] - Type of value. Default is `"distance"` - * @returns {number[]} - Array of clusters with the indices of the rows in given points. - */ - get_cluster_list(value, type = "distance") { - const clusters = this.get_clusters(value, type); - /** @type {number[]} */ - const list = new Array(this._N).fill(0); - for (let i = 0; i < clusters.length; ++i) { - const cluster = clusters[i]; - for (let j = 0; j < cluster.length; ++j) { - const index = cluster[j]; - list[index] = i; - } - } - return list; - } - - /** - * @private - * @param {Cluster} node - * @param {(d: {dist: number, depth: number}) => number} f - * @param {number} value - * @param {Cluster[][]} result - */ - _traverse(node, f, value, result) { - if (f(node) <= value) { - result.push(node.leaves()); - } else { - if (node.left) this._traverse(node.left, f, value, result); - if (node.right) this._traverse(node.right, f, value, result); - } - } -} -/** @private */ -class Cluster { - /**@type {number} */ - size; - /**@type {number} */ - depth; - /**@type {Cluster | null} */ - parent; - - /** - * - * @param {number} id - * @param {Cluster?} left - * @param {Cluster?} right - * @param {number} dist - * @param {Float64Array?} centroid - * @param {number} index - * @param {number} [size] - * @param {number} [depth] - */ - constructor(id, left, right, dist, centroid, index, size, depth) { - this.id = id; - this.left = left; - this.right = right; - this.dist = dist; - this.index = index; - if (size) { - this.size = size; - } else { - if (!left || !right) throw new Error("If size is not given, left & right cannot be null!"); - this.size = left.size + right.size; + const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); + if (!Object.hasOwn(eig_args, "seed")) { + eig_args.seed = this._randomizer; + } } - if (depth !== undefined) { - this.depth = depth; - } else { - if (!left || !right) throw new Error("If depth is not given, left & right cannot be null!"); - this.depth = Math.max(left.depth, right.depth) + 1; + /** + * Computes the projection. + * + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + *generator() { + yield this.transform(); + return this.projection; } - if (centroid !== undefined && centroid !== null) { - this.centroid = centroid; - } else { - if (!left || !right) - throw new Error("If centroid is not given, left & right cannot be null!"); - - this.centroid = this._calculate_centroid(left, right); - } - - this.parent = null; - } - - /** - * - * @param {Cluster} left - * @param {Cluster} right - * @returns {Float64Array} - */ - _calculate_centroid(left, right) { - const l_size = left.size; - const r_size = right.size; - const l_centroid = left.centroid; - const r_centroid = right.centroid; - const size = this.size; - const n = left.centroid.length; - const new_centroid = new Float64Array(n); - for (let i = 0; i < n; ++i) { - new_centroid[i] = (l_size * l_centroid[i] + r_size * r_centroid[i]) / size; - } - return new_centroid; - } - - get isLeaf() { - return this.depth === 0; - } - - /** - * - * @returns {Cluster[]} - */ - leaves() { - if (this.isLeaf) return [this]; - const left = this.left; - const right = this.right; - return (left ? (left.isLeaf ? [left] : left.leaves()) : []).concat( - right ? (right.isLeaf ? [right] : right.leaves()) : [], - ); - } - - /** - * - * @returns {Cluster[]} - */ - descendants() { - if (this.isLeaf) return [this]; - const left_descendants = this.left ? this.left.descendants() : []; - const right_descendants = this.right ? this.right.descendants() : []; - return left_descendants.concat(right_descendants).concat([this]); - } -} + /** + * @returns {T} + */ + transform() { + this.check_init(); + const X = this.X; + const rows = this._N; + const d = /** @type {number} */ (this.parameter("d")); + const metric = /** @type {typeof euclidean} */ (this.parameter("metric")); + const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); + const neighbors = /** @type {number} */ (this.parameter("neighbors")); + // TODO: make knn extern and parameter for constructor or transform? + const D = new Matrix(rows, rows, 0); + D.shape = [rows, rows, (i, j) => (i <= j ? metric(X.row(i), X.row(j)) : D.entry(j, i))]; + + /** @type {{ index: number; distance: number }[][]} */ + const kNearestNeighbors = []; + const tree = new BallTree(X.to2dArray(), { + metric, + seed: /** @type {number} */ (this.parameter("seed")), + }); + for (let i = 0; i < rows; ++i) { + // BallTree search returns elements including the queried point itself (at distance 0). + // Request neighbors + 1 and slice off the first one (which should be the query point). + const neighborsList = tree.search_by_index(i, neighbors + 1); + kNearestNeighbors.push( + neighborsList.slice(1).map((n) => ({ + index: n.index, + distance: n.distance, + })), + ); + } -/** - * @template T - * @typedef {Object} DisjointSetPayload - * @property {T} parent - * @property {Set} children - * @property {number} size - */ + // ISOMAP requires an undirected/symmetric nearest neighbor graph. + // If i is a nearest neighbor of j, then j should be connected to i as well. + for (let i = 0; i < rows; ++i) { + for (const neighbor of kNearestNeighbors[i]) { + const j = neighbor.index; + const d = neighbor.distance; + const reciprocal_edge = kNearestNeighbors[j].find((n) => n.index === i); + if (!reciprocal_edge) { + kNearestNeighbors[j].push({ index: i, distance: d }); + } + } + } -/** - * @template T - * @class - * @category Data Structures - * @see {@link https://en.wikipedia.org/wiki/Disjoint-set_data_structure} - */ -class DisjointSet { - /** - * @param {T[]?} elements - */ - constructor(elements = null) { - /** - * @private - * @type {Map>} - */ - this._list = new Map(); - if (elements) { - for (const e of elements) { - this.make_set(e); - } - } - } - - /** - * @private - * @param {T} x - * @returns {DisjointSet} - */ - make_set(x) { - const list = this._list; - if (!list.has(x)) { - list.set(x, { parent: x, children: new Set([x]), size: 1 }); - } - return this; - } - - /** - * @param {T} x - * @returns - */ - find(x) { - const list = this._list; - const disjoint_set = list.get(x); - if (disjoint_set) { - if (disjoint_set.parent !== x) { - disjoint_set.children.add(x); - const new_parent = this.find(disjoint_set.parent); - if (!new_parent) throw new Error("should not happen!"); - disjoint_set.parent = new_parent; - return disjoint_set.parent; - } else { - return x; - } - } else { - return null; - } - } + /*D = dijkstra(kNearestNeighbors);*/ + // compute shortest paths using Dijkstra's algorithm + // TODO: make extern + const G = new Matrix(rows, rows, Infinity); - /** - * @param {T} x - * @param {T} y - * @returns - */ - union(x, y) { - let node_x = this.find(x); - let node_y = this.find(y); + for (let i = 0; i < rows; ++i) { + G.set_entry(i, i, 0); + const H = new Heap([{ index: i, distance: 0 }], (d) => d.distance, "min"); - if (!node_x || !node_y) throw new Error("x or y not found!"); + while (!H.empty) { + const item = H.pop(); + if (!item) break; - let disjoint_set_x = this._list.get(node_x); - let disjoint_set_y = this._list.get(node_y); + const u = item.element.index; + const dist_u = item.element.distance; - if (!disjoint_set_x || !disjoint_set_y) throw new Error("should not happen!"); + if (dist_u > G.entry(i, u)) continue; - if (node_x === node_y) return this; - if (disjoint_set_x.size < disjoint_set_y.size) { - [node_x, node_y] = [node_y, node_x]; - [disjoint_set_x, disjoint_set_y] = [disjoint_set_y, disjoint_set_x]; - } + for (const neighbor of kNearestNeighbors[u]) { + const v = neighbor.index; + const alt = dist_u + neighbor.distance; + if (alt < G.entry(i, v)) { + G.set_entry(i, v, alt); + H.push({ index: v, distance: alt }); + } + } + } + } - disjoint_set_y.parent = node_x; - // keep track of children - disjoint_set_y.children.forEach(disjoint_set_x.children.add, disjoint_set_x.children); - disjoint_set_x.size += disjoint_set_y.size; + let max_val = 0; + for (let i = 0; i < rows; i++) { + for (let j = 0; j < rows; j++) { + const val = G.entry(i, j); + if (val !== Infinity && val > max_val) max_val = val; + } + } + const big_val = max_val * 10; - return this; - } + const project = /** @type {"MDS" | "SMACOF"} */ (this.parameter("project")); - /** @param {T} x */ - get_children(x) { - const node = this._list.get(x); - if (node) { - return node.children; - } else { - return null; + if (project === "SMACOF") { + // Apply SMACOF metric MDS to the distance matrix directly + const D_matrix = new Matrix(rows, rows, (i, j) => { + const val = G.entry(i, j); + return val === Infinity ? big_val : val; + }); + const smacof = new SMACOF(D_matrix, { + metric: "precomputed", + d, + seed: this.parameter("seed"), + }); + smacof.transform(); + this.Y = smacof.Y; + } else { + // "MDS" (Classical MDS) via Eigendecomposition of double-centered squared distance matrix + const D_sq = new Matrix(rows, rows, (i, j) => { + let val = G.entry(i, j); + if (val === Infinity) val = big_val; + return val * val; + }); + + const ai_ = D_sq.meanCols(); + const a_j = D_sq.meanRows(); + const a__ = D_sq.mean(); + const B = new Matrix(rows, rows, (i, j) => -0.5 * (D_sq.entry(i, j) - ai_[i] - a_j[j] + a__)); + + // compute d eigenvectors + const { eigenvectors: V } = simultaneous_poweriteration(B, d, eig_args); + this.Y = Matrix.from(V).transpose(); + } + // return embedding + return this.projection; } - } -} -/** @import { Comparator } from "./index.js" */ + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X, parameters) { + const dr = new ISOMAP(X, parameters); + return dr.transform(); + } -/** - * @template T - * @class - * @category Data Structures - */ -class Heap { - /** @type {{ element: T; value: number }[]} */ - _container; - - /** @type {Comparator} */ - _comparator; - - /** - * A heap is a datastructure holding its elements in a specific way, so that the top element would be the first - * entry of an ordered list. - * - * @param {T[]?} elements - Contains the elements for the Heap. `elements` can be null. - * @param {(d: T) => number} accessor - Function returns the value of the element. - * @param {"min" | "max" | Comparator} [comparator="min"] - Function returning true or false - * defining the wished order of the Heap, or String for predefined function. ("min" for a Min-Heap, "max" for a - * Max_heap). Default is `"min"` - * @see {@link https://en.wikipedia.org/wiki/Binary_heap} - */ - constructor(elements = null, accessor, comparator = "min") { - /** @type {(d: T) => number} */ - this._accessor = accessor; - this._container = []; - if (comparator === "min") { - this._comparator = (a, b) => a < b; - } else if (comparator === "max") { - this._comparator = (a, b) => a > b; - } else { - this._comparator = comparator; - } - if (elements) { - this._container = []; - for (const e of elements) { - this._container.push({ - element: e, - value: accessor(e), - }); - } - for (let i = Math.floor(elements.length / 2 - 1); i >= 0; --i) { - this._heapify_down(i); - } - } - } - - /** - * Creates a Heap from an Array - * - * @template T - * @param {T[]} elements - Contains the elements for the Heap. - * @param {(d: T) => number} accessor - Function returns the value of the element. - * @param {"min" | "max" | Comparator} [comparator="min"] - Function returning true or false - * defining the wished order of the Heap, or String for predefined function. ("min" for a Min-Heap, "max" for a - * Max_heap). Default is `"min"` - * @returns {Heap} - */ - static heapify(elements, accessor, comparator = "min") { - const heap = new Heap(null, accessor, comparator); - const container = heap._container; - for (const e of elements) { - container.push({ - element: e, - value: accessor(e), - }); - } - for (let i = Math.floor(elements.length / 2 - 1); i >= 0; --i) { - heap._heapify_down(i); - } - return heap; - } - - /** - * Swaps elements of container array. - * - * @private - * @param {number} index_a - * @param {number} index_b - */ - _swap(index_a, index_b) { - const container = this._container; - [container[index_b], container[index_a]] = [container[index_a], container[index_b]]; - return; - } - - /** @private */ - _heapify_up() { - const container = this._container; - let index = container.length - 1; - while (index > 0) { - const parentIndex = Math.floor((index - 1) / 2); - if (!this._comparator(container[index].value, container[parentIndex].value)) { - break; - } else { - this._swap(parentIndex, index); - index = parentIndex; - } - } - } - - /** - * Pushes the element to the heap. - * - * @param {T} element - * @returns {Heap} - */ - push(element) { - const value = this._accessor(element); - //const node = new Node(element, value); - const node = { element: element, value: value }; - this._container.push(node); - this._heapify_up(); - return this; - } - - /** - * @private - * @param {Number} [start_index=0] Default is `0` - */ - _heapify_down(start_index = 0) { - const container = this._container; - const comparator = this._comparator; - const length = container.length; - const left = 2 * start_index + 1; - const right = 2 * start_index + 2; - let index = start_index; - if (index >= length) throw "index higher than length"; - if (left < length && comparator(container[left].value, container[index].value)) { - index = left; - } - if (right < length && comparator(container[right].value, container[index].value)) { - index = right; - } - if (index !== start_index) { - this._swap(start_index, index); - this._heapify_down(index); - } - } - - /** - * Removes and returns the top entry of the heap. - * - * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by - * `accessor`}). - */ - pop() { - const container = this._container; - if (container.length === 0) { - return null; - } else if (container.length === 1) { - const item = container.pop(); - if (!item) throw new Error("Cannot happen!"); - return item; - } - this._swap(0, container.length - 1); - const item = container.pop(); - this._heapify_down(); - return item ?? null; - } - - /** - * Returns the top entry of the heap without removing it. - * - * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by - * `accessor`). - */ - get first() { - return this._container.length > 0 ? this._container[0] : null; - } - - /** - * Yields the raw data - * - * @yields {T} Object consists of the element and its value (computed by `accessor`}). - */ - *iterate() { - for (let i = 0, n = this._container.length; i < n; ++i) { - yield this._container[i].element; - } - } - - /** - * Returns the heap as ordered array. - * - * @returns {T[]} Array consisting the elements ordered by `comparator`. - */ - toArray() { - return this._container - .sort((a, b) => (this._comparator(a.value, b.value) ? -1 : 1)) - .map((d) => d.element); - } - - /** - * Returns elements of container array. - * - * @returns {T[]} Array consisting the elements. - */ - data() { - return this._container.map((d) => d.element); - } - - /** - * Returns the container array. - * - * @returns {{ element: T; value: number }[]} The container array. - */ - raw_data() { - return this._container; - } - - /** - * The size of the heap. - * - * @returns {number} - */ - get length() { - return this._container.length; - } - - /** - * Returns false if the the heap has entries, true if the heap has no entries. - * - * @returns {boolean} - */ - get empty() { - return this.length === 0; - } + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new ISOMAP(X, parameters); + yield* dr.generator(); + return dr.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new ISOMAP(X, parameters); + return dr.transform_async(); + } } -/** @import { InputType } from "../index.js" */ -/** @import { ParametersKMeans } from "./index.js" */ +/** @import {InputType} from "../index.js" */ +/** @import {ParametersLDA} from "./index.js" */ +/** @import {EigenArgs} from "../linear_algebra/index.js" */ + /** - * K-Means Clustering + * Linear Discriminant Analysis (LDA) * - * A popular clustering algorithm that partitions data into K clusters where each point - * belongs to the cluster with the nearest mean (centroid). + * A supervised dimensionality reduction technique that finds the axes that + * maximize the separation between multiple classes. * * @class - * @extends Clustering - * @category Clustering - * @see {@link KMedoids} for a more robust alternative - * - * @example - * import * as druid from "@saehrimnir/druidjs"; - * - * const points = [[1, 1], [1.5, 1.5], [5, 5], [5.5, 5.5]]; - * const kmeans = new druid.KMeans(points, { K: 2 }); - * - * const clusters = kmeans.get_cluster_list(); // [0, 0, 1, 1] - * const centroids = kmeans.centroids; // center points + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction */ -class KMeans extends Clustering { - /** - * @param {InputType} points - * @param {Partial} parameters - */ - constructor(points, parameters = {}) { - super( - points, - /** @type {ParametersKMeans} */ ( - Object.assign({ K: 4, metric: euclidean, seed: 1212 }, parameters) - ), - ); - - const K = this._parameters.K; - const seed = parameters.seed; - - // Convert points to Matrix if needed - if (points instanceof Matrix) { - this._matrix = points; - } else { - this._matrix = Matrix.from(points); +class LDA extends DR { + /** + * Linear Discriminant Analysis. + * + * @param {T} X - The high-dimensional data. + * @param {Partial & { labels: any[] | Float64Array }} parameters - Object containing parameterization of the DR method. + * @see {@link https://onlinelibrary.wiley.com/doi/10.1111/j.1469-1809.1936.tb02137.x} + */ + constructor(X, parameters) { + super(X, { labels: parameters.labels, d: 2, seed: 1212, eig_args: {} }, parameters); + const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); + if (!Object.hasOwn(eig_args, "seed")) { + eig_args.seed = this._randomizer; + } } - const [N, D] = this._matrix.shape; - this._N = N; - this._D = D; + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + *generator() { + yield this.transform(); + return this.projection; + } - this._K = K > N ? N : K; - this._randomizer = new Randomizer(seed); + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {T} - The projected data. + */ + transform() { + const X = this.X; + const [rows, cols] = X.shape; + const { d, labels, eig_args } = this._parameters; + if (labels === null || labels.length !== rows) { + throw new Error("LDA needs parameter label to every datapoint to work!"); + } - /** @type {number[]} */ - this._clusters = new Array(N).fill(0); - - this._cluster_centroids = parameters.initial_centroids - ? parameters.initial_centroids.map((c) => new Float64Array(c)) - : this._get_random_centroids(this._K); - let cluster_centroids = this._cluster_centroids; - let iterations = 0; - const max_iterations = 300; - let clusters_changed = true; - - while (clusters_changed && iterations < max_iterations) { - const iteration_result = this._iteration(cluster_centroids); - cluster_centroids = iteration_result.cluster_centroids; - clusters_changed = iteration_result.clusters_changed; - iterations++; - } - - this._cluster_centroids = cluster_centroids; - } - - /** @returns {number} The number of clusters */ - get k() { - return this._K; - } - - /** @returns {Float64Array[]} The cluster centroids */ - get centroids() { - return this._cluster_centroids; - } - - /** @returns {number[]} The cluster list */ - get_cluster_list() { - return this._clusters; - } - - /** @returns {number[][]} An Array of clusters with the indices of the points. */ - get_clusters() { - const K = this._K; - const clusters = this._clusters; - /** @type {number[][]} */ - const result = new Array(K).fill(0).map(() => []); - clusters.forEach((c, i) => { - if (c >= 0 && c < K) { - result[c].push(i); - } - }); - return result; - } - - /** - * @private - * @param {number[]} point_indices - * @param {number[]} candidates - * @returns {number} - */ - _furthest_point(point_indices, candidates) { - const A = this._matrix; - const metric = this._parameters.metric; - - if (point_indices.length === 0 || candidates.length === 0) { - return candidates[0] ?? 0; - } - - const H = Heap.heapify( - candidates, - (d) => { - const Ad = A.row(d); - let sum = 0; - for (let j = 0; j < point_indices.length; ++j) { - sum += metric(Ad, A.row(point_indices[j])); - } - return sum; - }, - "max", - ); - - const furthest = H.pop(); - if (!furthest) throw new Error("Should not happen!"); - - return furthest.element; - } - - /** - * @private - * @param {number} K - * @returns {Float64Array[]} - */ - _get_random_centroids(K) { - const N = this._N; - const randomizer = this._randomizer; - const A = this._matrix; - /** @type {Float64Array[]} */ - const cluster_centroids = new Array(K); - const indices = linspace(0, N - 1); - - // First centroid: random selection - const random_point = randomizer.random_int % N; - cluster_centroids[0] = A.row(random_point); - const init_points = [random_point]; - - const sample_size = Math.max(1, Math.floor((N - K) / K)); - - for (let i = 1; i < K; ++i) { - const remaining = indices.filter((d) => !init_points.includes(d)); - if (remaining.length === 0) break; - - const sample = randomizer.choice(remaining, Math.min(sample_size, remaining.length)); - const furthest_point = this._furthest_point(init_points, sample); - - init_points.push(furthest_point); - cluster_centroids[i] = A.row(furthest_point); - } - - return cluster_centroids; - } - - /** - * @private - * @param {Float64Array[]} cluster_centroids - * @returns {{ clusters_changed: boolean; cluster_centroids: Float64Array[] }} - */ - _iteration(cluster_centroids) { - const K = cluster_centroids.length; - const N = this._N; - const metric = this._parameters.metric; - const A = this._matrix; - const clusters = this._clusters; - let clusters_changed = false; - - // Find nearest cluster centroid for each point - for (let i = 0; i < N; ++i) { - const Ai = A.row(i); - let min_dist = Infinity; - let min_cluster = 0; - - for (let j = 0; j < K; ++j) { - const d = metric(cluster_centroids[j], Ai); - if (d < min_dist) { - min_dist = d; - min_cluster = j; - } - } - - if (clusters[i] !== min_cluster) { - clusters_changed = true; - clusters[i] = min_cluster; - } - } - - // Update cluster centroids - const new_centroids = this._compute_centroid(K); - - return { - clusters_changed: clusters_changed, - cluster_centroids: new_centroids, - }; - } - - /** - * @private - * @param {number} K - * @returns {Float64Array[]} - */ - _compute_centroid(K) { - const N = this._N; - const D = this._D; - const A = this._matrix; - const clusters = this._clusters; - - // Initialize new centroids and counters - /** @type {Float64Array[]} */ - const new_centroids = new Array(K); - const cluster_counter = new Array(K).fill(0); - - for (let i = 0; i < K; ++i) { - new_centroids[i] = new Float64Array(D); - } - - // Sum up all points in each cluster - for (let i = 0; i < N; ++i) { - const Ai = A.row(i); - const ci = clusters[i]; - if (ci >= 0 && ci < K) { - cluster_counter[ci]++; - const centroid = new_centroids[ci]; - for (let j = 0; j < D; ++j) { - centroid[j] += Ai[j]; + /** @type {Record} */ + const unique_labels = {}; + let label_id = 0; + labels.forEach((l, i) => { + if (l in unique_labels) { + unique_labels[l].count++; + unique_labels[l].rows.push(X.row(i)); + } else { + unique_labels[l] = { + id: label_id++, + count: 1, + rows: [X.row(i)], + }; + } + }); + + // create X_mean and vector means; + const X_mean = X.meanCols(); + const V_mean = new Matrix(label_id, cols); + for (const label in unique_labels) { + const V = Matrix.from(unique_labels[label].rows); + const v_mean = V.meanCols(); + for (let j = 0; j < cols; ++j) { + V_mean.set_entry(unique_labels[label].id, j, v_mean[j]); + } + } + // scatter_between + let S_b = new Matrix(cols, cols); + for (const label in unique_labels) { + const v = V_mean.row(unique_labels[label].id); + const m = Matrix.from([v]).sub(Matrix.from([X_mean])); + const N = unique_labels[label].count; + S_b = S_b.add(m.transDot(m).mult(N)); } - } - } - // Divide by count to get mean - for (let i = 0; i < K; ++i) { - const n = cluster_counter[i]; - if (n > 0) { - const centroid = new_centroids[i]; - for (let j = 0; j < D; ++j) { - centroid[j] /= n; + // scatter_within + let S_w = new Matrix(cols, cols); + for (const label in unique_labels) { + const v = V_mean.row(unique_labels[label].id); + const R = unique_labels[label].rows; + for (let i = 0, n = unique_labels[label].count; i < n; ++i) { + const row_v = Matrix.from([R[i]]).sub(Matrix.from([v])); + S_w = S_w.add(row_v.transDot(row_v)); + } } - } + + const { eigenvectors: EV } = simultaneous_poweriteration( + S_w.inverse().dot(S_b), + d || Math.min(cols, label_id - 1), + eig_args, + ); + const V = Matrix.from(EV).transpose(); + this.Y = X.dot(V); + + // return embedding + return this.projection; + } + + /** + * @template {InputType} T + * @template {{ seed?: number }} Para + * @param {T} X + * @param {Para} parameters + * @returns {T} + */ + static transform(X, parameters) { + // @ts-expect-error: LDA requires labels, but DR static transform doesn't + const dr = new LDA(X, parameters); + return dr.transform(); + } + + /** + * @template {InputType} T + * @template {{ seed?: number }} Para + * @param {T} X + * @param {Para} parameters + * @returns {Generator} + */ + static *generator(X, parameters) { + // @ts-expect-error: LDA requires labels, but DR static generator doesn't + const dr = new LDA(X, parameters); + yield* dr.generator(); + return dr.projection; } - return new_centroids; - } + /** + * @template {InputType} T + * @template {{ seed?: number }} Para + * @param {T} X + * @param {Para} parameters + * @returns {Promise} + */ + static async transform_async(X, parameters) { + // @ts-expect-error: LDA requires labels, but DR static transform doesn't + const dr = new LDA(X, parameters); + return dr.transform_async(); + } } /** @import {InputType} from "../index.js" */ -/** @import { ParametersKMedoids } from "./index.js" */ +/** @import {ParametersLLE} from "./index.js" */ +/** @import {EigenArgs} from "../linear_algebra/index.js" */ /** - * K-Medoids (PAM - Partitioning Around Medoids) + * Locally Linear Embedding (LLE) * - * A robust clustering algorithm similar to K-Means, but uses actual data points (medoids) - * as cluster centers and can work with any distance metric. + * A nonlinear dimensionality reduction technique that preserves local + * linear relationships between points. It represents each point as a linear + * combination of its neighbors. * * @class - * @extends Clustering - * @category Clustering - * @see {@link KMeans} for a faster but less robust alternative + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction + * @see {@link ISOMAP} for another nonlinear alternative */ -class KMedoids extends Clustering { - /** - * @param {InputType} points - Data matrix - * @param {Partial} parameters - * @see {@link https://link.springer.com/chapter/10.1007/978-3-030-32047-8_16} Faster k-Medoids Clustering: Improving the PAM, CLARA, and CLARANS Algorithms - */ - constructor(points, parameters = {}) { - super( - points, - Object.assign({ K: 4, max_iter: null, metric: euclidean, seed: 1212 }, parameters), - ); - this._A = this._matrix.to2dArray(); - let K = this._parameters.K; - const N = this._N; - this._max_iter = this._parameters.max_iter ?? 10 * Math.log10(N); - this._distance_matrix = new Matrix(N, N, "zeros"); - - if (K > N) { - this._parameters.K = K = N; - } - this._randomizer = new Randomizer(this._parameters.seed); - this._clusters = new Array(N).fill(-1); - this._cluster_medoids = this._get_random_medoids(K); - this._is_initialized = false; - } - - /** @returns {number[]} The cluster list */ - get_cluster_list() { - if (!this._is_initialized) { - this.get_clusters(); - } - return this._clusters; - } - - /** @returns {number[][]} - Array of clusters with the indices of the rows in given points. */ - get_clusters() { - const K = this._parameters.K; - const A = this._A; - const N = this._N; - if (!this._is_initialized) { - this.init(K, this._cluster_medoids); - } - /** @type {number[][]} */ - const result = new Array(K).fill(0).map(() => []); - for (let j = 0; j < N; j++) { - const nearest = this._nearest_medoid(A[j], j); - const cluster_idx = nearest.index_nearest; - result[cluster_idx].push(j); - this._clusters[j] = cluster_idx; +class LLE extends DR { + /** + * Locally Linear Embedding. + * + * @param {T} X - The high-dimensional data. + * @param {Partial} parameters - Object containing parameterization of the DR method. + * @see {@link https://doi.org/10.1126/science.290.5500.2323} + */ + constructor(X, parameters) { + super( + X, + { + neighbors: -Infinity, + d: 2, + metric: euclidean, + seed: 1212, + eig_args: {}, + }, + parameters, + ); + if (this._parameters.neighbors === -Infinity) { + this.parameter("neighbors", Math.min(Math.max(Math.floor(this._N / 10), 2), this._N - 1)); + } + + const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); + if (!Object.hasOwn(eig_args, "seed")) { + eig_args.seed = this._randomizer; + } } - return result; - } - - /** @returns {number} */ - get k() { - return this._parameters.K; - } - - /** @returns {number[]} */ - get medoids() { - return this.get_medoids(); - } - - /** @returns {number[]} */ - get_medoids() { - const K = this._parameters.K; - if (!this._is_initialized) { - this.init(K, this._cluster_medoids); - } - return this._cluster_medoids; - } - - async *generator() { - const max_iter = this._max_iter; - if (!this._is_initialized) { - this.get_clusters(); - } - yield this.get_clusters(); - let i = 0; - while (i < max_iter) { - const finish = this._iteration(); - this._update_clusters(); - yield this.get_clusters(); - if (finish) break; - i++; - } - } - - /** Algorithm 1. FastPAM1: Improved SWAP algorithm */ - /* _iteration_1() { - const A = this._A; - const N = this._N; - const K = this._K; - const medoids = this._cluster_medoids; - let DeltaTD = 0; - let m0 = null; - let x0 = null; - A.forEach((x_j, j) => { - if (medoids.findIndex(m => m === j) < 0) { - const nearest_medoid = this._nearest_medoid(x_j, j); - const d_j = nearest_medoid.distance_nearest; // distance to current medoid - const deltaTD = new Array(K).fill(-d_j); // change if making j a medoid - A.forEach((x_o, o) => { - // disance to new medoid - const d_oj = this._get_distance(o, j, x_o, x_j); - const { - "index_nearest": n, - "distance_nearest": d_n, - "distance_second": d_s, - } = this._nearest_medoid(x_o, o); - this._clusters[o] = n; // cached values - deltaTD[n] += Math.min(d_oj, d_s) - d_n; // loss change - if (d_oj < d_n) { // reassignment check - deltaTD.forEach((d_i, i) => { - if (n !== i) { - deltaTD[i] = d_i + d_oj - d_n; // update loss change - } - }); - } - }); - // choose best medoid i; - const i = deltaTD - .map((d, i) => [d, i]) - .sort((d1, d2) => d1[0] - d2[0])[0][1]; - const deltaTD_i = deltaTD[i]; - // store - if (deltaTD_i < DeltaTD) { - DeltaTD = deltaTD_i; - m0 = i; - x0 = j; + + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + *generator() { + yield this.transform(); + return this.projection; + } + + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {T} + */ + transform() { + const X = this.X; + const rows = this._N; + const cols = this._D; + const neighbors = /** @type {number} */ (this.parameter("neighbors")); + const d = /** @type {number} */ (this.parameter("d")); + const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); + const metric = /** @type {typeof euclidean} */ (this.parameter("metric")); + const nN = k_nearest_neighbors(X, neighbors, metric); + const O = new Matrix(neighbors, 1, 1); + const W = new Matrix(rows, rows); + + for (let row = 0; row < rows; ++row) { + const nN_row = nN[row]; + const Z = new Matrix(neighbors, cols, (i, j) => X.entry(nN_row[i].j, j) - X.entry(row, j)); + const C = Z.dotTrans(Z); + if (neighbors > cols) { + const C_trace = neumair_sum(C.diag()) / 1000; + for (let j = 0; j < neighbors; ++j) { + C.add_entry(j, j, C_trace); } } - }); - - if (DeltaTD >= 0) { - return true // break loop if DeltaTD >= 0 + // reconstruct; + let w = Matrix.solve_CG(C, O, this._randomizer); + w = w.divide(w.sum()); + for (let j = 0; j < neighbors; ++j) { + W.set_entry(row, nN_row[j].j, w.entry(j, 0)); + } } - // swap roles of medoid m and non-medoid x; - medoids[m0] = x0; - this._cluster_medoids = medoids; - return false - } */ + // comp embedding + const I = new Matrix(rows, rows, "identity"); + const IW = I.sub(W); + const M = IW.transDot(IW); + + // M is symmetric positive semi-definite. Smallest eigenvalue is 0 (ones vector). + // To find smallest eigenvalues of M, we can find largest of (C*I - M) + // Upper bound for max eigenvalue: Frobenius norm or sum of absolute values + const C = M.mean() * rows * 2; // Safe upper bound for a sparse-ish M in LLE + const CI_M = new Matrix(rows, rows, (i, j) => (i === j ? C : 0) - M.entry(i, j)); - /** FastPAM1: One best swap per iteration */ - _iteration() { - const A = this._A; - const K = this._parameters.K; - const medoids = this._cluster_medoids; - const N = this._N; - - // Precompute nearest and second nearest medoid for all points - const cache = new Array(N); - for (let i = 0; i < N; i++) { - cache[i] = this._nearest_medoid(A[i], i); - } - - let best_delta = 0; - let best_swap = null; // { m_idx: index in medoids, x_idx: index in A } - - // For each non-medoid point j, evaluate swapping it with each medoid i - const medoid_set = new Set(medoids); - for (let j = 0; j < N; j++) { - if (medoid_set.has(j)) continue; - - const x_j = A[j]; - const d_j = cache[j].distance_nearest; - - // deltaTD[i] will store the change in total distance if we swap medoid[i] with j - const deltaTD = new Array(K).fill(-d_j); - - for (let o = 0; o < N; o++) { - if (o === j) continue; - const dist_o_j = this._get_distance(o, j, A[o], x_j); - const { index_nearest: n, distance_nearest: d_n, distance_second: d_s } = cache[o]; - - // If o is assigned to the current medoid being swapped out (n) - deltaTD[n] += Math.min(dist_o_j, d_s) - d_n; - - // For all other medoids i != n, if j is closer to o than its current medoid - if (dist_o_j < d_n) { - for (let i = 0; i < K; i++) { - if (i !== n) { - deltaTD[i] += dist_o_j - d_n; - } - } - } - } - - // Find best medoid to swap with j - for (let i = 0; i < K; i++) { - if (deltaTD[i] < best_delta) { - best_delta = deltaTD[i]; - best_swap = { m_idx: i, x_idx: j }; - } - } - } - - if (best_swap && best_delta < 0) { - medoids[best_swap.m_idx] = best_swap.x_idx; - this._cluster_medoids = medoids; - return false; // not finished - } - - return true; // finished - } - - /** - * - * @param {number} i - * @param {number} j - * @param {Float64Array?} x_i - * @param {Float64Array?} x_j - * @returns - */ - _get_distance(i, j, x_i = null, x_j = null) { - if (i === j) return 0; - const D = this._distance_matrix; - const A = this._A; - const metric = this._parameters.metric; - let d_ij = D.entry(i, j); - if (d_ij === 0) { - d_ij = metric(x_i || A[i], x_j || A[j]); - D.set_entry(i, j, d_ij); - D.set_entry(j, i, d_ij); - } - return d_ij; - } - - /** - * - * @param {Float64Array} x_j - * @param {number} j - * @returns - */ - _nearest_medoid(x_j, j) { - const medoids = this._cluster_medoids; - const A = this._A; - if (medoids.length === 0) { - throw new Error("No medoids available. Initialization failed."); - } - - let d_n = Infinity; - let n = -1; - let d_s = Infinity; - let s = -1; - - for (let i = 0; i < medoids.length; i++) { - const m = medoids[i]; - const d = this._get_distance(j, m, x_j, A[m]); - if (d < d_n) { - d_s = d_n; - s = n; - d_n = d; - n = i; - } else if (d < d_s) { - d_s = d; - s = i; - } - } - - if (s === -1) s = n; - - return { - distance_nearest: d_n, - index_nearest: n, - distance_second: d_s, - index_second: s, - }; - } - - _update_clusters() { - const N = this._N; - const A = this._A; - for (let j = 0; j < N; j++) { - const nearest = this._nearest_medoid(A[j], j); - this._clusters[j] = nearest.index_nearest; - } - } - - /** - * Computes `K` clusters out of the `matrix`. - * @param {number} K - Number of clusters. - * @param {number[]} cluster_medoids - */ - init(K, cluster_medoids) { - if (!K) K = this._parameters.K; - if (!cluster_medoids) cluster_medoids = this._get_random_medoids(K); - this._cluster_medoids = cluster_medoids; - const max_iter = this._max_iter; - let finish = false; - let i = 0; - do { - finish = this._iteration(); - } while (!finish && ++i < max_iter); - this._update_clusters(); - this._is_initialized = true; - return this; - } - - /** - * Algorithm 3. FastPAM LAB: Linear Approximate BUILD initialization. - * - * @param {number} K - Number of clusters - * @returns {number[]} - */ - _get_random_medoids(K) { - const N = this._N; - const A = this._A; - const indices = linspace(0, N - 1); - const randomizer = this._randomizer; - const n = Math.min(N, 10 + Math.ceil(Math.sqrt(N))); - - // Handle case where K >= N - if (K >= N) { - return indices.slice(0, N); + const { eigenvectors: V } = simultaneous_poweriteration(CI_M, d + 1, eig_args); + // Skip the first eigenvector (the ones vector corresponding to eigenvalue C) + this.Y = Matrix.from(V.slice(1, 1 + d)).T; + + // return embedding + return this.projection; } - /** @type {number[]} */ - const medoids = []; - - // first medoid: select from a random sample of size n - let best_j = -1; - let min_td = Infinity; - let S = randomizer.choice(indices, n); - for (let j = 0; j < S.length; ++j) { - let td = 0; - const S_j = S[j]; - const x_j = A[S_j]; - for (let o = 0; o < S.length; ++o) { - if (o === j) continue; - td += this._get_distance(S_j, S[o], x_j, A[S[o]]); - } - if (td < min_td) { - min_td = td; - best_j = S_j; - } - } - medoids.push(best_j); - - // other medoids: greedy additive selection (Algorithm LAB) - for (let i = 1; i < K; ++i) { - let best_idx = -1; - let best_delta = Infinity; - - const remainingIndices = indices.filter((idx) => !medoids.includes(idx)); - if (remainingIndices.length === 0) break; - - S = randomizer.choice(remainingIndices, Math.min(n, remainingIndices.length)); - for (let j = 0; j < S.length; ++j) { - let deltaTD = 0; - const S_j = S[j]; - const x_j = A[S_j]; - - // Estimate TD reduction on the sample S - for (let o = 0; o < S.length; ++o) { - if (o === j) continue; - const S_o = S[o]; - const x_o = A[S_o]; - - // Closest distance to current medoids - let min_d_existing = Infinity; - for (let m = 0; m < medoids.length; m++) { - const d = this._get_distance(S_o, medoids[m], x_o, A[medoids[m]]); - if (d < min_d_existing) min_d_existing = d; - } - - const delta = this._get_distance(S_j, S_o, x_j, x_o) - min_d_existing; - if (delta < 0) { - deltaTD += delta; - } - } - - if (deltaTD < best_delta) { - best_delta = deltaTD; - best_idx = S_j; - } - } - if (best_idx !== -1) { - medoids.push(best_idx); - } - } - return medoids; - } + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {T} + */ + static transform(X, parameters) { + const dr = new LLE(X, parameters); + return dr.transform(); + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new LLE(X, parameters); + yield* dr.generator(); + return dr.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new LLE(X, parameters); + return dr.transform_async(); + } } -/** @import { ParametersMeanShift } from "./index.js" */ -/** @import { InputType } from "../index.js" */ +/** @import {InputType} from "../index.js" */ +/** @import {ParametersMDS} from "./index.js" */ +/** @import {EigenArgs} from "../linear_algebra/index.js" */ /** - * Mean Shift Clustering + * Classical Multidimensional Scaling (MDS) * - * A non-parametric clustering technique that does not require prior knowledge of the - * number of clusters. It identifies centers of density in the data. + * A linear dimensionality reduction technique that seeks to preserve the + * pairwise distances between points as much as possible in the lower-dimensional + * space. * * @class - * @extends Clustering - * @category Clustering - */ -class MeanShift extends Clustering { - /** @type {number} */ - _bandwidth; - /** @type {number} */ - _max_iter; - /** @type {number} */ - _tolerance; - /** @type {(dist: number) => number} */ - _kernel; - /** @type {Matrix} */ - _points; - /** @type {number[] | undefined} */ - _clusters; - /** @type {number[][] | undefined} */ - _cluster_list; - /** - * - * @param {InputType} points - * @param {Partial} parameters - */ - constructor(points, parameters = {}) { - super( - points, - /** @type {ParametersMeanShift} */ ( - Object.assign( - { seed: 1212, metric: euclidean, bandwidth: 0, kernel: "gaussian" }, - parameters, - ) - ), - ); - - // Ensure bandwidth is positive - this._bandwidth = parameters.bandwidth ?? this._compute_bandwidth(this._matrix); - this._max_iter = parameters.max_iter ?? Math.max(10, Math.floor(10 * Math.log10(this._N))); - this._tolerance = parameters.tolerance ?? 1e-3; - const kernel_param = parameters.kernel ?? "gaussian"; - // If kernel is a string, map to function - if (typeof kernel_param === "string") { - if (kernel_param === "flat") { - this._kernel = (dist) => (dist <= this._bandwidth ? 1 : 0); - } else { - // gaussian (default) - this._kernel = (dist) => Math.exp(-(dist * dist) / (2 * this._bandwidth * this._bandwidth)); - } - } else { - // custom function - this._kernel = kernel_param; - } - - // Copy points to a mutable matrix - this._points = this._matrix.clone(); - - this._mean_shift(); - this._assign_clusters(); - } - - // Helper to compute bandwidth if not provided - /** - * @param {Matrix} matrix - * @returns {number} - */ - _compute_bandwidth(matrix) { - const N = matrix.shape[0]; - //const D = matrix.shape[1]; - // Compute average pairwise distance - let totalDist = 0; - for (let i = 0; i < N; ++i) { - const row_i = matrix.row(i); - for (let j = i + 1; j < N; ++j) { - const row_j = matrix.row(j); - const dist = this._parameters.metric(row_i, row_j); - totalDist += dist; - } - } - const avgDist = totalDist / ((N * (N - 1)) / 2); - // Use a fraction of avgDist as bandwidth - return avgDist / 2; - } - - // Compute kernel weight - /** - * @param {number} dist - * @returns {number} - */ - _kernel_weight(dist) { - return this._kernel(dist); - } - - // Perform mean shift iterations - _mean_shift() { - const N = this._N; - const D = this._D; - const points = this._points; - const metric = this._parameters.metric; - //const bandwidth = this._bandwidth; - const kernel = this._kernel_weight.bind(this); - const tolerance = this._tolerance; - - for (let iter = 0; iter < this._max_iter; ++iter) { - let max_shift = 0; - // For each point compute shift - for (let i = 0; i < N; ++i) { - const row_i = points.row(i); - let sum_weights = 0; - const weighted_sum = new Float64Array(D); - for (let j = 0; j < N; ++j) { - const row_j = points.row(j); - const dist = metric(row_i, row_j); - const weight = kernel(dist); - sum_weights += weight; - for (let d = 0; d < D; ++d) { - weighted_sum[d] += weight * row_j[d]; - } - } - if (sum_weights === 0) { - // No neighbors within kernel, shift is zero - //const shift = new Float64Array(D); - // Compute shift magnitude - const shift_norm = Math.sqrt(weighted_sum.reduce((acc, v) => acc + v * v, 0)); - max_shift = Math.max(max_shift, shift_norm); - } else { - const shift = new Float64Array(D); - for (let d = 0; d < D; ++d) { - shift[d] = weighted_sum[d] / sum_weights - row_i[d]; - } - const shift_norm = Math.sqrt(shift.reduce((acc, v) => acc + v * v, 0)); - max_shift = Math.max(max_shift, shift_norm); - // Update point - for (let d = 0; d < D; ++d) { - row_i[d] += shift[d]; - } - } - } - if (max_shift < tolerance) { - // Converged - break; - } - } - } - - // After convergence, assign clusters based on nearest mode - _assign_clusters() { - const N = this._N; - const metric = this._parameters.metric; - const bandwidth = this._bandwidth; - - // Group points that converged to the same mode - // Two points are in the same mode if they're within bandwidth/2 of each other - const mode_threshold = bandwidth * 0.5; - /** @type {number[][]} */ - const modes = []; // Each mode contains indices of points in that mode - const point_to_mode = new Array(N).fill(-1); + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction + * @see {@link PCA} for another linear alternative + */ +class MDS extends DR { + /** + * Classical MDS. + * + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + */ + constructor(X, parameters = {}) { + super(X, { d: 2, metric: euclidean, seed: 1212, eig_args: {} }, parameters); + const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); + if (!Object.hasOwn(eig_args, "seed")) { + eig_args.seed = this._randomizer; + } + } - for (let i = 0; i < N; ++i) { - if (point_to_mode[i] !== -1) continue; // Already assigned to a mode + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + *generator() { + yield this.transform(); + return this.projection; + } - const row_i = this._points.row(i); - const mode = [i]; - point_to_mode[i] = modes.length; + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {T} + */ + transform() { + const X = this.X; + const rows = X.shape[0]; + const d = /** @type {number} */ (this.parameter("d")); + const metric = /** @type {typeof euclidean | "precomputed"} */ (this.parameter("metric")); + const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); + const A = metric === "precomputed" ? X : distance_matrix(X, metric); + + const D_sq = new Matrix(rows, rows, (i, j) => { + const val = A.entry(i, j); + return val * val; + }); - // Find all points close to this mode - for (let j = i + 1; j < N; ++j) { - if (point_to_mode[j] !== -1) continue; + const ai_ = D_sq.meanCols(); + const a_j = D_sq.meanRows(); + const a__ = D_sq.mean(); - const row_j = this._points.row(j); - const dist = metric(row_i, row_j); + this._d_X = A; + const B = new Matrix(rows, rows, (i, j) => -0.5 * (D_sq.entry(i, j) - ai_[i] - a_j[j] + a__)); - if (dist < mode_threshold) { - mode.push(j); - point_to_mode[j] = modes.length; - } - } + const { eigenvectors: V } = simultaneous_poweriteration(B, d, eig_args); + this.Y = Matrix.from(V).transpose(); - modes.push(mode); + return this.projection; } - // Build final clusters - each mode becomes a cluster - /** @type {number[][]} */ - const clusters = []; - const cluster_ids = new Array(N).fill(-1); + /** @returns {number} - The stress of the projection. */ + stress() { + const N = this.X.shape[0]; + const Y = this.Y; + const d_X = this._d_X; + if (!d_X) throw new Error("First transform!"); - for (let mode_idx = 0; mode_idx < modes.length; ++mode_idx) { - const mode = modes[mode_idx]; - clusters.push([...mode]); - for (const point_idx of mode) { - cluster_ids[point_idx] = mode_idx; - } + const d_Y = new Matrix(N, N, 0); + d_Y.shape = [ + N, + N, + (i, j) => { + return i < j ? euclidean(Y.row(i), Y.row(j)) : d_Y.entry(j, i); + }, + ]; + let top_sum = 0; + let bottom_sum = 0; + for (let i = 0; i < N; ++i) { + for (let j = i + 1; j < N; ++j) { + top_sum += (d_X.entry(i, j) - d_Y.entry(i, j)) ** 2; + bottom_sum += d_X.entry(i, j) ** 2; + } + } + return Math.sqrt(top_sum / bottom_sum); } - this._clusters = cluster_ids; - this._cluster_list = clusters; - } + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X, parameters) { + const dr = new MDS(X, parameters); + return dr.transform(); + } - /** - * @returns {number[][]} - */ - get_clusters() { - // Ensure algorithm has been run - if (!this._cluster_list) { - this._mean_shift(); - this._assign_clusters(); + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new MDS(X, parameters); + yield* dr.generator(); + return dr.projection; } - return /** @type {number[][]} */ (this._cluster_list); - } - /** - * - * @returns {number[]} - */ - get_cluster_list() { - if (!this._clusters) { - this._mean_shift(); - this._assign_clusters(); + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new MDS(X, parameters); + return dr.transform_async(); } - return /** @type {number[]} */ (this._clusters); - } } -/** @import { InputType } from "../index.js" */ -/** @import { ParametersOptics } from "./index.js" */ - -/** @typedef {Object} DBEntry - * @property {Float64Array} element - * @property {number} index - * @property {number} [reachability_distance] - * @property {boolean} processed - * @property {DBEntry[]} [neighbors] - */ +/** @import {InputType} from "../index.js" */ +/** @import {ParametersLSP} from "./index.js" */ /** - * OPTICS (Ordering Points To Identify the Clustering Structure) + * Least Square Projection (LSP) * - * A density-based clustering algorithm that extends DBSCAN. It handles clusters of varying - * densities and produces a reachability plot that can be used to extract clusters. + * A dimensionality reduction technique that uses a small set of control points + * (projected with MDS) to define the projection for the rest of the data + * using a Laplacian-based optimization. * * @class - * @extends Clustering - * @category Clustering + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction */ -class OPTICS extends Clustering { - /** - * **O**rdering **P**oints **T**o **I**dentify the **C**lustering **S**tructure. - * - * @param {InputType} points - The data. - * @param {Partial} [parameters={}] - * @see {@link https://www.dbs.ifi.lmu.de/Publikationen/Papers/OPTICS.pdf} - * @see {@link https://en.wikipedia.org/wiki/OPTICS_algorithm} - */ - constructor(points, parameters = {}) { - super( - points, - /** @type {ParametersOptics} */ ( - Object.assign({ epsilon: 1, min_points: 4, metric: euclidean }, parameters) - ), - ); - const matrix = this._matrix; +class LSP extends DR { /** - * @private - * @type {DBEntry[]} + * Least Squares Projection. + * + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + * @see {@link https://ieeexplore.ieee.org/document/4378370} + */ + constructor(X, parameters) { + super( + X, + { + neighbors: -Infinity, + control_points: -Infinity, + d: 2, + metric: euclidean, + seed: 1212, + }, + parameters, + ); + if (this.parameter("neighbors") === -Infinity) { + this.parameter("neighbors", Math.min(Math.max(Math.floor(this._N / 10), 2), this._N - 1)); + } + if (this.parameter("control_points") === -Infinity) { + this.parameter("control_points", Math.min(Math.ceil(Math.sqrt(this._N)), this._N - 1)); + } + this._is_initialized = false; + } + + /** + * @returns {LSP} + */ + // init(DR = MDS, DR_parameters = {}, KNN = BallTree) { + init() { + const DR = MDS; + let DR_parameters = {}; + const KNN = BallTree; + if (this._is_initialized) return this; + const X = this.X; + const N = this._N; + const K = /** @type {number} */ (this.parameter("neighbors")); + const d = /** @type {number} */ (this.parameter("d")); + const seed = /** @type {number} */ (this.parameter("seed")); + const metric = /** @type {typeof euclidean} */ (this.parameter("metric")); + DR_parameters = Object.assign({ d, metric, seed }, DR_parameters); + const nc = /** @type {number} */ (this.parameter("control_points")); + const control_points = new KMedoids(X, { K: nc, metric }).get_medoids(); + const C = new Matrix(nc, N, "zeros"); + control_points.forEach((c_i, i) => { + C.set_entry(i, c_i, 1); + }); + + const control_points_matrix = Matrix.from(control_points.map((c_i) => X.row(c_i))); + const Y_C = new DR(control_points_matrix, DR_parameters).transform(); + + const XA = X.to2dArray(); + const knn = new KNN(XA, { metric, seed }); + const L = new Matrix(N, N, "I"); + const alpha = -1 / K; + XA.forEach((x_i, i) => { + for (const { index: j } of knn.search(x_i, K)) { + if (i === j) continue; + L.set_entry(i, j, alpha); + } + }); + const A = L.concat(C, "vertical"); + + const z = new Matrix(N, d, "zeros"); + const b = z.concat(Y_C, "vertical"); + + this._A = A; + this._b = b; + this._is_initialized = true; + return this; + } + + /** + * Computes the projection. + * + * @returns {T} Returns the projection. */ - this._ordered_list = []; - const ordered_list = this._ordered_list; - /** @type {number[][]} */ - this._clusters = []; - const clusters = this._clusters; + transform() { + this.check_init(); + const A = this._A; + const b = this._b; - const N = this._N; + if (!A || !b) throw new Error("Call init() first!"); + const ATA = A.transDot(A); + const ATb = A.transDot(b); + this.Y = Matrix.solve_CG(ATA, ATb, this._randomizer); + return this.projection; + } /** - * @private - * @type {DBEntry[]} - */ - this._DB = new Array(N).fill(0).map((_, i) => { - return { - element: matrix.row(i), - index: i, - reachability_distance: undefined, - processed: false, - }; - }); - const DB = this._DB; - - this._cluster_index = 0; - let cluster_index = this._cluster_index; - - for (const p of DB) { - if (p.processed) continue; - p.neighbors = this._get_neighbors(p); - p.processed = true; - clusters.push([p.index]); - cluster_index = clusters.length - 1; - ordered_list.push(p); - if (this._core_distance(p) !== undefined) { - const seeds = new Heap(null, (d) => d.reachability_distance, "min"); - this._update(p, seeds); - this._expand_cluster(seeds, clusters[cluster_index]); - } - } - } - - /** - * @private - * @param {DBEntry} p - A point of the data. - * @returns {DBEntry[]} An array consisting of the `epsilon`-neighborhood of `p`. - */ - _get_neighbors(p) { - if (p?.neighbors) return p.neighbors; - const DB = this._DB; - const metric = this._parameters.metric; - const epsilon = this._parameters.epsilon; - const neighbors = []; - for (const q of DB) { - if (q.index === p.index) continue; - if (metric(p.element, q.element) <= epsilon) { - neighbors.push(q); - } - } - return neighbors; - } - - /** - * @private - * @param {DBEntry} p - A point of `matrix`. - * @returns {number|undefined} The distance to the `min_points`-th nearest point of `p`, or undefined if the - * `epsilon`-neighborhood has fewer elements than `min_points`. - */ - _core_distance(p) { - const min_points = this._parameters.min_points; - const metric = this._parameters.metric; - // Need min_points - 1 other points plus the point itself - if (!p.neighbors || p.neighbors.length < min_points - 1) { - return undefined; - } - // Sort neighbors by distance to find the MinPts-th closest - const sortedNeighbors = p.neighbors.toSorted( - (a, b) => metric(p.element, a.element) - metric(p.element, b.element), - ); - // MinPts-th closest is at index min_points - 2 (0-indexed, excluding p itself) - return metric(p.element, sortedNeighbors[min_points - 2].element); - } - - /** - * Updates the reachability distance of the points. - * - * @private - * @param {DBEntry} p - * @param {Heap} seeds - */ - _update(p, seeds) { - const metric = this._parameters.metric; - const core_distance = this._core_distance(p); - // If p is not a core point, don't update seeds - if (core_distance === undefined) { - return; - } - const neighbors = this._get_neighbors(p); //p.neighbors; - for (const q of neighbors) { - if (q.processed) continue; - const new_reachability_distance = Math.max(core_distance, metric(p.element, q.element)); - //if (q.reachability_distance == undefined) { // q is not in seeds - if (seeds.raw_data().findIndex((d) => d.element === q) < 0) { - q.reachability_distance = new_reachability_distance; - seeds.push(q); - } else { - // q is in seeds - if (new_reachability_distance < (q.reachability_distance ?? Infinity)) { - q.reachability_distance = new_reachability_distance; - seeds = Heap.heapify(seeds.data(), (d) => d.reachability_distance ?? Infinity, "min"); // seeds change key =/ - } - } - } - } - - /** - * Expands the `cluster` with points in `seeds`. - * - * @private - * @param {Heap} seeds - * @param {number[]} cluster - */ - _expand_cluster(seeds, cluster) { - const ordered_list = this._ordered_list; - while (!seeds.empty) { - const q = /** @type {{ element: DBEntry, value: number}} */ (seeds.pop()).element; - q.neighbors = this._get_neighbors(q); - q.processed = true; - cluster.push(q.index); - ordered_list.push(q); - if (this._core_distance(q) !== undefined) { - this._update(q, seeds); - // Recursive call removed - while loop handles iteration correctly - } - } - } - - /** - * Returns an array of clusters. - * - * @returns {number[][]} Array of clusters with the indices of the rows in given `matrix`. - */ - get_clusters() { - const clusters = []; - const outliers = []; - const min_points = this._parameters.min_points; - for (const cluster of this._clusters) { - if (cluster.length < min_points) { - outliers.push(...cluster); - } else { - clusters.push(cluster); - } - } - clusters.push(outliers); - return clusters; - } - - /** - * @returns {number[]} Returns an array, where the ith entry defines the cluster affirmation of the ith point of - * given data. (-1 stands for outlier) - */ - get_cluster_list() { - const N = this._matrix.shape[0]; - /** @type {number[]} */ - const result = new Array(N).fill(0); - const clusters = this.get_clusters(); - for (let i = 0, n = clusters.length; i < n; ++i) { - const cluster = clusters[i]; - for (const index of cluster) { - result[index] = i < n - 1 ? i : -1; - } + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X, parameters) { + const dr = new LSP(X, parameters); + return dr.transform(); } - return result; - } -} -/** @import { InputType } from "../index.js" */ -/** @import { ParametersXMeans } from "./index.js" */ + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new LSP(X, parameters); + yield* dr.generator(); + return dr.projection; + } -/** - * @typedef SplitResult - * @property {number} index - Index of the cluster being split - * @property {number} bic_parent - BIC score of the parent cluster - * @property {number} bic_children - BIC score of the split children - * @property {number[][]} child_clusters - Clusters after splitting - * @property {Float64Array[]} child_centroids - Centroids of child clusters - */ + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new LSP(X, parameters); + return dr.transform_async(); + } +} -/** - * @typedef CandidateResult - * @property {KMeans} kmeans - The KMeans instance for this K - * @property {number} score - BIC score - */ +/** @import {InputType} from "../index.js" */ +/** @import {ParametersLTSA} from "./index.js" */ +/** @import {EigenArgs} from "../linear_algebra/index.js" */ /** - * X-Means Clustering + * Local Tangent Space Alignment (LTSA) * - * An extension of K-Means that automatically determines the number of clusters (K) - * using the Bayesian Information Criterion (BIC). + * A nonlinear dimensionality reduction algorithm that represents the local + * geometry of the manifold by tangent spaces and then aligns them to reveal + * the global structure. * * @class - * @extends Clustering - * @category Clustering + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction */ -class XMeans extends Clustering { - /** - * XMeans clustering algorithm that automatically determines the optimal number of clusters. - * - * X-Means extends K-Means by starting with a minimum number of clusters and iteratively - * splitting clusters to improve the Bayesian Information Criterion (BIC). - * - * Algorithm: - * 1. Start with K_min clusters using KMeans - * 2. For each cluster, try splitting it into 2 sub-clusters - * 3. If BIC improves after splitting, keep the split - * 4. Run KMeans again with all (old + new) centroids - * 5. Repeat until K_max is reached or no more improvements - * - * @param {InputType} points - The data points to cluster - * @param {Partial} [parameters={}] - Configuration parameters - * @see {@link https://www.cs.cmu.edu/~dpelleg/download/xmeans.pdf} - * @see {@link https://github.com/annoviko/pyclustering/blob/master/pyclustering/cluster/xmeans.py} - * @see {@link https://github.com/haifengl/smile/blob/master/core/src/main/java/smile/clustering/XMeans.java} - */ - constructor(points, parameters = {}) { - const defaults = { - K_max: 10, - K_min: 2, - metric: euclidean, - seed: 1212, - min_cluster_size: 35, - tolerance: 0.001, - }; - super(points, /** @type {ParametersXMeans} */ (Object.assign(defaults, parameters))); - this._randomizer = new Randomizer(this._parameters.seed); - - /** @type {KMeans | null} */ - this._best_kmeans = null; - - // Run XMeans algorithm - this._run(); - } - - /** - * Run the XMeans algorithm - * - * @private - */ - _run() { - /** @type {Map} */ - const candidates = new Map(); - const A = this._matrix; - - // Initialize with K_min clusters - let current_kmeans = new KMeans(this._points, { - K: this._parameters.K_min, - metric: this._parameters.metric, - seed: this._parameters.seed, - }); - - let K = this._parameters.K_min; - - candidates.set(K, { - kmeans: current_kmeans, - score: -Infinity, - }); - - // Iteratively improve clustering - while (K < this._parameters.K_max) { - const clusters = current_kmeans.get_clusters(); - const centroids = current_kmeans.centroids; - - // Try splitting each cluster - /** @type {SplitResult[]} */ - const split_results = []; - - for (let j = 0; j < clusters.length; ++j) { - const cluster = clusters[j]; - - // Skip small clusters - need enough points for reliable BIC - if (cluster.length < this._parameters.min_cluster_size) { - continue; - } - - // Get subset data for this cluster - /** @type {number[][]} */ - const subset_points = cluster.map((idx) => { - const row = A.row(idx); - return Array.from(row); - }); - - // Calculate BIC for parent (single cluster) - const parent_bic = this._bic([cluster], [centroids[j]]); - - // Run KMeans with K=2 on subset - const subset_kmeans = new KMeans(subset_points, { - K: 2, - metric: this._parameters.metric, - seed: this._randomizer.seed, - }); +class LTSA extends DR { + /** + * Local Tangent Space Alignment + * + * @param {T} X - The high-dimensional data. + * @param {Partial} parameters - Object containing parameterization of the DR method. + * @see {@link https://epubs.siam.org/doi/abs/10.1137/S1064827502419154} + */ + constructor(X, parameters) { + super( + X, + { + neighbors: -Infinity, + d: 2, + metric: euclidean, + seed: 1212, + eig_args: {}, + }, + parameters, + ); + if (this.parameter("neighbors") === -Infinity) { + this.parameter("neighbors", Math.min(Math.max(Math.floor(this._N / 10), 2), this._N - 1)); + } + const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); + if (!Object.hasOwn(eig_args, "seed")) { + eig_args.seed = this._randomizer; + } - const child_clusters_local = subset_kmeans.get_clusters(); - const child_centroids = subset_kmeans.centroids; + const d = /** @type {number} */ (this.parameter("d")); + if (this._D <= d) { + throw new Error( + `Dimensionality of X (D = ${this._D}) must be greater than the required dimensionality of the result (d = ${d})!`, + ); + } + } - // Map local indices back to global indices - /** @type {number[][]} */ - const child_clusters_global = child_clusters_local.map((local_cluster) => - local_cluster.map((local_idx) => cluster[local_idx]), - ); + /** + * Transforms the inputdata `X` to dimensionality `d`. + * + * @returns {Generator} A generator yielding the intermediate steps of the projection. + */ + *generator() { + yield this.transform(); + return this.projection; + } - // Calculate BIC for children (split into 2 clusters) - const children_bic = this._bic(child_clusters_global, child_centroids); + /** + * Transforms the inputdata `X` to dimenionality `d`. + * + * @returns {T} + */ + transform() { + const X = this.X; + const [rows, D] = X.shape; + const neighbors = /** @type {number} */ (this.parameter("neighbors")); + const d = /** @type {number} */ (this.parameter("d")); + const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); + const metric = /** @type {typeof euclidean} */ (this.parameter("metric")); + // 1.1 determine k nearest neighbors + const nN = k_nearest_neighbors(X, neighbors, metric); + // center matrix + const O = new Matrix(D, D, "center"); + const B = new Matrix(rows, rows, 0); - split_results.push({ - index: j, - bic_parent: parent_bic, - bic_children: children_bic, - child_clusters: child_clusters_global, - child_centroids: child_centroids, - }); - } - - // Keep all splits that improve BIC (BIC_children > BIC_parent) - /** @type {SplitResult[]} */ - const accepted_splits = split_results.filter( - (result) => result.bic_children > result.bic_parent, - ); - - // If no splits improve BIC, we're done - if (accepted_splits.length === 0) { - break; - } - - // Build new centroids array: keep non-split centroids + add split centroids - /** @type {Float64Array[]} */ - const new_centroids = []; - const split_indices = new Set(); - - // Sort accepted splits by improvement (descending) - accepted_splits.sort( - (a, b) => b.bic_children - b.bic_parent - (a.bic_children - a.bic_parent), - ); - - for (const split of accepted_splits) { - if (centroids.length + split_indices.size + 1 <= this._parameters.K_max) { - split_indices.add(split.index); - } else { - break; + for (let row = 0; row < rows; ++row) { + // 1.2 compute the d largest eigenvectors of the correlation matrix + const I_i = [row, ...nN[row].map((n) => n.j)]; + let X_i = Matrix.from(I_i.map((n) => X.row(n))); + // center X_i + X_i = X_i.dot(O); + // correlation matrix + const C = X_i.dotTrans(X_i); + const { eigenvectors: g } = simultaneous_poweriteration(C, d, eig_args); + //g.push(linspace(0, k).map(_ => 1 / Math.sqrt(k + 1))); + const G_i_t = Matrix.from(g); + // 2. Constructing alignment matrix + const W_i = G_i_t.transDot(G_i_t).add(1 / Math.sqrt(neighbors + 1)); + for (let i = 0; i < neighbors + 1; ++i) { + for (let j = 0; j < neighbors + 1; ++j) { + B.add_entry(I_i[i], I_i[j], W_i.entry(i, j) - (i === j ? 1 : 0)); + } + } } - } - for (let i = 0; i < centroids.length; ++i) { - if (split_indices.has(i)) { - // This cluster was split - add both child centroids - const split_result = accepted_splits.find((s) => s.index === i); - if (split_result) { - new_centroids.push(...split_result.child_centroids); - } - } else { - // This cluster wasn't split - keep its centroid - new_centroids.push(centroids[i]); - } - } - - // Run KMeans on full dataset with new centroids as initialization - // This is crucial - we need to reassign all points to all clusters - const newK = new_centroids.length; - - // Create a new KMeans instance with K set to new number of clusters - current_kmeans = new KMeans(this._matrix, { - K: newK, - metric: this._parameters.metric, - seed: this._randomizer.seed, - initial_centroids: new_centroids, - }); - - // Store the candidate with the BIC of the FULL dataset - candidates.set(newK, { - kmeans: current_kmeans, - score: this._bic(current_kmeans.get_clusters(), current_kmeans.centroids), - }); - - K = newK; - } - - // Select best candidate based on BIC score - this._best_kmeans = this._select_best_candidate(candidates); - } + // 3. Aligning global coordinates + const { eigenvectors: Y } = simultaneous_poweriteration(B, d + 1, eig_args); + this.Y = Matrix.from(Y.slice(1)).transpose(); - /** - * Select the best candidate based on BIC score - * - * @private - * @param {Map} candidates - * @returns {KMeans} - */ - _select_best_candidate(candidates) { - if (candidates.size === 0) { - throw new Error("No candidates found"); - } - - const first_candidate = candidates.get(this._parameters.K_min); - if (!first_candidate) { - throw new Error("Missing initial candidate"); - } - - let best_score = first_candidate.score; - /** @type {KMeans} */ - let best_kmeans = first_candidate.kmeans; - - for (const candidate of candidates.values()) { - if (candidate.score > best_score) { - best_score = candidate.score; - best_kmeans = candidate.kmeans; - } - } - - return best_kmeans; - } - - /** - * Calculate Bayesian Information Criterion for a set of clusters. - * - * Uses Kass's formula for BIC calculation: - * BIC(θ) = L(D) - 0.5 * p * ln(N) - * - * Where: - * - L(D) is the log-likelihood of the data - * - p is the number of free parameters: (K-1) + D*K + 1 - * - N is the total number of points - * - * @private - * @param {number[][]} clusters - Array of clusters with point indices - * @param {Float64Array[]} centroids - Array of centroids - * @returns {number} BIC score (higher is better) - */ - _bic(clusters, centroids) { - const A = this._matrix; - const D = this._D; - const K = centroids.length; - - let total_variance = 0; - let N = 0; - - // Calculate total variance (sum of squared distances) - for (let i = 0; i < K; ++i) { - const cluster = clusters[i]; - const centroid = centroids[i]; - N += cluster.length; - - for (let j = 0; j < cluster.length; ++j) { - const point_idx = cluster[j]; - const point = A.row(point_idx); - // Sum of squared distances (variance term) - total_variance += euclidean_squared(centroid, point); - } - } - - // Not enough points for meaningful BIC - if (N <= K) { - return -Infinity; - } - - // Estimate variance (ML estimate) - const variance = total_variance / (N - K); - - // Handle case of zero variance (all points identical) - if (variance <= 0) { - return -Infinity; - } - - // Number of free parameters: (K-1) cluster weights + K*D centroid coordinates + 1 variance - const p = K - 1 + D * K + 1; - - // Calculate log-likelihood - let log_likelihood = 0; - const log_2pi = Math.log(2 * Math.PI); - - for (let i = 0; i < K; ++i) { - const n = clusters[i].length; - if (n <= 1) continue; - - // Log-likelihood for cluster i - const cluster_log_likelihood = - n * Math.log(n / N) - 0.5 * n * log_2pi - 0.5 * n * D * Math.log(variance) - 0.5 * (n - 1); - - log_likelihood += cluster_log_likelihood; - } - - // BIC = log_likelihood - 0.5 * p * ln(N) - return log_likelihood - 0.5 * p * Math.log(N); - } - - /** - * Get the computed clusters - * - * @returns {number[][]} Array of clusters, each containing indices of points - */ - get_clusters() { - if (!this._best_kmeans) { - throw new Error("XMeans has not been run"); - } - return this._best_kmeans.get_clusters(); - } - - /** @returns {number[]} The cluster list */ - get_cluster_list() { - if (!this._best_kmeans) { - throw new Error("XMeans has not been run"); - } - return this._best_kmeans.get_cluster_list(); - } - - /** - * Get the final centroids - * - * @returns {Float64Array[]} Array of centroids - */ - get centroids() { - if (!this._best_kmeans) { - throw new Error("XMeans has not been run"); - } - return this._best_kmeans.centroids; - } - - /** - * Get the optimal number of clusters found - * - * @returns {number} The number of clusters - */ - get k() { - if (!this._best_kmeans) { - throw new Error("XMeans has not been run"); - } - return this._best_kmeans.k; - } -} + // return embedding + return this.projection; + } -/** @import {InputType} from "../index.js" */ + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {T} + */ + static transform(X, parameters) { + const dr = new LTSA(X, parameters); + return dr.transform(); + } -/** - * @abstract - * @template {InputType} T - * @template {{ seed?: number }} Para - * - * Base class for all Dimensionality Reduction (DR) algorithms. - * - * Provides a common interface for parameters management, data initialization, - * and transformation (both synchronous and asynchronous). - * - * @class - */ -class DR { - /** @type {number} */ - _D; - /** @type {number} */ - _N; - /** @type {Randomizer} */ - _randomizer; - /** @type {boolean} */ - _is_initialized; - - /** - * Takes the default parameters and seals them, remembers the type of input `X`, and initializes the random number - * generator. - * - * @param {T} X - The high-dimensional data. - * @param {Para} default_parameters - Object containing default parameterization of the DR method. - * @param {Partial} parameters - Object containing parameterization of the DR method to override defaults. - */ - constructor(X, default_parameters, parameters = {}) { - /** @type {T} */ - this.__input = X; + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new LTSA(X, parameters); + yield* dr.generator(); + return dr.projection; + } - /** @type {Para} */ - this._parameters = /** @type {Para} */ Object.seal({ - ...default_parameters, - ...parameters, - }); - /** @type {"array" | "matrix" | "typed"} */ - this._type; - /** @type {Matrix} */ - this.X; - /** @type {Matrix} */ - this.Y; - - if (Array.isArray(X)) { - if (X[0] instanceof Float64Array) { - this._type = "typed"; - } else { - this._type = "array"; - } - this.X = Matrix.from(X); - } else if (X instanceof Matrix) { - this._type = "matrix"; - this.X = X; - } else { - throw new Error("No valid type for X!"); - } - const [N, D] = this.X.shape; - this._N = N; - this._D = D; - this._randomizer = new Randomizer(this._parameters.seed); - this._is_initialized = false; - } - - /** - * Get all Parameters. - * @overload - * @returns {Para} - */ - /** - * Get value of given parameter. - * @template {keyof Para} K - * @overload - * @param {K} name - Name of the parameter. - * @returns {Para[K]} - */ - /** - * Set value of given parameter. - * @template {keyof Para} K - * @overload - * @param {K} name - Name of the parameter. - * @param {Para[K]} value - Value of the parameter to set. - * @returns {this} - */ - /** - * @param {keyof Para} [name] - Name of the parameter. If null, returns all parameters as an Object. - * @param {Para[keyof Para]} [value] - Value of the parameter to set. If name is set and value is not given, returns the - * current value. - * @returns {Para | Para[keyof Para] | this} On setting a parameter, returns the DR object. If name is set and value is not - * given, returns the parameter value. If name is null, returns all parameters. On setting a parameter, this - * function returns the DR object. If `name` is set and `value == null` then return actual parameter value. If - * `name` is not given, then returns all parameters as an Object. - * @example - * ```js - * const DR = new druid.TSNE(X, {d: 3}); // creates a new DR object, with parameter for `d = 3`. - * DR.parameter("d"); // returns 3 - * DR.parameter("d", 2); // sets parameter `d` to 2 and returns `DR`. - * ``` - * - */ - parameter(name, value) { - if (name === undefined && value === undefined) { - return Object.assign({}, this._parameters); - } - if (name && !Object.hasOwn(this._parameters, name)) { - throw new Error(`${String(name)} is not a valid parameter!`); - } - if (name && value !== undefined) { - this._parameters[name] = value; - this._is_initialized = false; - return this; - } else if (name) { - return this._parameters[name]; - } - throw new Error("Should not happen!"); - } - - /** - * Computes the projection. - * - * @abstract - * @param {...unknown} args - * @returns {T} The projection. - */ - transform(...args) { - this.check_init(); - return this.projection; - } - - /** - * Computes the projection. - * - * @template {InputType} T - * @template {{ seed?: number }} Para - * @param {T} X - * @param {Para} parameters - * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method. - * @returns {T} The dimensionality reduced dataset. - */ - static transform(X, parameters, ...args) { - const dr = new DR(X, parameters, parameters); - return /** @type {T} */ (dr.transform()); - } - - /** - * Computes the projection. - * - * @abstract - * @param {...unknown} args - * @returns {Generator} The intermediate steps of the projection. - */ - *generator(...args) { - const R = this.transform(...args); - yield R; - return R; - } - - /** - * Computes the projection. - * - * @template {{ seed?: number }} Para - * @param {InputType} X - * @param {Para} parameters - * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method. - * @returns {Generator} A generator yielding the intermediate steps of the dimensionality - * reduction method. - */ - static *generator(X, parameters, ...args) { - const dr = new DR(X, parameters, parameters); - const generator = dr.generator(...args); - let result; - do { - result = generator.next(); - yield result.value; - } while (!result.done); - - return result.value; - } - - /** - * @abstract - * @param {...unknown} args - */ - init(...args) {} - - /** - * If the respective DR method has an `init` function, call it before `transform`. - * - * @returns {DR} - */ - check_init() { - if (!this._is_initialized && typeof this.init === "function") { - this.init(); - this._is_initialized = true; - } - return this; - } - - /** @returns {T} The projection in the type of input `X`. */ - get projection() { - if (Object.hasOwn(this, "Y")) { - this.check_init(); - //return this._type === "matrix" ? this.Y : this.Y.to2dArray(); - if (this._type === "matrix") { - return /** @type {T} */ (/** @type {any} */ (this.Y)); - } else if (this._type === "typed") { - return /** @type {T} */ (/** @type {any} */ (this.Y.to2dArray())); - } else { - return /** @type {T} */ (/** @type {any} */ (this.Y.asArray())); - } - } else { - throw new Error("The dataset is not transformed yet!"); - } - } - - /** - * Computes the projection. - * - * @param {...unknown} args - Arguments the transform method of the respective DR method takes. - * @returns {Promise} The dimensionality reduced dataset. - */ - async transform_async(...args) { - return this.transform(...args); - } - - /** - * Computes the projection. - * - * @template {{ seed?: number }} Para - * @param {InputType} X - * @param {Para} parameters - * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method. - * @returns {Promise} A promise yielding the dimensionality reduced dataset. - */ - static async transform_async(X, parameters, ...args) { - return DR.transform(X, parameters, ...args); - } + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new LTSA(X, parameters); + return dr.transform_async(); + } } -/** @import { InputType } from "../index.js" */ -/** @import { ParametersFASTMAP } from "./index.js"; */ +/** @import {InputType} from "../index.js" */ +/** @import {ParametersPCA, ParametersMDS, ParametersSAMMON} from "./index.js" */ +/** @typedef {"PCA" | "MDS" | "random"} AvailableInit */ + +/** @typedef {{ PCA: ParametersPCA; MDS: ParametersMDS; random: {} }} ChooseDR */ /** - * FastMap algorithm for dimensionality reduction. + * Sammon's Mapping * - * A very fast algorithm for projecting high-dimensional data into a lower-dimensional - * space while preserving pairwise distances. It works similarly to PCA but uses - * only a subset of the data to find projection axes. + * A nonlinear dimensionality reduction technique that minimizes a stress + * function based on the ratio of pairwise distances in high and low dimensional spaces. * * @class * @template {InputType} T - * @extends DR + * @extends DR> * @category Dimensionality Reduction */ -class FASTMAP extends DR { - /** - * FastMap: a fast algorithm for indexing, data-mining and visualization of traditional and multimedia datasets. - * @param {T} X - The high-dimensional data. - * @param {Partial} parameters - Object containing parameterization of the DR method. - * @see {@link https://doi.org/10.1145/223784.223812} - */ - constructor(X, parameters) { - super(X, { d: 2, metric: euclidean, seed: 1212 }, parameters); - } - - /** - * Chooses two points which are the most distant in the actual projection. - * - * @private - * @param {(a: number, b: number) => number} dist - * @returns {[number, number, number]} An array consisting of first index, second index, and distance between the - * two points. - */ - _choose_distant_objects(dist) { - const X = this.X; - const N = X.shape[0]; - let a_index = this._randomizer.random_int % N; - /** @type {number | null} */ - let b_index = null; - let max_dist = -Infinity; - for (let i = 0; i < N; ++i) { - const d_ai = dist(a_index, i); - if (d_ai > max_dist) { - max_dist = d_ai; - b_index = i; - } - } - if (b_index === null) throw new Error("should not happen!"); - max_dist = -Infinity; - for (let i = 0; i < N; ++i) { - const d_bi = dist(b_index, i); - if (d_bi > max_dist) { - max_dist = d_bi; - a_index = i; - } - } - return [a_index, b_index, max_dist]; - } - - /** - * Computes the projection. - * - * @returns {T} The `d`-dimensional projection of the data matrix `X`. - */ - transform() { - const X = this.X; - const N = X.shape[0]; - const d = /** @type {number} */ (this._parameters.d); - const metric = /** @type {typeof euclidean} */ (this._parameters.metric); - const Y = new Matrix(N, d, 0); - /** @type {(a: number, b: number) => number} */ - let dist = (a, b) => metric(X.row(a), X.row(b)); - - for (let _col = 0; _col < d; ++_col) { - const old_dist = dist; - // choose pivot objects - const [a_index, b_index, d_ab] = this._choose_distant_objects(dist); - if (d_ab !== 0) { - // project the objects on the line (O_a, O_b) - for (let i = 0; i < N; ++i) { - const d_ai = dist(a_index, i); - const d_bi = dist(b_index, i); - const y_i = (d_ai ** 2 + d_ab ** 2 - d_bi ** 2) / (2 * d_ab); - Y.set_entry(i, _col, y_i); - } - // consider the projections of the objects on a - // hyperplane perpendicluar to the line (a, b); - // the distance function D'() between two - // projections is given by Eq.4 - dist = (a, b) => - Math.sqrt(old_dist(a, b) ** 2 - (Y.entry(a, _col) - Y.entry(b, _col)) ** 2); - } - } - // return embedding. - this.Y = Y; - return this.projection; - } - - *generator() { - yield this.transform(); - return this.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {T} - */ - static transform(X, parameters) { - const dr = new FASTMAP(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new FASTMAP(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new FASTMAP(X, parameters); - return dr.transform_async(); - } -} - -/** - * Base class for all K-Nearest Neighbors (KNN) search algorithms. - * - * Provides a common interface for elements management and search operations. - * - * @abstract - * @category KNN - * @template {number[] | Float64Array} T - Type of elements - * @template {Object} Para - Type of parameters - * @class - */ -class KNN { - /** @type {T[]} */ - _elements; - /** @type {Para} */ - _parameters; - /** @type {"typed" | "array"} */ - _type; - - /** - * @param {T[]} elements - * @param {Para} parameters - */ - constructor(elements, parameters) { - if (elements.length === 0) throw new Error("Elements needs to contain at least one element!"); - if (elements[0] instanceof Float64Array) { - this._type = "typed"; - } else { - this._type = "array"; - } - this._parameters = parameters; - this._elements = elements; - } - - /** - * @abstract - * @param {T} t - * @param {number} k - * @returns {{ element: T; index: number; distance: number }[]} - */ - search(t, k) { - throw new Error("The function search must be implemented!"); - } - - /** - * @abstract - * @param {number} i - * @param {number} k - * @returns {{ element: T; index: number; distance: number }[]} - */ - search_by_index(i, k) { - throw new Error("The function search_by_index must be implemented!"); - } -} - -/** @import { Metric } from "../metrics/index.js" */ -/** @import { ParametersAnnoy } from "./index.js" */ +class SAMMON extends DR { + /** @type {Matrix | undefined} */ + distance_matrix; -/** - * @template {number[] | Float64Array} T - * @typedef {Object} AnnoyNode - * @property {boolean} isLeaf - Whether this is a leaf node - * @property {number[]} indices - Indices of points in this node (leaf) or children (internal) - * @property {number[]} normal - Hyperplane normal vector (internal nodes only) - * @property {number} offset - Hyperplane offset (internal nodes only) - * @property {AnnoyNode | null} left - Left child (internal nodes only) - * @property {AnnoyNode | null} right - Right child (internal nodes only) - */ + /** + * SAMMON's Mapping + * + * @param {T} X - The high-dimensional data. + * @param {Partial>} [parameters] - Object containing parameterization of the DR + * method. + * @see {@link https://arxiv.org/pdf/2009.01512.pdf} + */ + constructor(X, parameters) { + super( + X, + { + magic: 0.1, + d: 2, + metric: euclidean, + seed: 1212, + init_DR: "random", + init_parameters: {}, + }, + parameters, + ); + } -/** - * Annoy-style (Approximate Nearest Neighbors Oh Yeah) implementation using Random Projection Trees. - * - * This implementation builds multiple random projection trees where each tree randomly selects - * two points and splits the space based on a hyperplane equidistant between them. - * - * Key features: - * - Multiple random projection trees for better recall - * - Each tree uses random hyperplanes for splitting - * - Priority queue search for better recall - * - Combines results from all trees - * - * Best suited for: - * - High-dimensional data - * - Approximate nearest neighbor search - * - Large datasets - * - When high recall is needed with approximate methods - * - * @class - * @category KNN - * @template {number[] | Float64Array} T - * @extends KNN - * @see {@link https://github.com/spotify/annoy} - * @see {@link https://erikbern.com/2015/09/24/nearest-neighbors-and-vector-models-epilogue-curse-of-dimensionality.html} - */ -class Annoy extends KNN { - /** - * Creates a new Annoy-style index with random projection trees. - * - * @param {T[]} elements - Elements to index - * @param {ParametersAnnoy} [parameters={}] - Configuration parameters - */ - constructor( - elements, - parameters = { - metric: euclidean, - numTrees: 10, - maxPointsPerLeaf: 10, - seed: 1212, - }, - ) { - // Handle empty initialization - use dummy element - const hasElements = elements && elements.length > 0; - const firstElement = /** @type {T} */ (hasElements ? elements[0] : new Float64Array([0])); - - super([firstElement], parameters); - - this._metric = this._parameters.metric ?? euclidean; - this._numTrees = this._parameters.numTrees ?? 10; - this._maxPointsPerLeaf = this._parameters.maxPointsPerLeaf ?? 10; - this._seed = this._parameters.seed ?? 1212; - this._randomizer = new Randomizer(this._seed); + /** + * Initializes the projection. + * + * @param {Matrix | undefined} D + * @returns {asserts D is Matrix} + */ + init(D) { + const N = this.X.shape[0]; + const d = /** @type {number} */ (this.parameter("d")); + const metric = /** @type {typeof euclidean | "precomputed"} */ (this.parameter("metric")); + const init_DR = /** @type {AvailableInit} */ (this.parameter("init_DR")); + const DR_parameters = this.parameter("init_parameters"); + if (init_DR === "random") { + const randomizer = this._randomizer; + this.Y = new Matrix(N, d, () => randomizer.random); + } else if (init_DR === "PCA") { + this.Y = Matrix.from(PCA.transform(this.X, /** @type {ParametersPCA} */ (DR_parameters))); + } else if (init_DR === "MDS") { + this.Y = Matrix.from(MDS.transform(this.X, /** @type {ParametersMDS} */ (DR_parameters))); + } else { + throw new Error('init_DR needs to be either "random" or a DR method!'); + } + D = metric === "precomputed" ? Matrix.from(this.X) : distance_matrix(this.X, metric); + this.distance_matrix = D; + } /** - * @private - * @type {AnnoyNode[]} - */ - this._trees = []; - - // Build trees - if (hasElements) { - // Reset elements and rebuild properly - /** @type {T[]} */ - this._elements = []; - this._trees = []; - this.add(elements); - } - } - - /** - * Get the number of trees in the index. - * @returns {number} - */ - get num_trees() { - return this._trees.length; - } - - /** - * Get the total number of nodes in all trees. - * @returns {number} - */ - get num_nodes() { - let total = 0; - for (const tree of this._trees) { - total += this._countNodes(tree); - } - return total; - } - - /** - * @private - * @param {any} node - * @returns {number} - */ - _countNodes(node) { - if (!node) return 0; - return 1 + this._countNodes(node.left) + this._countNodes(node.right); - } - - /** - * Add elements to the Annoy index. - * @param {T[]} elements - * @returns {this} - */ - add(elements) { - // Extend elements array - this._elements = this._elements.concat(elements); - - // Rebuild all trees with new elements - this._trees = []; - this._buildTrees(); - - return this; - } - - /** - * Build all random projection trees. - * @private - */ - _buildTrees() { - const elements = this._elements; - const n = elements.length; - - for (let t = 0; t < this._numTrees; t++) { - // Create index array for this tree - const indices = Array.from({ length: n }, (_, i) => i); - const tree = this._buildTreeRecursive(indices); - this._trees.push(tree); - } - } - - /** - * Recursively build a random projection tree. - * @private - * @param {number[]} indices - Indices of elements to include - * @returns {AnnoyNode} - */ - _buildTreeRecursive(indices) { - const elements = this._elements; - - // Base case: small enough to be a leaf - if (indices.length <= this._maxPointsPerLeaf) { - return { - isLeaf: true, - indices: indices, - normal: [], - offset: 0, - left: null, - right: null, - }; - } - - // Select two random points to define the splitting hyperplane - const idx1 = indices[Math.floor(this._randomizer.random * indices.length)]; - const idx2 = indices[Math.floor(this._randomizer.random * indices.length)]; - - const point1 = elements[idx1]; - const point2 = elements[idx2]; - - // Compute normal vector (point2 - point1) - const dim = point1.length; - /** @type {number[]} */ - const normal = new Array(dim); - for (let i = 0; i < dim; i++) { - normal[i] = point2[i] - point1[i]; + * Transforms the inputdata `X` to dimensionality 2. + * + * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200` + * @returns {T} The projection of `X`. + */ + transform(max_iter = 200) { + this.check_init(); + if (!this.distance_matrix) this.init(this.distance_matrix); + for (let j = 0; j < max_iter; ++j) { + this._step(); + } + return this.projection; } - // Normalize - let norm = 0; - for (let i = 0; i < dim; i++) { - norm += normal[i] * normal[i]; - } - norm = Math.sqrt(norm); + /** + * Transforms the inputdata `X` to dimenionality 2. + * + * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200` + * @returns {Generator} A generator yielding the intermediate steps of the projection of + * `X`. + */ + *generator(max_iter = 200) { + this.check_init(); + if (!this.distance_matrix) this.init(this.distance_matrix); + + for (let j = 0; j < max_iter; ++j) { + this._step(); + yield this.projection; + } - if (norm > 1e-10) { - for (let i = 0; i < dim; i++) { - normal[i] /= norm; - } + return this.projection; } - // Compute midpoint and offset - /** @type {number[]} */ - const midpoint = new Array(dim); - for (let i = 0; i < dim; i++) { - midpoint[i] = (point1[i] + point2[i]) / 2; - } - - // Compute offset: dot(normal, midpoint) - let offset = 0; - for (let i = 0; i < dim; i++) { - offset += normal[i] * midpoint[i]; - } - - // Split points based on which side of hyperplane they fall - const leftIndices = []; - const rightIndices = []; - - for (const idx of indices) { - const point = elements[idx]; - let dot = 0; - for (let i = 0; i < dim; i++) { - dot += normal[i] * point[i]; - } - - if (dot < offset) { - leftIndices.push(idx); - } else { - rightIndices.push(idx); - } - } - - // Handle edge case where all points fall on one side - if (leftIndices.length === 0 || rightIndices.length === 0) { - return { - isLeaf: true, - indices: indices, - normal: [], - offset: 0, - left: null, - right: null, - }; - } - - // Recursively build subtrees - const left = this._buildTreeRecursive(leftIndices); - const right = this._buildTreeRecursive(rightIndices); - - return { - isLeaf: false, - indices: [], - normal: normal, - offset: offset, - left: left, - right: right, - }; - } - - /** - * Compute distance from point to hyperplane. - * @private - * @param {T} point - * @param {number[]} normal - * @param {number} offset - * @returns {number} Signed distance (positive = right side, negative = left side) - */ - _distanceToHyperplane(point, normal, offset) { - let dot = 0; - for (let i = 0; i < point.length; i++) { - dot += normal[i] * point[i]; - } - return dot - offset; - } - - /** - * Search for k approximate nearest neighbors. - * @param {T} query - * @param {number} [k=5] - * @returns {{ element: T; index: number; distance: number }[]} - */ - search(query, k = 5) { - const metric = this._metric; - const elements = this._elements; - - if (elements.length === 0) return []; - - // Collect candidates from all trees using priority queue - const candidates = new Set(); - - // Collect more candidates for better recall - // Search at least k * numTrees * 2 candidates - const minCandidates = Math.min(k * this._numTrees * 3, elements.length); - - for (const tree of this._trees) { - this._searchTreePriority(tree, query, candidates, minCandidates); - } - - // Compute exact distances for all candidates - /** @type {Heap<{ index: number; distance: number }>} */ - const best = new Heap(null, (d) => d.distance, "max"); - - for (const idx of candidates) { - const element = elements[idx]; - if (!element || element.length !== query.length) continue; - - const dist = metric(query, element); - - if (best.length < k) { - best.push({ index: idx, distance: dist }); - } else if (dist < (best.first?.value ?? Infinity)) { - best.pop(); - best.push({ index: idx, distance: dist }); - } - } - - // If we still don't have enough candidates, do a linear scan fallback - if (best.length < k) { - for (let i = 0; i < elements.length && best.length < k; i++) { - if (candidates.has(i)) continue; + _step() { + if (!this.distance_matrix) this.init(this.distance_matrix); + const MAGIC = /** @type {number} */ (this.parameter("magic")); + const D = /** @type {Matrix} */ (this.distance_matrix); + const N = this.X.shape[0]; + const d = /** @type {number} */ (this.parameter("d")); + const Y = this.Y; - const element = elements[i]; - if (!element || element.length !== query.length) continue; - - const dist = metric(query, element); - best.push({ index: i, distance: dist }); - } - } - - // Convert to result format - /** @type {{ element: T; index: number; distance: number }[]} */ - const result = []; - while (best.length > 0) { - const item = /** @type {{ element: { index: number; distance: number }; value: number }} */ ( - best.pop() - ); - result.push({ - element: elements[item.element.index], - index: item.element.index, - distance: item.value, - }); - } - - return result.reverse(); - } - - /** - * Search tree using priority queue for better recall. - * Explores nodes in order of distance to hyperplane. - * @private - * @param {AnnoyNode} node - * @param {T} query - * @param {Set} candidates - * @param {number} maxCandidates - */ - _searchTreePriority(node, query, candidates, maxCandidates) { - if (!node) return; - - // Priority queue entry: { node, distance } - /** @type {Heap<{ node: AnnoyNode; dist: number }>} */ - const pq = new Heap(null, (d) => d.dist, "min"); - pq.push({ node: node, dist: 0 }); - - while (!pq.empty && candidates.size < maxCandidates) { - const entry = pq.pop(); - if (!entry) continue; - - const currentNode = entry.element.node; - - // Leaf node: add all points - if (currentNode.isLeaf) { - for (const idx of currentNode.indices) { - candidates.add(idx); - if (candidates.size >= maxCandidates) return; - } - continue; - } - - // Internal node: compute distance to hyperplane - const dist = this._distanceToHyperplane(query, currentNode.normal, currentNode.offset); - - // Determine which side is closer - const closerSide = dist < 0 ? currentNode.left : currentNode.right; - const fartherSide = dist < 0 ? currentNode.right : currentNode.left; - - // Add closer side with priority 0 (explore first) - if (closerSide) { - pq.push({ node: closerSide, dist: 0 }); - } - - // Add farther side with priority = |dist| (explore later if needed) - if (fartherSide && candidates.size < maxCandidates) { - pq.push({ node: fartherSide, dist: Math.abs(dist) }); - } - } - } - - /** - * @param {number} i - * @param {number} [k=5] - * @returns {{ element: T; index: number; distance: number }[]} - */ - search_by_index(i, k = 5) { - if (i < 0 || i >= this._elements.length) return []; - return this.search(this._elements[i], k); - } - - /** - * Alias for search_by_index for backward compatibility. - * - * @param {number} i - Index of the query element - * @param {number} [k=5] - Number of nearest neighbors to return - * @returns {{ element: T; index: number; distance: number }[]} - */ - search_index(i, k = 5) { - return this.search_by_index(i, k); - } -} + const G = new Matrix(N, d, 0); -/** @import { Metric } from "../metrics/index.js" */ -/** @import { ParametersBallTree } from "./index.js" */ + const sum = new Float64Array(d); + for (let i = 0; i < N; ++i) { + const e1 = new Float64Array(d); + const e2 = new Float64Array(d); + const Yi = Y.row(i); + for (let j = 0; j < N; ++j) { + if (i === j) continue; + const dX = D.entry(i, j); + if (dX === 0) continue; // Skip identical points in high-dim + + const Yj = Y.row(j); + const delta = new Float64Array(d); + for (let k = 0; k < d; ++k) { + delta[k] = Yi[k] - Yj[k]; + } + const dY = Math.max(euclidean(Yi, Yj), 1e-6); + const dq = dX - dY; + const dr = dX * dY; + for (let k = 0; k < d; ++k) { + e1[k] += (delta[k] * dq) / dr; + e2[k] += (dq - (delta[k] ** 2 * (1 + dq / dY)) / dY) / dr; + } + } + for (let k = 0; k < d; ++k) { + const val = Y.entry(i, k) + ((MAGIC * e1[k]) / Math.abs(e2[k]) || 0); + G.set_entry(i, k, val); + sum[k] += val; + } + } + for (let k = 0; k < d; ++k) { + sum[k] /= N; + } -/** - * @template {number[] | Float64Array} T - * @typedef {Object} ElementWithIndex - * @property {number} index - * @property {T} element - */ + for (let i = 0; i < N; ++i) { + for (let k = 0; k < d; ++k) { + Y.set_entry(i, k, G.entry(i, k) - sum[k]); + } + } + return Y; + } -/** - * Ball Tree for efficient nearest neighbor search. - * - * A Ball Tree is a metric tree that partitions points into a nested set of - * hyperspheres (balls). It is particularly effective for high-dimensional - * data and supports any valid metric. - * - * @class - * @category KNN - * @template {number[] | Float64Array} T - * @extends KNN - */ -class BallTree extends KNN { - /** - * Generates a BallTree with given `elements`. - * - * @param {T[]} elements - Elements which should be added to the BallTree - * @param {ParametersBallTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}` - * @see {@link https://en.wikipedia.org/wiki/Ball_tree} - * @see {@link https://github.com/invisal/noobjs/blob/master/src/tree/BallTree.js} - */ - constructor(elements, parameters = { metric: euclidean, seed: 1212 }) { - super(elements, Object.assign({ seed: 1212 }, parameters)); /** - * @private - * @type {BallTreeNode | BallTreeLeaf} - */ - this._root = this._construct(elements.map((element, index) => ({ index, element }))); - } - - /** @returns {Metric} */ - get _metric() { - return this._parameters.metric; - } - - /** - * @private - * @param {ElementWithIndex[]} elements - * @returns {BallTreeNode | BallTreeLeaf} Root of balltree. - */ - _construct(elements) { - if (elements.length === 1) { - return new BallTreeLeaf(elements); - } else { - const c = this._greatest_spread(elements); - const sorted_elements = elements.sort((a, b) => a.element[c] - b.element[c]); - const n = sorted_elements.length; - const p_index = Math.floor(n / 2); - const p = sorted_elements[p_index]; - const L = sorted_elements.slice(0, p_index); - const R = sorted_elements.slice(p_index, n); - const radius = Math.max(...elements.map((d) => this._metric(p.element, d.element))); - let B; - if (L.length > 0 && R.length > 0) { - B = new BallTreeNode(p, this._construct(L), this._construct(R), radius); - } else { - B = new BallTreeLeaf(elements); - } - return B; - } - } - - /** - * @private - * @param {ElementWithIndex[]} B - * @returns {number} - */ - _greatest_spread(B) { - const d = B[0].element.length; - const start = new Array(d); - - for (let i = 0; i < d; ++i) { - start[i] = [Infinity, -Infinity]; - } - - let spread = B.reduce((acc, current) => { - for (let i = 0; i < d; ++i) { - acc[i][0] = Math.min(acc[i][0], current.element[i]); - acc[i][1] = Math.max(acc[i][1], current.element[i]); - } - return acc; - }, start); - spread = spread.map((d) => d[1] - d[0]); - - let c = 0; - for (let i = 0; i < d; ++i) { - c = spread[i] > spread[c] ? i : c; + * @template {InputType} T + * @param {T} X + * @param {Partial>} [parameters] + * @returns {T} + */ + static transform(X, parameters) { + const dr = new SAMMON(X, parameters); + return dr.transform(); } - return c; - } - - /** - * @param {number} i - * @param {number} k - */ - search_by_index(i, k = 5) { - return this.search(this._elements[i], k); - } - - /** - * @param {T} t - Query element. - * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5` - * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors. - */ - search(t, k = 5) { - /** @type {Heap>} */ - const heap = new Heap(null, (d) => this._metric(d.element, t), "max"); - this._search(t, k, heap, this._root); - - // Convert heap to result array - /** @type {{ element: T; index: number; distance: number }[]} */ - const result = []; - while (heap.length > 0) { - const item = /** @type {{ element: ElementWithIndex; value: number }} */ (heap.pop()); - result.push({ - element: item.element.element, - index: item.element.index, - distance: item.value, - }); - } - return result.reverse(); // Reverse to get closest first - } - - /** - * @private - * @param {T} t - Query element. - * @param {number} k - Number of nearest neighbors to return. - * @param {Heap>} Q - Heap consists of the currently found `k` nearest neighbors. - * @param {BallTreeNode | BallTreeLeaf} B - */ - _search(t, k, Q, B) { - if (!B) return; - - if (B instanceof BallTreeNode) { - const dist_to_pivot = this._metric(t, B.pivot.element); - if (Q.length >= k && dist_to_pivot - B.radius >= (Q.first?.value ?? -Infinity)) { - return; - } - - const c1 = B.child1; - const c2 = B.child2; - - let d1 = Infinity; - let d2 = Infinity; - - if (c1 instanceof BallTreeNode) d1 = this._metric(t, c1.pivot.element); - else if (c1 instanceof BallTreeLeaf) d1 = this._metric(t, c1.points[0].element); - - if (c2 instanceof BallTreeNode) d2 = this._metric(t, c2.pivot.element); - else if (c2 instanceof BallTreeLeaf) d2 = this._metric(t, c2.points[0].element); - - if (d1 < d2) { - if (c1) this._search(t, k, Q, c1); - if (c2) this._search(t, k, Q, c2); - } else { - if (c2) this._search(t, k, Q, c2); - if (c1) this._search(t, k, Q, c1); - } - } else if (B instanceof BallTreeLeaf) { - for (let i = 0, n = B.points.length; i < n; ++i) { - const p = B.points[i]; - const dist = this._metric(p.element, t); - if (Q.length < k) { - Q.push(p); - } else if (dist < (Q.first?.value ?? Infinity)) { - Q.pop(); - Q.push(p); - } - } - } - } -} -/** - * @private - * @template {number[] | Float64Array} T - */ -class BallTreeNode { - /** - * @param {ElementWithIndex} pivot - * @param {BallTreeNode | BallTreeLeaf | null} child1 - * @param {BallTreeNode | BallTreeLeaf | null} child2 - * @param {number} radius - */ - constructor(pivot, child1 = null, child2 = null, radius = 0) { - this.pivot = pivot; - this.child1 = child1; - this.child2 = child2; - this.radius = radius; - } -} + /** + * @template {InputType} T + * @param {T} X + * @param {Partial>} [parameters] + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new SAMMON(X, parameters); + yield* dr.generator(); + return dr.projection; + } -/** - * @private - * @template {number[] | Float64Array} T - */ -class BallTreeLeaf { - /** @param {ElementWithIndex[]} points */ - constructor(points) { - this.points = points; - } + /** + * @template {InputType} T + * @param {T} X + * @param {Partial>} [parameters] + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new SAMMON(X, parameters); + return dr.transform_async(); + } } -/** @import { Metric } from "../metrics/index.js" */ -/** @import { ParametersHNSW } from "./index.js" */ - -/** - * @typedef {Object} Layer - * @property {number} l_c - Layer number - * @property {number[]} point_indices - Global indices of points in this layer - * @property {Map} edges - Global index -> array of connected global indices - */ - -/** - * @template {number[] | Float64Array} T - * @typedef {Object} Candidate - * @property {T} element - The actual data point - * @property {number} index - Global index in the dataset - * @property {number} distance - Distance from query - */ +/** @import {InputType} from "../index.js" */ +/** @import {Metric} from "../metrics/index.js" */ +/** @import {ParametersSQDMDS} from "./index.js" */ /** - * Hierarchical Navigable Small World (HNSW) graph for approximate nearest neighbor search. - * - * HNSW builds a multi-layer graph structure where each layer is a navigable small world graph. - * The top layers serve as "highways" for fast traversal, while lower layers provide accuracy. - * Each element is assigned to a random level, allowing logarithmic search complexity. - * - * Key parameters: - * - `m`: Controls the number of connections per element (affects accuracy/memory) - * - `ef_construction`: Controls the quality of the graph during construction (higher = better but slower) - * - `ef`: Controls the quality of search (higher = better recall but slower) + * SQuadMDS (Stochastic Quartet MDS) * - * Based on: - * - "Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs" - * by Malkov & Yashunin (2016) - * - "Approximate Nearest Neighbor Search on High Dimensional Data" - * by Li et al. (2019) + * A lean Stochastic Quartet MDS improving global structure preservation in + * neighbor embedding like t-SNE and UMAP. * * @class - * @category KNN - * @template {number[] | Float64Array} T - * @extends KNN - * - * @example - * import * as druid from "@saehrimnir/druidjs"; - * - * const points = [[1, 2], [3, 4], [5, 6], [7, 8]]; - * const hnsw = new druid.HNSW(points, { - * metric: druid.euclidean, - * m: 16, - * ef_construction: 200 - * }); - * - * const query = [2, 3]; - * const neighbors = hnsw.search(query, 2); - * // [{ element: [1, 2], index: 0, distance: 1.41 }, ...] + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction */ -class HNSW extends KNN { - /** - * Creates a new HNSW index. - * - * @param {T[]} points - Initial points to add to the index - * @param {ParametersHNSW} [parameters={}] - Configuration parameters - */ - constructor( - points, - parameters = { - metric: euclidean, - heuristic: true, - m: 16, - ef_construction: 200, - m0: null, - mL: null, - seed: 1212, - ef: 50, - }, - ) { - // Handle empty initialization - use dummy element - const hasElements = points && points.length > 0; - let firstElement = /** @type {T} */ (hasElements ? points[0] : new Float64Array([0])); - - // Validate all points have consistent dimensions - if (hasElements) { - const expected_dim = firstElement.length; - for (let i = 1; i < points.length; i++) { - if (!points[i] || points[i].length !== expected_dim) { - console.warn( - `HNSW: Point ${i} has inconsistent dimensions (expected ${expected_dim}, got ${points[i]?.length})`, - ); - // Remove invalid points - points = points.filter((_, idx) => idx === 0 || points[idx]?.length === expected_dim); - firstElement = points[0]; - } - } - } - - super([firstElement], parameters); - - // Store reference to elements before clearing - const elementsToAdd = hasElements ? [...points] : []; - /** @type {T[]} */ - this._elements = []; +class SQDMDS extends DR { + /** + * SQuadMDS: a lean Stochastic Quartet MDS improving global structure preservation in neighbor embedding like t-SNE + * and UMAP. + * + * @param {T} X + * @param {Partial} [parameters] + * @see {@link https://arxiv.org/pdf/2202.12087.pdf} + */ + constructor(X, parameters) { + super( + X, + { + d: 2, + metric: euclidean, + seed: 1212, + decay_start: 0.1, + decay_cte: 0.34, // 0.34 + }, + parameters, + ); - /** @type {Metric} */ - this._metric = this._parameters.metric || euclidean; + this.init(); + if (this.parameter("metric") === "precomputed" && this.X.shape[0] !== this.X.shape[1]) { + throw new Error("SQDMDS input data must be a square Matrix"); + } + } - /** @type {Function} */ - this._select = this._parameters.heuristic - ? this._select_heuristic.bind(this) - : this._select_simple.bind(this); + init() { + const N = this._N; + const d = /** @type {number} */ (this.parameter("d")); + + // initialize helpers. + this._add = this.__add(d); + this._sub_div = this.__sub_div(d); + this._minus = this.__minus(d); + this._mult = this.__mult(d); + this._LR_init = Math.max(2, 0.005 * N); + this._LR = this._LR_init; + const decay_cte = /** @type {number} */ (this.parameter("decay_cte")); + this._offset = -Math.exp(-1 / decay_cte); + this._momentums = new Matrix(N, d, 0); + this._grads = new Matrix(N, d, 0); + this._indices = linspace(0, N - 1); + // initialize projection. + const R = this._randomizer; + this.Y = new Matrix(N, d, () => R.random - 0.5); + + // preparing metric for optimization. + const this_metric = /** @type {Metric | "precomputed"} */ (this.parameter("metric")); + if (this_metric === "precomputed") { + /** @type {(i: number, j: number, X: Matrix) => number} */ + this._HD_metric = (i, j, X) => X.entry(i, j); + /** @type {(i: number, j: number, X: Matrix) => number} */ + this._HD_metric_exaggeration = (i, j, X) => X.entry(i, j) ** 2; + } else { + this._HD_metric = (i, j, X) => this_metric(X.row(i), X.row(j)); + if (this_metric === euclidean) { + this._HD_metric_exaggeration = (i, j, X) => euclidean_squared(X.row(i), X.row(j)); + } else { + this._HD_metric_exaggeration = (i, j, X) => this_metric(X.row(i), X.row(j)) ** 2; + } + } + return; + } /** - * @private - * @type {Map} + * Computes the projection. + * + * @param {number} [iterations=500] - Number of iterations. Default is `500` + * @returns {T} The projection. */ - this._graph = new Map(); + transform(iterations = 500) { + this.check_init(); + const decay_start = /** @type {number} */ (this.parameter("decay_start")); + this._decay_start = Math.round(decay_start * iterations); + for (let i = 0; i < iterations; ++i) { + this._step(i, iterations); + } + return this.projection; + } - /** @type {number} */ - this._next_index = 0; + /** + * Computes the projection. + * + * @param {number} [iterations=500] - Number of iterations. Default is `500` + * @returns {Generator} The intermediate steps of the projection. + */ + *generator(iterations = 500) { + this.check_init(); + const decay_start = /** @type {number} */ (this.parameter("decay_start")); + this._decay_start = Math.round(decay_start * iterations); + for (let i = 0; i < iterations; ++i) { + this._step(i, iterations); + yield this.projection; + } - // Validate and set parameters - const m_param = this._parameters.m ?? 16; - if (m_param <= 0 || !Number.isInteger(m_param)) { - throw new Error("HNSW: parameter 'm' must be a positive integer"); + return this.projection; } - /** @type {number} */ - this._m = Math.max(2, m_param); - const ef_construction_param = this._parameters.ef_construction ?? 200; - if (ef_construction_param <= 0 || !Number.isInteger(ef_construction_param)) { - throw new Error("HNSW: parameter 'ef_construction' must be a positive integer"); + /** + * Performs an optimization step. + * + * @private + * @param {number} i - Acutal iteration. + * @param {number} iterations - Number of iterations. + */ + _step(i, iterations) { + if (this._LR_init === undefined || this._offset === undefined) throw new Error("Call init() first!"); + + const decay_start = /** @type {number} */ (this.parameter("decay_start")); + if (i > decay_start) { + const decay_cte = /** @type {number} */ (this.parameter("decay_cte")); + const offset = this._offset; + const ratio = (i - decay_start) / (iterations - decay_start); + this._LR = this._LR_init * (Math.exp(-(ratio * ratio) / decay_cte) + offset); + this._distance_exaggeration = false; + } else { + this._distance_exaggeration = true; + } + this._nestrov_iteration(this._distance_exaggeration); } - /** @type {number} */ - this._ef_construction = ef_construction_param; - const ef_param = this._parameters.ef ?? 50; - if (ef_param <= 0 || !Number.isInteger(ef_param)) { - throw new Error("HNSW: parameter 'ef' must be a positive integer"); + /** + * Creates quartets of non overlapping indices. + * + * @private + * @returns {Uint32Array[]} + */ + __quartets() { + if (!this._indices) throw new Error("Call init() first!"); + if (this._offset === undefined) throw new Error("Call init() first!"); + const N = this._N; + const max_N = N - (N % 4); + const R = this._randomizer; + const shuffled_indices = R.choice(this._indices, max_N); + const result = []; + for (let i = 0; i < max_N; i += 4) { + result.push( + Uint32Array.of( + shuffled_indices[i], + shuffled_indices[i + 1], + shuffled_indices[i + 2], + shuffled_indices[i + 3], + ), + ); + } + return result; } - /** @type {number} */ - this._ef = ef_param; - const m0_param = this._parameters.m0 ?? 2 * this._m; - if (m0_param <= 0 || !Number.isInteger(m0_param)) { - throw new Error("HNSW: parameter 'm0' must be a positive integer"); + /** + * Computes and applies gradients, and updates momentum. + * + * @private + * @param {boolean} distance_exaggeration + */ + _nestrov_iteration(distance_exaggeration) { + if (!this._momentums || !this._grads || this._LR === undefined) throw new Error("Call init() first!"); + const momentums = this._momentums.mult(0.99, { inline: true }); + const LR = this._LR; + const grads = this._fill_MDS_grads(this.Y.add(momentums), this._grads, distance_exaggeration); + const [n, d] = momentums.shape; + for (let i = 0; i < n; ++i) { + const g_i = grads.row(i); + const g_i_norm = norm(g_i); + if (g_i_norm === 0) continue; + const mul = LR / g_i_norm; + const m_i = momentums.row(i); + for (let j = 0; j < d; ++j) { + m_i[j] -= mul * g_i[j]; + } + } // momentums -= (LR / norm) * grads + this.Y.add(momentums, { inline: true }); } - /** @type {number} */ - this._m0 = m0_param; - /** @type {number} */ - this._mL = this._parameters.mL ?? 1 / Math.log(this._m); + /** + * Computes the gradients. + * + * @param {Matrix} Y - The Projection. + * @param {Matrix} grads - The gradients. + * @param {boolean} [exaggeration=false] - Whether or not to use early exaggeration. Default is `false` + * @param {boolean} [zero_grad=true] - Whether or not to reset the gradient in the beginning. Default is `true` + * @returns {Matrix} The gradients. + */ + _fill_MDS_grads(Y, grads, exaggeration = false, zero_grad = true) { + if (!this._HD_metric || !this._HD_metric_exaggeration || !this._add) throw new Error("Call init() first!"); + if (zero_grad) { + // compute new gradients + grads.values.fill(0); + } + const add = this._add; + const X = this.X; + let HD_metric; + if (exaggeration === true) { + HD_metric = this._HD_metric_exaggeration; + } else { + HD_metric = this._HD_metric; + } - /** @type {Randomizer} */ - this._randomizer = new Randomizer(this._parameters.seed); - - /** @type {number} - Current maximum layer in the graph */ - this._L = -1; - - /** @type {number[] | null} - Entry point indices for search */ - this._ep = null; - - // Add initial points - if (elementsToAdd && elementsToAdd.length > 0) { - this.add(elementsToAdd); - } - } - - /** - * Add a single element to the index. - * - * @param {T} element - Element to add - * @returns {HNSW} This instance for chaining - */ - addOne(element) { - return this.add([element]); - } - - /** - * Add multiple elements to the index. - * - * @param {T[]} new_elements - Elements to add - * @returns {HNSW} This instance for chaining - */ - add(new_elements) { - // Handle empty array - if (!new_elements || new_elements.length === 0) { - return this; - } - - const m = this._m; - const ef_construction = this._ef_construction; - const m0 = this._m0; - const mL = this._mL; - const randomizer = this._randomizer; - const graph = this._graph; - - // Ensure _elements is a proper array that supports push - if (!Array.isArray(this._elements)) { - this._elements = Array.from(this._elements); - } - const elements = this._elements; - - // Get expected dimension from first existing element or first new element - const expected_dim = elements.length > 0 ? elements[0].length : new_elements[0]?.length; - - for (const element of new_elements) { - // Validate element - if (!element || (!Array.isArray(element) && !(element instanceof Float64Array))) { - console.warn("HNSW: Skipping invalid element (null, undefined, or not an array)"); - continue; - } - - // Validate dimensions - if (element.length !== expected_dim) { - console.warn( - `HNSW: Skipping element with wrong dimensions (expected ${expected_dim}, got ${element.length})`, - ); - continue; - } - - elements.push(element); - const global_index = elements.length - 1; - - // Assign random level to the element - // Level is drawn from exponential distribution: l = floor(-ln(uniform(0,1)) * mL) - const rand = Math.max(randomizer.random, 1e-10); // Avoid log(0) - const l = Math.min(31, Math.floor(-Math.log(rand) * mL)); - - let ep_indices = this._ep ? [...this._ep] : null; - const L = this._L; - - if (L >= 0) { - // Search from top layer down to min(L, l) + 1 - // These are the layers where element will NOT be inserted - for (let l_c = L; l_c > l; --l_c) { - const search_result = this._search_layer(element, ep_indices, 1, l_c); - if (search_result.length > 0) { - ep_indices = [search_result[0].index]; - } - } - - // Insert element into layers l down to 0 - for (let l_c = Math.min(L, l); l_c >= 0; --l_c) { - const layer = graph.get(l_c); - if (!layer) continue; - - layer.point_indices.push(global_index); - - // Search for ef_construction nearest neighbors - let W = this._search_layer(element, ep_indices, ef_construction, l_c); - - // If graph search returns no results (e.g., graph is empty or disconnected), - // fall back to linear search over all existing elements - if (W.length === 0 && elements.length > 1) { - const fallbackCandidates = []; - for (let i = 0; i < elements.length - 1; i++) { - const elem = elements[i]; - if (elem && elem.length === element.length) { - fallbackCandidates.push({ - element: elem, - index: i, - distance: this._metric(element, elem), - }); - } - } - fallbackCandidates.sort((a, b) => a.distance - b.distance); - W = fallbackCandidates.slice(0, ef_construction); - // Update ep_indices for next layer based on fallback results - if (l_c === Math.min(L, l)) { - ep_indices = W.map((c) => c.index); + const D_quartet = new Float64Array(6); + const quartets = this.__quartets(); + for (const [i, j, k, l] of quartets) { + // compute quartet's HD distances. + D_quartet[0] = HD_metric(i, j, X); + D_quartet[1] = HD_metric(i, k, X); + D_quartet[2] = HD_metric(i, l, X); + D_quartet[3] = HD_metric(j, k, X); + D_quartet[4] = HD_metric(j, l, X); + D_quartet[5] = HD_metric(k, l, X); + + const D_quartet_sum = neumair_sum(D_quartet); + + if (D_quartet_sum > 0) { + for (let i = 0; i < 6; ++i) { + D_quartet[i] /= D_quartet_sum; + D_quartet[i] += 1e-11; + } } - } + const [gi, gj, gk, gl] = this._compute_quartet_grads(Y, [i, j, k, l], D_quartet); - // Select neighbors using heuristic or simple approach (respect heuristic setting on all layers) - const neighbor_indices = this._select(element, W, l_c === 0 ? m0 : m, l_c); + // add is inline, row acces the matrix + add(grads.row(i), gi); + add(grads.row(j), gj); + add(grads.row(k), gk); + add(grads.row(l), gl); + } + return grads; + } - // Add bidirectional connections - for (const neighbor_idx of neighbor_indices) { - if (neighbor_idx === global_index) continue; + /** + * Quartet gradients for a projection. + * + * @private + * @param {Matrix} Y - The acutal projection. + * @param {number[]} quartet - The indices of the quartet. + * @param {Float64Array} D_hd - The high-dimensional distances of the quartet. + * @returns {Float64Array[]} The gradients for the quartet. + */ + _compute_quartet_grads(Y, quartet, [p_ab, p_ac, p_ad, p_bc, p_bd, p_cd]) { + const [a, b, c, d] = quartet.map((index) => Y.row(index)); + // LD distances, add a small number just in case + const d_ab = euclidean(a, b) + 1e-12; + const d_ac = euclidean(a, c) + 1e-12; + const d_ad = euclidean(a, d) + 1e-12; + const d_bc = euclidean(b, c) + 1e-12; + const d_bd = euclidean(b, d) + 1e-12; + const d_cd = euclidean(c, d) + 1e-12; + const sum_LD_dist = neumair_sum([d_ab, d_ac, d_ad, d_bc, d_bd, d_cd]); + + // for each element of the sum: use the same gradient function and just permute the points given in input. + const [gA1, gB1, gC1, gD1] = this._ABCD_grads( + a, + b, + c, + d, + d_ab, + d_ac, + d_ad, + d_bc, + d_bd, + d_cd, + p_ab, + sum_LD_dist, + ); + const [gA2, gC2, gB2, gD2] = this._ABCD_grads( + a, + c, + b, + d, + d_ac, + d_ab, + d_ad, + d_bc, + d_cd, + d_bd, + p_ac, + sum_LD_dist, + ); + const [gA3, gD3, gC3, gB3] = this._ABCD_grads( + a, + d, + c, + b, + d_ad, + d_ac, + d_ab, + d_cd, + d_bd, + d_bc, + p_ad, + sum_LD_dist, + ); + const [gB4, gC4, gA4, gD4] = this._ABCD_grads( + b, + c, + a, + d, + d_bc, + d_ab, + d_bd, + d_ac, + d_cd, + d_ad, + p_bc, + sum_LD_dist, + ); + const [gB5, gD5, gA5, gC5] = this._ABCD_grads( + b, + d, + a, + c, + d_bd, + d_ab, + d_bc, + d_ad, + d_cd, + d_ac, + p_bd, + sum_LD_dist, + ); + const [gC6, gD6, gA6, gB6] = this._ABCD_grads( + c, + d, + a, + b, + d_cd, + d_ac, + d_bc, + d_ad, + d_bd, + d_ab, + p_cd, + sum_LD_dist, + ); - // Add connection from element to neighbor - if (!layer.edges.has(global_index)) { - layer.edges.set(global_index, []); - } - layer.edges.get(global_index)?.push(neighbor_idx); + if (!this._add) throw new Error("Call init() first!"); + const add = this._add; + const gA = add(gA1, gA2, gA3, gA4, gA5, gA6); + const gB = add(gB1, gB2, gB3, gB4, gB5, gB6); + const gC = add(gC1, gC2, gC3, gC4, gC5, gC6); + const gD = add(gD1, gD2, gD3, gD4, gD5, gD6); - // Add connection from neighbor to element - if (!layer.edges.has(neighbor_idx)) { - layer.edges.set(neighbor_idx, []); - } - const neighbor_edge_list = layer.edges.get(neighbor_idx); - if (neighbor_edge_list && !neighbor_edge_list.includes(global_index)) { - neighbor_edge_list.push(global_index); - } + return [gA, gB, gC, gD]; + } - // Prune connections if too many - const max_conn = l_c === 0 ? m0 : m; - const neighbor_edges = layer.edges.get(neighbor_idx); - if (neighbor_edges && neighbor_edges.length > max_conn) { - const neighbor_element = elements[neighbor_idx]; - // Filter out self-connections before pruning - const valid_neighbor_edges = neighbor_edges.filter((idx) => idx !== neighbor_idx); - const neighbor_candidates = valid_neighbor_edges.map((idx) => ({ - element: elements[idx], - index: idx, - distance: this._metric(neighbor_element, elements[idx]), - })); - const pruned = - l_c === 0 - ? this._select_simple(neighbor_element, neighbor_candidates, max_conn) - : this._select(neighbor_element, neighbor_candidates, max_conn, l_c); - layer.edges.set(neighbor_idx, pruned); - } - } - - // Use closest neighbor as entry point for next layer (following HNSW paper) - if (W.length > 0) { - ep_indices = [W[0].index]; - } - } - } - - // If element's level is higher than current max, create new layers - if (l > L) { - for (let i = L + 1; i <= l; ++i) { - graph.set(i, { - l_c: i, - point_indices: [global_index], - edges: new Map(), - }); - } - // Element becomes the new entry point - this._ep = [global_index]; - this._L = l; - } - - // Special case: if this is the first element (L was -1), - // we need to ensure layer 0 has proper structure for future insertions - if (L === -1) { - if (!graph.has(0)) { - graph.set(0, { - l_c: 0, - point_indices: [global_index], - edges: new Map(), - }); - } - const layer0 = graph.get(0); - if (layer0 && !layer0.edges.has(global_index)) { - layer0.edges.set(global_index, []); - } - } - } - - return this; - } - - /** - * Select neighbors using the heuristic approach. - * - * The heuristic extends candidates with their neighbors and selects - * points that are closer to the query than to already selected points. - * This maintains graph connectivity better than simple selection. - * - * @private - * @param {T} q - Query element - * @param {Candidate[]} candidates - Candidate elements with distances - * @param {number} M - Maximum number of neighbors to return - * @param {number} l_c - Layer number - * @param {boolean} [extend_candidates=true] - Whether to extend candidates with their neighbors - * @param {boolean} [keep_pruned_connections=true] - Whether to add pruned connections back if needed - * @returns {number[]} Selected neighbor indices - */ - _select_heuristic( - q, - candidates, - M, - l_c, - extend_candidates = true, - keep_pruned_connections = true, - ) { - if (l_c > this._L) { - return candidates.map((c) => c.index); - } - - const metric = this._metric; - const layer = this._graph.get(l_c); - const elements = this._elements; - - // Extend candidate set with neighbors of candidates - const W_set = new Set(candidates.map((c) => c.index)); - if (extend_candidates) { - for (const c of candidates) { - const edges = layer?.edges.get(c.index); - if (edges) { - for (const neighbor_idx of edges) { - W_set.add(neighbor_idx); - } - } - } - } - - // Create extended candidates with distances - const W = [...W_set] - .map((idx) => ({ - element: elements[idx], - index: idx, - distance: metric(elements[idx], q), - })) - .sort((a, b) => a.distance - b.distance); - - const R = []; - const W_discarded = []; - - // Select neighbors: prefer points closer to query than to already selected points - for (const e of W) { - if (R.length >= M) break; - - let should_add = true; - - // Check if e is closer to query than to any already selected point - for (const r of R) { - const dist_er = metric(e.element, r.element); - if (dist_er < e.distance) { - should_add = false; - break; - } - } - - if (should_add) { - R.push(e); - } else { - W_discarded.push(e); - } - } - - // Add discarded connections if we need more - if (keep_pruned_connections && R.length < M) { - for (const e of W_discarded) { - if (R.length >= M) break; - R.push(e); - } - } - - return R.map((c) => c.index); - } - - /** - * Select neighbors using simple distance-based selection. - * - * Simply returns the M closest candidates to the query. - * - * @private - * @param {T} q - Query element - * @param {Candidate[]} C - Candidate elements with distances - * @param {number} M - Maximum number of neighbors to return - * @returns {number[]} M nearest candidate indices - */ - _select_simple(q, C, M) { - if (C.length <= M) return C.map((c) => c.index); - - // Candidates already have distance computed, use it directly - return C.slice() - .sort((a, b) => a.distance - b.distance) - .slice(0, M) - .map((c) => c.index); - } - - /** - * Search a single layer for nearest neighbors. - * - * Implements the greedy search algorithm: start from entry points, - * always expand the closest unvisited candidate, maintain a list - * of the ef closest found neighbors. - * - * @private - * @param {T} q - Query element - * @param {number[] | null} ep_indices - Entry point indices - * @param {number} ef - Number of nearest neighbors to find - * @param {number} l_c - Layer number to search - * @returns {Candidate[]} ef nearest neighbors found with their distances - */ - _search_layer(q, ep_indices, ef, l_c) { - const metric = this._metric; - const layer = this._graph.get(l_c); - const elements = this._elements; - - if (!layer || layer.edges.size === 0 || !ep_indices || ep_indices.length === 0) { - return []; - } - - // Filter out invalid indices - const valid_ep_indices = ep_indices.filter((idx) => elements[idx] !== undefined); - if (valid_ep_indices.length === 0) { - return []; - } - - // Visited set to avoid cycles - const visited = new Set(valid_ep_indices); - - // Candidate set (min-heap): closest unvisited candidates to expand - const C = new Heap( - valid_ep_indices.map((idx) => ({ - element: elements[idx], - index: idx, - distance: metric(elements[idx], q), - })), - (item) => item.distance, - "min", - ); - - // Result set (max-heap): ef closest found neighbors - const W = new Heap( - valid_ep_indices.map((idx) => ({ - element: elements[idx], - index: idx, - distance: metric(elements[idx], q), - })), - (item) => item.distance, - "max", - ); - - // Algorithm 2 stops when the distance from query to the next candidate is greater - // than the distance to the furthest element in the result set W. - while (!C.empty) { - const c = C.pop(); - if (!c) break; - const furthest_dist = W.first?.value ?? Infinity; - - // Stop if current candidate is farther than furthest result - if (c.value > furthest_dist) { - break; - } - - const edges = layer.edges.get(c.element.index); - if (!edges) continue; - - for (const neighbor_idx of edges) { - if (!visited.has(neighbor_idx)) { - const neighbor_element = elements[neighbor_idx]; - // Skip invalid elements or elements with different dimensions - if (!neighbor_element || neighbor_element.length !== q.length) continue; - - // Skip self-connections - if (neighbor_idx === c.element.index) continue; - - visited.add(neighbor_idx); - const dist_e = metric(neighbor_element, q); - - const current_furthest = W.first?.value ?? Infinity; - if (dist_e < current_furthest || W.length < ef) { - C.push({ - element: neighbor_element, - index: neighbor_idx, - distance: dist_e, - }); - W.push({ - element: neighbor_element, - index: neighbor_idx, - distance: dist_e, - }); + /** + * Gradients for one element of the loss function's sum. + * + * @private + * @param {Float64Array} a + * @param {Float64Array} b + * @param {Float64Array} c + * @param {Float64Array} d + * @param {number} d_ab + * @param {number} d_ac + * @param {number} d_ad + * @param {number} d_bc + * @param {number} d_bd + * @param {number} d_cd + * @param {number} p_ab + * @param {number} sum_LD_dist + * @returns {Float64Array[]} + */ + _ABCD_grads(a, b, c, d, d_ab, d_ac, d_ad, d_bc, d_bd, d_cd, p_ab, sum_LD_dist) { + if (!this._minus || !this._add || !this._mult || !this._sub_div) throw new Error("Call init() first!"); + const ratio = d_ab / sum_LD_dist; + const twice_ratio = 2 * ((p_ab - ratio) / sum_LD_dist); + const minus = this._minus; + const add = this._add; + const mult = this._mult; + const sub_div = this._sub_div; + // no side effects because sub_div creates new arrays, and the inline functions work on this new created arrays. + const gA = mult( + minus(mult(add(sub_div(a, b, d_ab), sub_div(a, c, d_ac), sub_div(a, d, d_ad)), ratio), sub_div(a, b, d_ab)), + twice_ratio, + ); + const gB = mult( + minus(mult(add(sub_div(b, a, d_ab), sub_div(b, c, d_bc), sub_div(b, d, d_bd)), ratio), sub_div(b, a, d_ab)), + twice_ratio, + ); + const gC = mult(add(sub_div(c, a, d_ac), sub_div(c, b, d_bc), sub_div(c, d, d_cd)), ratio * twice_ratio); + const gD = mult(add(sub_div(d, a, d_ad), sub_div(d, b, d_bd), sub_div(d, c, d_cd)), ratio * twice_ratio); + return [gA, gB, gC, gD]; + } - if (W.length > ef) { - W.pop(); + /** + * Inline! + * + * @param {number} d + */ + __minus(d) { + return /** @type {(a: Float64Array, b: Float64Array) => Float64Array} */ (a, b) => { + for (let i = 0; i < d; ++i) { + a[i] -= b[i]; } - } - } - } + return a; + }; } - // Return sorted results for consistent entry point selection - return W.data().sort((a, b) => a.distance - b.distance); - } - - /** - * Searches for the K nearest neighbors to a query element in the HNSW graph. - * - * Performs a multi-layer search starting from the entry point and traversing - * each layer as entry points for the next. - * - * @param {T} q - Query element - * @param {number} K - Number of nearest neighbors to return - * @returns {Candidate[]} K nearest neighbors with their distances - */ - search(q, K) { - // Validate K - if (!Number.isInteger(K) || K <= 0) { - throw new Error("HNSW: parameter 'K' must be a positive integer"); - } - - // Validate query dimensions - if (!q || (!Array.isArray(q) && !(q instanceof Float64Array))) { - throw new Error("HNSW: query must be an array"); - } - - const search_ef = this._ef; - - // Fallback to linear search if graph is not properly initialized - if (this._L < 0 || !this._ep || this._elements.length === 0) { - return this._linear_search(q, K); - } - - let ep_indices = [...this._ep]; - - // Search from top layer down to layer 1 - for (let l_c = this._L; l_c > 0; --l_c) { - const result = this._search_layer(q, ep_indices, 1, l_c); - if (result.length > 0) { - ep_indices = [result[0].index]; - } - } - - // Search layer 0 with ef candidates - const result = this._search_layer(q, ep_indices, Math.max(search_ef, K), 0); - - // If graph search returns no results, fallback to linear search - if (result.length === 0) { - return this._linear_search(q, K); - } - - // Return K closest - return result.slice(0, K); - } - - /** - * Fallback linear search when graph search fails - * @private - * @param {T} q - Query element - * @param {number} K - Number of nearest neighbors to return - * @returns {Candidate[]} - */ - _linear_search(q, K) { - const metric = this._metric; - const elements = this._elements; - const N = elements.length; - - if (N === 0) return []; - - /** @type {Candidate[]} */ - const candidates = []; - for (let i = 0; i < N; i++) { - const element = elements[i]; - // Skip elements with different dimensions (can happen with inconsistent data) - if (!element || element.length !== q.length) continue; - - candidates.push({ - element: element, - index: i, - distance: metric(q, element), - }); - } - - candidates.sort((a, b) => a.distance - b.distance); - return candidates.slice(0, K); - } - - /** - * Iterator for searching the HNSW graph layer by layer. - * - * Yields intermediate results at each layer for debugging or visualization. - * - * @param {T} q - Query element - * @param {number} K - Number of nearest neighbors to return - * @param {number?} [ef] - Size of dynamic candidate list - * @yields {{layer: number, candidates: Candidate[]}} - */ - *search_iter(q, K, ef = null) { - const search_ef = ef ?? this._ef; - - if (this._L < 0 || !this._ep) { - return; - } - - let ep_indices = [...this._ep]; - - // Yield entry points at top layer instead of query itself - const top_layer = this._graph.get(this._L); - if (top_layer && this._ep && this._ep.length > 0) { - const entry_candidates = this._ep - .filter((idx) => this._elements[idx] !== undefined) - .map((idx) => ({ - element: this._elements[idx], - index: idx, - distance: this._metric(this._elements[idx], q), - })); - yield { - layer: this._L, - candidates: entry_candidates, - }; - } - - for (let l_c = this._L; l_c > 0; --l_c) { - const result = this._search_layer(q, ep_indices, 1, l_c); - yield { layer: l_c, candidates: result }; - // Use closest candidate as entry point for next layer (following HNSW paper) - ep_indices = result.length > 0 ? [result[0].index] : ep_indices; - } - - const result = this._search_layer(q, ep_indices, Math.max(search_ef, K), 0); - yield { layer: 0, candidates: result }; - } - - /** - * Get the number of elements in the index. - * - * @returns {number} Number of elements - */ - get size() { - return this._elements?.length ?? 0; - } - - /** - * Get the number of layers in the graph. - * - * @returns {number} Number of layers - */ - get num_layers() { - return this._L + 1; - } - - /** - * Get an element by its index. - * - * @param {number} index - Element index - * @returns {T} The element at the given index - */ - get_element(index) { - return this._elements[index]; - } - - /** - * Search for nearest neighbors using an element index as the query. - * - * @param {number} i - Index of the query element - * @param {number} [K=5] - Number of nearest neighbors to return - * @returns {Candidate[]} K nearest neighbors - */ - search_by_index(i, K = 5) { - const elements = this._elements; - if (i < 0 || i >= elements.length) return []; - - const element = elements[i]; - if (!element) return []; - - return this.search(element, K); - } -} + /** + * Inline! + * + * @param {number} d + */ + __add(d) { + return /** @type {(...summands: Float64Array[]) => Float64Array} */ (...summands) => { + const n = summands.length; + const s1 = summands[0]; + for (let j = 1; j < n; ++j) { + const summand = summands[j]; + for (let i = 0; i < d; ++i) { + s1[i] += summand[i]; + } + } + return s1; + }; + } -/** @import { Metric } from "../metrics/index.js" */ -/** @import { ParametersKDTree } from "./index.js" */ + /** + * Inline! + * + * @param {number} d + */ + __mult(d) { + return /** @type {(a: Float64Array, v: number) => Float64Array} */ (a, v) => { + for (let i = 0; i < d; ++i) { + a[i] *= v; + } + return a; + }; + } -/** - * @template {number[] | Float64Array} T - * @typedef {Object} ElementWithIndex - * @property {number} index - * @property {T} element - */ + /** + * Creates a new array `(x - y) / div`. + * + * @param {number} d + */ + __sub_div(d) { + return /** @type {(x: Float64Array, y: Float64Array, div: number) => Float64Array} */ (x, y, div) => { + return Float64Array.from({ length: d }, (_, i) => (x[i] - y[i]) / div); + }; + } -/** - * KD-Tree (K-dimensional Tree) for efficient nearest neighbor search. - * - * KD-Trees partition k-dimensional space by recursively splitting along coordinate axes. - * At each level, the tree splits points based on the median of the coordinate with the largest spread. - * This creates a balanced binary tree structure that enables efficient O(log n) search on average. - * - * Best suited for: - * - Low to moderate dimensional data (d < 20-30) - * - When exact nearest neighbors are needed - * - When dimensionality is not too high - * - * Performance degrades in high dimensions (curse of dimensionality) where approximate - * methods like HNSW or LSH become more effective. - * - * @class - * @category KNN - * @template {number[] | Float64Array} T - * @extends KNN - * @see {@link https://en.wikipedia.org/wiki/K-d_tree} - */ -class KDTree extends KNN { - /** - * Generates a KD-Tree with given `elements`. - * - * @param {T[]} elements - Elements which should be added to the KD-Tree - * @param {ParametersKDTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}` - */ - constructor(elements, parameters = { metric: euclidean, seed: 1212 }) { - super(elements, Object.assign({ seed: 1212 }, parameters)); /** - * @private - * @type {KDTreeNode | KDTreeLeaf | null} - */ - this._root = this._construct( - elements.map((element, index) => ({ index, element })), - 0, - ); - } - - /** @returns {Metric} */ - get _metric() { - return this._parameters.metric; - } - - /** - * @private - * @param {ElementWithIndex[]} elements - * @param {number} depth - Current depth in the tree (determines splitting axis) - * @returns {KDTreeNode | KDTreeLeaf | null} Root of KD-Tree. - */ - _construct(elements, depth) { - if (elements.length === 0) { - return null; - } - - if (elements.length === 1) { - return new KDTreeLeaf(elements[0]); - } - - const k = elements[0].element.length; - const axis = depth % k; - - // Sort by the splitting axis and find median - elements.sort((a, b) => a.element[axis] - b.element[axis]); - const medianIndex = Math.floor(elements.length / 2); - const medianPoint = elements[medianIndex]; - - // Recursively build left and right subtrees - const leftElements = elements.slice(0, medianIndex); - const rightElements = elements.slice(medianIndex + 1); - - const left = this._construct(leftElements, depth + 1); - const right = this._construct(rightElements, depth + 1); - - return new KDTreeNode(medianPoint, axis, left, right); - } - - /** - * @param {number} i - * @param {number} k - */ - search_by_index(i, k = 5) { - return this.search(this._elements[i], k); - } - - /** - * @param {T} t - Query element. - * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5` - * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors. - */ - search(t, k = 5) { - /** @type {Heap<{ point: ElementWithIndex; distance: number }>} */ - const best = new Heap(null, (d) => d.distance, "max"); - - this._search_recursive(t, k, this._root, best); - - // Convert heap to result array (closest first) - /** @type {{ element: T; index: number; distance: number }[]} */ - const result = []; - while (best.length > 0) { - const item = - /** @type {{ element: { point: ElementWithIndex; distance: number }; value: number }} */ ( - best.pop() - ); - result.push({ - element: item.element.point.element, - index: item.element.point.index, - distance: item.value, - }); - } - return result.reverse(); - } - - /** - * @private - * @param {T} target - Query element. - * @param {number} k - Number of nearest neighbors to return. - * @param {KDTreeNode | KDTreeLeaf | null} node - Current node. - * @param {Heap<{ point: ElementWithIndex; distance: number }>} best - Heap of k best found so far. - */ - _search_recursive(target, k, node, best) { - if (node === null) return; - - if (node instanceof KDTreeLeaf) { - const dist = this._metric(target, node.point.element); - if (best.length < k) { - best.push({ point: node.point, distance: dist }); - } else if (dist < (best.first?.value ?? Infinity)) { - best.pop(); - best.push({ point: node.point, distance: dist }); - } - return; - } - - // Node is an internal node - const axis = node.axis; - const point = node.point; - const pointValue = point.element[axis]; - const targetValue = target[axis]; - - // Determine which subtree to search first - const firstSubtree = targetValue < pointValue ? node.left : node.right; - const secondSubtree = targetValue < pointValue ? node.right : node.left; - - // Search the nearer subtree - this._search_recursive(target, k, firstSubtree, best); - - // Check if we need to search the other subtree - // The hyperplane could contain closer points - const distToHyperplane = Math.abs(targetValue - pointValue); - const currentMaxDist = best.first?.value ?? Infinity; - - // Calculate distance to current point - const distToPoint = this._metric(target, point.element); - if (best.length < k) { - best.push({ point: point, distance: distToPoint }); - } else if (distToPoint < currentMaxDist) { - best.pop(); - best.push({ point: point, distance: distToPoint }); - } - - // Check if we need to explore the other side of the hyperplane - if (best.length < k || distToHyperplane < (best.first?.value ?? Infinity)) { - this._search_recursive(target, k, secondSubtree, best); - } - } -} + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X, parameters) { + const dr = new SQDMDS(X, parameters); + return dr.transform(); + } -/** - * @private - * @template {number[] | Float64Array} T - */ -class KDTreeNode { - /** - * @param {ElementWithIndex} point - * @param {number} axis - The splitting axis - * @param {KDTreeNode | KDTreeLeaf | null} left - * @param {KDTreeNode | KDTreeLeaf | null} right - */ - constructor(point, axis, left = null, right = null) { - this.point = point; - this.axis = axis; - this.left = left; - this.right = right; - } -} + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new SQDMDS(X, parameters); + yield* dr.generator(); + return dr.projection; + } -/** - * @private - * @template {number[] | Float64Array} T - */ -class KDTreeLeaf { - /** - * @param {ElementWithIndex} point - */ - constructor(point) { - this.point = point; - } + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new SQDMDS(X, parameters); + return dr.transform_async(); + } } -/** @import { Metric } from "../metrics/index.js" */ -/** @import { ParametersLSH } from "./index.js" */ +/** @import {InputType} from "../index.js" */ +/** @import {ParametersTopoMap} from "./index.js" */ /** - * Locality Sensitive Hashing (LSH) for approximate nearest neighbor search. - * - * LSH uses hash functions that map similar items to the same buckets with high probability. - * This implementation uses Random Projection hashing (SimHash-style) which works well for - * cosine similarity and Euclidean distance. - * - * Key concepts: - * - Multiple hash tables increase recall probability - * - Each hash function projects data onto random hyperplanes - * - Points on the same side of hyperplanes are hashed together - * - Combines results from all tables for better accuracy + * TopoMap * - * Best suited for: - * - High-dimensional data where exact methods fail - * - Approximate nearest neighbor needs - * - Large datasets where linear scan is too slow - * - When some false positives/negatives are acceptable + * A 0-dimensional Homology Preserving Projection of High-Dimensional Data. + * It aims to preserve the topological structure of the data by maintaining + * the connectivity of a minimum spanning tree. * * @class - * @category KNN - * @template {number[] | Float64Array} T - * @extends KNN - * @see {@link https://en.wikipedia.org/wiki/Locality-sensitive_hashing} + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction */ -class LSH extends KNN { - /** - * Creates a new LSH index. - * - * @param {T[]} elements - Elements to index - * @param {ParametersLSH} [parameters={}] - Configuration parameters - */ - constructor( - elements, - parameters = { - metric: euclidean, - numHashTables: 10, - numHashFunctions: 10, - seed: 1212, - }, - ) { - // Handle empty initialization - use dummy element - const hasElements = elements && elements.length > 0; - const firstElement = /** @type {T} */ (hasElements ? elements[0] : new Float64Array([0])); - - super([firstElement], parameters); - - this._metric = this._parameters.metric ?? euclidean; - this._numHashTables = this._parameters.numHashTables ?? 10; - this._numHashFunctions = this._parameters.numHashFunctions ?? 10; - this._seed = this._parameters.seed ?? 1212; - this._randomizer = new Randomizer(this._seed); - - // Hash tables: array of Maps where key is hash bucket, value is array of element indices - /** @type {Map[]} */ - this._hashTables = []; - - // Random projection vectors for each hash table and hash function - /** @type {Float64Array[][]} */ - this._projections = []; - - // Random offsets for each hash table and hash function (for quantization) - /** @type {number[][]} */ - this._offsets = []; - - // Store dimensionality for later - /** @type {number} */ - this._dim = firstElement.length; +class TopoMap extends DR { + /** + * TopoMap: A 0-dimensional Homology Preserving Projection of High-Dimensional Data. + * + * @param {T} X - The high-dimensional data. + * @param {Partial} parameters - Object containing parameterization of the DR method. + * @see {@link https://arxiv.org/pdf/2009.01512.pdf} + */ + constructor(X, parameters) { + super(X, { metric: euclidean, seed: 1212 }, parameters); + [this._N, this._D] = this.X.shape; + this._distance_matrix = new Matrix(this._N, this._N, -1); + } + + /** + * @private + * @param {number} i + * @param {number} j + * @param {import("../metrics/index.js").Metric} metric + * @returns {number} + */ + __lazy_distance_matrix(i, j, metric) { + const D = this._distance_matrix; + const X = this.X; + const D_ij = D.entry(i, j); + if (D_ij === -1 && i !== j) { + const dist = metric(X.row(i), X.row(j)); + D.set_entry(i, j, dist); + D.set_entry(j, i, dist); + return dist; + } + return i === j ? 0 : D_ij; + } - // Initialize hash functions - this._initializeHashFunctions(); + /** + * Computes the minimum spanning tree, using a given metric + * + * @private + * @param {import("../metrics/index.js").Metric} metric + * @see {@link https://en.wikipedia.org/wiki/Kruskal%27s_algorithm} + */ + _make_minimum_spanning_tree(metric = euclidean) { + const N = this._N; + const X = [...this.X]; - // Reset elements if we were initialized with dummy - if (!hasElements) { - /** @type {T[]} */ - this._elements = []; - } else { - // Clear and re-add elements properly - /** @type {T[]} */ - this._elements = []; - this._hashTables = []; - this._projections = []; - this._offsets = []; - this._initializeHashFunctions(); - this.add(elements); - } - } - - /** - * Initialize random projection vectors for all hash tables. - * @private - */ - _initializeHashFunctions() { - const dim = this._elements[0]?.length ?? 0; - - for (let t = 0; t < this._numHashTables; t++) { - const tableProjections = []; - const tableOffsets = []; - - for (let h = 0; h < this._numHashFunctions; h++) { - // Generate random projection vector (normalized) - const projection = new Float64Array(dim); - let norm = 0; - for (let i = 0; i < dim; i++) { - // Box-Muller transform for normal distribution - const u1 = this._randomizer.random; - const u2 = this._randomizer.random; - const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2); - projection[i] = z; - norm += z * z; + this._disjoint_set = new DisjointSet(X); + const disjoint_set = this._disjoint_set; + const F = []; + let E = []; + for (let i = 0; i < N; ++i) { + for (let j = i + 1; j < N; ++j) { + E.push([i, j, this.__lazy_distance_matrix(i, j, metric)]); + } + } + E = E.sort((a, b) => a[2] - b[2]); + + for (const [u, v, w] of E) { + const set_u = disjoint_set.find(X[u]); + const set_v = disjoint_set.find(X[v]); + if (!set_u || !set_v) throw new Error("Should not happen!"); + if (set_u !== set_v) { + F.push([u, v, w]); + disjoint_set.union(set_u, set_v); + } } - // Normalize - norm = Math.sqrt(norm); - for (let i = 0; i < dim; i++) { - projection[i] /= norm; - } - - tableProjections.push(projection); - // Random offset for quantization buckets - tableOffsets.push(this._randomizer.random); - } - - this._projections.push(tableProjections); - this._offsets.push(tableOffsets); - this._hashTables.push(new Map()); - } - } - - /** - * Compute hash signature for an element using random projections. - * @private - * @param {T} element - * @param {number} tableIndex - * @returns {string} Hash signature - */ - _computeHash(element, tableIndex) { - const projections = this._projections[tableIndex]; - const offsets = this._offsets[tableIndex]; - const bits = []; - - for (let i = 0; i < this._numHashFunctions; i++) { - // Compute dot product - let dot = 0; - const proj = projections[i]; - for (let j = 0; j < element.length; j++) { - dot += element[j] * proj[j]; - } - // Quantize with offset - const bucket = Math.floor(dot + offsets[i]); - bits.push(bucket); - } - - return bits.join(","); - } - - /** - * Add elements to the LSH index. - * @param {T[]} elements - * @returns {this} - */ - add(elements) { - // Extend elements array - const startIndex = this._elements.length; - this._elements = this._elements.concat(elements); - - // Hash each new element and add to tables - for (let i = 0; i < elements.length; i++) { - const globalIndex = startIndex + i; - const element = elements[i]; - - for (let t = 0; t < this._numHashTables; t++) { - const hash = this._computeHash(element, t); - const table = this._hashTables[t]; - - if (!table.has(hash)) { - table.set(hash, []); - } - const bucket = table.get(hash); - if (bucket) { - bucket.push(globalIndex); - } - } - } - - return this; - } - - /** - * Search for k approximate nearest neighbors. - * @param {T} query - * @param {number} [k=5] - * @returns {{ element: T; index: number; distance: number }[]} - */ - search(query, k = 5) { - const metric = this._metric; - const elements = this._elements; - - if (elements.length === 0) return []; - - // Collect candidate indices from all hash tables - const candidates = new Set(); - - for (let t = 0; t < this._numHashTables; t++) { - const hash = this._computeHash(query, t); - const table = this._hashTables[t]; - const bucket = table.get(hash); - - if (bucket) { - for (const idx of bucket) { - if (idx !== undefined) { - candidates.add(idx); - } - } - } - } - - // If insufficient candidates found, fall back to linear search - if (candidates.size < k) { - // Add more candidates from all buckets or entire dataset - //const needed = k - candidates.size; - - // First, try to add from neighboring buckets (different hashes) - for (let t = 0; t < this._numHashTables && candidates.size < k; t++) { - const table = this._hashTables[t]; - for (const [, bucket] of table) { - for (const idx of bucket) { - if (idx !== undefined) { - candidates.add(idx); - if (candidates.size >= k) break; - } - } - if (candidates.size >= k) break; - } - } - - // If still not enough, add from entire dataset - for (let i = 0; i < elements.length && candidates.size < k; i++) { - candidates.add(i); - } - } - - // Compute exact distances for candidates - /** @type {Heap<{ index: number; distance: number }>} */ - const best = new Heap(null, (d) => d.distance, "max"); - - for (const idx of candidates) { - const element = elements[idx]; - if (!element || element.length !== query.length) continue; - - const dist = metric(query, element); - - if (best.length < k) { - best.push({ index: idx, distance: dist }); - } else if (dist < (best.first?.value ?? Infinity)) { - best.pop(); - best.push({ index: idx, distance: dist }); - } - } - - // Convert to result format - /** @type {{ element: T; index: number; distance: number }[]} */ - const result = []; - while (best.length > 0) { - const item = /** @type {{ element: { index: number; distance: number }; value: number }} */ ( - best.pop() - ); - result.push({ - element: elements[item.element.index], - index: item.element.index, - distance: item.value, - }); - } - - return result.reverse(); - } - - /** - * @param {number} i - * @param {number} [k=5] - * @returns {{ element: T; index: number; distance: number }[]} - */ - search_by_index(i, k = 5) { - if (i < 0 || i >= this._elements.length) return []; - return this.search(this._elements[i], k); - } -} -/** @import { ParametersNaiveKNN } from "./index.js" */ + return F.sort((a, b) => a[2] - b[2]); + } -/** - * Naive KNN implementation using a distance matrix. - * - * This implementation pre-computes the entire distance matrix and performs - * an exhaustive search. Best suited for small datasets or when a distance - * matrix is already available. - * - * @template {number[] | Float64Array} T - * @category KNN - * @class - * @extends KNN - */ -class NaiveKNN extends KNN { - /** - * Generates a KNN list with given `elements`. - * - * @param {T[]} elements - Elements which should be added to the KNN list - * @param {ParametersNaiveKNN} parameters - */ - constructor(elements, parameters = {}) { - const params = Object.assign({ metric: euclidean, seed: 1212 }, parameters); - super(elements, params); - const N = - this._elements instanceof Matrix - ? /** @type {any} */ (this._elements).shape[0] - : this._elements.length; - if (this._parameters.metric === "precomputed") { - this._D = Matrix.from( - /** @type {number[][] | Float64Array[]} */ (/** @type {any} */ (this._elements)), - ); - } else { - this._D = distance_matrix( - /** @type {number[][] | Float64Array[]} */ (this._elements), - this._parameters.metric, - ); - } - - /** @type {Heap<{ value: number; index: number }>[]} */ - this.KNN = []; - for (let row = 0; row < N; ++row) { - const distances = this._D.row(row); - /** @type {Heap<{ value: number; index: number }>} */ - const H = new Heap(null, (d) => d.value, "min"); - for (let j = 0; j < N; ++j) { - H.push({ - value: distances[j], - index: j, - }); - } - this.KNN.push(H); - } - } - - /** - * @param {number} i - * @param {number} k - */ - search_by_index(i, k = 5) { - if (this._parameters.metric === "precomputed") { - const H = this.KNN[i]; - /** @type {{ element: T; index: number; distance: number }[]} */ - const result = []; - const data = H.toArray(); // Get array representation - const temp_heap = new Heap(data, (d) => d.value, "min"); - const N = - this._elements instanceof Matrix - ? /** @type {any} */ (this._elements).shape[0] - : this._elements.length; - for (let j = 0; j < Math.min(k, N); ++j) { - const node = temp_heap.pop(); - if (!node) break; - result.push({ - element: /** @type {T} */ ( - this._elements instanceof Matrix - ? /** @type {any} */ (this._elements).row(node.element.index) - : this._elements[node.element.index] - ), - index: /** @type {number} */ (node.element.index), - distance: /** @type {number} */ (node.value), - }); - } - return result; - } - return this.search( - /** @type {T} */ ( - this._elements instanceof Matrix - ? /** @type {any} */ (this._elements).row(i) - : this._elements[i] - ), - k, - ); - } - - /** - * @param {T} t - Query element. - * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5` - * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors. - */ - search(t, k = 5) { - if (this._parameters.metric === "precomputed") { - throw new Error( - "Search by query element is only possible when not using a precomputed distance matrix!", - ); - } - /** @type {import("../metrics/index.js").Metric} */ - const metric = /** @type {any} */ (this._parameters.metric); - - const isMatrix = this._elements instanceof Matrix; - const elementsAny = /** @type {any} */ (this._elements); - const N = isMatrix ? elementsAny.shape[0] : this._elements.length; - - // Compute distances from query to ALL points - const distances = []; - for (let i = 0; i < N; i++) { - const element = /** @type {T} */ (isMatrix ? elementsAny.row(i) : this._elements[i]); - distances.push({ - element: element, - index: i, - distance: metric(t, element), - }); - } - - // Sort by distance and return k nearest - distances.sort((a, b) => a.distance - b.distance); - return distances.slice(0, k); - } -} + /** Initializes TopoMap. Sets all projcted points to zero, and computes a minimum spanning tree. */ + init() { + const { metric } = this._parameters; + this.Y = new Matrix(this._N, 2, 0); + this._Emst = this._make_minimum_spanning_tree(metric); + this._is_initialized = true; + return this; + } -/** @import {ParametersNNDescent} from "./index.js" */ -/** - * - * @template {number[] | Float64Array} T - * @typedef {Object} NNDescentElement - * @property {T} value - * @property {number} index - * @property {boolean} flag - */ + /** + * Returns true if Point C is left of line AB. + * + * @private + * @param {Float64Array} PointA - Point A of line AB + * @param {Float64Array} PointB - Point B of line AB + * @param {Float64Array} PointC - Point C + * @returns {boolean} + */ + __hull_cross([ax, ay], [bx, by], [sx, sy]) { + return (bx - ax) * (sy - ay) - (by - ay) * (sx - ax) <= 0; + } -/** - * @template {number[] | Float64Array} T - * @typedef {Object} NNDescentNeighbor - * @property {T} value - * @property {number} index - * @property {number} distance - * @property {boolean} [flag] - */ + /** + * Computes the convex hull of the set of Points S + * + * @private + * @param {Float64Array[]} S - Set of Points. + * @returns {Float64Array[]} Convex hull of S. Starts at the bottom-most point and continues counter-clockwise. + * @see {@link https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain#JavaScript} + */ + __hull(S) { + const points = S.sort(([x1, y1], [x2, y2]) => y1 - y2 || x1 - x2); + const N = points.length; + if (N <= 2) return points; -/** - * NN-Descent - * - * An efficient graph-based approximate nearest neighbor search algorithm. - * It works by iteratively improving a neighbor graph using the fact that - * "neighbors of neighbors are likely to be neighbors". - * - * @class - * @category KNN - * @template {number[] | Float64Array} T - * @extends KNN - * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf|NN-Descent Paper} - */ -class NNDescent extends KNN { - /** - * @private - * @type {KNNHeap[]} - */ - _B = []; - /** - * @private - * @type {NNDescentNeighbor[][]} - */ - nn = []; - - /** - * @param {T[]} elements - Called V in paper. - * @param {Partial} parameters - * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf} - */ - constructor(elements, parameters = {}) { - super( - elements, - /** @type {ParametersNNDescent} */ ( - Object.assign({ metric: euclidean, K: 10, rho: 1, delta: 1e-3, seed: 1212 }, parameters) - ), - ); - this._N = elements.length; - this._randomizer = new Randomizer(this._parameters.seed); - this._sample_size = this._parameters.samples * this._parameters.rho; - - this._nndescent_elements = elements.map((e, i) => { - return { - value: e, - index: i, - flag: true, - }; - }); - - if (elements) { - this.add(elements); - } - } - - /** - * Samples Array A with sample size. - * - * @private - * @template U - * @param {U[]} A - * @returns {U[]} - */ - _sample(A) { - const n = A.length; - const sample_size = this._sample_size; - if (sample_size > n) { - return A; - } else { - const randomizer = this._randomizer; - return randomizer.choice(A, sample_size); - } - } - - /** - * @private - * @param {KNNHeap} B - * @param {NNDescentNeighbor} u - * @returns {number} - */ - _update(B, u) { - if (B.set.has(u.index)) return 0; - - const worst = B.first; - if (worst && B.length >= this._parameters.samples) { - const dist = B._accessor(u); - const worst_dist = B._accessor(worst.element); - if (dist >= worst_dist) { - return 0; // u is worse than the worst neighbor - } - } - - B.push(u); - u.flag = true; - if (B.length > this._parameters.samples) { - B.pop(); - } - return 1; - } - - /** - * @private - * @param {(KNNHeap | null)[]} B - * @returns {NNDescentNeighbor[][]} - */ - _reverse(B) { - const N = this._N; - const R = new Array(N); - for (let i = 0; i < N; i++) { - R[i] = []; - } - for (let j = 0; j < N; j++) { - const Bi = B[j]; - if (Bi) { - const Bjdata = Bi.data(); - for (const neighbor of Bjdata) { - const v = neighbor.index; - R[v].push(neighbor); - } - } - } - return R; - } - - /** - * @param {T[]} elements - * @returns {this} - */ - add(elements) { - const randomizer = this._randomizer; - const metric = this._parameters.metric; - const K = this._parameters.samples; - const delta = this._parameters.delta; - const N = elements.length; - this._N = N; - /** @type {KNNHeap[]} */ - const B = []; - this._B = B; - for (let i = 0; i < N; i++) { - const e = elements[i]; - const sample = randomizer - .choice( - elements.map((el, idx) => ({ el, idx })), - K, - ) - .map((d) => { - return { index: d.idx, distance: metric(d.el, e), value: d.el }; - }); - const Bi = new KNNHeap(sample, (d) => d.distance, "max"); - B.push(Bi); - } - - let c = Infinity; - let old_c = -Infinity; - while (c > delta * N * K && c !== old_c) { - const old_ = new Array(N); - const new_ = new Array(N); - for (let i = 0; i < N; i++) { - const Bi = B[i].data(); - const falseBs = Bi.filter((d) => !d.flag); - const trueBs = this._sample(Bi.filter((d) => d.flag)); - for (const d of trueBs) { - d.flag = false; - } - old_[i] = new KNNHeap(falseBs, (d) => d.distance, "max"); - new_[i] = new KNNHeap(trueBs, (d) => d.distance, "max"); - } - const old_reverse = this._reverse(old_); - const new_reverse = this._reverse(new_); - old_c = c; - c = 0; - for (let i = 0; i < N; i++) { - for (const o of this._sample(old_reverse[i])) { - old_[i].push(o); - } - for (const n of this._sample(new_reverse[i])) { - new_[i].push(n); - } - - const new_i = new_[i].data(); - const old_i = old_[i].data(); - const n1 = new_i.length; - const n2 = old_i.length; - for (let j = 0; j < n1; j++) { - const u1 = new_i[j]; - const Bu1 = B[u1.index]; - for (let k = 0; k < n1; k++) { - const u2 = new_i[k]; - if (u1.index === u2.index) continue; - const Bu2 = B[u2.index]; - c += this._update(Bu2, u1); - c += this._update(Bu1, u2); - } - for (let k = 0; k < n2; k++) { - const u2 = old_i[k]; - if (u1.index === u2.index) continue; - const Bu2 = B[u2.index]; - c += this._update(Bu2, u1); - c += this._update(Bu1, u2); - } - } - } - } - this.nn = this._B.map((heap) => heap.data()); - return this; - } - - /** - * @param {T} x - * @param {number} [k=5] Default is `5` - * @returns {{ element: T, index: number; distance: number }[]} - */ - search(x, k = 5) { - const metric = this._parameters.metric; - const N = this._N; - const elements = this._elements; - - if (N === 0) return []; - const xLength = x.length; - - // Initialize candidate pool - const visited = new Set(); - /** @type {{index: number, dist: number, evaluated: boolean}[]} */ - let pool = []; - - // Randomly pick initial candidates - const randomizer = this._randomizer; - for (let i = 0; i < Math.min(N, Math.max(k * 10, 50)); i++) { - let rnd; - do { - rnd = randomizer.random_int % N; - } while (visited.has(rnd)); - visited.add(rnd); - - const element = elements[rnd]; - if (!element || element.length !== xLength) continue; - - pool.push({ - index: rnd, - dist: metric(x, element), - evaluated: false, - }); - } - - let searching = true; - while (searching) { - pool.sort((a, b) => a.dist - b.dist); - // keep the top subset for exploration - pool = pool.slice(0, Math.max(k * 5, 50)); - - searching = false; - for (let i = 0; i < pool.length; i++) { - const candidate = pool[i]; - if (candidate.evaluated) continue; - - candidate.evaluated = true; - searching = true; - - // get neighbors of this candidate from graph - const neighbors = this.nn[candidate.index]; - if (!neighbors) continue; - - for (const neighbor of neighbors) { - const n_idx = neighbor.index; - if (!visited.has(n_idx)) { - visited.add(n_idx); - const element = elements[n_idx]; - if (element && element.length === xLength) { - pool.push({ - index: n_idx, - dist: metric(x, element), - evaluated: false, - }); + const lower = []; + for (let i = 0; i < N; ++i) { + while ( + lower.length >= 2 && + this.__hull_cross(lower[lower.length - 2], lower[lower.length - 1], points[i]) + ) { + lower.pop(); + } + lower.push(points[i]); + } + const upper = []; + for (let i = N - 1; i >= 0; --i) { + while ( + upper.length >= 2 && + this.__hull_cross(upper[upper.length - 2], upper[upper.length - 1], points[i]) + ) { + upper.pop(); } - } + upper.push(points[i]); } - // Don't break here! Look at more candidates per iteration for better convergence - // break; - } + upper.pop(); + lower.pop(); + return lower.concat(upper); } - pool.sort((a, b) => a.dist - b.dist); - - /** @type {{ element: T, index: number; distance: number }[]} */ - const result = []; - for (let i = 0; i < Math.min(k, pool.length); i++) { - const item = pool[i]; - result.push({ - element: elements[item.index], - index: item.index, - distance: item.dist, - }); + /** + * Finds the angle to rotate Point A and B to lie on a line parallel to the x-axis. + * + * @private + * @param {Float64Array} PointA + * @param {Float64Array} PointB + * @returns {{ sin: number; cos: number }} Object containing the sinus- and cosinus-values for a rotation. + */ + __findAngle([p1x, p1y], [p2x, p2y]) { + const n = euclidean([p1x, p1y], [p2x, p2y]); + if (n === 0) + return { + sin: 0, + cos: 1, + }; + const vec = [(p2x - p1x) / n, (p2y - p1y) / n]; + const cos = vec[0]; + let sin = Math.sqrt(1 - cos * cos); + sin = vec[1] >= 0 ? -sin : sin; + return { + sin: sin, + cos: cos, + }; } - return result; - } - - /** - * @param {number} i - * @param {number} [k=5] Default is `5` - * @returns {{ element: T; index: number; distance: number }[]} - */ - search_by_index(i, k = 5) { - // Use regular search with the element at index i - const elements = this._elements; - if (i < 0 || i >= elements.length) return []; - - const element = elements[i]; - if (!element) return []; - - return this.search(element, k); - } -} -/** - * @template {number[] | Float64Array} U - * @typedef {Object} HeapEntry - * @property {NNDescentNeighbor} element - * @property {number} value - */ + /** + * @private + * @param {Float64Array[]} hull + * @param {Float64Array} p + * @param {boolean} topEdge + * @returns {{ sin: number; cos: number; tx: number; ty: number }} + */ + __align_hull(hull, p, topEdge) { + let v = -1; + /** @type {number} */ + let d2 = -Infinity; + for (let i = 0; i < hull.length; ++i) { + const d = euclidean(hull[i], p); + if (v === -1) { + d2 = d; + v = i; + } else { + if (d2 > d) { + d2 = d; + v = i; + } + } + } -/** - * @template {number[] | Float64Array} U - * @extends {Heap>} - */ -class KNNHeap extends Heap { - /** @type {Set} */ - set; - - /** - * @param {NNDescentNeighbor[]} elements - * @param {(d: NNDescentNeighbor) => number} accessor - * @param {"max" | "min"} comparator - */ - constructor(elements, accessor, comparator) { - super(null, accessor, comparator); - this.set = new Set(); - if (elements) { - for (const element of elements) { - this.push(element); - } - } - } - - /** - * @param {NNDescentNeighbor} element - * @returns {KNNHeap} - */ - push(element) { - const set = this.set; - if (set.has(element.index)) { - return this; - } else { - set.add(element.index); - super.push(element); - return this; - } - } - - /** @returns {{ element: NNDescentNeighbor; value: number } | null} */ - pop() { - const result = super.pop(); - if (result?.element) { - this.set.delete(result.element.index); - return result; - } - return null; - } - - /** @returns {NNDescentNeighbor[]} */ - data() { - return this._container.map((d) => d.element); - } -} + const v1 = hull[v]; + let v2; + if (topEdge) { + v2 = hull[(v + 1) % hull.length]; + } else { + v2 = hull[(v - 1 + hull.length) % hull.length]; + } -/** @import {InputType} from "../index.js" */ -/** @import {ParametersSMACOF} from "./index.js" */ + /** @type {{ sin?: number; cos?: number; tx: number; ty: number }} */ + const transformation = { + tx: -v1[0], + ty: -v1[1], + }; -/** - * Metric Multidimensional Scaling (MDS) via SMACOF. - * - * SMACOF (Scaling by Majorizing a Complicated Function) is an iterative majorization - * algorithm for solving metric multidimensional scaling problems, which aims to - * minimize the stress function. - * - * @class - * @template {InputType} T - * @extends DR - * @category Dimensionality Reduction - * @see {@link MDS} for the classical approach. - */ -class SMACOF extends DR { - /** - * SMACOF for MDS. - * - * @param {T} X - The high-dimensional data or precomputed distance matrix. - * @param {Partial} [parameters] - Object containing parameterization. - */ - constructor(X, parameters = {}) { - super(X, { d: 2, metric: euclidean, seed: 1212, iterations: 300, epsilon: 1e-4 }, parameters); - } - - /** - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - *generator() { - this.check_init(); - const X = this.X; - const rows = this._N; - const d = /** @type {number} */ (this.parameter("d")); - const metric = /** @type {typeof euclidean | "precomputed"} */ (this.parameter("metric")); - const iterations = /** @type {number} */ (this.parameter("iterations")); - const epsilon = /** @type {number} */ (this.parameter("epsilon")); - - const target_distances = metric === "precomputed" ? X : distance_matrix(X, metric); - - let Z = new Matrix(rows, d, () => (this._randomizer.random - 0.5) * 2); - - // Center Z - for (let j = 0; j < d; ++j) { - const col = Z.col(j); - const mean = col.reduce((a, b) => a + b, 0) / rows; - for (let i = 0; i < rows; ++i) { - Z.sub_entry(i, j, mean); - } - } - - this.Y = /** @type {Matrix} */ (Z); // Initial state - - let prev_stress = Infinity; - - if (!(iterations > 0)) { - yield this.projection; - return this.projection; - } - - for (let iter = 0; iter < iterations; ++iter) { - const B = new Matrix(rows, rows, 0); - - for (let i = 0; i < rows; ++i) { - let bii = 0; - const z_i = Z.row(i); - for (let j = 0; j < rows; ++j) { - if (i === j) continue; - const z_j = Z.row(j); - const dist_Z = euclidean(z_i, z_j); - const dist_target = target_distances.entry(i, j); - - let bij = 0; - if (dist_Z > 1e-12) { - bij = -dist_target / dist_Z; - } - B.set_entry(i, j, bij); - bii -= bij; - } - B.set_entry(i, i, bii); - } - - // Z_new = 1/N * B(Z) * Z - const Z_new = B.dot(Z)._apply(rows, (val, n) => val / n); - - this.Y = /** @type {Matrix} */ (Z_new); - Z = /** @type {Matrix} */ (Z_new); - - // Calculate stress - let stress_num = 0; - let stress_den = 0; - for (let i = 0; i < rows; ++i) { - const z_i = Z.row(i); - for (let j = i + 1; j < rows; ++j) { - const z_j = Z.row(j); - const dist_Y = euclidean(z_i, z_j); - const diff = target_distances.entry(i, j) - dist_Y; - stress_num += diff * diff; - stress_den += target_distances.entry(i, j) ** 2; - } - } - const current_stress = Math.sqrt(stress_num / Math.max(stress_den, 1e-12)); - - yield this.projection; - - if (Math.abs(prev_stress - current_stress) < epsilon) { - break; - } - prev_stress = current_stress; - } - return this.projection; - } - - /** - * @returns {T} - */ - transform() { - const gen = this.generator(); - let res = /** @type {T} */ (this.X); - for (const step of gen) { - res = step; - } - return res; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X, parameters) { - const dr = new SMACOF(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new SMACOF(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new SMACOF(X, parameters); - return dr.transform_async(); - } -} + if (hull.length >= 2) { + const { sin, cos } = this.__findAngle(v1, v2); + transformation.sin = sin; + transformation.cos = cos; + } else { + transformation.sin = 0; + transformation.cos = 1; + } -/** @import {InputType} from "../index.js" */ -/** @import {ParametersISOMAP} from "./index.js" */ -/** @import {EigenArgs} from "../linear_algebra/index.js" */ + return /** @type {{ sin: number; cos: number; tx: number; ty: number }} */ (transformation); + } -/** - * Isomap (Isometric Mapping) - * - * A nonlinear dimensionality reduction algorithm that uses geodesic distances - * between points on a manifold to perform embedding. It builds a neighborhood - * graph and uses MDS on the shortest-path distances. - * - * @class - * @template {InputType} T - * @extends DR - * @category Dimensionality Reduction - * @see {@link LLE} for another nonlinear alternative - */ -class ISOMAP extends DR { - /** - * Isometric feature mapping (ISOMAP). - * - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - * @see {@link https://doi.org/10.1126/science.290.5500.2319} - */ - constructor(X, parameters = {}) { - /** @type {ParametersISOMAP} */ - const defaults = { - neighbors: -Infinity, - d: 2, - metric: euclidean, - seed: 1212, - project: "MDS", - eig_args: {}, - }; - super(X, defaults, parameters); - - this.defaults = defaults; - - if (this._parameters.neighbors === -Infinity) { - this.parameter( - "neighbors", - Math.min(Math.max(Math.floor(this.X.shape[0] / 10), 2), this._N - 1), - ); - } - - const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); - if (!Object.hasOwn(eig_args, "seed")) { - eig_args.seed = this._randomizer; - } - } - - /** - * Computes the projection. - * - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - *generator() { - yield this.transform(); - return this.projection; - } - - /** - * @returns {T} - */ - transform() { - this.check_init(); - const X = this.X; - const rows = this._N; - const d = /** @type {number} */ (this.parameter("d")); - const metric = /** @type {typeof euclidean} */ (this.parameter("metric")); - const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); - const neighbors = /** @type {number} */ (this.parameter("neighbors")); - // TODO: make knn extern and parameter for constructor or transform? - const D = new Matrix(rows, rows, 0); - D.shape = [rows, rows, (i, j) => (i <= j ? metric(X.row(i), X.row(j)) : D.entry(j, i))]; - - /** @type {{ index: number; distance: number }[][]} */ - const kNearestNeighbors = []; - const tree = new BallTree(X.to2dArray(), { - metric, - seed: /** @type {number} */ (this.parameter("seed")), - }); - for (let i = 0; i < rows; ++i) { - // BallTree search returns elements including the queried point itself (at distance 0). - // Request neighbors + 1 and slice off the first one (which should be the query point). - const neighborsList = tree.search_by_index(i, neighbors + 1); - kNearestNeighbors.push( - neighborsList.slice(1).map((n) => ({ - index: n.index, - distance: n.distance, - })), - ); - } - - // ISOMAP requires an undirected/symmetric nearest neighbor graph. - // If i is a nearest neighbor of j, then j should be connected to i as well. - for (let i = 0; i < rows; ++i) { - for (const neighbor of kNearestNeighbors[i]) { - const j = neighbor.index; - const d = neighbor.distance; - const reciprocal_edge = kNearestNeighbors[j].find((n) => n.index === i); - if (!reciprocal_edge) { - kNearestNeighbors[j].push({ index: i, distance: d }); - } - } - } - - /*D = dijkstra(kNearestNeighbors);*/ - // compute shortest paths using Dijkstra's algorithm - // TODO: make extern - const G = new Matrix(rows, rows, Infinity); - - for (let i = 0; i < rows; ++i) { - G.set_entry(i, i, 0); - const H = new Heap([{ index: i, distance: 0 }], (d) => d.distance, "min"); - - while (!H.empty) { - const item = H.pop(); - if (!item) break; - - const u = item.element.index; - const dist_u = item.element.distance; - - if (dist_u > G.entry(i, u)) continue; - - for (const neighbor of kNearestNeighbors[u]) { - const v = neighbor.index; - const alt = dist_u + neighbor.distance; - if (alt < G.entry(i, v)) { - G.set_entry(i, v, alt); - H.push({ index: v, distance: alt }); - } - } - } - } - - let max_val = 0; - for (let i = 0; i < rows; i++) { - for (let j = 0; j < rows; j++) { - const val = G.entry(i, j); - if (val !== Infinity && val > max_val) max_val = val; - } - } - const big_val = max_val * 10; - - const project = /** @type {"MDS" | "SMACOF"} */ (this.parameter("project")); - - if (project === "SMACOF") { - // Apply SMACOF metric MDS to the distance matrix directly - const D_matrix = new Matrix(rows, rows, (i, j) => { - const val = G.entry(i, j); - return val === Infinity ? big_val : val; - }); - const smacof = new SMACOF(D_matrix, { - metric: "precomputed", - d, - seed: this.parameter("seed"), - }); - smacof.transform(); - this.Y = smacof.Y; - } else { - // "MDS" (Classical MDS) via Eigendecomposition of double-centered squared distance matrix - const D_sq = new Matrix(rows, rows, (i, j) => { - let val = G.entry(i, j); - if (val === Infinity) val = big_val; - return val * val; - }); - - const ai_ = D_sq.meanCols(); - const a_j = D_sq.meanRows(); - const a__ = D_sq.mean(); - const B = new Matrix(rows, rows, (i, j) => -0.5 * (D_sq.entry(i, j) - ai_[i] - a_j[j] + a__)); - - // compute d eigenvectors - const { eigenvectors: V } = simultaneous_poweriteration(B, d, eig_args); - this.Y = Matrix.from(V).transpose(); - } - // return embedding - return this.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X, parameters) { - const dr = new ISOMAP(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new ISOMAP(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new ISOMAP(X, parameters); - return dr.transform_async(); - } -} + /** + * @private + * @param {Float64Array} Point - The point which should get transformed. + * @param {{ sin: number; cos: number; tx: number; ty: number }} Transformation - Contains the values for + * translation and rotation. + */ + __transform([px, py], { tx, ty, sin, cos }) { + const x = px + tx; + const y = py + ty; + const xx = x * cos - y * sin; + const yy = x * sin + y * cos; + return [xx, yy]; + } -/** @import {InputType} from "../index.js" */ -/** @import {ParametersLDA} from "./index.js" */ -/** @import {EigenArgs} from "../linear_algebra/index.js" */ + /** + * Calls `__transform` for each point in Set C + * + * @private + * @param {Float64Array[]} C - Set of points. + * @param {{ sin: number; cos: number; tx: number; ty: number }} t - Transform object. + * @param {number} yOffset - Value to offset set C. + */ + __transform_component(C, t, yOffset) { + const N = C.length; + for (let i = 0; i < N; ++i) { + const c = C[i]; + const [cx, cy] = this.__transform(c, t); + c[0] = cx; + c[1] = cy + yOffset; + } + } -/** - * Linear Discriminant Analysis (LDA) - * - * A supervised dimensionality reduction technique that finds the axes that - * maximize the separation between multiple classes. - * - * @class - * @template {InputType} T - * @extends DR - * @category Dimensionality Reduction - */ -class LDA extends DR { - /** - * Linear Discriminant Analysis. - * - * @param {T} X - The high-dimensional data. - * @param {Partial & { labels: any[] | Float64Array }} parameters - Object containing parameterization of the DR method. - * @see {@link https://onlinelibrary.wiley.com/doi/10.1111/j.1469-1809.1936.tb02137.x} - */ - constructor(X, parameters) { - super(X, { labels: parameters.labels, d: 2, seed: 1212, eig_args: {} }, parameters); - const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); - if (!Object.hasOwn(eig_args, "seed")) { - eig_args.seed = this._randomizer; - } - } - - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - *generator() { - yield this.transform(); - return this.projection; - } - - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {T} - The projected data. - */ - transform() { - const X = this.X; - const [rows, cols] = X.shape; - const { d, labels, eig_args } = this._parameters; - if (labels === null || labels.length !== rows) { - throw new Error("LDA needs parameter label to every datapoint to work!"); - } - - /** @type {Record} */ - const unique_labels = {}; - let label_id = 0; - labels.forEach((l, i) => { - if (l in unique_labels) { - unique_labels[l].count++; - unique_labels[l].rows.push(X.row(i)); - } else { - unique_labels[l] = { - id: label_id++, - count: 1, - rows: [X.row(i)], - }; - } - }); - - // create X_mean and vector means; - const X_mean = X.meanCols(); - const V_mean = new Matrix(label_id, cols); - for (const label in unique_labels) { - const V = Matrix.from(unique_labels[label].rows); - const v_mean = V.meanCols(); - for (let j = 0; j < cols; ++j) { - V_mean.set_entry(unique_labels[label].id, j, v_mean[j]); - } - } - // scatter_between - let S_b = new Matrix(cols, cols); - for (const label in unique_labels) { - const v = V_mean.row(unique_labels[label].id); - const m = Matrix.from([v]).sub(Matrix.from([X_mean])); - const N = unique_labels[label].count; - S_b = S_b.add(m.transDot(m).mult(N)); - } - - // scatter_within - let S_w = new Matrix(cols, cols); - for (const label in unique_labels) { - const v = V_mean.row(unique_labels[label].id); - const R = unique_labels[label].rows; - for (let i = 0, n = unique_labels[label].count; i < n; ++i) { - const row_v = Matrix.from([R[i]]).sub(Matrix.from([v])); - S_w = S_w.add(row_v.transDot(row_v)); - } - } - - const { eigenvectors: EV } = simultaneous_poweriteration( - S_w.inverse().dot(S_b), - d || Math.min(cols, label_id - 1), - eig_args, - ); - const V = Matrix.from(EV).transpose(); - this.Y = X.dot(V); - - // return embedding - return this.projection; - } - - /** - * @template {InputType} T - * @template {{ seed?: number }} Para - * @param {T} X - * @param {Para} parameters - * @returns {T} - */ - static transform(X, parameters) { - // @ts-expect-error: LDA requires labels, but DR static transform doesn't - const dr = new LDA(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @template {{ seed?: number }} Para - * @param {T} X - * @param {Para} parameters - * @returns {Generator} - */ - static *generator(X, parameters) { - // @ts-expect-error: LDA requires labels, but DR static generator doesn't - const dr = new LDA(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @template {{ seed?: number }} Para - * @param {T} X - * @param {Para} parameters - * @returns {Promise} - */ - static async transform_async(X, parameters) { - // @ts-expect-error: LDA requires labels, but DR static transform doesn't - const dr = new LDA(X, parameters); - return dr.transform_async(); - } -} + /** + * @private + * @param {Float64Array} root_u - Root of component u + * @param {Float64Array} root_v - Root of component v + * @param {Float64Array} p_u - Point u + * @param {Float64Array} p_v - Point v + * @param {number} w - Edge weight w + * @param {DisjointSet} components - The disjoint set containing the components + */ + __align_components(root_u, root_v, p_u, p_v, w, components) { + if (!components) throw new Error("components not provided!"); + const u_children = components.get_children(root_u); + const v_children = components.get_children(root_v); + if (!u_children || !v_children) throw new Error("should not happen!"); -/** @import {InputType} from "../index.js" */ -/** @import {ParametersLLE} from "./index.js" */ -/** @import {EigenArgs} from "../linear_algebra/index.js" */ + const points_u = [...u_children]; + const points_v = [...v_children]; + + const hull_u = this.__hull(points_u); + const hull_v = this.__hull(points_v); + + const t_u = this.__align_hull(hull_u, p_u, false); + const t_v = this.__align_hull(hull_v, p_v, true); + + this.__transform_component(points_u, t_u, 0); + this.__transform_component(points_v, t_v, w); + } + + /** + * Transforms the inputdata `X` to dimensionality 2. + * + * @returns {T} + */ + transform() { + if (!this._is_initialized) this.init(); + if (!this._Emst) throw new Error("Call init() first!"); + const Emst = this._Emst; + const Y = this.Y.to2dArray(); + /** @type {DisjointSet} */ + const components = new DisjointSet( + Y, + // Y.map((y, i) => { + // y.i = i; + // return y; + // }), + ); -/** - * Locally Linear Embedding (LLE) - * - * A nonlinear dimensionality reduction technique that preserves local - * linear relationships between points. It represents each point as a linear - * combination of its neighbors. - * - * @class - * @template {InputType} T - * @extends DR - * @category Dimensionality Reduction - * @see {@link ISOMAP} for another nonlinear alternative - */ -class LLE extends DR { - /** - * Locally Linear Embedding. - * - * @param {T} X - The high-dimensional data. - * @param {Partial} parameters - Object containing parameterization of the DR method. - * @see {@link https://doi.org/10.1126/science.290.5500.2323} - */ - constructor(X, parameters) { - super( - X, - { - neighbors: -Infinity, - d: 2, - metric: euclidean, - seed: 1212, - eig_args: {}, - }, - parameters, - ); - if (this._parameters.neighbors === -Infinity) { - this.parameter("neighbors", Math.min(Math.max(Math.floor(this._N / 10), 2), this._N - 1)); - } - - const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); - if (!Object.hasOwn(eig_args, "seed")) { - eig_args.seed = this._randomizer; - } - } - - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - *generator() { - yield this.transform(); - return this.projection; - } - - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {T} - */ - transform() { - const X = this.X; - const rows = this._N; - const cols = this._D; - const neighbors = /** @type {number} */ (this.parameter("neighbors")); - const d = /** @type {number} */ (this.parameter("d")); - const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); - const metric = /** @type {typeof euclidean} */ (this.parameter("metric")); - const nN = k_nearest_neighbors(X, neighbors, metric); - const O = new Matrix(neighbors, 1, 1); - const W = new Matrix(rows, rows); + for (const [u, v, w] of Emst) { + const p_u = Y[u]; + const p_v = Y[v]; + const component_u = components.find(p_u); + const component_v = components.find(p_v); + if (!component_u || !component_v) throw new Error("Should not happen!"); + if (component_u === component_v) continue; + this.__align_components(component_u, component_v, p_u, p_v, w, components); + components.union(component_u, component_v); + } + return this.projection; + } - for (let row = 0; row < rows; ++row) { - const nN_row = nN[row]; - const Z = new Matrix(neighbors, cols, (i, j) => X.entry(nN_row[i].j, j) - X.entry(row, j)); - const C = Z.dotTrans(Z); - if (neighbors > cols) { - const C_trace = neumair_sum(C.diag()) / 1000; - for (let j = 0; j < neighbors; ++j) { - C.add_entry(j, j, C_trace); - } - } - // reconstruct; - let w = Matrix.solve_CG(C, O, this._randomizer); - w = w.divide(w.sum()); - for (let j = 0; j < neighbors; ++j) { - W.set_entry(row, nN_row[j].j, w.entry(j, 0)); - } - } - // comp embedding - const I = new Matrix(rows, rows, "identity"); - const IW = I.sub(W); - const M = IW.transDot(IW); - - // M is symmetric positive semi-definite. Smallest eigenvalue is 0 (ones vector). - // To find smallest eigenvalues of M, we can find largest of (C*I - M) - // Upper bound for max eigenvalue: Frobenius norm or sum of absolute values - const C = M.mean() * rows * 2; // Safe upper bound for a sparse-ish M in LLE - const CI_M = new Matrix(rows, rows, (i, j) => (i === j ? C : 0) - M.entry(i, j)); - - const { eigenvectors: V } = simultaneous_poweriteration(CI_M, d + 1, eig_args); - // Skip the first eigenvector (the ones vector corresponding to eigenvalue C) - this.Y = Matrix.from(V.slice(1, 1 + d)).T; - - // return embedding - return this.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {T} - */ - static transform(X, parameters) { - const dr = new LLE(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new LLE(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new LLE(X, parameters); - return dr.transform_async(); - } -} + /** + * Transforms the inputdata `X` to dimensionality 2. + * + * @returns {Generator} + */ + *generator() { + if (!this._is_initialized) this.init(); + if (!this._Emst) throw new Error("call init() first!"); + const Emst = this._Emst; + const Y = this.Y.to2dArray(); + const components = new DisjointSet( + Y, + // Y.map((y, i) => { + // y.i = i; + // return y; + // }), + ); -/** @import {InputType} from "../index.js" */ -/** @import {ParametersMDS} from "./index.js" */ -/** @import {EigenArgs} from "../linear_algebra/index.js" */ + for (const [u, v, w] of Emst) { + const p_u = Y[u]; + const p_v = Y[v]; + const component_u = components.find(p_u); + const component_v = components.find(p_v); + if (!component_u || !component_v) throw new Error("should not happen!"); + if (component_u === component_v) continue; + this.__align_components(component_u, component_v, p_u, p_v, w, components); + components.union(component_u, component_v); + yield this.projection; + } + return this.projection; + } -/** - * Classical Multidimensional Scaling (MDS) - * - * A linear dimensionality reduction technique that seeks to preserve the - * pairwise distances between points as much as possible in the lower-dimensional - * space. - * - * @class - * @template {InputType} T - * @extends DR - * @category Dimensionality Reduction - * @see {@link PCA} for another linear alternative - */ -class MDS extends DR { - /** - * Classical MDS. - * - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - */ - constructor(X, parameters = {}) { - super(X, { d: 2, metric: euclidean, seed: 1212, eig_args: {} }, parameters); - const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); - if (!Object.hasOwn(eig_args, "seed")) { - eig_args.seed = this._randomizer; - } - } - - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - *generator() { - yield this.transform(); - return this.projection; - } - - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {T} - */ - transform() { - const X = this.X; - const rows = X.shape[0]; - const d = /** @type {number} */ (this.parameter("d")); - const metric = /** @type {typeof euclidean | "precomputed"} */ (this.parameter("metric")); - const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); - const A = metric === "precomputed" ? X : distance_matrix(X, metric); - - const D_sq = new Matrix(rows, rows, (i, j) => { - const val = A.entry(i, j); - return val * val; - }); - - const ai_ = D_sq.meanCols(); - const a_j = D_sq.meanRows(); - const a__ = D_sq.mean(); - - this._d_X = A; - const B = new Matrix(rows, rows, (i, j) => -0.5 * (D_sq.entry(i, j) - ai_[i] - a_j[j] + a__)); - - const { eigenvectors: V } = simultaneous_poweriteration(B, d, eig_args); - this.Y = Matrix.from(V).transpose(); - - return this.projection; - } - - /** @returns {number} - The stress of the projection. */ - stress() { - const N = this.X.shape[0]; - const Y = this.Y; - const d_X = this._d_X; - if (!d_X) throw new Error("First transform!"); - - const d_Y = new Matrix(N, N, 0); - d_Y.shape = [ - N, - N, - (i, j) => { - return i < j ? euclidean(Y.row(i), Y.row(j)) : d_Y.entry(j, i); - }, - ]; - let top_sum = 0; - let bottom_sum = 0; - for (let i = 0; i < N; ++i) { - for (let j = i + 1; j < N; ++j) { - top_sum += (d_X.entry(i, j) - d_Y.entry(i, j)) ** 2; - bottom_sum += d_X.entry(i, j) ** 2; - } - } - return Math.sqrt(top_sum / bottom_sum); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X, parameters) { - const dr = new MDS(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new MDS(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new MDS(X, parameters); - return dr.transform_async(); - } -} + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {T} + */ + static transform(X, parameters) { + const dr = new TopoMap(X, parameters); + return dr.transform(); + } -/** @import {InputType} from "../index.js" */ -/** @import {ParametersLSP} from "./index.js" */ + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new TopoMap(X, parameters); + yield* dr.generator(); + return dr.projection; + } -/** - * Least Square Projection (LSP) - * - * A dimensionality reduction technique that uses a small set of control points - * (projected with MDS) to define the projection for the rest of the data - * using a Laplacian-based optimization. - * - * @class - * @template {InputType} T - * @extends DR - * @category Dimensionality Reduction - */ -class LSP extends DR { - /** - * Least Squares Projection. - * - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - * @see {@link https://ieeexplore.ieee.org/document/4378370} - */ - constructor(X, parameters) { - super( - X, - { - neighbors: -Infinity, - control_points: -Infinity, - d: 2, - metric: euclidean, - seed: 1212, - }, - parameters, - ); - if (this.parameter("neighbors") === -Infinity) { - this.parameter("neighbors", Math.min(Math.max(Math.floor(this._N / 10), 2), this._N - 1)); - } - if (this.parameter("control_points") === -Infinity) { - this.parameter("control_points", Math.min(Math.ceil(Math.sqrt(this._N)), this._N - 1)); - } - this._is_initialized = false; - } - - /** - * @returns {LSP} - */ - // init(DR = MDS, DR_parameters = {}, KNN = BallTree) { - init() { - const DR = MDS; - let DR_parameters = {}; - const KNN = BallTree; - if (this._is_initialized) return this; - const X = this.X; - const N = this._N; - const K = /** @type {number} */ (this.parameter("neighbors")); - const d = /** @type {number} */ (this.parameter("d")); - const seed = /** @type {number} */ (this.parameter("seed")); - const metric = /** @type {typeof euclidean} */ (this.parameter("metric")); - DR_parameters = Object.assign({ d, metric, seed }, DR_parameters); - const nc = /** @type {number} */ (this.parameter("control_points")); - const control_points = new KMedoids(X, { K: nc, metric }).get_medoids(); - const C = new Matrix(nc, N, "zeros"); - control_points.forEach((c_i, i) => { - C.set_entry(i, c_i, 1); - }); - - const control_points_matrix = Matrix.from(control_points.map((c_i) => X.row(c_i))); - const Y_C = new DR(control_points_matrix, DR_parameters).transform(); - - const XA = X.to2dArray(); - const knn = new KNN(XA, { metric, seed }); - const L = new Matrix(N, N, "I"); - const alpha = -1 / K; - XA.forEach((x_i, i) => { - for (const { index: j } of knn.search(x_i, K)) { - if (i === j) continue; - L.set_entry(i, j, alpha); - } - }); - const A = L.concat(C, "vertical"); - - const z = new Matrix(N, d, "zeros"); - const b = z.concat(Y_C, "vertical"); - - this._A = A; - this._b = b; - this._is_initialized = true; - return this; - } - - /** - * Computes the projection. - * - * @returns {T} Returns the projection. - */ - transform() { - this.check_init(); - const A = this._A; - const b = this._b; - - if (!A || !b) throw new Error("Call init() first!"); - const ATA = A.transDot(A); - const ATb = A.transDot(b); - this.Y = Matrix.solve_CG(ATA, ATb, this._randomizer); - return this.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X, parameters) { - const dr = new LSP(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new LSP(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new LSP(X, parameters); - return dr.transform_async(); - } + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} parameters + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new TopoMap(X, parameters); + return dr.transform_async(); + } } /** @import {InputType} from "../index.js" */ -/** @import {ParametersLTSA} from "./index.js" */ -/** @import {EigenArgs} from "../linear_algebra/index.js" */ +/** @import {Metric} from "../metrics/index.js" */ +/** @import {ParametersTriMap} from "./index.js" */ +/** @import {KNN} from "../knn/KNN.js" */ /** - * Local Tangent Space Alignment (LTSA) + * TriMap * - * A nonlinear dimensionality reduction algorithm that represents the local - * geometry of the manifold by tangent spaces and then aligns them to reveal - * the global structure. + * A dimensionality reduction technique that preserves both local and global + * structure using triplets. It is designed to be a more robust alternative + * to t-SNE and UMAP. * * @class * @template {InputType} T - * @extends DR + * @extends DR * @category Dimensionality Reduction */ -class LTSA extends DR { - /** - * Local Tangent Space Alignment - * - * @param {T} X - The high-dimensional data. - * @param {Partial} parameters - Object containing parameterization of the DR method. - * @see {@link https://epubs.siam.org/doi/abs/10.1137/S1064827502419154} - */ - constructor(X, parameters) { - super( - X, - { - neighbors: -Infinity, - d: 2, - metric: euclidean, - seed: 1212, - eig_args: {}, - }, - parameters, - ); - if (this.parameter("neighbors") === -Infinity) { - this.parameter("neighbors", Math.min(Math.max(Math.floor(this._N / 10), 2), this._N - 1)); - } - const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); - if (!Object.hasOwn(eig_args, "seed")) { - eig_args.seed = this._randomizer; - } - - const d = /** @type {number} */ (this.parameter("d")); - if (this._D <= d) { - throw new Error( - `Dimensionality of X (D = ${this._D}) must be greater than the required dimensionality of the result (d = ${d})!`, - ); - } - } - - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - *generator() { - yield this.transform(); - return this.projection; - } - - /** - * Transforms the inputdata `X` to dimenionality `d`. - * - * @returns {T} - */ - transform() { - const X = this.X; - const [rows, D] = X.shape; - const neighbors = /** @type {number} */ (this.parameter("neighbors")); - const d = /** @type {number} */ (this.parameter("d")); - const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); - const metric = /** @type {typeof euclidean} */ (this.parameter("metric")); - // 1.1 determine k nearest neighbors - const nN = k_nearest_neighbors(X, neighbors, metric); - // center matrix - const O = new Matrix(D, D, "center"); - const B = new Matrix(rows, rows, 0); +class TriMap extends DR { + /** + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + * @see {@link https://arxiv.org/pdf/1910.00204v1.pdf} + * @see {@link https://github.com/eamid/trimap} + */ + constructor(X, parameters) { + super( + X, + { + weight_adj: 500, + n_inliers: 10, + n_outliers: 5, + n_random: 5, + d: 2, + metric: euclidean, + tol: 1e-8, + seed: 1212, + }, + parameters, + ); + } - for (let row = 0; row < rows; ++row) { - // 1.2 compute the d largest eigenvectors of the correlation matrix - const I_i = [row, ...nN[row].map((n) => n.j)]; - let X_i = Matrix.from(I_i.map((n) => X.row(n))); - // center X_i - X_i = X_i.dot(O); - // correlation matrix - const C = X_i.dotTrans(X_i); - const { eigenvectors: g } = simultaneous_poweriteration(C, d, eig_args); - //g.push(linspace(0, k).map(_ => 1 / Math.sqrt(k + 1))); - const G_i_t = Matrix.from(g); - // 2. Constructing alignment matrix - const W_i = G_i_t.transDot(G_i_t).add(1 / Math.sqrt(neighbors + 1)); - for (let i = 0; i < neighbors + 1; ++i) { - for (let j = 0; j < neighbors + 1; ++j) { - B.add_entry(I_i[i], I_i[j], W_i.entry(i, j) - (i === j ? 1 : 0)); - } - } - } - - // 3. Aligning global coordinates - const { eigenvectors: Y } = simultaneous_poweriteration(B, d + 1, eig_args); - this.Y = Matrix.from(Y.slice(1)).transpose(); - - // return embedding - return this.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {T} - */ - static transform(X, parameters) { - const dr = new LTSA(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new LTSA(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new LTSA(X, parameters); - return dr.transform_async(); - } -} + /** + * @param {Matrix | null} [pca=null] - Initial Embedding (if null then PCA gets used). Default is `null` + * @param {import("../knn/KNN.js").KNN | null} [knn=null] - KNN Object (if null then BallTree gets used). Default is `null` + */ + init(pca = null, knn = null) { + const X = this.X; + const N = X.shape[0]; + //const c = /** @type {number} */ (this._parameters.c); + const d = /** @type {number} */ (this._parameters.d); + const metric = /** @type {Metric} */ (this._parameters.metric); + const seed = /** @type {number} */ (this._parameters.seed); + this.n_inliers = /** @type {number} */ (this._parameters.n_inliers); + this.n_outliers = /** @type {number} */ (this._parameters.n_outliers); + this.n_random = /** @type {number} */ (this._parameters.n_random); + this.Y = pca ?? PCA.transform(X, { d, seed }); + this.knn = knn ?? new BallTree(X.to2dArray(), { metric, seed }); + const { triplets, weights } = this._generate_triplets(this.n_inliers, this.n_outliers, this.n_random); + this.triplets = triplets; + this.weights = weights; + this.lr = (1000 * N) / triplets.shape[0]; + this.C = Infinity; + this.vel = new Matrix(N, d, 0); + this.gain = new Matrix(N, d, 1); + return this; + } -/** @import {InputType} from "../index.js" */ -/** @import {ParametersPCA} from "./index.js" */ -/** @import {EigenArgs} from "../linear_algebra/index.js" */ + /** + * Generates {@link n_inliers} x {@link n_outliers} x {@link n_random} triplets. + * + * @param {number} n_inliers + * @param {number} n_outliers + * @param {number} n_random + */ + _generate_triplets(n_inliers, n_outliers, n_random) { + const metric = /** @type {Metric} */ (this._parameters.metric); + const weight_adj = /** @type {number} */ (this._parameters.weight_adj); + const X = this.X; + const N = X.shape[0]; + const knn = this.knn; + if (!knn) throw new Error("Call init() first!"); + const n_extra = Math.min(n_inliers + 20, N); + const nbrs = new Matrix(N, n_extra); + const knn_distances = new Matrix(N, n_extra); + for (let i = 0; i < N; ++i) { + const results = knn + .search(X.row(i), n_extra + 1) + .filter((d) => d.distance !== 0) + .sort((a, b) => a.distance - b.distance); + + results.forEach((d, j) => { + if (j < n_extra) { + nbrs.set_entry(i, j, d.index); + knn_distances.set_entry(i, j, d.distance); + } + }); + } + // scale parameter + const sig = new Float64Array(N); + for (let i = 0; i < N; ++i) { + sig[i] = Math.max( + (knn_distances.entry(i, 3) + knn_distances.entry(i, 4) + knn_distances.entry(i, 5)) / 3, + 1e-10, + ); + } -/** - * Principal Component Analysis (PCA) - * - * A linear dimensionality reduction technique that identifies the axes (principal components) - * along which the variance of the data is maximized. - * - * @class - * @template {InputType} T - * @extends DR - * @category Dimensionality Reduction - * @see {@link MDS} for another linear alternative - * - * @example - * import * as druid from "@saehrimnir/druidjs"; - * - * const X = [[1, 2], [3, 4], [5, 6]]; - * const pca = new druid.PCA(X, { d: 2 }); - * const Y = pca.transform(); - * // [[x1, y1], [x2, y2], [x3, y3]] - */ -class PCA extends DR { - /** - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - */ - constructor(X, parameters = {}) { - super(X, { d: 2, seed: 1212, eig_args: {} }, parameters); - const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); - if (!Object.hasOwn(eig_args, "seed")) { - eig_args.seed = this._randomizer; - } - } - - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {Generator} A generator yielding the intermediate steps of the projection. - */ - *generator() { - yield this.transform(); - return this.projection; - } - - /** - * Transforms the inputdata `X` to dimensionality `d`. - * - * @returns {T} - The projected data. - */ - transform() { - const V = this.principal_components(); - const X = this.X; - this.Y = X.dot(V); - return this.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {T} - */ - static transform(X, parameters) { - const dr = new PCA(X, parameters); - return dr.transform(); - } - - /** - * Computes the `d` principal components of Matrix `X`. - * - * @returns {Matrix} - */ - principal_components() { - if (this.V) { - return this.V; - } - const d = /** @type {number} */ (this.parameter("d")); - const eig_args = /** @type {Partial} */ (this.parameter("eig_args")); - const X = this.X; - const X_cent = X.sub(X.meanCols()); - const C = X_cent.transDot(X_cent); - const { eigenvectors: V } = simultaneous_poweriteration(C, d, eig_args); - this.V = Matrix.from(V).transpose(); - return this.V; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Matrix} - */ - static principal_components(X, parameters) { - const dr = new PCA(X, parameters); - return dr.principal_components(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new PCA(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new PCA(X, parameters); - return dr.transform_async(); - } -} + const P = this._find_p(knn_distances, sig, nbrs); -/** @import {InputType} from "../index.js" */ -/** @import {ParametersPCA, ParametersMDS, ParametersSAMMON} from "./index.js" */ -/** @typedef {"PCA" | "MDS" | "random"} AvailableInit */ + let triplets = this._sample_knn_triplets(P, nbrs, n_inliers, n_outliers); + let n_triplets = triplets.shape[0]; + const outlier_distances = new Float64Array(n_triplets); + for (let i = 0; i < n_triplets; ++i) { + const j = triplets.entry(i, 0); + const k = triplets.entry(i, 2); + outlier_distances[i] = metric(X.row(j), X.row(k)); + } + let weights = this._find_weights(triplets, P, nbrs, outlier_distances, sig); -/** @typedef {{ PCA: ParametersPCA; MDS: ParametersMDS; random: {} }} ChooseDR */ + if (n_random > 0) { + const { random_triplets, random_weights } = this._sample_random_triplets(X, n_random, sig); + triplets = triplets.concat(random_triplets, "vertical"); + weights = Float64Array.from([...weights, ...random_weights]); + } + n_triplets = triplets.shape[0]; + let max_weight = -Infinity; + for (let i = 0; i < n_triplets; ++i) { + if (Number.isNaN(weights[i])) { + weights[i] = 0; + } + if (max_weight < weights[i]) max_weight = weights[i]; + } + let max_weight_2 = -Infinity; + for (let i = 0; i < n_triplets; ++i) { + weights[i] /= max_weight; + weights[i] += 0.0001; + weights[i] = Math.log(1 + weight_adj * weights[i]); + if (max_weight_2 < weights[i]) max_weight_2 = weights[i]; + } + for (let i = 0; i < n_triplets; ++i) { + weights[i] /= max_weight_2; + } + return { + triplets: triplets, + weights: weights, + }; + } -/** - * Sammon's Mapping - * - * A nonlinear dimensionality reduction technique that minimizes a stress - * function based on the ratio of pairwise distances in high and low dimensional spaces. - * - * @class - * @template {InputType} T - * @extends DR> - * @category Dimensionality Reduction - */ -class SAMMON extends DR { - /** @type {Matrix | undefined} */ - distance_matrix; - - /** - * SAMMON's Mapping - * - * @param {T} X - The high-dimensional data. - * @param {Partial>} [parameters] - Object containing parameterization of the DR - * method. - * @see {@link https://arxiv.org/pdf/2009.01512.pdf} - */ - constructor(X, parameters) { - super( - X, - { - magic: 0.1, - d: 2, - metric: euclidean, - seed: 1212, - init_DR: "random", - init_parameters: {}, - }, - parameters, - ); - } - - /** - * Initializes the projection. - * - * @param {Matrix | undefined} D - * @returns {asserts D is Matrix} - */ - init(D) { - const N = this.X.shape[0]; - const d = /** @type {number} */ (this.parameter("d")); - const metric = /** @type {typeof euclidean | "precomputed"} */ (this.parameter("metric")); - const init_DR = /** @type {AvailableInit} */ (this.parameter("init_DR")); - const DR_parameters = this.parameter("init_parameters"); - if (init_DR === "random") { - const randomizer = this._randomizer; - this.Y = new Matrix(N, d, () => randomizer.random); - } else if (init_DR === "PCA") { - this.Y = Matrix.from(PCA.transform(this.X, /** @type {ParametersPCA} */ (DR_parameters))); - } else if (init_DR === "MDS") { - this.Y = Matrix.from(MDS.transform(this.X, /** @type {ParametersMDS} */ (DR_parameters))); - } else { - throw new Error('init_DR needs to be either "random" or a DR method!'); - } - D = metric === "precomputed" ? Matrix.from(this.X) : distance_matrix(this.X, metric); - this.distance_matrix = D; - } - - /** - * Transforms the inputdata `X` to dimensionality 2. - * - * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200` - * @returns {T} The projection of `X`. - */ - transform(max_iter = 200) { - this.check_init(); - if (!this.distance_matrix) this.init(this.distance_matrix); - for (let j = 0; j < max_iter; ++j) { - this._step(); - } - return this.projection; - } - - /** - * Transforms the inputdata `X` to dimenionality 2. - * - * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200` - * @returns {Generator} A generator yielding the intermediate steps of the projection of - * `X`. - */ - *generator(max_iter = 200) { - this.check_init(); - if (!this.distance_matrix) this.init(this.distance_matrix); - - for (let j = 0; j < max_iter; ++j) { - this._step(); - yield this.projection; - } - - return this.projection; - } - - _step() { - if (!this.distance_matrix) this.init(this.distance_matrix); - const MAGIC = /** @type {number} */ (this.parameter("magic")); - const D = /** @type {Matrix} */ (this.distance_matrix); - const N = this.X.shape[0]; - const d = /** @type {number} */ (this.parameter("d")); - const Y = this.Y; - - const G = new Matrix(N, d, 0); - - const sum = new Float64Array(d); - for (let i = 0; i < N; ++i) { - const e1 = new Float64Array(d); - const e2 = new Float64Array(d); - const Yi = Y.row(i); - for (let j = 0; j < N; ++j) { - if (i === j) continue; - const dX = D.entry(i, j); - if (dX === 0) continue; // Skip identical points in high-dim - - const Yj = Y.row(j); - const delta = new Float64Array(d); - for (let k = 0; k < d; ++k) { - delta[k] = Yi[k] - Yj[k]; + /** + * Calculates the similarity matrix P + * + * @private + * @param {Matrix} knn_distances - Matrix of pairwise knn distances + * @param {Float64Array} sig - Scaling factor for the distances + * @param {Matrix} nbrs - Nearest neighbors + * @returns {Matrix} Pairwise similarity matrix + */ + _find_p(knn_distances, sig, nbrs) { + const [N, n_neighbors] = knn_distances.shape; + return new Matrix(N, n_neighbors, (i, j) => { + return Math.exp(-(knn_distances.entry(i, j) ** 2 / sig[i] / sig[nbrs.entry(i, j)])); + }); + } + + /** + * Sample nearest neighbors triplets based on the similarity values given in P. + * + * @private + * @param {Matrix} P - Matrix of pairwise similarities between each point and its neighbors given in matrix nbrs. + * @param {Matrix} nbrs - Nearest neighbors indices for each point. The similarity values are given in matrix + * {@link P}. Row i corresponds to the i-th point. + * @param {number} n_inliers - Number of inlier points. + * @param {number} n_outliers - Number of outlier points. + */ + _sample_knn_triplets(P, nbrs, n_inliers, n_outliers) { + const N = nbrs.shape[0]; + const triplets_list = []; + for (let i = 0; i < N; ++i) { + const sort_indices = this.__argsort(P.row(i)); + for (let j = 0; j < n_inliers; ++j) { + const sim = nbrs.entry(i, sort_indices[sort_indices[j] === i ? j + 1 : j]); + const rejects = [i, ...Array.from(sort_indices.slice(0, j + 2)).map((idx) => nbrs.entry(i, idx))]; + const samples = this._rejection_sample(n_outliers, N, rejects); + for (let k = 0; k < samples.length; ++k) { + const out = samples[k]; + triplets_list.push([i, sim, out]); + } + } } - const dY = Math.max(euclidean(Yi, Yj), 1e-6); - const dq = dX - dY; - const dr = dX * dY; - for (let k = 0; k < d; ++k) { - e1[k] += (delta[k] * dq) / dr; - e2[k] += (dq - (delta[k] ** 2 * (1 + dq / dY)) / dY) / dr; + const triplets = new Matrix(triplets_list.length, 3); + for (let t = 0; t < triplets_list.length; ++t) { + triplets.set_entry(t, 0, triplets_list[t][0]); + triplets.set_entry(t, 1, triplets_list[t][1]); + triplets.set_entry(t, 2, triplets_list[t][2]); } - } - for (let k = 0; k < d; ++k) { - const val = Y.entry(i, k) + ((MAGIC * e1[k]) / Math.abs(e2[k]) || 0); - G.set_entry(i, k, val); - sum[k] += val; - } + return triplets; } - for (let k = 0; k < d; ++k) { - sum[k] /= N; + + /** + * Should do the same as np.argsort() + * + * @private + * @param {Float64Array | number[]} A + */ + __argsort(A) { + return linspace(0, A.length - 1).sort((i, j) => A[j] - A[i]); } - for (let i = 0; i < N; ++i) { - for (let k = 0; k < d; ++k) { - Y.set_entry(i, k, G.entry(i, k) - sum[k]); - } - } - return Y; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial>} [parameters] - * @returns {T} - */ - static transform(X, parameters) { - const dr = new SAMMON(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial>} [parameters] - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new SAMMON(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial>} [parameters] - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new SAMMON(X, parameters); - return dr.transform_async(); - } -} + /** + * Samples {@link n_samples} integers from a given interval [0, {@link max_int}] while rejection the values that are + * in the {@link rejects}. + * + * @private + * @param {number} n_samples + * @param {number} max_int + * @param {number[]} rejects + */ + _rejection_sample(n_samples, max_int, rejects) { + const randomizer = this._randomizer; + const interval = linspace(0, max_int - 1).filter((d) => rejects.indexOf(d) < 0); + return randomizer.choice(interval, Math.min(n_samples, interval.length)); + } -/** @import {InputType} from "../index.js" */ -/** @import {Metric} from "../metrics/index.js" */ -/** @import {ParametersSQDMDS} from "./index.js" */ + /** + * Calculates the weights for the sampled nearest neighbors triplets + * + * @private + * @param {Matrix} triplets - Sampled Triplets. + * @param {Matrix} P - Pairwise similarity matrix. + * @param {Matrix} nbrs - Nearest Neighbors + * @param {Float64Array} outlier_distances - Matrix of pairwise outlier distances + * @param {Float64Array} sig - Scaling factor for the distances. + */ + _find_weights(triplets, P, nbrs, outlier_distances, sig) { + const n_triplets = triplets.shape[0]; + const weights = new Float64Array(n_triplets); + for (let t = 0; t < n_triplets; ++t) { + const i = triplets.entry(t, 0); + const sim = nbrs.row(i).indexOf(triplets.entry(t, 1)); + const p_sim = P.entry(i, sim); + let p_out = Math.exp(-(outlier_distances[t] ** 2 / (sig[i] * sig[triplets.entry(t, 2)]))); + if (p_out < 1e-20) p_out = 1e-20; + weights[t] = p_sim / p_out; + } + return weights; + } -/** - * SQuadMDS (Stochastic Quartet MDS) - * - * A lean Stochastic Quartet MDS improving global structure preservation in - * neighbor embedding like t-SNE and UMAP. - * - * @class - * @template {InputType} T - * @extends DR - * @category Dimensionality Reduction - */ -class SQDMDS extends DR { - /** - * SQuadMDS: a lean Stochastic Quartet MDS improving global structure preservation in neighbor embedding like t-SNE - * and UMAP. - * - * @param {T} X - * @param {Partial} [parameters] - * @see {@link https://arxiv.org/pdf/2202.12087.pdf} - */ - constructor(X, parameters) { - super( - X, - { - d: 2, - metric: euclidean, - seed: 1212, - decay_start: 0.1, - decay_cte: 0.34, // 0.34 - }, - parameters, - ); - - this.init(); - if (this.parameter("metric") === "precomputed" && this.X.shape[0] !== this.X.shape[1]) { - throw new Error("SQDMDS input data must be a square Matrix"); - } - } - - init() { - const N = this._N; - const d = /** @type {number} */ (this.parameter("d")); - - // initialize helpers. - this._add = this.__add(d); - this._sub_div = this.__sub_div(d); - this._minus = this.__minus(d); - this._mult = this.__mult(d); - this._LR_init = Math.max(2, 0.005 * N); - this._LR = this._LR_init; - const decay_cte = /** @type {number} */ (this.parameter("decay_cte")); - this._offset = -Math.exp(-1 / decay_cte); - this._momentums = new Matrix(N, d, 0); - this._grads = new Matrix(N, d, 0); - this._indices = linspace(0, N - 1); - // initialize projection. - const R = this._randomizer; - this.Y = new Matrix(N, d, () => R.random - 0.5); - - // preparing metric for optimization. - const this_metric = /** @type {Metric | "precomputed"} */ (this.parameter("metric")); - if (this_metric === "precomputed") { - /** @type {(i: number, j: number, X: Matrix) => number} */ - this._HD_metric = (i, j, X) => X.entry(i, j); - /** @type {(i: number, j: number, X: Matrix) => number} */ - this._HD_metric_exaggeration = (i, j, X) => X.entry(i, j) ** 2; - } else { - this._HD_metric = (i, j, X) => this_metric(X.row(i), X.row(j)); - if (this_metric === euclidean) { - this._HD_metric_exaggeration = (i, j, X) => euclidean_squared(X.row(i), X.row(j)); - } else { - this._HD_metric_exaggeration = (i, j, X) => this_metric(X.row(i), X.row(j)) ** 2; - } - } - return; - } - - /** - * Computes the projection. - * - * @param {number} [iterations=500] - Number of iterations. Default is `500` - * @returns {T} The projection. - */ - transform(iterations = 500) { - this.check_init(); - const decay_start = /** @type {number} */ (this.parameter("decay_start")); - this._decay_start = Math.round(decay_start * iterations); - for (let i = 0; i < iterations; ++i) { - this._step(i, iterations); - } - return this.projection; - } - - /** - * Computes the projection. - * - * @param {number} [iterations=500] - Number of iterations. Default is `500` - * @returns {Generator} The intermediate steps of the projection. - */ - *generator(iterations = 500) { - this.check_init(); - const decay_start = /** @type {number} */ (this.parameter("decay_start")); - this._decay_start = Math.round(decay_start * iterations); - for (let i = 0; i < iterations; ++i) { - this._step(i, iterations); - yield this.projection; - } - - return this.projection; - } - - /** - * Performs an optimization step. - * - * @private - * @param {number} i - Acutal iteration. - * @param {number} iterations - Number of iterations. - */ - _step(i, iterations) { - if (this._LR_init === undefined || this._offset === undefined) - throw new Error("Call init() first!"); - - const decay_start = /** @type {number} */ (this.parameter("decay_start")); - if (i > decay_start) { - const decay_cte = /** @type {number} */ (this.parameter("decay_cte")); - const offset = this._offset; - const ratio = (i - decay_start) / (iterations - decay_start); - this._LR = this._LR_init * (Math.exp(-(ratio * ratio) / decay_cte) + offset); - this._distance_exaggeration = false; - } else { - this._distance_exaggeration = true; - } - this._nestrov_iteration(this._distance_exaggeration); - } - - /** - * Creates quartets of non overlapping indices. - * - * @private - * @returns {Uint32Array[]} - */ - __quartets() { - if (!this._indices) throw new Error("Call init() first!"); - if (this._offset === undefined) throw new Error("Call init() first!"); - const N = this._N; - const max_N = N - (N % 4); - const R = this._randomizer; - const shuffled_indices = R.choice(this._indices, max_N); - const result = []; - for (let i = 0; i < max_N; i += 4) { - result.push( - Uint32Array.of( - shuffled_indices[i], - shuffled_indices[i + 1], - shuffled_indices[i + 2], - shuffled_indices[i + 3], - ), - ); + /** + * Sample uniformly ranom triplets + * + * @private + * @param {Matrix} X - Data matrix. + * @param {number} n_random - Number of random triplets per point + * @param {Float64Array} sig - Scaling factor for the distances + */ + _sample_random_triplets(X, n_random, sig) { + const metric = /** @type {Metric} */ (this.parameter("metric")); + const randomizer = this._randomizer; + const N = X.shape[0]; + const random_triplets = new Matrix(N * n_random, 3); + const random_weights = new Float64Array(N * n_random); + for (let i = 0; i < N; ++i) { + const n_i = i * n_random; + const indices = Array.from({ length: N }, (_, idx) => idx).filter((idx) => idx !== i); + for (let j = 0; j < n_random; ++j) { + let [sim, out] = randomizer.choice(indices, 2); + let p_sim = Math.exp(-(metric(X.row(i), X.row(sim)) ** 2 / (sig[i] * sig[sim]))); + if (p_sim < 1e-20) p_sim = 1e-20; + let p_out = Math.exp(-(metric(X.row(i), X.row(out)) ** 2 / (sig[i] * sig[out]))); + if (p_out < 1e-20) p_out = 1e-20; + + if (p_sim < p_out) { + [sim, out] = [out, sim]; + [p_sim, p_out] = [p_out, p_sim]; + } + const index = n_i + j; + random_triplets.set_entry(index, 0, i); + random_triplets.set_entry(index, 1, sim); + random_triplets.set_entry(index, 2, out); + random_weights[index] = 0.1 * (p_sim / p_out); + } + } + return { + random_triplets: random_triplets, + random_weights: random_weights, + }; } - return result; - } - - /** - * Computes and applies gradients, and updates momentum. - * - * @private - * @param {boolean} distance_exaggeration - */ - _nestrov_iteration(distance_exaggeration) { - if (!this._momentums || !this._grads || this._LR === undefined) - throw new Error("Call init() first!"); - const momentums = this._momentums.mult(0.99, { inline: true }); - const LR = this._LR; - const grads = this._fill_MDS_grads(this.Y.add(momentums), this._grads, distance_exaggeration); - const [n, d] = momentums.shape; - for (let i = 0; i < n; ++i) { - const g_i = grads.row(i); - const g_i_norm = norm(g_i); - if (g_i_norm === 0) continue; - const mul = LR / g_i_norm; - const m_i = momentums.row(i); - for (let j = 0; j < d; ++j) { - m_i[j] -= mul * g_i[j]; - } - } // momentums -= (LR / norm) * grads - this.Y.add(momentums, { inline: true }); - } - - /** - * Computes the gradients. - * - * @param {Matrix} Y - The Projection. - * @param {Matrix} grads - The gradients. - * @param {boolean} [exaggeration=false] - Whether or not to use early exaggeration. Default is `false` - * @param {boolean} [zero_grad=true] - Whether or not to reset the gradient in the beginning. Default is `true` - * @returns {Matrix} The gradients. - */ - _fill_MDS_grads(Y, grads, exaggeration = false, zero_grad = true) { - if (!this._HD_metric || !this._HD_metric_exaggeration || !this._add) - throw new Error("Call init() first!"); - if (zero_grad) { - // compute new gradients - grads.values.fill(0); - } - const add = this._add; - const X = this.X; - let HD_metric; - if (exaggeration === true) { - HD_metric = this._HD_metric_exaggeration; - } else { - HD_metric = this._HD_metric; - } - - const D_quartet = new Float64Array(6); - const quartets = this.__quartets(); - for (const [i, j, k, l] of quartets) { - // compute quartet's HD distances. - D_quartet[0] = HD_metric(i, j, X); - D_quartet[1] = HD_metric(i, k, X); - D_quartet[2] = HD_metric(i, l, X); - D_quartet[3] = HD_metric(j, k, X); - D_quartet[4] = HD_metric(j, l, X); - D_quartet[5] = HD_metric(k, l, X); - - const D_quartet_sum = neumair_sum(D_quartet); - - if (D_quartet_sum > 0) { - for (let i = 0; i < 6; ++i) { - D_quartet[i] /= D_quartet_sum; - D_quartet[i] += 1e-11; - } - } - const [gi, gj, gk, gl] = this._compute_quartet_grads(Y, [i, j, k, l], D_quartet); - - // add is inline, row acces the matrix - add(grads.row(i), gi); - add(grads.row(j), gj); - add(grads.row(k), gk); - add(grads.row(l), gl); - } - return grads; - } - - /** - * Quartet gradients for a projection. - * - * @private - * @param {Matrix} Y - The acutal projection. - * @param {number[]} quartet - The indices of the quartet. - * @param {Float64Array} D_hd - The high-dimensional distances of the quartet. - * @returns {Float64Array[]} The gradients for the quartet. - */ - _compute_quartet_grads(Y, quartet, [p_ab, p_ac, p_ad, p_bc, p_bd, p_cd]) { - const [a, b, c, d] = quartet.map((index) => Y.row(index)); - // LD distances, add a small number just in case - const d_ab = euclidean(a, b) + 1e-12; - const d_ac = euclidean(a, c) + 1e-12; - const d_ad = euclidean(a, d) + 1e-12; - const d_bc = euclidean(b, c) + 1e-12; - const d_bd = euclidean(b, d) + 1e-12; - const d_cd = euclidean(c, d) + 1e-12; - const sum_LD_dist = neumair_sum([d_ab, d_ac, d_ad, d_bc, d_bd, d_cd]); - - // for each element of the sum: use the same gradient function and just permute the points given in input. - const [gA1, gB1, gC1, gD1] = this._ABCD_grads( - a, - b, - c, - d, - d_ab, - d_ac, - d_ad, - d_bc, - d_bd, - d_cd, - p_ab, - sum_LD_dist, - ); - const [gA2, gC2, gB2, gD2] = this._ABCD_grads( - a, - c, - b, - d, - d_ac, - d_ab, - d_ad, - d_bc, - d_cd, - d_bd, - p_ac, - sum_LD_dist, - ); - const [gA3, gD3, gC3, gB3] = this._ABCD_grads( - a, - d, - c, - b, - d_ad, - d_ac, - d_ab, - d_cd, - d_bd, - d_bc, - p_ad, - sum_LD_dist, - ); - const [gB4, gC4, gA4, gD4] = this._ABCD_grads( - b, - c, - a, - d, - d_bc, - d_ab, - d_bd, - d_ac, - d_cd, - d_ad, - p_bc, - sum_LD_dist, - ); - const [gB5, gD5, gA5, gC5] = this._ABCD_grads( - b, - d, - a, - c, - d_bd, - d_ab, - d_bc, - d_ad, - d_cd, - d_ac, - p_bd, - sum_LD_dist, - ); - const [gC6, gD6, gA6, gB6] = this._ABCD_grads( - c, - d, - a, - b, - d_cd, - d_ac, - d_bc, - d_ad, - d_bd, - d_ab, - p_cd, - sum_LD_dist, - ); - - if (!this._add) throw new Error("Call init() first!"); - const add = this._add; - const gA = add(gA1, gA2, gA3, gA4, gA5, gA6); - const gB = add(gB1, gB2, gB3, gB4, gB5, gB6); - const gC = add(gC1, gC2, gC3, gC4, gC5, gC6); - const gD = add(gD1, gD2, gD3, gD4, gD5, gD6); - - return [gA, gB, gC, gD]; - } - - /** - * Gradients for one element of the loss function's sum. - * - * @private - * @param {Float64Array} a - * @param {Float64Array} b - * @param {Float64Array} c - * @param {Float64Array} d - * @param {number} d_ab - * @param {number} d_ac - * @param {number} d_ad - * @param {number} d_bc - * @param {number} d_bd - * @param {number} d_cd - * @param {number} p_ab - * @param {number} sum_LD_dist - * @returns {Float64Array[]} - */ - _ABCD_grads(a, b, c, d, d_ab, d_ac, d_ad, d_bc, d_bd, d_cd, p_ab, sum_LD_dist) { - if (!this._minus || !this._add || !this._mult || !this._sub_div) - throw new Error("Call init() first!"); - const ratio = d_ab / sum_LD_dist; - const twice_ratio = 2 * ((p_ab - ratio) / sum_LD_dist); - const minus = this._minus; - const add = this._add; - const mult = this._mult; - const sub_div = this._sub_div; - // no side effects because sub_div creates new arrays, and the inline functions work on this new created arrays. - const gA = mult( - minus( - mult(add(sub_div(a, b, d_ab), sub_div(a, c, d_ac), sub_div(a, d, d_ad)), ratio), - sub_div(a, b, d_ab), - ), - twice_ratio, - ); - const gB = mult( - minus( - mult(add(sub_div(b, a, d_ab), sub_div(b, c, d_bc), sub_div(b, d, d_bd)), ratio), - sub_div(b, a, d_ab), - ), - twice_ratio, - ); - const gC = mult( - add(sub_div(c, a, d_ac), sub_div(c, b, d_bc), sub_div(c, d, d_cd)), - ratio * twice_ratio, - ); - const gD = mult( - add(sub_div(d, a, d_ad), sub_div(d, b, d_bd), sub_div(d, c, d_cd)), - ratio * twice_ratio, - ); - return [gA, gB, gC, gD]; - } - - /** - * Inline! - * - * @param {number} d - */ - __minus(d) { - return /** @type {(a: Float64Array, b: Float64Array) => Float64Array} */ (a, b) => { - for (let i = 0; i < d; ++i) { - a[i] -= b[i]; - } - return a; - }; - } - - /** - * Inline! - * - * @param {number} d - */ - __add(d) { - return /** @type {(...summands: Float64Array[]) => Float64Array} */ (...summands) => { - const n = summands.length; - const s1 = summands[0]; - for (let j = 1; j < n; ++j) { - const summand = summands[j]; - for (let i = 0; i < d; ++i) { - s1[i] += summand[i]; - } - } - return s1; - }; - } - - /** - * Inline! - * - * @param {number} d - */ - __mult(d) { - return /** @type {(a: Float64Array, v: number) => Float64Array} */ (a, v) => { - for (let i = 0; i < d; ++i) { - a[i] *= v; - } - return a; - }; - } - - /** - * Creates a new array `(x - y) / div`. - * - * @param {number} d - */ - __sub_div(d) { - return /** @type {(x: Float64Array, y: Float64Array, div: number) => Float64Array} */ ( - x, - y, - div, - ) => { - return Float64Array.from({ length: d }, (_, i) => (x[i] - y[i]) / div); - }; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X, parameters) { - const dr = new SQDMDS(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new SQDMDS(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new SQDMDS(X, parameters); - return dr.transform_async(); - } -} -/** @import {InputType} from "../index.js" */ -/** @import {ParametersTopoMap} from "./index.js" */ + /** + * Computes the gradient for updating the embedding. + * + * @param {Matrix} Y - The embedding + */ + _grad(Y) { + const n_inliers = this.n_inliers; + const n_outliers = this.n_outliers; + const triplets = this.triplets; + const weights = this.weights; + if (!triplets || n_inliers === undefined || n_outliers === undefined || !weights) + throw new Error("Call init() first!"); + const [N, dim] = Y.shape; + const n_triplets = triplets.shape[0]; + const grad = new Matrix(N, dim, 0); + const y_ij = new Float64Array(dim); + const y_ik = new Float64Array(dim); + let d_ij = 1; + let d_ik = 1; + let n_viol = 0; + let loss = 0; + const n_knn_triplets = N * n_inliers * n_outliers; + + for (let t = 0; t < n_triplets; ++t) { + const [i, j, k] = triplets.row(t); + // update y_ij, y_ik, d_ij, d_ik + if (t % n_outliers === 0 || t >= n_knn_triplets) { + d_ij = 1; + d_ik = 1; + for (let d = 0; d < dim; ++d) { + const Y_id = Y.entry(i, d); + const Y_jd = Y.entry(j, d); + const Y_kd = Y.entry(k, d); + y_ij[d] = Y_id - Y_jd; + y_ik[d] = Y_id - Y_kd; + d_ij += y_ij[d] ** 2; + d_ik += y_ik[d] ** 2; + } + // update y_ik and d_ik only + } else { + d_ik = 1; + for (let d = 0; d < dim; ++d) { + const Y_id = Y.entry(i, d); + const Y_kd = Y.entry(k, d); + y_ik[d] = Y_id - Y_kd; + d_ik += y_ik[d] ** 2; + } + } -/** - * TopoMap - * - * A 0-dimensional Homology Preserving Projection of High-Dimensional Data. - * It aims to preserve the topological structure of the data by maintaining - * the connectivity of a minimum spanning tree. - * - * @class - * @template {InputType} T - * @extends DR - * @category Dimensionality Reduction - */ -class TopoMap extends DR { - /** - * TopoMap: A 0-dimensional Homology Preserving Projection of High-Dimensional Data. - * - * @param {T} X - The high-dimensional data. - * @param {Partial} parameters - Object containing parameterization of the DR method. - * @see {@link https://arxiv.org/pdf/2009.01512.pdf} - */ - constructor(X, parameters) { - super(X, { metric: euclidean, seed: 1212 }, parameters); - [this._N, this._D] = this.X.shape; - this._distance_matrix = new Matrix(this._N, this._N, -1); - } - - /** - * @private - * @param {number} i - * @param {number} j - * @param {import("../metrics/index.js").Metric} metric - * @returns {number} - */ - __lazy_distance_matrix(i, j, metric) { - const D = this._distance_matrix; - const X = this.X; - const D_ij = D.entry(i, j); - if (D_ij === -1 && i !== j) { - const dist = metric(X.row(i), X.row(j)); - D.set_entry(i, j, dist); - D.set_entry(j, i, dist); - return dist; - } - return i === j ? 0 : D_ij; - } - - /** - * Computes the minimum spanning tree, using a given metric - * - * @private - * @param {import("../metrics/index.js").Metric} metric - * @see {@link https://en.wikipedia.org/wiki/Kruskal%27s_algorithm} - */ - _make_minimum_spanning_tree(metric = euclidean) { - const N = this._N; - const X = [...this.X]; - - this._disjoint_set = new DisjointSet(X); - const disjoint_set = this._disjoint_set; - const F = []; - let E = []; - for (let i = 0; i < N; ++i) { - for (let j = i + 1; j < N; ++j) { - E.push([i, j, this.__lazy_distance_matrix(i, j, metric)]); - } - } - E = E.sort((a, b) => a[2] - b[2]); - - for (const [u, v, w] of E) { - const set_u = disjoint_set.find(X[u]); - const set_v = disjoint_set.find(X[v]); - if (!set_u || !set_v) throw new Error("Should not happen!"); - if (set_u !== set_v) { - F.push([u, v, w]); - disjoint_set.union(set_u, set_v); - } - } - - return F.sort((a, b) => a[2] - b[2]); - } - - /** Initializes TopoMap. Sets all projcted points to zero, and computes a minimum spanning tree. */ - init() { - const { metric } = this._parameters; - this.Y = new Matrix(this._N, 2, 0); - this._Emst = this._make_minimum_spanning_tree(metric); - this._is_initialized = true; - return this; - } - - /** - * Returns true if Point C is left of line AB. - * - * @private - * @param {Float64Array} PointA - Point A of line AB - * @param {Float64Array} PointB - Point B of line AB - * @param {Float64Array} PointC - Point C - * @returns {boolean} - */ - __hull_cross([ax, ay], [bx, by], [sx, sy]) { - return (bx - ax) * (sy - ay) - (by - ay) * (sx - ax) <= 0; - } - - /** - * Computes the convex hull of the set of Points S - * - * @private - * @param {Float64Array[]} S - Set of Points. - * @returns {Float64Array[]} Convex hull of S. Starts at the bottom-most point and continues counter-clockwise. - * @see {@link https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain#JavaScript} - */ - __hull(S) { - const points = S.sort(([x1, y1], [x2, y2]) => y1 - y2 || x1 - x2); - const N = points.length; - if (N <= 2) return points; - - const lower = []; - for (let i = 0; i < N; ++i) { - while ( - lower.length >= 2 && - this.__hull_cross(lower[lower.length - 2], lower[lower.length - 1], points[i]) - ) { - lower.pop(); - } - lower.push(points[i]); - } - const upper = []; - for (let i = N - 1; i >= 0; --i) { - while ( - upper.length >= 2 && - this.__hull_cross(upper[upper.length - 2], upper[upper.length - 1], points[i]) - ) { - upper.pop(); - } - upper.push(points[i]); - } - upper.pop(); - lower.pop(); - return lower.concat(upper); - } - - /** - * Finds the angle to rotate Point A and B to lie on a line parallel to the x-axis. - * - * @private - * @param {Float64Array} PointA - * @param {Float64Array} PointB - * @returns {{ sin: number; cos: number }} Object containing the sinus- and cosinus-values for a rotation. - */ - __findAngle([p1x, p1y], [p2x, p2y]) { - const n = euclidean([p1x, p1y], [p2x, p2y]); - if (n === 0) - return { - sin: 0, - cos: 1, - }; - const vec = [(p2x - p1x) / n, (p2y - p1y) / n]; - const cos = vec[0]; - let sin = Math.sqrt(1 - cos * cos); - sin = vec[1] >= 0 ? -sin : sin; - return { - sin: sin, - cos: cos, - }; - } - - /** - * @private - * @param {Float64Array[]} hull - * @param {Float64Array} p - * @param {boolean} topEdge - * @returns {{ sin: number; cos: number; tx: number; ty: number }} - */ - __align_hull(hull, p, topEdge) { - let v = -1; - /** @type {number} */ - let d2 = -Infinity; - for (let i = 0; i < hull.length; ++i) { - const d = euclidean(hull[i], p); - if (v === -1) { - d2 = d; - v = i; - } else { - if (d2 > d) { - d2 = d; - v = i; - } - } - } - - const v1 = hull[v]; - let v2; - if (topEdge) { - v2 = hull[(v + 1) % hull.length]; - } else { - v2 = hull[(v - 1 + hull.length) % hull.length]; + if (d_ij > d_ik) ++n_viol; + loss += weights[t] / (1 + d_ik / d_ij); + const w = weights[t] / (d_ij + d_ik) ** 2; + for (let d = 0; d < dim; ++d) { + const gs = y_ij[d] * d_ik * w; + const go = y_ik[d] * d_ij * w; + grad.add_entry(i, d, gs - go); + grad.sub_entry(j, d, gs); + grad.add_entry(k, d, go); + } + } + return { grad, loss, n_viol }; + } + + /** + * @param {number} max_iteration + * @returns {T} + */ + transform(max_iteration = 800) { + this.check_init(); + for (let iter = 0; iter < max_iteration; ++iter) { + this._next(iter); + } + return this.projection; + } + + /** + * @param {number} max_iteration + * @returns {Generator} + */ + *generator(max_iteration = 800) { + this.check_init(); + for (let iter = 0; iter < max_iteration; ++iter) { + this._next(iter); + yield this.projection; + } + return this.projection; + } + + /** + * Does the iteration step. + * + * @private + * @param {number} iter + */ + _next(iter) { + const gamma = iter > 250 ? 0.5 : 0.3; + const old_C = this.C; + const vel = this.vel; + if (!vel || old_C === undefined || this.lr === undefined) throw new Error("Call init() first!"); + const Y = this.Y.add(vel.mult(gamma)); + const { grad, loss } = this._grad(Y); + this.C = loss; + this.Y = this._update_embedding(Y, iter, grad); + const tol = /** @type {number} */ (this.parameter("tol")); + this.lr *= old_C > loss + tol ? 1.01 : 0.9; + return this.Y; } - /** @type {{ sin?: number; cos?: number; tx: number; ty: number }} */ - const transformation = { - tx: -v1[0], - ty: -v1[1], - }; - - if (hull.length >= 2) { - const { sin, cos } = this.__findAngle(v1, v2); - transformation.sin = sin; - transformation.cos = cos; - } else { - transformation.sin = 0; - transformation.cos = 1; - } - - return /** @type {{ sin: number; cos: number; tx: number; ty: number }} */ (transformation); - } - - /** - * @private - * @param {Float64Array} Point - The point which should get transformed. - * @param {{ sin: number; cos: number; tx: number; ty: number }} Transformation - Contains the values for - * translation and rotation. - */ - __transform([px, py], { tx, ty, sin, cos }) { - const x = px + tx; - const y = py + ty; - const xx = x * cos - y * sin; - const yy = x * sin + y * cos; - return [xx, yy]; - } - - /** - * Calls `__transform` for each point in Set C - * - * @private - * @param {Float64Array[]} C - Set of points. - * @param {{ sin: number; cos: number; tx: number; ty: number }} t - Transform object. - * @param {number} yOffset - Value to offset set C. - */ - __transform_component(C, t, yOffset) { - const N = C.length; - for (let i = 0; i < N; ++i) { - const c = C[i]; - const [cx, cy] = this.__transform(c, t); - c[0] = cx; - c[1] = cy + yOffset; - } - } - - /** - * @private - * @param {Float64Array} root_u - Root of component u - * @param {Float64Array} root_v - Root of component v - * @param {Float64Array} p_u - Point u - * @param {Float64Array} p_v - Point v - * @param {number} w - Edge weight w - * @param {DisjointSet} components - The disjoint set containing the components - */ - __align_components(root_u, root_v, p_u, p_v, w, components) { - if (!components) throw new Error("components not provided!"); - const u_children = components.get_children(root_u); - const v_children = components.get_children(root_v); - if (!u_children || !v_children) throw new Error("should not happen!"); - - const points_u = [...u_children]; - const points_v = [...v_children]; - - const hull_u = this.__hull(points_u); - const hull_v = this.__hull(points_v); - - const t_u = this.__align_hull(hull_u, p_u, false); - const t_v = this.__align_hull(hull_v, p_v, true); - - this.__transform_component(points_u, t_u, 0); - this.__transform_component(points_v, t_v, w); - } - - /** - * Transforms the inputdata `X` to dimensionality 2. - * - * @returns {T} - */ - transform() { - if (!this._is_initialized) this.init(); - if (!this._Emst) throw new Error("Call init() first!"); - const Emst = this._Emst; - const Y = this.Y.to2dArray(); - /** @type {DisjointSet} */ - const components = new DisjointSet( - Y, - // Y.map((y, i) => { - // y.i = i; - // return y; - // }), - ); - - for (const [u, v, w] of Emst) { - const p_u = Y[u]; - const p_v = Y[v]; - const component_u = components.find(p_u); - const component_v = components.find(p_v); - if (!component_u || !component_v) throw new Error("Should not happen!"); - if (component_u === component_v) continue; - this.__align_components(component_u, component_v, p_u, p_v, w, components); - components.union(component_u, component_v); - } - return this.projection; - } - - /** - * Transforms the inputdata `X` to dimensionality 2. - * - * @returns {Generator} - */ - *generator() { - if (!this._is_initialized) this.init(); - if (!this._Emst) throw new Error("call init() first!"); - const Emst = this._Emst; - const Y = this.Y.to2dArray(); - const components = new DisjointSet( - Y, - // Y.map((y, i) => { - // y.i = i; - // return y; - // }), - ); - - for (const [u, v, w] of Emst) { - const p_u = Y[u]; - const p_v = Y[v]; - const component_u = components.find(p_u); - const component_v = components.find(p_v); - if (!component_u || !component_v) throw new Error("should not happen!"); - if (component_u === component_v) continue; - this.__align_components(component_u, component_v, p_u, p_v, w, components); - components.union(component_u, component_v); - yield this.projection; - } - return this.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {T} - */ - static transform(X, parameters) { - const dr = new TopoMap(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new TopoMap(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} parameters - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new TopoMap(X, parameters); - return dr.transform_async(); - } -} + /** + * Updates the embedding. + * + * @private + * @param {Matrix} Y + * @param {number} iter + * @param {Matrix} grad + */ + _update_embedding(Y, iter, grad) { + const [N, dim] = Y.shape; + const gamma = iter > 250 ? 0.8 : 0.5; // moment parameter + const min_gain = 0.01; + const gain = this.gain; + const vel = this.vel; + const lr = this.lr; + if (!vel || !gain || lr === undefined) throw new Error("Call init() first!"); + for (let i = 0; i < N; ++i) { + for (let d = 0; d < dim; ++d) { + const new_gain = + Math.sign(vel.entry(i, d)) !== Math.sign(grad.entry(i, d)) + ? gain.entry(i, d) + 0.2 + : Math.max(gain.entry(i, d) * 0.8, min_gain); + gain.set_entry(i, d, new_gain); + vel.set_entry(i, d, gamma * vel.entry(i, d) - lr * gain.entry(i, d) * grad.entry(i, d)); + Y.set_entry(i, d, Y.entry(i, d) + vel.entry(i, d)); + } + } + return Y; + } -/** @import {InputType} from "../index.js" */ -/** @import {Metric} from "../metrics/index.js" */ -/** @import {ParametersTriMap} from "./index.js" */ -/** @import {KNN} from "../knn/KNN.js" */ + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X, parameters) { + const dr = new TriMap(X, parameters); + return dr.transform(); + } -/** - * TriMap - * - * A dimensionality reduction technique that preserves both local and global - * structure using triplets. It is designed to be a more robust alternative - * to t-SNE and UMAP. - * - * @class - * @template {InputType} T - * @extends DR - * @category Dimensionality Reduction - */ -class TriMap extends DR { - /** - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - * @see {@link https://arxiv.org/pdf/1910.00204v1.pdf} - * @see {@link https://github.com/eamid/trimap} - */ - constructor(X, parameters) { - super( - X, - { - weight_adj: 500, - n_inliers: 10, - n_outliers: 5, - n_random: 5, - d: 2, - metric: euclidean, - tol: 1e-8, - seed: 1212, - }, - parameters, - ); - } - - /** - * @param {Matrix | null} [pca=null] - Initial Embedding (if null then PCA gets used). Default is `null` - * @param {import("../knn/KNN.js").KNN | null} [knn=null] - KNN Object (if null then BallTree gets used). Default is `null` - */ - init(pca = null, knn = null) { - const X = this.X; - const N = X.shape[0]; - //const c = /** @type {number} */ (this._parameters.c); - const d = /** @type {number} */ (this._parameters.d); - const metric = /** @type {Metric} */ (this._parameters.metric); - const seed = /** @type {number} */ (this._parameters.seed); - this.n_inliers = /** @type {number} */ (this._parameters.n_inliers); - this.n_outliers = /** @type {number} */ (this._parameters.n_outliers); - this.n_random = /** @type {number} */ (this._parameters.n_random); - this.Y = pca ?? PCA.transform(X, { d, seed }); - this.knn = knn ?? new BallTree(X.to2dArray(), { metric, seed }); - const { triplets, weights } = this._generate_triplets( - this.n_inliers, - this.n_outliers, - this.n_random, - ); - this.triplets = triplets; - this.weights = weights; - this.lr = (1000 * N) / triplets.shape[0]; - this.C = Infinity; - this.vel = new Matrix(N, d, 0); - this.gain = new Matrix(N, d, 1); - return this; - } - - /** - * Generates {@link n_inliers} x {@link n_outliers} x {@link n_random} triplets. - * - * @param {number} n_inliers - * @param {number} n_outliers - * @param {number} n_random - */ - _generate_triplets(n_inliers, n_outliers, n_random) { - const metric = /** @type {Metric} */ (this._parameters.metric); - const weight_adj = /** @type {number} */ (this._parameters.weight_adj); - const X = this.X; - const N = X.shape[0]; - const knn = this.knn; - if (!knn) throw new Error("Call init() first!"); - const n_extra = Math.min(n_inliers + 20, N); - const nbrs = new Matrix(N, n_extra); - const knn_distances = new Matrix(N, n_extra); - for (let i = 0; i < N; ++i) { - const results = knn - .search(X.row(i), n_extra + 1) - .filter((d) => d.distance !== 0) - .sort((a, b) => a.distance - b.distance); + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new TriMap(X, parameters); + yield* dr.generator(); + return dr.projection; + } - results.forEach((d, j) => { - if (j < n_extra) { - nbrs.set_entry(i, j, d.index); - knn_distances.set_entry(i, j, d.distance); - } - }); + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new TriMap(X, parameters); + return dr.transform_async(); } - // scale parameter - const sig = new Float64Array(N); - for (let i = 0; i < N; ++i) { - sig[i] = Math.max( - (knn_distances.entry(i, 3) + knn_distances.entry(i, 4) + knn_distances.entry(i, 5)) / 3, - 1e-10, - ); - } - - const P = this._find_p(knn_distances, sig, nbrs); - - let triplets = this._sample_knn_triplets(P, nbrs, n_inliers, n_outliers); - let n_triplets = triplets.shape[0]; - const outlier_distances = new Float64Array(n_triplets); - for (let i = 0; i < n_triplets; ++i) { - const j = triplets.entry(i, 0); - const k = triplets.entry(i, 2); - outlier_distances[i] = metric(X.row(j), X.row(k)); - } - let weights = this._find_weights(triplets, P, nbrs, outlier_distances, sig); - - if (n_random > 0) { - const { random_triplets, random_weights } = this._sample_random_triplets(X, n_random, sig); - triplets = triplets.concat(random_triplets, "vertical"); - weights = Float64Array.from([...weights, ...random_weights]); - } - n_triplets = triplets.shape[0]; - let max_weight = -Infinity; - for (let i = 0; i < n_triplets; ++i) { - if (Number.isNaN(weights[i])) { - weights[i] = 0; - } - if (max_weight < weights[i]) max_weight = weights[i]; - } - let max_weight_2 = -Infinity; - for (let i = 0; i < n_triplets; ++i) { - weights[i] /= max_weight; - weights[i] += 0.0001; - weights[i] = Math.log(1 + weight_adj * weights[i]); - if (max_weight_2 < weights[i]) max_weight_2 = weights[i]; - } - for (let i = 0; i < n_triplets; ++i) { - weights[i] /= max_weight_2; - } - return { - triplets: triplets, - weights: weights, - }; - } - - /** - * Calculates the similarity matrix P - * - * @private - * @param {Matrix} knn_distances - Matrix of pairwise knn distances - * @param {Float64Array} sig - Scaling factor for the distances - * @param {Matrix} nbrs - Nearest neighbors - * @returns {Matrix} Pairwise similarity matrix - */ - _find_p(knn_distances, sig, nbrs) { - const [N, n_neighbors] = knn_distances.shape; - return new Matrix(N, n_neighbors, (i, j) => { - return Math.exp(-(knn_distances.entry(i, j) ** 2 / sig[i] / sig[nbrs.entry(i, j)])); - }); - } - - /** - * Sample nearest neighbors triplets based on the similarity values given in P. - * - * @private - * @param {Matrix} P - Matrix of pairwise similarities between each point and its neighbors given in matrix nbrs. - * @param {Matrix} nbrs - Nearest neighbors indices for each point. The similarity values are given in matrix - * {@link P}. Row i corresponds to the i-th point. - * @param {number} n_inliers - Number of inlier points. - * @param {number} n_outliers - Number of outlier points. - */ - _sample_knn_triplets(P, nbrs, n_inliers, n_outliers) { - const N = nbrs.shape[0]; - const triplets_list = []; - for (let i = 0; i < N; ++i) { - const sort_indices = this.__argsort(P.row(i)); - for (let j = 0; j < n_inliers; ++j) { - const sim = nbrs.entry(i, sort_indices[sort_indices[j] === i ? j + 1 : j]); - const rejects = [ - i, - ...Array.from(sort_indices.slice(0, j + 2)).map((idx) => nbrs.entry(i, idx)), - ]; - const samples = this._rejection_sample(n_outliers, N, rejects); - for (let k = 0; k < samples.length; ++k) { - const out = samples[k]; - triplets_list.push([i, sim, out]); - } - } - } - const triplets = new Matrix(triplets_list.length, 3); - for (let t = 0; t < triplets_list.length; ++t) { - triplets.set_entry(t, 0, triplets_list[t][0]); - triplets.set_entry(t, 1, triplets_list[t][1]); - triplets.set_entry(t, 2, triplets_list[t][2]); - } - return triplets; - } - - /** - * Should do the same as np.argsort() - * - * @private - * @param {Float64Array | number[]} A - */ - __argsort(A) { - return linspace(0, A.length - 1).sort((i, j) => A[j] - A[i]); - } - - /** - * Samples {@link n_samples} integers from a given interval [0, {@link max_int}] while rejection the values that are - * in the {@link rejects}. - * - * @private - * @param {number} n_samples - * @param {number} max_int - * @param {number[]} rejects - */ - _rejection_sample(n_samples, max_int, rejects) { - const randomizer = this._randomizer; - const interval = linspace(0, max_int - 1).filter((d) => rejects.indexOf(d) < 0); - return randomizer.choice(interval, Math.min(n_samples, interval.length)); - } - - /** - * Calculates the weights for the sampled nearest neighbors triplets - * - * @private - * @param {Matrix} triplets - Sampled Triplets. - * @param {Matrix} P - Pairwise similarity matrix. - * @param {Matrix} nbrs - Nearest Neighbors - * @param {Float64Array} outlier_distances - Matrix of pairwise outlier distances - * @param {Float64Array} sig - Scaling factor for the distances. - */ - _find_weights(triplets, P, nbrs, outlier_distances, sig) { - const n_triplets = triplets.shape[0]; - const weights = new Float64Array(n_triplets); - for (let t = 0; t < n_triplets; ++t) { - const i = triplets.entry(t, 0); - const sim = nbrs.row(i).indexOf(triplets.entry(t, 1)); - const p_sim = P.entry(i, sim); - let p_out = Math.exp(-(outlier_distances[t] ** 2 / (sig[i] * sig[triplets.entry(t, 2)]))); - if (p_out < 1e-20) p_out = 1e-20; - weights[t] = p_sim / p_out; - } - return weights; - } - - /** - * Sample uniformly ranom triplets - * - * @private - * @param {Matrix} X - Data matrix. - * @param {number} n_random - Number of random triplets per point - * @param {Float64Array} sig - Scaling factor for the distances - */ - _sample_random_triplets(X, n_random, sig) { - const metric = /** @type {Metric} */ (this.parameter("metric")); - const randomizer = this._randomizer; - const N = X.shape[0]; - const random_triplets = new Matrix(N * n_random, 3); - const random_weights = new Float64Array(N * n_random); - for (let i = 0; i < N; ++i) { - const n_i = i * n_random; - const indices = Array.from({ length: N }, (_, idx) => idx).filter((idx) => idx !== i); - for (let j = 0; j < n_random; ++j) { - let [sim, out] = randomizer.choice(indices, 2); - let p_sim = Math.exp(-(metric(X.row(i), X.row(sim)) ** 2 / (sig[i] * sig[sim]))); - if (p_sim < 1e-20) p_sim = 1e-20; - let p_out = Math.exp(-(metric(X.row(i), X.row(out)) ** 2 / (sig[i] * sig[out]))); - if (p_out < 1e-20) p_out = 1e-20; - - if (p_sim < p_out) { - [sim, out] = [out, sim]; - [p_sim, p_out] = [p_out, p_sim]; - } - const index = n_i + j; - random_triplets.set_entry(index, 0, i); - random_triplets.set_entry(index, 1, sim); - random_triplets.set_entry(index, 2, out); - random_weights[index] = 0.1 * (p_sim / p_out); - } - } - return { - random_triplets: random_triplets, - random_weights: random_weights, - }; - } - - /** - * Computes the gradient for updating the embedding. - * - * @param {Matrix} Y - The embedding - */ - _grad(Y) { - const n_inliers = this.n_inliers; - const n_outliers = this.n_outliers; - const triplets = this.triplets; - const weights = this.weights; - if (!triplets || n_inliers === undefined || n_outliers === undefined || !weights) - throw new Error("Call init() first!"); - const [N, dim] = Y.shape; - const n_triplets = triplets.shape[0]; - const grad = new Matrix(N, dim, 0); - const y_ij = new Float64Array(dim); - const y_ik = new Float64Array(dim); - let d_ij = 1; - let d_ik = 1; - let n_viol = 0; - let loss = 0; - const n_knn_triplets = N * n_inliers * n_outliers; - - for (let t = 0; t < n_triplets; ++t) { - const [i, j, k] = triplets.row(t); - // update y_ij, y_ik, d_ij, d_ik - if (t % n_outliers === 0 || t >= n_knn_triplets) { - d_ij = 1; - d_ik = 1; - for (let d = 0; d < dim; ++d) { - const Y_id = Y.entry(i, d); - const Y_jd = Y.entry(j, d); - const Y_kd = Y.entry(k, d); - y_ij[d] = Y_id - Y_jd; - y_ik[d] = Y_id - Y_kd; - d_ij += y_ij[d] ** 2; - d_ik += y_ik[d] ** 2; - } - // update y_ik and d_ik only - } else { - d_ik = 1; - for (let d = 0; d < dim; ++d) { - const Y_id = Y.entry(i, d); - const Y_kd = Y.entry(k, d); - y_ik[d] = Y_id - Y_kd; - d_ik += y_ik[d] ** 2; - } - } - - if (d_ij > d_ik) ++n_viol; - loss += weights[t] / (1 + d_ik / d_ij); - const w = weights[t] / (d_ij + d_ik) ** 2; - for (let d = 0; d < dim; ++d) { - const gs = y_ij[d] * d_ik * w; - const go = y_ik[d] * d_ij * w; - grad.add_entry(i, d, gs - go); - grad.sub_entry(j, d, gs); - grad.add_entry(k, d, go); - } - } - return { grad, loss, n_viol }; - } - - /** - * @param {number} max_iteration - * @returns {T} - */ - transform(max_iteration = 800) { - this.check_init(); - for (let iter = 0; iter < max_iteration; ++iter) { - this._next(iter); - } - return this.projection; - } - - /** - * @param {number} max_iteration - * @returns {Generator} - */ - *generator(max_iteration = 800) { - this.check_init(); - for (let iter = 0; iter < max_iteration; ++iter) { - this._next(iter); - yield this.projection; - } - return this.projection; - } - - /** - * Does the iteration step. - * - * @private - * @param {number} iter - */ - _next(iter) { - const gamma = iter > 250 ? 0.5 : 0.3; - const old_C = this.C; - const vel = this.vel; - if (!vel || old_C === undefined || this.lr === undefined) throw new Error("Call init() first!"); - const Y = this.Y.add(vel.mult(gamma)); - const { grad, loss } = this._grad(Y); - this.C = loss; - this.Y = this._update_embedding(Y, iter, grad); - const tol = /** @type {number} */ (this.parameter("tol")); - this.lr *= old_C > loss + tol ? 1.01 : 0.9; - return this.Y; - } - - /** - * Updates the embedding. - * - * @private - * @param {Matrix} Y - * @param {number} iter - * @param {Matrix} grad - */ - _update_embedding(Y, iter, grad) { - const [N, dim] = Y.shape; - const gamma = iter > 250 ? 0.8 : 0.5; // moment parameter - const min_gain = 0.01; - const gain = this.gain; - const vel = this.vel; - const lr = this.lr; - if (!vel || !gain || lr === undefined) throw new Error("Call init() first!"); - for (let i = 0; i < N; ++i) { - for (let d = 0; d < dim; ++d) { - const new_gain = - Math.sign(vel.entry(i, d)) !== Math.sign(grad.entry(i, d)) - ? gain.entry(i, d) + 0.2 - : Math.max(gain.entry(i, d) * 0.8, min_gain); - gain.set_entry(i, d, new_gain); - vel.set_entry(i, d, gamma * vel.entry(i, d) - lr * gain.entry(i, d) * grad.entry(i, d)); - Y.set_entry(i, d, Y.entry(i, d) + vel.entry(i, d)); - } - } - return Y; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X, parameters) { - const dr = new TriMap(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new TriMap(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new TriMap(X, parameters); - return dr.transform_async(); - } } /** @import {InputType} from "../index.js" */ @@ -10182,255 +10764,255 @@ class TriMap extends DR { * // [[x1, y1], [x2, y2], [x3, y3]] */ class TSNE extends DR { - /** - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - */ - constructor(X, parameters) { - super( - X, - { - perplexity: 50, - epsilon: 10, - d: 2, - metric: euclidean_squared, - seed: 1212, - }, - parameters, - ); - [this._N, this._D] = this.X.shape; - this._iter = 0; - const d = /** @type {number} */ (this.parameter("d")); - this.Y = new Matrix(this._N, d, () => this._randomizer.gauss_random() * 1e-4); - } - - init() { - // init - const perplexity = /** @type {number} */ (this.parameter("perplexity")); - const Htarget = Math.log(perplexity); - const N = this._N; - const D = this._D; - const metric = /** @type {Metric | "precomputed"} */ (this._parameters.metric); - const X = this.X; - let Delta; - if (metric === "precomputed") { - Delta = Matrix.from(X); - } else { - Delta = new Matrix(N, N); - for (let i = 0; i < N; ++i) { - const X_i = X.row(i); - for (let j = i + 1; j < N; ++j) { - const distance = metric(X_i, X.row(j)); - Delta.set_entry(i, j, distance); - Delta.set_entry(j, i, distance); - } - } + /** + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + */ + constructor(X, parameters) { + super( + X, + { + perplexity: 50, + epsilon: 10, + d: 2, + metric: euclidean_squared, + seed: 1212, + }, + parameters, + ); + [this._N, this._D] = this.X.shape; + this._iter = 0; + const d = /** @type {number} */ (this.parameter("d")); + this.Y = new Matrix(this._N, d, () => this._randomizer.gauss_random() * 1e-4); } - const P = new Matrix(N, N, 0); + init() { + // init + const perplexity = /** @type {number} */ (this.parameter("perplexity")); + const Htarget = Math.log(perplexity); + const N = this._N; + const D = this._D; + const metric = /** @type {Metric | "precomputed"} */ (this._parameters.metric); + const X = this.X; + let Delta; + if (metric === "precomputed") { + Delta = Matrix.from(X); + } else { + Delta = new Matrix(N, N); + for (let i = 0; i < N; ++i) { + const X_i = X.row(i); + for (let j = i + 1; j < N; ++j) { + const distance = metric(X_i, X.row(j)); + Delta.set_entry(i, j, distance); + Delta.set_entry(j, i, distance); + } + } + } + + const P = new Matrix(N, N, 0); - this._ystep = new Matrix(N, D, 0); - this._gains = new Matrix(N, D, 1); + this._ystep = new Matrix(N, D, 0); + this._gains = new Matrix(N, D, 1); - // search for fitting sigma - const tol = 1e-4; - const maxtries = 50; - for (let i = 0; i < N; ++i) { - const dist_i = Delta.row(i); - const prow = P.row(i); - let betamin = -Infinity; - let betamax = Infinity; - let beta = 1; - let cnt = maxtries; - let done = false; - let psum = 0; - - while (!done && cnt--) { - // compute entropy and kernel row with beta precision - psum = 0; - let dp_sum = 0; - for (let j = 0; j < N; ++j) { - const dist = dist_i[j]; - const pj = i !== j ? Math.exp(-dist * beta) : 0; - dp_sum += dist * pj; - prow[j] = pj; - psum += pj; - } - // compute entropy - const H = psum > 0 ? Math.log(psum) + (beta * dp_sum) / psum : 0; - if (H > Htarget) { - betamin = beta; - beta = betamax === Infinity ? beta * 2 : (beta + betamax) / 2; - } else { - betamax = beta; - beta = betamin === -Infinity ? beta / 2 : (beta + betamin) / 2; + // search for fitting sigma + const tol = 1e-4; + const maxtries = 50; + for (let i = 0; i < N; ++i) { + const dist_i = Delta.row(i); + const prow = P.row(i); + let betamin = -Infinity; + let betamax = Infinity; + let beta = 1; + let cnt = maxtries; + let done = false; + let psum = 0; + + while (!done && cnt--) { + // compute entropy and kernel row with beta precision + psum = 0; + let dp_sum = 0; + for (let j = 0; j < N; ++j) { + const dist = dist_i[j]; + const pj = i !== j ? Math.exp(-dist * beta) : 0; + dp_sum += dist * pj; + prow[j] = pj; + psum += pj; + } + // compute entropy + const H = psum > 0 ? Math.log(psum) + (beta * dp_sum) / psum : 0; + if (H > Htarget) { + betamin = beta; + beta = betamax === Infinity ? beta * 2 : (beta + betamax) / 2; + } else { + betamax = beta; + beta = betamin === -Infinity ? beta / 2 : (beta + betamin) / 2; + } + done = Math.abs(H - Htarget) < tol; + } + // normalize p + for (let j = 0; j < N; ++j) { + prow[j] /= psum; + } } - done = Math.abs(H - Htarget) < tol; - } - // normalize p - for (let j = 0; j < N; ++j) { - prow[j] /= psum; - } - } - // compute probabilities - const N2 = N * 2; - for (let i = 0; i < N; ++i) { - for (let j = i; j < N; ++j) { - const p = Math.max((P.entry(i, j) + P.entry(j, i)) / N2, 1e-100); - P.set_entry(i, j, p); - P.set_entry(j, i, p); - } - } - this._P = P; - return this; - } - - /** - * @param {number} [iterations=500] - Number of iterations. Default is `500` - * @returns {T} The projection. - */ - transform(iterations = 500) { - this.check_init(); - for (let i = 0; i < iterations; ++i) { - this.next(); - } - return this.projection; - } - - /** - * @param {number} [iterations=500] - Number of iterations. Default is `500` - * @returns {Generator} - The projection. - */ - *generator(iterations = 500) { - this.check_init(); - for (let i = 0; i < iterations; ++i) { - this.next(); - yield this.projection; - } - return this.projection; - } - - /** - * Performs a optimization step - * - * @private - * @returns {Matrix} - */ - next() { - const iter = ++this._iter; - if (!this._P || !this._ystep || !this._gains) throw new Error("Call init() first!"); - const P = this._P; - const ystep = this._ystep; - const gains = this._gains; - const N = this._N; - const dim = /** @type {number} */ (this._parameters.d); - const epsilon = /** @type {number} */ (this._parameters.epsilon); - const Y = this.Y; - - //calc cost gradient; - const pmul = iter < 100 ? 4 : 1; - - // compute Q dist (unnormalized) - const Qu = new Matrix(N, N, "zeros"); - let qsum = 0; - for (let i = 0; i < N; ++i) { - for (let j = i + 1; j < N; ++j) { - let dsum = 0; - for (let d = 0; d < dim; ++d) { - const dhere = Y.entry(i, d) - Y.entry(j, d); - dsum += dhere * dhere; + // compute probabilities + const N2 = N * 2; + for (let i = 0; i < N; ++i) { + for (let j = i; j < N; ++j) { + const p = Math.max((P.entry(i, j) + P.entry(j, i)) / N2, 1e-100); + P.set_entry(i, j, p); + P.set_entry(j, i, p); + } } - const qu = 1 / (1 + dsum); - Qu.set_entry(i, j, qu); - Qu.set_entry(j, i, qu); - qsum += 2 * qu; - } + this._P = P; + return this; } - // normalize Q dist - const Q = new Matrix(N, N, 0); - for (let i = 0; i < N; ++i) { - for (let j = i + 1; j < N; ++j) { - const val = Math.max(Qu.entry(i, j) / qsum, 1e-100); - Q.set_entry(i, j, val); - Q.set_entry(j, i, val); - } + /** + * @param {number} [iterations=500] - Number of iterations. Default is `500` + * @returns {T} The projection. + */ + transform(iterations = 500) { + this.check_init(); + for (let i = 0; i < iterations; ++i) { + this.next(); + } + return this.projection; } - const grad = new Matrix(N, dim, "zeros"); - for (let i = 0; i < N; ++i) { - for (let j = 0; j < N; ++j) { - const premult = 4 * (pmul * P.entry(i, j) - Q.entry(i, j)) * Qu.entry(i, j); - for (let d = 0; d < dim; ++d) { - grad.add_entry(i, d, premult * (Y.entry(i, d) - Y.entry(j, d))); + /** + * @param {number} [iterations=500] - Number of iterations. Default is `500` + * @returns {Generator} - The projection. + */ + *generator(iterations = 500) { + this.check_init(); + for (let i = 0; i < iterations; ++i) { + this.next(); + yield this.projection; } - } + return this.projection; } - // perform gradient step - const ymean = new Float64Array(dim); - for (let i = 0; i < N; ++i) { - for (let d = 0; d < dim; ++d) { - const gid = grad.entry(i, d); - const sid = ystep.entry(i, d); - const gainid = gains.entry(i, d); + /** + * Performs a optimization step + * + * @private + * @returns {Matrix} + */ + next() { + const iter = ++this._iter; + if (!this._P || !this._ystep || !this._gains) throw new Error("Call init() first!"); + const P = this._P; + const ystep = this._ystep; + const gains = this._gains; + const N = this._N; + const dim = /** @type {number} */ (this._parameters.d); + const epsilon = /** @type {number} */ (this._parameters.epsilon); + const Y = this.Y; + + //calc cost gradient; + const pmul = iter < 100 ? 4 : 1; + + // compute Q dist (unnormalized) + const Qu = new Matrix(N, N, "zeros"); + let qsum = 0; + for (let i = 0; i < N; ++i) { + for (let j = i + 1; j < N; ++j) { + let dsum = 0; + for (let d = 0; d < dim; ++d) { + const dhere = Y.entry(i, d) - Y.entry(j, d); + dsum += dhere * dhere; + } + const qu = 1 / (1 + dsum); + Qu.set_entry(i, j, qu); + Qu.set_entry(j, i, qu); + qsum += 2 * qu; + } + } + + // normalize Q dist + const Q = new Matrix(N, N, 0); + for (let i = 0; i < N; ++i) { + for (let j = i + 1; j < N; ++j) { + const val = Math.max(Qu.entry(i, j) / qsum, 1e-100); + Q.set_entry(i, j, val); + Q.set_entry(j, i, val); + } + } + + const grad = new Matrix(N, dim, "zeros"); + for (let i = 0; i < N; ++i) { + for (let j = 0; j < N; ++j) { + const premult = 4 * (pmul * P.entry(i, j) - Q.entry(i, j)) * Qu.entry(i, j); + for (let d = 0; d < dim; ++d) { + grad.add_entry(i, d, premult * (Y.entry(i, d) - Y.entry(j, d))); + } + } + } - let newgain = Math.sign(gid) === Math.sign(sid) ? gainid * 0.8 : gainid + 0.2; - if (newgain < 0.01) newgain = 0.01; - gains.set_entry(i, d, newgain); + // perform gradient step + const ymean = new Float64Array(dim); + for (let i = 0; i < N; ++i) { + for (let d = 0; d < dim; ++d) { + const gid = grad.entry(i, d); + const sid = ystep.entry(i, d); + const gainid = gains.entry(i, d); + + let newgain = Math.sign(gid) === Math.sign(sid) ? gainid * 0.8 : gainid + 0.2; + if (newgain < 0.01) newgain = 0.01; + gains.set_entry(i, d, newgain); + + const momval = iter < 250 ? 0.5 : 0.8; + const newsid = momval * sid - epsilon * newgain * gid; + ystep.set_entry(i, d, newsid); + + Y.add_entry(i, d, newsid); + ymean[d] += Y.entry(i, d); + } + } + + for (let i = 0; i < N; ++i) { + for (let d = 0; d < dim; ++d) { + Y.sub_entry(i, d, ymean[d] / N); + } + } - const momval = iter < 250 ? 0.5 : 0.8; - const newsid = momval * sid - epsilon * newgain * gid; - ystep.set_entry(i, d, newsid); + return this.Y; + } - Y.add_entry(i, d, newsid); - ymean[d] += Y.entry(i, d); - } + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X, parameters) { + const dr = new TSNE(X, parameters); + return dr.transform(); } - for (let i = 0; i < N; ++i) { - for (let d = 0; d < dim; ++d) { - Y.sub_entry(i, d, ymean[d] / N); - } - } - - return this.Y; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X, parameters) { - const dr = new TSNE(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new TSNE(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new TSNE(X, parameters); - return dr.transform_async(); - } + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new TSNE(X, parameters); + yield* dr.generator(); + return dr.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new TSNE(X, parameters); + return dr.transform_async(); + } } /** @@ -10443,31 +11025,31 @@ class TSNE extends DR { * @see http://optimization-js.github.io/optimization-js/optimization.js.html#line438 */ function powell(f, x0, max_iter = 300) { - const epsilon = 1e-2; - const n = x0.length; - let alpha = 1e-3; - let pfx = 10000; - const x = /** @type {T} */ (x0.slice()); - let fx = f(x); - let convergence = false; - - while (max_iter-- >= 0 && !convergence) { - convergence = true; - for (let i = 0; i < n; ++i) { - x[i] += 1e-6; - const fxi = f(x); - x[i] -= 1e-6; - const dx = (fxi - fx) / 1e-6; - if (Math.abs(dx) > epsilon) { - convergence = false; - } - x[i] -= alpha * dx; - fx = f(x); - } - alpha *= pfx >= fx ? 1.05 : 0.4; - pfx = fx; - } - return x; + const epsilon = 1e-2; + const n = x0.length; + let alpha = 1e-3; + let pfx = 10000; + const x = /** @type {T} */ (x0.slice()); + let fx = f(x); + let convergence = false; + + while (max_iter-- >= 0 && !convergence) { + convergence = true; + for (let i = 0; i < n; ++i) { + x[i] += 1e-6; + const fxi = f(x); + x[i] -= 1e-6; + const dx = (fxi - fx) / 1e-6; + if (Math.abs(dx) > epsilon) { + convergence = false; + } + x[i] -= alpha * dx; + fx = f(x); + } + alpha *= pfx >= fx ? 1.05 : 0.4; + pfx = fx; + } + return x; } /** @import {InputType} from "../index.js" */ @@ -10503,552 +11085,484 @@ function powell(f, x0, max_iter = 300) { * // [[x1, y1], [x2, y2], [x3, y3]] */ class UMAP extends DR { - /** - * @param {T} X - The high-dimensional data. - * @param {Partial} [parameters] - Object containing parameterization of the DR method. - */ - constructor(X, parameters) { - super( - X, - { - n_neighbors: 15, - local_connectivity: 1, - min_dist: 1, - d: 2, - metric: euclidean, - seed: 1212, - _spread: 1, - _set_op_mix_ratio: 1, - _repulsion_strength: 1, - _negative_sample_rate: 5, - _n_epochs: 350, - _initial_alpha: 1, - }, - parameters, - ); - [this._N, this._D] = this.X.shape; - const n_neighbors = /** @type {number} */ (this.parameter("n_neighbors")); - const local_connectivity = /** @type {number} */ (this.parameter("local_connectivity")); - const d = /** @type {number} */ (this.parameter("d")); - /* let n_neighbors = Math.min(this._N - 1, parameters.n_neighbors); + /** + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + */ + constructor(X, parameters) { + super( + X, + { + n_neighbors: 15, + local_connectivity: 1, + min_dist: 1, + d: 2, + metric: euclidean, + seed: 1212, + _spread: 1, + _set_op_mix_ratio: 1, + _repulsion_strength: 1, + _negative_sample_rate: 5, + _n_epochs: 350, + _initial_alpha: 1, + }, + parameters, + ); + [this._N, this._D] = this.X.shape; + const n_neighbors = /** @type {number} */ (this.parameter("n_neighbors")); + const local_connectivity = /** @type {number} */ (this.parameter("local_connectivity")); + const d = /** @type {number} */ (this.parameter("d")); + /* let n_neighbors = Math.min(this._N - 1, parameters.n_neighbors); this.parameter("n_neighbors", n_neighbors); this.parameter("local_connectivity", Math.min(this.parameter("local_connectivity"), n_neighbors - 1)); */ - if (n_neighbors > this._N) { - throw new Error( - `Parameter n_neighbors (=${n_neighbors}) needs to be smaller than dataset size (N=${this._N})!`, - ); - } - if (local_connectivity > n_neighbors) { - throw new Error( - `Parameter local_connectivity (=${local_connectivity}) needs to be smaller than parameter n_neighbors (=${n_neighbors})`, - ); - } - this._iter = 0; - const randomizer = this._randomizer; - this.Y = new Matrix(this._N, d, () => randomizer.random); - } - - /** - * @private - * @param {number} spread - * @param {number} min_dist - * @returns {number[]} - */ - _find_ab_params(spread, min_dist) { - /** @type {(x: number, a: number, b: number) => number} */ - const curve = (x, a, b) => 1 / (1 + a * x ** (2 * b)); - const xv = linspace(0, spread * 3, 300); - const yv = linspace(0, spread * 3, 300); - - for (let i = 0, n = xv.length; i < n; ++i) { - const xv_i = xv[i]; - yv[i] = xv_i < min_dist ? 1 : Math.exp(-(xv_i - min_dist) / spread); - } - - /** @type {(p: [number, number]) => number} */ - const err = (p) => { - const error = linspace(1, 300).map((_, i) => yv[i] - curve(xv[i], p[0], p[1])); - return Math.sqrt(neumair_sum(error.map((e) => e * e))); - }; - - return powell(err, [1, 1]); - } - - /** - * @private - * @param {{ element: Float64Array; index: number; distance: number }[][]} distances - * @param {number[]} sigmas - * @param {number[]} rhos - * @returns {{ element: Float64Array; index: number; distance: number }[][]} - */ - _compute_membership_strengths(distances, sigmas, rhos) { - for (let i = 0, n = distances.length; i < n; ++i) { - const rho = rhos[i]; - const curr_dist = distances[i]; - for (let j = 0, m = curr_dist.length; j < m; ++j) { - const v = curr_dist[j].distance - rho; - curr_dist[j].distance = v > 0 ? Math.exp(-v / sigmas[i]) : 1.0; - } - } - return distances; - } - - /** - * @private - * @param {NaiveKNN | BallTree} knn - * @param {number} k - * @returns {{ - * distances: { element: Float64Array; index: number; distance: number }[][]; - * sigmas: number[]; - * rhos: number[]; - * }} - */ - _smooth_knn_dist(knn, k) { - const SMOOTH_K_TOLERANCE = 1e-5; - const MIN_K_DIST_SCALE = 1e-3; - const n_iter = 64; - const local_connectivity = /** @type {number} */ (this._parameters.local_connectivity); - const metric = /** @type {Metric | "precomputed"} */ (this._parameters.metric); - const target = Math.log2(k); - const rhos = []; - const sigmas = []; - const X = this.X; - const N = X.shape[0]; - //const distances = [...X].map(x_i => knn.search(x_i, k).raw_data().reverse()); - - /** @type {{ element: Float64Array; index: number; distance: number }[][]} */ - const distances = []; - if (metric === "precomputed" || knn instanceof NaiveKNN) { - for (let i = 0; i < N; ++i) { - distances.push(knn.search_by_index(i, k).reverse()); - } - } else { - for (const x_i of X) { - distances.push(knn.search(x_i, k).reverse()); - } + if (n_neighbors > this._N) { + throw new Error( + `Parameter n_neighbors (=${n_neighbors}) needs to be smaller than dataset size (N=${this._N})!`, + ); + } + if (local_connectivity > n_neighbors) { + throw new Error( + `Parameter local_connectivity (=${local_connectivity}) needs to be smaller than parameter n_neighbors (=${n_neighbors})`, + ); + } + this._iter = 0; + const randomizer = this._randomizer; + this.Y = new Matrix(this._N, d, () => randomizer.random); } - const index = Math.floor(local_connectivity); - const interpolation = local_connectivity - index; - for (let i = 0; i < N; ++i) { - let lo = 0; - let hi = Infinity; - let mid = 1; - let rho = 0; - - const search_result = distances[i]; - const non_zero_dist = search_result.filter((d) => d.distance > 0); - const non_zero_dist_length = non_zero_dist.length; - if (non_zero_dist_length >= local_connectivity) { - if (index > 0) { - rho = non_zero_dist[index - 1].distance; - if (interpolation > SMOOTH_K_TOLERANCE) { - rho += - interpolation * (non_zero_dist[index].distance - non_zero_dist[index - 1].distance); - } - } else { - rho = interpolation * non_zero_dist[0].distance; - } - } else if (non_zero_dist_length > 0) { - rho = non_zero_dist[non_zero_dist_length - 1].distance; - } - for (let x = 0; x < n_iter; ++x) { - let psum = 0; - for (let j = 0; j < k; ++j) { - const d = search_result[j].distance - rho; - psum += d > 0 ? Math.exp(-(d / mid)) : 1; - } - if (Math.abs(psum - target) < SMOOTH_K_TOLERANCE) { - break; - } - if (psum > target) { - [hi, mid] = [mid, (lo + hi) / 2]; + /** + * @private + * @param {number} spread + * @param {number} min_dist + * @returns {number[]} + */ + _find_ab_params(spread, min_dist) { + /** @type {(x: number, a: number, b: number) => number} */ + const curve = (x, a, b) => 1 / (1 + a * x ** (2 * b)); + const xv = linspace(0, spread * 3, 300); + const yv = linspace(0, spread * 3, 300); + + for (let i = 0, n = xv.length; i < n; ++i) { + const xv_i = xv[i]; + yv[i] = xv_i < min_dist ? 1 : Math.exp(-(xv_i - min_dist) / spread); + } + + /** @type {(p: [number, number]) => number} */ + const err = (p) => { + const error = linspace(1, 300).map((_, i) => yv[i] - curve(xv[i], p[0], p[1])); + return Math.sqrt(neumair_sum(error.map((e) => e * e))); + }; + + return powell(err, [1, 1]); + } + + /** + * @private + * @param {{ element: Float64Array; index: number; distance: number }[][]} distances + * @param {number[]} sigmas + * @param {number[]} rhos + * @returns {{ element: Float64Array; index: number; distance: number }[][]} + */ + _compute_membership_strengths(distances, sigmas, rhos) { + for (let i = 0, n = distances.length; i < n; ++i) { + const rho = rhos[i]; + const curr_dist = distances[i]; + for (let j = 0, m = curr_dist.length; j < m; ++j) { + const v = curr_dist[j].distance - rho; + curr_dist[j].distance = v > 0 ? Math.exp(-v / sigmas[i]) : 1.0; + } + } + return distances; + } + + /** + * @private + * @param {NaiveKNN | BallTree} knn + * @param {number} k + * @returns {{ + * distances: { element: Float64Array; index: number; distance: number }[][]; + * sigmas: number[]; + * rhos: number[]; + * }} + */ + _smooth_knn_dist(knn, k) { + const SMOOTH_K_TOLERANCE = 1e-5; + const MIN_K_DIST_SCALE = 1e-3; + const n_iter = 64; + const local_connectivity = /** @type {number} */ (this._parameters.local_connectivity); + const metric = /** @type {Metric | "precomputed"} */ (this._parameters.metric); + const target = Math.log2(k); + const rhos = []; + const sigmas = []; + const X = this.X; + const N = X.shape[0]; + //const distances = [...X].map(x_i => knn.search(x_i, k).raw_data().reverse()); + + /** @type {{ element: Float64Array; index: number; distance: number }[][]} */ + const distances = []; + if (metric === "precomputed" || knn instanceof NaiveKNN) { + for (let i = 0; i < N; ++i) { + distances.push(knn.search_by_index(i, k).reverse()); + } } else { - if (hi === Infinity) { - [lo, mid] = [mid, mid * 2]; - } else { - [lo, mid] = [mid, (lo + hi) / 2]; - } - } - } - - //let mean_d = null; - if (rho > 0) { - const mean_ithd = search_result.reduce((a, b) => a + b.distance, 0) / search_result.length; - if (mid < MIN_K_DIST_SCALE * mean_ithd) { - mid = MIN_K_DIST_SCALE * mean_ithd; - } - } else { - const mean_d = distances.reduce( - (acc, res) => acc + res.reduce((a, b) => a + b.distance, 0) / res.length, - 0, - ); - if (mid < MIN_K_DIST_SCALE * mean_d) { - mid = MIN_K_DIST_SCALE * mean_d; - } - } - rhos[i] = rho; - sigmas[i] = mid; - } - return { - distances: distances, - sigmas: sigmas, - rhos: rhos, - }; - } - - /** - * @private - * @param {Matrix} X - * @param {number} n_neighbors - * @returns {Matrix} - */ - _fuzzy_simplicial_set(X, n_neighbors) { - const N = X.shape[0]; - const metric = /** @type {Metric | "precomputed"} */ (this._parameters.metric); - const _set_op_mix_ratio = /** @type {number} */ (this._parameters._set_op_mix_ratio); - - const knn = - metric === "precomputed" - ? new NaiveKNN(X.to2dArray(), { - metric: "precomputed", - seed: /** @type {number} */ (this._parameters.seed), - }) - : new BallTree(X.to2dArray(), { - metric, - seed: /** @type {number} */ (this._parameters.seed), - }); - let { distances, sigmas, rhos } = this._smooth_knn_dist(knn, n_neighbors); - distances = this._compute_membership_strengths(distances, sigmas, rhos); - const result = new Matrix(N, N, "zeros"); - for (let i = 0; i < N; ++i) { - const distances_i = distances[i]; - for (let j = 0; j < distances_i.length; ++j) { - result.set_entry(i, distances_i[j].index, distances_i[j].distance); - } - } - - const transposed_result = result.T; - const prod_matrix = result.mult(transposed_result); - return result - .add(transposed_result) - .sub(prod_matrix) - .mult(_set_op_mix_ratio) - .add(prod_matrix.mult(1 - _set_op_mix_ratio)); - } - - /** - * @private - * @param {number} n_epochs - * @returns {Float32Array} - */ - _make_epochs_per_sample(n_epochs) { - if (!this._weights) throw new Error("Call init() first!"); - const weights = this._weights; - const result = new Float32Array(weights.length).fill(-1); - const weight_scl = n_epochs / max(weights); - weights.forEach((w, i) => { - const sample = w * weight_scl; - if (sample > 0) result[i] = Math.round(n_epochs / sample); - }); - return result; - } - - /** - * @private - * @param {Matrix} graph - * @returns {{ rows: number[]; cols: number[]; data: number[] }} - */ - _tocoo(graph) { - const rows = []; - const cols = []; - const data = []; - const [rows_n, cols_n] = graph.shape; - for (let row = 0; row < rows_n; ++row) { - for (let col = 0; col < cols_n; ++col) { - const entry = graph.entry(row, col); - if (entry !== 0) { - rows.push(row); - cols.push(col); - data.push(entry); - } - } - } - return { - rows: rows, - cols: cols, - data: data, - }; - } - - /** - * Computes all necessary - * - * @returns {UMAP} - */ - init() { - const _spread = /** @type {number} */ (this._parameters._spread); - const min_dist = /** @type {number} */ (this._parameters.min_dist); - const n_neighbors = /** @type {number} */ (this._parameters.n_neighbors); - const _n_epochs = /** @type {number} */ (this._parameters._n_epochs); - const _negative_sample_rate = /** @type {number} */ (this._parameters._negative_sample_rate); - const [a, b] = this._find_ab_params(_spread, min_dist); - this._a = a; - this._b = b; - this._graph = this._fuzzy_simplicial_set(this.X, n_neighbors); - const { rows, cols, data: weights } = this._tocoo(this._graph); - this._head = rows; - this._tail = cols; - this._weights = weights; - this._epochs_per_sample = this._make_epochs_per_sample(_n_epochs); - this._epochs_per_negative_sample = this._epochs_per_sample.map( - (d) => d * _negative_sample_rate, - ); - this._epoch_of_next_sample = this._epochs_per_sample.slice(); - this._epoch_of_next_negative_sample = this._epochs_per_negative_sample.slice(); - return this; - } - - graph() { - this.check_init(); - return { cols: this._head, rows: this._tail, weights: this._weights }; - } - - /** - * @param {number} [iterations=350] - Number of iterations. Default is `350` - * @returns {T} - */ - transform(iterations = 350) { - if (this.parameter("_n_epochs") !== iterations) { - this.parameter("_n_epochs", iterations); - this.init(); - } - this.check_init(); - for (let i = 0; i < iterations; ++i) { - this.next(); - } - return this.projection; - } - - /** - * @param {number} [iterations=350] - Number of iterations. Default is `350` - * @returns {Generator} - */ - *generator(iterations = 350) { - if (this.parameter("_n_epochs") !== iterations) { - this.parameter("_n_epochs", iterations); - this.init(); - } - this.check_init(); - for (let i = 0; i < iterations; ++i) { - this.next(); - yield this.projection; - } - return this.projection; - } - - /** - * @private - * @param {number} x - * @returns {number} - */ - _clip(x) { - if (x > 4) return 4; - if (x < -4) return -4; - return x; - } - - /** - * Performs the optimization step. - * - * @private - * @param {Matrix} head_embedding - * @param {Matrix} tail_embedding - * @param {number[]} head - * @param {number[]} tail - * @returns {Matrix} - */ - _optimize_layout(head_embedding, tail_embedding, head, tail) { - const randomizer = this._randomizer; - const _repulsion_strength = /** @type {number} */ (this.parameter("_repulsion_strength")); - const dim = /** @type {number} */ (this.parameter("d")); - const { - _alpha: alpha, - _a: a, - _b: b, - _epochs_per_sample: epochs_per_sample, - _epochs_per_negative_sample: epochs_per_negative_sample, - _epoch_of_next_negative_sample: epoch_of_next_negative_sample, - _epoch_of_next_sample: epoch_of_next_sample, - _clip: clip, - } = this; - if ( - alpha === undefined || - a === undefined || - b === undefined || - epochs_per_sample === undefined || - epochs_per_negative_sample === undefined || - epoch_of_next_negative_sample === undefined || - epoch_of_next_sample === undefined || - clip === undefined - ) { - throw new Error("call init() first!"); - } - const tail_length = tail.length; - - for (let i = 0, n = epochs_per_sample.length; i < n; ++i) { - if (epoch_of_next_sample[i] <= this._iter) { - const j = head[i]; - const k = tail[i]; - const current = head_embedding.row(j); - const other = tail_embedding.row(k); - const dist = euclidean_squared(current, other); - if (dist > 0) { - const grad_coeff = (-2 * a * b * dist ** (b - 1)) / (a * dist ** b + 1); - for (let d = 0; d < dim; ++d) { - const grad_d = clip(grad_coeff * (current[d] - other[d])) * alpha; - current[d] += grad_d; - other[d] -= grad_d; - } - } - epoch_of_next_sample[i] += epochs_per_sample[i]; - const n_neg_samples = - (this._iter - epoch_of_next_negative_sample[i]) / epochs_per_negative_sample[i]; - for (let p = 0; p < n_neg_samples; ++p) { - const k = randomizer.random_int % tail_length; - const other = tail_embedding.row(tail[k]); - const dist = euclidean_squared(current, other); - if (dist > 0) { - const grad_coeff = - (2 * _repulsion_strength * b) / ((0.01 + dist) * (a * dist ** b + 1)); - for (let d = 0; d < dim; ++d) { - const grad_d = clip(grad_coeff * (current[d] - other[d])) * alpha; - current[d] += grad_d; - other[d] -= grad_d; - } - } - } - epoch_of_next_negative_sample[i] += n_neg_samples * epochs_per_negative_sample[i]; - } - } - return head_embedding; - } - - /** - * @private - * @returns {Matrix} - */ - next() { - if (!this._head || !this._tail) throw new Error("Call init() first!"); - const iter = ++this._iter; - const Y = this.Y; - const _initial_alpha = /** @type {number} */ (this._parameters._initial_alpha); - const _n_epochs = /** @type {number} */ (this._parameters._n_epochs); - this._alpha = _initial_alpha * (1 - iter / _n_epochs); - this.Y = this._optimize_layout(Y, Y, this._head, this._tail); - - return this.Y; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {T} - */ - static transform(X, parameters) { - const dr = new UMAP(X, parameters); - return dr.transform(); - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Generator} - */ - static *generator(X, parameters) { - const dr = new UMAP(X, parameters); - yield* dr.generator(); - return dr.projection; - } - - /** - * @template {InputType} T - * @param {T} X - * @param {Partial} [parameters] - * @returns {Promise} - */ - static async transform_async(X, parameters) { - const dr = new UMAP(X, parameters); - return dr.transform_async(); - } + for (const x_i of X) { + distances.push(knn.search(x_i, k).reverse()); + } + } + + const index = Math.floor(local_connectivity); + const interpolation = local_connectivity - index; + for (let i = 0; i < N; ++i) { + let lo = 0; + let hi = Infinity; + let mid = 1; + let rho = 0; + + const search_result = distances[i]; + const non_zero_dist = search_result.filter((d) => d.distance > 0); + const non_zero_dist_length = non_zero_dist.length; + if (non_zero_dist_length >= local_connectivity) { + if (index > 0) { + rho = non_zero_dist[index - 1].distance; + if (interpolation > SMOOTH_K_TOLERANCE) { + rho += interpolation * (non_zero_dist[index].distance - non_zero_dist[index - 1].distance); + } + } else { + rho = interpolation * non_zero_dist[0].distance; + } + } else if (non_zero_dist_length > 0) { + rho = non_zero_dist[non_zero_dist_length - 1].distance; + } + for (let x = 0; x < n_iter; ++x) { + let psum = 0; + for (let j = 0; j < k; ++j) { + const d = search_result[j].distance - rho; + psum += d > 0 ? Math.exp(-(d / mid)) : 1; + } + if (Math.abs(psum - target) < SMOOTH_K_TOLERANCE) { + break; + } + if (psum > target) { + [hi, mid] = [mid, (lo + hi) / 2]; + } else { + if (hi === Infinity) { + [lo, mid] = [mid, mid * 2]; + } else { + [lo, mid] = [mid, (lo + hi) / 2]; + } + } + } + + //let mean_d = null; + if (rho > 0) { + const mean_ithd = search_result.reduce((a, b) => a + b.distance, 0) / search_result.length; + if (mid < MIN_K_DIST_SCALE * mean_ithd) { + mid = MIN_K_DIST_SCALE * mean_ithd; + } + } else { + const mean_d = distances.reduce( + (acc, res) => acc + res.reduce((a, b) => a + b.distance, 0) / res.length, + 0, + ); + if (mid < MIN_K_DIST_SCALE * mean_d) { + mid = MIN_K_DIST_SCALE * mean_d; + } + } + rhos[i] = rho; + sigmas[i] = mid; + } + return { + distances: distances, + sigmas: sigmas, + rhos: rhos, + }; + } + + /** + * @private + * @param {Matrix} X + * @param {number} n_neighbors + * @returns {Matrix} + */ + _fuzzy_simplicial_set(X, n_neighbors) { + const N = X.shape[0]; + const metric = /** @type {Metric | "precomputed"} */ (this._parameters.metric); + const _set_op_mix_ratio = /** @type {number} */ (this._parameters._set_op_mix_ratio); + + const knn = + metric === "precomputed" + ? new NaiveKNN(X.to2dArray(), { + metric: "precomputed", + seed: /** @type {number} */ (this._parameters.seed), + }) + : new BallTree(X.to2dArray(), { + metric, + seed: /** @type {number} */ (this._parameters.seed), + }); + let { distances, sigmas, rhos } = this._smooth_knn_dist(knn, n_neighbors); + distances = this._compute_membership_strengths(distances, sigmas, rhos); + const result = new Matrix(N, N, "zeros"); + for (let i = 0; i < N; ++i) { + const distances_i = distances[i]; + for (let j = 0; j < distances_i.length; ++j) { + result.set_entry(i, distances_i[j].index, distances_i[j].distance); + } + } + + const transposed_result = result.T; + const prod_matrix = result.mult(transposed_result); + return result + .add(transposed_result) + .sub(prod_matrix) + .mult(_set_op_mix_ratio) + .add(prod_matrix.mult(1 - _set_op_mix_ratio)); + } + + /** + * @private + * @param {number} n_epochs + * @returns {Float32Array} + */ + _make_epochs_per_sample(n_epochs) { + if (!this._weights) throw new Error("Call init() first!"); + const weights = this._weights; + const result = new Float32Array(weights.length).fill(-1); + const weight_scl = n_epochs / max(weights); + weights.forEach((w, i) => { + const sample = w * weight_scl; + if (sample > 0) result[i] = Math.round(n_epochs / sample); + }); + return result; + } + + /** + * @private + * @param {Matrix} graph + * @returns {{ rows: number[]; cols: number[]; data: number[] }} + */ + _tocoo(graph) { + const rows = []; + const cols = []; + const data = []; + const [rows_n, cols_n] = graph.shape; + for (let row = 0; row < rows_n; ++row) { + for (let col = 0; col < cols_n; ++col) { + const entry = graph.entry(row, col); + if (entry !== 0) { + rows.push(row); + cols.push(col); + data.push(entry); + } + } + } + return { + rows: rows, + cols: cols, + data: data, + }; + } + + /** + * Computes all necessary + * + * @returns {UMAP} + */ + init() { + const _spread = /** @type {number} */ (this._parameters._spread); + const min_dist = /** @type {number} */ (this._parameters.min_dist); + const n_neighbors = /** @type {number} */ (this._parameters.n_neighbors); + const _n_epochs = /** @type {number} */ (this._parameters._n_epochs); + const _negative_sample_rate = /** @type {number} */ (this._parameters._negative_sample_rate); + const [a, b] = this._find_ab_params(_spread, min_dist); + this._a = a; + this._b = b; + this._graph = this._fuzzy_simplicial_set(this.X, n_neighbors); + const { rows, cols, data: weights } = this._tocoo(this._graph); + this._head = rows; + this._tail = cols; + this._weights = weights; + this._epochs_per_sample = this._make_epochs_per_sample(_n_epochs); + this._epochs_per_negative_sample = this._epochs_per_sample.map((d) => d * _negative_sample_rate); + this._epoch_of_next_sample = this._epochs_per_sample.slice(); + this._epoch_of_next_negative_sample = this._epochs_per_negative_sample.slice(); + return this; + } + + graph() { + this.check_init(); + return { cols: this._head, rows: this._tail, weights: this._weights }; + } + + /** + * @param {number} [iterations=350] - Number of iterations. Default is `350` + * @returns {T} + */ + transform(iterations = 350) { + if (this.parameter("_n_epochs") !== iterations) { + this.parameter("_n_epochs", iterations); + this.init(); + } + this.check_init(); + for (let i = 0; i < iterations; ++i) { + this.next(); + } + return this.projection; + } + + /** + * @param {number} [iterations=350] - Number of iterations. Default is `350` + * @returns {Generator} + */ + *generator(iterations = 350) { + if (this.parameter("_n_epochs") !== iterations) { + this.parameter("_n_epochs", iterations); + this.init(); + } + this.check_init(); + for (let i = 0; i < iterations; ++i) { + this.next(); + yield this.projection; + } + return this.projection; + } + + /** + * @private + * @param {number} x + * @returns {number} + */ + _clip(x) { + if (x > 4) return 4; + if (x < -4) return -4; + return x; + } + + /** + * Performs the optimization step. + * + * @private + * @param {Matrix} head_embedding + * @param {Matrix} tail_embedding + * @param {number[]} head + * @param {number[]} tail + * @returns {Matrix} + */ + _optimize_layout(head_embedding, tail_embedding, head, tail) { + const randomizer = this._randomizer; + const _repulsion_strength = /** @type {number} */ (this.parameter("_repulsion_strength")); + const dim = /** @type {number} */ (this.parameter("d")); + const { + _alpha: alpha, + _a: a, + _b: b, + _epochs_per_sample: epochs_per_sample, + _epochs_per_negative_sample: epochs_per_negative_sample, + _epoch_of_next_negative_sample: epoch_of_next_negative_sample, + _epoch_of_next_sample: epoch_of_next_sample, + _clip: clip, + } = this; + if ( + alpha === undefined || + a === undefined || + b === undefined || + epochs_per_sample === undefined || + epochs_per_negative_sample === undefined || + epoch_of_next_negative_sample === undefined || + epoch_of_next_sample === undefined || + clip === undefined + ) { + throw new Error("call init() first!"); + } + const tail_length = tail.length; + + for (let i = 0, n = epochs_per_sample.length; i < n; ++i) { + if (epoch_of_next_sample[i] <= this._iter) { + const j = head[i]; + const k = tail[i]; + const current = head_embedding.row(j); + const other = tail_embedding.row(k); + const dist = euclidean_squared(current, other); + if (dist > 0) { + const grad_coeff = (-2 * a * b * dist ** (b - 1)) / (a * dist ** b + 1); + for (let d = 0; d < dim; ++d) { + const grad_d = clip(grad_coeff * (current[d] - other[d])) * alpha; + current[d] += grad_d; + other[d] -= grad_d; + } + } + epoch_of_next_sample[i] += epochs_per_sample[i]; + const n_neg_samples = (this._iter - epoch_of_next_negative_sample[i]) / epochs_per_negative_sample[i]; + for (let p = 0; p < n_neg_samples; ++p) { + const k = randomizer.random_int % tail_length; + const other = tail_embedding.row(tail[k]); + const dist = euclidean_squared(current, other); + if (dist > 0) { + const grad_coeff = (2 * _repulsion_strength * b) / ((0.01 + dist) * (a * dist ** b + 1)); + for (let d = 0; d < dim; ++d) { + const grad_d = clip(grad_coeff * (current[d] - other[d])) * alpha; + current[d] += grad_d; + other[d] -= grad_d; + } + } + } + epoch_of_next_negative_sample[i] += n_neg_samples * epochs_per_negative_sample[i]; + } + } + return head_embedding; + } + + /** + * @private + * @returns {Matrix} + */ + next() { + if (!this._head || !this._tail) throw new Error("Call init() first!"); + const iter = ++this._iter; + const Y = this.Y; + const _initial_alpha = /** @type {number} */ (this._parameters._initial_alpha); + const _n_epochs = /** @type {number} */ (this._parameters._n_epochs); + this._alpha = _initial_alpha * (1 - iter / _n_epochs); + this.Y = this._optimize_layout(Y, Y, this._head, this._tail); + + return this.Y; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X, parameters) { + const dr = new UMAP(X, parameters); + return dr.transform(); + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new UMAP(X, parameters); + yield* dr.generator(); + return dr.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new UMAP(X, parameters); + return dr.transform_async(); + } } const version = pkg.version; -export { - Annoy, - BallTree, - CURE, - DisjointSet, - FASTMAP, - HNSW, - Heap, - HierarchicalClustering, - ISOMAP, - KDTree, - KMeans, - KMedoids, - LDA, - LLE, - LSH, - LSP, - LTSA, - MDS, - Matrix, - MeanShift, - NNDescent, - NaiveKNN, - OPTICS, - PCA, - Randomizer, - SAMMON, - SMACOF, - SQDMDS, - TSNE, - TopoMap, - TriMap, - UMAP, - XMeans, - bray_curtis, - canberra, - chebyshev, - cosine, - distance_matrix, - euclidean, - euclidean_squared, - goodman_kruskal, - hamming, - haversine, - inner_product, - jaccard, - k_nearest_neighbors, - kahan_sum, - linspace, - manhattan, - max, - min, - neumair_sum, - norm, - normalize, - powell, - qr, - qr_householder, - simultaneous_poweriteration, - sokal_michener, - version, - wasserstein, - yule, -}; +export { Annoy, BallTree, CURE, DisjointSet, FASTMAP, HNSW, Heap, HierarchicalClustering, ISOMAP, KDTree, KMeans, KMedoids, LDA, LLE, LSH, LSP, LTSA, LocalMAP, MDS, Matrix, MeanShift, NNDescent, NaiveKNN, OPTICS, PCA, PaCMAP, Randomizer, SAMMON, SMACOF, SQDMDS, TSNE, TopoMap, TriMap, UMAP, XMeans, bray_curtis, canberra, chebyshev, cosine, distance_matrix, euclidean, euclidean_squared, goodman_kruskal, hamming, haversine, inner_product, jaccard, k_nearest_neighbors, kahan_sum, linspace, manhattan, max, min, neumair_sum, norm, normalize, powell, qr, qr_householder, simultaneous_poweriteration, sokal_michener, version, wasserstein, yule }; //# sourceMappingURL=druid.js.map diff --git a/dist/druid.js.map b/dist/druid.js.map index f9ee6f5..d5d40ef 100644 --- a/dist/druid.js.map +++ b/dist/druid.js.map @@ -1 +1 @@ -{"version":3,"file":"druid.js","sources":["../src/metrics/bray_curtis.js","../src/metrics/canberra.js","../src/metrics/chebyshev.js","../src/metrics/cosine.js","../src/metrics/euclidean_squared.js","../src/metrics/euclidean.js","../src/metrics/goodman_kruskal.js","../src/metrics/hamming.js","../src/metrics/haversine.js","../src/metrics/jaccard.js","../src/metrics/manhattan.js","../src/metrics/sokal_michener.js","../src/metrics/wasserstein.js","../src/metrics/yule.js","../src/matrix/distance_matrix.js","../src/matrix/k_nearest_neighbors.js","../src/matrix/linspace.js","../src/linear_algebra/inner_product.js","../src/numerical/kahan_sum.js","../src/numerical/neumair_sum.js","../src/linear_algebra/qr.js","../src/linear_algebra/qr_householder.js","../src/util/max.js","../src/util/min.js","../src/util/randomizer.js","../src/linear_algebra/simultaneous_poweriteration.js","../src/matrix/Matrix.js","../src/matrix/norm.js","../src/matrix/normalize.js","../src/clustering/Clustering.js","../src/clustering/CURE.js","../src/clustering/Hierarchical_Clustering.js","../src/datastructure/DisjointSet.js","../src/datastructure/Heap.js","../src/clustering/KMeans.js","../src/clustering/KMedoids.js","../src/clustering/MeanShift.js","../src/clustering/OPTICS.js","../src/clustering/XMeans.js","../src/dimred/DR.js","../src/dimred/FASTMAP.js","../src/knn/KNN.js","../src/knn/Annoy.js","../src/knn/BallTree.js","../src/knn/HNSW.js","../src/knn/KDTree.js","../src/knn/LSH.js","../src/knn/NaiveKNN.js","../src/knn/NNDescent.js","../src/dimred/SMACOF.js","../src/dimred/ISOMAP.js","../src/dimred/LDA.js","../src/dimred/LLE.js","../src/dimred/MDS.js","../src/dimred/LSP.js","../src/dimred/LTSA.js","../src/dimred/PCA.js","../src/dimred/SAMMON.js","../src/dimred/SQDMDS.js","../src/dimred/TopoMap.js","../src/dimred/TriMap.js","../src/dimred/TSNE.js","../src/optimization/powell.js","../src/dimred/UMAP.js","../src/index.js"],"sourcesContent":["/**\n * Computes the Bray-Curtis distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The Bray-Curtis distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Bray%E2%80%93Curtis_dissimilarity}\n */\nexport function bray_curtis(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n let sum_abs_diff = 0;\n let sum_ab = 0;\n for (let i = 0; i < a.length; ++i) {\n sum_abs_diff += Math.abs(a[i] - b[i]);\n sum_ab += a[i] + b[i];\n }\n return sum_abs_diff / sum_ab;\n}\n","/**\n * Computes the canberra distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The canberra distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Canberra_distance}\n */\nexport function canberra(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let sum = 0;\n for (let i = 0; i < n; ++i) {\n sum += Math.abs(a[i] - b[i]) / (Math.abs(a[i]) + Math.abs(b[i]));\n }\n return sum;\n}\n","/**\n * Computes the chebyshev distance (L) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The chebyshev distance between `a` and `b`.\n */\nexport function chebyshev(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n const res = [];\n for (let i = 0; i < n; ++i) {\n res.push(Math.abs(a[i] - b[i]));\n }\n return Math.max(...res);\n}\n","/**\n * Computes the cosine distance (not similarity) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The cosine distance between `a` and `b`.\n * @example\n * import { cosine } from \"@saehrimnir/druidjs\";\n * const a = [1, 2, 3];\n * const b = [4, 5, 6];\n * const distance = cosine(a, b); // 0.9746318461970762\n */\nexport function cosine(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let sum = 0;\n let sum_a = 0;\n let sum_b = 0;\n for (let i = 0; i < n; ++i) {\n sum += a[i] * b[i];\n sum_a += a[i] * a[i];\n sum_b += b[i] * b[i];\n }\n return Math.acos(sum / (Math.sqrt(sum_a) * Math.sqrt(sum_b)));\n}\n","/**\n * Computes the squared euclidean distance (l_2^2) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The squared euclidean distance between `a` and `b`.\n\n */\nexport function euclidean_squared(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let sum = 0;\n for (let i = 0; i < n; ++i) {\n const a_b = a[i] - b[i];\n sum += a_b * a_b;\n }\n return sum;\n}\n","import { euclidean_squared } from \"../metrics/euclidean_squared.js\";\n\n/**\n * Computes the euclidean distance (`l_2`) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The euclidean distance between `a` and `b`.\n */\nexport function euclidean(a, b) {\n return Math.sqrt(euclidean_squared(a, b));\n}\n","/**\n * Computes the Goodman-Kruskal gamma coefficient for ordinal association.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a - First categorical/ordinal variable\n * @param {number[] | Float64Array} b - Second categorical/ordinal variable\n * @returns {number} The Goodman-Kruskal gamma coefficient between `a` and `b` (-1 to 1).\n * @see {@link https://en.wikipedia.org/wiki/Goodman_and_Kruskal%27s_gamma}\n */\nexport function goodman_kruskal(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n if (n < 2) return 0;\n\n let concordant = 0;\n let discordant = 0;\n let tie_a = 0;\n let tie_b = 0;\n\n for (let i = 0; i < n; ++i) {\n for (let j = i + 1; j < n; ++j) {\n const a_diff = a[i] - a[j];\n const b_diff = b[i] - b[j];\n const a_tied = a_diff === 0;\n const b_tied = b_diff === 0;\n\n if (a_tied && b_tied) {\n } else if (a_tied) {\n tie_a++;\n } else if (b_tied) {\n tie_b++;\n } else if (a_diff * b_diff > 0) {\n concordant++;\n } else {\n discordant++;\n }\n }\n }\n\n const denominator = concordant + discordant + tie_a + tie_b;\n if (denominator === 0) return 0;\n\n const numerator = concordant + discordant;\n if (numerator === 0) return 0;\n\n return (concordant - discordant) / numerator;\n}\n","/**\n * Computes the hamming distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The hamming distance between `a` and `b`.\n */\nexport function hamming(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let disagree = 0;\n for (let i = 0; i < n; ++i) {\n const x = a[i];\n const y = b[i];\n disagree += x !== y ? 1 : 0;\n }\n return disagree / n;\n}\n","/**\n * Computes the Haversine distance between two points on a sphere of unit length 1. Multiply the result with the radius of the sphere. (For instance Earth's radius is 6371km)\n *\n * @category Metrics\n * @param {number[] | Float64Array} a - Point [lat1, lon1] in radians\n * @param {number[] | Float64Array} b - Point [lat2, lon2] in radians\n * @returns {number} The Haversine distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Haversine_formula}\n */\nexport function haversine(a, b) {\n if (a.length !== 2 || b.length !== 2)\n throw new Error(\"Haversine distance requires exactly 2 coordinates [lat, lon] for each point!\");\n const lat1 = a[0];\n const lon1 = a[1];\n const lat2 = b[0];\n const lon2 = b[1];\n\n const dlat = lat2 - lat1;\n const dlon = lon2 - lon1;\n\n const sin_dlat2 = Math.sin(dlat / 2);\n const sin_dlon2 = Math.sin(dlon / 2);\n\n const x = sin_dlat2 * sin_dlat2 + Math.cos(lat1) * Math.cos(lat2) * sin_dlon2 * sin_dlon2;\n const c = 2 * Math.atan2(Math.sqrt(x), Math.sqrt(1 - x));\n\n return c;\n}\n","/**\n * Computes the jaccard distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The jaccard distance between `a` and `b`.\n */\nexport function jaccard(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let num_non_zero = 0;\n let num_equal = 0;\n for (let i = 0; i < n; ++i) {\n const x = a[i] !== 0;\n const y = b[i] !== 0;\n num_non_zero += x || y ? 1 : 0;\n num_equal += x && y ? 1 : 0;\n }\n return (num_non_zero - num_equal) / num_non_zero;\n}\n","/**\n * Computes the manhattan distance (`l_1`) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The manhattan distance between `a` and `b`.\n */\nexport function manhattan(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let sum = 0;\n for (let i = 0; i < n; ++i) {\n sum += Math.abs(a[i] - b[i]);\n }\n return sum;\n}\n","/**\n * Computes the Sokal-Michener distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The Sokal-Michener distance between `a` and `b`.\n\n */\nexport function sokal_michener(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let num_not_equal = 0;\n for (let i = 0; i < n; ++i) {\n const x = a[i] !== 0;\n const y = b[i] !== 0;\n num_not_equal += x !== y ? 1 : 0;\n }\n return (2 * num_not_equal) / (n + num_not_equal);\n}\n","/**\n * Computes the 1D Wasserstein distance (Earth Mover's Distance) between two distributions.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a - First distribution (histogram or probability mass)\n * @param {number[] | Float64Array} b - Second distribution (histogram or probability mass)\n * @returns {number} The Wasserstein/EMD distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Wasserstein_metric}\n */\nexport function wasserstein(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let sumA = 0;\n let sumB = 0;\n for (let i = 0; i < n; i++) {\n sumA += a[i];\n sumB += b[i];\n }\n\n // Fallback if sums are 0\n if (sumA === 0 && sumB === 0) return 0;\n if (sumA === 0 || sumB === 0) return Infinity;\n\n let distance = 0;\n let cumA = 0;\n let cumB = 0;\n for (let i = 0; i < n; i++) {\n cumA += a[i] / sumA;\n cumB += b[i] / sumB;\n distance += Math.abs(cumA - cumB);\n }\n return distance;\n}\n","/**\n * Computes the yule distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The yule distance between `a` and `b`.\n */\nexport function yule(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let num_true_true = 0;\n let num_true_false = 0;\n let num_false_true = 0;\n for (let i = 0; i < n; ++i) {\n const x = a[i] !== 0;\n const y = b[i] !== 0;\n num_true_true += x && y ? 1 : 0;\n num_true_false += x && !y ? 1 : 0;\n num_false_true += !x && y ? 1 : 0;\n }\n const num_false_false = n - num_true_true - num_true_false - num_false_true;\n return num_true_false === 0 || num_false_true === 0\n ? 0\n : (2 * num_true_false * num_false_true) / (num_true_true * num_false_false + num_true_false * num_false_true);\n}\n","import { euclidean } from \"../metrics/index.js\";\nimport { Matrix } from \"./index.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n\n/**\n * @param {Matrix | Float64Array[] | number[][]} A\n * @returns {A is Matrix}\n */\nfunction isMatrix(A) {\n return A instanceof Matrix;\n}\n\n/**\n * Computes the distance matrix of datamatrix `A`.\n *\n * @category Matrix\n * @param {Matrix | Float64Array[] | number[][]} A - Matrix.\n * @param {Metric} [metric=euclidean] - The diistance metric. Default is `euclidean`\n * @returns {Matrix} The distance matrix of `A`.\n */\nexport function distance_matrix(A, metric = euclidean) {\n /** @type {number} */\n const n = isMatrix(A) ? A.shape[0] : A.length;\n const D = new Matrix(n, n);\n for (let i = 0; i < n; ++i) {\n const A_i = isMatrix(A) ? A.row(i) : A[i];\n for (let j = i + 1; j < n; ++j) {\n const dist = metric(A_i, isMatrix(A) ? A.row(j) : A[j]);\n D.set_entry(i, j, dist);\n D.set_entry(j, i, dist);\n }\n }\n return D;\n}\n","//@ts-check\n\nimport { distance_matrix, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n\n/**\n * Computes the k-nearest neighbors of each row of `A`.\n *\n * @category Matrix\n * @param {Matrix} A - Either the data matrix, or a distance matrix.\n * @param {number} k - The number of neighbors to compute.\n * @param {Metric | \"precomputed\"} [metric=euclidean] Default is `euclidean`\n * @returns {{ i: number; j: number; distance: number }[][]} The kNN graph.\n */\nexport function k_nearest_neighbors(A, k, metric = euclidean) {\n A = A instanceof Matrix ? A : Matrix.from(A);\n const rows = A.shape[0];\n const D = metric === \"precomputed\" ? A : distance_matrix(A, metric);\n /** @type {{ i: number; j: number; distance: number }[][]} */\n const nN = [];\n for (let row = 0; row < rows; ++row) {\n const res = Array.from(D.row(row))\n .map((distance, col) => {\n return {\n i: row,\n j: col,\n distance: distance,\n };\n })\n .sort((a, b) => a.distance - b.distance)\n .slice(1, k + 1);\n nN.push(res);\n }\n return nN;\n}\n","/**\n * Creates an Array containing `number` numbers from `start` to `end`. If `number = null`.\n *\n * @category Matrix\n * @param {number} start - Start value.\n * @param {number} end - End value.\n * @param {number} [number] - Number of number between `start` and `end`.\n * @returns {number[]} An array with `number` entries, beginning at `start` ending at `end`.\n */\nexport function linspace(start, end, number) {\n if (number === undefined || number === null) {\n number = Math.max(Math.round(end - start) + 1, 1);\n }\n if (number < 2) {\n return number === 1 ? [start] : [];\n }\n const result = new Array(number);\n number -= 1;\n for (let i = number; i >= 0; --i) {\n result[i] = (i * end + (number - i) * start) / number;\n }\n return result;\n}\n","/**\n * Computes the inner product between two arrays of the same length.\n *\n * @category Linear Algebra\n * @param {number[] | Float64Array} a - Array a.\n * @param {number[] | Float64Array} b - Array b.\n * @returns The inner product between `a` and `b`.\n */\nexport function inner_product(a, b) {\n const N = a.length;\n if (N !== b.length) {\n throw new Error(\"Array a and b must have the same length!\");\n }\n let sum = 0;\n for (let i = 0; i < N; ++i) {\n sum += a[i] * b[i];\n }\n return sum;\n}\n","/**\n * Numerical stable summation with the Kahan summation algorithm.\n *\n * @category Numerical\n * @param {number[] | Float64Array} summands - Array of values to sum up.\n * @returns {number} The sum.\n * @see {@link https://en.wikipedia.org/wiki/Kahan_summation_algorithm}\n */\nexport function kahan_sum(summands) {\n const n = summands.length;\n let sum = 0;\n let compensation = 0;\n let y, t;\n\n for (let i = 0; i < n; ++i) {\n y = summands[i] - compensation;\n t = sum + y;\n compensation = t - sum - y;\n sum = t;\n }\n return sum;\n}\n","/**\n * Numerical stable summation with the Neumair summation algorithm.\n *\n * @category Numerical\n * @param {number[] | Float64Array} summands - Array of values to sum up.\n * @returns {number} The sum.\n * @see {@link https://en.wikipedia.org/wiki/Kahan_summation_algorithm#Further_enhancements}\n */\nexport function neumair_sum(summands) {\n const n = summands.length;\n let sum = 0;\n let compensation = 0;\n\n for (let i = 0; i < n; ++i) {\n const summand = summands[i];\n const t = sum + summand;\n if (Math.abs(sum) >= Math.abs(summand)) {\n compensation += sum - t + summand;\n } else {\n compensation += summand - t + sum;\n }\n sum = t;\n }\n return sum + compensation;\n}\n","import { Matrix, norm } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { neumair_sum } from \"../numerical/index.js\";\n\n/**\n * Computes the QR Decomposition of the Matrix `A` using Gram-Schmidt process.\n *\n * @category Linear Algebra\n * @param {Matrix} A\n * @returns {{ R: Matrix; Q: Matrix }}\n * @see {@link https://en.wikipedia.org/wiki/QR_decomposition#Using_the_Gram%E2%80%93Schmidt_process}\n */\nexport function qr(A) {\n const [rows, cols] = A.shape;\n const Q = new Matrix(rows, cols, \"identity\");\n const R = new Matrix(cols, cols, 0);\n\n for (let j = 0; j < cols; ++j) {\n const v = A.col(j);\n for (let i = 0; i < j; ++i) {\n const q = Q.col(i);\n const q_dot_v = neumair_sum(q.map((q_, k) => q_ * v[k]));\n for (let k = 0; k < rows; ++k) {\n v[k] -= q_dot_v * q[k];\n }\n R.set_entry(i, j, q_dot_v);\n }\n const v_norm = norm(v, euclidean);\n for (let k = 0; k < rows; ++k) {\n Q.set_entry(k, j, v[k] / v_norm);\n }\n R.set_entry(j, j, v_norm);\n }\n return { R, Q };\n}\n","import { Matrix, norm } from \"../matrix/index.js\";\n\n/**\n * Computes the QR Decomposition of the Matrix `A` with householder transformations.\n *\n * @category Linear Algebra\n * @param {Matrix} A\n * @returns {{ R: Matrix; Q: Matrix }}\n * @see {@link https://en.wikipedia.org/wiki/QR_decomposition#Using_Householder_reflections}\n * @see {@link http://mlwiki.org/index.php/Householder_Transformation}\n */\nexport function qr_householder(A) {\n const [rows, cols] = A.shape;\n const Q = new Matrix(rows, rows, \"I\");\n const R = A.clone();\n\n for (let j = 0; j < cols; ++j) {\n const x = Matrix.from_vector(R.col(j).slice(j), \"row\");\n const x_norm = norm(x);\n const x0 = x.entry(0, 0);\n const rho = -Math.sign(x0);\n const u1 = x0 - rho * x_norm;\n const u = x.divide(u1).set_entry(0, 0, 1);\n const beta = (-rho * u1) / x_norm;\n\n const u_outer_u = u.outer(u);\n const R_block = R.get_block(j, 0);\n const new_R = R_block.sub(u_outer_u.dot(R_block).mult(beta));\n const Q_block = Q.get_block(0, j);\n const new_Q = Q_block.sub(Q_block.dot(u_outer_u).mult(beta));\n R.set_block(j, 0, new_R);\n Q.set_block(0, j, new_Q);\n }\n return { R, Q };\n}\n","/**\n * Returns maximum in Array `values`.\n *\n * @category Utils\n * @param {Iterable} values\n * @returns {number}\n */\nexport function max(values) {\n let max = -Infinity;\n for (const value of values) {\n if (value !== null && max < value) {\n max = value;\n }\n }\n return max;\n}\n","/**\n * Returns maximum in Array `values`.\n *\n * @category Utils\n * @param {Iterable} values\n * @returns {number}\n */\nexport function min(values) {\n let min = Infinity;\n for (const value of values) {\n if (value !== null && min > value) {\n min = value;\n }\n }\n return min;\n}\n","import { linspace } from \"../matrix/index.js\";\n\n/**\n * @category Utils\n * @class\n */\nexport class Randomizer {\n _N = 624;\n _M = 397;\n _MATRIX_A = 0x9908b0df;\n _UPPER_MASK = 0x80000000;\n _LOWER_MASK = 0x7fffffff;\n\n /** @type {number[]} */\n _mt;\n /** @type {number} */\n _mti;\n /** @type {number} */\n _seed;\n\n /**\n * Mersenne Twister random number generator.\n *\n * @param {number} [_seed=new Date().getTime()] - The seed for the random number generator. If `_seed == null` then\n * the actual time gets used as seed. Default is `new Date().getTime()`\n * @see https://github.com/bmurray7/mersenne-twister-examples/blob/master/javascript-mersenne-twister.js\n */\n constructor(_seed) {\n this._mt = new Array(this._N);\n this._mti = this._N + 1;\n this._seed = _seed ?? Date.now();\n this.seed = this._seed;\n }\n\n /** @type {number} seed */\n set seed(_seed) {\n this._seed = _seed;\n const mt = this._mt;\n\n mt[0] = _seed >>> 0;\n for (this._mti = 1; this._mti < this._N; this._mti += 1) {\n const mti = this._mti;\n const s = mt[mti - 1] ^ (mt[mti - 1] >>> 30);\n mt[mti] = ((((s & 0xffff0000) >>> 16) * 1812433253) << 16) + (s & 0x0000ffff) * 1812433253 + mti;\n mt[mti] >>>= 0;\n }\n }\n\n /**\n * Returns the seed of the random number generator.\n *\n * @returns {number} - The seed.\n */\n get seed() {\n return this._seed;\n }\n\n /**\n * Returns a float between 0 and 1.\n *\n * @returns {number} - A random number between [0, 1]\n */\n get random() {\n return this.random_int * (1.0 / 4294967296.0);\n }\n\n /**\n * Returns an integer between 0 and MAX_INTEGER.\n *\n * @returns {number} - A random integer.\n */\n get random_int() {\n let y,\n mag01 = [0x0, this._MATRIX_A];\n if (this._mti >= this._N) {\n let kk;\n\n /* if (this._mti == this._N + 1) {\n this.seed = 5489;\n } */\n\n const N_M = this._N - this._M;\n const M_N = this._M - this._N;\n\n for (kk = 0; kk < N_M; ++kk) {\n y = (this._mt[kk] & this._UPPER_MASK) | (this._mt[kk + 1] & this._LOWER_MASK);\n this._mt[kk] = this._mt[kk + this._M] ^ (y >>> 1) ^ mag01[y & 0x1];\n }\n for (; kk < this._N - 1; ++kk) {\n y = (this._mt[kk] & this._UPPER_MASK) | (this._mt[kk + 1] & this._LOWER_MASK);\n this._mt[kk] = this._mt[kk + M_N] ^ (y >>> 1) ^ mag01[y & 0x1];\n }\n\n y = (this._mt[this._N - 1] & this._UPPER_MASK) | (this._mt[0] & this._LOWER_MASK);\n this._mt[this._N - 1] = this._mt[this._M - 1] ^ (y >>> 1) ^ mag01[y & 0x1];\n\n this._mti = 0;\n }\n this._mti += 1;\n y = this._mt[this._mti];\n y ^= y >>> 11;\n y ^= (y << 7) & 0x9d2c5680;\n y ^= (y << 15) & 0xefc60000;\n y ^= y >>> 18;\n\n return y >>> 0;\n }\n\n gauss_random() {\n let x, y, r;\n if (this._val != null) {\n x = this._val;\n this._val = null;\n return x;\n } else\n do {\n x = 2 * this.random - 1;\n y = 2 * this.random - 1;\n r = x * x + y * y;\n } while (!r || r > 1);\n const c = Math.sqrt((-2 * Math.log(r)) / r);\n this._val = y * c; // cache this for next function call for efficiency\n return x * c;\n }\n\n /**\n * @template T Returns samples from an input Matrix or Array.\n * @param {T[]} A - The input Matrix or Array.\n * @param {number} n - The number of samples.\n * @returns {T[]} A random selection form `A` of `n` samples.\n */\n choice(A, n) {\n if (!Array.isArray(A)) throw new Error(\"A must be an Array!\");\n // if (A instanceof Matrix) {\n // let rows = A.shape[0];\n // if (n > rows) {\n // throw new Error(\"n bigger than A!\");\n // }\n // /** @type {number[]} */\n // let sample = new Array(n);\n // let index_list = linspace(0, rows - 1);\n // for (let i = 0, l = index_list.length; i < n; ++i, --l) {\n // let random_index = this.random_int % l;\n // sample[i] = index_list.splice(random_index, 1)[0];\n // }\n // return sample.map((d) => A.row(d));\n // } else if (Array.isArray(A) || A instanceof Float64Array) {\n const rows = A.length;\n if (n > rows) {\n throw new Error(\"n bigger than A!\");\n }\n const sample = new Array(n);\n const index_list = linspace(0, rows - 1);\n for (let i = 0, l = index_list.length; i < n; ++i, --l) {\n const random_index = this.random_int % l;\n sample[i] = index_list.splice(random_index, 1)[0];\n }\n return sample.map((d) => A[d]);\n //} else {\n //throw new Error(\"A must be of type Matrix or Float64Array or number[]!\");\n // }\n }\n\n /**\n * @template T Returns samples from an input Matrix or Array.\n * @param {T[]} A - The input Matrix or Array.\n * @param {number} n - The number of samples.\n * @param {number} seed - The seed for the random number generator.\n * @returns {T[]} - A random selection form `A` of `n` samples.\n */\n static choice(A, n, seed = 1212) {\n const R = new Randomizer(seed);\n return R.choice(A, n);\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { euclidean_squared } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { qr as qr_gramschmidt } from \"./index.js\";\n\n/** @import { EigenArgs } from \"./index.js\" */\n\n/**\n * Computes the `k` biggest Eigenvectors and Eigenvalues from Matrix `A` with the QR-Algorithm.\n *\n * @category Linear Algebra\n * @param {Matrix} A - The Matrix\n * @param {number} k - The number of eigenvectors and eigenvalues to compute.\n * @param {EigenArgs} parameters - Object containing parameterization of the simultanious\n * poweriteration method.\n * @returns {{ eigenvalues: Float64Array; eigenvectors: Float64Array[] }} The `k` biggest eigenvectors and eigenvalues\n * of Matrix `A`.\n */\nexport function simultaneous_poweriteration(\n A,\n k = 2,\n { seed = 1212, max_iterations = 100, qr = qr_gramschmidt, tol = 1e-8 } = {},\n) {\n const randomizer = seed instanceof Randomizer ? seed : new Randomizer(seed);\n if (!(A instanceof Matrix)) A = Matrix.from(A);\n const n = A.shape[0];\n let { Q, R } = qr(new Matrix(n, k, () => (randomizer.random - 0.5) * 2));\n while (max_iterations--) {\n const oldQ = Q;\n const Z = A.dot(Q);\n const QR = qr(Z);\n Q = QR.Q;\n R = QR.R;\n const error = euclidean_squared(Q.values, oldQ.values);\n if (error < tol) {\n break;\n }\n }\n\n const eigenvalues = R.diag();\n const eigenvectors = Q.transpose().to2dArray();\n return { eigenvalues, eigenvectors };\n}\n","import { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { neumair_sum } from \"../numerical/index.js\";\nimport { Randomizer } from \"../util/index.js\";\n\n/** @typedef {(i: number, j: number) => number} Accessor */\n\n/**\n * @class\n * @category Matrix\n */\nexport class Matrix {\n /**\n * Creates a new Matrix. Entries are stored in a Float64Array.\n *\n * @example let A = new Matrix(10, 10, () => Math.random()); //creates a 10 times 10 random matrix. let B = new\n * Matrix(3, 3, \"I\"); // creates a 3 times 3 identity matrix.\n *\n * @param {number} rows - The amount of rows of the matrix.\n * @param {number} cols - The amount of columns of the matrix.\n * @param {Accessor | string | number} value - Can be a function with row and col as parameters, a number, or\n * \"zeros\", \"identity\" or \"I\", or \"center\".\n *\n * - **function**: for each entry the function gets called with the parameters for the actual row and column.\n * - **string**: allowed are\n *\n * - \"zero\", creates a zero matrix.\n * - \"identity\" or \"I\", creates an identity matrix.\n * - \"center\", creates an center matrix.\n * - **number**: create a matrix filled with the given value.\n */\n constructor(rows, cols, value = 0) {\n /** @type {number} */ this._rows = rows;\n /** @type {number} */ this._cols = cols;\n /** @type {Float64Array} */ this._data;\n\n if (rows && cols) {\n if (!value) {\n this._data = new Float64Array(rows * cols);\n }\n if (typeof value === \"function\") {\n this._data = new Float64Array(rows * cols);\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col) {\n this._data[row * cols + col] = value(row, col);\n }\n }\n }\n if (typeof value === \"string\") {\n if (value === \"zeros\") {\n this._data = new Float64Array(rows * cols);\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col) {\n this._data[row * cols + col] = 0;\n }\n }\n }\n if (value === \"identity\" || value === \"I\") {\n this._data = new Float64Array(rows * cols);\n for (let row = 0; row < rows; ++row) {\n this._data[row * cols + row] = 1;\n }\n }\n if (value === \"center\" && rows === cols) {\n this._data = new Float64Array(rows * cols);\n value = (i, j) => (i === j ? 1 : 0) - 1 / rows;\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col) {\n this._data[row * cols + col] = value(row, col);\n }\n }\n }\n }\n if (typeof value === \"number\") {\n this._data = new Float64Array(rows * cols);\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col) {\n this._data[row * cols + col] = value;\n }\n }\n }\n if (Array.isArray(value)) {\n this._data = new Float64Array(rows * cols);\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col) {\n this._data[row * cols + col] = value[row][col];\n }\n }\n }\n }\n }\n\n /**\n * Creates a Matrix out of `A`.\n * @param {Matrix | Float64Array[] | number[][]} A - The matrix, array, or number, which should converted to a Matrix.\n * @returns {Matrix}\n * @example\n * let A = Matrix.from([ [1, 0], [0, 1], ]); //creates a two by two identity matrix.\n */\n static from(A) {\n if (A instanceof Matrix) {\n return A.clone();\n }\n if (Matrix.is2dArray(A)) {\n const m = A.length;\n const n = A[0].length;\n for (let row = 0; row < m; ++row) {\n if (A[row].length !== n) {\n throw new Error(\"various array lengths\");\n }\n }\n return new Matrix(m, n, (i, j) => A[i][j]);\n }\n throw new Error(\"error\");\n }\n\n /**\n * Creates a Matrix with the diagonal being the values of `v`.\n *\n * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]]\n *\n * @param {number[] | Float64Array} v\n * @returns {Matrix}\n */\n static from_diag(v) {\n const N = v.length;\n return new Matrix(N, N, (i, j) => (i === j ? v[i] : 0));\n }\n\n /**\n * Creates a Matrix with the diagonal being the values of `v`.\n *\n * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]]\n *\n * @param {number[] | Float64Array} v\n * @param {\"col\" | \"row\"} type\n * @returns {Matrix}\n */\n static from_vector(v, type) {\n const N = v.length;\n if (type === \"col\") {\n return new Matrix(N, 1, (i, _) => v[i]);\n } else {\n return new Matrix(1, N, (_, j) => v[j]);\n }\n }\n\n /**\n * Returns the `row`th row from the Matrix.\n *\n * @param {number} row\n * @returns {Float64Array}\n */\n row(row) {\n const data = this.values;\n const cols = this._cols;\n return data.subarray(row * cols, (row + 1) * cols);\n }\n\n /**\n * Returns an generator yielding each row of the Matrix.\n *\n * @yields {Float64Array}\n */\n *iterate_rows() {\n const cols = this._cols;\n const rows = this._rows;\n const data = this.values;\n for (let row = 0; row < rows; ++row) {\n yield data.subarray(row * cols, (row + 1) * cols);\n }\n }\n\n /**\n * Makes a `Matrix` object an iterable object.\n *\n * @yields {Float64Array}\n */\n *[Symbol.iterator]() {\n for (const row of this.iterate_rows()) {\n yield row;\n }\n }\n\n /**\n * Sets the entries of `row`th row from the Matrix to the entries from `values`.\n *\n * @param {number} row\n * @param {number[]} values\n * @returns {Matrix}\n */\n set_row(row, values) {\n const cols = this._cols;\n if (Matrix.isArray(values) && values.length === cols) {\n const offset = row * cols;\n for (let col = 0; col < cols; ++col) {\n this.values[offset + col] = values[col];\n }\n } else if (values instanceof Matrix && values.shape[1] === cols && values.shape[0] === 1) {\n const offset = row * cols;\n for (let col = 0; col < cols; ++col) {\n this.values[offset + col] = values._data[col];\n }\n } else {\n throw new Error(\"Values not valid! Needs to be either an Array, a Float64Array, or a fitting Matrix!\");\n }\n return this;\n }\n\n /**\n * Swaps the rows `row1` and `row2` of the Matrix.\n *\n * @param {number} row1\n * @param {number} row2\n * @returns {Matrix}\n */\n swap_rows(row1, row2) {\n const cols = this._cols;\n const data = this.values;\n for (let i = row1 * cols, j = row2 * cols, col = 0; col < cols; ++col, ++i, ++j) {\n const t = data[i];\n data[i] = data[j];\n data[j] = t;\n }\n return this;\n }\n\n /**\n * Returns the colth column from the Matrix.\n *\n * @param {number} col\n * @returns {Float64Array}\n */\n col(col) {\n const result_col = new Float64Array(this._rows);\n for (let row = 0; row < this._rows; ++row) {\n result_col[row] = this.values[row * this._cols + col];\n }\n return result_col;\n }\n\n /**\n * Returns the `col`th entry from the `row`th row of the Matrix.\n *\n * @param {number} row\n * @param {number} col\n * @returns {number}\n */\n entry(row, col) {\n return this.values[row * this._cols + col];\n }\n\n /**\n * Sets the {@link col}th entry from the {@link row}th row of the Matrix to the given\n * {@link value}.\n *\n * @param {number} row\n * @param {number} col\n * @param {number} value\n * @returns {Matrix}\n */\n set_entry(row, col, value) {\n this.values[row * this._cols + col] = value;\n return this;\n }\n\n /**\n * Adds a given {@link value} to the {@link col}th entry from the {@link row}th row of the\n * Matrix.\n *\n * @param {number} row\n * @param {number} col\n * @param {number} value\n * @returns {Matrix}\n */\n add_entry(row, col, value) {\n this.values[row * this._cols + col] += value;\n return this;\n }\n\n /**\n * Subtracts a given {@link value} from the {@link col}th entry from the {@link row}th row of the\n * Matrix.\n *\n * @param {number} row\n * @param {number} col\n * @param {number} value\n * @returns {Matrix}\n */\n sub_entry(row, col, value) {\n this.values[row * this._cols + col] -= value;\n return this;\n }\n\n /**\n * Returns a new transposed Matrix.\n *\n * @returns {Matrix}\n */\n transpose() {\n const B = new Matrix(this._cols, this._rows, (row, col) => this.entry(col, row));\n return B;\n }\n\n /**\n * Returns a new transposed Matrix. Short-form of `transpose`.\n *\n * @returns {Matrix}\n */\n get T() {\n return this.transpose();\n }\n\n /**\n * Returns the inverse of the Matrix.\n *\n * @returns {Matrix}\n */\n inverse() {\n const rows = this._rows;\n const cols = this._cols;\n const A = this.clone();\n const B = new Matrix(rows, cols, \"I\");\n\n // foreach column\n for (let col = 0; col < cols; ++col) {\n // Search for maximum in this column (pivot)\n let max_idx = col;\n let max_val = Math.abs(A.entry(col, col));\n for (let row = col + 1; row < rows; ++row) {\n const val = Math.abs(A.entry(row, col));\n if (max_val < val) {\n max_idx = row;\n max_val = val;\n }\n }\n if (max_val === 0) {\n throw new Error(\"Cannot compute inverse of Matrix, determinant is zero\");\n }\n // Swap maximum row with current row\n if (max_idx !== col) {\n A.swap_rows(col, max_idx);\n B.swap_rows(col, max_idx);\n }\n\n // eliminate non-zero values on the other rows at column c\n const A_col = A.row(col);\n const B_col = B.row(col);\n for (let row = 0; row < rows; ++row) {\n if (row !== col) {\n // eliminate value at column c and row r\n const A_row = A.row(row);\n const B_row = B.row(row);\n if (A_row[col] !== 0) {\n const f = A_row[col] / A_col[col];\n // sub (f * row c) from row r to eliminate the value at column c\n for (let s = col; s < cols; ++s) {\n A_row[s] -= f * A_col[s];\n }\n for (let s = 0; s < cols; ++s) {\n B_row[s] -= f * B_col[s];\n }\n }\n } else {\n // normalize value at Acc to 1 (diagonal):\n // divide each value of row r=c by the value at Acc\n const f = A_col[col];\n for (let s = col; s < cols; ++s) {\n A_col[s] /= f;\n }\n for (let s = 0; s < cols; ++s) {\n B_col[s] /= f;\n }\n }\n }\n }\n return B;\n }\n\n /**\n * Returns the dot product. If `B` is an Array or Float64Array then an Array gets returned. If `B` is a Matrix then\n * a Matrix gets returned.\n *\n * @param {Matrix | number[] | Float64Array} B The right side\n * @returns {Matrix}\n */\n dot(B) {\n if (B instanceof Matrix) {\n const [rows_A, cols_A] = this.shape;\n const [rows_B, cols_B] = B.shape;\n if (cols_A !== rows_B) {\n throw new Error(`A.dot(B): A is a ${this.shape.join(\" ⨯ \")}-Matrix, B is a ${B.shape.join(\" ⨯ \")}-Matrix:\n A has ${cols_A} cols and B ${rows_B} rows.\n Must be equal!`);\n }\n const C = new Matrix(rows_A, cols_B, 0);\n const A_val = this.values;\n const B_val = B.values;\n const C_val = C.values;\n\n for (let i = 0; i < rows_A; ++i) {\n const i_cols_A = i * cols_A;\n const i_cols_B = i * cols_B;\n for (let k = 0; k < cols_A; ++k) {\n const aik = A_val[i_cols_A + k];\n if (aik === 0) continue;\n const k_cols_B = k * cols_B;\n for (let j = 0; j < cols_B; ++j) {\n C_val[i_cols_B + j] += aik * B_val[k_cols_B + j];\n }\n }\n }\n return C;\n } else if (Matrix.isArray(B)) {\n // TODO: create Matrix directly\n const rows = this._rows;\n if (B.length !== rows) {\n throw new Error(`A.dot(B): A has ${rows} cols and B has ${B.length} rows. Must be equal!`);\n }\n const C = new Array(rows);\n for (let row = 0; row < rows; ++row) {\n C[row] = neumair_sum(this.row(row).map((e) => e * B[row]));\n }\n return Matrix.from(C);\n } else {\n throw new Error(`B must be Matrix or Array`);\n }\n }\n\n /**\n * Transposes the current matrix and returns the dot product with `B`. If `B` is an Array or Float64Array then an\n * Array gets returned. If `B` is a Matrix then a Matrix gets returned.\n *\n * @param {Matrix | number[] | Float64Array} B The right side\n * @returns {Matrix}\n */\n transDot(B) {\n if (B instanceof Matrix) {\n const [cols_A, rows_A] = this.shape; // transpose matrix\n const [rows_B, cols_B] = B.shape;\n if (cols_A !== rows_B) {\n throw new Error(`A.dot(B): A is a ${[rows_A, cols_A].join(\" ⨯ \")}-Matrix, B is a ${B.shape.join(\" ⨯ \")}-Matrix:\n A has ${cols_A} cols and B ${rows_B} rows, which must be equal!`);\n }\n // let B = new Matrix(this._cols, this._rows, (row, col) => this.entry(col, row));\n // this.values[row * this._cols + col];\n const C = new Matrix(rows_A, cols_B, 0);\n const A_val = this.values; // A is rows_B x rows_A (transposed)\n const B_val = B.values;\n const C_val = C.values;\n\n for (let k = 0; k < cols_A; ++k) {\n // cols_A is rows_B\n const k_rows_A = k * rows_A;\n const k_cols_B = k * cols_B;\n for (let i = 0; i < rows_A; ++i) {\n const aki = A_val[k_rows_A + i];\n if (aki === 0) continue;\n for (let j = 0; j < cols_B; ++j) {\n C_val[i * cols_B + j] += aki * B_val[k_cols_B + j];\n }\n }\n }\n return C;\n } else if (Matrix.isArray(B)) {\n // TODO: create Matrix directly\n const rows = this._cols;\n if (B.length !== rows) {\n throw new Error(`A.dot(B): A has ${rows} cols and B has ${B.length} rows. Must be equal!`);\n }\n const C = new Array(rows);\n for (let row = 0; row < rows; ++row) {\n C[row] = neumair_sum(this.col(row).map((e) => e * B[row]));\n }\n return Matrix.from(C);\n } else {\n throw new Error(`B must be Matrix or Array`);\n }\n }\n\n /**\n * Returns the dot product with the transposed version of `B`. If `B` is an Array or Float64Array then an Array gets\n * returned. If `B` is a Matrix then a Matrix gets returned.\n *\n * @param {Matrix | number[] | Float64Array} B The right side\n * @returns {Matrix}\n */\n dotTrans(B) {\n if (B instanceof Matrix) {\n const [rows_A, cols_A] = this.shape;\n const [cols_B, rows_B] = B.shape;\n if (cols_A !== rows_B) {\n throw new Error(`A.dot(B): A is a ${this.shape.join(\" ⨯ \")}-Matrix, B is a ${[rows_B, cols_B].join(\" ⨯ \")}-Matrix:\n A has ${cols_A} cols and B ${rows_B} rows, which must be equal!`);\n }\n const C = new Matrix(rows_A, cols_B, (row, col) => {\n const A_i = this.row(row);\n const B_i = B.row(col);\n let sum = 0;\n for (let i = 0; i < cols_A; ++i) {\n sum += A_i[i] * B_i[i];\n }\n return sum;\n });\n return C;\n } else if (Matrix.isArray(B)) {\n // TODO: create Matrix directly\n const rows = this._rows;\n if (B.length !== rows) {\n throw new Error(`A.dot(B): A has ${rows} cols and B has ${B.length} rows. Must be equal!`);\n }\n const C = new Array(rows);\n for (let row = 0; row < rows; ++row) {\n C[row] = neumair_sum(this.row(row).map((e) => e * B[row]));\n }\n return Matrix.from(C);\n } else {\n throw new Error(`B must be Matrix or Array`);\n }\n }\n\n /**\n * Computes the outer product from `this` and `B`.\n *\n * @param {Matrix} B\n * @returns {Matrix}\n */\n outer(B) {\n const l = this._data.length;\n const r = B._data.length;\n if (l !== r) throw new Error(\"Matrix A and B needs to be of the same length!\");\n const C = new Matrix(\n l,\n l,\n /** @type {Accessor} */ (i, j) => {\n if (i <= j) {\n return this._data[i] * B._data[j];\n } else {\n return this.entry(j, i);\n }\n },\n );\n\n return C;\n }\n\n /**\n * Appends matrix `B` to the matrix.\n *\n * @example let A = Matrix.from([ [1, 1], [1, 1], ]); // 2 by 2 matrix filled with ones. let B = Matrix.from([ [2,\n * 2], [2, 2], ]); // 2 by 2 matrix filled with twos.\n *\n * A.concat(B, \"horizontal\"); // 2 by 4 matrix. [[1, 1, 2, 2], [1, 1, 2, 2]]\n * A.concat(B, \"vertical\"); // 4 by 2 matrix. [[1, 1], [1, 1], [2, 2], [2, 2]]\n * A.concat(B, \"diag\"); // 4 by 4 matrix. [[1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 2, 2], [0, 0, 2, 2]]\n *\n * @param {Matrix} B - Matrix to append.\n * @param {\"horizontal\" | \"vertical\" | \"diag\"} [type=\"horizontal\"] - Type of concatenation. Default is\n * `\"horizontal\"`\n * @returns {Matrix}\n */\n concat(B, type = \"horizontal\") {\n const [rows_A, cols_A] = this.shape;\n const [rows_B, cols_B] = B.shape;\n if (type === \"horizontal\") {\n if (rows_A !== rows_B) {\n throw new Error(\n `A.concat(B, \"horizontal\"): A and B need same number of rows, A has ${rows_A} rows, B has ${rows_B} rows.`,\n );\n }\n const X = new Matrix(rows_A, cols_A + cols_B, \"zeros\");\n X.set_block(0, 0, this);\n X.set_block(0, cols_A, B);\n return X;\n } else if (type === \"vertical\") {\n if (cols_A !== cols_B) {\n throw new Error(\n `A.concat(B, \"vertical\"): A and B need same number of columns, A has ${cols_A} columns, B has ${cols_B} columns.`,\n );\n }\n const X = new Matrix(rows_A + rows_B, cols_A, \"zeros\");\n X.set_block(0, 0, this);\n X.set_block(rows_A, 0, B);\n return X;\n } else if (type === \"diag\") {\n const X = new Matrix(rows_A + rows_B, cols_A + cols_B, \"zeros\");\n X.set_block(0, 0, this);\n X.set_block(rows_A, cols_A, B);\n return X;\n } else {\n throw new Error(`type must be \"horizontal\" or \"vertical\", but type is ${type}!`);\n }\n }\n\n /**\n * Writes the entries of B in A at an offset position given by `offset_row` and `offset_col`.\n *\n * @param {number} offset_row\n * @param {number} offset_col\n * @param {Matrix} B\n * @returns {Matrix}\n */\n set_block(offset_row, offset_col, B) {\n const rows = Math.min(this._rows - offset_row, B.shape[0]);\n const cols = Math.min(this._cols - offset_col, B.shape[1]);\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col) {\n this.set_entry(row + offset_row, col + offset_col, B.entry(row, col));\n }\n }\n return this;\n }\n\n /**\n * Extracts the entries from the `start_row`th row to the `end_row`th row, the\n * `start_col`th column to the `end_col`th column of the matrix. If `end_row` or `end_col` is\n * empty, the respective value is set to `this.rows` or `this.cols`.\n *\n * @example let A = Matrix.from([ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]); // a 3 by 3 matrix.\n *\n * A.get_block(1, 1); // [[5, 6], [8, 9]]\n * A.get_block(0, 0, 1, 1); // [[1]]\n * A.get_block(1, 1, 2, 2); // [[5]]\n * A.get_block(0, 0, 2, 2); // [[1, 2], [4, 5]]\n *\n * @param {number} start_row\n * @param {number} start_col\n * @param {number | null} [end_row]\n * @param {number | null} [end_col]\n * @returns {Matrix} Returns a `end_row` - `start_row` times `end_col` - `start_col` matrix, with respective entries\n * from the matrix.\n */\n get_block(start_row, start_col, end_row, end_col) {\n const [rows, cols] = this.shape;\n end_row = end_row ?? rows;\n end_col = end_col ?? cols;\n if (end_row <= start_row || end_col <= start_col) {\n throw new Error(`\n end_row must be greater than start_row, and\n end_col must be greater than start_col, but\n end_row = ${end_row}, start_row = ${start_row}, end_col = ${end_col}, and start_col = ${start_col}!`);\n }\n const X = new Matrix(end_row - start_row, end_col - start_col, \"zeros\");\n for (let row = start_row, new_row = 0; row < end_row; ++row, ++new_row) {\n for (let col = start_col, new_col = 0; col < end_col; ++col, ++new_col) {\n X.set_entry(new_row, new_col, this.entry(row, col));\n }\n }\n return X;\n }\n\n /**\n * Returns a new array gathering entries defined by the indices given by argument.\n *\n * @param {number[]} row_indices - Array consists of indices of rows for gathering entries of this matrix\n * @param {number[]} col_indices - Array consists of indices of cols for gathering entries of this matrix\n * @returns {Matrix}\n */\n gather(row_indices, col_indices) {\n const N = row_indices.length;\n const D = col_indices.length;\n\n const R = new Matrix(N, D);\n for (let i = 0; i < N; ++i) {\n const row_index = row_indices[i];\n for (let j = 0; j < D; ++j) {\n const col_index = col_indices[j];\n R.set_entry(i, j, this.entry(row_index, col_index));\n }\n }\n\n return R;\n }\n\n /**\n * Applies a function to each entry of the matrix.\n *\n * @private\n * @param {(d: number, v: number) => number} f Function takes 2 parameters, the value of the actual entry and a\n * value given by the function `v`. The result of `f` gets writen to the Matrix.\n * @param {Accessor} v Function takes 2 parameters for `row` and `col`, and returns a value witch should be applied\n * to the `col`th entry of the `row`th row of the matrix.\n * @returns {Matrix}\n */\n _apply_array(f, v) {\n const data = this.values;\n const [rows, cols] = this.shape;\n for (let i = 0, row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col, ++i) {\n data[i] = f(data[i], v(row, col));\n }\n }\n return this;\n }\n\n /**\n * @param {number[] | Float64Array} values\n * @param {(d: number, v: number) => number} f\n * @returns {Matrix}\n */\n _apply_rowwise_array(values, f) {\n return this._apply_array(f, (_, j) => values[j]);\n }\n /**\n * @param {number[] | Float64Array} values\n * @param {(d: number, v: number) => number} f\n * @returns {Matrix}\n */\n _apply_colwise_array(values, f) {\n const data = this.values;\n const [rows, cols] = this.shape;\n for (let i = 0, row = 0; row < rows; ++row) {\n const val = values[row];\n for (let col = 0; col < cols; ++col, ++i) {\n data[i] = f(data[i], val);\n }\n }\n return this;\n }\n\n /**\n * @param {Matrix | number[] | Float64Array | number} value\n * @param {(d: number, v: number) => number} f\n * @returns {Matrix}\n */\n _apply(value, f) {\n const data = this.values;\n const [rows, cols] = this.shape;\n if (value instanceof Matrix) {\n const values = value.values;\n const [value_rows, value_cols] = value.shape;\n if (value_rows === 1) {\n if (cols !== value_cols) {\n throw new Error(`cols !== value_cols`);\n }\n for (let i = 0, row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col, ++i) {\n data[i] = f(data[i], values[col]);\n }\n }\n } else if (value_cols === 1) {\n if (rows !== value_rows) {\n throw new Error(`rows !== value_rows`);\n }\n for (let i = 0, row = 0; row < rows; ++row) {\n const v = values[row];\n for (let col = 0; col < cols; ++col, ++i) {\n data[i] = f(data[i], v);\n }\n }\n } else if (rows === value_rows && cols === value_cols) {\n for (let i = 0, n = rows * cols; i < n; ++i) {\n data[i] = f(data[i], values[i]);\n }\n } else {\n throw new Error(`error`);\n }\n } else if (Matrix.isArray(value)) {\n if (value.length === rows) {\n for (let i = 0, row = 0; row < rows; ++row) {\n const v = value[row];\n for (let col = 0; col < cols; ++col, ++i) {\n data[i] = f(data[i], v);\n }\n }\n } else if (value.length === cols) {\n for (let i = 0, row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col, ++i) {\n data[i] = f(data[i], value[col]);\n }\n }\n } else {\n throw new Error(`error`);\n }\n } else {\n // scalar value\n for (let i = 0, n = rows * cols; i < n; ++i) {\n data[i] = f(data[i], value);\n }\n }\n return this;\n }\n\n /**\n * Clones the Matrix.\n *\n * @returns {Matrix}\n */\n clone() {\n const B = new Matrix(this._rows, this._cols);\n //B._rows = this._rows;\n //B._cols = this._cols;\n if (this._data) {\n B._data = this._data.slice(0);\n }\n return B;\n }\n\n /**\n * Entrywise multiplication with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.mult(2); // [[2, 4], [6, 8]];\n * A.mult(B); // [[1, 4], [9, 16]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {boolean} [options.inline=false] - If true, applies multiplication to the element, otherwise it creates\n * first a copy and applies the multiplication on the copy. Default is `false`\n * @returns {Matrix}\n */\n mult(value, { inline = false } = {}) {\n const A = inline ? this : this.clone();\n return A._apply(value, (a, b) => a * b);\n }\n\n /**\n * Entrywise division with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.divide(2); // [[0.5, 1], [1.5, 2]];\n * A.divide(B); // [[1, 1], [1, 1]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {Boolean} [options.inline=false] - If true, applies division to the element, otherwise it creates first a\n * copy and applies the division on the copy. Default is `false`\n * @returns {Matrix}\n */\n divide(value, { inline = false } = {}) {\n const A = inline ? this : this.clone();\n return A._apply(value, (a, b) => a / b);\n }\n\n /**\n * Entrywise addition with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.add(2); // [[3, 4], [5, 6]];\n * A.add(B); // [[2, 4], [6, 8]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {boolean} [options.inline=false] - If true, applies addition to the element, otherwise it creates first a\n * copy and applies the addition on the copy. Default is `false`\n * @returns {Matrix}\n */\n add(value, { inline = false } = {}) {\n const A = inline ? this : this.clone();\n return A._apply(value, (a, b) => a + b);\n }\n\n /**\n * Entrywise subtraction with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.sub(2); // [[-1, 0], [1, 2]];\n * A.sub(B); // [[0, 0], [0, 0]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {boolean} [options.inline=false] - If true, applies subtraction to the element, otherwise it creates first\n * a copy and applies the subtraction on the copy. Default is `false`\n * @returns {Matrix}\n */\n sub(value, { inline = false } = {}) {\n const A = inline ? this : this.clone();\n return A._apply(value, (a, b) => a - b);\n }\n\n /**\n * Returns the number of rows and columns of the Matrix.\n *\n * @returns {number[]} An Array in the form [rows, columns].\n */\n get shape() {\n return [this._rows, this._cols];\n }\n\n /**\n * Returns the matrix in the given shape with the given function which returns values for the entries of the matrix.\n *\n * @param {[number, number, Accessor]} parameter - Takes an Array in the form [rows, cols, value], where rows and\n * cols are the number of rows and columns of the matrix, and value is a function which takes two parameters (row\n * and col) which has to return a value for the colth entry of the rowth row.\n * @returns {Matrix}\n */\n set shape([rows, cols, value = () => 0]) {\n this._rows = rows;\n this._cols = cols;\n this._data = new Float64Array(rows * cols);\n for (let i = 0, row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col, ++i) {\n this._data[i] = value(row, col);\n }\n }\n }\n\n /**\n * Returns the Matrix as a Array of Float64Arrays.\n *\n * @returns {Float64Array[]}\n */\n to2dArray() {\n const result = [];\n for (const row of this.iterate_rows()) {\n result.push(row);\n }\n return result;\n }\n\n /**\n * Returns the Matrix as a Array of Arrays.\n *\n * @returns {number[][]}\n */\n asArray() {\n const result = [];\n for (const row of this.iterate_rows()) {\n result.push(Array.from(row));\n }\n return result;\n }\n\n /**\n * Returns the diagonal of the Matrix.\n *\n * @returns {Float64Array}\n */\n diag() {\n const rows = this._rows;\n const cols = this._cols;\n const min_row_col = Math.min(rows, cols);\n const result = new Float64Array(min_row_col);\n for (let i = 0; i < min_row_col; ++i) {\n result[i] = this.entry(i, i);\n }\n return result;\n }\n\n /**\n * Returns the mean of all entries of the Matrix.\n *\n * @returns {number}\n */\n mean() {\n const sum = this.sum();\n const n = this._rows * this._cols;\n return sum / n;\n }\n\n /**\n * Returns the sum oof all entries of the Matrix.\n *\n * @returns {number}\n */\n sum() {\n const data = this.values;\n return neumair_sum(data);\n }\n\n /**\n * Returns the entries of the Matrix.\n *\n * @returns {Float64Array}\n */\n get values() {\n const data = this._data;\n return data;\n }\n\n /**\n * Returns the mean of each row of the matrix.\n *\n * @returns {Float64Array}\n */\n meanRows() {\n const data = this.values;\n const rows = this._rows;\n const cols = this._cols;\n const result = Float64Array.from({ length: rows });\n for (let i = 0, row = 0; row < rows; ++row) {\n let sum = 0;\n for (let col = 0; col < cols; ++col, ++i) {\n sum += data[i];\n }\n result[row] = sum / cols;\n }\n return result;\n }\n\n /**\n * Returns the mean of each column of the matrix.\n *\n * @returns {Float64Array}\n */\n meanCols() {\n const data = this.values;\n const rows = this._rows;\n const cols = this._cols;\n const result = Float64Array.from({ length: cols });\n for (let col = 0; col < cols; ++col) {\n let sum = 0;\n for (let i = col, row = 0; row < rows; ++row, i += cols) {\n sum += data[i];\n }\n result[col] = sum / rows;\n }\n return result;\n }\n\n /**\n * Solves the equation `Ax = b` using the conjugate gradient method. Returns the result `x`.\n *\n * @param {Matrix} A - Matrix\n * @param {Matrix} b - Matrix\n * @param {Randomizer | null} [randomizer]\n * @param {number} [tol=1e-3] Default is `1e-3`\n * @returns {Matrix}\n */\n static solve_CG(A, b, randomizer, tol = 1e-3) {\n if (!randomizer) {\n randomizer = new Randomizer();\n }\n const rows = A.shape[0];\n const cols = b.shape[1];\n let result = new Matrix(rows, 0);\n for (let i = 0; i < cols; ++i) {\n const b_i = Matrix.from_vector(b.col(i), \"col\");\n let x = new Matrix(rows, 1, () => randomizer.random);\n let r = b_i.sub(A.dot(x));\n let d = r.clone();\n let iter = 0;\n const max_iter = rows * 10; // Prevent infinite loops\n do {\n const z = A.dot(d);\n const alpha = r.transDot(r).entry(0, 0) / d.transDot(z).entry(0, 0);\n x = x.add(d.mult(alpha));\n const r_next = r.sub(z.mult(alpha));\n const beta = r_next.transDot(r_next).entry(0, 0) / r.transDot(r).entry(0, 0);\n d = r_next.add(d.mult(beta));\n r = r_next;\n iter++;\n } while (Math.abs(r.mean()) > tol && iter < max_iter);\n result = result.concat(x, \"horizontal\");\n }\n return result;\n }\n\n /**\n * Solves the equation `Ax = b`. Returns the result `x`.\n *\n * @param {Matrix | { L: Matrix; U: Matrix }} A - Matrix or LU Decomposition\n * @param {Matrix} b - Matrix\n * @returns {Matrix}\n */\n static solve(A, b) {\n const { L, U } = \"L\" in A && \"U\" in A ? A : Matrix.LU(A);\n const rows = L.shape[0];\n const x = b.clone();\n\n // forward\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < row; ++col) {\n x.sub_entry(0, row, L.entry(row, col) * x.entry(0, col));\n }\n x.set_entry(0, row, x.entry(0, row) / L.entry(row, row));\n }\n\n // backward\n for (let row = rows - 1; row >= 0; --row) {\n for (let col = rows - 1; col > row; --col) {\n x.sub_entry(0, row, U.entry(row, col) * x.entry(0, col));\n }\n x.set_entry(0, row, x.entry(0, row) / U.entry(row, row));\n }\n\n return x;\n }\n\n /**\n * `LU` decomposition of the Matrix `A`. Creates two matrices, so that the dot product `LU` equals `A`.\n *\n * @param {Matrix} A\n * @returns {{ L: Matrix; U: Matrix }} The left triangle matrix `L` and the upper triangle matrix `U`.\n */\n static LU(A) {\n const rows = A.shape[0];\n const L = new Matrix(rows, rows, \"zeros\");\n const U = new Matrix(rows, rows, \"identity\");\n\n for (let j = 0; j < rows; ++j) {\n for (let i = j; i < rows; ++i) {\n let sum = 0;\n for (let k = 0; k < j; ++k) {\n sum += L.entry(i, k) * U.entry(k, j);\n }\n L.set_entry(i, j, A.entry(i, j) - sum);\n }\n for (let i = j; i < rows; ++i) {\n if (L.entry(j, j) === 0) {\n throw new Error(\"L's diagonal not supposed to be 0!\");\n }\n let sum = 0;\n for (let k = 0; k < j; ++k) {\n sum += L.entry(j, k) * U.entry(k, i);\n }\n U.set_entry(j, i, (A.entry(j, i) - sum) / L.entry(j, j));\n }\n }\n\n return { L, U };\n }\n\n /**\n * Computes the determinante of `A`, by using the `LU` decomposition of `A`.\n *\n * @param {Matrix} A\n * @returns {number} The determinate of the Matrix `A`.\n */\n static det(A) {\n const [rows, cols] = A.shape;\n\n if (rows === 2 && cols === 2) {\n return A.entry(0, 0) * A.entry(1, 1) - A.entry(0, 1) * A.entry(1, 0);\n }\n if (rows === 3 && cols === 3) {\n const a = A.entry(0, 0);\n const b = A.entry(0, 1);\n const c = A.entry(0, 2);\n const d = A.entry(1, 0);\n const e = A.entry(1, 1);\n const f = A.entry(1, 2);\n const g = A.entry(2, 0);\n const h = A.entry(2, 1);\n const i = A.entry(2, 2);\n return a * (e * i - f * h) - b * (d * i - f * g) + c * (d * h - e * g);\n }\n\n const { L, U } = Matrix.LU(A);\n const L_diag = L.diag();\n const U_diag = U.diag();\n let det = L_diag[0] * U_diag[0];\n for (let row = 1; row < rows; ++row) {\n det *= L_diag[row] * U_diag[row];\n }\n return det;\n }\n\n /**\n * Computes the `k` components of the SVD decomposition of the matrix `M`.\n *\n * @param {Matrix} M\n * @param {number} [k=2] Default is `2`\n * @returns {{ U: Float64Array[]; Sigma: Float64Array; V: Float64Array[] }}\n */\n static SVD(M, k = 2) {\n const MtM = M.transDot(M);\n const MMt = M.dotTrans(M);\n const { eigenvectors: V, eigenvalues: Sigma } = simultaneous_poweriteration(MtM, k);\n const { eigenvectors: U } = simultaneous_poweriteration(MMt, k);\n return { U: U, Sigma: Sigma.map((sigma) => Math.sqrt(sigma)), V: V };\n\n //Algorithm 1a: Householder reduction to bidiagonal form:\n /* const [m, n] = A.shape;\n let U = new Matrix(m, n, (i, j) => i == j ? 1 : 0);\n console.log(U.to2dArray)\n let V = new Matrix(n, m, (i, j) => i == j ? 1 : 0);\n console.log(V.to2dArray)\n let B = Matrix.bidiagonal(A.clone(), U, V);\n console.log(U,V,B)\n return { U: U, \"Sigma\": B, V: V }; */\n }\n\n /**\n * @param {unknown} A\n * @returns {A is unknown[]|number[]|Float64Array|Float32Array}\n */\n static isArray(A) {\n return Array.isArray(A) || A instanceof Float64Array || A instanceof Float32Array;\n }\n\n /**\n * @param {any[]} A\n * @returns {A is number[][]|Float64Array[]}\n */\n static is2dArray(A) {\n if (!Array.isArray(A) || A.length === 0) {\n return false;\n }\n const n = A[0].length;\n for (let i = 0; i < A.length; ++i) {\n if (!Array.isArray(A[i]) && !(A[i] instanceof Float64Array)) {\n return false;\n }\n if (A[i].length !== n) {\n return false;\n }\n }\n return true;\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n\n/**\n * Computes the norm of a vector, by computing its distance to **0**.\n *\n * @category Matrix\n * @param {Matrix | number[] | Float64Array} v - Vector.\n * @param {Metric} [metric=euclidean] - Which metric should be used to compute the norm. Default is `euclidean`\n * @returns {number} - The norm of `v`.\n */\nexport function norm(v, metric = euclidean) {\n let vector = null;\n if (v instanceof Matrix) {\n const [rows, cols] = v.shape;\n if (rows === 1) vector = v.row(0);\n else if (cols === 1) vector = v.col(0);\n else throw new Error(\"Matrix must be 1d!\");\n } else {\n vector = v;\n }\n const n = vector.length;\n const zeros = new Float64Array(n);\n return metric(vector, zeros);\n}\n","import { euclidean } from \"../metrics/index.js\";\nimport { norm } from \"./index.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n\n/**\n * Normalizes Vector `v`.\n *\n * @category Matrix\n * @param {number[] | Float64Array} v - Vector\n * @param {Metric} metric\n * @returns {number[] | Float64Array} - The normalized vector with length 1.\n */\nexport function normalize(v, metric = euclidean) {\n const v_norm = norm(v, metric);\n return v.map((value) => value / v_norm);\n}\n","import { Matrix } from \"../matrix/index.js\";\n\n/** @import {InputType} from \"../index.js\" */\n\n/**\n * Base class for all clustering algorithms.\n * @template Para\n */\nexport class Clustering {\n /** @type {InputType} */\n _points;\n /** @type {Para} */\n _parameters;\n /** @type {Matrix} */\n _matrix;\n /** @type {number} */\n _N;\n /** @type {number} */\n _D;\n\n /**\n * Compute the respective Clustering with given parameters\n * @param {InputType} points\n * @param {Para} parameters\n */\n constructor(points, parameters) {\n this._points = points;\n this._parameters = parameters;\n\n this._matrix = points instanceof Matrix ? points : Matrix.from(points);\n const [N, D] = this._matrix.shape;\n this._N = N;\n this._D = D;\n }\n\n /**\n * @abstract\n * @param {...unknown} args\n * @returns {number[][]} An array with the indices of the clusters.\n */\n get_clusters(...args) {\n args;\n throw new Error(\"The function get_clusters must be implemented!\");\n }\n\n /**\n * @abstract\n * @param {...unknown} args\n * @returns {number[]} An array with the clusters id's for each point.\n */\n get_cluster_list(...args) {\n args;\n throw new Error(\"The function get_cluster_list must be implemented!\");\n }\n}\n","import { euclidean } from \"../metrics/index.js\";\nimport { Clustering } from \"./Clustering.js\";\n\n/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersCURE } from \"./index.js\" */\n\n/**\n * CURE (Clustering Using REpresentatives)\n *\n * An efficient clustering algorithm for large databases that is robust to outliers\n * and identifies clusters with non-spherical shapes and wide variances in size.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class CURE extends Clustering {\n /** @type {number} */\n _K;\n /** @type {number} */\n _num_representatives;\n /** @type {number} */\n _shrink_factor;\n /**\n * @private\n * @type {CURECluster[]}\n */\n _clusters = [];\n /** @type {number[]} */\n _cluster_ids = [];\n\n /**\n * @param {InputType} points\n * @param {Partial} parameters\n */\n constructor(points, parameters = {}) {\n super(\n points,\n /** @type {ParametersCURE} */ (\n Object.assign(\n { K: 2, num_representatives: 5, shrink_factor: 0.5, metric: euclidean, seed: 1212 },\n parameters,\n )\n ),\n );\n\n this._K = this._parameters.K ?? 2;\n this._num_representatives = this._parameters.num_representatives ?? 5;\n this._shrink_factor = this._parameters.shrink_factor ?? 0.5;\n\n // Initialize clusters\n this._initialize_clusters();\n // Run CURE algorithm\n this._cure();\n }\n\n /**\n * Initialize each point as its own cluster\n * @private\n */\n _initialize_clusters() {\n const N = this._N;\n //const D = this._D;\n this._clusters = [];\n\n for (let i = 0; i < N; ++i) {\n const point = this._matrix.row(i);\n const centroid = new Float64Array(point);\n // For single point, representative is the point itself\n const representatives = [new Float64Array(point)];\n\n this._clusters.push(new CURECluster([i], centroid, representatives));\n }\n }\n\n /**\n * Compute distance between two clusters using representative points\n * @private\n * @param {CURECluster} cluster1\n * @param {CURECluster} cluster2\n * @returns {number}\n */\n _cluster_distance(cluster1, cluster2) {\n const reps1 = cluster1.representatives;\n const reps2 = cluster2.representatives;\n const metric = this._parameters.metric;\n\n let min_dist = Infinity;\n for (const r1 of reps1) {\n for (const r2 of reps2) {\n const dist = metric(r1, r2);\n if (dist < min_dist) {\n min_dist = dist;\n }\n }\n }\n return min_dist;\n }\n\n /**\n * Find the closest pair of clusters\n * @private\n * @returns {[number, number, number]} [index1, index2, distance]\n */\n _find_closest_clusters() {\n let min_dist = Infinity;\n let min_i = 0;\n let min_j = 1;\n\n for (let i = 0; i < this._clusters.length; ++i) {\n for (let j = i + 1; j < this._clusters.length; ++j) {\n const dist = this._cluster_distance(this._clusters[i], this._clusters[j]);\n if (dist < min_dist) {\n min_dist = dist;\n min_i = i;\n min_j = j;\n }\n }\n }\n\n return [min_i, min_j, min_dist];\n }\n\n /**\n * Merge two clusters\n * @private\n * @param {CURECluster} cluster1\n * @param {CURECluster} cluster2\n * @returns {CURECluster}\n */\n _merge_clusters(cluster1, cluster2) {\n // Merge indices\n const merged_indices = [...cluster1.indices, ...cluster2.indices];\n\n // Calculate new centroid\n const size1 = cluster1.indices.length;\n const size2 = cluster2.indices.length;\n const total_size = size1 + size2;\n const D = this._D;\n const new_centroid = new Float64Array(D);\n\n for (let d = 0; d < D; ++d) {\n new_centroid[d] = (size1 * cluster1.centroid[d] + size2 * cluster2.centroid[d]) / total_size;\n }\n\n // Collect all points from both clusters\n /** @type {{index: number, point: Float64Array}[]} */\n const all_points = [];\n for (const idx of cluster1.indices) {\n all_points.push({ index: idx, point: this._matrix.row(idx) });\n }\n for (const idx of cluster2.indices) {\n all_points.push({ index: idx, point: this._matrix.row(idx) });\n }\n\n // Select representative points - pick points farthest from centroid\n const num_reps = Math.min(this._num_representatives, all_points.length);\n const metric = this._parameters.metric;\n\n // Calculate distances from centroid for all points\n const distances = all_points.map(({ point }) => metric(point, new_centroid));\n\n // Select num_reps points with maximum distance (farthest from centroid)\n const selected_indices = [];\n const used = new Set();\n\n for (let r = 0; r < num_reps; ++r) {\n let max_dist = -1;\n let max_idx = -1;\n\n for (let i = 0; i < distances.length; ++i) {\n if (!used.has(i) && distances[i] > max_dist) {\n max_dist = distances[i];\n max_idx = i;\n }\n }\n\n if (max_idx >= 0) {\n used.add(max_idx);\n selected_indices.push(max_idx);\n }\n }\n\n // Shrink representative points toward centroid\n const new_representatives = selected_indices.map((idx) => {\n const point = all_points[idx].point;\n const shrunk = new Float64Array(D);\n const alpha = this._shrink_factor;\n\n for (let d = 0; d < D; ++d) {\n shrunk[d] = point[d] + alpha * (new_centroid[d] - point[d]);\n }\n\n return shrunk;\n });\n\n return new CURECluster(merged_indices, new_centroid, new_representatives);\n }\n\n /**\n * Run CURE clustering algorithm\n * @private\n */\n _cure() {\n // Merge clusters until we have K clusters\n while (this._clusters.length > this._K) {\n const [i, j] = this._find_closest_clusters();\n\n // Merge clusters i and j\n const merged = this._merge_clusters(this._clusters[i], this._clusters[j]);\n\n // Remove the old clusters and add the merged one\n // Remove larger index first to maintain correct indices\n // min_i < min_j is always true from _find_closest_clusters\n this._clusters.splice(j, 1);\n this._clusters.splice(i, 1);\n\n this._clusters.push(merged);\n }\n\n // Build cluster list for get_cluster_list\n this._build_cluster_ids();\n }\n\n /**\n * Build the cluster list (point -> cluster assignment)\n * @private\n */\n _build_cluster_ids() {\n const N = this._N;\n this._cluster_ids = new Array(N).fill(-1);\n\n for (let c = 0; c < this._clusters.length; ++c) {\n for (const idx of this._clusters[c].indices) {\n this._cluster_ids[idx] = c;\n }\n }\n }\n\n /**\n * @returns {number[][]}\n */\n get_clusters() {\n return this._clusters.map((cluster) => cluster.indices);\n }\n\n /**\n * @returns {number[]}\n */\n get_cluster_list() {\n return this._cluster_ids;\n }\n}\n\n/**\n * @private\n * Represents a cluster in CURE algorithm\n */\nclass CURECluster {\n /**\n * @param {number[]} indices - Indices of points in the cluster\n * @param {Float64Array} centroid - Centroid of the cluster\n * @param {Float64Array[]} representatives - Representative points (shrunk toward centroid)\n */\n constructor(indices, centroid, representatives) {\n /** @type {number[]} */\n this.indices = indices;\n /** @type {Float64Array} */\n this.centroid = centroid;\n /** @type {Float64Array[]} */\n this.representatives = representatives;\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Clustering } from \"./Clustering.js\";\n\n/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersHierarchicalClustering } from \"./index.js\" */\n\n/**\n * Hierarchical Clustering\n *\n * A bottom-up approach (agglomerative) to clustering that builds a tree of clusters (dendrogram).\n * Supports different linkage criteria: single, complete, and average.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class HierarchicalClustering extends Clustering {\n /** @type {Cluster | null} */\n root = null;\n\n /**\n * @param {InputType} points - Data or distance matrix if metric is 'precomputed'\n * @param {Partial} parameters\n */\n constructor(points, parameters = {}) {\n super(\n points,\n /** @type {ParametersHierarchicalClustering} */ (\n Object.assign({ linkage: \"complete\", metric: euclidean }, parameters)\n ),\n );\n this._id = 0;\n if (this._parameters.metric === \"precomputed\" && this._matrix.shape[0] !== this._matrix.shape[1]) {\n throw new Error(\"If metric is 'precomputed', then matrix has to be square!\");\n }\n\n const metric = this._parameters.metric;\n const A = this._matrix;\n const N = this._N;\n this._d_min = new Float64Array(N);\n const d_min = this._d_min;\n let distance_matrix;\n if (metric !== \"precomputed\") {\n distance_matrix = new Matrix(N, N, Infinity);\n for (let i = 0; i < N; ++i) {\n distance_matrix.set_entry(i, i, 0);\n d_min[i] = i; // temporary\n const Ai = A.row(i);\n for (let j = i + 1; j < N; ++j) {\n const dist = metric(Ai, A.row(j));\n distance_matrix.set_entry(i, j, dist);\n distance_matrix.set_entry(j, i, dist);\n }\n }\n for (let i = 0; i < N; i++) {\n let min_j = 0;\n let min_d = Infinity;\n for (let j = 0; j < N; j++) {\n if (i === j) continue;\n const d = distance_matrix.entry(i, j);\n if (d < min_d) {\n min_d = d;\n min_j = j;\n }\n }\n d_min[i] = min_j;\n }\n } else {\n distance_matrix = this._matrix.clone();\n for (let i = 0; i < N; ++i) {\n distance_matrix.set_entry(i, i, 0);\n d_min[i] = i === 0 ? 1 : 0;\n for (let j = 0; j < N; ++j) {\n if (i === j) continue;\n if (distance_matrix.entry(i, d_min[i]) > distance_matrix.entry(i, j)) {\n d_min[i] = j;\n }\n }\n }\n }\n this._distance_matrix = distance_matrix;\n this._clusters = new Array(N);\n const clusters = this._clusters;\n this._c_size = new Uint16Array(N);\n const c_size = this._c_size;\n for (let i = 0; i < N; ++i) {\n clusters[i] = [];\n clusters[i][0] = new Cluster(this._id++, null, null, 0, A.row(i), i, 1, 0);\n c_size[i] = 1;\n }\n const D = this._distance_matrix;\n const linkage = this._parameters.linkage;\n const p_max = N - 1;\n for (let p = 0; p < p_max; ++p) {\n let c1 = -1;\n let min_dist = Infinity;\n for (let i = 0; i < N; ++i) {\n if (D.entry(i, i) === Infinity) continue;\n const dist = D.entry(i, d_min[i]);\n if (dist < min_dist) {\n min_dist = dist;\n c1 = i;\n }\n }\n if (c1 === -1) break;\n\n const c2 = d_min[c1];\n const c1_cluster = clusters[c1][0];\n const c2_cluster = clusters[c2][0];\n const c1_cluster_indices = c1_cluster.isLeaf ? [c1_cluster.index] : c1_cluster.index;\n const c2_cluster_indices = c2_cluster.isLeaf ? [c2_cluster.index] : c2_cluster.index;\n const indices = c1_cluster_indices.concat(c2_cluster_indices);\n const new_cluster = new Cluster(this._id++, c1_cluster, c2_cluster, D.entry(c1, c2), null, indices);\n c1_cluster.parent = new_cluster;\n c2_cluster.parent = new_cluster;\n clusters[c1].unshift(new_cluster);\n\n const size1 = c_size[c1];\n const size2 = c_size[c2];\n c_size[c1] += size2;\n\n for (let j = 0; j < N; ++j) {\n if (j === c1 || j === c2 || D.entry(j, j) === Infinity) continue;\n const D_c1_j = D.entry(c1, j);\n const D_c2_j = D.entry(c2, j);\n let value;\n switch (linkage) {\n case \"single\":\n value = Math.min(D_c1_j, D_c2_j);\n break;\n case \"complete\":\n value = Math.max(D_c1_j, D_c2_j);\n break;\n case \"average\":\n value = (size1 * D_c1_j + size2 * D_c2_j) / (size1 + size2);\n break;\n }\n D.set_entry(j, c1, value);\n D.set_entry(c1, j, value);\n }\n\n D.set_entry(c2, c2, Infinity);\n for (let i = 0; i < N; ++i) {\n D.set_entry(i, c2, Infinity);\n D.set_entry(c2, i, Infinity);\n }\n\n // Update d_min for all rows\n for (let i = 0; i < N; i++) {\n if (D.entry(i, i) === Infinity) continue;\n if (d_min[i] === c1 || d_min[i] === c2 || i === c1) {\n let min_j = 0;\n let min_d = Infinity;\n for (let j = 0; j < N; j++) {\n if (i === j || D.entry(j, j) === Infinity) continue;\n const d = D.entry(i, j);\n if (d < min_d) {\n min_d = d;\n min_j = j;\n }\n }\n d_min[i] = min_j;\n } else {\n if (D.entry(i, c1) < D.entry(i, d_min[i])) {\n d_min[i] = c1;\n }\n }\n }\n\n this.root = new_cluster;\n }\n }\n\n /**\n * @param {number} value - Value where to cut the tree.\n * @param {\"distance\" | \"depth\"} [type=\"distance\"] - Type of value. Default is `\"distance\"`\n * @returns {Cluster[][]} - Array of clusters with the indices of the rows in given points.\n */\n get_clusters_raw(value, type = \"distance\") {\n /** @type {Cluster[][]} */\n const clusters = [];\n /** @type {(d: {dist: number, depth: number}) => number} */\n let accessor;\n switch (type) {\n case \"distance\":\n accessor = (d) => d.dist;\n break;\n case \"depth\":\n accessor = (d) => d.depth;\n break;\n default:\n throw new Error(\"invalid type\");\n }\n this._traverse(/** @type {Cluster} */ (this.root), accessor, value, clusters);\n return clusters;\n }\n\n /**\n * @param {number} value - Value where to cut the tree.\n * @param {\"distance\" | \"depth\"} [type=\"distance\"] - Type of value. Default is `\"distance\"`\n * @returns {number[][]} - Array of clusters with the indices of the rows in given points.\n */\n get_clusters(value, type = \"distance\") {\n /** @type {Cluster[][]} */\n const clusters = [];\n /** @type {(d: {dist: number, depth: number}) => number} */\n let accessor;\n switch (type) {\n case \"distance\":\n accessor = (d) => d.dist;\n break;\n case \"depth\":\n accessor = (d) => d.depth;\n break;\n default:\n throw new Error(\"invalid type\");\n }\n if (this.root) this._traverse(this.root, accessor, value, clusters);\n return clusters.map((cluster) => cluster.map((d) => d.index));\n }\n\n /**\n * @param {number} value - Value where to cut the tree.\n * @param {\"distance\" | \"depth\"} [type=\"distance\"] - Type of value. Default is `\"distance\"`\n * @returns {number[]} - Array of clusters with the indices of the rows in given points.\n */\n get_cluster_list(value, type = \"distance\") {\n const clusters = this.get_clusters(value, type);\n /** @type {number[]} */\n const list = new Array(this._N).fill(0);\n for (let i = 0; i < clusters.length; ++i) {\n const cluster = clusters[i];\n for (let j = 0; j < cluster.length; ++j) {\n const index = cluster[j];\n list[index] = i;\n }\n }\n return list;\n }\n\n /**\n * @private\n * @param {Cluster} node\n * @param {(d: {dist: number, depth: number}) => number} f\n * @param {number} value\n * @param {Cluster[][]} result\n */\n _traverse(node, f, value, result) {\n if (f(node) <= value) {\n result.push(node.leaves());\n } else {\n if (node.left) this._traverse(node.left, f, value, result);\n if (node.right) this._traverse(node.right, f, value, result);\n }\n }\n}\n\n/** @private */\nclass Cluster {\n /**@type {number} */\n size;\n /**@type {number} */\n depth;\n /**@type {Cluster | null} */\n parent;\n\n /**\n *\n * @param {number} id\n * @param {Cluster?} left\n * @param {Cluster?} right\n * @param {number} dist\n * @param {Float64Array?} centroid\n * @param {number} index\n * @param {number} [size]\n * @param {number} [depth]\n */\n constructor(id, left, right, dist, centroid, index, size, depth) {\n this.id = id;\n this.left = left;\n this.right = right;\n this.dist = dist;\n this.index = index;\n if (size) {\n this.size = size;\n } else {\n if (!left || !right) throw new Error(\"If size is not given, left & right cannot be null!\");\n this.size = left.size + right.size;\n }\n\n if (depth !== undefined) {\n this.depth = depth;\n } else {\n if (!left || !right) throw new Error(\"If depth is not given, left & right cannot be null!\");\n this.depth = Math.max(left.depth, right.depth) + 1;\n }\n\n if (centroid !== undefined && centroid !== null) {\n this.centroid = centroid;\n } else {\n if (!left || !right) throw new Error(\"If centroid is not given, left & right cannot be null!\");\n\n this.centroid = this._calculate_centroid(left, right);\n }\n\n this.parent = null;\n }\n\n /**\n *\n * @param {Cluster} left\n * @param {Cluster} right\n * @returns {Float64Array}\n */\n _calculate_centroid(left, right) {\n const l_size = left.size;\n const r_size = right.size;\n const l_centroid = left.centroid;\n const r_centroid = right.centroid;\n const size = this.size;\n const n = left.centroid.length;\n const new_centroid = new Float64Array(n);\n for (let i = 0; i < n; ++i) {\n new_centroid[i] = (l_size * l_centroid[i] + r_size * r_centroid[i]) / size;\n }\n return new_centroid;\n }\n\n get isLeaf() {\n return this.depth === 0;\n }\n\n /**\n *\n * @returns {Cluster[]}\n */\n leaves() {\n if (this.isLeaf) return [this];\n const left = this.left;\n const right = this.right;\n return (left ? (left.isLeaf ? [left] : left.leaves()) : []).concat(\n right ? (right.isLeaf ? [right] : right.leaves()) : [],\n );\n }\n\n /**\n *\n * @returns {Cluster[]}\n */\n descendants() {\n if (this.isLeaf) return [this];\n const left_descendants = this.left ? this.left.descendants() : [];\n const right_descendants = this.right ? this.right.descendants() : [];\n return left_descendants.concat(right_descendants).concat([this]);\n }\n}\n","/**\n * @template T\n * @typedef {Object} DisjointSetPayload\n * @property {T} parent\n * @property {Set} children\n * @property {number} size\n */\n\n/**\n * @template T\n * @class\n * @category Data Structures\n * @see {@link https://en.wikipedia.org/wiki/Disjoint-set_data_structure}\n */\nexport class DisjointSet {\n /**\n * @param {T[]?} elements\n */\n constructor(elements = null) {\n /**\n * @private\n * @type {Map>}\n */\n this._list = new Map();\n if (elements) {\n for (const e of elements) {\n this.make_set(e);\n }\n }\n }\n\n /**\n * @private\n * @param {T} x\n * @returns {DisjointSet}\n */\n make_set(x) {\n const list = this._list;\n if (!list.has(x)) {\n list.set(x, { parent: x, children: new Set([x]), size: 1 });\n }\n return this;\n }\n\n /**\n * @param {T} x\n * @returns\n */\n find(x) {\n const list = this._list;\n const disjoint_set = list.get(x);\n if (disjoint_set) {\n if (disjoint_set.parent !== x) {\n disjoint_set.children.add(x);\n const new_parent = this.find(disjoint_set.parent);\n if (!new_parent) throw new Error(\"should not happen!\");\n disjoint_set.parent = new_parent;\n return disjoint_set.parent;\n } else {\n return x;\n }\n } else {\n return null;\n }\n }\n\n /**\n * @param {T} x\n * @param {T} y\n * @returns\n */\n union(x, y) {\n let node_x = this.find(x);\n let node_y = this.find(y);\n\n if (!node_x || !node_y) throw new Error(\"x or y not found!\");\n\n let disjoint_set_x = this._list.get(node_x);\n let disjoint_set_y = this._list.get(node_y);\n\n if (!disjoint_set_x || !disjoint_set_y) throw new Error(\"should not happen!\");\n\n if (node_x === node_y) return this;\n if (disjoint_set_x.size < disjoint_set_y.size) {\n [node_x, node_y] = [node_y, node_x];\n [disjoint_set_x, disjoint_set_y] = [disjoint_set_y, disjoint_set_x];\n }\n\n disjoint_set_y.parent = node_x;\n // keep track of children\n disjoint_set_y.children.forEach(disjoint_set_x.children.add, disjoint_set_x.children);\n disjoint_set_x.size += disjoint_set_y.size;\n\n return this;\n }\n\n /** @param {T} x */\n get_children(x) {\n const node = this._list.get(x);\n if (node) {\n return node.children;\n } else {\n return null;\n }\n }\n}\n","/** @import { Comparator } from \"./index.js\" */\n\n/**\n * @template T\n * @class\n * @category Data Structures\n */\nexport class Heap {\n /** @type {{ element: T; value: number }[]} */\n _container;\n\n /** @type {Comparator} */\n _comparator;\n\n /**\n * A heap is a datastructure holding its elements in a specific way, so that the top element would be the first\n * entry of an ordered list.\n *\n * @param {T[]?} elements - Contains the elements for the Heap. `elements` can be null.\n * @param {(d: T) => number} accessor - Function returns the value of the element.\n * @param {\"min\" | \"max\" | Comparator} [comparator=\"min\"] - Function returning true or false\n * defining the wished order of the Heap, or String for predefined function. (\"min\" for a Min-Heap, \"max\" for a\n * Max_heap). Default is `\"min\"`\n * @see {@link https://en.wikipedia.org/wiki/Binary_heap}\n */\n constructor(elements = null, accessor, comparator = \"min\") {\n /** @type {(d: T) => number} */\n this._accessor = accessor;\n this._container = [];\n if (comparator === \"min\") {\n this._comparator = (a, b) => a < b;\n } else if (comparator === \"max\") {\n this._comparator = (a, b) => a > b;\n } else {\n this._comparator = comparator;\n }\n if (elements) {\n this._container = [];\n for (const e of elements) {\n this._container.push({\n element: e,\n value: accessor(e),\n });\n }\n for (let i = Math.floor(elements.length / 2 - 1); i >= 0; --i) {\n this._heapify_down(i);\n }\n }\n }\n\n /**\n * Creates a Heap from an Array\n *\n * @template T\n * @param {T[]} elements - Contains the elements for the Heap.\n * @param {(d: T) => number} accessor - Function returns the value of the element.\n * @param {\"min\" | \"max\" | Comparator} [comparator=\"min\"] - Function returning true or false\n * defining the wished order of the Heap, or String for predefined function. (\"min\" for a Min-Heap, \"max\" for a\n * Max_heap). Default is `\"min\"`\n * @returns {Heap}\n */\n static heapify(elements, accessor, comparator = \"min\") {\n const heap = new Heap(null, accessor, comparator);\n const container = heap._container;\n for (const e of elements) {\n container.push({\n element: e,\n value: accessor(e),\n });\n }\n for (let i = Math.floor(elements.length / 2 - 1); i >= 0; --i) {\n heap._heapify_down(i);\n }\n return heap;\n }\n\n /**\n * Swaps elements of container array.\n *\n * @private\n * @param {number} index_a\n * @param {number} index_b\n */\n _swap(index_a, index_b) {\n const container = this._container;\n [container[index_b], container[index_a]] = [container[index_a], container[index_b]];\n return;\n }\n\n /** @private */\n _heapify_up() {\n const container = this._container;\n let index = container.length - 1;\n while (index > 0) {\n const parentIndex = Math.floor((index - 1) / 2);\n if (!this._comparator(container[index].value, container[parentIndex].value)) {\n break;\n } else {\n this._swap(parentIndex, index);\n index = parentIndex;\n }\n }\n }\n\n /**\n * Pushes the element to the heap.\n *\n * @param {T} element\n * @returns {Heap}\n */\n push(element) {\n const value = this._accessor(element);\n //const node = new Node(element, value);\n const node = { element: element, value: value };\n this._container.push(node);\n this._heapify_up();\n return this;\n }\n\n /**\n * @private\n * @param {Number} [start_index=0] Default is `0`\n */\n _heapify_down(start_index = 0) {\n const container = this._container;\n const comparator = this._comparator;\n const length = container.length;\n const left = 2 * start_index + 1;\n const right = 2 * start_index + 2;\n let index = start_index;\n if (index >= length) throw \"index higher than length\";\n if (left < length && comparator(container[left].value, container[index].value)) {\n index = left;\n }\n if (right < length && comparator(container[right].value, container[index].value)) {\n index = right;\n }\n if (index !== start_index) {\n this._swap(start_index, index);\n this._heapify_down(index);\n }\n }\n\n /**\n * Removes and returns the top entry of the heap.\n *\n * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by\n * `accessor`}).\n */\n pop() {\n const container = this._container;\n if (container.length === 0) {\n return null;\n } else if (container.length === 1) {\n const item = container.pop();\n if (!item) throw new Error(\"Cannot happen!\");\n return item;\n }\n this._swap(0, container.length - 1);\n const item = container.pop();\n this._heapify_down();\n return item ?? null;\n }\n\n /**\n * Returns the top entry of the heap without removing it.\n *\n * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by\n * `accessor`).\n */\n get first() {\n return this._container.length > 0 ? this._container[0] : null;\n }\n\n /**\n * Yields the raw data\n *\n * @yields {T} Object consists of the element and its value (computed by `accessor`}).\n */\n *iterate() {\n for (let i = 0, n = this._container.length; i < n; ++i) {\n yield this._container[i].element;\n }\n }\n\n /**\n * Returns the heap as ordered array.\n *\n * @returns {T[]} Array consisting the elements ordered by `comparator`.\n */\n toArray() {\n return this._container.sort((a, b) => (this._comparator(a.value, b.value) ? -1 : 1)).map((d) => d.element);\n }\n\n /**\n * Returns elements of container array.\n *\n * @returns {T[]} Array consisting the elements.\n */\n data() {\n return this._container.map((d) => d.element);\n }\n\n /**\n * Returns the container array.\n *\n * @returns {{ element: T; value: number }[]} The container array.\n */\n raw_data() {\n return this._container;\n }\n\n /**\n * The size of the heap.\n *\n * @returns {number}\n */\n get length() {\n return this._container.length;\n }\n\n /**\n * Returns false if the the heap has entries, true if the heap has no entries.\n *\n * @returns {boolean}\n */\n get empty() {\n return this.length === 0;\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { linspace, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { Clustering } from \"./Clustering.js\";\n\n/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersKMeans } from \"./index.js\" */\n/**\n * K-Means Clustering\n *\n * A popular clustering algorithm that partitions data into K clusters where each point\n * belongs to the cluster with the nearest mean (centroid).\n *\n * @class\n * @extends Clustering\n * @category Clustering\n * @see {@link KMedoids} for a more robust alternative\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const points = [[1, 1], [1.5, 1.5], [5, 5], [5.5, 5.5]];\n * const kmeans = new druid.KMeans(points, { K: 2 });\n *\n * const clusters = kmeans.get_cluster_list(); // [0, 0, 1, 1]\n * const centroids = kmeans.centroids; // center points\n */\nexport class KMeans extends Clustering {\n /**\n * @param {InputType} points\n * @param {Partial} parameters\n */\n constructor(points, parameters = {}) {\n super(\n points,\n /** @type {ParametersKMeans} */ (Object.assign({ K: 4, metric: euclidean, seed: 1212 }, parameters)),\n );\n\n const K = this._parameters.K;\n const seed = parameters.seed;\n\n // Convert points to Matrix if needed\n if (points instanceof Matrix) {\n this._matrix = points;\n } else {\n this._matrix = Matrix.from(points);\n }\n\n const [N, D] = this._matrix.shape;\n this._N = N;\n this._D = D;\n\n this._K = K > N ? N : K;\n this._randomizer = new Randomizer(seed);\n\n /** @type {number[]} */\n this._clusters = new Array(N).fill(0);\n\n this._cluster_centroids = parameters.initial_centroids\n ? parameters.initial_centroids.map((c) => new Float64Array(c))\n : this._get_random_centroids(this._K);\n let cluster_centroids = this._cluster_centroids;\n let iterations = 0;\n const max_iterations = 300;\n let clusters_changed = true;\n\n while (clusters_changed && iterations < max_iterations) {\n const iteration_result = this._iteration(cluster_centroids);\n cluster_centroids = iteration_result.cluster_centroids;\n clusters_changed = iteration_result.clusters_changed;\n iterations++;\n }\n\n this._cluster_centroids = cluster_centroids;\n }\n\n /** @returns {number} The number of clusters */\n get k() {\n return this._K;\n }\n\n /** @returns {Float64Array[]} The cluster centroids */\n get centroids() {\n return this._cluster_centroids;\n }\n\n /** @returns {number[]} The cluster list */\n get_cluster_list() {\n return this._clusters;\n }\n\n /** @returns {number[][]} An Array of clusters with the indices of the points. */\n get_clusters() {\n const K = this._K;\n const clusters = this._clusters;\n /** @type {number[][]} */\n const result = new Array(K).fill(0).map(() => []);\n clusters.forEach((c, i) => {\n if (c >= 0 && c < K) {\n result[c].push(i);\n }\n });\n return result;\n }\n\n /**\n * @private\n * @param {number[]} point_indices\n * @param {number[]} candidates\n * @returns {number}\n */\n _furthest_point(point_indices, candidates) {\n const A = this._matrix;\n const metric = this._parameters.metric;\n\n if (point_indices.length === 0 || candidates.length === 0) {\n return candidates[0] ?? 0;\n }\n\n const H = Heap.heapify(\n candidates,\n (d) => {\n const Ad = A.row(d);\n let sum = 0;\n for (let j = 0; j < point_indices.length; ++j) {\n sum += metric(Ad, A.row(point_indices[j]));\n }\n return sum;\n },\n \"max\",\n );\n\n const furthest = H.pop();\n if (!furthest) throw new Error(\"Should not happen!\");\n\n return furthest.element;\n }\n\n /**\n * @private\n * @param {number} K\n * @returns {Float64Array[]}\n */\n _get_random_centroids(K) {\n const N = this._N;\n const randomizer = this._randomizer;\n const A = this._matrix;\n /** @type {Float64Array[]} */\n const cluster_centroids = new Array(K);\n const indices = linspace(0, N - 1);\n\n // First centroid: random selection\n const random_point = randomizer.random_int % N;\n cluster_centroids[0] = A.row(random_point);\n const init_points = [random_point];\n\n const sample_size = Math.max(1, Math.floor((N - K) / K));\n\n for (let i = 1; i < K; ++i) {\n const remaining = indices.filter((d) => !init_points.includes(d));\n if (remaining.length === 0) break;\n\n const sample = randomizer.choice(remaining, Math.min(sample_size, remaining.length));\n const furthest_point = this._furthest_point(init_points, sample);\n\n init_points.push(furthest_point);\n cluster_centroids[i] = A.row(furthest_point);\n }\n\n return cluster_centroids;\n }\n\n /**\n * @private\n * @param {Float64Array[]} cluster_centroids\n * @returns {{ clusters_changed: boolean; cluster_centroids: Float64Array[] }}\n */\n _iteration(cluster_centroids) {\n const K = cluster_centroids.length;\n const N = this._N;\n const metric = this._parameters.metric;\n const A = this._matrix;\n const clusters = this._clusters;\n let clusters_changed = false;\n\n // Find nearest cluster centroid for each point\n for (let i = 0; i < N; ++i) {\n const Ai = A.row(i);\n let min_dist = Infinity;\n let min_cluster = 0;\n\n for (let j = 0; j < K; ++j) {\n const d = metric(cluster_centroids[j], Ai);\n if (d < min_dist) {\n min_dist = d;\n min_cluster = j;\n }\n }\n\n if (clusters[i] !== min_cluster) {\n clusters_changed = true;\n clusters[i] = min_cluster;\n }\n }\n\n // Update cluster centroids\n const new_centroids = this._compute_centroid(K);\n\n return {\n clusters_changed: clusters_changed,\n cluster_centroids: new_centroids,\n };\n }\n\n /**\n * @private\n * @param {number} K\n * @returns {Float64Array[]}\n */\n _compute_centroid(K) {\n const N = this._N;\n const D = this._D;\n const A = this._matrix;\n const clusters = this._clusters;\n\n // Initialize new centroids and counters\n /** @type {Float64Array[]} */\n const new_centroids = new Array(K);\n const cluster_counter = new Array(K).fill(0);\n\n for (let i = 0; i < K; ++i) {\n new_centroids[i] = new Float64Array(D);\n }\n\n // Sum up all points in each cluster\n for (let i = 0; i < N; ++i) {\n const Ai = A.row(i);\n const ci = clusters[i];\n if (ci >= 0 && ci < K) {\n cluster_counter[ci]++;\n const centroid = new_centroids[ci];\n for (let j = 0; j < D; ++j) {\n centroid[j] += Ai[j];\n }\n }\n }\n\n // Divide by count to get mean\n for (let i = 0; i < K; ++i) {\n const n = cluster_counter[i];\n if (n > 0) {\n const centroid = new_centroids[i];\n for (let j = 0; j < D; ++j) {\n centroid[j] /= n;\n }\n }\n }\n\n return new_centroids;\n }\n}\n","import { linspace, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { Clustering } from \"./Clustering.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import { ParametersKMedoids } from \"./index.js\" */\n\n/**\n * K-Medoids (PAM - Partitioning Around Medoids)\n *\n * A robust clustering algorithm similar to K-Means, but uses actual data points (medoids)\n * as cluster centers and can work with any distance metric.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n * @see {@link KMeans} for a faster but less robust alternative\n */\nexport class KMedoids extends Clustering {\n /**\n * @param {InputType} points - Data matrix\n * @param {Partial} parameters\n * @see {@link https://link.springer.com/chapter/10.1007/978-3-030-32047-8_16} Faster k-Medoids Clustering: Improving the PAM, CLARA, and CLARANS Algorithms\n */\n constructor(points, parameters = {}) {\n super(points, Object.assign({ K: 4, max_iter: null, metric: euclidean, seed: 1212 }, parameters));\n this._A = this._matrix.to2dArray();\n let K = this._parameters.K;\n const N = this._N;\n this._max_iter = this._parameters.max_iter ?? 10 * Math.log10(N);\n this._distance_matrix = new Matrix(N, N, \"zeros\");\n\n if (K > N) {\n this._parameters.K = K = N;\n }\n this._randomizer = new Randomizer(this._parameters.seed);\n this._clusters = new Array(N).fill(-1);\n this._cluster_medoids = this._get_random_medoids(K);\n this._is_initialized = false;\n }\n\n /** @returns {number[]} The cluster list */\n get_cluster_list() {\n if (!this._is_initialized) {\n this.get_clusters();\n }\n return this._clusters;\n }\n\n /** @returns {number[][]} - Array of clusters with the indices of the rows in given points. */\n get_clusters() {\n const K = this._parameters.K;\n const A = this._A;\n const N = this._N;\n if (!this._is_initialized) {\n this.init(K, this._cluster_medoids);\n }\n /** @type {number[][]} */\n const result = new Array(K).fill(0).map(() => []);\n for (let j = 0; j < N; j++) {\n const nearest = this._nearest_medoid(A[j], j);\n const cluster_idx = nearest.index_nearest;\n result[cluster_idx].push(j);\n this._clusters[j] = cluster_idx;\n }\n return result;\n }\n\n /** @returns {number} */\n get k() {\n return this._parameters.K;\n }\n\n /** @returns {number[]} */\n get medoids() {\n return this.get_medoids();\n }\n\n /** @returns {number[]} */\n get_medoids() {\n const K = this._parameters.K;\n if (!this._is_initialized) {\n this.init(K, this._cluster_medoids);\n }\n return this._cluster_medoids;\n }\n\n async *generator() {\n const max_iter = this._max_iter;\n if (!this._is_initialized) {\n this.get_clusters();\n }\n yield this.get_clusters();\n let i = 0;\n while (i < max_iter) {\n const finish = this._iteration();\n this._update_clusters();\n yield this.get_clusters();\n if (finish) break;\n i++;\n }\n }\n\n /** Algorithm 1. FastPAM1: Improved SWAP algorithm */\n /* _iteration_1() {\n const A = this._A;\n const N = this._N;\n const K = this._K;\n const medoids = this._cluster_medoids;\n let DeltaTD = 0;\n let m0 = null;\n let x0 = null;\n A.forEach((x_j, j) => {\n if (medoids.findIndex(m => m === j) < 0) {\n const nearest_medoid = this._nearest_medoid(x_j, j);\n const d_j = nearest_medoid.distance_nearest; // distance to current medoid\n const deltaTD = new Array(K).fill(-d_j); // change if making j a medoid\n A.forEach((x_o, o) => {\n // disance to new medoid\n const d_oj = this._get_distance(o, j, x_o, x_j);\n const {\n \"index_nearest\": n,\n \"distance_nearest\": d_n,\n \"distance_second\": d_s,\n } = this._nearest_medoid(x_o, o);\n this._clusters[o] = n; // cached values\n deltaTD[n] += Math.min(d_oj, d_s) - d_n; // loss change\n if (d_oj < d_n) { // reassignment check\n deltaTD.forEach((d_i, i) => {\n if (n !== i) {\n deltaTD[i] = d_i + d_oj - d_n; // update loss change\n }\n });\n }\n });\n // choose best medoid i;\n const i = deltaTD\n .map((d, i) => [d, i])\n .sort((d1, d2) => d1[0] - d2[0])[0][1];\n const deltaTD_i = deltaTD[i];\n // store\n if (deltaTD_i < DeltaTD) {\n DeltaTD = deltaTD_i;\n m0 = i;\n x0 = j;\n }\n }\n });\n\n if (DeltaTD >= 0) {\n return true // break loop if DeltaTD >= 0\n }\n // swap roles of medoid m and non-medoid x;\n medoids[m0] = x0;\n this._cluster_medoids = medoids;\n return false\n } */\n\n /** FastPAM1: One best swap per iteration */\n _iteration() {\n const A = this._A;\n const K = this._parameters.K;\n const medoids = this._cluster_medoids;\n const N = this._N;\n\n // Precompute nearest and second nearest medoid for all points\n const cache = new Array(N);\n for (let i = 0; i < N; i++) {\n cache[i] = this._nearest_medoid(A[i], i);\n }\n\n let best_delta = 0;\n let best_swap = null; // { m_idx: index in medoids, x_idx: index in A }\n\n // For each non-medoid point j, evaluate swapping it with each medoid i\n const medoid_set = new Set(medoids);\n for (let j = 0; j < N; j++) {\n if (medoid_set.has(j)) continue;\n\n const x_j = A[j];\n const d_j = cache[j].distance_nearest;\n\n // deltaTD[i] will store the change in total distance if we swap medoid[i] with j\n const deltaTD = new Array(K).fill(-d_j);\n\n for (let o = 0; o < N; o++) {\n if (o === j) continue;\n const dist_o_j = this._get_distance(o, j, A[o], x_j);\n const { index_nearest: n, distance_nearest: d_n, distance_second: d_s } = cache[o];\n\n // If o is assigned to the current medoid being swapped out (n)\n deltaTD[n] += Math.min(dist_o_j, d_s) - d_n;\n\n // For all other medoids i != n, if j is closer to o than its current medoid\n if (dist_o_j < d_n) {\n for (let i = 0; i < K; i++) {\n if (i !== n) {\n deltaTD[i] += dist_o_j - d_n;\n }\n }\n }\n }\n\n // Find best medoid to swap with j\n for (let i = 0; i < K; i++) {\n if (deltaTD[i] < best_delta) {\n best_delta = deltaTD[i];\n best_swap = { m_idx: i, x_idx: j };\n }\n }\n }\n\n if (best_swap && best_delta < 0) {\n medoids[best_swap.m_idx] = best_swap.x_idx;\n this._cluster_medoids = medoids;\n return false; // not finished\n }\n\n return true; // finished\n }\n\n /**\n *\n * @param {number} i\n * @param {number} j\n * @param {Float64Array?} x_i\n * @param {Float64Array?} x_j\n * @returns\n */\n _get_distance(i, j, x_i = null, x_j = null) {\n if (i === j) return 0;\n const D = this._distance_matrix;\n const A = this._A;\n const metric = this._parameters.metric;\n let d_ij = D.entry(i, j);\n if (d_ij === 0) {\n d_ij = metric(x_i || A[i], x_j || A[j]);\n D.set_entry(i, j, d_ij);\n D.set_entry(j, i, d_ij);\n }\n return d_ij;\n }\n\n /**\n *\n * @param {Float64Array} x_j\n * @param {number} j\n * @returns\n */\n _nearest_medoid(x_j, j) {\n const medoids = this._cluster_medoids;\n const A = this._A;\n if (medoids.length === 0) {\n throw new Error(\"No medoids available. Initialization failed.\");\n }\n\n let d_n = Infinity;\n let n = -1;\n let d_s = Infinity;\n let s = -1;\n\n for (let i = 0; i < medoids.length; i++) {\n const m = medoids[i];\n const d = this._get_distance(j, m, x_j, A[m]);\n if (d < d_n) {\n d_s = d_n;\n s = n;\n d_n = d;\n n = i;\n } else if (d < d_s) {\n d_s = d;\n s = i;\n }\n }\n\n if (s === -1) s = n;\n\n return {\n distance_nearest: d_n,\n index_nearest: n,\n distance_second: d_s,\n index_second: s,\n };\n }\n\n _update_clusters() {\n const N = this._N;\n const A = this._A;\n for (let j = 0; j < N; j++) {\n const nearest = this._nearest_medoid(A[j], j);\n this._clusters[j] = nearest.index_nearest;\n }\n }\n\n /**\n * Computes `K` clusters out of the `matrix`.\n * @param {number} K - Number of clusters.\n * @param {number[]} cluster_medoids\n */\n init(K, cluster_medoids) {\n if (!K) K = this._parameters.K;\n if (!cluster_medoids) cluster_medoids = this._get_random_medoids(K);\n this._cluster_medoids = cluster_medoids;\n const max_iter = this._max_iter;\n let finish = false;\n let i = 0;\n do {\n finish = this._iteration();\n } while (!finish && ++i < max_iter);\n this._update_clusters();\n this._is_initialized = true;\n return this;\n }\n\n /**\n * Algorithm 3. FastPAM LAB: Linear Approximate BUILD initialization.\n *\n * @param {number} K - Number of clusters\n * @returns {number[]}\n */\n _get_random_medoids(K) {\n const N = this._N;\n const A = this._A;\n const indices = linspace(0, N - 1);\n const randomizer = this._randomizer;\n const n = Math.min(N, 10 + Math.ceil(Math.sqrt(N)));\n\n // Handle case where K >= N\n if (K >= N) {\n return indices.slice(0, N);\n }\n\n /** @type {number[]} */\n const medoids = [];\n\n // first medoid: select from a random sample of size n\n let best_j = -1;\n let min_td = Infinity;\n let S = randomizer.choice(indices, n);\n for (let j = 0; j < S.length; ++j) {\n let td = 0;\n const S_j = S[j];\n const x_j = A[S_j];\n for (let o = 0; o < S.length; ++o) {\n if (o === j) continue;\n td += this._get_distance(S_j, S[o], x_j, A[S[o]]);\n }\n if (td < min_td) {\n min_td = td;\n best_j = S_j;\n }\n }\n medoids.push(best_j);\n\n // other medoids: greedy additive selection (Algorithm LAB)\n for (let i = 1; i < K; ++i) {\n let best_idx = -1;\n let best_delta = Infinity;\n\n const remainingIndices = indices.filter((idx) => !medoids.includes(idx));\n if (remainingIndices.length === 0) break;\n\n S = randomizer.choice(remainingIndices, Math.min(n, remainingIndices.length));\n for (let j = 0; j < S.length; ++j) {\n let deltaTD = 0;\n const S_j = S[j];\n const x_j = A[S_j];\n\n // Estimate TD reduction on the sample S\n for (let o = 0; o < S.length; ++o) {\n if (o === j) continue;\n const S_o = S[o];\n const x_o = A[S_o];\n\n // Closest distance to current medoids\n let min_d_existing = Infinity;\n for (let m = 0; m < medoids.length; m++) {\n const d = this._get_distance(S_o, medoids[m], x_o, A[medoids[m]]);\n if (d < min_d_existing) min_d_existing = d;\n }\n\n const delta = this._get_distance(S_j, S_o, x_j, x_o) - min_d_existing;\n if (delta < 0) {\n deltaTD += delta;\n }\n }\n\n if (deltaTD < best_delta) {\n best_delta = deltaTD;\n best_idx = S_j;\n }\n }\n if (best_idx !== -1) {\n medoids.push(best_idx);\n }\n }\n return medoids;\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Clustering } from \"./Clustering.js\";\n\n/** @import { ParametersMeanShift } from \"./index.js\" */\n/** @import { InputType } from \"../index.js\" */\n\n/**\n * Mean Shift Clustering\n *\n * A non-parametric clustering technique that does not require prior knowledge of the\n * number of clusters. It identifies centers of density in the data.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class MeanShift extends Clustering {\n /** @type {number} */\n _bandwidth;\n /** @type {number} */\n _max_iter;\n /** @type {number} */\n _tolerance;\n /** @type {(dist: number) => number} */\n _kernel;\n /** @type {Matrix} */\n _points;\n /** @type {number[] | undefined} */\n _clusters;\n /** @type {number[][] | undefined} */\n _cluster_list;\n /**\n *\n * @param {InputType} points\n * @param {Partial} parameters\n */\n constructor(points, parameters = {}) {\n super(\n points,\n /** @type {ParametersMeanShift} */ (\n Object.assign({ seed: 1212, metric: euclidean, bandwidth: 0, kernel: \"gaussian\" }, parameters)\n ),\n );\n\n // Ensure bandwidth is positive\n this._bandwidth = parameters.bandwidth ?? this._compute_bandwidth(this._matrix);\n this._max_iter = parameters.max_iter ?? Math.max(10, Math.floor(10 * Math.log10(this._N)));\n this._tolerance = parameters.tolerance ?? 1e-3;\n const kernel_param = parameters.kernel ?? \"gaussian\";\n // If kernel is a string, map to function\n if (typeof kernel_param === \"string\") {\n if (kernel_param === \"flat\") {\n this._kernel = (dist) => (dist <= this._bandwidth ? 1 : 0);\n } else {\n // gaussian (default)\n this._kernel = (dist) => Math.exp(-(dist * dist) / (2 * this._bandwidth * this._bandwidth));\n }\n } else {\n // custom function\n this._kernel = kernel_param;\n }\n\n // Copy points to a mutable matrix\n this._points = this._matrix.clone();\n\n this._mean_shift();\n this._assign_clusters();\n }\n\n // Helper to compute bandwidth if not provided\n /**\n * @param {Matrix} matrix\n * @returns {number}\n */\n _compute_bandwidth(matrix) {\n const N = matrix.shape[0];\n //const D = matrix.shape[1];\n // Compute average pairwise distance\n let totalDist = 0;\n for (let i = 0; i < N; ++i) {\n const row_i = matrix.row(i);\n for (let j = i + 1; j < N; ++j) {\n const row_j = matrix.row(j);\n const dist = this._parameters.metric(row_i, row_j);\n totalDist += dist;\n }\n }\n const avgDist = totalDist / ((N * (N - 1)) / 2);\n // Use a fraction of avgDist as bandwidth\n return avgDist / 2;\n }\n\n // Compute kernel weight\n /**\n * @param {number} dist\n * @returns {number}\n */\n _kernel_weight(dist) {\n return this._kernel(dist);\n }\n\n // Perform mean shift iterations\n _mean_shift() {\n const N = this._N;\n const D = this._D;\n const points = this._points;\n const metric = this._parameters.metric;\n //const bandwidth = this._bandwidth;\n const kernel = this._kernel_weight.bind(this);\n const tolerance = this._tolerance;\n\n for (let iter = 0; iter < this._max_iter; ++iter) {\n let max_shift = 0;\n // For each point compute shift\n for (let i = 0; i < N; ++i) {\n const row_i = points.row(i);\n let sum_weights = 0;\n const weighted_sum = new Float64Array(D);\n for (let j = 0; j < N; ++j) {\n const row_j = points.row(j);\n const dist = metric(row_i, row_j);\n const weight = kernel(dist);\n sum_weights += weight;\n for (let d = 0; d < D; ++d) {\n weighted_sum[d] += weight * row_j[d];\n }\n }\n if (sum_weights === 0) {\n // No neighbors within kernel, shift is zero\n //const shift = new Float64Array(D);\n // Compute shift magnitude\n const shift_norm = Math.sqrt(weighted_sum.reduce((acc, v) => acc + v * v, 0));\n max_shift = Math.max(max_shift, shift_norm);\n } else {\n const shift = new Float64Array(D);\n for (let d = 0; d < D; ++d) {\n shift[d] = weighted_sum[d] / sum_weights - row_i[d];\n }\n const shift_norm = Math.sqrt(shift.reduce((acc, v) => acc + v * v, 0));\n max_shift = Math.max(max_shift, shift_norm);\n // Update point\n for (let d = 0; d < D; ++d) {\n row_i[d] += shift[d];\n }\n }\n }\n if (max_shift < tolerance) {\n // Converged\n break;\n }\n }\n }\n\n // After convergence, assign clusters based on nearest mode\n _assign_clusters() {\n const N = this._N;\n const metric = this._parameters.metric;\n const bandwidth = this._bandwidth;\n\n // Group points that converged to the same mode\n // Two points are in the same mode if they're within bandwidth/2 of each other\n const mode_threshold = bandwidth * 0.5;\n /** @type {number[][]} */\n const modes = []; // Each mode contains indices of points in that mode\n const point_to_mode = new Array(N).fill(-1);\n\n for (let i = 0; i < N; ++i) {\n if (point_to_mode[i] !== -1) continue; // Already assigned to a mode\n\n const row_i = this._points.row(i);\n const mode = [i];\n point_to_mode[i] = modes.length;\n\n // Find all points close to this mode\n for (let j = i + 1; j < N; ++j) {\n if (point_to_mode[j] !== -1) continue;\n\n const row_j = this._points.row(j);\n const dist = metric(row_i, row_j);\n\n if (dist < mode_threshold) {\n mode.push(j);\n point_to_mode[j] = modes.length;\n }\n }\n\n modes.push(mode);\n }\n\n // Build final clusters - each mode becomes a cluster\n /** @type {number[][]} */\n const clusters = [];\n const cluster_ids = new Array(N).fill(-1);\n\n for (let mode_idx = 0; mode_idx < modes.length; ++mode_idx) {\n const mode = modes[mode_idx];\n clusters.push([...mode]);\n for (const point_idx of mode) {\n cluster_ids[point_idx] = mode_idx;\n }\n }\n\n this._clusters = cluster_ids;\n this._cluster_list = clusters;\n }\n\n /**\n * @returns {number[][]}\n */\n get_clusters() {\n // Ensure algorithm has been run\n if (!this._cluster_list) {\n this._mean_shift();\n this._assign_clusters();\n }\n return /** @type {number[][]} */ (this._cluster_list);\n }\n\n /**\n *\n * @returns {number[]}\n */\n get_cluster_list() {\n if (!this._clusters) {\n this._mean_shift();\n this._assign_clusters();\n }\n return /** @type {number[]} */ (this._clusters);\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Clustering } from \"./Clustering.js\";\n\n/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersOptics } from \"./index.js\" */\n\n/** @typedef {Object} DBEntry\n * @property {Float64Array} element\n * @property {number} index\n * @property {number} [reachability_distance]\n * @property {boolean} processed\n * @property {DBEntry[]} [neighbors]\n */\n\n/**\n * OPTICS (Ordering Points To Identify the Clustering Structure)\n *\n * A density-based clustering algorithm that extends DBSCAN. It handles clusters of varying\n * densities and produces a reachability plot that can be used to extract clusters.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class OPTICS extends Clustering {\n /**\n * **O**rdering **P**oints **T**o **I**dentify the **C**lustering **S**tructure.\n *\n * @param {InputType} points - The data.\n * @param {Partial} [parameters={}]\n * @see {@link https://www.dbs.ifi.lmu.de/Publikationen/Papers/OPTICS.pdf}\n * @see {@link https://en.wikipedia.org/wiki/OPTICS_algorithm}\n */\n constructor(points, parameters = {}) {\n super(\n points,\n /** @type {ParametersOptics} */ (\n Object.assign({ epsilon: 1, min_points: 4, metric: euclidean }, parameters)\n ),\n );\n const matrix = this._matrix;\n /**\n * @private\n * @type {DBEntry[]}\n */\n this._ordered_list = [];\n const ordered_list = this._ordered_list;\n /** @type {number[][]} */\n this._clusters = [];\n const clusters = this._clusters;\n\n const N = this._N;\n\n /**\n * @private\n * @type {DBEntry[]}\n */\n this._DB = new Array(N).fill(0).map((_, i) => {\n return {\n element: matrix.row(i),\n index: i,\n reachability_distance: undefined,\n processed: false,\n };\n });\n const DB = this._DB;\n\n this._cluster_index = 0;\n let cluster_index = this._cluster_index;\n\n for (const p of DB) {\n if (p.processed) continue;\n p.neighbors = this._get_neighbors(p);\n p.processed = true;\n clusters.push([p.index]);\n cluster_index = clusters.length - 1;\n ordered_list.push(p);\n if (this._core_distance(p) !== undefined) {\n const seeds = new Heap(null, (d) => d.reachability_distance, \"min\");\n this._update(p, seeds);\n this._expand_cluster(seeds, clusters[cluster_index]);\n }\n }\n }\n\n /**\n * @private\n * @param {DBEntry} p - A point of the data.\n * @returns {DBEntry[]} An array consisting of the `epsilon`-neighborhood of `p`.\n */\n _get_neighbors(p) {\n if (p?.neighbors) return p.neighbors;\n const DB = this._DB;\n const metric = this._parameters.metric;\n const epsilon = this._parameters.epsilon;\n const neighbors = [];\n for (const q of DB) {\n if (q.index === p.index) continue;\n if (metric(p.element, q.element) <= epsilon) {\n neighbors.push(q);\n }\n }\n return neighbors;\n }\n\n /**\n * @private\n * @param {DBEntry} p - A point of `matrix`.\n * @returns {number|undefined} The distance to the `min_points`-th nearest point of `p`, or undefined if the\n * `epsilon`-neighborhood has fewer elements than `min_points`.\n */\n _core_distance(p) {\n const min_points = this._parameters.min_points;\n const metric = this._parameters.metric;\n // Need min_points - 1 other points plus the point itself\n if (!p.neighbors || p.neighbors.length < min_points - 1) {\n return undefined;\n }\n // Sort neighbors by distance to find the MinPts-th closest\n const sortedNeighbors = p.neighbors.toSorted(\n (a, b) => metric(p.element, a.element) - metric(p.element, b.element),\n );\n // MinPts-th closest is at index min_points - 2 (0-indexed, excluding p itself)\n return metric(p.element, sortedNeighbors[min_points - 2].element);\n }\n\n /**\n * Updates the reachability distance of the points.\n *\n * @private\n * @param {DBEntry} p\n * @param {Heap} seeds\n */\n _update(p, seeds) {\n const metric = this._parameters.metric;\n const core_distance = this._core_distance(p);\n // If p is not a core point, don't update seeds\n if (core_distance === undefined) {\n return;\n }\n const neighbors = this._get_neighbors(p); //p.neighbors;\n for (const q of neighbors) {\n if (q.processed) continue;\n const new_reachability_distance = Math.max(core_distance, metric(p.element, q.element));\n //if (q.reachability_distance == undefined) { // q is not in seeds\n if (seeds.raw_data().findIndex((d) => d.element === q) < 0) {\n q.reachability_distance = new_reachability_distance;\n seeds.push(q);\n } else {\n // q is in seeds\n if (new_reachability_distance < (q.reachability_distance ?? Infinity)) {\n q.reachability_distance = new_reachability_distance;\n seeds = Heap.heapify(seeds.data(), (d) => d.reachability_distance ?? Infinity, \"min\"); // seeds change key =/\n }\n }\n }\n }\n\n /**\n * Expands the `cluster` with points in `seeds`.\n *\n * @private\n * @param {Heap} seeds\n * @param {number[]} cluster\n */\n _expand_cluster(seeds, cluster) {\n const ordered_list = this._ordered_list;\n while (!seeds.empty) {\n const q = /** @type {{ element: DBEntry, value: number}} */ (seeds.pop()).element;\n q.neighbors = this._get_neighbors(q);\n q.processed = true;\n cluster.push(q.index);\n ordered_list.push(q);\n if (this._core_distance(q) !== undefined) {\n this._update(q, seeds);\n // Recursive call removed - while loop handles iteration correctly\n }\n }\n }\n\n /**\n * Returns an array of clusters.\n *\n * @returns {number[][]} Array of clusters with the indices of the rows in given `matrix`.\n */\n get_clusters() {\n const clusters = [];\n const outliers = [];\n const min_points = this._parameters.min_points;\n for (const cluster of this._clusters) {\n if (cluster.length < min_points) {\n outliers.push(...cluster);\n } else {\n clusters.push(cluster);\n }\n }\n clusters.push(outliers);\n return clusters;\n }\n\n /**\n * @returns {number[]} Returns an array, where the ith entry defines the cluster affirmation of the ith point of\n * given data. (-1 stands for outlier)\n */\n get_cluster_list() {\n const N = this._matrix.shape[0];\n /** @type {number[]} */\n const result = new Array(N).fill(0);\n const clusters = this.get_clusters();\n for (let i = 0, n = clusters.length; i < n; ++i) {\n const cluster = clusters[i];\n for (const index of cluster) {\n result[index] = i < n - 1 ? i : -1;\n }\n }\n return result;\n }\n}\n","import { euclidean, euclidean_squared } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport { KMeans } from \"./KMeans.js\";\n\n/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersXMeans } from \"./index.js\" */\n\n/**\n * @typedef SplitResult\n * @property {number} index - Index of the cluster being split\n * @property {number} bic_parent - BIC score of the parent cluster\n * @property {number} bic_children - BIC score of the split children\n * @property {number[][]} child_clusters - Clusters after splitting\n * @property {Float64Array[]} child_centroids - Centroids of child clusters\n */\n\n/**\n * @typedef CandidateResult\n * @property {KMeans} kmeans - The KMeans instance for this K\n * @property {number} score - BIC score\n */\n\n/**\n * X-Means Clustering\n *\n * An extension of K-Means that automatically determines the number of clusters (K)\n * using the Bayesian Information Criterion (BIC).\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class XMeans extends Clustering {\n /**\n * XMeans clustering algorithm that automatically determines the optimal number of clusters.\n *\n * X-Means extends K-Means by starting with a minimum number of clusters and iteratively\n * splitting clusters to improve the Bayesian Information Criterion (BIC).\n *\n * Algorithm:\n * 1. Start with K_min clusters using KMeans\n * 2. For each cluster, try splitting it into 2 sub-clusters\n * 3. If BIC improves after splitting, keep the split\n * 4. Run KMeans again with all (old + new) centroids\n * 5. Repeat until K_max is reached or no more improvements\n *\n * @param {InputType} points - The data points to cluster\n * @param {Partial} [parameters={}] - Configuration parameters\n * @see {@link https://www.cs.cmu.edu/~dpelleg/download/xmeans.pdf}\n * @see {@link https://github.com/annoviko/pyclustering/blob/master/pyclustering/cluster/xmeans.py}\n * @see {@link https://github.com/haifengl/smile/blob/master/core/src/main/java/smile/clustering/XMeans.java}\n */\n constructor(points, parameters = {}) {\n const defaults = {\n K_max: 10,\n K_min: 2,\n metric: euclidean,\n seed: 1212,\n min_cluster_size: 35,\n tolerance: 0.001,\n };\n super(points, /** @type {ParametersXMeans} */ (Object.assign(defaults, parameters)));\n this._randomizer = new Randomizer(this._parameters.seed);\n\n /** @type {KMeans | null} */\n this._best_kmeans = null;\n\n // Run XMeans algorithm\n this._run();\n }\n\n /**\n * Run the XMeans algorithm\n *\n * @private\n */\n _run() {\n /** @type {Map} */\n const candidates = new Map();\n const A = this._matrix;\n\n // Initialize with K_min clusters\n let current_kmeans = new KMeans(this._points, {\n K: this._parameters.K_min,\n metric: this._parameters.metric,\n seed: this._parameters.seed,\n });\n\n let K = this._parameters.K_min;\n\n candidates.set(K, {\n kmeans: current_kmeans,\n score: -Infinity,\n });\n\n // Iteratively improve clustering\n while (K < this._parameters.K_max) {\n const clusters = current_kmeans.get_clusters();\n const centroids = current_kmeans.centroids;\n\n // Try splitting each cluster\n /** @type {SplitResult[]} */\n const split_results = [];\n\n for (let j = 0; j < clusters.length; ++j) {\n const cluster = clusters[j];\n\n // Skip small clusters - need enough points for reliable BIC\n if (cluster.length < this._parameters.min_cluster_size) {\n continue;\n }\n\n // Get subset data for this cluster\n /** @type {number[][]} */\n const subset_points = cluster.map((idx) => {\n const row = A.row(idx);\n return Array.from(row);\n });\n\n // Calculate BIC for parent (single cluster)\n const parent_bic = this._bic([cluster], [centroids[j]]);\n\n // Run KMeans with K=2 on subset\n const subset_kmeans = new KMeans(subset_points, {\n K: 2,\n metric: this._parameters.metric,\n seed: this._randomizer.seed,\n });\n\n const child_clusters_local = subset_kmeans.get_clusters();\n const child_centroids = subset_kmeans.centroids;\n\n // Map local indices back to global indices\n /** @type {number[][]} */\n const child_clusters_global = child_clusters_local.map((local_cluster) =>\n local_cluster.map((local_idx) => cluster[local_idx]),\n );\n\n // Calculate BIC for children (split into 2 clusters)\n const children_bic = this._bic(child_clusters_global, child_centroids);\n\n split_results.push({\n index: j,\n bic_parent: parent_bic,\n bic_children: children_bic,\n child_clusters: child_clusters_global,\n child_centroids: child_centroids,\n });\n }\n\n // Keep all splits that improve BIC (BIC_children > BIC_parent)\n /** @type {SplitResult[]} */\n const accepted_splits = split_results.filter((result) => result.bic_children > result.bic_parent);\n\n // If no splits improve BIC, we're done\n if (accepted_splits.length === 0) {\n break;\n }\n\n // Build new centroids array: keep non-split centroids + add split centroids\n /** @type {Float64Array[]} */\n const new_centroids = [];\n const split_indices = new Set();\n\n // Sort accepted splits by improvement (descending)\n accepted_splits.sort((a, b) => b.bic_children - b.bic_parent - (a.bic_children - a.bic_parent));\n\n for (const split of accepted_splits) {\n if (centroids.length + split_indices.size + 1 <= this._parameters.K_max) {\n split_indices.add(split.index);\n } else {\n break;\n }\n }\n\n for (let i = 0; i < centroids.length; ++i) {\n if (split_indices.has(i)) {\n // This cluster was split - add both child centroids\n const split_result = accepted_splits.find((s) => s.index === i);\n if (split_result) {\n new_centroids.push(...split_result.child_centroids);\n }\n } else {\n // This cluster wasn't split - keep its centroid\n new_centroids.push(centroids[i]);\n }\n }\n\n // Run KMeans on full dataset with new centroids as initialization\n // This is crucial - we need to reassign all points to all clusters\n const newK = new_centroids.length;\n\n // Create a new KMeans instance with K set to new number of clusters\n current_kmeans = new KMeans(this._matrix, {\n K: newK,\n metric: this._parameters.metric,\n seed: this._randomizer.seed,\n initial_centroids: new_centroids,\n });\n\n // Store the candidate with the BIC of the FULL dataset\n candidates.set(newK, {\n kmeans: current_kmeans,\n score: this._bic(current_kmeans.get_clusters(), current_kmeans.centroids),\n });\n\n K = newK;\n }\n\n // Select best candidate based on BIC score\n this._best_kmeans = this._select_best_candidate(candidates);\n }\n\n /**\n * Select the best candidate based on BIC score\n *\n * @private\n * @param {Map} candidates\n * @returns {KMeans}\n */\n _select_best_candidate(candidates) {\n if (candidates.size === 0) {\n throw new Error(\"No candidates found\");\n }\n\n const first_candidate = candidates.get(this._parameters.K_min);\n if (!first_candidate) {\n throw new Error(\"Missing initial candidate\");\n }\n\n let best_score = first_candidate.score;\n /** @type {KMeans} */\n let best_kmeans = first_candidate.kmeans;\n\n for (const candidate of candidates.values()) {\n if (candidate.score > best_score) {\n best_score = candidate.score;\n best_kmeans = candidate.kmeans;\n }\n }\n\n return best_kmeans;\n }\n\n /**\n * Calculate Bayesian Information Criterion for a set of clusters.\n *\n * Uses Kass's formula for BIC calculation:\n * BIC(θ) = L(D) - 0.5 * p * ln(N)\n *\n * Where:\n * - L(D) is the log-likelihood of the data\n * - p is the number of free parameters: (K-1) + D*K + 1\n * - N is the total number of points\n *\n * @private\n * @param {number[][]} clusters - Array of clusters with point indices\n * @param {Float64Array[]} centroids - Array of centroids\n * @returns {number} BIC score (higher is better)\n */\n _bic(clusters, centroids) {\n const A = this._matrix;\n const D = this._D;\n const K = centroids.length;\n\n let total_variance = 0;\n let N = 0;\n\n // Calculate total variance (sum of squared distances)\n for (let i = 0; i < K; ++i) {\n const cluster = clusters[i];\n const centroid = centroids[i];\n N += cluster.length;\n\n for (let j = 0; j < cluster.length; ++j) {\n const point_idx = cluster[j];\n const point = A.row(point_idx);\n // Sum of squared distances (variance term)\n total_variance += euclidean_squared(centroid, point);\n }\n }\n\n // Not enough points for meaningful BIC\n if (N <= K) {\n return -Infinity;\n }\n\n // Estimate variance (ML estimate)\n const variance = total_variance / (N - K);\n\n // Handle case of zero variance (all points identical)\n if (variance <= 0) {\n return -Infinity;\n }\n\n // Number of free parameters: (K-1) cluster weights + K*D centroid coordinates + 1 variance\n const p = K - 1 + D * K + 1;\n\n // Calculate log-likelihood\n let log_likelihood = 0;\n const log_2pi = Math.log(2 * Math.PI);\n\n for (let i = 0; i < K; ++i) {\n const n = clusters[i].length;\n if (n <= 1) continue;\n\n // Log-likelihood for cluster i\n const cluster_log_likelihood =\n n * Math.log(n / N) - 0.5 * n * log_2pi - 0.5 * n * D * Math.log(variance) - 0.5 * (n - 1);\n\n log_likelihood += cluster_log_likelihood;\n }\n\n // BIC = log_likelihood - 0.5 * p * ln(N)\n return log_likelihood - 0.5 * p * Math.log(N);\n }\n\n /**\n * Get the computed clusters\n *\n * @returns {number[][]} Array of clusters, each containing indices of points\n */\n get_clusters() {\n if (!this._best_kmeans) {\n throw new Error(\"XMeans has not been run\");\n }\n return this._best_kmeans.get_clusters();\n }\n\n /** @returns {number[]} The cluster list */\n get_cluster_list() {\n if (!this._best_kmeans) {\n throw new Error(\"XMeans has not been run\");\n }\n return this._best_kmeans.get_cluster_list();\n }\n\n /**\n * Get the final centroids\n *\n * @returns {Float64Array[]} Array of centroids\n */\n get centroids() {\n if (!this._best_kmeans) {\n throw new Error(\"XMeans has not been run\");\n }\n return this._best_kmeans.centroids;\n }\n\n /**\n * Get the optimal number of clusters found\n *\n * @returns {number} The number of clusters\n */\n get k() {\n if (!this._best_kmeans) {\n throw new Error(\"XMeans has not been run\");\n }\n return this._best_kmeans.k;\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { Randomizer } from \"../util/index.js\";\n\n/** @import {InputType} from \"../index.js\" */\n\n/**\n * @abstract\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n *\n * Base class for all Dimensionality Reduction (DR) algorithms.\n *\n * Provides a common interface for parameters management, data initialization,\n * and transformation (both synchronous and asynchronous).\n *\n * @class\n */\nexport class DR {\n /** @type {number} */\n _D;\n /** @type {number} */\n _N;\n /** @type {Randomizer} */\n _randomizer;\n /** @type {boolean} */\n _is_initialized;\n\n /**\n * Takes the default parameters and seals them, remembers the type of input `X`, and initializes the random number\n * generator.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Para} default_parameters - Object containing default parameterization of the DR method.\n * @param {Partial} parameters - Object containing parameterization of the DR method to override defaults.\n */\n constructor(X, default_parameters, parameters = {}) {\n /** @type {T} */\n this.__input = X;\n\n /** @type {Para} */\n this._parameters = /** @type {Para} */ Object.seal({\n ...default_parameters,\n ...parameters,\n });\n /** @type {\"array\" | \"matrix\" | \"typed\"} */\n this._type;\n /** @type {Matrix} */\n this.X;\n /** @type {Matrix} */\n this.Y;\n\n if (Array.isArray(X)) {\n if (X[0] instanceof Float64Array) {\n this._type = \"typed\";\n } else {\n this._type = \"array\";\n }\n this.X = Matrix.from(X);\n } else if (X instanceof Matrix) {\n this._type = \"matrix\";\n this.X = X;\n } else {\n throw new Error(\"No valid type for X!\");\n }\n const [N, D] = this.X.shape;\n this._N = N;\n this._D = D;\n this._randomizer = new Randomizer(this._parameters.seed);\n this._is_initialized = false;\n }\n\n /**\n * Get all Parameters.\n * @overload\n * @returns {Para}\n */\n /**\n * Get value of given parameter.\n * @template {keyof Para} K\n * @overload\n * @param {K} name - Name of the parameter.\n * @returns {Para[K]}\n */\n /**\n * Set value of given parameter.\n * @template {keyof Para} K\n * @overload\n * @param {K} name - Name of the parameter.\n * @param {Para[K]} value - Value of the parameter to set.\n * @returns {this}\n */\n /**\n * @param {keyof Para} [name] - Name of the parameter. If null, returns all parameters as an Object.\n * @param {Para[keyof Para]} [value] - Value of the parameter to set. If name is set and value is not given, returns the\n * current value.\n * @returns {Para | Para[keyof Para] | this} On setting a parameter, returns the DR object. If name is set and value is not\n * given, returns the parameter value. If name is null, returns all parameters. On setting a parameter, this\n * function returns the DR object. If `name` is set and `value == null` then return actual parameter value. If\n * `name` is not given, then returns all parameters as an Object.\n * @example\n * ```js\n * const DR = new druid.TSNE(X, {d: 3}); // creates a new DR object, with parameter for `d = 3`.\n * DR.parameter(\"d\"); // returns 3\n * DR.parameter(\"d\", 2); // sets parameter `d` to 2 and returns `DR`.\n * ```\n *\n */\n parameter(name, value) {\n if (name === undefined && value === undefined) {\n return Object.assign({}, this._parameters);\n }\n if (name && !Object.hasOwn(this._parameters, name)) {\n throw new Error(`${String(name)} is not a valid parameter!`);\n }\n if (name && value !== undefined) {\n this._parameters[name] = value;\n this._is_initialized = false;\n return this;\n } else if (name) {\n return this._parameters[name];\n }\n throw new Error(\"Should not happen!\");\n }\n\n /**\n * Computes the projection.\n *\n * @abstract\n * @param {...unknown} args\n * @returns {T} The projection.\n */\n transform(...args) {\n args;\n this.check_init();\n return this.projection;\n }\n\n /**\n * Computes the projection.\n *\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.\n * @returns {T} The dimensionality reduced dataset.\n */\n static transform(X, parameters, ...args) {\n args;\n const dr = new DR(X, parameters, parameters);\n return /** @type {T} */ (dr.transform());\n }\n\n /**\n * Computes the projection.\n *\n * @abstract\n * @param {...unknown} args\n * @returns {Generator} The intermediate steps of the projection.\n */\n *generator(...args) {\n const R = this.transform(...args);\n yield R;\n return R;\n }\n\n /**\n * Computes the projection.\n *\n * @template {{ seed?: number }} Para\n * @param {InputType} X\n * @param {Para} parameters\n * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.\n * @returns {Generator} A generator yielding the intermediate steps of the dimensionality\n * reduction method.\n */\n static *generator(X, parameters, ...args) {\n const dr = new DR(X, parameters, parameters);\n const generator = dr.generator(...args);\n let result;\n do {\n result = generator.next();\n yield result.value;\n } while (!result.done);\n\n return result.value;\n }\n\n /**\n * @abstract\n * @param {...unknown} args\n */\n init(...args) {\n args;\n }\n\n /**\n * If the respective DR method has an `init` function, call it before `transform`.\n *\n * @returns {DR}\n */\n check_init() {\n if (!this._is_initialized && typeof this.init === \"function\") {\n this.init();\n this._is_initialized = true;\n }\n return this;\n }\n\n /** @returns {T} The projection in the type of input `X`. */\n get projection() {\n if (Object.hasOwn(this, \"Y\")) {\n this.check_init();\n //return this._type === \"matrix\" ? this.Y : this.Y.to2dArray();\n if (this._type === \"matrix\") {\n return /** @type {T} */ (/** @type {any} */ (this.Y));\n } else if (this._type === \"typed\") {\n return /** @type {T} */ (/** @type {any} */ (this.Y.to2dArray()));\n } else {\n return /** @type {T} */ (/** @type {any} */ (this.Y.asArray()));\n }\n } else {\n throw new Error(\"The dataset is not transformed yet!\");\n }\n }\n\n /**\n * Computes the projection.\n *\n * @param {...unknown} args - Arguments the transform method of the respective DR method takes.\n * @returns {Promise} The dimensionality reduced dataset.\n */\n async transform_async(...args) {\n return this.transform(...args);\n }\n\n /**\n * Computes the projection.\n *\n * @template {{ seed?: number }} Para\n * @param {InputType} X\n * @param {Para} parameters\n * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.\n * @returns {Promise} A promise yielding the dimensionality reduced dataset.\n */\n static async transform_async(X, parameters, ...args) {\n return DR.transform(X, parameters, ...args);\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersFASTMAP } from \"./index.js\"; */\n\n/**\n * FastMap algorithm for dimensionality reduction.\n *\n * A very fast algorithm for projecting high-dimensional data into a lower-dimensional\n * space while preserving pairwise distances. It works similarly to PCA but uses\n * only a subset of the data to find projection axes.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class FASTMAP extends DR {\n /**\n * FastMap: a fast algorithm for indexing, data-mining and visualization of traditional and multimedia datasets.\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://doi.org/10.1145/223784.223812}\n */\n constructor(X, parameters) {\n super(X, { d: 2, metric: euclidean, seed: 1212 }, parameters);\n }\n\n /**\n * Chooses two points which are the most distant in the actual projection.\n *\n * @private\n * @param {(a: number, b: number) => number} dist\n * @returns {[number, number, number]} An array consisting of first index, second index, and distance between the\n * two points.\n */\n _choose_distant_objects(dist) {\n const X = this.X;\n const N = X.shape[0];\n let a_index = this._randomizer.random_int % N;\n /** @type {number | null} */\n let b_index = null;\n let max_dist = -Infinity;\n for (let i = 0; i < N; ++i) {\n const d_ai = dist(a_index, i);\n if (d_ai > max_dist) {\n max_dist = d_ai;\n b_index = i;\n }\n }\n if (b_index === null) throw new Error(\"should not happen!\");\n max_dist = -Infinity;\n for (let i = 0; i < N; ++i) {\n const d_bi = dist(b_index, i);\n if (d_bi > max_dist) {\n max_dist = d_bi;\n a_index = i;\n }\n }\n return [a_index, b_index, max_dist];\n }\n\n /**\n * Computes the projection.\n *\n * @returns {T} The `d`-dimensional projection of the data matrix `X`.\n */\n transform() {\n const X = this.X;\n const N = X.shape[0];\n const d = /** @type {number} */ (this._parameters.d);\n const metric = /** @type {typeof euclidean} */ (this._parameters.metric);\n const Y = new Matrix(N, d, 0);\n /** @type {(a: number, b: number) => number} */\n let dist = (a, b) => metric(X.row(a), X.row(b));\n\n for (let _col = 0; _col < d; ++_col) {\n const old_dist = dist;\n // choose pivot objects\n const [a_index, b_index, d_ab] = this._choose_distant_objects(dist);\n if (d_ab !== 0) {\n // project the objects on the line (O_a, O_b)\n for (let i = 0; i < N; ++i) {\n const d_ai = dist(a_index, i);\n const d_bi = dist(b_index, i);\n const y_i = (d_ai ** 2 + d_ab ** 2 - d_bi ** 2) / (2 * d_ab);\n Y.set_entry(i, _col, y_i);\n }\n // consider the projections of the objects on a\n // hyperplane perpendicluar to the line (a, b);\n // the distance function D'() between two\n // projections is given by Eq.4\n dist = (a, b) => Math.sqrt(old_dist(a, b) ** 2 - (Y.entry(a, _col) - Y.entry(b, _col)) ** 2);\n }\n }\n // return embedding.\n this.Y = Y;\n return this.projection;\n }\n\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new FASTMAP(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new FASTMAP(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new FASTMAP(X, parameters);\n return dr.transform_async();\n }\n}\n","/**\n * Base class for all K-Nearest Neighbors (KNN) search algorithms.\n *\n * Provides a common interface for elements management and search operations.\n *\n * @abstract\n * @category KNN\n * @template {number[] | Float64Array} T - Type of elements\n * @template {Object} Para - Type of parameters\n * @class\n */\nexport class KNN {\n /** @type {T[]} */\n _elements;\n /** @type {Para} */\n _parameters;\n /** @type {\"typed\" | \"array\"} */\n _type;\n\n /**\n * @param {T[]} elements\n * @param {Para} parameters\n */\n constructor(elements, parameters) {\n if (elements.length === 0) throw new Error(\"Elements needs to contain at least one element!\");\n if (elements[0] instanceof Float64Array) {\n this._type = \"typed\";\n } else {\n this._type = \"array\";\n }\n this._parameters = parameters;\n this._elements = elements;\n }\n\n /**\n * @abstract\n * @param {T} t\n * @param {number} k\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search(t, k) {\n t;\n k;\n throw new Error(\"The function search must be implemented!\");\n }\n\n /**\n * @abstract\n * @param {number} i\n * @param {number} k\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i, k) {\n i;\n k;\n throw new Error(\"The function search_by_index must be implemented!\");\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersAnnoy } from \"./index.js\" */\n\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} AnnoyNode\n * @property {boolean} isLeaf - Whether this is a leaf node\n * @property {number[]} indices - Indices of points in this node (leaf) or children (internal)\n * @property {number[]} normal - Hyperplane normal vector (internal nodes only)\n * @property {number} offset - Hyperplane offset (internal nodes only)\n * @property {AnnoyNode | null} left - Left child (internal nodes only)\n * @property {AnnoyNode | null} right - Right child (internal nodes only)\n */\n\n/**\n * Annoy-style (Approximate Nearest Neighbors Oh Yeah) implementation using Random Projection Trees.\n *\n * This implementation builds multiple random projection trees where each tree randomly selects\n * two points and splits the space based on a hyperplane equidistant between them.\n *\n * Key features:\n * - Multiple random projection trees for better recall\n * - Each tree uses random hyperplanes for splitting\n * - Priority queue search for better recall\n * - Combines results from all trees\n *\n * Best suited for:\n * - High-dimensional data\n * - Approximate nearest neighbor search\n * - Large datasets\n * - When high recall is needed with approximate methods\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link https://github.com/spotify/annoy}\n * @see {@link https://erikbern.com/2015/09/24/nearest-neighbors-and-vector-models-epilogue-curse-of-dimensionality.html}\n */\nexport class Annoy extends KNN {\n /**\n * Creates a new Annoy-style index with random projection trees.\n *\n * @param {T[]} elements - Elements to index\n * @param {ParametersAnnoy} [parameters={}] - Configuration parameters\n */\n constructor(\n elements,\n parameters = {\n metric: euclidean,\n numTrees: 10,\n maxPointsPerLeaf: 10,\n seed: 1212,\n },\n ) {\n // Handle empty initialization - use dummy element\n const hasElements = elements && elements.length > 0;\n const firstElement = /** @type {T} */ (hasElements ? elements[0] : new Float64Array([0]));\n\n super([firstElement], parameters);\n\n this._metric = this._parameters.metric ?? euclidean;\n this._numTrees = this._parameters.numTrees ?? 10;\n this._maxPointsPerLeaf = this._parameters.maxPointsPerLeaf ?? 10;\n this._seed = this._parameters.seed ?? 1212;\n this._randomizer = new Randomizer(this._seed);\n\n /**\n * @private\n * @type {AnnoyNode[]}\n */\n this._trees = [];\n\n // Build trees\n if (hasElements) {\n // Reset elements and rebuild properly\n /** @type {T[]} */\n this._elements = [];\n this._trees = [];\n this.add(elements);\n }\n }\n\n /**\n * Get the number of trees in the index.\n * @returns {number}\n */\n get num_trees() {\n return this._trees.length;\n }\n\n /**\n * Get the total number of nodes in all trees.\n * @returns {number}\n */\n get num_nodes() {\n let total = 0;\n for (const tree of this._trees) {\n total += this._countNodes(tree);\n }\n return total;\n }\n\n /**\n * @private\n * @param {any} node\n * @returns {number}\n */\n _countNodes(node) {\n if (!node) return 0;\n return 1 + this._countNodes(node.left) + this._countNodes(node.right);\n }\n\n /**\n * Add elements to the Annoy index.\n * @param {T[]} elements\n * @returns {this}\n */\n add(elements) {\n // Extend elements array\n this._elements = this._elements.concat(elements);\n\n // Rebuild all trees with new elements\n this._trees = [];\n this._buildTrees();\n\n return this;\n }\n\n /**\n * Build all random projection trees.\n * @private\n */\n _buildTrees() {\n const elements = this._elements;\n const n = elements.length;\n\n for (let t = 0; t < this._numTrees; t++) {\n // Create index array for this tree\n const indices = Array.from({ length: n }, (_, i) => i);\n const tree = this._buildTreeRecursive(indices);\n this._trees.push(tree);\n }\n }\n\n /**\n * Recursively build a random projection tree.\n * @private\n * @param {number[]} indices - Indices of elements to include\n * @returns {AnnoyNode}\n */\n _buildTreeRecursive(indices) {\n const elements = this._elements;\n\n // Base case: small enough to be a leaf\n if (indices.length <= this._maxPointsPerLeaf) {\n return {\n isLeaf: true,\n indices: indices,\n normal: [],\n offset: 0,\n left: null,\n right: null,\n };\n }\n\n // Select two random points to define the splitting hyperplane\n const idx1 = indices[Math.floor(this._randomizer.random * indices.length)];\n const idx2 = indices[Math.floor(this._randomizer.random * indices.length)];\n\n const point1 = elements[idx1];\n const point2 = elements[idx2];\n\n // Compute normal vector (point2 - point1)\n const dim = point1.length;\n /** @type {number[]} */\n const normal = new Array(dim);\n for (let i = 0; i < dim; i++) {\n normal[i] = point2[i] - point1[i];\n }\n\n // Normalize\n let norm = 0;\n for (let i = 0; i < dim; i++) {\n norm += normal[i] * normal[i];\n }\n norm = Math.sqrt(norm);\n\n if (norm > 1e-10) {\n for (let i = 0; i < dim; i++) {\n normal[i] /= norm;\n }\n }\n\n // Compute midpoint and offset\n /** @type {number[]} */\n const midpoint = new Array(dim);\n for (let i = 0; i < dim; i++) {\n midpoint[i] = (point1[i] + point2[i]) / 2;\n }\n\n // Compute offset: dot(normal, midpoint)\n let offset = 0;\n for (let i = 0; i < dim; i++) {\n offset += normal[i] * midpoint[i];\n }\n\n // Split points based on which side of hyperplane they fall\n const leftIndices = [];\n const rightIndices = [];\n\n for (const idx of indices) {\n const point = elements[idx];\n let dot = 0;\n for (let i = 0; i < dim; i++) {\n dot += normal[i] * point[i];\n }\n\n if (dot < offset) {\n leftIndices.push(idx);\n } else {\n rightIndices.push(idx);\n }\n }\n\n // Handle edge case where all points fall on one side\n if (leftIndices.length === 0 || rightIndices.length === 0) {\n return {\n isLeaf: true,\n indices: indices,\n normal: [],\n offset: 0,\n left: null,\n right: null,\n };\n }\n\n // Recursively build subtrees\n const left = this._buildTreeRecursive(leftIndices);\n const right = this._buildTreeRecursive(rightIndices);\n\n return {\n isLeaf: false,\n indices: [],\n normal: normal,\n offset: offset,\n left: left,\n right: right,\n };\n }\n\n /**\n * Compute distance from point to hyperplane.\n * @private\n * @param {T} point\n * @param {number[]} normal\n * @param {number} offset\n * @returns {number} Signed distance (positive = right side, negative = left side)\n */\n _distanceToHyperplane(point, normal, offset) {\n let dot = 0;\n for (let i = 0; i < point.length; i++) {\n dot += normal[i] * point[i];\n }\n return dot - offset;\n }\n\n /**\n * Search for k approximate nearest neighbors.\n * @param {T} query\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search(query, k = 5) {\n const metric = this._metric;\n const elements = this._elements;\n\n if (elements.length === 0) return [];\n\n // Collect candidates from all trees using priority queue\n const candidates = new Set();\n\n // Collect more candidates for better recall\n // Search at least k * numTrees * 2 candidates\n const minCandidates = Math.min(k * this._numTrees * 3, elements.length);\n\n for (const tree of this._trees) {\n this._searchTreePriority(tree, query, candidates, minCandidates);\n }\n\n // Compute exact distances for all candidates\n /** @type {Heap<{ index: number; distance: number }>} */\n const best = new Heap(null, (d) => d.distance, \"max\");\n\n for (const idx of candidates) {\n const element = elements[idx];\n if (!element || element.length !== query.length) continue;\n\n const dist = metric(query, element);\n\n if (best.length < k) {\n best.push({ index: idx, distance: dist });\n } else if (dist < (best.first?.value ?? Infinity)) {\n best.pop();\n best.push({ index: idx, distance: dist });\n }\n }\n\n // If we still don't have enough candidates, do a linear scan fallback\n if (best.length < k) {\n for (let i = 0; i < elements.length && best.length < k; i++) {\n if (candidates.has(i)) continue;\n\n const element = elements[i];\n if (!element || element.length !== query.length) continue;\n\n const dist = metric(query, element);\n best.push({ index: i, distance: dist });\n }\n }\n\n // Convert to result format\n /** @type {{ element: T; index: number; distance: number }[]} */\n const result = [];\n while (best.length > 0) {\n const item = /** @type {{ element: { index: number; distance: number }; value: number }} */ (best.pop());\n result.push({\n element: elements[item.element.index],\n index: item.element.index,\n distance: item.value,\n });\n }\n\n return result.reverse();\n }\n\n /**\n * Search tree using priority queue for better recall.\n * Explores nodes in order of distance to hyperplane.\n * @private\n * @param {AnnoyNode} node\n * @param {T} query\n * @param {Set} candidates\n * @param {number} maxCandidates\n */\n _searchTreePriority(node, query, candidates, maxCandidates) {\n if (!node) return;\n\n // Priority queue entry: { node, distance }\n /** @type {Heap<{ node: AnnoyNode; dist: number }>} */\n const pq = new Heap(null, (d) => d.dist, \"min\");\n pq.push({ node: node, dist: 0 });\n\n while (!pq.empty && candidates.size < maxCandidates) {\n const entry = pq.pop();\n if (!entry) continue;\n\n const currentNode = entry.element.node;\n\n // Leaf node: add all points\n if (currentNode.isLeaf) {\n for (const idx of currentNode.indices) {\n candidates.add(idx);\n if (candidates.size >= maxCandidates) return;\n }\n continue;\n }\n\n // Internal node: compute distance to hyperplane\n const dist = this._distanceToHyperplane(query, currentNode.normal, currentNode.offset);\n\n // Determine which side is closer\n const closerSide = dist < 0 ? currentNode.left : currentNode.right;\n const fartherSide = dist < 0 ? currentNode.right : currentNode.left;\n\n // Add closer side with priority 0 (explore first)\n if (closerSide) {\n pq.push({ node: closerSide, dist: 0 });\n }\n\n // Add farther side with priority = |dist| (explore later if needed)\n if (fartherSide && candidates.size < maxCandidates) {\n pq.push({ node: fartherSide, dist: Math.abs(dist) });\n }\n }\n }\n\n /**\n * @param {number} i\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i, k = 5) {\n if (i < 0 || i >= this._elements.length) return [];\n return this.search(this._elements[i], k);\n }\n\n /**\n * Alias for search_by_index for backward compatibility.\n *\n * @param {number} i - Index of the query element\n * @param {number} [k=5] - Number of nearest neighbors to return\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_index(i, k = 5) {\n return this.search_by_index(i, k);\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersBallTree } from \"./index.js\" */\n\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} ElementWithIndex\n * @property {number} index\n * @property {T} element\n */\n\n/**\n * Ball Tree for efficient nearest neighbor search.\n *\n * A Ball Tree is a metric tree that partitions points into a nested set of\n * hyperspheres (balls). It is particularly effective for high-dimensional\n * data and supports any valid metric.\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n */\nexport class BallTree extends KNN {\n /**\n * Generates a BallTree with given `elements`.\n *\n * @param {T[]} elements - Elements which should be added to the BallTree\n * @param {ParametersBallTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}`\n * @see {@link https://en.wikipedia.org/wiki/Ball_tree}\n * @see {@link https://github.com/invisal/noobjs/blob/master/src/tree/BallTree.js}\n */\n constructor(elements, parameters = { metric: euclidean, seed: 1212 }) {\n super(elements, Object.assign({ seed: 1212 }, parameters));\n /**\n * @private\n * @type {BallTreeNode | BallTreeLeaf}\n */\n this._root = this._construct(elements.map((element, index) => ({ index, element })));\n }\n\n /** @returns {Metric} */\n get _metric() {\n return this._parameters.metric;\n }\n\n /**\n * @private\n * @param {ElementWithIndex[]} elements\n * @returns {BallTreeNode | BallTreeLeaf} Root of balltree.\n */\n _construct(elements) {\n if (elements.length === 1) {\n return new BallTreeLeaf(elements);\n } else {\n const c = this._greatest_spread(elements);\n const sorted_elements = elements.sort((a, b) => a.element[c] - b.element[c]);\n const n = sorted_elements.length;\n const p_index = Math.floor(n / 2);\n const p = sorted_elements[p_index];\n const L = sorted_elements.slice(0, p_index);\n const R = sorted_elements.slice(p_index, n);\n const radius = Math.max(...elements.map((d) => this._metric(p.element, d.element)));\n let B;\n if (L.length > 0 && R.length > 0) {\n B = new BallTreeNode(p, this._construct(L), this._construct(R), radius);\n } else {\n B = new BallTreeLeaf(elements);\n }\n return B;\n }\n }\n\n /**\n * @private\n * @param {ElementWithIndex[]} B\n * @returns {number}\n */\n _greatest_spread(B) {\n const d = B[0].element.length;\n const start = new Array(d);\n\n for (let i = 0; i < d; ++i) {\n start[i] = [Infinity, -Infinity];\n }\n\n let spread = B.reduce((acc, current) => {\n for (let i = 0; i < d; ++i) {\n acc[i][0] = Math.min(acc[i][0], current.element[i]);\n acc[i][1] = Math.max(acc[i][1], current.element[i]);\n }\n return acc;\n }, start);\n spread = spread.map((d) => d[1] - d[0]);\n\n let c = 0;\n for (let i = 0; i < d; ++i) {\n c = spread[i] > spread[c] ? i : c;\n }\n return c;\n }\n\n /**\n * @param {number} i\n * @param {number} k\n */\n search_by_index(i, k = 5) {\n return this.search(this._elements[i], k);\n }\n\n /**\n * @param {T} t - Query element.\n * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors.\n */\n search(t, k = 5) {\n /** @type {Heap>} */\n const heap = new Heap(null, (d) => this._metric(d.element, t), \"max\");\n this._search(t, k, heap, this._root);\n\n // Convert heap to result array\n /** @type {{ element: T; index: number; distance: number }[]} */\n const result = [];\n while (heap.length > 0) {\n const item = /** @type {{ element: ElementWithIndex; value: number }} */ (heap.pop());\n result.push({\n element: item.element.element,\n index: item.element.index,\n distance: item.value,\n });\n }\n return result.reverse(); // Reverse to get closest first\n }\n\n /**\n * @private\n * @param {T} t - Query element.\n * @param {number} k - Number of nearest neighbors to return.\n * @param {Heap>} Q - Heap consists of the currently found `k` nearest neighbors.\n * @param {BallTreeNode | BallTreeLeaf} B\n */\n _search(t, k, Q, B) {\n if (!B) return;\n\n if (B instanceof BallTreeNode) {\n const dist_to_pivot = this._metric(t, B.pivot.element);\n if (Q.length >= k && dist_to_pivot - B.radius >= (Q.first?.value ?? -Infinity)) {\n return;\n }\n\n const c1 = B.child1;\n const c2 = B.child2;\n\n let d1 = Infinity;\n let d2 = Infinity;\n\n if (c1 instanceof BallTreeNode) d1 = this._metric(t, c1.pivot.element);\n else if (c1 instanceof BallTreeLeaf) d1 = this._metric(t, c1.points[0].element);\n\n if (c2 instanceof BallTreeNode) d2 = this._metric(t, c2.pivot.element);\n else if (c2 instanceof BallTreeLeaf) d2 = this._metric(t, c2.points[0].element);\n\n if (d1 < d2) {\n if (c1) this._search(t, k, Q, c1);\n if (c2) this._search(t, k, Q, c2);\n } else {\n if (c2) this._search(t, k, Q, c2);\n if (c1) this._search(t, k, Q, c1);\n }\n } else if (B instanceof BallTreeLeaf) {\n for (let i = 0, n = B.points.length; i < n; ++i) {\n const p = B.points[i];\n const dist = this._metric(p.element, t);\n if (Q.length < k) {\n Q.push(p);\n } else if (dist < (Q.first?.value ?? Infinity)) {\n Q.pop();\n Q.push(p);\n }\n }\n }\n }\n}\n\n/**\n * @private\n * @template {number[] | Float64Array} T\n */\nclass BallTreeNode {\n /**\n * @param {ElementWithIndex} pivot\n * @param {BallTreeNode | BallTreeLeaf | null} child1\n * @param {BallTreeNode | BallTreeLeaf | null} child2\n * @param {number} radius\n */\n constructor(pivot, child1 = null, child2 = null, radius = 0) {\n this.pivot = pivot;\n this.child1 = child1;\n this.child2 = child2;\n this.radius = radius;\n }\n}\n\n/**\n * @private\n * @template {number[] | Float64Array} T\n */\nclass BallTreeLeaf {\n /** @param {ElementWithIndex[]} points */\n constructor(points) {\n this.points = points;\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersHNSW } from \"./index.js\" */\n\n/**\n * @typedef {Object} Layer\n * @property {number} l_c - Layer number\n * @property {number[]} point_indices - Global indices of points in this layer\n * @property {Map} edges - Global index -> array of connected global indices\n */\n\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} Candidate\n * @property {T} element - The actual data point\n * @property {number} index - Global index in the dataset\n * @property {number} distance - Distance from query\n */\n\n/**\n * Hierarchical Navigable Small World (HNSW) graph for approximate nearest neighbor search.\n *\n * HNSW builds a multi-layer graph structure where each layer is a navigable small world graph.\n * The top layers serve as \"highways\" for fast traversal, while lower layers provide accuracy.\n * Each element is assigned to a random level, allowing logarithmic search complexity.\n *\n * Key parameters:\n * - `m`: Controls the number of connections per element (affects accuracy/memory)\n * - `ef_construction`: Controls the quality of the graph during construction (higher = better but slower)\n * - `ef`: Controls the quality of search (higher = better recall but slower)\n *\n * Based on:\n * - \"Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs\"\n * by Malkov & Yashunin (2016)\n * - \"Approximate Nearest Neighbor Search on High Dimensional Data\"\n * by Li et al. (2019)\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const points = [[1, 2], [3, 4], [5, 6], [7, 8]];\n * const hnsw = new druid.HNSW(points, {\n * metric: druid.euclidean,\n * m: 16,\n * ef_construction: 200\n * });\n *\n * const query = [2, 3];\n * const neighbors = hnsw.search(query, 2);\n * // [{ element: [1, 2], index: 0, distance: 1.41 }, ...]\n */\nexport class HNSW extends KNN {\n /**\n * Creates a new HNSW index.\n *\n * @param {T[]} points - Initial points to add to the index\n * @param {ParametersHNSW} [parameters={}] - Configuration parameters\n */\n constructor(\n points,\n parameters = {\n metric: euclidean,\n heuristic: true,\n m: 16,\n ef_construction: 200,\n m0: null,\n mL: null,\n seed: 1212,\n ef: 50,\n },\n ) {\n // Handle empty initialization - use dummy element\n const hasElements = points && points.length > 0;\n let firstElement = /** @type {T} */ (hasElements ? points[0] : new Float64Array([0]));\n\n // Validate all points have consistent dimensions\n if (hasElements) {\n const expected_dim = firstElement.length;\n for (let i = 1; i < points.length; i++) {\n if (!points[i] || points[i].length !== expected_dim) {\n console.warn(\n `HNSW: Point ${i} has inconsistent dimensions (expected ${expected_dim}, got ${points[i]?.length})`,\n );\n // Remove invalid points\n points = points.filter((_, idx) => idx === 0 || points[idx]?.length === expected_dim);\n firstElement = points[0];\n }\n }\n }\n\n super([firstElement], parameters);\n\n // Store reference to elements before clearing\n const elementsToAdd = hasElements ? [...points] : [];\n /** @type {T[]} */\n this._elements = [];\n\n /** @type {Metric} */\n this._metric = this._parameters.metric || euclidean;\n\n /** @type {Function} */\n this._select = this._parameters.heuristic ? this._select_heuristic.bind(this) : this._select_simple.bind(this);\n\n /**\n * @private\n * @type {Map}\n */\n this._graph = new Map();\n\n /** @type {number} */\n this._next_index = 0;\n\n // Validate and set parameters\n const m_param = this._parameters.m ?? 16;\n if (m_param <= 0 || !Number.isInteger(m_param)) {\n throw new Error(\"HNSW: parameter 'm' must be a positive integer\");\n }\n /** @type {number} */\n this._m = Math.max(2, m_param);\n\n const ef_construction_param = this._parameters.ef_construction ?? 200;\n if (ef_construction_param <= 0 || !Number.isInteger(ef_construction_param)) {\n throw new Error(\"HNSW: parameter 'ef_construction' must be a positive integer\");\n }\n /** @type {number} */\n this._ef_construction = ef_construction_param;\n\n const ef_param = this._parameters.ef ?? 50;\n if (ef_param <= 0 || !Number.isInteger(ef_param)) {\n throw new Error(\"HNSW: parameter 'ef' must be a positive integer\");\n }\n /** @type {number} */\n this._ef = ef_param;\n\n const m0_param = this._parameters.m0 ?? 2 * this._m;\n if (m0_param <= 0 || !Number.isInteger(m0_param)) {\n throw new Error(\"HNSW: parameter 'm0' must be a positive integer\");\n }\n /** @type {number} */\n this._m0 = m0_param;\n\n /** @type {number} */\n this._mL = this._parameters.mL ?? 1 / Math.log(this._m);\n\n /** @type {Randomizer} */\n this._randomizer = new Randomizer(this._parameters.seed);\n\n /** @type {number} - Current maximum layer in the graph */\n this._L = -1;\n\n /** @type {number[] | null} - Entry point indices for search */\n this._ep = null;\n\n // Add initial points\n if (elementsToAdd && elementsToAdd.length > 0) {\n this.add(elementsToAdd);\n }\n }\n\n /**\n * Add a single element to the index.\n *\n * @param {T} element - Element to add\n * @returns {HNSW} This instance for chaining\n */\n addOne(element) {\n return this.add([element]);\n }\n\n /**\n * Add multiple elements to the index.\n *\n * @param {T[]} new_elements - Elements to add\n * @returns {HNSW} This instance for chaining\n */\n add(new_elements) {\n // Handle empty array\n if (!new_elements || new_elements.length === 0) {\n return this;\n }\n\n const m = this._m;\n const ef_construction = this._ef_construction;\n const m0 = this._m0;\n const mL = this._mL;\n const randomizer = this._randomizer;\n const graph = this._graph;\n\n // Ensure _elements is a proper array that supports push\n if (!Array.isArray(this._elements)) {\n this._elements = Array.from(this._elements);\n }\n const elements = this._elements;\n\n // Get expected dimension from first existing element or first new element\n const expected_dim = elements.length > 0 ? elements[0].length : new_elements[0]?.length;\n\n for (const element of new_elements) {\n // Validate element\n if (!element || (!Array.isArray(element) && !(element instanceof Float64Array))) {\n console.warn(\"HNSW: Skipping invalid element (null, undefined, or not an array)\");\n continue;\n }\n\n // Validate dimensions\n if (element.length !== expected_dim) {\n console.warn(\n `HNSW: Skipping element with wrong dimensions (expected ${expected_dim}, got ${element.length})`,\n );\n continue;\n }\n\n elements.push(element);\n const global_index = elements.length - 1;\n\n // Assign random level to the element\n // Level is drawn from exponential distribution: l = floor(-ln(uniform(0,1)) * mL)\n const rand = Math.max(randomizer.random, 1e-10); // Avoid log(0)\n const l = Math.min(31, Math.floor(-Math.log(rand) * mL));\n\n let ep_indices = this._ep ? [...this._ep] : null;\n const L = this._L;\n\n if (L >= 0) {\n // Search from top layer down to min(L, l) + 1\n // These are the layers where element will NOT be inserted\n for (let l_c = L; l_c > l; --l_c) {\n const search_result = this._search_layer(element, ep_indices, 1, l_c);\n if (search_result.length > 0) {\n ep_indices = [search_result[0].index];\n }\n }\n\n // Insert element into layers l down to 0\n for (let l_c = Math.min(L, l); l_c >= 0; --l_c) {\n const layer = graph.get(l_c);\n if (!layer) continue;\n\n layer.point_indices.push(global_index);\n\n // Search for ef_construction nearest neighbors\n let W = this._search_layer(element, ep_indices, ef_construction, l_c);\n\n // If graph search returns no results (e.g., graph is empty or disconnected),\n // fall back to linear search over all existing elements\n if (W.length === 0 && elements.length > 1) {\n const fallbackCandidates = [];\n for (let i = 0; i < elements.length - 1; i++) {\n const elem = elements[i];\n if (elem && elem.length === element.length) {\n fallbackCandidates.push({\n element: elem,\n index: i,\n distance: this._metric(element, elem),\n });\n }\n }\n fallbackCandidates.sort((a, b) => a.distance - b.distance);\n W = fallbackCandidates.slice(0, ef_construction);\n // Update ep_indices for next layer based on fallback results\n if (l_c === Math.min(L, l)) {\n ep_indices = W.map((c) => c.index);\n }\n }\n\n // Select neighbors using heuristic or simple approach (respect heuristic setting on all layers)\n const neighbor_indices = this._select(element, W, l_c === 0 ? m0 : m, l_c);\n\n // Add bidirectional connections\n for (const neighbor_idx of neighbor_indices) {\n if (neighbor_idx === global_index) continue;\n\n // Add connection from element to neighbor\n if (!layer.edges.has(global_index)) {\n layer.edges.set(global_index, []);\n }\n layer.edges.get(global_index)?.push(neighbor_idx);\n\n // Add connection from neighbor to element\n if (!layer.edges.has(neighbor_idx)) {\n layer.edges.set(neighbor_idx, []);\n }\n const neighbor_edge_list = layer.edges.get(neighbor_idx);\n if (neighbor_edge_list && !neighbor_edge_list.includes(global_index)) {\n neighbor_edge_list.push(global_index);\n }\n\n // Prune connections if too many\n const max_conn = l_c === 0 ? m0 : m;\n const neighbor_edges = layer.edges.get(neighbor_idx);\n if (neighbor_edges && neighbor_edges.length > max_conn) {\n const neighbor_element = elements[neighbor_idx];\n // Filter out self-connections before pruning\n const valid_neighbor_edges = neighbor_edges.filter((idx) => idx !== neighbor_idx);\n const neighbor_candidates = valid_neighbor_edges.map((idx) => ({\n element: elements[idx],\n index: idx,\n distance: this._metric(neighbor_element, elements[idx]),\n }));\n const pruned =\n l_c === 0\n ? this._select_simple(neighbor_element, neighbor_candidates, max_conn)\n : this._select(neighbor_element, neighbor_candidates, max_conn, l_c);\n layer.edges.set(neighbor_idx, pruned);\n }\n }\n\n // Use closest neighbor as entry point for next layer (following HNSW paper)\n if (W.length > 0) {\n ep_indices = [W[0].index];\n }\n }\n }\n\n // If element's level is higher than current max, create new layers\n if (l > L) {\n for (let i = L + 1; i <= l; ++i) {\n graph.set(i, {\n l_c: i,\n point_indices: [global_index],\n edges: new Map(),\n });\n }\n // Element becomes the new entry point\n this._ep = [global_index];\n this._L = l;\n }\n\n // Special case: if this is the first element (L was -1),\n // we need to ensure layer 0 has proper structure for future insertions\n if (L === -1) {\n if (!graph.has(0)) {\n graph.set(0, {\n l_c: 0,\n point_indices: [global_index],\n edges: new Map(),\n });\n }\n const layer0 = graph.get(0);\n if (layer0 && !layer0.edges.has(global_index)) {\n layer0.edges.set(global_index, []);\n }\n }\n }\n\n return this;\n }\n\n /**\n * Select neighbors using the heuristic approach.\n *\n * The heuristic extends candidates with their neighbors and selects\n * points that are closer to the query than to already selected points.\n * This maintains graph connectivity better than simple selection.\n *\n * @private\n * @param {T} q - Query element\n * @param {Candidate[]} candidates - Candidate elements with distances\n * @param {number} M - Maximum number of neighbors to return\n * @param {number} l_c - Layer number\n * @param {boolean} [extend_candidates=true] - Whether to extend candidates with their neighbors\n * @param {boolean} [keep_pruned_connections=true] - Whether to add pruned connections back if needed\n * @returns {number[]} Selected neighbor indices\n */\n _select_heuristic(q, candidates, M, l_c, extend_candidates = true, keep_pruned_connections = true) {\n if (l_c > this._L) {\n return candidates.map((c) => c.index);\n }\n\n const metric = this._metric;\n const layer = this._graph.get(l_c);\n const elements = this._elements;\n\n // Extend candidate set with neighbors of candidates\n const W_set = new Set(candidates.map((c) => c.index));\n if (extend_candidates) {\n for (const c of candidates) {\n const edges = layer?.edges.get(c.index);\n if (edges) {\n for (const neighbor_idx of edges) {\n W_set.add(neighbor_idx);\n }\n }\n }\n }\n\n // Create extended candidates with distances\n const W = [...W_set]\n .map((idx) => ({\n element: elements[idx],\n index: idx,\n distance: metric(elements[idx], q),\n }))\n .sort((a, b) => a.distance - b.distance);\n\n const R = [];\n const W_discarded = [];\n\n // Select neighbors: prefer points closer to query than to already selected points\n for (const e of W) {\n if (R.length >= M) break;\n\n let should_add = true;\n\n // Check if e is closer to query than to any already selected point\n for (const r of R) {\n const dist_er = metric(e.element, r.element);\n if (dist_er < e.distance) {\n should_add = false;\n break;\n }\n }\n\n if (should_add) {\n R.push(e);\n } else {\n W_discarded.push(e);\n }\n }\n\n // Add discarded connections if we need more\n if (keep_pruned_connections && R.length < M) {\n for (const e of W_discarded) {\n if (R.length >= M) break;\n R.push(e);\n }\n }\n\n return R.map((c) => c.index);\n }\n\n /**\n * Select neighbors using simple distance-based selection.\n *\n * Simply returns the M closest candidates to the query.\n *\n * @private\n * @param {T} q - Query element\n * @param {Candidate[]} C - Candidate elements with distances\n * @param {number} M - Maximum number of neighbors to return\n * @returns {number[]} M nearest candidate indices\n */\n _select_simple(q, C, M) {\n if (C.length <= M) return C.map((c) => c.index);\n\n // Candidates already have distance computed, use it directly\n return C.slice()\n .sort((a, b) => a.distance - b.distance)\n .slice(0, M)\n .map((c) => c.index);\n }\n\n /**\n * Search a single layer for nearest neighbors.\n *\n * Implements the greedy search algorithm: start from entry points,\n * always expand the closest unvisited candidate, maintain a list\n * of the ef closest found neighbors.\n *\n * @private\n * @param {T} q - Query element\n * @param {number[] | null} ep_indices - Entry point indices\n * @param {number} ef - Number of nearest neighbors to find\n * @param {number} l_c - Layer number to search\n * @returns {Candidate[]} ef nearest neighbors found with their distances\n */\n _search_layer(q, ep_indices, ef, l_c) {\n const metric = this._metric;\n const layer = this._graph.get(l_c);\n const elements = this._elements;\n\n if (!layer || layer.edges.size === 0 || !ep_indices || ep_indices.length === 0) {\n return [];\n }\n\n // Filter out invalid indices\n const valid_ep_indices = ep_indices.filter((idx) => elements[idx] !== undefined);\n if (valid_ep_indices.length === 0) {\n return [];\n }\n\n // Visited set to avoid cycles\n const visited = new Set(valid_ep_indices);\n\n // Candidate set (min-heap): closest unvisited candidates to expand\n const C = new Heap(\n valid_ep_indices.map((idx) => ({\n element: elements[idx],\n index: idx,\n distance: metric(elements[idx], q),\n })),\n (item) => item.distance,\n \"min\",\n );\n\n // Result set (max-heap): ef closest found neighbors\n const W = new Heap(\n valid_ep_indices.map((idx) => ({\n element: elements[idx],\n index: idx,\n distance: metric(elements[idx], q),\n })),\n (item) => item.distance,\n \"max\",\n );\n\n // Algorithm 2 stops when the distance from query to the next candidate is greater\n // than the distance to the furthest element in the result set W.\n while (!C.empty) {\n const c = C.pop();\n if (!c) break;\n const furthest_dist = W.first?.value ?? Infinity;\n\n // Stop if current candidate is farther than furthest result\n if (c.value > furthest_dist) {\n break;\n }\n\n const edges = layer.edges.get(c.element.index);\n if (!edges) continue;\n\n for (const neighbor_idx of edges) {\n if (!visited.has(neighbor_idx)) {\n const neighbor_element = elements[neighbor_idx];\n // Skip invalid elements or elements with different dimensions\n if (!neighbor_element || neighbor_element.length !== q.length) continue;\n\n // Skip self-connections\n if (neighbor_idx === c.element.index) continue;\n\n visited.add(neighbor_idx);\n const dist_e = metric(neighbor_element, q);\n\n const current_furthest = W.first?.value ?? Infinity;\n if (dist_e < current_furthest || W.length < ef) {\n C.push({\n element: neighbor_element,\n index: neighbor_idx,\n distance: dist_e,\n });\n W.push({\n element: neighbor_element,\n index: neighbor_idx,\n distance: dist_e,\n });\n\n if (W.length > ef) {\n W.pop();\n }\n }\n }\n }\n }\n\n // Return sorted results for consistent entry point selection\n return W.data().sort((a, b) => a.distance - b.distance);\n }\n\n /**\n * Searches for the K nearest neighbors to a query element in the HNSW graph.\n *\n * Performs a multi-layer search starting from the entry point and traversing\n * each layer as entry points for the next.\n *\n * @param {T} q - Query element\n * @param {number} K - Number of nearest neighbors to return\n * @returns {Candidate[]} K nearest neighbors with their distances\n */\n search(q, K) {\n // Validate K\n if (!Number.isInteger(K) || K <= 0) {\n throw new Error(\"HNSW: parameter 'K' must be a positive integer\");\n }\n\n // Validate query dimensions\n if (!q || (!Array.isArray(q) && !(q instanceof Float64Array))) {\n throw new Error(\"HNSW: query must be an array\");\n }\n\n const search_ef = this._ef;\n\n // Fallback to linear search if graph is not properly initialized\n if (this._L < 0 || !this._ep || this._elements.length === 0) {\n return this._linear_search(q, K);\n }\n\n let ep_indices = [...this._ep];\n\n // Search from top layer down to layer 1\n for (let l_c = this._L; l_c > 0; --l_c) {\n const result = this._search_layer(q, ep_indices, 1, l_c);\n if (result.length > 0) {\n ep_indices = [result[0].index];\n }\n }\n\n // Search layer 0 with ef candidates\n const result = this._search_layer(q, ep_indices, Math.max(search_ef, K), 0);\n\n // If graph search returns no results, fallback to linear search\n if (result.length === 0) {\n return this._linear_search(q, K);\n }\n\n // Return K closest\n return result.slice(0, K);\n }\n\n /**\n * Fallback linear search when graph search fails\n * @private\n * @param {T} q - Query element\n * @param {number} K - Number of nearest neighbors to return\n * @returns {Candidate[]}\n */\n _linear_search(q, K) {\n const metric = this._metric;\n const elements = this._elements;\n const N = elements.length;\n\n if (N === 0) return [];\n\n /** @type {Candidate[]} */\n const candidates = [];\n for (let i = 0; i < N; i++) {\n const element = elements[i];\n // Skip elements with different dimensions (can happen with inconsistent data)\n if (!element || element.length !== q.length) continue;\n\n candidates.push({\n element: element,\n index: i,\n distance: metric(q, element),\n });\n }\n\n candidates.sort((a, b) => a.distance - b.distance);\n return candidates.slice(0, K);\n }\n\n /**\n * Iterator for searching the HNSW graph layer by layer.\n *\n * Yields intermediate results at each layer for debugging or visualization.\n *\n * @param {T} q - Query element\n * @param {number} K - Number of nearest neighbors to return\n * @param {number?} [ef] - Size of dynamic candidate list\n * @yields {{layer: number, candidates: Candidate[]}}\n */\n *search_iter(q, K, ef = null) {\n const search_ef = ef ?? this._ef;\n\n if (this._L < 0 || !this._ep) {\n return;\n }\n\n let ep_indices = [...this._ep];\n\n // Yield entry points at top layer instead of query itself\n const top_layer = this._graph.get(this._L);\n if (top_layer && this._ep && this._ep.length > 0) {\n const entry_candidates = this._ep\n .filter((idx) => this._elements[idx] !== undefined)\n .map((idx) => ({\n element: this._elements[idx],\n index: idx,\n distance: this._metric(this._elements[idx], q),\n }));\n yield {\n layer: this._L,\n candidates: entry_candidates,\n };\n }\n\n for (let l_c = this._L; l_c > 0; --l_c) {\n const result = this._search_layer(q, ep_indices, 1, l_c);\n yield { layer: l_c, candidates: result };\n // Use closest candidate as entry point for next layer (following HNSW paper)\n ep_indices = result.length > 0 ? [result[0].index] : ep_indices;\n }\n\n const result = this._search_layer(q, ep_indices, Math.max(search_ef, K), 0);\n yield { layer: 0, candidates: result };\n }\n\n /**\n * Get the number of elements in the index.\n *\n * @returns {number} Number of elements\n */\n get size() {\n return this._elements?.length ?? 0;\n }\n\n /**\n * Get the number of layers in the graph.\n *\n * @returns {number} Number of layers\n */\n get num_layers() {\n return this._L + 1;\n }\n\n /**\n * Get an element by its index.\n *\n * @param {number} index - Element index\n * @returns {T} The element at the given index\n */\n get_element(index) {\n return this._elements[index];\n }\n\n /**\n * Search for nearest neighbors using an element index as the query.\n *\n * @param {number} i - Index of the query element\n * @param {number} [K=5] - Number of nearest neighbors to return\n * @returns {Candidate[]} K nearest neighbors\n */\n search_by_index(i, K = 5) {\n const elements = this._elements;\n if (i < 0 || i >= elements.length) return [];\n\n const element = elements[i];\n if (!element) return [];\n\n return this.search(element, K);\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersKDTree } from \"./index.js\" */\n\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} ElementWithIndex\n * @property {number} index\n * @property {T} element\n */\n\n/**\n * KD-Tree (K-dimensional Tree) for efficient nearest neighbor search.\n *\n * KD-Trees partition k-dimensional space by recursively splitting along coordinate axes.\n * At each level, the tree splits points based on the median of the coordinate with the largest spread.\n * This creates a balanced binary tree structure that enables efficient O(log n) search on average.\n *\n * Best suited for:\n * - Low to moderate dimensional data (d < 20-30)\n * - When exact nearest neighbors are needed\n * - When dimensionality is not too high\n *\n * Performance degrades in high dimensions (curse of dimensionality) where approximate\n * methods like HNSW or LSH become more effective.\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link https://en.wikipedia.org/wiki/K-d_tree}\n */\nexport class KDTree extends KNN {\n /**\n * Generates a KD-Tree with given `elements`.\n *\n * @param {T[]} elements - Elements which should be added to the KD-Tree\n * @param {ParametersKDTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}`\n */\n constructor(elements, parameters = { metric: euclidean, seed: 1212 }) {\n super(elements, Object.assign({ seed: 1212 }, parameters));\n /**\n * @private\n * @type {KDTreeNode | KDTreeLeaf | null}\n */\n this._root = this._construct(\n elements.map((element, index) => ({ index, element })),\n 0,\n );\n }\n\n /** @returns {Metric} */\n get _metric() {\n return this._parameters.metric;\n }\n\n /**\n * @private\n * @param {ElementWithIndex[]} elements\n * @param {number} depth - Current depth in the tree (determines splitting axis)\n * @returns {KDTreeNode | KDTreeLeaf | null} Root of KD-Tree.\n */\n _construct(elements, depth) {\n if (elements.length === 0) {\n return null;\n }\n\n if (elements.length === 1) {\n return new KDTreeLeaf(elements[0]);\n }\n\n const k = elements[0].element.length;\n const axis = depth % k;\n\n // Sort by the splitting axis and find median\n elements.sort((a, b) => a.element[axis] - b.element[axis]);\n const medianIndex = Math.floor(elements.length / 2);\n const medianPoint = elements[medianIndex];\n\n // Recursively build left and right subtrees\n const leftElements = elements.slice(0, medianIndex);\n const rightElements = elements.slice(medianIndex + 1);\n\n const left = this._construct(leftElements, depth + 1);\n const right = this._construct(rightElements, depth + 1);\n\n return new KDTreeNode(medianPoint, axis, left, right);\n }\n\n /**\n * @param {number} i\n * @param {number} k\n */\n search_by_index(i, k = 5) {\n return this.search(this._elements[i], k);\n }\n\n /**\n * @param {T} t - Query element.\n * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors.\n */\n search(t, k = 5) {\n /** @type {Heap<{ point: ElementWithIndex; distance: number }>} */\n const best = new Heap(null, (d) => d.distance, \"max\");\n\n this._search_recursive(t, k, this._root, best);\n\n // Convert heap to result array (closest first)\n /** @type {{ element: T; index: number; distance: number }[]} */\n const result = [];\n while (best.length > 0) {\n const item = /** @type {{ element: { point: ElementWithIndex; distance: number }; value: number }} */ (\n best.pop()\n );\n result.push({\n element: item.element.point.element,\n index: item.element.point.index,\n distance: item.value,\n });\n }\n return result.reverse();\n }\n\n /**\n * @private\n * @param {T} target - Query element.\n * @param {number} k - Number of nearest neighbors to return.\n * @param {KDTreeNode | KDTreeLeaf | null} node - Current node.\n * @param {Heap<{ point: ElementWithIndex; distance: number }>} best - Heap of k best found so far.\n */\n _search_recursive(target, k, node, best) {\n if (node === null) return;\n\n if (node instanceof KDTreeLeaf) {\n const dist = this._metric(target, node.point.element);\n if (best.length < k) {\n best.push({ point: node.point, distance: dist });\n } else if (dist < (best.first?.value ?? Infinity)) {\n best.pop();\n best.push({ point: node.point, distance: dist });\n }\n return;\n }\n\n // Node is an internal node\n const axis = node.axis;\n const point = node.point;\n const pointValue = point.element[axis];\n const targetValue = target[axis];\n\n // Determine which subtree to search first\n const firstSubtree = targetValue < pointValue ? node.left : node.right;\n const secondSubtree = targetValue < pointValue ? node.right : node.left;\n\n // Search the nearer subtree\n this._search_recursive(target, k, firstSubtree, best);\n\n // Check if we need to search the other subtree\n // The hyperplane could contain closer points\n const distToHyperplane = Math.abs(targetValue - pointValue);\n const currentMaxDist = best.first?.value ?? Infinity;\n\n // Calculate distance to current point\n const distToPoint = this._metric(target, point.element);\n if (best.length < k) {\n best.push({ point: point, distance: distToPoint });\n } else if (distToPoint < currentMaxDist) {\n best.pop();\n best.push({ point: point, distance: distToPoint });\n }\n\n // Check if we need to explore the other side of the hyperplane\n if (best.length < k || distToHyperplane < (best.first?.value ?? Infinity)) {\n this._search_recursive(target, k, secondSubtree, best);\n }\n }\n}\n\n/**\n * @private\n * @template {number[] | Float64Array} T\n */\nclass KDTreeNode {\n /**\n * @param {ElementWithIndex} point\n * @param {number} axis - The splitting axis\n * @param {KDTreeNode | KDTreeLeaf | null} left\n * @param {KDTreeNode | KDTreeLeaf | null} right\n */\n constructor(point, axis, left = null, right = null) {\n this.point = point;\n this.axis = axis;\n this.left = left;\n this.right = right;\n }\n}\n\n/**\n * @private\n * @template {number[] | Float64Array} T\n */\nclass KDTreeLeaf {\n /**\n * @param {ElementWithIndex} point\n */\n constructor(point) {\n this.point = point;\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersLSH } from \"./index.js\" */\n\n/**\n * Locality Sensitive Hashing (LSH) for approximate nearest neighbor search.\n *\n * LSH uses hash functions that map similar items to the same buckets with high probability.\n * This implementation uses Random Projection hashing (SimHash-style) which works well for\n * cosine similarity and Euclidean distance.\n *\n * Key concepts:\n * - Multiple hash tables increase recall probability\n * - Each hash function projects data onto random hyperplanes\n * - Points on the same side of hyperplanes are hashed together\n * - Combines results from all tables for better accuracy\n *\n * Best suited for:\n * - High-dimensional data where exact methods fail\n * - Approximate nearest neighbor needs\n * - Large datasets where linear scan is too slow\n * - When some false positives/negatives are acceptable\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link https://en.wikipedia.org/wiki/Locality-sensitive_hashing}\n */\nexport class LSH extends KNN {\n /**\n * Creates a new LSH index.\n *\n * @param {T[]} elements - Elements to index\n * @param {ParametersLSH} [parameters={}] - Configuration parameters\n */\n constructor(\n elements,\n parameters = {\n metric: euclidean,\n numHashTables: 10,\n numHashFunctions: 10,\n seed: 1212,\n },\n ) {\n // Handle empty initialization - use dummy element\n const hasElements = elements && elements.length > 0;\n const firstElement = /** @type {T} */ (hasElements ? elements[0] : new Float64Array([0]));\n\n super([firstElement], parameters);\n\n this._metric = this._parameters.metric ?? euclidean;\n this._numHashTables = this._parameters.numHashTables ?? 10;\n this._numHashFunctions = this._parameters.numHashFunctions ?? 10;\n this._seed = this._parameters.seed ?? 1212;\n this._randomizer = new Randomizer(this._seed);\n\n // Hash tables: array of Maps where key is hash bucket, value is array of element indices\n /** @type {Map[]} */\n this._hashTables = [];\n\n // Random projection vectors for each hash table and hash function\n /** @type {Float64Array[][]} */\n this._projections = [];\n\n // Random offsets for each hash table and hash function (for quantization)\n /** @type {number[][]} */\n this._offsets = [];\n\n // Store dimensionality for later\n /** @type {number} */\n this._dim = firstElement.length;\n\n // Initialize hash functions\n this._initializeHashFunctions();\n\n // Reset elements if we were initialized with dummy\n if (!hasElements) {\n /** @type {T[]} */\n this._elements = [];\n } else {\n // Clear and re-add elements properly\n /** @type {T[]} */\n this._elements = [];\n this._hashTables = [];\n this._projections = [];\n this._offsets = [];\n this._initializeHashFunctions();\n this.add(elements);\n }\n }\n\n /**\n * Initialize random projection vectors for all hash tables.\n * @private\n */\n _initializeHashFunctions() {\n const dim = this._elements[0]?.length ?? 0;\n\n for (let t = 0; t < this._numHashTables; t++) {\n const tableProjections = [];\n const tableOffsets = [];\n\n for (let h = 0; h < this._numHashFunctions; h++) {\n // Generate random projection vector (normalized)\n const projection = new Float64Array(dim);\n let norm = 0;\n for (let i = 0; i < dim; i++) {\n // Box-Muller transform for normal distribution\n const u1 = this._randomizer.random;\n const u2 = this._randomizer.random;\n const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);\n projection[i] = z;\n norm += z * z;\n }\n // Normalize\n norm = Math.sqrt(norm);\n for (let i = 0; i < dim; i++) {\n projection[i] /= norm;\n }\n\n tableProjections.push(projection);\n // Random offset for quantization buckets\n tableOffsets.push(this._randomizer.random);\n }\n\n this._projections.push(tableProjections);\n this._offsets.push(tableOffsets);\n this._hashTables.push(new Map());\n }\n }\n\n /**\n * Compute hash signature for an element using random projections.\n * @private\n * @param {T} element\n * @param {number} tableIndex\n * @returns {string} Hash signature\n */\n _computeHash(element, tableIndex) {\n const projections = this._projections[tableIndex];\n const offsets = this._offsets[tableIndex];\n const bits = [];\n\n for (let i = 0; i < this._numHashFunctions; i++) {\n // Compute dot product\n let dot = 0;\n const proj = projections[i];\n for (let j = 0; j < element.length; j++) {\n dot += element[j] * proj[j];\n }\n // Quantize with offset\n const bucket = Math.floor(dot + offsets[i]);\n bits.push(bucket);\n }\n\n return bits.join(\",\");\n }\n\n /**\n * Add elements to the LSH index.\n * @param {T[]} elements\n * @returns {this}\n */\n add(elements) {\n // Extend elements array\n const startIndex = this._elements.length;\n this._elements = this._elements.concat(elements);\n\n // Hash each new element and add to tables\n for (let i = 0; i < elements.length; i++) {\n const globalIndex = startIndex + i;\n const element = elements[i];\n\n for (let t = 0; t < this._numHashTables; t++) {\n const hash = this._computeHash(element, t);\n const table = this._hashTables[t];\n\n if (!table.has(hash)) {\n table.set(hash, []);\n }\n const bucket = table.get(hash);\n if (bucket) {\n bucket.push(globalIndex);\n }\n }\n }\n\n return this;\n }\n\n /**\n * Search for k approximate nearest neighbors.\n * @param {T} query\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search(query, k = 5) {\n const metric = this._metric;\n const elements = this._elements;\n\n if (elements.length === 0) return [];\n\n // Collect candidate indices from all hash tables\n const candidates = new Set();\n\n for (let t = 0; t < this._numHashTables; t++) {\n const hash = this._computeHash(query, t);\n const table = this._hashTables[t];\n const bucket = table.get(hash);\n\n if (bucket) {\n for (const idx of bucket) {\n if (idx !== undefined) {\n candidates.add(idx);\n }\n }\n }\n }\n\n // If insufficient candidates found, fall back to linear search\n if (candidates.size < k) {\n // Add more candidates from all buckets or entire dataset\n //const needed = k - candidates.size;\n\n // First, try to add from neighboring buckets (different hashes)\n for (let t = 0; t < this._numHashTables && candidates.size < k; t++) {\n const table = this._hashTables[t];\n for (const [, bucket] of table) {\n for (const idx of bucket) {\n if (idx !== undefined) {\n candidates.add(idx);\n if (candidates.size >= k) break;\n }\n }\n if (candidates.size >= k) break;\n }\n }\n\n // If still not enough, add from entire dataset\n for (let i = 0; i < elements.length && candidates.size < k; i++) {\n candidates.add(i);\n }\n }\n\n // Compute exact distances for candidates\n /** @type {Heap<{ index: number; distance: number }>} */\n const best = new Heap(null, (d) => d.distance, \"max\");\n\n for (const idx of candidates) {\n const element = elements[idx];\n if (!element || element.length !== query.length) continue;\n\n const dist = metric(query, element);\n\n if (best.length < k) {\n best.push({ index: idx, distance: dist });\n } else if (dist < (best.first?.value ?? Infinity)) {\n best.pop();\n best.push({ index: idx, distance: dist });\n }\n }\n\n // Convert to result format\n /** @type {{ element: T; index: number; distance: number }[]} */\n const result = [];\n while (best.length > 0) {\n const item = /** @type {{ element: { index: number; distance: number }; value: number }} */ (best.pop());\n result.push({\n element: elements[item.element.index],\n index: item.element.index,\n distance: item.value,\n });\n }\n\n return result.reverse();\n }\n\n /**\n * @param {number} i\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i, k = 5) {\n if (i < 0 || i >= this._elements.length) return [];\n return this.search(this._elements[i], k);\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { distance_matrix, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import { ParametersNaiveKNN } from \"./index.js\" */\n\n/**\n * Naive KNN implementation using a distance matrix.\n *\n * This implementation pre-computes the entire distance matrix and performs\n * an exhaustive search. Best suited for small datasets or when a distance\n * matrix is already available.\n *\n * @template {number[] | Float64Array} T\n * @category KNN\n * @class\n * @extends KNN\n */\nexport class NaiveKNN extends KNN {\n /**\n * Generates a KNN list with given `elements`.\n *\n * @param {T[]} elements - Elements which should be added to the KNN list\n * @param {ParametersNaiveKNN} parameters\n */\n constructor(elements, parameters = {}) {\n const params = Object.assign({ metric: euclidean, seed: 1212 }, parameters);\n super(elements, params);\n const N =\n this._elements instanceof Matrix ? /** @type {any} */ (this._elements).shape[0] : this._elements.length;\n if (this._parameters.metric === \"precomputed\") {\n this._D = Matrix.from(/** @type {number[][] | Float64Array[]} */ (/** @type {any} */ (this._elements)));\n } else {\n this._D = distance_matrix(\n /** @type {number[][] | Float64Array[]} */ (this._elements),\n this._parameters.metric,\n );\n }\n\n /** @type {Heap<{ value: number; index: number }>[]} */\n this.KNN = [];\n for (let row = 0; row < N; ++row) {\n const distances = this._D.row(row);\n /** @type {Heap<{ value: number; index: number }>} */\n const H = new Heap(null, (d) => d.value, \"min\");\n for (let j = 0; j < N; ++j) {\n H.push({\n value: distances[j],\n index: j,\n });\n }\n this.KNN.push(H);\n }\n }\n\n /**\n * @param {number} i\n * @param {number} k\n */\n search_by_index(i, k = 5) {\n if (this._parameters.metric === \"precomputed\") {\n const H = this.KNN[i];\n /** @type {{ element: T; index: number; distance: number }[]} */\n const result = [];\n const data = H.toArray(); // Get array representation\n const temp_heap = new Heap(data, (d) => d.value, \"min\");\n const N =\n this._elements instanceof Matrix ? /** @type {any} */ (this._elements).shape[0] : this._elements.length;\n for (let j = 0; j < Math.min(k, N); ++j) {\n const node = temp_heap.pop();\n if (!node) break;\n result.push({\n element: /** @type {T} */ (\n this._elements instanceof Matrix\n ? /** @type {any} */ (this._elements).row(node.element.index)\n : this._elements[node.element.index]\n ),\n index: /** @type {number} */ (node.element.index),\n distance: /** @type {number} */ (node.value),\n });\n }\n return result;\n }\n return this.search(\n /** @type {T} */ (\n this._elements instanceof Matrix ? /** @type {any} */ (this._elements).row(i) : this._elements[i]\n ),\n k,\n );\n }\n\n /**\n * @param {T} t - Query element.\n * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors.\n */\n search(t, k = 5) {\n if (this._parameters.metric === \"precomputed\") {\n throw new Error(\"Search by query element is only possible when not using a precomputed distance matrix!\");\n }\n /** @type {import(\"../metrics/index.js\").Metric} */\n const metric = /** @type {any} */ (this._parameters.metric);\n\n const isMatrix = this._elements instanceof Matrix;\n const elementsAny = /** @type {any} */ (this._elements);\n const N = isMatrix ? elementsAny.shape[0] : this._elements.length;\n\n // Compute distances from query to ALL points\n const distances = [];\n for (let i = 0; i < N; i++) {\n const element = /** @type {T} */ (isMatrix ? elementsAny.row(i) : this._elements[i]);\n distances.push({\n element: element,\n index: i,\n distance: metric(t, element),\n });\n }\n\n // Sort by distance and return k nearest\n distances.sort((a, b) => a.distance - b.distance);\n return distances.slice(0, k);\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import {ParametersNNDescent} from \"./index.js\" */\n/**\n *\n * @template {number[] | Float64Array} T\n * @typedef {Object} NNDescentElement\n * @property {T} value\n * @property {number} index\n * @property {boolean} flag\n */\n\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} NNDescentNeighbor\n * @property {T} value\n * @property {number} index\n * @property {number} distance\n * @property {boolean} [flag]\n */\n\n/**\n * NN-Descent\n *\n * An efficient graph-based approximate nearest neighbor search algorithm.\n * It works by iteratively improving a neighbor graph using the fact that\n * \"neighbors of neighbors are likely to be neighbors\".\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf|NN-Descent Paper}\n */\nexport class NNDescent extends KNN {\n /**\n * @private\n * @type {KNNHeap[]}\n */\n _B = [];\n /**\n * @private\n * @type {NNDescentNeighbor[][]}\n */\n nn = [];\n\n /**\n * @param {T[]} elements - Called V in paper.\n * @param {Partial} parameters\n * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf}\n */\n constructor(elements, parameters = {}) {\n super(\n elements,\n /** @type {ParametersNNDescent} */ (\n Object.assign({ metric: euclidean, K: 10, rho: 1, delta: 1e-3, seed: 1212 }, parameters)\n ),\n );\n this._N = elements.length;\n this._randomizer = new Randomizer(this._parameters.seed);\n this._sample_size = this._parameters.samples * this._parameters.rho;\n\n this._nndescent_elements = elements.map((e, i) => {\n return {\n value: e,\n index: i,\n flag: true,\n };\n });\n\n if (elements) {\n this.add(elements);\n }\n }\n\n /**\n * Samples Array A with sample size.\n *\n * @private\n * @template U\n * @param {U[]} A\n * @returns {U[]}\n */\n _sample(A) {\n const n = A.length;\n const sample_size = this._sample_size;\n if (sample_size > n) {\n return A;\n } else {\n const randomizer = this._randomizer;\n return randomizer.choice(A, sample_size);\n }\n }\n\n /**\n * @private\n * @param {KNNHeap} B\n * @param {NNDescentNeighbor} u\n * @returns {number}\n */\n _update(B, u) {\n if (B.set.has(u.index)) return 0;\n\n const worst = B.first;\n if (worst && B.length >= this._parameters.samples) {\n const dist = B._accessor(u);\n const worst_dist = B._accessor(worst.element);\n if (dist >= worst_dist) {\n return 0; // u is worse than the worst neighbor\n }\n }\n\n B.push(u);\n u.flag = true;\n if (B.length > this._parameters.samples) {\n B.pop();\n }\n return 1;\n }\n\n /**\n * @private\n * @param {(KNNHeap | null)[]} B\n * @returns {NNDescentNeighbor[][]}\n */\n _reverse(B) {\n const N = this._N;\n const R = new Array(N);\n for (let i = 0; i < N; i++) {\n R[i] = [];\n }\n for (let j = 0; j < N; j++) {\n const Bi = B[j];\n if (Bi) {\n const Bjdata = Bi.data();\n for (const neighbor of Bjdata) {\n const v = neighbor.index;\n R[v].push(neighbor);\n }\n }\n }\n return R;\n }\n\n /**\n * @param {T[]} elements\n * @returns {this}\n */\n add(elements) {\n const randomizer = this._randomizer;\n const metric = this._parameters.metric;\n const K = this._parameters.samples;\n const delta = this._parameters.delta;\n const N = elements.length;\n this._N = N;\n /** @type {KNNHeap[]} */\n const B = [];\n this._B = B;\n for (let i = 0; i < N; i++) {\n const e = elements[i];\n const sample = randomizer\n .choice(\n elements.map((el, idx) => ({ el, idx })),\n K,\n )\n .map((d) => {\n return { index: d.idx, distance: metric(d.el, e), value: d.el };\n });\n const Bi = new KNNHeap(sample, (d) => d.distance, \"max\");\n B.push(Bi);\n }\n\n let c = Infinity;\n let old_c = -Infinity;\n while (c > delta * N * K && c !== old_c) {\n const old_ = new Array(N);\n const new_ = new Array(N);\n for (let i = 0; i < N; i++) {\n const Bi = B[i].data();\n const falseBs = Bi.filter((d) => !d.flag);\n const trueBs = this._sample(Bi.filter((d) => d.flag));\n for (const d of trueBs) {\n d.flag = false;\n }\n old_[i] = new KNNHeap(falseBs, (d) => d.distance, \"max\");\n new_[i] = new KNNHeap(trueBs, (d) => d.distance, \"max\");\n }\n const old_reverse = this._reverse(old_);\n const new_reverse = this._reverse(new_);\n old_c = c;\n c = 0;\n for (let i = 0; i < N; i++) {\n for (const o of this._sample(old_reverse[i])) {\n old_[i].push(o);\n }\n for (const n of this._sample(new_reverse[i])) {\n new_[i].push(n);\n }\n\n const new_i = new_[i].data();\n const old_i = old_[i].data();\n const n1 = new_i.length;\n const n2 = old_i.length;\n for (let j = 0; j < n1; j++) {\n const u1 = new_i[j];\n const Bu1 = B[u1.index];\n for (let k = 0; k < n1; k++) {\n const u2 = new_i[k];\n if (u1.index === u2.index) continue;\n const Bu2 = B[u2.index];\n c += this._update(Bu2, u1);\n c += this._update(Bu1, u2);\n }\n for (let k = 0; k < n2; k++) {\n const u2 = old_i[k];\n if (u1.index === u2.index) continue;\n const Bu2 = B[u2.index];\n c += this._update(Bu2, u1);\n c += this._update(Bu1, u2);\n }\n }\n }\n }\n this.nn = this._B.map((heap) => heap.data());\n return this;\n }\n\n /**\n * @param {T} x\n * @param {number} [k=5] Default is `5`\n * @returns {{ element: T, index: number; distance: number }[]}\n */\n search(x, k = 5) {\n const metric = this._parameters.metric;\n const N = this._N;\n const elements = this._elements;\n\n if (N === 0) return [];\n const xLength = x.length;\n\n // Initialize candidate pool\n const visited = new Set();\n /** @type {{index: number, dist: number, evaluated: boolean}[]} */\n let pool = [];\n\n // Randomly pick initial candidates\n const randomizer = this._randomizer;\n for (let i = 0; i < Math.min(N, Math.max(k * 10, 50)); i++) {\n let rnd;\n do {\n rnd = randomizer.random_int % N;\n } while (visited.has(rnd));\n visited.add(rnd);\n\n const element = elements[rnd];\n if (!element || element.length !== xLength) continue;\n\n pool.push({\n index: rnd,\n dist: metric(x, element),\n evaluated: false,\n });\n }\n\n let searching = true;\n while (searching) {\n pool.sort((a, b) => a.dist - b.dist);\n // keep the top subset for exploration\n pool = pool.slice(0, Math.max(k * 5, 50));\n\n searching = false;\n for (let i = 0; i < pool.length; i++) {\n const candidate = pool[i];\n if (candidate.evaluated) continue;\n\n candidate.evaluated = true;\n searching = true;\n\n // get neighbors of this candidate from graph\n const neighbors = this.nn[candidate.index];\n if (!neighbors) continue;\n\n for (const neighbor of neighbors) {\n const n_idx = neighbor.index;\n if (!visited.has(n_idx)) {\n visited.add(n_idx);\n const element = elements[n_idx];\n if (element && element.length === xLength) {\n pool.push({\n index: n_idx,\n dist: metric(x, element),\n evaluated: false,\n });\n }\n }\n }\n // Don't break here! Look at more candidates per iteration for better convergence\n // break;\n }\n }\n\n pool.sort((a, b) => a.dist - b.dist);\n\n /** @type {{ element: T, index: number; distance: number }[]} */\n const result = [];\n for (let i = 0; i < Math.min(k, pool.length); i++) {\n const item = pool[i];\n result.push({\n element: elements[item.index],\n index: item.index,\n distance: item.dist,\n });\n }\n return result;\n }\n\n /**\n * @param {number} i\n * @param {number} [k=5] Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i, k = 5) {\n // Use regular search with the element at index i\n const elements = this._elements;\n if (i < 0 || i >= elements.length) return [];\n\n const element = elements[i];\n if (!element) return [];\n\n return this.search(element, k);\n }\n}\n\n/**\n * @template {number[] | Float64Array} U\n * @typedef {Object} HeapEntry\n * @property {NNDescentNeighbor} element\n * @property {number} value\n */\n\n/**\n * @template {number[] | Float64Array} U\n * @extends {Heap>}\n */\nclass KNNHeap extends Heap {\n /** @type {Set} */\n set;\n\n /**\n * @param {NNDescentNeighbor[]} elements\n * @param {(d: NNDescentNeighbor) => number} accessor\n * @param {\"max\" | \"min\"} comparator\n */\n constructor(elements, accessor, comparator) {\n super(null, accessor, comparator);\n this.set = new Set();\n if (elements) {\n for (const element of elements) {\n this.push(element);\n }\n }\n }\n\n /**\n * @param {NNDescentNeighbor} element\n * @returns {KNNHeap}\n */\n push(element) {\n const set = this.set;\n if (set.has(element.index)) {\n return this;\n } else {\n set.add(element.index);\n super.push(element);\n return this;\n }\n }\n\n /** @returns {{ element: NNDescentNeighbor; value: number } | null} */\n pop() {\n const result = super.pop();\n if (result?.element) {\n this.set.delete(result.element.index);\n return result;\n }\n return null;\n }\n\n /** @returns {NNDescentNeighbor[]} */\n data() {\n return this._container.map((d) => d.element);\n }\n}\n","import { distance_matrix, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersSMACOF} from \"./index.js\" */\n\n/**\n * Metric Multidimensional Scaling (MDS) via SMACOF.\n *\n * SMACOF (Scaling by Majorizing a Complicated Function) is an iterative majorization\n * algorithm for solving metric multidimensional scaling problems, which aims to\n * minimize the stress function.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link MDS} for the classical approach.\n */\nexport class SMACOF extends DR {\n /**\n * SMACOF for MDS.\n *\n * @param {T} X - The high-dimensional data or precomputed distance matrix.\n * @param {Partial} [parameters] - Object containing parameterization.\n */\n constructor(X, parameters = {}) {\n super(X, { d: 2, metric: euclidean, seed: 1212, iterations: 300, epsilon: 1e-4 }, parameters);\n }\n\n /**\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n this.check_init();\n const X = this.X;\n const rows = this._N;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const metric = /** @type {typeof euclidean | \"precomputed\"} */ (this.parameter(\"metric\"));\n const iterations = /** @type {number} */ (this.parameter(\"iterations\"));\n const epsilon = /** @type {number} */ (this.parameter(\"epsilon\"));\n\n const target_distances = metric === \"precomputed\" ? X : distance_matrix(X, metric);\n\n let Z = new Matrix(rows, d, () => (this._randomizer.random - 0.5) * 2);\n\n // Center Z\n for (let j = 0; j < d; ++j) {\n const col = Z.col(j);\n const mean = col.reduce((a, b) => a + b, 0) / rows;\n for (let i = 0; i < rows; ++i) {\n Z.sub_entry(i, j, mean);\n }\n }\n\n this.Y = /** @type {Matrix} */ (Z); // Initial state\n\n let prev_stress = Infinity;\n\n if (!(iterations > 0)) {\n yield this.projection;\n return this.projection;\n }\n\n for (let iter = 0; iter < iterations; ++iter) {\n const B = new Matrix(rows, rows, 0);\n\n for (let i = 0; i < rows; ++i) {\n let bii = 0;\n const z_i = Z.row(i);\n for (let j = 0; j < rows; ++j) {\n if (i === j) continue;\n const z_j = Z.row(j);\n const dist_Z = euclidean(z_i, z_j);\n const dist_target = target_distances.entry(i, j);\n\n let bij = 0;\n if (dist_Z > 1e-12) {\n bij = -dist_target / dist_Z;\n }\n B.set_entry(i, j, bij);\n bii -= bij;\n }\n B.set_entry(i, i, bii);\n }\n\n // Z_new = 1/N * B(Z) * Z\n const Z_new = B.dot(Z)._apply(rows, (val, n) => val / n);\n\n this.Y = /** @type {Matrix} */ (Z_new);\n Z = /** @type {Matrix} */ (Z_new);\n\n // Calculate stress\n let stress_num = 0;\n let stress_den = 0;\n for (let i = 0; i < rows; ++i) {\n const z_i = Z.row(i);\n for (let j = i + 1; j < rows; ++j) {\n const z_j = Z.row(j);\n const dist_Y = euclidean(z_i, z_j);\n const diff = target_distances.entry(i, j) - dist_Y;\n stress_num += diff * diff;\n stress_den += target_distances.entry(i, j) ** 2;\n }\n }\n const current_stress = Math.sqrt(stress_num / Math.max(stress_den, 1e-12));\n\n yield this.projection;\n\n if (Math.abs(prev_stress - current_stress) < epsilon) {\n break;\n }\n prev_stress = current_stress;\n }\n return this.projection;\n }\n\n /**\n * @returns {T}\n */\n transform() {\n const gen = this.generator();\n let res = /** @type {T} */ (this.X);\n for (const step of gen) {\n res = step;\n }\n return res;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new SMACOF(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new SMACOF(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new SMACOF(X, parameters);\n return dr.transform_async();\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { BallTree } from \"../knn/index.js\";\nimport { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\nimport { SMACOF } from \"./SMACOF.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersISOMAP} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n\n/**\n * Isomap (Isometric Mapping)\n *\n * A nonlinear dimensionality reduction algorithm that uses geodesic distances\n * between points on a manifold to perform embedding. It builds a neighborhood\n * graph and uses MDS on the shortest-path distances.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link LLE} for another nonlinear alternative\n */\nexport class ISOMAP extends DR {\n /**\n * Isometric feature mapping (ISOMAP).\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n * @see {@link https://doi.org/10.1126/science.290.5500.2319}\n */\n constructor(X, parameters = {}) {\n /** @type {ParametersISOMAP} */\n const defaults = {\n neighbors: -Infinity,\n d: 2,\n metric: euclidean,\n seed: 1212,\n project: \"MDS\",\n eig_args: {},\n };\n super(X, defaults, parameters);\n\n this.defaults = defaults;\n\n if (this._parameters.neighbors === -Infinity) {\n this.parameter(\"neighbors\", Math.min(Math.max(Math.floor(this.X.shape[0] / 10), 2), this._N - 1));\n }\n\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n if (!Object.hasOwn(eig_args, \"seed\")) {\n eig_args.seed = this._randomizer;\n }\n }\n\n /**\n * Computes the projection.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * @returns {T}\n */\n transform() {\n this.check_init();\n const X = this.X;\n const rows = this._N;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const metric = /** @type {typeof euclidean} */ (this.parameter(\"metric\"));\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n const neighbors = /** @type {number} */ (this.parameter(\"neighbors\"));\n // TODO: make knn extern and parameter for constructor or transform?\n const D = new Matrix(rows, rows, 0);\n D.shape = [rows, rows, (i, j) => (i <= j ? metric(X.row(i), X.row(j)) : D.entry(j, i))];\n\n /** @type {{ index: number; distance: number }[][]} */\n const kNearestNeighbors = [];\n const tree = new BallTree(X.to2dArray(), { metric, seed: /** @type {number} */ (this.parameter(\"seed\")) });\n for (let i = 0; i < rows; ++i) {\n // BallTree search returns elements including the queried point itself (at distance 0).\n // Request neighbors + 1 and slice off the first one (which should be the query point).\n const neighborsList = tree.search_by_index(i, neighbors + 1);\n kNearestNeighbors.push(\n neighborsList.slice(1).map((n) => ({\n index: n.index,\n distance: n.distance,\n })),\n );\n }\n\n // ISOMAP requires an undirected/symmetric nearest neighbor graph.\n // If i is a nearest neighbor of j, then j should be connected to i as well.\n for (let i = 0; i < rows; ++i) {\n for (const neighbor of kNearestNeighbors[i]) {\n const j = neighbor.index;\n const d = neighbor.distance;\n const reciprocal_edge = kNearestNeighbors[j].find((n) => n.index === i);\n if (!reciprocal_edge) {\n kNearestNeighbors[j].push({ index: i, distance: d });\n }\n }\n }\n\n /*D = dijkstra(kNearestNeighbors);*/\n // compute shortest paths using Dijkstra's algorithm\n // TODO: make extern\n const G = new Matrix(rows, rows, Infinity);\n\n for (let i = 0; i < rows; ++i) {\n G.set_entry(i, i, 0);\n const H = new Heap([{ index: i, distance: 0 }], (d) => d.distance, \"min\");\n\n while (!H.empty) {\n const item = H.pop();\n if (!item) break;\n\n const u = item.element.index;\n const dist_u = item.element.distance;\n\n if (dist_u > G.entry(i, u)) continue;\n\n for (const neighbor of kNearestNeighbors[u]) {\n const v = neighbor.index;\n const alt = dist_u + neighbor.distance;\n if (alt < G.entry(i, v)) {\n G.set_entry(i, v, alt);\n H.push({ index: v, distance: alt });\n }\n }\n }\n }\n\n let max_val = 0;\n for (let i = 0; i < rows; i++) {\n for (let j = 0; j < rows; j++) {\n const val = G.entry(i, j);\n if (val !== Infinity && val > max_val) max_val = val;\n }\n }\n const big_val = max_val * 10;\n\n const project = /** @type {\"MDS\" | \"SMACOF\"} */ (this.parameter(\"project\"));\n\n if (project === \"SMACOF\") {\n // Apply SMACOF metric MDS to the distance matrix directly\n const D_matrix = new Matrix(rows, rows, (i, j) => {\n const val = G.entry(i, j);\n return val === Infinity ? big_val : val;\n });\n const smacof = new SMACOF(D_matrix, { metric: \"precomputed\", d, seed: this.parameter(\"seed\") });\n smacof.transform();\n this.Y = smacof.Y;\n } else {\n // \"MDS\" (Classical MDS) via Eigendecomposition of double-centered squared distance matrix\n const D_sq = new Matrix(rows, rows, (i, j) => {\n let val = G.entry(i, j);\n if (val === Infinity) val = big_val;\n return val * val;\n });\n\n const ai_ = D_sq.meanCols();\n const a_j = D_sq.meanRows();\n const a__ = D_sq.mean();\n const B = new Matrix(rows, rows, (i, j) => -0.5 * (D_sq.entry(i, j) - ai_[i] - a_j[j] + a__));\n\n // compute d eigenvectors\n const { eigenvectors: V } = simultaneous_poweriteration(B, d, eig_args);\n this.Y = Matrix.from(V).transpose();\n }\n // return embedding\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new ISOMAP(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new ISOMAP(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new ISOMAP(X, parameters);\n return dr.transform_async();\n }\n}\n","import { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLDA} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n\n/**\n * Linear Discriminant Analysis (LDA)\n *\n * A supervised dimensionality reduction technique that finds the axes that\n * maximize the separation between multiple classes.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class LDA extends DR {\n /**\n * Linear Discriminant Analysis.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial & { labels: any[] | Float64Array }} parameters - Object containing parameterization of the DR method.\n * @see {@link https://onlinelibrary.wiley.com/doi/10.1111/j.1469-1809.1936.tb02137.x}\n */\n constructor(X, parameters) {\n super(X, { labels: parameters.labels, d: 2, seed: 1212, eig_args: {} }, parameters);\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n if (!Object.hasOwn(eig_args, \"seed\")) {\n eig_args.seed = this._randomizer;\n }\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T} - The projected data.\n */\n transform() {\n const X = this.X;\n const [rows, cols] = X.shape;\n const { d, labels, eig_args } = this._parameters;\n if (labels === null || labels.length !== rows) {\n throw new Error(\"LDA needs parameter label to every datapoint to work!\");\n }\n\n /** @type {Record} */\n const unique_labels = {};\n let label_id = 0;\n labels.forEach((l, i) => {\n if (l in unique_labels) {\n unique_labels[l].count++;\n unique_labels[l].rows.push(X.row(i));\n } else {\n unique_labels[l] = {\n id: label_id++,\n count: 1,\n rows: [X.row(i)],\n };\n }\n });\n\n // create X_mean and vector means;\n const X_mean = X.meanCols();\n const V_mean = new Matrix(label_id, cols);\n for (const label in unique_labels) {\n const V = Matrix.from(unique_labels[label].rows);\n const v_mean = V.meanCols();\n for (let j = 0; j < cols; ++j) {\n V_mean.set_entry(unique_labels[label].id, j, v_mean[j]);\n }\n }\n // scatter_between\n let S_b = new Matrix(cols, cols);\n for (const label in unique_labels) {\n const v = V_mean.row(unique_labels[label].id);\n const m = Matrix.from([v]).sub(Matrix.from([X_mean]));\n const N = unique_labels[label].count;\n S_b = S_b.add(m.transDot(m).mult(N));\n }\n\n // scatter_within\n let S_w = new Matrix(cols, cols);\n for (const label in unique_labels) {\n const v = V_mean.row(unique_labels[label].id);\n const R = unique_labels[label].rows;\n for (let i = 0, n = unique_labels[label].count; i < n; ++i) {\n const row_v = Matrix.from([R[i]]).sub(Matrix.from([v]));\n S_w = S_w.add(row_v.transDot(row_v));\n }\n }\n\n const { eigenvectors: EV } = simultaneous_poweriteration(\n S_w.inverse().dot(S_b),\n d || Math.min(cols, label_id - 1),\n eig_args,\n );\n const V = Matrix.from(EV).transpose();\n this.Y = X.dot(V);\n\n // return embedding\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @returns {T}\n */\n static transform(X, parameters) {\n // @ts-expect-error: LDA requires labels, but DR static transform doesn't\n const dr = new LDA(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n // @ts-expect-error: LDA requires labels, but DR static generator doesn't\n const dr = new LDA(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n // @ts-expect-error: LDA requires labels, but DR static transform doesn't\n const dr = new LDA(X, parameters);\n return dr.transform_async();\n }\n}\n","import { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { k_nearest_neighbors, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { neumair_sum } from \"../numerical/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLLE} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n\n/**\n * Locally Linear Embedding (LLE)\n *\n * A nonlinear dimensionality reduction technique that preserves local\n * linear relationships between points. It represents each point as a linear\n * combination of its neighbors.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link ISOMAP} for another nonlinear alternative\n */\nexport class LLE extends DR {\n /**\n * Locally Linear Embedding.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://doi.org/10.1126/science.290.5500.2323}\n */\n constructor(X, parameters) {\n super(\n X,\n {\n neighbors: -Infinity,\n d: 2,\n metric: euclidean,\n seed: 1212,\n eig_args: {},\n },\n parameters,\n );\n if (this._parameters.neighbors === -Infinity) {\n this.parameter(\"neighbors\", Math.min(Math.max(Math.floor(this._N / 10), 2), this._N - 1));\n }\n\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n if (!Object.hasOwn(eig_args, \"seed\")) {\n eig_args.seed = this._randomizer;\n }\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T}\n */\n transform() {\n const X = this.X;\n const rows = this._N;\n const cols = this._D;\n const neighbors = /** @type {number} */ (this.parameter(\"neighbors\"));\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n const metric = /** @type {typeof euclidean} */ (this.parameter(\"metric\"));\n const nN = k_nearest_neighbors(X, neighbors, metric);\n const O = new Matrix(neighbors, 1, 1);\n const W = new Matrix(rows, rows);\n\n for (let row = 0; row < rows; ++row) {\n const nN_row = nN[row];\n const Z = new Matrix(neighbors, cols, (i, j) => X.entry(nN_row[i].j, j) - X.entry(row, j));\n const C = Z.dotTrans(Z);\n if (neighbors > cols) {\n const C_trace = neumair_sum(C.diag()) / 1000;\n for (let j = 0; j < neighbors; ++j) {\n C.add_entry(j, j, C_trace);\n }\n }\n // reconstruct;\n let w = Matrix.solve_CG(C, O, this._randomizer);\n w = w.divide(w.sum());\n for (let j = 0; j < neighbors; ++j) {\n W.set_entry(row, nN_row[j].j, w.entry(j, 0));\n }\n }\n // comp embedding\n const I = new Matrix(rows, rows, \"identity\");\n const IW = I.sub(W);\n const M = IW.transDot(IW);\n\n // M is symmetric positive semi-definite. Smallest eigenvalue is 0 (ones vector).\n // To find smallest eigenvalues of M, we can find largest of (C*I - M)\n // Upper bound for max eigenvalue: Frobenius norm or sum of absolute values\n const C = M.mean() * rows * 2; // Safe upper bound for a sparse-ish M in LLE\n const CI_M = new Matrix(rows, rows, (i, j) => (i === j ? C : 0) - M.entry(i, j));\n\n const { eigenvectors: V } = simultaneous_poweriteration(CI_M, d + 1, eig_args);\n // Skip the first eigenvector (the ones vector corresponding to eigenvalue C)\n this.Y = Matrix.from(V.slice(1, 1 + d)).T;\n\n // return embedding\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new LLE(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new LLE(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new LLE(X, parameters);\n return dr.transform_async();\n }\n}\n","import { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { distance_matrix, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersMDS} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n\n/**\n * Classical Multidimensional Scaling (MDS)\n *\n * A linear dimensionality reduction technique that seeks to preserve the\n * pairwise distances between points as much as possible in the lower-dimensional\n * space.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link PCA} for another linear alternative\n */\nexport class MDS extends DR {\n /**\n * Classical MDS.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X, parameters = {}) {\n super(X, { d: 2, metric: euclidean, seed: 1212, eig_args: {} }, parameters);\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n if (!Object.hasOwn(eig_args, \"seed\")) {\n eig_args.seed = this._randomizer;\n }\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T}\n */\n transform() {\n const X = this.X;\n const rows = X.shape[0];\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const metric = /** @type {typeof euclidean | \"precomputed\"} */ (this.parameter(\"metric\"));\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n const A = metric === \"precomputed\" ? X : distance_matrix(X, metric);\n\n const D_sq = new Matrix(rows, rows, (i, j) => {\n const val = A.entry(i, j);\n return val * val;\n });\n\n const ai_ = D_sq.meanCols();\n const a_j = D_sq.meanRows();\n const a__ = D_sq.mean();\n\n this._d_X = A;\n const B = new Matrix(rows, rows, (i, j) => -0.5 * (D_sq.entry(i, j) - ai_[i] - a_j[j] + a__));\n\n const { eigenvectors: V } = simultaneous_poweriteration(B, d, eig_args);\n this.Y = Matrix.from(V).transpose();\n\n return this.projection;\n }\n\n /** @returns {number} - The stress of the projection. */\n stress() {\n const N = this.X.shape[0];\n const Y = this.Y;\n const d_X = this._d_X;\n if (!d_X) throw new Error(\"First transform!\");\n\n const d_Y = new Matrix(N, N, 0);\n d_Y.shape = [\n N,\n N,\n (i, j) => {\n return i < j ? euclidean(Y.row(i), Y.row(j)) : d_Y.entry(j, i);\n },\n ];\n let top_sum = 0;\n let bottom_sum = 0;\n for (let i = 0; i < N; ++i) {\n for (let j = i + 1; j < N; ++j) {\n top_sum += (d_X.entry(i, j) - d_Y.entry(i, j)) ** 2;\n bottom_sum += d_X.entry(i, j) ** 2;\n }\n }\n return Math.sqrt(top_sum / bottom_sum);\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new MDS(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new MDS(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new MDS(X, parameters);\n return dr.transform_async();\n }\n}\n","import { KMedoids } from \"../clustering/index.js\";\nimport { BallTree } from \"../knn/index.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\nimport { MDS } from \"./MDS.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLSP} from \"./index.js\" */\n\n/**\n * Least Square Projection (LSP)\n *\n * A dimensionality reduction technique that uses a small set of control points\n * (projected with MDS) to define the projection for the rest of the data\n * using a Laplacian-based optimization.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class LSP extends DR {\n /**\n * Least Squares Projection.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n * @see {@link https://ieeexplore.ieee.org/document/4378370}\n */\n constructor(X, parameters) {\n super(\n X,\n {\n neighbors: -Infinity,\n control_points: -Infinity,\n d: 2,\n metric: euclidean,\n seed: 1212,\n },\n parameters,\n );\n if (this.parameter(\"neighbors\") === -Infinity) {\n this.parameter(\"neighbors\", Math.min(Math.max(Math.floor(this._N / 10), 2), this._N - 1));\n }\n if (this.parameter(\"control_points\") === -Infinity) {\n this.parameter(\"control_points\", Math.min(Math.ceil(Math.sqrt(this._N)), this._N - 1));\n }\n this._is_initialized = false;\n }\n\n /**\n * @returns {LSP}\n */\n //\tinit(DR = MDS, DR_parameters = {}, KNN = BallTree) {\n init() {\n const DR = MDS;\n let DR_parameters = {};\n const KNN = BallTree;\n if (this._is_initialized) return this;\n const X = this.X;\n const N = this._N;\n const K = /** @type {number} */ (this.parameter(\"neighbors\"));\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const seed = /** @type {number} */ (this.parameter(\"seed\"));\n const metric = /** @type {typeof euclidean} */ (this.parameter(\"metric\"));\n DR_parameters = Object.assign({ d, metric, seed }, DR_parameters);\n const nc = /** @type {number} */ (this.parameter(\"control_points\"));\n const control_points = new KMedoids(X, { K: nc, metric }).get_medoids();\n const C = new Matrix(nc, N, \"zeros\");\n control_points.forEach((c_i, i) => {\n C.set_entry(i, c_i, 1);\n });\n\n const control_points_matrix = Matrix.from(control_points.map((c_i) => X.row(c_i)));\n const Y_C = new DR(control_points_matrix, DR_parameters).transform();\n\n const XA = X.to2dArray();\n const knn = new KNN(XA, { metric, seed });\n const L = new Matrix(N, N, \"I\");\n const alpha = -1 / K;\n XA.forEach((x_i, i) => {\n for (const { index: j } of knn.search(x_i, K)) {\n if (i === j) continue;\n L.set_entry(i, j, alpha);\n }\n });\n const A = L.concat(C, \"vertical\");\n\n const z = new Matrix(N, d, \"zeros\");\n const b = z.concat(Y_C, \"vertical\");\n\n this._A = A;\n this._b = b;\n this._is_initialized = true;\n return this;\n }\n\n /**\n * Computes the projection.\n *\n * @returns {T} Returns the projection.\n */\n transform() {\n this.check_init();\n const A = this._A;\n const b = this._b;\n\n if (!A || !b) throw new Error(\"Call init() first!\");\n const ATA = A.transDot(A);\n const ATb = A.transDot(b);\n this.Y = Matrix.solve_CG(ATA, ATb, this._randomizer);\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new LSP(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new LSP(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new LSP(X, parameters);\n return dr.transform_async();\n }\n}\n","import { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { k_nearest_neighbors, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLTSA} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n\n/**\n * Local Tangent Space Alignment (LTSA)\n *\n * A nonlinear dimensionality reduction algorithm that represents the local\n * geometry of the manifold by tangent spaces and then aligns them to reveal\n * the global structure.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class LTSA extends DR {\n /**\n * Local Tangent Space Alignment\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://epubs.siam.org/doi/abs/10.1137/S1064827502419154}\n */\n constructor(X, parameters) {\n super(\n X,\n {\n neighbors: -Infinity,\n d: 2,\n metric: euclidean,\n seed: 1212,\n eig_args: {},\n },\n parameters,\n );\n if (this.parameter(\"neighbors\") === -Infinity) {\n this.parameter(\"neighbors\", Math.min(Math.max(Math.floor(this._N / 10), 2), this._N - 1));\n }\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n if (!Object.hasOwn(eig_args, \"seed\")) {\n eig_args.seed = this._randomizer;\n }\n\n const d = /** @type {number} */ (this.parameter(\"d\"));\n if (this._D <= d) {\n throw new Error(\n `Dimensionality of X (D = ${this._D}) must be greater than the required dimensionality of the result (d = ${d})!`,\n );\n }\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimenionality `d`.\n *\n * @returns {T}\n */\n transform() {\n const X = this.X;\n const [rows, D] = X.shape;\n const neighbors = /** @type {number} */ (this.parameter(\"neighbors\"));\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n const metric = /** @type {typeof euclidean} */ (this.parameter(\"metric\"));\n // 1.1 determine k nearest neighbors\n const nN = k_nearest_neighbors(X, neighbors, metric);\n // center matrix\n const O = new Matrix(D, D, \"center\");\n const B = new Matrix(rows, rows, 0);\n\n for (let row = 0; row < rows; ++row) {\n // 1.2 compute the d largest eigenvectors of the correlation matrix\n const I_i = [row, ...nN[row].map((n) => n.j)];\n let X_i = Matrix.from(I_i.map((n) => X.row(n)));\n // center X_i\n X_i = X_i.dot(O);\n // correlation matrix\n const C = X_i.dotTrans(X_i);\n const { eigenvectors: g } = simultaneous_poweriteration(C, d, eig_args);\n //g.push(linspace(0, k).map(_ => 1 / Math.sqrt(k + 1)));\n const G_i_t = Matrix.from(g);\n // 2. Constructing alignment matrix\n const W_i = G_i_t.transDot(G_i_t).add(1 / Math.sqrt(neighbors + 1));\n for (let i = 0; i < neighbors + 1; ++i) {\n for (let j = 0; j < neighbors + 1; ++j) {\n B.add_entry(I_i[i], I_i[j], W_i.entry(i, j) - (i === j ? 1 : 0));\n }\n }\n }\n\n // 3. Aligning global coordinates\n const { eigenvectors: Y } = simultaneous_poweriteration(B, d + 1, eig_args);\n this.Y = Matrix.from(Y.slice(1)).transpose();\n\n // return embedding\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new LTSA(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new LTSA(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new LTSA(X, parameters);\n return dr.transform_async();\n }\n}\n","import { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersPCA} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n\n/**\n * Principal Component Analysis (PCA)\n *\n * A linear dimensionality reduction technique that identifies the axes (principal components)\n * along which the variance of the data is maximized.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link MDS} for another linear alternative\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2], [3, 4], [5, 6]];\n * const pca = new druid.PCA(X, { d: 2 });\n * const Y = pca.transform();\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class PCA extends DR {\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X, parameters = {}) {\n super(X, { d: 2, seed: 1212, eig_args: {} }, parameters);\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n if (!Object.hasOwn(eig_args, \"seed\")) {\n eig_args.seed = this._randomizer;\n }\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T} - The projected data.\n */\n transform() {\n const V = this.principal_components();\n const X = this.X;\n this.Y = X.dot(V);\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new PCA(X, parameters);\n return dr.transform();\n }\n\n /**\n * Computes the `d` principal components of Matrix `X`.\n *\n * @returns {Matrix}\n */\n principal_components() {\n if (this.V) {\n return this.V;\n }\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n const X = this.X;\n const X_cent = X.sub(X.meanCols());\n const C = X_cent.transDot(X_cent);\n const { eigenvectors: V } = simultaneous_poweriteration(C, d, eig_args);\n this.V = Matrix.from(V).transpose();\n return this.V;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Matrix}\n */\n static principal_components(X, parameters) {\n const dr = new PCA(X, parameters);\n return dr.principal_components();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new PCA(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new PCA(X, parameters);\n return dr.transform_async();\n }\n}\n","import { distance_matrix, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\nimport { MDS, PCA } from \"./index.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersPCA, ParametersMDS, ParametersSAMMON} from \"./index.js\" */\n/** @typedef {\"PCA\" | \"MDS\" | \"random\"} AvailableInit */\n\n/** @typedef {{ PCA: ParametersPCA; MDS: ParametersMDS; random: {} }} ChooseDR */\n\n/**\n * Sammon's Mapping\n *\n * A nonlinear dimensionality reduction technique that minimizes a stress\n * function based on the ratio of pairwise distances in high and low dimensional spaces.\n *\n * @class\n * @template {InputType} T\n * @extends DR>\n * @category Dimensionality Reduction\n */\nexport class SAMMON extends DR {\n /** @type {Matrix | undefined} */\n distance_matrix;\n\n /**\n * SAMMON's Mapping\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial>} [parameters] - Object containing parameterization of the DR\n * method.\n * @see {@link https://arxiv.org/pdf/2009.01512.pdf}\n */\n constructor(X, parameters) {\n super(\n X,\n {\n magic: 0.1,\n d: 2,\n metric: euclidean,\n seed: 1212,\n init_DR: \"random\",\n init_parameters: {},\n },\n parameters,\n );\n }\n\n /**\n * Initializes the projection.\n *\n * @param {Matrix | undefined} D\n * @returns {asserts D is Matrix}\n */\n init(D) {\n const N = this.X.shape[0];\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const metric = /** @type {typeof euclidean | \"precomputed\"} */ (this.parameter(\"metric\"));\n const init_DR = /** @type {AvailableInit} */ (this.parameter(\"init_DR\"));\n const DR_parameters = this.parameter(\"init_parameters\");\n if (init_DR === \"random\") {\n const randomizer = this._randomizer;\n this.Y = new Matrix(N, d, () => randomizer.random);\n } else if (init_DR === \"PCA\") {\n this.Y = Matrix.from(PCA.transform(this.X, /** @type {ParametersPCA} */ (DR_parameters)));\n } else if (init_DR === \"MDS\") {\n this.Y = Matrix.from(MDS.transform(this.X, /** @type {ParametersMDS} */ (DR_parameters)));\n } else {\n throw new Error('init_DR needs to be either \"random\" or a DR method!');\n }\n D = metric === \"precomputed\" ? Matrix.from(this.X) : distance_matrix(this.X, metric);\n this.distance_matrix = D;\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality 2.\n *\n * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200`\n * @returns {T} The projection of `X`.\n */\n transform(max_iter = 200) {\n this.check_init();\n if (!this.distance_matrix) this.init(this.distance_matrix);\n for (let j = 0; j < max_iter; ++j) {\n this._step();\n }\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimenionality 2.\n *\n * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200`\n * @returns {Generator} A generator yielding the intermediate steps of the projection of\n * `X`.\n */\n *generator(max_iter = 200) {\n this.check_init();\n if (!this.distance_matrix) this.init(this.distance_matrix);\n\n for (let j = 0; j < max_iter; ++j) {\n this._step();\n yield this.projection;\n }\n\n return this.projection;\n }\n\n _step() {\n if (!this.distance_matrix) this.init(this.distance_matrix);\n const MAGIC = /** @type {number} */ (this.parameter(\"magic\"));\n const D = /** @type {Matrix} */ (this.distance_matrix);\n const N = this.X.shape[0];\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const Y = this.Y;\n\n const G = new Matrix(N, d, 0);\n\n const sum = new Float64Array(d);\n for (let i = 0; i < N; ++i) {\n const e1 = new Float64Array(d);\n const e2 = new Float64Array(d);\n const Yi = Y.row(i);\n for (let j = 0; j < N; ++j) {\n if (i === j) continue;\n const dX = D.entry(i, j);\n if (dX === 0) continue; // Skip identical points in high-dim\n\n const Yj = Y.row(j);\n const delta = new Float64Array(d);\n for (let k = 0; k < d; ++k) {\n delta[k] = Yi[k] - Yj[k];\n }\n const dY = Math.max(euclidean(Yi, Yj), 1e-6);\n const dq = dX - dY;\n const dr = dX * dY;\n for (let k = 0; k < d; ++k) {\n e1[k] += (delta[k] * dq) / dr;\n e2[k] += (dq - (delta[k] ** 2 * (1 + dq / dY)) / dY) / dr;\n }\n }\n for (let k = 0; k < d; ++k) {\n const val = Y.entry(i, k) + ((MAGIC * e1[k]) / Math.abs(e2[k]) || 0);\n G.set_entry(i, k, val);\n sum[k] += val;\n }\n }\n for (let k = 0; k < d; ++k) {\n sum[k] /= N;\n }\n\n for (let i = 0; i < N; ++i) {\n for (let k = 0; k < d; ++k) {\n Y.set_entry(i, k, G.entry(i, k) - sum[k]);\n }\n }\n return Y;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial>} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new SAMMON(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial>} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new SAMMON(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial>} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new SAMMON(X, parameters);\n return dr.transform_async();\n }\n}\n","import { linspace, Matrix, norm } from \"../matrix/index.js\";\nimport { euclidean, euclidean_squared } from \"../metrics/index.js\";\nimport { neumair_sum } from \"../numerical/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersSQDMDS} from \"./index.js\" */\n\n/**\n * SQuadMDS (Stochastic Quartet MDS)\n *\n * A lean Stochastic Quartet MDS improving global structure preservation in\n * neighbor embedding like t-SNE and UMAP.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class SQDMDS extends DR {\n /**\n * SQuadMDS: a lean Stochastic Quartet MDS improving global structure preservation in neighbor embedding like t-SNE\n * and UMAP.\n *\n * @param {T} X\n * @param {Partial} [parameters]\n * @see {@link https://arxiv.org/pdf/2202.12087.pdf}\n */\n constructor(X, parameters) {\n super(\n X,\n {\n d: 2,\n metric: euclidean,\n seed: 1212,\n decay_start: 0.1,\n decay_cte: 0.34, // 0.34\n },\n parameters,\n );\n\n this.init();\n if (this.parameter(\"metric\") === \"precomputed\" && this.X.shape[0] !== this.X.shape[1]) {\n throw new Error(\"SQDMDS input data must be a square Matrix\");\n }\n }\n\n init() {\n const N = this._N;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n\n // initialize helpers.\n this._add = this.__add(d);\n this._sub_div = this.__sub_div(d);\n this._minus = this.__minus(d);\n this._mult = this.__mult(d);\n this._LR_init = Math.max(2, 0.005 * N);\n this._LR = this._LR_init;\n const decay_cte = /** @type {number} */ (this.parameter(\"decay_cte\"));\n this._offset = -Math.exp(-1 / decay_cte);\n this._momentums = new Matrix(N, d, 0);\n this._grads = new Matrix(N, d, 0);\n this._indices = linspace(0, N - 1);\n // initialize projection.\n const R = this._randomizer;\n this.Y = new Matrix(N, d, () => R.random - 0.5);\n\n // preparing metric for optimization.\n const this_metric = /** @type {Metric | \"precomputed\"} */ (this.parameter(\"metric\"));\n if (this_metric === \"precomputed\") {\n /** @type {(i: number, j: number, X: Matrix) => number} */\n this._HD_metric = (i, j, X) => X.entry(i, j);\n /** @type {(i: number, j: number, X: Matrix) => number} */\n this._HD_metric_exaggeration = (i, j, X) => X.entry(i, j) ** 2;\n } else {\n this._HD_metric = (i, j, X) => this_metric(X.row(i), X.row(j));\n if (this_metric === euclidean) {\n this._HD_metric_exaggeration = (i, j, X) => euclidean_squared(X.row(i), X.row(j));\n } else {\n this._HD_metric_exaggeration = (i, j, X) => this_metric(X.row(i), X.row(j)) ** 2;\n }\n }\n return;\n }\n\n /**\n * Computes the projection.\n *\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {T} The projection.\n */\n transform(iterations = 500) {\n this.check_init();\n const decay_start = /** @type {number} */ (this.parameter(\"decay_start\"));\n this._decay_start = Math.round(decay_start * iterations);\n for (let i = 0; i < iterations; ++i) {\n this._step(i, iterations);\n }\n return this.projection;\n }\n\n /**\n * Computes the projection.\n *\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {Generator} The intermediate steps of the projection.\n */\n *generator(iterations = 500) {\n this.check_init();\n const decay_start = /** @type {number} */ (this.parameter(\"decay_start\"));\n this._decay_start = Math.round(decay_start * iterations);\n for (let i = 0; i < iterations; ++i) {\n this._step(i, iterations);\n yield this.projection;\n }\n\n return this.projection;\n }\n\n /**\n * Performs an optimization step.\n *\n * @private\n * @param {number} i - Acutal iteration.\n * @param {number} iterations - Number of iterations.\n */\n _step(i, iterations) {\n if (this._LR_init === undefined || this._offset === undefined) throw new Error(\"Call init() first!\");\n\n const decay_start = /** @type {number} */ (this.parameter(\"decay_start\"));\n if (i > decay_start) {\n const decay_cte = /** @type {number} */ (this.parameter(\"decay_cte\"));\n const offset = this._offset;\n const ratio = (i - decay_start) / (iterations - decay_start);\n this._LR = this._LR_init * (Math.exp(-(ratio * ratio) / decay_cte) + offset);\n this._distance_exaggeration = false;\n } else {\n this._distance_exaggeration = true;\n }\n this._nestrov_iteration(this._distance_exaggeration);\n }\n\n /**\n * Creates quartets of non overlapping indices.\n *\n * @private\n * @returns {Uint32Array[]}\n */\n __quartets() {\n if (!this._indices) throw new Error(\"Call init() first!\");\n if (this._offset === undefined) throw new Error(\"Call init() first!\");\n const N = this._N;\n const max_N = N - (N % 4);\n const R = this._randomizer;\n const shuffled_indices = R.choice(this._indices, max_N);\n const result = [];\n for (let i = 0; i < max_N; i += 4) {\n result.push(\n Uint32Array.of(\n shuffled_indices[i],\n shuffled_indices[i + 1],\n shuffled_indices[i + 2],\n shuffled_indices[i + 3],\n ),\n );\n }\n return result;\n }\n\n /**\n * Computes and applies gradients, and updates momentum.\n *\n * @private\n * @param {boolean} distance_exaggeration\n */\n _nestrov_iteration(distance_exaggeration) {\n if (!this._momentums || !this._grads || this._LR === undefined) throw new Error(\"Call init() first!\");\n const momentums = this._momentums.mult(0.99, { inline: true });\n const LR = this._LR;\n const grads = this._fill_MDS_grads(this.Y.add(momentums), this._grads, distance_exaggeration);\n const [n, d] = momentums.shape;\n for (let i = 0; i < n; ++i) {\n const g_i = grads.row(i);\n const g_i_norm = norm(g_i);\n if (g_i_norm === 0) continue;\n const mul = LR / g_i_norm;\n const m_i = momentums.row(i);\n for (let j = 0; j < d; ++j) {\n m_i[j] -= mul * g_i[j];\n }\n } // momentums -= (LR / norm) * grads\n this.Y.add(momentums, { inline: true });\n }\n\n /**\n * Computes the gradients.\n *\n * @param {Matrix} Y - The Projection.\n * @param {Matrix} grads - The gradients.\n * @param {boolean} [exaggeration=false] - Whether or not to use early exaggeration. Default is `false`\n * @param {boolean} [zero_grad=true] - Whether or not to reset the gradient in the beginning. Default is `true`\n * @returns {Matrix} The gradients.\n */\n _fill_MDS_grads(Y, grads, exaggeration = false, zero_grad = true) {\n if (!this._HD_metric || !this._HD_metric_exaggeration || !this._add) throw new Error(\"Call init() first!\");\n if (zero_grad) {\n // compute new gradients\n grads.values.fill(0);\n }\n const add = this._add;\n const X = this.X;\n let HD_metric;\n if (exaggeration === true) {\n HD_metric = this._HD_metric_exaggeration;\n } else {\n HD_metric = this._HD_metric;\n }\n\n const D_quartet = new Float64Array(6);\n const quartets = this.__quartets();\n for (const [i, j, k, l] of quartets) {\n // compute quartet's HD distances.\n D_quartet[0] = HD_metric(i, j, X);\n D_quartet[1] = HD_metric(i, k, X);\n D_quartet[2] = HD_metric(i, l, X);\n D_quartet[3] = HD_metric(j, k, X);\n D_quartet[4] = HD_metric(j, l, X);\n D_quartet[5] = HD_metric(k, l, X);\n\n const D_quartet_sum = neumair_sum(D_quartet);\n\n if (D_quartet_sum > 0) {\n for (let i = 0; i < 6; ++i) {\n D_quartet[i] /= D_quartet_sum;\n D_quartet[i] += 1e-11;\n }\n }\n const [gi, gj, gk, gl] = this._compute_quartet_grads(Y, [i, j, k, l], D_quartet);\n\n // add is inline, row acces the matrix\n add(grads.row(i), gi);\n add(grads.row(j), gj);\n add(grads.row(k), gk);\n add(grads.row(l), gl);\n }\n return grads;\n }\n\n /**\n * Quartet gradients for a projection.\n *\n * @private\n * @param {Matrix} Y - The acutal projection.\n * @param {number[]} quartet - The indices of the quartet.\n * @param {Float64Array} D_hd - The high-dimensional distances of the quartet.\n * @returns {Float64Array[]} The gradients for the quartet.\n */\n _compute_quartet_grads(Y, quartet, [p_ab, p_ac, p_ad, p_bc, p_bd, p_cd]) {\n const [a, b, c, d] = quartet.map((index) => Y.row(index));\n // LD distances, add a small number just in case\n const d_ab = euclidean(a, b) + 1e-12;\n const d_ac = euclidean(a, c) + 1e-12;\n const d_ad = euclidean(a, d) + 1e-12;\n const d_bc = euclidean(b, c) + 1e-12;\n const d_bd = euclidean(b, d) + 1e-12;\n const d_cd = euclidean(c, d) + 1e-12;\n const sum_LD_dist = neumair_sum([d_ab, d_ac, d_ad, d_bc, d_bd, d_cd]);\n\n // for each element of the sum: use the same gradient function and just permute the points given in input.\n const [gA1, gB1, gC1, gD1] = this._ABCD_grads(\n a,\n b,\n c,\n d,\n d_ab,\n d_ac,\n d_ad,\n d_bc,\n d_bd,\n d_cd,\n p_ab,\n sum_LD_dist,\n );\n const [gA2, gC2, gB2, gD2] = this._ABCD_grads(\n a,\n c,\n b,\n d,\n d_ac,\n d_ab,\n d_ad,\n d_bc,\n d_cd,\n d_bd,\n p_ac,\n sum_LD_dist,\n );\n const [gA3, gD3, gC3, gB3] = this._ABCD_grads(\n a,\n d,\n c,\n b,\n d_ad,\n d_ac,\n d_ab,\n d_cd,\n d_bd,\n d_bc,\n p_ad,\n sum_LD_dist,\n );\n const [gB4, gC4, gA4, gD4] = this._ABCD_grads(\n b,\n c,\n a,\n d,\n d_bc,\n d_ab,\n d_bd,\n d_ac,\n d_cd,\n d_ad,\n p_bc,\n sum_LD_dist,\n );\n const [gB5, gD5, gA5, gC5] = this._ABCD_grads(\n b,\n d,\n a,\n c,\n d_bd,\n d_ab,\n d_bc,\n d_ad,\n d_cd,\n d_ac,\n p_bd,\n sum_LD_dist,\n );\n const [gC6, gD6, gA6, gB6] = this._ABCD_grads(\n c,\n d,\n a,\n b,\n d_cd,\n d_ac,\n d_bc,\n d_ad,\n d_bd,\n d_ab,\n p_cd,\n sum_LD_dist,\n );\n\n if (!this._add) throw new Error(\"Call init() first!\");\n const add = this._add;\n const gA = add(gA1, gA2, gA3, gA4, gA5, gA6);\n const gB = add(gB1, gB2, gB3, gB4, gB5, gB6);\n const gC = add(gC1, gC2, gC3, gC4, gC5, gC6);\n const gD = add(gD1, gD2, gD3, gD4, gD5, gD6);\n\n return [gA, gB, gC, gD];\n }\n\n /**\n * Gradients for one element of the loss function's sum.\n *\n * @private\n * @param {Float64Array} a\n * @param {Float64Array} b\n * @param {Float64Array} c\n * @param {Float64Array} d\n * @param {number} d_ab\n * @param {number} d_ac\n * @param {number} d_ad\n * @param {number} d_bc\n * @param {number} d_bd\n * @param {number} d_cd\n * @param {number} p_ab\n * @param {number} sum_LD_dist\n * @returns {Float64Array[]}\n */\n _ABCD_grads(a, b, c, d, d_ab, d_ac, d_ad, d_bc, d_bd, d_cd, p_ab, sum_LD_dist) {\n if (!this._minus || !this._add || !this._mult || !this._sub_div) throw new Error(\"Call init() first!\");\n const ratio = d_ab / sum_LD_dist;\n const twice_ratio = 2 * ((p_ab - ratio) / sum_LD_dist);\n const minus = this._minus;\n const add = this._add;\n const mult = this._mult;\n const sub_div = this._sub_div;\n // no side effects because sub_div creates new arrays, and the inline functions work on this new created arrays.\n const gA = mult(\n minus(mult(add(sub_div(a, b, d_ab), sub_div(a, c, d_ac), sub_div(a, d, d_ad)), ratio), sub_div(a, b, d_ab)),\n twice_ratio,\n );\n const gB = mult(\n minus(mult(add(sub_div(b, a, d_ab), sub_div(b, c, d_bc), sub_div(b, d, d_bd)), ratio), sub_div(b, a, d_ab)),\n twice_ratio,\n );\n const gC = mult(add(sub_div(c, a, d_ac), sub_div(c, b, d_bc), sub_div(c, d, d_cd)), ratio * twice_ratio);\n const gD = mult(add(sub_div(d, a, d_ad), sub_div(d, b, d_bd), sub_div(d, c, d_cd)), ratio * twice_ratio);\n return [gA, gB, gC, gD];\n }\n\n /**\n * Inline!\n *\n * @param {number} d\n */\n __minus(d) {\n return /** @type {(a: Float64Array, b: Float64Array) => Float64Array} */ (a, b) => {\n for (let i = 0; i < d; ++i) {\n a[i] -= b[i];\n }\n return a;\n };\n }\n\n /**\n * Inline!\n *\n * @param {number} d\n */\n __add(d) {\n return /** @type {(...summands: Float64Array[]) => Float64Array} */ (...summands) => {\n const n = summands.length;\n const s1 = summands[0];\n for (let j = 1; j < n; ++j) {\n const summand = summands[j];\n for (let i = 0; i < d; ++i) {\n s1[i] += summand[i];\n }\n }\n return s1;\n };\n }\n\n /**\n * Inline!\n *\n * @param {number} d\n */\n __mult(d) {\n return /** @type {(a: Float64Array, v: number) => Float64Array} */ (a, v) => {\n for (let i = 0; i < d; ++i) {\n a[i] *= v;\n }\n return a;\n };\n }\n\n /**\n * Creates a new array `(x - y) / div`.\n *\n * @param {number} d\n */\n __sub_div(d) {\n return /** @type {(x: Float64Array, y: Float64Array, div: number) => Float64Array} */ (x, y, div) => {\n return Float64Array.from({ length: d }, (_, i) => (x[i] - y[i]) / div);\n };\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new SQDMDS(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new SQDMDS(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new SQDMDS(X, parameters);\n return dr.transform_async();\n }\n}\n","import { DisjointSet } from \"../datastructure/index.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersTopoMap} from \"./index.js\" */\n\n/**\n * TopoMap\n *\n * A 0-dimensional Homology Preserving Projection of High-Dimensional Data.\n * It aims to preserve the topological structure of the data by maintaining\n * the connectivity of a minimum spanning tree.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class TopoMap extends DR {\n /**\n * TopoMap: A 0-dimensional Homology Preserving Projection of High-Dimensional Data.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://arxiv.org/pdf/2009.01512.pdf}\n */\n constructor(X, parameters) {\n super(X, { metric: euclidean, seed: 1212 }, parameters);\n [this._N, this._D] = this.X.shape;\n this._distance_matrix = new Matrix(this._N, this._N, -1);\n }\n\n /**\n * @private\n * @param {number} i\n * @param {number} j\n * @param {import(\"../metrics/index.js\").Metric} metric\n * @returns {number}\n */\n __lazy_distance_matrix(i, j, metric) {\n const D = this._distance_matrix;\n const X = this.X;\n const D_ij = D.entry(i, j);\n if (D_ij === -1 && i !== j) {\n const dist = metric(X.row(i), X.row(j));\n D.set_entry(i, j, dist);\n D.set_entry(j, i, dist);\n return dist;\n }\n return i === j ? 0 : D_ij;\n }\n\n /**\n * Computes the minimum spanning tree, using a given metric\n *\n * @private\n * @param {import(\"../metrics/index.js\").Metric} metric\n * @see {@link https://en.wikipedia.org/wiki/Kruskal%27s_algorithm}\n */\n _make_minimum_spanning_tree(metric = euclidean) {\n const N = this._N;\n const X = [...this.X];\n\n this._disjoint_set = new DisjointSet(X);\n const disjoint_set = this._disjoint_set;\n const F = [];\n let E = [];\n for (let i = 0; i < N; ++i) {\n for (let j = i + 1; j < N; ++j) {\n E.push([i, j, this.__lazy_distance_matrix(i, j, metric)]);\n }\n }\n E = E.sort((a, b) => a[2] - b[2]);\n\n for (const [u, v, w] of E) {\n const set_u = disjoint_set.find(X[u]);\n const set_v = disjoint_set.find(X[v]);\n if (!set_u || !set_v) throw new Error(\"Should not happen!\");\n if (set_u !== set_v) {\n F.push([u, v, w]);\n disjoint_set.union(set_u, set_v);\n }\n }\n\n return F.sort((a, b) => a[2] - b[2]);\n }\n\n /** Initializes TopoMap. Sets all projcted points to zero, and computes a minimum spanning tree. */\n init() {\n const { metric } = this._parameters;\n this.Y = new Matrix(this._N, 2, 0);\n this._Emst = this._make_minimum_spanning_tree(metric);\n this._is_initialized = true;\n return this;\n }\n\n /**\n * Returns true if Point C is left of line AB.\n *\n * @private\n * @param {Float64Array} PointA - Point A of line AB\n * @param {Float64Array} PointB - Point B of line AB\n * @param {Float64Array} PointC - Point C\n * @returns {boolean}\n */\n __hull_cross([ax, ay], [bx, by], [sx, sy]) {\n return (bx - ax) * (sy - ay) - (by - ay) * (sx - ax) <= 0;\n }\n\n /**\n * Computes the convex hull of the set of Points S\n *\n * @private\n * @param {Float64Array[]} S - Set of Points.\n * @returns {Float64Array[]} Convex hull of S. Starts at the bottom-most point and continues counter-clockwise.\n * @see {@link https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain#JavaScript}\n */\n __hull(S) {\n const points = S.sort(([x1, y1], [x2, y2]) => y1 - y2 || x1 - x2);\n const N = points.length;\n if (N <= 2) return points;\n\n const lower = [];\n for (let i = 0; i < N; ++i) {\n while (\n lower.length >= 2 &&\n this.__hull_cross(lower[lower.length - 2], lower[lower.length - 1], points[i])\n ) {\n lower.pop();\n }\n lower.push(points[i]);\n }\n const upper = [];\n for (let i = N - 1; i >= 0; --i) {\n while (\n upper.length >= 2 &&\n this.__hull_cross(upper[upper.length - 2], upper[upper.length - 1], points[i])\n ) {\n upper.pop();\n }\n upper.push(points[i]);\n }\n upper.pop();\n lower.pop();\n return lower.concat(upper);\n }\n\n /**\n * Finds the angle to rotate Point A and B to lie on a line parallel to the x-axis.\n *\n * @private\n * @param {Float64Array} PointA\n * @param {Float64Array} PointB\n * @returns {{ sin: number; cos: number }} Object containing the sinus- and cosinus-values for a rotation.\n */\n __findAngle([p1x, p1y], [p2x, p2y]) {\n const n = euclidean([p1x, p1y], [p2x, p2y]);\n if (n === 0)\n return {\n sin: 0,\n cos: 1,\n };\n const vec = [(p2x - p1x) / n, (p2y - p1y) / n];\n const cos = vec[0];\n let sin = Math.sqrt(1 - cos * cos);\n sin = vec[1] >= 0 ? -sin : sin;\n return {\n sin: sin,\n cos: cos,\n };\n }\n\n /**\n * @private\n * @param {Float64Array[]} hull\n * @param {Float64Array} p\n * @param {boolean} topEdge\n * @returns {{ sin: number; cos: number; tx: number; ty: number }}\n */\n __align_hull(hull, p, topEdge) {\n let v = -1;\n /** @type {number} */\n let d2 = -Infinity;\n for (let i = 0; i < hull.length; ++i) {\n const d = euclidean(hull[i], p);\n if (v === -1) {\n d2 = d;\n v = i;\n } else {\n if (d2 > d) {\n d2 = d;\n v = i;\n }\n }\n }\n\n const v1 = hull[v];\n let v2;\n if (topEdge) {\n v2 = hull[(v + 1) % hull.length];\n } else {\n v2 = hull[(v - 1 + hull.length) % hull.length];\n }\n\n /** @type {{ sin?: number; cos?: number; tx: number; ty: number }} */\n const transformation = {\n tx: -v1[0],\n ty: -v1[1],\n };\n\n if (hull.length >= 2) {\n const { sin, cos } = this.__findAngle(v1, v2);\n transformation.sin = sin;\n transformation.cos = cos;\n } else {\n transformation.sin = 0;\n transformation.cos = 1;\n }\n\n return /** @type {{ sin: number; cos: number; tx: number; ty: number }} */ (transformation);\n }\n\n /**\n * @private\n * @param {Float64Array} Point - The point which should get transformed.\n * @param {{ sin: number; cos: number; tx: number; ty: number }} Transformation - Contains the values for\n * translation and rotation.\n */\n __transform([px, py], { tx, ty, sin, cos }) {\n const x = px + tx;\n const y = py + ty;\n const xx = x * cos - y * sin;\n const yy = x * sin + y * cos;\n return [xx, yy];\n }\n\n /**\n * Calls `__transform` for each point in Set C\n *\n * @private\n * @param {Float64Array[]} C - Set of points.\n * @param {{ sin: number; cos: number; tx: number; ty: number }} t - Transform object.\n * @param {number} yOffset - Value to offset set C.\n */\n __transform_component(C, t, yOffset) {\n const N = C.length;\n for (let i = 0; i < N; ++i) {\n const c = C[i];\n const [cx, cy] = this.__transform(c, t);\n c[0] = cx;\n c[1] = cy + yOffset;\n }\n }\n\n /**\n * @private\n * @param {Float64Array} root_u - Root of component u\n * @param {Float64Array} root_v - Root of component v\n * @param {Float64Array} p_u - Point u\n * @param {Float64Array} p_v - Point v\n * @param {number} w - Edge weight w\n * @param {DisjointSet} components - The disjoint set containing the components\n */\n __align_components(root_u, root_v, p_u, p_v, w, components) {\n if (!components) throw new Error(\"components not provided!\");\n const u_children = components.get_children(root_u);\n const v_children = components.get_children(root_v);\n if (!u_children || !v_children) throw new Error(\"should not happen!\");\n\n const points_u = [...u_children];\n const points_v = [...v_children];\n\n const hull_u = this.__hull(points_u);\n const hull_v = this.__hull(points_v);\n\n const t_u = this.__align_hull(hull_u, p_u, false);\n const t_v = this.__align_hull(hull_v, p_v, true);\n\n this.__transform_component(points_u, t_u, 0);\n this.__transform_component(points_v, t_v, w);\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality 2.\n *\n * @returns {T}\n */\n transform() {\n if (!this._is_initialized) this.init();\n if (!this._Emst) throw new Error(\"Call init() first!\");\n const Emst = this._Emst;\n const Y = this.Y.to2dArray();\n /** @type {DisjointSet} */\n const components = new DisjointSet(\n Y,\n // Y.map((y, i) => {\n // y.i = i;\n // return y;\n // }),\n );\n\n for (const [u, v, w] of Emst) {\n const p_u = Y[u];\n const p_v = Y[v];\n const component_u = components.find(p_u);\n const component_v = components.find(p_v);\n if (!component_u || !component_v) throw new Error(\"Should not happen!\");\n if (component_u === component_v) continue;\n this.__align_components(component_u, component_v, p_u, p_v, w, components);\n components.union(component_u, component_v);\n }\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality 2.\n *\n * @returns {Generator}\n */\n *generator() {\n if (!this._is_initialized) this.init();\n if (!this._Emst) throw new Error(\"call init() first!\");\n const Emst = this._Emst;\n const Y = this.Y.to2dArray();\n const components = new DisjointSet(\n Y,\n // Y.map((y, i) => {\n // y.i = i;\n // return y;\n // }),\n );\n\n for (const [u, v, w] of Emst) {\n const p_u = Y[u];\n const p_v = Y[v];\n const component_u = components.find(p_u);\n const component_v = components.find(p_v);\n if (!component_u || !component_v) throw new Error(\"should not happen!\");\n if (component_u === component_v) continue;\n this.__align_components(component_u, component_v, p_u, p_v, w, components);\n components.union(component_u, component_v);\n yield this.projection;\n }\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new TopoMap(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new TopoMap(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new TopoMap(X, parameters);\n return dr.transform_async();\n }\n}\n","import { BallTree } from \"../knn/index.js\";\nimport { linspace, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\nimport { PCA } from \"./PCA.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersTriMap} from \"./index.js\" */\n/** @import {KNN} from \"../knn/KNN.js\" */\n\n/**\n * TriMap\n *\n * A dimensionality reduction technique that preserves both local and global\n * structure using triplets. It is designed to be a more robust alternative\n * to t-SNE and UMAP.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class TriMap extends DR {\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n * @see {@link https://arxiv.org/pdf/1910.00204v1.pdf}\n * @see {@link https://github.com/eamid/trimap}\n */\n constructor(X, parameters) {\n super(\n X,\n {\n weight_adj: 500,\n n_inliers: 10,\n n_outliers: 5,\n n_random: 5,\n d: 2,\n metric: euclidean,\n tol: 1e-8,\n seed: 1212,\n },\n parameters,\n );\n }\n\n /**\n * @param {Matrix | null} [pca=null] - Initial Embedding (if null then PCA gets used). Default is `null`\n * @param {import(\"../knn/KNN.js\").KNN | null} [knn=null] - KNN Object (if null then BallTree gets used). Default is `null`\n */\n init(pca = null, knn = null) {\n const X = this.X;\n const N = X.shape[0];\n //const c = /** @type {number} */ (this._parameters.c);\n const d = /** @type {number} */ (this._parameters.d);\n const metric = /** @type {Metric} */ (this._parameters.metric);\n const seed = /** @type {number} */ (this._parameters.seed);\n this.n_inliers = /** @type {number} */ (this._parameters.n_inliers);\n this.n_outliers = /** @type {number} */ (this._parameters.n_outliers);\n this.n_random = /** @type {number} */ (this._parameters.n_random);\n this.Y = pca ?? PCA.transform(X, { d, seed });\n this.knn = knn ?? new BallTree(X.to2dArray(), { metric, seed });\n const { triplets, weights } = this._generate_triplets(this.n_inliers, this.n_outliers, this.n_random);\n this.triplets = triplets;\n this.weights = weights;\n this.lr = (1000 * N) / triplets.shape[0];\n this.C = Infinity;\n this.vel = new Matrix(N, d, 0);\n this.gain = new Matrix(N, d, 1);\n return this;\n }\n\n /**\n * Generates {@link n_inliers} x {@link n_outliers} x {@link n_random} triplets.\n *\n * @param {number} n_inliers\n * @param {number} n_outliers\n * @param {number} n_random\n */\n _generate_triplets(n_inliers, n_outliers, n_random) {\n const metric = /** @type {Metric} */ (this._parameters.metric);\n const weight_adj = /** @type {number} */ (this._parameters.weight_adj);\n const X = this.X;\n const N = X.shape[0];\n const knn = this.knn;\n if (!knn) throw new Error(\"Call init() first!\");\n const n_extra = Math.min(n_inliers + 20, N);\n const nbrs = new Matrix(N, n_extra);\n const knn_distances = new Matrix(N, n_extra);\n for (let i = 0; i < N; ++i) {\n const results = knn\n .search(X.row(i), n_extra + 1)\n .filter((d) => d.distance !== 0)\n .sort((a, b) => a.distance - b.distance);\n\n results.forEach((d, j) => {\n if (j < n_extra) {\n nbrs.set_entry(i, j, d.index);\n knn_distances.set_entry(i, j, d.distance);\n }\n });\n }\n // scale parameter\n const sig = new Float64Array(N);\n for (let i = 0; i < N; ++i) {\n sig[i] = Math.max(\n (knn_distances.entry(i, 3) + knn_distances.entry(i, 4) + knn_distances.entry(i, 5)) / 3,\n 1e-10,\n );\n }\n\n const P = this._find_p(knn_distances, sig, nbrs);\n\n let triplets = this._sample_knn_triplets(P, nbrs, n_inliers, n_outliers);\n let n_triplets = triplets.shape[0];\n const outlier_distances = new Float64Array(n_triplets);\n for (let i = 0; i < n_triplets; ++i) {\n const j = triplets.entry(i, 0);\n const k = triplets.entry(i, 2);\n outlier_distances[i] = metric(X.row(j), X.row(k));\n }\n let weights = this._find_weights(triplets, P, nbrs, outlier_distances, sig);\n\n if (n_random > 0) {\n const { random_triplets, random_weights } = this._sample_random_triplets(X, n_random, sig);\n triplets = triplets.concat(random_triplets, \"vertical\");\n weights = Float64Array.from([...weights, ...random_weights]);\n }\n n_triplets = triplets.shape[0];\n let max_weight = -Infinity;\n for (let i = 0; i < n_triplets; ++i) {\n if (Number.isNaN(weights[i])) {\n weights[i] = 0;\n }\n if (max_weight < weights[i]) max_weight = weights[i];\n }\n let max_weight_2 = -Infinity;\n for (let i = 0; i < n_triplets; ++i) {\n weights[i] /= max_weight;\n weights[i] += 0.0001;\n weights[i] = Math.log(1 + weight_adj * weights[i]);\n if (max_weight_2 < weights[i]) max_weight_2 = weights[i];\n }\n for (let i = 0; i < n_triplets; ++i) {\n weights[i] /= max_weight_2;\n }\n return {\n triplets: triplets,\n weights: weights,\n };\n }\n\n /**\n * Calculates the similarity matrix P\n *\n * @private\n * @param {Matrix} knn_distances - Matrix of pairwise knn distances\n * @param {Float64Array} sig - Scaling factor for the distances\n * @param {Matrix} nbrs - Nearest neighbors\n * @returns {Matrix} Pairwise similarity matrix\n */\n _find_p(knn_distances, sig, nbrs) {\n const [N, n_neighbors] = knn_distances.shape;\n return new Matrix(N, n_neighbors, (i, j) => {\n return Math.exp(-(knn_distances.entry(i, j) ** 2 / sig[i] / sig[nbrs.entry(i, j)]));\n });\n }\n\n /**\n * Sample nearest neighbors triplets based on the similarity values given in P.\n *\n * @private\n * @param {Matrix} P - Matrix of pairwise similarities between each point and its neighbors given in matrix nbrs.\n * @param {Matrix} nbrs - Nearest neighbors indices for each point. The similarity values are given in matrix\n * {@link P}. Row i corresponds to the i-th point.\n * @param {number} n_inliers - Number of inlier points.\n * @param {number} n_outliers - Number of outlier points.\n */\n _sample_knn_triplets(P, nbrs, n_inliers, n_outliers) {\n const N = nbrs.shape[0];\n const triplets_list = [];\n for (let i = 0; i < N; ++i) {\n const sort_indices = this.__argsort(P.row(i));\n for (let j = 0; j < n_inliers; ++j) {\n const sim = nbrs.entry(i, sort_indices[sort_indices[j] === i ? j + 1 : j]);\n const rejects = [i, ...Array.from(sort_indices.slice(0, j + 2)).map((idx) => nbrs.entry(i, idx))];\n const samples = this._rejection_sample(n_outliers, N, rejects);\n for (let k = 0; k < samples.length; ++k) {\n const out = samples[k];\n triplets_list.push([i, sim, out]);\n }\n }\n }\n const triplets = new Matrix(triplets_list.length, 3);\n for (let t = 0; t < triplets_list.length; ++t) {\n triplets.set_entry(t, 0, triplets_list[t][0]);\n triplets.set_entry(t, 1, triplets_list[t][1]);\n triplets.set_entry(t, 2, triplets_list[t][2]);\n }\n return triplets;\n }\n\n /**\n * Should do the same as np.argsort()\n *\n * @private\n * @param {Float64Array | number[]} A\n */\n __argsort(A) {\n return linspace(0, A.length - 1).sort((i, j) => A[j] - A[i]);\n }\n\n /**\n * Samples {@link n_samples} integers from a given interval [0, {@link max_int}] while rejection the values that are\n * in the {@link rejects}.\n *\n * @private\n * @param {number} n_samples\n * @param {number} max_int\n * @param {number[]} rejects\n */\n _rejection_sample(n_samples, max_int, rejects) {\n const randomizer = this._randomizer;\n const interval = linspace(0, max_int - 1).filter((d) => rejects.indexOf(d) < 0);\n return randomizer.choice(interval, Math.min(n_samples, interval.length));\n }\n\n /**\n * Calculates the weights for the sampled nearest neighbors triplets\n *\n * @private\n * @param {Matrix} triplets - Sampled Triplets.\n * @param {Matrix} P - Pairwise similarity matrix.\n * @param {Matrix} nbrs - Nearest Neighbors\n * @param {Float64Array} outlier_distances - Matrix of pairwise outlier distances\n * @param {Float64Array} sig - Scaling factor for the distances.\n */\n _find_weights(triplets, P, nbrs, outlier_distances, sig) {\n const n_triplets = triplets.shape[0];\n const weights = new Float64Array(n_triplets);\n for (let t = 0; t < n_triplets; ++t) {\n const i = triplets.entry(t, 0);\n const sim = nbrs.row(i).indexOf(triplets.entry(t, 1));\n const p_sim = P.entry(i, sim);\n let p_out = Math.exp(-(outlier_distances[t] ** 2 / (sig[i] * sig[triplets.entry(t, 2)])));\n if (p_out < 1e-20) p_out = 1e-20;\n weights[t] = p_sim / p_out;\n }\n return weights;\n }\n\n /**\n * Sample uniformly ranom triplets\n *\n * @private\n * @param {Matrix} X - Data matrix.\n * @param {number} n_random - Number of random triplets per point\n * @param {Float64Array} sig - Scaling factor for the distances\n */\n _sample_random_triplets(X, n_random, sig) {\n const metric = /** @type {Metric} */ (this.parameter(\"metric\"));\n const randomizer = this._randomizer;\n const N = X.shape[0];\n const random_triplets = new Matrix(N * n_random, 3);\n const random_weights = new Float64Array(N * n_random);\n for (let i = 0; i < N; ++i) {\n const n_i = i * n_random;\n const indices = Array.from({ length: N }, (_, idx) => idx).filter((idx) => idx !== i);\n for (let j = 0; j < n_random; ++j) {\n let [sim, out] = randomizer.choice(indices, 2);\n let p_sim = Math.exp(-(metric(X.row(i), X.row(sim)) ** 2 / (sig[i] * sig[sim])));\n if (p_sim < 1e-20) p_sim = 1e-20;\n let p_out = Math.exp(-(metric(X.row(i), X.row(out)) ** 2 / (sig[i] * sig[out])));\n if (p_out < 1e-20) p_out = 1e-20;\n\n if (p_sim < p_out) {\n [sim, out] = [out, sim];\n [p_sim, p_out] = [p_out, p_sim];\n }\n const index = n_i + j;\n random_triplets.set_entry(index, 0, i);\n random_triplets.set_entry(index, 1, sim);\n random_triplets.set_entry(index, 2, out);\n random_weights[index] = 0.1 * (p_sim / p_out);\n }\n }\n return {\n random_triplets: random_triplets,\n random_weights: random_weights,\n };\n }\n\n /**\n * Computes the gradient for updating the embedding.\n *\n * @param {Matrix} Y - The embedding\n */\n _grad(Y) {\n const n_inliers = this.n_inliers;\n const n_outliers = this.n_outliers;\n const triplets = this.triplets;\n const weights = this.weights;\n if (!triplets || n_inliers === undefined || n_outliers === undefined || !weights)\n throw new Error(\"Call init() first!\");\n const [N, dim] = Y.shape;\n const n_triplets = triplets.shape[0];\n const grad = new Matrix(N, dim, 0);\n const y_ij = new Float64Array(dim);\n const y_ik = new Float64Array(dim);\n let d_ij = 1;\n let d_ik = 1;\n let n_viol = 0;\n let loss = 0;\n const n_knn_triplets = N * n_inliers * n_outliers;\n\n for (let t = 0; t < n_triplets; ++t) {\n const [i, j, k] = triplets.row(t);\n // update y_ij, y_ik, d_ij, d_ik\n if (t % n_outliers === 0 || t >= n_knn_triplets) {\n d_ij = 1;\n d_ik = 1;\n for (let d = 0; d < dim; ++d) {\n const Y_id = Y.entry(i, d);\n const Y_jd = Y.entry(j, d);\n const Y_kd = Y.entry(k, d);\n y_ij[d] = Y_id - Y_jd;\n y_ik[d] = Y_id - Y_kd;\n d_ij += y_ij[d] ** 2;\n d_ik += y_ik[d] ** 2;\n }\n // update y_ik and d_ik only\n } else {\n d_ik = 1;\n for (let d = 0; d < dim; ++d) {\n const Y_id = Y.entry(i, d);\n const Y_kd = Y.entry(k, d);\n y_ik[d] = Y_id - Y_kd;\n d_ik += y_ik[d] ** 2;\n }\n }\n\n if (d_ij > d_ik) ++n_viol;\n loss += weights[t] / (1 + d_ik / d_ij);\n const w = weights[t] / (d_ij + d_ik) ** 2;\n for (let d = 0; d < dim; ++d) {\n const gs = y_ij[d] * d_ik * w;\n const go = y_ik[d] * d_ij * w;\n grad.add_entry(i, d, gs - go);\n grad.sub_entry(j, d, gs);\n grad.add_entry(k, d, go);\n }\n }\n return { grad, loss, n_viol };\n }\n\n /**\n * @param {number} max_iteration\n * @returns {T}\n */\n transform(max_iteration = 800) {\n this.check_init();\n for (let iter = 0; iter < max_iteration; ++iter) {\n this._next(iter);\n }\n return this.projection;\n }\n\n /**\n * @param {number} max_iteration\n * @returns {Generator}\n */\n *generator(max_iteration = 800) {\n this.check_init();\n for (let iter = 0; iter < max_iteration; ++iter) {\n this._next(iter);\n yield this.projection;\n }\n return this.projection;\n }\n\n /**\n * Does the iteration step.\n *\n * @private\n * @param {number} iter\n */\n _next(iter) {\n const gamma = iter > 250 ? 0.5 : 0.3;\n const old_C = this.C;\n const vel = this.vel;\n if (!vel || old_C === undefined || this.lr === undefined) throw new Error(\"Call init() first!\");\n const Y = this.Y.add(vel.mult(gamma));\n const { grad, loss } = this._grad(Y);\n this.C = loss;\n this.Y = this._update_embedding(Y, iter, grad);\n const tol = /** @type {number} */ (this.parameter(\"tol\"));\n this.lr *= old_C > loss + tol ? 1.01 : 0.9;\n return this.Y;\n }\n\n /**\n * Updates the embedding.\n *\n * @private\n * @param {Matrix} Y\n * @param {number} iter\n * @param {Matrix} grad\n */\n _update_embedding(Y, iter, grad) {\n const [N, dim] = Y.shape;\n const gamma = iter > 250 ? 0.8 : 0.5; // moment parameter\n const min_gain = 0.01;\n const gain = this.gain;\n const vel = this.vel;\n const lr = this.lr;\n if (!vel || !gain || lr === undefined) throw new Error(\"Call init() first!\");\n for (let i = 0; i < N; ++i) {\n for (let d = 0; d < dim; ++d) {\n const new_gain =\n Math.sign(vel.entry(i, d)) !== Math.sign(grad.entry(i, d))\n ? gain.entry(i, d) + 0.2\n : Math.max(gain.entry(i, d) * 0.8, min_gain);\n gain.set_entry(i, d, new_gain);\n vel.set_entry(i, d, gamma * vel.entry(i, d) - lr * gain.entry(i, d) * grad.entry(i, d));\n Y.set_entry(i, d, Y.entry(i, d) + vel.entry(i, d));\n }\n }\n return Y;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new TriMap(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new TriMap(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new TriMap(X, parameters);\n return dr.transform_async();\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { euclidean_squared } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersTSNE} from \"./index.js\" */\n/**\n * t-SNE (t-Distributed Stochastic Neighbor Embedding)\n *\n * A nonlinear dimensionality reduction technique particularly well-suited\n * for visualizing high-dimensional data in 2D or 3D. Preserves local\n * structure while revealing global patterns.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link https://lvdmaaten.github.io/tsne/|t-SNE Paper}\n * @see {@link UMAP} for faster alternative with similar results\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];\n * const tsne = new druid.TSNE(X, {\n * perplexity: 30,\n * epsilon: 10,\n * d: 2,\n * seed: 42\n * });\n *\n * const Y = tsne.transform(500); // 500 iterations\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class TSNE extends DR {\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X, parameters) {\n super(\n X,\n {\n perplexity: 50,\n epsilon: 10,\n d: 2,\n metric: euclidean_squared,\n seed: 1212,\n },\n parameters,\n );\n [this._N, this._D] = this.X.shape;\n this._iter = 0;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n this.Y = new Matrix(this._N, d, () => this._randomizer.gauss_random() * 1e-4);\n }\n\n init() {\n // init\n const perplexity = /** @type {number} */ (this.parameter(\"perplexity\"));\n const Htarget = Math.log(perplexity);\n const N = this._N;\n const D = this._D;\n const metric = /** @type {Metric | \"precomputed\"} */ (this._parameters.metric);\n const X = this.X;\n let Delta;\n if (metric === \"precomputed\") {\n Delta = Matrix.from(X);\n } else {\n Delta = new Matrix(N, N);\n for (let i = 0; i < N; ++i) {\n const X_i = X.row(i);\n for (let j = i + 1; j < N; ++j) {\n const distance = metric(X_i, X.row(j));\n Delta.set_entry(i, j, distance);\n Delta.set_entry(j, i, distance);\n }\n }\n }\n\n const P = new Matrix(N, N, 0);\n\n this._ystep = new Matrix(N, D, 0);\n this._gains = new Matrix(N, D, 1);\n\n // search for fitting sigma\n const tol = 1e-4;\n const maxtries = 50;\n for (let i = 0; i < N; ++i) {\n const dist_i = Delta.row(i);\n const prow = P.row(i);\n let betamin = -Infinity;\n let betamax = Infinity;\n let beta = 1;\n let cnt = maxtries;\n let done = false;\n let psum = 0;\n\n while (!done && cnt--) {\n // compute entropy and kernel row with beta precision\n psum = 0;\n let dp_sum = 0;\n for (let j = 0; j < N; ++j) {\n const dist = dist_i[j];\n const pj = i !== j ? Math.exp(-dist * beta) : 0;\n dp_sum += dist * pj;\n prow[j] = pj;\n psum += pj;\n }\n // compute entropy\n const H = psum > 0 ? Math.log(psum) + (beta * dp_sum) / psum : 0;\n if (H > Htarget) {\n betamin = beta;\n beta = betamax === Infinity ? beta * 2 : (beta + betamax) / 2;\n } else {\n betamax = beta;\n beta = betamin === -Infinity ? beta / 2 : (beta + betamin) / 2;\n }\n done = Math.abs(H - Htarget) < tol;\n }\n // normalize p\n for (let j = 0; j < N; ++j) {\n prow[j] /= psum;\n }\n }\n\n // compute probabilities\n const N2 = N * 2;\n for (let i = 0; i < N; ++i) {\n for (let j = i; j < N; ++j) {\n const p = Math.max((P.entry(i, j) + P.entry(j, i)) / N2, 1e-100);\n P.set_entry(i, j, p);\n P.set_entry(j, i, p);\n }\n }\n this._P = P;\n return this;\n }\n\n /**\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {T} The projection.\n */\n transform(iterations = 500) {\n this.check_init();\n for (let i = 0; i < iterations; ++i) {\n this.next();\n }\n return this.projection;\n }\n\n /**\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {Generator} - The projection.\n */\n *generator(iterations = 500) {\n this.check_init();\n for (let i = 0; i < iterations; ++i) {\n this.next();\n yield this.projection;\n }\n return this.projection;\n }\n\n /**\n * Performs a optimization step\n *\n * @private\n * @returns {Matrix}\n */\n next() {\n const iter = ++this._iter;\n if (!this._P || !this._ystep || !this._gains) throw new Error(\"Call init() first!\");\n const P = this._P;\n const ystep = this._ystep;\n const gains = this._gains;\n const N = this._N;\n const dim = /** @type {number} */ (this._parameters.d);\n const epsilon = /** @type {number} */ (this._parameters.epsilon);\n const Y = this.Y;\n\n //calc cost gradient;\n const pmul = iter < 100 ? 4 : 1;\n\n // compute Q dist (unnormalized)\n const Qu = new Matrix(N, N, \"zeros\");\n let qsum = 0;\n for (let i = 0; i < N; ++i) {\n for (let j = i + 1; j < N; ++j) {\n let dsum = 0;\n for (let d = 0; d < dim; ++d) {\n const dhere = Y.entry(i, d) - Y.entry(j, d);\n dsum += dhere * dhere;\n }\n const qu = 1 / (1 + dsum);\n Qu.set_entry(i, j, qu);\n Qu.set_entry(j, i, qu);\n qsum += 2 * qu;\n }\n }\n\n // normalize Q dist\n const Q = new Matrix(N, N, 0);\n for (let i = 0; i < N; ++i) {\n for (let j = i + 1; j < N; ++j) {\n const val = Math.max(Qu.entry(i, j) / qsum, 1e-100);\n Q.set_entry(i, j, val);\n Q.set_entry(j, i, val);\n }\n }\n\n const grad = new Matrix(N, dim, \"zeros\");\n for (let i = 0; i < N; ++i) {\n for (let j = 0; j < N; ++j) {\n const premult = 4 * (pmul * P.entry(i, j) - Q.entry(i, j)) * Qu.entry(i, j);\n for (let d = 0; d < dim; ++d) {\n grad.add_entry(i, d, premult * (Y.entry(i, d) - Y.entry(j, d)));\n }\n }\n }\n\n // perform gradient step\n const ymean = new Float64Array(dim);\n for (let i = 0; i < N; ++i) {\n for (let d = 0; d < dim; ++d) {\n const gid = grad.entry(i, d);\n const sid = ystep.entry(i, d);\n const gainid = gains.entry(i, d);\n\n let newgain = Math.sign(gid) === Math.sign(sid) ? gainid * 0.8 : gainid + 0.2;\n if (newgain < 0.01) newgain = 0.01;\n gains.set_entry(i, d, newgain);\n\n const momval = iter < 250 ? 0.5 : 0.8;\n const newsid = momval * sid - epsilon * newgain * gid;\n ystep.set_entry(i, d, newsid);\n\n Y.add_entry(i, d, newsid);\n ymean[d] += Y.entry(i, d);\n }\n }\n\n for (let i = 0; i < N; ++i) {\n for (let d = 0; d < dim; ++d) {\n Y.sub_entry(i, d, ymean[d] / N);\n }\n }\n\n return this.Y;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new TSNE(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new TSNE(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new TSNE(X, parameters);\n return dr.transform_async();\n }\n}\n","/**\n * @template {Float64Array | number[]} T\n * @category Optimization\n * @param {(d: T) => number} f\n * @param {T} x0\n * @param {number} [max_iter=300] Default is `300`\n * @returns {T}\n * @see http://optimization-js.github.io/optimization-js/optimization.js.html#line438\n */\nexport function powell(f, x0, max_iter = 300) {\n const epsilon = 1e-2;\n const n = x0.length;\n let alpha = 1e-3;\n let pfx = 10000;\n const x = /** @type {T} */ (x0.slice());\n let fx = f(x);\n let convergence = false;\n\n while (max_iter-- >= 0 && !convergence) {\n convergence = true;\n for (let i = 0; i < n; ++i) {\n x[i] += 1e-6;\n const fxi = f(x);\n x[i] -= 1e-6;\n const dx = (fxi - fx) / 1e-6;\n if (Math.abs(dx) > epsilon) {\n convergence = false;\n }\n x[i] -= alpha * dx;\n fx = f(x);\n }\n alpha *= pfx >= fx ? 1.05 : 0.4;\n pfx = fx;\n }\n return x;\n}\n","import { BallTree, NaiveKNN } from \"../knn/index.js\";\nimport { linspace, Matrix } from \"../matrix/index.js\";\nimport { euclidean, euclidean_squared } from \"../metrics/index.js\";\nimport { neumair_sum } from \"../numerical/index.js\";\nimport { powell } from \"../optimization/index.js\";\nimport { max } from \"../util/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersUMAP} from \"./index.js\" */\n\n/**\n * Uniform Manifold Approximation and Projection (UMAP)\n *\n * A novel manifold learning technique for dimensionality reduction. UMAP is constructed\n * from a theoretical framework based on Riemannian geometry and algebraic topology.\n * It is often faster than t-SNE while preserving more of the global structure.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link https://arxiv.org/abs/1802.03426|UMAP Paper}\n * @see {@link TSNE} for a similar visualization technique\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];\n * const umap = new druid.UMAP(X, {\n * n_neighbors: 15,\n * min_dist: 0.1,\n * d: 2,\n * seed: 42\n * });\n *\n * const Y = umap.transform(500); // 500 iterations\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class UMAP extends DR {\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X, parameters) {\n super(\n X,\n {\n n_neighbors: 15,\n local_connectivity: 1,\n min_dist: 1,\n d: 2,\n metric: euclidean,\n seed: 1212,\n _spread: 1,\n _set_op_mix_ratio: 1,\n _repulsion_strength: 1,\n _negative_sample_rate: 5,\n _n_epochs: 350,\n _initial_alpha: 1,\n },\n parameters,\n );\n [this._N, this._D] = this.X.shape;\n const n_neighbors = /** @type {number} */ (this.parameter(\"n_neighbors\"));\n const local_connectivity = /** @type {number} */ (this.parameter(\"local_connectivity\"));\n const d = /** @type {number} */ (this.parameter(\"d\"));\n /* let n_neighbors = Math.min(this._N - 1, parameters.n_neighbors);\n this.parameter(\"n_neighbors\", n_neighbors);\n this.parameter(\"local_connectivity\", Math.min(this.parameter(\"local_connectivity\"), n_neighbors - 1)); */\n if (n_neighbors > this._N) {\n throw new Error(\n `Parameter n_neighbors (=${n_neighbors}) needs to be smaller than dataset size (N=${this._N})!`,\n );\n }\n if (local_connectivity > n_neighbors) {\n throw new Error(\n `Parameter local_connectivity (=${local_connectivity}) needs to be smaller than parameter n_neighbors (=${n_neighbors})`,\n );\n }\n this._iter = 0;\n const randomizer = this._randomizer;\n this.Y = new Matrix(this._N, d, () => randomizer.random);\n }\n\n /**\n * @private\n * @param {number} spread\n * @param {number} min_dist\n * @returns {number[]}\n */\n _find_ab_params(spread, min_dist) {\n /** @type {(x: number, a: number, b: number) => number} */\n const curve = (x, a, b) => 1 / (1 + a * x ** (2 * b));\n const xv = linspace(0, spread * 3, 300);\n const yv = linspace(0, spread * 3, 300);\n\n for (let i = 0, n = xv.length; i < n; ++i) {\n const xv_i = xv[i];\n yv[i] = xv_i < min_dist ? 1 : Math.exp(-(xv_i - min_dist) / spread);\n }\n\n /** @type {(p: [number, number]) => number} */\n const err = (p) => {\n const error = linspace(1, 300).map((_, i) => yv[i] - curve(xv[i], p[0], p[1]));\n return Math.sqrt(neumair_sum(error.map((e) => e * e)));\n };\n\n return powell(err, [1, 1]);\n }\n\n /**\n * @private\n * @param {{ element: Float64Array; index: number; distance: number }[][]} distances\n * @param {number[]} sigmas\n * @param {number[]} rhos\n * @returns {{ element: Float64Array; index: number; distance: number }[][]}\n */\n _compute_membership_strengths(distances, sigmas, rhos) {\n for (let i = 0, n = distances.length; i < n; ++i) {\n const rho = rhos[i];\n const curr_dist = distances[i];\n for (let j = 0, m = curr_dist.length; j < m; ++j) {\n const v = curr_dist[j].distance - rho;\n curr_dist[j].distance = v > 0 ? Math.exp(-v / sigmas[i]) : 1.0;\n }\n }\n return distances;\n }\n\n /**\n * @private\n * @param {NaiveKNN | BallTree} knn\n * @param {number} k\n * @returns {{\n * distances: { element: Float64Array; index: number; distance: number }[][];\n * sigmas: number[];\n * rhos: number[];\n * }}\n */\n _smooth_knn_dist(knn, k) {\n const SMOOTH_K_TOLERANCE = 1e-5;\n const MIN_K_DIST_SCALE = 1e-3;\n const n_iter = 64;\n const local_connectivity = /** @type {number} */ (this._parameters.local_connectivity);\n const metric = /** @type {Metric | \"precomputed\"} */ (this._parameters.metric);\n const target = Math.log2(k);\n const rhos = [];\n const sigmas = [];\n const X = this.X;\n const N = X.shape[0];\n //const distances = [...X].map(x_i => knn.search(x_i, k).raw_data().reverse());\n\n /** @type {{ element: Float64Array; index: number; distance: number }[][]} */\n const distances = [];\n if (metric === \"precomputed\" || knn instanceof NaiveKNN) {\n for (let i = 0; i < N; ++i) {\n distances.push(knn.search_by_index(i, k).reverse());\n }\n } else {\n for (const x_i of X) {\n distances.push(knn.search(x_i, k).reverse());\n }\n }\n\n const index = Math.floor(local_connectivity);\n const interpolation = local_connectivity - index;\n for (let i = 0; i < N; ++i) {\n let lo = 0;\n let hi = Infinity;\n let mid = 1;\n let rho = 0;\n\n const search_result = distances[i];\n const non_zero_dist = search_result.filter((d) => d.distance > 0);\n const non_zero_dist_length = non_zero_dist.length;\n if (non_zero_dist_length >= local_connectivity) {\n if (index > 0) {\n rho = non_zero_dist[index - 1].distance;\n if (interpolation > SMOOTH_K_TOLERANCE) {\n rho += interpolation * (non_zero_dist[index].distance - non_zero_dist[index - 1].distance);\n }\n } else {\n rho = interpolation * non_zero_dist[0].distance;\n }\n } else if (non_zero_dist_length > 0) {\n rho = non_zero_dist[non_zero_dist_length - 1].distance;\n }\n for (let x = 0; x < n_iter; ++x) {\n let psum = 0;\n for (let j = 0; j < k; ++j) {\n const d = search_result[j].distance - rho;\n psum += d > 0 ? Math.exp(-(d / mid)) : 1;\n }\n if (Math.abs(psum - target) < SMOOTH_K_TOLERANCE) {\n break;\n }\n if (psum > target) {\n [hi, mid] = [mid, (lo + hi) / 2];\n } else {\n if (hi === Infinity) {\n [lo, mid] = [mid, mid * 2];\n } else {\n [lo, mid] = [mid, (lo + hi) / 2];\n }\n }\n }\n\n //let mean_d = null;\n if (rho > 0) {\n const mean_ithd = search_result.reduce((a, b) => a + b.distance, 0) / search_result.length;\n if (mid < MIN_K_DIST_SCALE * mean_ithd) {\n mid = MIN_K_DIST_SCALE * mean_ithd;\n }\n } else {\n const mean_d = distances.reduce(\n (acc, res) => acc + res.reduce((a, b) => a + b.distance, 0) / res.length,\n 0,\n );\n if (mid < MIN_K_DIST_SCALE * mean_d) {\n mid = MIN_K_DIST_SCALE * mean_d;\n }\n }\n rhos[i] = rho;\n sigmas[i] = mid;\n }\n return {\n distances: distances,\n sigmas: sigmas,\n rhos: rhos,\n };\n }\n\n /**\n * @private\n * @param {Matrix} X\n * @param {number} n_neighbors\n * @returns {Matrix}\n */\n _fuzzy_simplicial_set(X, n_neighbors) {\n const N = X.shape[0];\n const metric = /** @type {Metric | \"precomputed\"} */ (this._parameters.metric);\n const _set_op_mix_ratio = /** @type {number} */ (this._parameters._set_op_mix_ratio);\n\n const knn =\n metric === \"precomputed\"\n ? new NaiveKNN(X.to2dArray(), {\n metric: \"precomputed\",\n seed: /** @type {number} */ (this._parameters.seed),\n })\n : new BallTree(X.to2dArray(), { metric, seed: /** @type {number} */ (this._parameters.seed) });\n let { distances, sigmas, rhos } = this._smooth_knn_dist(knn, n_neighbors);\n distances = this._compute_membership_strengths(distances, sigmas, rhos);\n const result = new Matrix(N, N, \"zeros\");\n for (let i = 0; i < N; ++i) {\n const distances_i = distances[i];\n for (let j = 0; j < distances_i.length; ++j) {\n result.set_entry(i, distances_i[j].index, distances_i[j].distance);\n }\n }\n\n const transposed_result = result.T;\n const prod_matrix = result.mult(transposed_result);\n return result\n .add(transposed_result)\n .sub(prod_matrix)\n .mult(_set_op_mix_ratio)\n .add(prod_matrix.mult(1 - _set_op_mix_ratio));\n }\n\n /**\n * @private\n * @param {number} n_epochs\n * @returns {Float32Array}\n */\n _make_epochs_per_sample(n_epochs) {\n if (!this._weights) throw new Error(\"Call init() first!\");\n const weights = this._weights;\n const result = new Float32Array(weights.length).fill(-1);\n const weight_scl = n_epochs / max(weights);\n weights.forEach((w, i) => {\n const sample = w * weight_scl;\n if (sample > 0) result[i] = Math.round(n_epochs / sample);\n });\n return result;\n }\n\n /**\n * @private\n * @param {Matrix} graph\n * @returns {{ rows: number[]; cols: number[]; data: number[] }}\n */\n _tocoo(graph) {\n const rows = [];\n const cols = [];\n const data = [];\n const [rows_n, cols_n] = graph.shape;\n for (let row = 0; row < rows_n; ++row) {\n for (let col = 0; col < cols_n; ++col) {\n const entry = graph.entry(row, col);\n if (entry !== 0) {\n rows.push(row);\n cols.push(col);\n data.push(entry);\n }\n }\n }\n return {\n rows: rows,\n cols: cols,\n data: data,\n };\n }\n\n /**\n * Computes all necessary\n *\n * @returns {UMAP}\n */\n init() {\n const _spread = /** @type {number} */ (this._parameters._spread);\n const min_dist = /** @type {number} */ (this._parameters.min_dist);\n const n_neighbors = /** @type {number} */ (this._parameters.n_neighbors);\n const _n_epochs = /** @type {number} */ (this._parameters._n_epochs);\n const _negative_sample_rate = /** @type {number} */ (this._parameters._negative_sample_rate);\n const [a, b] = this._find_ab_params(_spread, min_dist);\n this._a = a;\n this._b = b;\n this._graph = this._fuzzy_simplicial_set(this.X, n_neighbors);\n const { rows, cols, data: weights } = this._tocoo(this._graph);\n this._head = rows;\n this._tail = cols;\n this._weights = weights;\n this._epochs_per_sample = this._make_epochs_per_sample(_n_epochs);\n this._epochs_per_negative_sample = this._epochs_per_sample.map((d) => d * _negative_sample_rate);\n this._epoch_of_next_sample = this._epochs_per_sample.slice();\n this._epoch_of_next_negative_sample = this._epochs_per_negative_sample.slice();\n return this;\n }\n\n graph() {\n this.check_init();\n return { cols: this._head, rows: this._tail, weights: this._weights };\n }\n\n /**\n * @param {number} [iterations=350] - Number of iterations. Default is `350`\n * @returns {T}\n */\n transform(iterations = 350) {\n if (this.parameter(\"_n_epochs\") !== iterations) {\n this.parameter(\"_n_epochs\", iterations);\n this.init();\n }\n this.check_init();\n for (let i = 0; i < iterations; ++i) {\n this.next();\n }\n return this.projection;\n }\n\n /**\n * @param {number} [iterations=350] - Number of iterations. Default is `350`\n * @returns {Generator}\n */\n *generator(iterations = 350) {\n if (this.parameter(\"_n_epochs\") !== iterations) {\n this.parameter(\"_n_epochs\", iterations);\n this.init();\n }\n this.check_init();\n for (let i = 0; i < iterations; ++i) {\n this.next();\n yield this.projection;\n }\n return this.projection;\n }\n\n /**\n * @private\n * @param {number} x\n * @returns {number}\n */\n _clip(x) {\n if (x > 4) return 4;\n if (x < -4) return -4;\n return x;\n }\n\n /**\n * Performs the optimization step.\n *\n * @private\n * @param {Matrix} head_embedding\n * @param {Matrix} tail_embedding\n * @param {number[]} head\n * @param {number[]} tail\n * @returns {Matrix}\n */\n _optimize_layout(head_embedding, tail_embedding, head, tail) {\n const randomizer = this._randomizer;\n const _repulsion_strength = /** @type {number} */ (this.parameter(\"_repulsion_strength\"));\n const dim = /** @type {number} */ (this.parameter(\"d\"));\n const {\n _alpha: alpha,\n _a: a,\n _b: b,\n _epochs_per_sample: epochs_per_sample,\n _epochs_per_negative_sample: epochs_per_negative_sample,\n _epoch_of_next_negative_sample: epoch_of_next_negative_sample,\n _epoch_of_next_sample: epoch_of_next_sample,\n _clip: clip,\n } = this;\n if (\n alpha === undefined ||\n a === undefined ||\n b === undefined ||\n epochs_per_sample === undefined ||\n epochs_per_negative_sample === undefined ||\n epoch_of_next_negative_sample === undefined ||\n epoch_of_next_sample === undefined ||\n clip === undefined\n ) {\n throw new Error(\"call init() first!\");\n }\n const tail_length = tail.length;\n\n for (let i = 0, n = epochs_per_sample.length; i < n; ++i) {\n if (epoch_of_next_sample[i] <= this._iter) {\n const j = head[i];\n const k = tail[i];\n const current = head_embedding.row(j);\n const other = tail_embedding.row(k);\n const dist = euclidean_squared(current, other);\n if (dist > 0) {\n const grad_coeff = (-2 * a * b * dist ** (b - 1)) / (a * dist ** b + 1);\n for (let d = 0; d < dim; ++d) {\n const grad_d = clip(grad_coeff * (current[d] - other[d])) * alpha;\n current[d] += grad_d;\n other[d] -= grad_d;\n }\n }\n epoch_of_next_sample[i] += epochs_per_sample[i];\n const n_neg_samples = (this._iter - epoch_of_next_negative_sample[i]) / epochs_per_negative_sample[i];\n for (let p = 0; p < n_neg_samples; ++p) {\n const k = randomizer.random_int % tail_length;\n const other = tail_embedding.row(tail[k]);\n const dist = euclidean_squared(current, other);\n if (dist > 0) {\n const grad_coeff = (2 * _repulsion_strength * b) / ((0.01 + dist) * (a * dist ** b + 1));\n for (let d = 0; d < dim; ++d) {\n const grad_d = clip(grad_coeff * (current[d] - other[d])) * alpha;\n current[d] += grad_d;\n other[d] -= grad_d;\n }\n } else if (j === k) {\n }\n }\n epoch_of_next_negative_sample[i] += n_neg_samples * epochs_per_negative_sample[i];\n }\n }\n return head_embedding;\n }\n\n /**\n * @private\n * @returns {Matrix}\n */\n next() {\n if (!this._head || !this._tail) throw new Error(\"Call init() first!\");\n const iter = ++this._iter;\n const Y = this.Y;\n const _initial_alpha = /** @type {number} */ (this._parameters._initial_alpha);\n const _n_epochs = /** @type {number} */ (this._parameters._n_epochs);\n this._alpha = _initial_alpha * (1 - iter / _n_epochs);\n this.Y = this._optimize_layout(Y, Y, this._head, this._tail);\n\n return this.Y;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new UMAP(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new UMAP(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new UMAP(X, parameters);\n return dr.transform_async();\n }\n}\n","import pkg from \"../package.json\" with { type: \"json\" };\n\nconst version = pkg.version;\nexport { version };\n\n/** @import {Matrix} from \"./matrix/index.js\" */\n/** @typedef {Matrix | Float64Array[] | number[][]} InputType*/\n\n//export { version } from \"../package.json\" with { type: \"json\" };\nexport * from \"./clustering/index.js\";\nexport * from \"./datastructure/index.js\";\nexport * from \"./dimred/index.js\";\nexport * from \"./knn/index.js\";\nexport * from \"./linear_algebra/index.js\";\nexport * from \"./matrix/index.js\";\nexport * from \"./metrics/index.js\";\nexport * from \"./numerical/index.js\";\nexport * from \"./optimization/index.js\";\nexport * from \"./util/index.js\";\n"],"names":["qr","qr_gramschmidt"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"druid.js","sources":["../src/metrics/bray_curtis.js","../src/metrics/canberra.js","../src/metrics/chebyshev.js","../src/metrics/cosine.js","../src/metrics/euclidean_squared.js","../src/metrics/euclidean.js","../src/metrics/goodman_kruskal.js","../src/metrics/hamming.js","../src/metrics/haversine.js","../src/metrics/jaccard.js","../src/metrics/manhattan.js","../src/metrics/sokal_michener.js","../src/metrics/wasserstein.js","../src/metrics/yule.js","../src/matrix/distance_matrix.js","../src/matrix/k_nearest_neighbors.js","../src/matrix/linspace.js","../src/linear_algebra/inner_product.js","../src/numerical/kahan_sum.js","../src/numerical/neumair_sum.js","../src/linear_algebra/qr.js","../src/linear_algebra/qr_householder.js","../src/util/max.js","../src/util/min.js","../src/util/randomizer.js","../src/linear_algebra/simultaneous_poweriteration.js","../src/matrix/Matrix.js","../src/matrix/norm.js","../src/matrix/normalize.js","../src/clustering/Clustering.js","../src/clustering/CURE.js","../src/clustering/Hierarchical_Clustering.js","../src/datastructure/DisjointSet.js","../src/datastructure/Heap.js","../src/clustering/KMeans.js","../src/clustering/KMedoids.js","../src/clustering/MeanShift.js","../src/clustering/OPTICS.js","../src/clustering/XMeans.js","../src/dimred/DR.js","../src/dimred/FASTMAP.js","../src/knn/KNN.js","../src/knn/Annoy.js","../src/knn/BallTree.js","../src/knn/HNSW.js","../src/knn/KDTree.js","../src/knn/LSH.js","../src/knn/NaiveKNN.js","../src/knn/NNDescent.js","../src/dimred/PCA.js","../src/dimred/PaCMAP.js","../src/dimred/LocalMAP.js","../src/dimred/SMACOF.js","../src/dimred/ISOMAP.js","../src/dimred/LDA.js","../src/dimred/LLE.js","../src/dimred/MDS.js","../src/dimred/LSP.js","../src/dimred/LTSA.js","../src/dimred/SAMMON.js","../src/dimred/SQDMDS.js","../src/dimred/TopoMap.js","../src/dimred/TriMap.js","../src/dimred/TSNE.js","../src/optimization/powell.js","../src/dimred/UMAP.js","../src/index.js"],"sourcesContent":["/**\n * Computes the Bray-Curtis distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The Bray-Curtis distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Bray%E2%80%93Curtis_dissimilarity}\n */\nexport function bray_curtis(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n let sum_abs_diff = 0;\n let sum_ab = 0;\n for (let i = 0; i < a.length; ++i) {\n sum_abs_diff += Math.abs(a[i] - b[i]);\n sum_ab += a[i] + b[i];\n }\n return sum_abs_diff / sum_ab;\n}\n","/**\n * Computes the canberra distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The canberra distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Canberra_distance}\n */\nexport function canberra(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let sum = 0;\n for (let i = 0; i < n; ++i) {\n sum += Math.abs(a[i] - b[i]) / (Math.abs(a[i]) + Math.abs(b[i]));\n }\n return sum;\n}\n","/**\n * Computes the chebyshev distance (L) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The chebyshev distance between `a` and `b`.\n */\nexport function chebyshev(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n const res = [];\n for (let i = 0; i < n; ++i) {\n res.push(Math.abs(a[i] - b[i]));\n }\n return Math.max(...res);\n}\n","/**\n * Computes the cosine distance (not similarity) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The cosine distance between `a` and `b`.\n * @example\n * import { cosine } from \"@saehrimnir/druidjs\";\n * const a = [1, 2, 3];\n * const b = [4, 5, 6];\n * const distance = cosine(a, b); // 0.9746318461970762\n */\nexport function cosine(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let sum = 0;\n let sum_a = 0;\n let sum_b = 0;\n for (let i = 0; i < n; ++i) {\n sum += a[i] * b[i];\n sum_a += a[i] * a[i];\n sum_b += b[i] * b[i];\n }\n return Math.acos(sum / (Math.sqrt(sum_a) * Math.sqrt(sum_b)));\n}\n","/**\n * Computes the squared euclidean distance (l_2^2) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The squared euclidean distance between `a` and `b`.\n\n */\nexport function euclidean_squared(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let sum = 0;\n for (let i = 0; i < n; ++i) {\n const a_b = a[i] - b[i];\n sum += a_b * a_b;\n }\n return sum;\n}\n","import { euclidean_squared } from \"../metrics/euclidean_squared.js\";\n\n/**\n * Computes the euclidean distance (`l_2`) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The euclidean distance between `a` and `b`.\n */\nexport function euclidean(a, b) {\n return Math.sqrt(euclidean_squared(a, b));\n}\n","/**\n * Computes the Goodman-Kruskal gamma coefficient for ordinal association.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a - First categorical/ordinal variable\n * @param {number[] | Float64Array} b - Second categorical/ordinal variable\n * @returns {number} The Goodman-Kruskal gamma coefficient between `a` and `b` (-1 to 1).\n * @see {@link https://en.wikipedia.org/wiki/Goodman_and_Kruskal%27s_gamma}\n */\nexport function goodman_kruskal(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n if (n < 2) return 0;\n\n let concordant = 0;\n let discordant = 0;\n let tie_a = 0;\n let tie_b = 0;\n\n for (let i = 0; i < n; ++i) {\n for (let j = i + 1; j < n; ++j) {\n const a_diff = a[i] - a[j];\n const b_diff = b[i] - b[j];\n const a_tied = a_diff === 0;\n const b_tied = b_diff === 0;\n\n if (a_tied && b_tied) {\n } else if (a_tied) {\n tie_a++;\n } else if (b_tied) {\n tie_b++;\n } else if (a_diff * b_diff > 0) {\n concordant++;\n } else {\n discordant++;\n }\n }\n }\n\n const denominator = concordant + discordant + tie_a + tie_b;\n if (denominator === 0) return 0;\n\n const numerator = concordant + discordant;\n if (numerator === 0) return 0;\n\n return (concordant - discordant) / numerator;\n}\n","/**\n * Computes the hamming distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The hamming distance between `a` and `b`.\n */\nexport function hamming(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let disagree = 0;\n for (let i = 0; i < n; ++i) {\n const x = a[i];\n const y = b[i];\n disagree += x !== y ? 1 : 0;\n }\n return disagree / n;\n}\n","/**\n * Computes the Haversine distance between two points on a sphere of unit length 1. Multiply the result with the radius of the sphere. (For instance Earth's radius is 6371km)\n *\n * @category Metrics\n * @param {number[] | Float64Array} a - Point [lat1, lon1] in radians\n * @param {number[] | Float64Array} b - Point [lat2, lon2] in radians\n * @returns {number} The Haversine distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Haversine_formula}\n */\nexport function haversine(a, b) {\n if (a.length !== 2 || b.length !== 2)\n throw new Error(\"Haversine distance requires exactly 2 coordinates [lat, lon] for each point!\");\n const lat1 = a[0];\n const lon1 = a[1];\n const lat2 = b[0];\n const lon2 = b[1];\n\n const dlat = lat2 - lat1;\n const dlon = lon2 - lon1;\n\n const sin_dlat2 = Math.sin(dlat / 2);\n const sin_dlon2 = Math.sin(dlon / 2);\n\n const x = sin_dlat2 * sin_dlat2 + Math.cos(lat1) * Math.cos(lat2) * sin_dlon2 * sin_dlon2;\n const c = 2 * Math.atan2(Math.sqrt(x), Math.sqrt(1 - x));\n\n return c;\n}\n","/**\n * Computes the jaccard distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The jaccard distance between `a` and `b`.\n */\nexport function jaccard(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let num_non_zero = 0;\n let num_equal = 0;\n for (let i = 0; i < n; ++i) {\n const x = a[i] !== 0;\n const y = b[i] !== 0;\n num_non_zero += x || y ? 1 : 0;\n num_equal += x && y ? 1 : 0;\n }\n return (num_non_zero - num_equal) / num_non_zero;\n}\n","/**\n * Computes the manhattan distance (`l_1`) between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The manhattan distance between `a` and `b`.\n */\nexport function manhattan(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let sum = 0;\n for (let i = 0; i < n; ++i) {\n sum += Math.abs(a[i] - b[i]);\n }\n return sum;\n}\n","/**\n * Computes the Sokal-Michener distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The Sokal-Michener distance between `a` and `b`.\n\n */\nexport function sokal_michener(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let num_not_equal = 0;\n for (let i = 0; i < n; ++i) {\n const x = a[i] !== 0;\n const y = b[i] !== 0;\n num_not_equal += x !== y ? 1 : 0;\n }\n return (2 * num_not_equal) / (n + num_not_equal);\n}\n","/**\n * Computes the 1D Wasserstein distance (Earth Mover's Distance) between two distributions.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a - First distribution (histogram or probability mass)\n * @param {number[] | Float64Array} b - Second distribution (histogram or probability mass)\n * @returns {number} The Wasserstein/EMD distance between `a` and `b`.\n * @see {@link https://en.wikipedia.org/wiki/Wasserstein_metric}\n */\nexport function wasserstein(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let sumA = 0;\n let sumB = 0;\n for (let i = 0; i < n; i++) {\n sumA += a[i];\n sumB += b[i];\n }\n\n // Fallback if sums are 0\n if (sumA === 0 && sumB === 0) return 0;\n if (sumA === 0 || sumB === 0) return Infinity;\n\n let distance = 0;\n let cumA = 0;\n let cumB = 0;\n for (let i = 0; i < n; i++) {\n cumA += a[i] / sumA;\n cumB += b[i] / sumB;\n distance += Math.abs(cumA - cumB);\n }\n return distance;\n}\n","/**\n * Computes the yule distance between `a` and `b`.\n *\n * @category Metrics\n * @param {number[] | Float64Array} a\n * @param {number[] | Float64Array} b\n * @returns {number} The yule distance between `a` and `b`.\n */\nexport function yule(a, b) {\n if (a.length !== b.length) throw new Error(\"Vector a and b needs to be of the same length!\");\n const n = a.length;\n let num_true_true = 0;\n let num_true_false = 0;\n let num_false_true = 0;\n for (let i = 0; i < n; ++i) {\n const x = a[i] !== 0;\n const y = b[i] !== 0;\n num_true_true += x && y ? 1 : 0;\n num_true_false += x && !y ? 1 : 0;\n num_false_true += !x && y ? 1 : 0;\n }\n const num_false_false = n - num_true_true - num_true_false - num_false_true;\n return num_true_false === 0 || num_false_true === 0\n ? 0\n : (2 * num_true_false * num_false_true) / (num_true_true * num_false_false + num_true_false * num_false_true);\n}\n","import { euclidean } from \"../metrics/index.js\";\nimport { Matrix } from \"./index.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n\n/**\n * @param {Matrix | Float64Array[] | number[][]} A\n * @returns {A is Matrix}\n */\nfunction isMatrix(A) {\n return A instanceof Matrix;\n}\n\n/**\n * Computes the distance matrix of datamatrix `A`.\n *\n * @category Matrix\n * @param {Matrix | Float64Array[] | number[][]} A - Matrix.\n * @param {Metric} [metric=euclidean] - The diistance metric. Default is `euclidean`\n * @returns {Matrix} The distance matrix of `A`.\n */\nexport function distance_matrix(A, metric = euclidean) {\n /** @type {number} */\n const n = isMatrix(A) ? A.shape[0] : A.length;\n const D = new Matrix(n, n);\n for (let i = 0; i < n; ++i) {\n const A_i = isMatrix(A) ? A.row(i) : A[i];\n for (let j = i + 1; j < n; ++j) {\n const dist = metric(A_i, isMatrix(A) ? A.row(j) : A[j]);\n D.set_entry(i, j, dist);\n D.set_entry(j, i, dist);\n }\n }\n return D;\n}\n","//@ts-check\n\nimport { distance_matrix, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n\n/**\n * Computes the k-nearest neighbors of each row of `A`.\n *\n * @category Matrix\n * @param {Matrix} A - Either the data matrix, or a distance matrix.\n * @param {number} k - The number of neighbors to compute.\n * @param {Metric | \"precomputed\"} [metric=euclidean] Default is `euclidean`\n * @returns {{ i: number; j: number; distance: number }[][]} The kNN graph.\n */\nexport function k_nearest_neighbors(A, k, metric = euclidean) {\n A = A instanceof Matrix ? A : Matrix.from(A);\n const rows = A.shape[0];\n const D = metric === \"precomputed\" ? A : distance_matrix(A, metric);\n /** @type {{ i: number; j: number; distance: number }[][]} */\n const nN = [];\n for (let row = 0; row < rows; ++row) {\n const res = Array.from(D.row(row))\n .map((distance, col) => {\n return {\n i: row,\n j: col,\n distance: distance,\n };\n })\n .sort((a, b) => a.distance - b.distance)\n .slice(1, k + 1);\n nN.push(res);\n }\n return nN;\n}\n","/**\n * Creates an Array containing `number` numbers from `start` to `end`. If `number = null`.\n *\n * @category Matrix\n * @param {number} start - Start value.\n * @param {number} end - End value.\n * @param {number} [number] - Number of number between `start` and `end`.\n * @returns {number[]} An array with `number` entries, beginning at `start` ending at `end`.\n */\nexport function linspace(start, end, number) {\n if (number === undefined || number === null) {\n number = Math.max(Math.round(end - start) + 1, 1);\n }\n if (number < 2) {\n return number === 1 ? [start] : [];\n }\n const result = new Array(number);\n number -= 1;\n for (let i = number; i >= 0; --i) {\n result[i] = (i * end + (number - i) * start) / number;\n }\n return result;\n}\n","/**\n * Computes the inner product between two arrays of the same length.\n *\n * @category Linear Algebra\n * @param {number[] | Float64Array} a - Array a.\n * @param {number[] | Float64Array} b - Array b.\n * @returns The inner product between `a` and `b`.\n */\nexport function inner_product(a, b) {\n const N = a.length;\n if (N !== b.length) {\n throw new Error(\"Array a and b must have the same length!\");\n }\n let sum = 0;\n for (let i = 0; i < N; ++i) {\n sum += a[i] * b[i];\n }\n return sum;\n}\n","/**\n * Numerical stable summation with the Kahan summation algorithm.\n *\n * @category Numerical\n * @param {number[] | Float64Array} summands - Array of values to sum up.\n * @returns {number} The sum.\n * @see {@link https://en.wikipedia.org/wiki/Kahan_summation_algorithm}\n */\nexport function kahan_sum(summands) {\n const n = summands.length;\n let sum = 0;\n let compensation = 0;\n let y, t;\n\n for (let i = 0; i < n; ++i) {\n y = summands[i] - compensation;\n t = sum + y;\n compensation = t - sum - y;\n sum = t;\n }\n return sum;\n}\n","/**\n * Numerical stable summation with the Neumair summation algorithm.\n *\n * @category Numerical\n * @param {number[] | Float64Array} summands - Array of values to sum up.\n * @returns {number} The sum.\n * @see {@link https://en.wikipedia.org/wiki/Kahan_summation_algorithm#Further_enhancements}\n */\nexport function neumair_sum(summands) {\n const n = summands.length;\n let sum = 0;\n let compensation = 0;\n\n for (let i = 0; i < n; ++i) {\n const summand = summands[i];\n const t = sum + summand;\n if (Math.abs(sum) >= Math.abs(summand)) {\n compensation += sum - t + summand;\n } else {\n compensation += summand - t + sum;\n }\n sum = t;\n }\n return sum + compensation;\n}\n","import { Matrix, norm } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { neumair_sum } from \"../numerical/index.js\";\n\n/**\n * Computes the QR Decomposition of the Matrix `A` using Gram-Schmidt process.\n *\n * @category Linear Algebra\n * @param {Matrix} A\n * @returns {{ R: Matrix; Q: Matrix }}\n * @see {@link https://en.wikipedia.org/wiki/QR_decomposition#Using_the_Gram%E2%80%93Schmidt_process}\n */\nexport function qr(A) {\n const [rows, cols] = A.shape;\n const Q = new Matrix(rows, cols, \"identity\");\n const R = new Matrix(cols, cols, 0);\n\n for (let j = 0; j < cols; ++j) {\n const v = A.col(j);\n for (let i = 0; i < j; ++i) {\n const q = Q.col(i);\n const q_dot_v = neumair_sum(q.map((q_, k) => q_ * v[k]));\n for (let k = 0; k < rows; ++k) {\n v[k] -= q_dot_v * q[k];\n }\n R.set_entry(i, j, q_dot_v);\n }\n const v_norm = norm(v, euclidean);\n for (let k = 0; k < rows; ++k) {\n Q.set_entry(k, j, v[k] / v_norm);\n }\n R.set_entry(j, j, v_norm);\n }\n return { R, Q };\n}\n","import { Matrix, norm } from \"../matrix/index.js\";\n\n/**\n * Computes the QR Decomposition of the Matrix `A` with householder transformations.\n *\n * @category Linear Algebra\n * @param {Matrix} A\n * @returns {{ R: Matrix; Q: Matrix }}\n * @see {@link https://en.wikipedia.org/wiki/QR_decomposition#Using_Householder_reflections}\n * @see {@link http://mlwiki.org/index.php/Householder_Transformation}\n */\nexport function qr_householder(A) {\n const [rows, cols] = A.shape;\n const Q = new Matrix(rows, rows, \"I\");\n const R = A.clone();\n\n for (let j = 0; j < cols; ++j) {\n const x = Matrix.from_vector(R.col(j).slice(j), \"row\");\n const x_norm = norm(x);\n const x0 = x.entry(0, 0);\n const rho = -Math.sign(x0);\n const u1 = x0 - rho * x_norm;\n const u = x.divide(u1).set_entry(0, 0, 1);\n const beta = (-rho * u1) / x_norm;\n\n const u_outer_u = u.outer(u);\n const R_block = R.get_block(j, 0);\n const new_R = R_block.sub(u_outer_u.dot(R_block).mult(beta));\n const Q_block = Q.get_block(0, j);\n const new_Q = Q_block.sub(Q_block.dot(u_outer_u).mult(beta));\n R.set_block(j, 0, new_R);\n Q.set_block(0, j, new_Q);\n }\n return { R, Q };\n}\n","/**\n * Returns maximum in Array `values`.\n *\n * @category Utils\n * @param {Iterable} values\n * @returns {number}\n */\nexport function max(values) {\n let max = -Infinity;\n for (const value of values) {\n if (value !== null && max < value) {\n max = value;\n }\n }\n return max;\n}\n","/**\n * Returns maximum in Array `values`.\n *\n * @category Utils\n * @param {Iterable} values\n * @returns {number}\n */\nexport function min(values) {\n let min = Infinity;\n for (const value of values) {\n if (value !== null && min > value) {\n min = value;\n }\n }\n return min;\n}\n","import { linspace } from \"../matrix/index.js\";\n\n/**\n * @category Utils\n * @class\n */\nexport class Randomizer {\n _N = 624;\n _M = 397;\n _MATRIX_A = 0x9908b0df;\n _UPPER_MASK = 0x80000000;\n _LOWER_MASK = 0x7fffffff;\n\n /** @type {number[]} */\n _mt;\n /** @type {number} */\n _mti;\n /** @type {number} */\n _seed;\n\n /**\n * Mersenne Twister random number generator.\n *\n * @param {number} [_seed=new Date().getTime()] - The seed for the random number generator. If `_seed == null` then\n * the actual time gets used as seed. Default is `new Date().getTime()`\n * @see https://github.com/bmurray7/mersenne-twister-examples/blob/master/javascript-mersenne-twister.js\n */\n constructor(_seed) {\n this._mt = new Array(this._N);\n this._mti = this._N + 1;\n this._seed = _seed ?? Date.now();\n this.seed = this._seed;\n }\n\n /** @type {number} seed */\n set seed(_seed) {\n this._seed = _seed;\n const mt = this._mt;\n\n mt[0] = _seed >>> 0;\n for (this._mti = 1; this._mti < this._N; this._mti += 1) {\n const mti = this._mti;\n const s = mt[mti - 1] ^ (mt[mti - 1] >>> 30);\n mt[mti] = ((((s & 0xffff0000) >>> 16) * 1812433253) << 16) + (s & 0x0000ffff) * 1812433253 + mti;\n mt[mti] >>>= 0;\n }\n }\n\n /**\n * Returns the seed of the random number generator.\n *\n * @returns {number} - The seed.\n */\n get seed() {\n return this._seed;\n }\n\n /**\n * Returns a float between 0 and 1.\n *\n * @returns {number} - A random number between [0, 1]\n */\n get random() {\n return this.random_int * (1.0 / 4294967296.0);\n }\n\n /**\n * Returns an integer between 0 and MAX_INTEGER.\n *\n * @returns {number} - A random integer.\n */\n get random_int() {\n let y,\n mag01 = [0x0, this._MATRIX_A];\n if (this._mti >= this._N) {\n let kk;\n\n /* if (this._mti == this._N + 1) {\n this.seed = 5489;\n } */\n\n const N_M = this._N - this._M;\n const M_N = this._M - this._N;\n\n for (kk = 0; kk < N_M; ++kk) {\n y = (this._mt[kk] & this._UPPER_MASK) | (this._mt[kk + 1] & this._LOWER_MASK);\n this._mt[kk] = this._mt[kk + this._M] ^ (y >>> 1) ^ mag01[y & 0x1];\n }\n for (; kk < this._N - 1; ++kk) {\n y = (this._mt[kk] & this._UPPER_MASK) | (this._mt[kk + 1] & this._LOWER_MASK);\n this._mt[kk] = this._mt[kk + M_N] ^ (y >>> 1) ^ mag01[y & 0x1];\n }\n\n y = (this._mt[this._N - 1] & this._UPPER_MASK) | (this._mt[0] & this._LOWER_MASK);\n this._mt[this._N - 1] = this._mt[this._M - 1] ^ (y >>> 1) ^ mag01[y & 0x1];\n\n this._mti = 0;\n }\n this._mti += 1;\n y = this._mt[this._mti];\n y ^= y >>> 11;\n y ^= (y << 7) & 0x9d2c5680;\n y ^= (y << 15) & 0xefc60000;\n y ^= y >>> 18;\n\n return y >>> 0;\n }\n\n gauss_random() {\n let x, y, r;\n if (this._val != null) {\n x = this._val;\n this._val = null;\n return x;\n } else\n do {\n x = 2 * this.random - 1;\n y = 2 * this.random - 1;\n r = x * x + y * y;\n } while (!r || r > 1);\n const c = Math.sqrt((-2 * Math.log(r)) / r);\n this._val = y * c; // cache this for next function call for efficiency\n return x * c;\n }\n\n /**\n * @template T Returns samples from an input Matrix or Array.\n * @param {T[]} A - The input Matrix or Array.\n * @param {number} n - The number of samples.\n * @returns {T[]} A random selection form `A` of `n` samples.\n */\n choice(A, n) {\n if (!Array.isArray(A)) throw new Error(\"A must be an Array!\");\n // if (A instanceof Matrix) {\n // let rows = A.shape[0];\n // if (n > rows) {\n // throw new Error(\"n bigger than A!\");\n // }\n // /** @type {number[]} */\n // let sample = new Array(n);\n // let index_list = linspace(0, rows - 1);\n // for (let i = 0, l = index_list.length; i < n; ++i, --l) {\n // let random_index = this.random_int % l;\n // sample[i] = index_list.splice(random_index, 1)[0];\n // }\n // return sample.map((d) => A.row(d));\n // } else if (Array.isArray(A) || A instanceof Float64Array) {\n const rows = A.length;\n if (n > rows) {\n throw new Error(\"n bigger than A!\");\n }\n const sample = new Array(n);\n const index_list = linspace(0, rows - 1);\n for (let i = 0, l = index_list.length; i < n; ++i, --l) {\n const random_index = this.random_int % l;\n sample[i] = index_list.splice(random_index, 1)[0];\n }\n return sample.map((d) => A[d]);\n //} else {\n //throw new Error(\"A must be of type Matrix or Float64Array or number[]!\");\n // }\n }\n\n /**\n * @template T Returns samples from an input Matrix or Array.\n * @param {T[]} A - The input Matrix or Array.\n * @param {number} n - The number of samples.\n * @param {number} seed - The seed for the random number generator.\n * @returns {T[]} - A random selection form `A` of `n` samples.\n */\n static choice(A, n, seed = 1212) {\n const R = new Randomizer(seed);\n return R.choice(A, n);\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { euclidean_squared } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { qr as qr_gramschmidt } from \"./index.js\";\n\n/** @import { EigenArgs } from \"./index.js\" */\n\n/**\n * Computes the `k` biggest Eigenvectors and Eigenvalues from Matrix `A` with the QR-Algorithm.\n *\n * @category Linear Algebra\n * @param {Matrix} A - The Matrix\n * @param {number} k - The number of eigenvectors and eigenvalues to compute.\n * @param {EigenArgs} parameters - Object containing parameterization of the simultanious\n * poweriteration method.\n * @returns {{ eigenvalues: Float64Array; eigenvectors: Float64Array[] }} The `k` biggest eigenvectors and eigenvalues\n * of Matrix `A`.\n */\nexport function simultaneous_poweriteration(\n A,\n k = 2,\n { seed = 1212, max_iterations = 100, qr = qr_gramschmidt, tol = 1e-8 } = {},\n) {\n const randomizer = seed instanceof Randomizer ? seed : new Randomizer(seed);\n if (!(A instanceof Matrix)) A = Matrix.from(A);\n const n = A.shape[0];\n let { Q, R } = qr(new Matrix(n, k, () => (randomizer.random - 0.5) * 2));\n while (max_iterations--) {\n const oldQ = Q;\n const Z = A.dot(Q);\n const QR = qr(Z);\n Q = QR.Q;\n R = QR.R;\n const error = euclidean_squared(Q.values, oldQ.values);\n if (error < tol) {\n break;\n }\n }\n\n const eigenvalues = R.diag();\n const eigenvectors = Q.transpose().to2dArray();\n return { eigenvalues, eigenvectors };\n}\n","import { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { neumair_sum } from \"../numerical/index.js\";\nimport { Randomizer } from \"../util/index.js\";\n\n/** @typedef {(i: number, j: number) => number} Accessor */\n\n/**\n * @class\n * @category Matrix\n */\nexport class Matrix {\n /**\n * Creates a new Matrix. Entries are stored in a Float64Array.\n *\n * @example let A = new Matrix(10, 10, () => Math.random()); //creates a 10 times 10 random matrix. let B = new\n * Matrix(3, 3, \"I\"); // creates a 3 times 3 identity matrix.\n *\n * @param {number} rows - The amount of rows of the matrix.\n * @param {number} cols - The amount of columns of the matrix.\n * @param {Accessor | string | number} value - Can be a function with row and col as parameters, a number, or\n * \"zeros\", \"identity\" or \"I\", or \"center\".\n *\n * - **function**: for each entry the function gets called with the parameters for the actual row and column.\n * - **string**: allowed are\n *\n * - \"zero\", creates a zero matrix.\n * - \"identity\" or \"I\", creates an identity matrix.\n * - \"center\", creates an center matrix.\n * - **number**: create a matrix filled with the given value.\n */\n constructor(rows, cols, value = 0) {\n /** @type {number} */ this._rows = rows;\n /** @type {number} */ this._cols = cols;\n /** @type {Float64Array} */ this._data;\n\n if (rows && cols) {\n if (!value) {\n this._data = new Float64Array(rows * cols);\n }\n if (typeof value === \"function\") {\n this._data = new Float64Array(rows * cols);\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col) {\n this._data[row * cols + col] = value(row, col);\n }\n }\n }\n if (typeof value === \"string\") {\n if (value === \"zeros\") {\n this._data = new Float64Array(rows * cols);\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col) {\n this._data[row * cols + col] = 0;\n }\n }\n }\n if (value === \"identity\" || value === \"I\") {\n this._data = new Float64Array(rows * cols);\n for (let row = 0; row < rows; ++row) {\n this._data[row * cols + row] = 1;\n }\n }\n if (value === \"center\" && rows === cols) {\n this._data = new Float64Array(rows * cols);\n value = (i, j) => (i === j ? 1 : 0) - 1 / rows;\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col) {\n this._data[row * cols + col] = value(row, col);\n }\n }\n }\n }\n if (typeof value === \"number\") {\n this._data = new Float64Array(rows * cols);\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col) {\n this._data[row * cols + col] = value;\n }\n }\n }\n if (Array.isArray(value)) {\n this._data = new Float64Array(rows * cols);\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col) {\n this._data[row * cols + col] = value[row][col];\n }\n }\n }\n }\n }\n\n /**\n * Creates a Matrix out of `A`.\n * @param {Matrix | Float64Array[] | number[][]} A - The matrix, array, or number, which should converted to a Matrix.\n * @returns {Matrix}\n * @example\n * let A = Matrix.from([ [1, 0], [0, 1], ]); //creates a two by two identity matrix.\n */\n static from(A) {\n if (A instanceof Matrix) {\n return A.clone();\n }\n if (Matrix.is2dArray(A)) {\n const m = A.length;\n const n = A[0].length;\n for (let row = 0; row < m; ++row) {\n if (A[row].length !== n) {\n throw new Error(\"various array lengths\");\n }\n }\n return new Matrix(m, n, (i, j) => A[i][j]);\n }\n throw new Error(\"error\");\n }\n\n /**\n * Creates a Matrix with the diagonal being the values of `v`.\n *\n * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]]\n *\n * @param {number[] | Float64Array} v\n * @returns {Matrix}\n */\n static from_diag(v) {\n const N = v.length;\n return new Matrix(N, N, (i, j) => (i === j ? v[i] : 0));\n }\n\n /**\n * Creates a Matrix with the diagonal being the values of `v`.\n *\n * @example let S = Matrix.from_diag([1, 2, 3]); // creates [[1, 0, 0], [0, 2, 0], [0, 0, 3]]\n *\n * @param {number[] | Float64Array} v\n * @param {\"col\" | \"row\"} type\n * @returns {Matrix}\n */\n static from_vector(v, type) {\n const N = v.length;\n if (type === \"col\") {\n return new Matrix(N, 1, (i, _) => v[i]);\n } else {\n return new Matrix(1, N, (_, j) => v[j]);\n }\n }\n\n /**\n * Returns the `row`th row from the Matrix.\n *\n * @param {number} row\n * @returns {Float64Array}\n */\n row(row) {\n const data = this.values;\n const cols = this._cols;\n return data.subarray(row * cols, (row + 1) * cols);\n }\n\n /**\n * Returns an generator yielding each row of the Matrix.\n *\n * @yields {Float64Array}\n */\n *iterate_rows() {\n const cols = this._cols;\n const rows = this._rows;\n const data = this.values;\n for (let row = 0; row < rows; ++row) {\n yield data.subarray(row * cols, (row + 1) * cols);\n }\n }\n\n /**\n * Makes a `Matrix` object an iterable object.\n *\n * @yields {Float64Array}\n */\n *[Symbol.iterator]() {\n for (const row of this.iterate_rows()) {\n yield row;\n }\n }\n\n /**\n * Sets the entries of `row`th row from the Matrix to the entries from `values`.\n *\n * @param {number} row\n * @param {number[]} values\n * @returns {Matrix}\n */\n set_row(row, values) {\n const cols = this._cols;\n if (Matrix.isArray(values) && values.length === cols) {\n const offset = row * cols;\n for (let col = 0; col < cols; ++col) {\n this.values[offset + col] = values[col];\n }\n } else if (values instanceof Matrix && values.shape[1] === cols && values.shape[0] === 1) {\n const offset = row * cols;\n for (let col = 0; col < cols; ++col) {\n this.values[offset + col] = values._data[col];\n }\n } else {\n throw new Error(\"Values not valid! Needs to be either an Array, a Float64Array, or a fitting Matrix!\");\n }\n return this;\n }\n\n /**\n * Swaps the rows `row1` and `row2` of the Matrix.\n *\n * @param {number} row1\n * @param {number} row2\n * @returns {Matrix}\n */\n swap_rows(row1, row2) {\n const cols = this._cols;\n const data = this.values;\n for (let i = row1 * cols, j = row2 * cols, col = 0; col < cols; ++col, ++i, ++j) {\n const t = data[i];\n data[i] = data[j];\n data[j] = t;\n }\n return this;\n }\n\n /**\n * Returns the colth column from the Matrix.\n *\n * @param {number} col\n * @returns {Float64Array}\n */\n col(col) {\n const result_col = new Float64Array(this._rows);\n for (let row = 0; row < this._rows; ++row) {\n result_col[row] = this.values[row * this._cols + col];\n }\n return result_col;\n }\n\n /**\n * Returns the `col`th entry from the `row`th row of the Matrix.\n *\n * @param {number} row\n * @param {number} col\n * @returns {number}\n */\n entry(row, col) {\n return this.values[row * this._cols + col];\n }\n\n /**\n * Sets the {@link col}th entry from the {@link row}th row of the Matrix to the given\n * {@link value}.\n *\n * @param {number} row\n * @param {number} col\n * @param {number} value\n * @returns {Matrix}\n */\n set_entry(row, col, value) {\n this.values[row * this._cols + col] = value;\n return this;\n }\n\n /**\n * Adds a given {@link value} to the {@link col}th entry from the {@link row}th row of the\n * Matrix.\n *\n * @param {number} row\n * @param {number} col\n * @param {number} value\n * @returns {Matrix}\n */\n add_entry(row, col, value) {\n this.values[row * this._cols + col] += value;\n return this;\n }\n\n /**\n * Subtracts a given {@link value} from the {@link col}th entry from the {@link row}th row of the\n * Matrix.\n *\n * @param {number} row\n * @param {number} col\n * @param {number} value\n * @returns {Matrix}\n */\n sub_entry(row, col, value) {\n this.values[row * this._cols + col] -= value;\n return this;\n }\n\n /**\n * Returns a new transposed Matrix.\n *\n * @returns {Matrix}\n */\n transpose() {\n const B = new Matrix(this._cols, this._rows, (row, col) => this.entry(col, row));\n return B;\n }\n\n /**\n * Returns a new transposed Matrix. Short-form of `transpose`.\n *\n * @returns {Matrix}\n */\n get T() {\n return this.transpose();\n }\n\n /**\n * Returns the inverse of the Matrix.\n *\n * @returns {Matrix}\n */\n inverse() {\n const rows = this._rows;\n const cols = this._cols;\n const A = this.clone();\n const B = new Matrix(rows, cols, \"I\");\n\n // foreach column\n for (let col = 0; col < cols; ++col) {\n // Search for maximum in this column (pivot)\n let max_idx = col;\n let max_val = Math.abs(A.entry(col, col));\n for (let row = col + 1; row < rows; ++row) {\n const val = Math.abs(A.entry(row, col));\n if (max_val < val) {\n max_idx = row;\n max_val = val;\n }\n }\n if (max_val === 0) {\n throw new Error(\"Cannot compute inverse of Matrix, determinant is zero\");\n }\n // Swap maximum row with current row\n if (max_idx !== col) {\n A.swap_rows(col, max_idx);\n B.swap_rows(col, max_idx);\n }\n\n // eliminate non-zero values on the other rows at column c\n const A_col = A.row(col);\n const B_col = B.row(col);\n for (let row = 0; row < rows; ++row) {\n if (row !== col) {\n // eliminate value at column c and row r\n const A_row = A.row(row);\n const B_row = B.row(row);\n if (A_row[col] !== 0) {\n const f = A_row[col] / A_col[col];\n // sub (f * row c) from row r to eliminate the value at column c\n for (let s = col; s < cols; ++s) {\n A_row[s] -= f * A_col[s];\n }\n for (let s = 0; s < cols; ++s) {\n B_row[s] -= f * B_col[s];\n }\n }\n } else {\n // normalize value at Acc to 1 (diagonal):\n // divide each value of row r=c by the value at Acc\n const f = A_col[col];\n for (let s = col; s < cols; ++s) {\n A_col[s] /= f;\n }\n for (let s = 0; s < cols; ++s) {\n B_col[s] /= f;\n }\n }\n }\n }\n return B;\n }\n\n /**\n * Returns the dot product. If `B` is an Array or Float64Array then an Array gets returned. If `B` is a Matrix then\n * a Matrix gets returned.\n *\n * @param {Matrix | number[] | Float64Array} B The right side\n * @returns {Matrix}\n */\n dot(B) {\n if (B instanceof Matrix) {\n const [rows_A, cols_A] = this.shape;\n const [rows_B, cols_B] = B.shape;\n if (cols_A !== rows_B) {\n throw new Error(`A.dot(B): A is a ${this.shape.join(\" ⨯ \")}-Matrix, B is a ${B.shape.join(\" ⨯ \")}-Matrix:\n A has ${cols_A} cols and B ${rows_B} rows.\n Must be equal!`);\n }\n const C = new Matrix(rows_A, cols_B, 0);\n const A_val = this.values;\n const B_val = B.values;\n const C_val = C.values;\n\n for (let i = 0; i < rows_A; ++i) {\n const i_cols_A = i * cols_A;\n const i_cols_B = i * cols_B;\n for (let k = 0; k < cols_A; ++k) {\n const aik = A_val[i_cols_A + k];\n if (aik === 0) continue;\n const k_cols_B = k * cols_B;\n for (let j = 0; j < cols_B; ++j) {\n C_val[i_cols_B + j] += aik * B_val[k_cols_B + j];\n }\n }\n }\n return C;\n } else if (Matrix.isArray(B)) {\n // TODO: create Matrix directly\n const rows = this._rows;\n if (B.length !== rows) {\n throw new Error(`A.dot(B): A has ${rows} cols and B has ${B.length} rows. Must be equal!`);\n }\n const C = new Array(rows);\n for (let row = 0; row < rows; ++row) {\n C[row] = neumair_sum(this.row(row).map((e) => e * B[row]));\n }\n return Matrix.from(C);\n } else {\n throw new Error(`B must be Matrix or Array`);\n }\n }\n\n /**\n * Transposes the current matrix and returns the dot product with `B`. If `B` is an Array or Float64Array then an\n * Array gets returned. If `B` is a Matrix then a Matrix gets returned.\n *\n * @param {Matrix | number[] | Float64Array} B The right side\n * @returns {Matrix}\n */\n transDot(B) {\n if (B instanceof Matrix) {\n const [cols_A, rows_A] = this.shape; // transpose matrix\n const [rows_B, cols_B] = B.shape;\n if (cols_A !== rows_B) {\n throw new Error(`A.dot(B): A is a ${[rows_A, cols_A].join(\" ⨯ \")}-Matrix, B is a ${B.shape.join(\" ⨯ \")}-Matrix:\n A has ${cols_A} cols and B ${rows_B} rows, which must be equal!`);\n }\n // let B = new Matrix(this._cols, this._rows, (row, col) => this.entry(col, row));\n // this.values[row * this._cols + col];\n const C = new Matrix(rows_A, cols_B, 0);\n const A_val = this.values; // A is rows_B x rows_A (transposed)\n const B_val = B.values;\n const C_val = C.values;\n\n for (let k = 0; k < cols_A; ++k) {\n // cols_A is rows_B\n const k_rows_A = k * rows_A;\n const k_cols_B = k * cols_B;\n for (let i = 0; i < rows_A; ++i) {\n const aki = A_val[k_rows_A + i];\n if (aki === 0) continue;\n for (let j = 0; j < cols_B; ++j) {\n C_val[i * cols_B + j] += aki * B_val[k_cols_B + j];\n }\n }\n }\n return C;\n } else if (Matrix.isArray(B)) {\n // TODO: create Matrix directly\n const rows = this._cols;\n if (B.length !== rows) {\n throw new Error(`A.dot(B): A has ${rows} cols and B has ${B.length} rows. Must be equal!`);\n }\n const C = new Array(rows);\n for (let row = 0; row < rows; ++row) {\n C[row] = neumair_sum(this.col(row).map((e) => e * B[row]));\n }\n return Matrix.from(C);\n } else {\n throw new Error(`B must be Matrix or Array`);\n }\n }\n\n /**\n * Returns the dot product with the transposed version of `B`. If `B` is an Array or Float64Array then an Array gets\n * returned. If `B` is a Matrix then a Matrix gets returned.\n *\n * @param {Matrix | number[] | Float64Array} B The right side\n * @returns {Matrix}\n */\n dotTrans(B) {\n if (B instanceof Matrix) {\n const [rows_A, cols_A] = this.shape;\n const [cols_B, rows_B] = B.shape;\n if (cols_A !== rows_B) {\n throw new Error(`A.dot(B): A is a ${this.shape.join(\" ⨯ \")}-Matrix, B is a ${[rows_B, cols_B].join(\" ⨯ \")}-Matrix:\n A has ${cols_A} cols and B ${rows_B} rows, which must be equal!`);\n }\n const C = new Matrix(rows_A, cols_B, (row, col) => {\n const A_i = this.row(row);\n const B_i = B.row(col);\n let sum = 0;\n for (let i = 0; i < cols_A; ++i) {\n sum += A_i[i] * B_i[i];\n }\n return sum;\n });\n return C;\n } else if (Matrix.isArray(B)) {\n // TODO: create Matrix directly\n const rows = this._rows;\n if (B.length !== rows) {\n throw new Error(`A.dot(B): A has ${rows} cols and B has ${B.length} rows. Must be equal!`);\n }\n const C = new Array(rows);\n for (let row = 0; row < rows; ++row) {\n C[row] = neumair_sum(this.row(row).map((e) => e * B[row]));\n }\n return Matrix.from(C);\n } else {\n throw new Error(`B must be Matrix or Array`);\n }\n }\n\n /**\n * Computes the outer product from `this` and `B`.\n *\n * @param {Matrix} B\n * @returns {Matrix}\n */\n outer(B) {\n const l = this._data.length;\n const r = B._data.length;\n if (l !== r) throw new Error(\"Matrix A and B needs to be of the same length!\");\n const C = new Matrix(\n l,\n l,\n /** @type {Accessor} */ (i, j) => {\n if (i <= j) {\n return this._data[i] * B._data[j];\n } else {\n return this.entry(j, i);\n }\n },\n );\n\n return C;\n }\n\n /**\n * Appends matrix `B` to the matrix.\n *\n * @example let A = Matrix.from([ [1, 1], [1, 1], ]); // 2 by 2 matrix filled with ones. let B = Matrix.from([ [2,\n * 2], [2, 2], ]); // 2 by 2 matrix filled with twos.\n *\n * A.concat(B, \"horizontal\"); // 2 by 4 matrix. [[1, 1, 2, 2], [1, 1, 2, 2]]\n * A.concat(B, \"vertical\"); // 4 by 2 matrix. [[1, 1], [1, 1], [2, 2], [2, 2]]\n * A.concat(B, \"diag\"); // 4 by 4 matrix. [[1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 2, 2], [0, 0, 2, 2]]\n *\n * @param {Matrix} B - Matrix to append.\n * @param {\"horizontal\" | \"vertical\" | \"diag\"} [type=\"horizontal\"] - Type of concatenation. Default is\n * `\"horizontal\"`\n * @returns {Matrix}\n */\n concat(B, type = \"horizontal\") {\n const [rows_A, cols_A] = this.shape;\n const [rows_B, cols_B] = B.shape;\n if (type === \"horizontal\") {\n if (rows_A !== rows_B) {\n throw new Error(\n `A.concat(B, \"horizontal\"): A and B need same number of rows, A has ${rows_A} rows, B has ${rows_B} rows.`,\n );\n }\n const X = new Matrix(rows_A, cols_A + cols_B, \"zeros\");\n X.set_block(0, 0, this);\n X.set_block(0, cols_A, B);\n return X;\n } else if (type === \"vertical\") {\n if (cols_A !== cols_B) {\n throw new Error(\n `A.concat(B, \"vertical\"): A and B need same number of columns, A has ${cols_A} columns, B has ${cols_B} columns.`,\n );\n }\n const X = new Matrix(rows_A + rows_B, cols_A, \"zeros\");\n X.set_block(0, 0, this);\n X.set_block(rows_A, 0, B);\n return X;\n } else if (type === \"diag\") {\n const X = new Matrix(rows_A + rows_B, cols_A + cols_B, \"zeros\");\n X.set_block(0, 0, this);\n X.set_block(rows_A, cols_A, B);\n return X;\n } else {\n throw new Error(`type must be \"horizontal\" or \"vertical\", but type is ${type}!`);\n }\n }\n\n /**\n * Writes the entries of B in A at an offset position given by `offset_row` and `offset_col`.\n *\n * @param {number} offset_row\n * @param {number} offset_col\n * @param {Matrix} B\n * @returns {Matrix}\n */\n set_block(offset_row, offset_col, B) {\n const rows = Math.min(this._rows - offset_row, B.shape[0]);\n const cols = Math.min(this._cols - offset_col, B.shape[1]);\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col) {\n this.set_entry(row + offset_row, col + offset_col, B.entry(row, col));\n }\n }\n return this;\n }\n\n /**\n * Extracts the entries from the `start_row`th row to the `end_row`th row, the\n * `start_col`th column to the `end_col`th column of the matrix. If `end_row` or `end_col` is\n * empty, the respective value is set to `this.rows` or `this.cols`.\n *\n * @example let A = Matrix.from([ [1, 2, 3], [4, 5, 6], [7, 8, 9], ]); // a 3 by 3 matrix.\n *\n * A.get_block(1, 1); // [[5, 6], [8, 9]]\n * A.get_block(0, 0, 1, 1); // [[1]]\n * A.get_block(1, 1, 2, 2); // [[5]]\n * A.get_block(0, 0, 2, 2); // [[1, 2], [4, 5]]\n *\n * @param {number} start_row\n * @param {number} start_col\n * @param {number | null} [end_row]\n * @param {number | null} [end_col]\n * @returns {Matrix} Returns a `end_row` - `start_row` times `end_col` - `start_col` matrix, with respective entries\n * from the matrix.\n */\n get_block(start_row, start_col, end_row, end_col) {\n const [rows, cols] = this.shape;\n end_row = end_row ?? rows;\n end_col = end_col ?? cols;\n if (end_row <= start_row || end_col <= start_col) {\n throw new Error(`\n end_row must be greater than start_row, and\n end_col must be greater than start_col, but\n end_row = ${end_row}, start_row = ${start_row}, end_col = ${end_col}, and start_col = ${start_col}!`);\n }\n const X = new Matrix(end_row - start_row, end_col - start_col, \"zeros\");\n for (let row = start_row, new_row = 0; row < end_row; ++row, ++new_row) {\n for (let col = start_col, new_col = 0; col < end_col; ++col, ++new_col) {\n X.set_entry(new_row, new_col, this.entry(row, col));\n }\n }\n return X;\n }\n\n /**\n * Returns a new array gathering entries defined by the indices given by argument.\n *\n * @param {number[]} row_indices - Array consists of indices of rows for gathering entries of this matrix\n * @param {number[]} col_indices - Array consists of indices of cols for gathering entries of this matrix\n * @returns {Matrix}\n */\n gather(row_indices, col_indices) {\n const N = row_indices.length;\n const D = col_indices.length;\n\n const R = new Matrix(N, D);\n for (let i = 0; i < N; ++i) {\n const row_index = row_indices[i];\n for (let j = 0; j < D; ++j) {\n const col_index = col_indices[j];\n R.set_entry(i, j, this.entry(row_index, col_index));\n }\n }\n\n return R;\n }\n\n /**\n * Applies a function to each entry of the matrix.\n *\n * @private\n * @param {(d: number, v: number) => number} f Function takes 2 parameters, the value of the actual entry and a\n * value given by the function `v`. The result of `f` gets writen to the Matrix.\n * @param {Accessor} v Function takes 2 parameters for `row` and `col`, and returns a value witch should be applied\n * to the `col`th entry of the `row`th row of the matrix.\n * @returns {Matrix}\n */\n _apply_array(f, v) {\n const data = this.values;\n const [rows, cols] = this.shape;\n for (let i = 0, row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col, ++i) {\n data[i] = f(data[i], v(row, col));\n }\n }\n return this;\n }\n\n /**\n * @param {number[] | Float64Array} values\n * @param {(d: number, v: number) => number} f\n * @returns {Matrix}\n */\n _apply_rowwise_array(values, f) {\n return this._apply_array(f, (_, j) => values[j]);\n }\n /**\n * @param {number[] | Float64Array} values\n * @param {(d: number, v: number) => number} f\n * @returns {Matrix}\n */\n _apply_colwise_array(values, f) {\n const data = this.values;\n const [rows, cols] = this.shape;\n for (let i = 0, row = 0; row < rows; ++row) {\n const val = values[row];\n for (let col = 0; col < cols; ++col, ++i) {\n data[i] = f(data[i], val);\n }\n }\n return this;\n }\n\n /**\n * @param {Matrix | number[] | Float64Array | number} value\n * @param {(d: number, v: number) => number} f\n * @returns {Matrix}\n */\n _apply(value, f) {\n const data = this.values;\n const [rows, cols] = this.shape;\n if (value instanceof Matrix) {\n const values = value.values;\n const [value_rows, value_cols] = value.shape;\n if (value_rows === 1) {\n if (cols !== value_cols) {\n throw new Error(`cols !== value_cols`);\n }\n for (let i = 0, row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col, ++i) {\n data[i] = f(data[i], values[col]);\n }\n }\n } else if (value_cols === 1) {\n if (rows !== value_rows) {\n throw new Error(`rows !== value_rows`);\n }\n for (let i = 0, row = 0; row < rows; ++row) {\n const v = values[row];\n for (let col = 0; col < cols; ++col, ++i) {\n data[i] = f(data[i], v);\n }\n }\n } else if (rows === value_rows && cols === value_cols) {\n for (let i = 0, n = rows * cols; i < n; ++i) {\n data[i] = f(data[i], values[i]);\n }\n } else {\n throw new Error(`error`);\n }\n } else if (Matrix.isArray(value)) {\n if (value.length === rows) {\n for (let i = 0, row = 0; row < rows; ++row) {\n const v = value[row];\n for (let col = 0; col < cols; ++col, ++i) {\n data[i] = f(data[i], v);\n }\n }\n } else if (value.length === cols) {\n for (let i = 0, row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col, ++i) {\n data[i] = f(data[i], value[col]);\n }\n }\n } else {\n throw new Error(`error`);\n }\n } else {\n // scalar value\n for (let i = 0, n = rows * cols; i < n; ++i) {\n data[i] = f(data[i], value);\n }\n }\n return this;\n }\n\n /**\n * Clones the Matrix.\n *\n * @returns {Matrix}\n */\n clone() {\n const B = new Matrix(this._rows, this._cols);\n //B._rows = this._rows;\n //B._cols = this._cols;\n if (this._data) {\n B._data = this._data.slice(0);\n }\n return B;\n }\n\n /**\n * Entrywise multiplication with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.mult(2); // [[2, 4], [6, 8]];\n * A.mult(B); // [[1, 4], [9, 16]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {boolean} [options.inline=false] - If true, applies multiplication to the element, otherwise it creates\n * first a copy and applies the multiplication on the copy. Default is `false`\n * @returns {Matrix}\n */\n mult(value, { inline = false } = {}) {\n const A = inline ? this : this.clone();\n return A._apply(value, (a, b) => a * b);\n }\n\n /**\n * Entrywise division with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.divide(2); // [[0.5, 1], [1.5, 2]];\n * A.divide(B); // [[1, 1], [1, 1]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {Boolean} [options.inline=false] - If true, applies division to the element, otherwise it creates first a\n * copy and applies the division on the copy. Default is `false`\n * @returns {Matrix}\n */\n divide(value, { inline = false } = {}) {\n const A = inline ? this : this.clone();\n return A._apply(value, (a, b) => a / b);\n }\n\n /**\n * Entrywise addition with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.add(2); // [[3, 4], [5, 6]];\n * A.add(B); // [[2, 4], [6, 8]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {boolean} [options.inline=false] - If true, applies addition to the element, otherwise it creates first a\n * copy and applies the addition on the copy. Default is `false`\n * @returns {Matrix}\n */\n add(value, { inline = false } = {}) {\n const A = inline ? this : this.clone();\n return A._apply(value, (a, b) => a + b);\n }\n\n /**\n * Entrywise subtraction with `value`.\n *\n * @example let A = Matrix.from([ [1, 2], [3, 4], ]); // a 2 by 2 matrix. let B = A.clone(); // B == A;\n *\n * A.sub(2); // [[-1, 0], [1, 2]];\n * A.sub(B); // [[0, 0], [0, 0]];\n *\n * @param {Matrix | Float64Array | number[] | number} value\n * @param {Object} [options]\n * @param {boolean} [options.inline=false] - If true, applies subtraction to the element, otherwise it creates first\n * a copy and applies the subtraction on the copy. Default is `false`\n * @returns {Matrix}\n */\n sub(value, { inline = false } = {}) {\n const A = inline ? this : this.clone();\n return A._apply(value, (a, b) => a - b);\n }\n\n /**\n * Returns the number of rows and columns of the Matrix.\n *\n * @returns {number[]} An Array in the form [rows, columns].\n */\n get shape() {\n return [this._rows, this._cols];\n }\n\n /**\n * Returns the matrix in the given shape with the given function which returns values for the entries of the matrix.\n *\n * @param {[number, number, Accessor]} parameter - Takes an Array in the form [rows, cols, value], where rows and\n * cols are the number of rows and columns of the matrix, and value is a function which takes two parameters (row\n * and col) which has to return a value for the colth entry of the rowth row.\n * @returns {Matrix}\n */\n set shape([rows, cols, value = () => 0]) {\n this._rows = rows;\n this._cols = cols;\n this._data = new Float64Array(rows * cols);\n for (let i = 0, row = 0; row < rows; ++row) {\n for (let col = 0; col < cols; ++col, ++i) {\n this._data[i] = value(row, col);\n }\n }\n }\n\n /**\n * Returns the Matrix as a Array of Float64Arrays.\n *\n * @returns {Float64Array[]}\n */\n to2dArray() {\n const result = [];\n for (const row of this.iterate_rows()) {\n result.push(row);\n }\n return result;\n }\n\n /**\n * Returns the Matrix as a Array of Arrays.\n *\n * @returns {number[][]}\n */\n asArray() {\n const result = [];\n for (const row of this.iterate_rows()) {\n result.push(Array.from(row));\n }\n return result;\n }\n\n /**\n * Returns the diagonal of the Matrix.\n *\n * @returns {Float64Array}\n */\n diag() {\n const rows = this._rows;\n const cols = this._cols;\n const min_row_col = Math.min(rows, cols);\n const result = new Float64Array(min_row_col);\n for (let i = 0; i < min_row_col; ++i) {\n result[i] = this.entry(i, i);\n }\n return result;\n }\n\n /**\n * Returns the mean of all entries of the Matrix.\n *\n * @returns {number}\n */\n mean() {\n const sum = this.sum();\n const n = this._rows * this._cols;\n return sum / n;\n }\n\n /**\n * Returns the sum oof all entries of the Matrix.\n *\n * @returns {number}\n */\n sum() {\n const data = this.values;\n return neumair_sum(data);\n }\n\n /**\n * Returns the entries of the Matrix.\n *\n * @returns {Float64Array}\n */\n get values() {\n const data = this._data;\n return data;\n }\n\n /**\n * Returns the mean of each row of the matrix.\n *\n * @returns {Float64Array}\n */\n meanRows() {\n const data = this.values;\n const rows = this._rows;\n const cols = this._cols;\n const result = Float64Array.from({ length: rows });\n for (let i = 0, row = 0; row < rows; ++row) {\n let sum = 0;\n for (let col = 0; col < cols; ++col, ++i) {\n sum += data[i];\n }\n result[row] = sum / cols;\n }\n return result;\n }\n\n /**\n * Returns the mean of each column of the matrix.\n *\n * @returns {Float64Array}\n */\n meanCols() {\n const data = this.values;\n const rows = this._rows;\n const cols = this._cols;\n const result = Float64Array.from({ length: cols });\n for (let col = 0; col < cols; ++col) {\n let sum = 0;\n for (let i = col, row = 0; row < rows; ++row, i += cols) {\n sum += data[i];\n }\n result[col] = sum / rows;\n }\n return result;\n }\n\n /**\n * Solves the equation `Ax = b` using the conjugate gradient method. Returns the result `x`.\n *\n * @param {Matrix} A - Matrix\n * @param {Matrix} b - Matrix\n * @param {Randomizer | null} [randomizer]\n * @param {number} [tol=1e-3] Default is `1e-3`\n * @returns {Matrix}\n */\n static solve_CG(A, b, randomizer, tol = 1e-3) {\n if (!randomizer) {\n randomizer = new Randomizer();\n }\n const rows = A.shape[0];\n const cols = b.shape[1];\n let result = new Matrix(rows, 0);\n for (let i = 0; i < cols; ++i) {\n const b_i = Matrix.from_vector(b.col(i), \"col\");\n let x = new Matrix(rows, 1, () => randomizer.random);\n let r = b_i.sub(A.dot(x));\n let d = r.clone();\n let iter = 0;\n const max_iter = rows * 10; // Prevent infinite loops\n do {\n const z = A.dot(d);\n const alpha = r.transDot(r).entry(0, 0) / d.transDot(z).entry(0, 0);\n x = x.add(d.mult(alpha));\n const r_next = r.sub(z.mult(alpha));\n const beta = r_next.transDot(r_next).entry(0, 0) / r.transDot(r).entry(0, 0);\n d = r_next.add(d.mult(beta));\n r = r_next;\n iter++;\n } while (Math.abs(r.mean()) > tol && iter < max_iter);\n result = result.concat(x, \"horizontal\");\n }\n return result;\n }\n\n /**\n * Solves the equation `Ax = b`. Returns the result `x`.\n *\n * @param {Matrix | { L: Matrix; U: Matrix }} A - Matrix or LU Decomposition\n * @param {Matrix} b - Matrix\n * @returns {Matrix}\n */\n static solve(A, b) {\n const { L, U } = \"L\" in A && \"U\" in A ? A : Matrix.LU(A);\n const rows = L.shape[0];\n const x = b.clone();\n\n // forward\n for (let row = 0; row < rows; ++row) {\n for (let col = 0; col < row; ++col) {\n x.sub_entry(0, row, L.entry(row, col) * x.entry(0, col));\n }\n x.set_entry(0, row, x.entry(0, row) / L.entry(row, row));\n }\n\n // backward\n for (let row = rows - 1; row >= 0; --row) {\n for (let col = rows - 1; col > row; --col) {\n x.sub_entry(0, row, U.entry(row, col) * x.entry(0, col));\n }\n x.set_entry(0, row, x.entry(0, row) / U.entry(row, row));\n }\n\n return x;\n }\n\n /**\n * `LU` decomposition of the Matrix `A`. Creates two matrices, so that the dot product `LU` equals `A`.\n *\n * @param {Matrix} A\n * @returns {{ L: Matrix; U: Matrix }} The left triangle matrix `L` and the upper triangle matrix `U`.\n */\n static LU(A) {\n const rows = A.shape[0];\n const L = new Matrix(rows, rows, \"zeros\");\n const U = new Matrix(rows, rows, \"identity\");\n\n for (let j = 0; j < rows; ++j) {\n for (let i = j; i < rows; ++i) {\n let sum = 0;\n for (let k = 0; k < j; ++k) {\n sum += L.entry(i, k) * U.entry(k, j);\n }\n L.set_entry(i, j, A.entry(i, j) - sum);\n }\n for (let i = j; i < rows; ++i) {\n if (L.entry(j, j) === 0) {\n throw new Error(\"L's diagonal not supposed to be 0!\");\n }\n let sum = 0;\n for (let k = 0; k < j; ++k) {\n sum += L.entry(j, k) * U.entry(k, i);\n }\n U.set_entry(j, i, (A.entry(j, i) - sum) / L.entry(j, j));\n }\n }\n\n return { L, U };\n }\n\n /**\n * Computes the determinante of `A`, by using the `LU` decomposition of `A`.\n *\n * @param {Matrix} A\n * @returns {number} The determinate of the Matrix `A`.\n */\n static det(A) {\n const [rows, cols] = A.shape;\n\n if (rows === 2 && cols === 2) {\n return A.entry(0, 0) * A.entry(1, 1) - A.entry(0, 1) * A.entry(1, 0);\n }\n if (rows === 3 && cols === 3) {\n const a = A.entry(0, 0);\n const b = A.entry(0, 1);\n const c = A.entry(0, 2);\n const d = A.entry(1, 0);\n const e = A.entry(1, 1);\n const f = A.entry(1, 2);\n const g = A.entry(2, 0);\n const h = A.entry(2, 1);\n const i = A.entry(2, 2);\n return a * (e * i - f * h) - b * (d * i - f * g) + c * (d * h - e * g);\n }\n\n const { L, U } = Matrix.LU(A);\n const L_diag = L.diag();\n const U_diag = U.diag();\n let det = L_diag[0] * U_diag[0];\n for (let row = 1; row < rows; ++row) {\n det *= L_diag[row] * U_diag[row];\n }\n return det;\n }\n\n /**\n * Computes the `k` components of the SVD decomposition of the matrix `M`.\n *\n * @param {Matrix} M\n * @param {number} [k=2] Default is `2`\n * @returns {{ U: Float64Array[]; Sigma: Float64Array; V: Float64Array[] }}\n */\n static SVD(M, k = 2) {\n const MtM = M.transDot(M);\n const MMt = M.dotTrans(M);\n const { eigenvectors: V, eigenvalues: Sigma } = simultaneous_poweriteration(MtM, k);\n const { eigenvectors: U } = simultaneous_poweriteration(MMt, k);\n return { U: U, Sigma: Sigma.map((sigma) => Math.sqrt(sigma)), V: V };\n\n //Algorithm 1a: Householder reduction to bidiagonal form:\n /* const [m, n] = A.shape;\n let U = new Matrix(m, n, (i, j) => i == j ? 1 : 0);\n console.log(U.to2dArray)\n let V = new Matrix(n, m, (i, j) => i == j ? 1 : 0);\n console.log(V.to2dArray)\n let B = Matrix.bidiagonal(A.clone(), U, V);\n console.log(U,V,B)\n return { U: U, \"Sigma\": B, V: V }; */\n }\n\n /**\n * @param {unknown} A\n * @returns {A is unknown[]|number[]|Float64Array|Float32Array}\n */\n static isArray(A) {\n return Array.isArray(A) || A instanceof Float64Array || A instanceof Float32Array;\n }\n\n /**\n * @param {any[]} A\n * @returns {A is number[][]|Float64Array[]}\n */\n static is2dArray(A) {\n if (!Array.isArray(A) || A.length === 0) {\n return false;\n }\n const n = A[0].length;\n for (let i = 0; i < A.length; ++i) {\n if (!Array.isArray(A[i]) && !(A[i] instanceof Float64Array)) {\n return false;\n }\n if (A[i].length !== n) {\n return false;\n }\n }\n return true;\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n\n/**\n * Computes the norm of a vector, by computing its distance to **0**.\n *\n * @category Matrix\n * @param {Matrix | number[] | Float64Array} v - Vector.\n * @param {Metric} [metric=euclidean] - Which metric should be used to compute the norm. Default is `euclidean`\n * @returns {number} - The norm of `v`.\n */\nexport function norm(v, metric = euclidean) {\n let vector = null;\n if (v instanceof Matrix) {\n const [rows, cols] = v.shape;\n if (rows === 1) vector = v.row(0);\n else if (cols === 1) vector = v.col(0);\n else throw new Error(\"Matrix must be 1d!\");\n } else {\n vector = v;\n }\n const n = vector.length;\n const zeros = new Float64Array(n);\n return metric(vector, zeros);\n}\n","import { euclidean } from \"../metrics/index.js\";\nimport { norm } from \"./index.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n\n/**\n * Normalizes Vector `v`.\n *\n * @category Matrix\n * @param {number[] | Float64Array} v - Vector\n * @param {Metric} metric\n * @returns {number[] | Float64Array} - The normalized vector with length 1.\n */\nexport function normalize(v, metric = euclidean) {\n const v_norm = norm(v, metric);\n return v.map((value) => value / v_norm);\n}\n","import { Matrix } from \"../matrix/index.js\";\n\n/** @import {InputType} from \"../index.js\" */\n\n/**\n * Base class for all clustering algorithms.\n * @template Para\n */\nexport class Clustering {\n /** @type {InputType} */\n _points;\n /** @type {Para} */\n _parameters;\n /** @type {Matrix} */\n _matrix;\n /** @type {number} */\n _N;\n /** @type {number} */\n _D;\n\n /**\n * Compute the respective Clustering with given parameters\n * @param {InputType} points\n * @param {Para} parameters\n */\n constructor(points, parameters) {\n this._points = points;\n this._parameters = parameters;\n\n this._matrix = points instanceof Matrix ? points : Matrix.from(points);\n const [N, D] = this._matrix.shape;\n this._N = N;\n this._D = D;\n }\n\n /**\n * @abstract\n * @param {...unknown} args\n * @returns {number[][]} An array with the indices of the clusters.\n */\n get_clusters(...args) {\n args;\n throw new Error(\"The function get_clusters must be implemented!\");\n }\n\n /**\n * @abstract\n * @param {...unknown} args\n * @returns {number[]} An array with the clusters id's for each point.\n */\n get_cluster_list(...args) {\n args;\n throw new Error(\"The function get_cluster_list must be implemented!\");\n }\n}\n","import { euclidean } from \"../metrics/index.js\";\nimport { Clustering } from \"./Clustering.js\";\n\n/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersCURE } from \"./index.js\" */\n\n/**\n * CURE (Clustering Using REpresentatives)\n *\n * An efficient clustering algorithm for large databases that is robust to outliers\n * and identifies clusters with non-spherical shapes and wide variances in size.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class CURE extends Clustering {\n /** @type {number} */\n _K;\n /** @type {number} */\n _num_representatives;\n /** @type {number} */\n _shrink_factor;\n /**\n * @private\n * @type {CURECluster[]}\n */\n _clusters = [];\n /** @type {number[]} */\n _cluster_ids = [];\n\n /**\n * @param {InputType} points\n * @param {Partial} parameters\n */\n constructor(points, parameters = {}) {\n super(\n points,\n /** @type {ParametersCURE} */ (\n Object.assign(\n { K: 2, num_representatives: 5, shrink_factor: 0.5, metric: euclidean, seed: 1212 },\n parameters,\n )\n ),\n );\n\n this._K = this._parameters.K ?? 2;\n this._num_representatives = this._parameters.num_representatives ?? 5;\n this._shrink_factor = this._parameters.shrink_factor ?? 0.5;\n\n // Initialize clusters\n this._initialize_clusters();\n // Run CURE algorithm\n this._cure();\n }\n\n /**\n * Initialize each point as its own cluster\n * @private\n */\n _initialize_clusters() {\n const N = this._N;\n //const D = this._D;\n this._clusters = [];\n\n for (let i = 0; i < N; ++i) {\n const point = this._matrix.row(i);\n const centroid = new Float64Array(point);\n // For single point, representative is the point itself\n const representatives = [new Float64Array(point)];\n\n this._clusters.push(new CURECluster([i], centroid, representatives));\n }\n }\n\n /**\n * Compute distance between two clusters using representative points\n * @private\n * @param {CURECluster} cluster1\n * @param {CURECluster} cluster2\n * @returns {number}\n */\n _cluster_distance(cluster1, cluster2) {\n const reps1 = cluster1.representatives;\n const reps2 = cluster2.representatives;\n const metric = this._parameters.metric;\n\n let min_dist = Infinity;\n for (const r1 of reps1) {\n for (const r2 of reps2) {\n const dist = metric(r1, r2);\n if (dist < min_dist) {\n min_dist = dist;\n }\n }\n }\n return min_dist;\n }\n\n /**\n * Find the closest pair of clusters\n * @private\n * @returns {[number, number, number]} [index1, index2, distance]\n */\n _find_closest_clusters() {\n let min_dist = Infinity;\n let min_i = 0;\n let min_j = 1;\n\n for (let i = 0; i < this._clusters.length; ++i) {\n for (let j = i + 1; j < this._clusters.length; ++j) {\n const dist = this._cluster_distance(this._clusters[i], this._clusters[j]);\n if (dist < min_dist) {\n min_dist = dist;\n min_i = i;\n min_j = j;\n }\n }\n }\n\n return [min_i, min_j, min_dist];\n }\n\n /**\n * Merge two clusters\n * @private\n * @param {CURECluster} cluster1\n * @param {CURECluster} cluster2\n * @returns {CURECluster}\n */\n _merge_clusters(cluster1, cluster2) {\n // Merge indices\n const merged_indices = [...cluster1.indices, ...cluster2.indices];\n\n // Calculate new centroid\n const size1 = cluster1.indices.length;\n const size2 = cluster2.indices.length;\n const total_size = size1 + size2;\n const D = this._D;\n const new_centroid = new Float64Array(D);\n\n for (let d = 0; d < D; ++d) {\n new_centroid[d] = (size1 * cluster1.centroid[d] + size2 * cluster2.centroid[d]) / total_size;\n }\n\n // Collect all points from both clusters\n /** @type {{index: number, point: Float64Array}[]} */\n const all_points = [];\n for (const idx of cluster1.indices) {\n all_points.push({ index: idx, point: this._matrix.row(idx) });\n }\n for (const idx of cluster2.indices) {\n all_points.push({ index: idx, point: this._matrix.row(idx) });\n }\n\n // Select representative points - pick points farthest from centroid\n const num_reps = Math.min(this._num_representatives, all_points.length);\n const metric = this._parameters.metric;\n\n // Calculate distances from centroid for all points\n const distances = all_points.map(({ point }) => metric(point, new_centroid));\n\n // Select num_reps points with maximum distance (farthest from centroid)\n const selected_indices = [];\n const used = new Set();\n\n for (let r = 0; r < num_reps; ++r) {\n let max_dist = -1;\n let max_idx = -1;\n\n for (let i = 0; i < distances.length; ++i) {\n if (!used.has(i) && distances[i] > max_dist) {\n max_dist = distances[i];\n max_idx = i;\n }\n }\n\n if (max_idx >= 0) {\n used.add(max_idx);\n selected_indices.push(max_idx);\n }\n }\n\n // Shrink representative points toward centroid\n const new_representatives = selected_indices.map((idx) => {\n const point = all_points[idx].point;\n const shrunk = new Float64Array(D);\n const alpha = this._shrink_factor;\n\n for (let d = 0; d < D; ++d) {\n shrunk[d] = point[d] + alpha * (new_centroid[d] - point[d]);\n }\n\n return shrunk;\n });\n\n return new CURECluster(merged_indices, new_centroid, new_representatives);\n }\n\n /**\n * Run CURE clustering algorithm\n * @private\n */\n _cure() {\n // Merge clusters until we have K clusters\n while (this._clusters.length > this._K) {\n const [i, j] = this._find_closest_clusters();\n\n // Merge clusters i and j\n const merged = this._merge_clusters(this._clusters[i], this._clusters[j]);\n\n // Remove the old clusters and add the merged one\n // Remove larger index first to maintain correct indices\n // min_i < min_j is always true from _find_closest_clusters\n this._clusters.splice(j, 1);\n this._clusters.splice(i, 1);\n\n this._clusters.push(merged);\n }\n\n // Build cluster list for get_cluster_list\n this._build_cluster_ids();\n }\n\n /**\n * Build the cluster list (point -> cluster assignment)\n * @private\n */\n _build_cluster_ids() {\n const N = this._N;\n this._cluster_ids = new Array(N).fill(-1);\n\n for (let c = 0; c < this._clusters.length; ++c) {\n for (const idx of this._clusters[c].indices) {\n this._cluster_ids[idx] = c;\n }\n }\n }\n\n /**\n * @returns {number[][]}\n */\n get_clusters() {\n return this._clusters.map((cluster) => cluster.indices);\n }\n\n /**\n * @returns {number[]}\n */\n get_cluster_list() {\n return this._cluster_ids;\n }\n}\n\n/**\n * @private\n * Represents a cluster in CURE algorithm\n */\nclass CURECluster {\n /**\n * @param {number[]} indices - Indices of points in the cluster\n * @param {Float64Array} centroid - Centroid of the cluster\n * @param {Float64Array[]} representatives - Representative points (shrunk toward centroid)\n */\n constructor(indices, centroid, representatives) {\n /** @type {number[]} */\n this.indices = indices;\n /** @type {Float64Array} */\n this.centroid = centroid;\n /** @type {Float64Array[]} */\n this.representatives = representatives;\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Clustering } from \"./Clustering.js\";\n\n/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersHierarchicalClustering } from \"./index.js\" */\n\n/**\n * Hierarchical Clustering\n *\n * A bottom-up approach (agglomerative) to clustering that builds a tree of clusters (dendrogram).\n * Supports different linkage criteria: single, complete, and average.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class HierarchicalClustering extends Clustering {\n /** @type {Cluster | null} */\n root = null;\n\n /**\n * @param {InputType} points - Data or distance matrix if metric is 'precomputed'\n * @param {Partial} parameters\n */\n constructor(points, parameters = {}) {\n super(\n points,\n /** @type {ParametersHierarchicalClustering} */ (\n Object.assign({ linkage: \"complete\", metric: euclidean }, parameters)\n ),\n );\n this._id = 0;\n if (this._parameters.metric === \"precomputed\" && this._matrix.shape[0] !== this._matrix.shape[1]) {\n throw new Error(\"If metric is 'precomputed', then matrix has to be square!\");\n }\n\n const metric = this._parameters.metric;\n const A = this._matrix;\n const N = this._N;\n this._d_min = new Float64Array(N);\n const d_min = this._d_min;\n let distance_matrix;\n if (metric !== \"precomputed\") {\n distance_matrix = new Matrix(N, N, Infinity);\n for (let i = 0; i < N; ++i) {\n distance_matrix.set_entry(i, i, 0);\n d_min[i] = i; // temporary\n const Ai = A.row(i);\n for (let j = i + 1; j < N; ++j) {\n const dist = metric(Ai, A.row(j));\n distance_matrix.set_entry(i, j, dist);\n distance_matrix.set_entry(j, i, dist);\n }\n }\n for (let i = 0; i < N; i++) {\n let min_j = 0;\n let min_d = Infinity;\n for (let j = 0; j < N; j++) {\n if (i === j) continue;\n const d = distance_matrix.entry(i, j);\n if (d < min_d) {\n min_d = d;\n min_j = j;\n }\n }\n d_min[i] = min_j;\n }\n } else {\n distance_matrix = this._matrix.clone();\n for (let i = 0; i < N; ++i) {\n distance_matrix.set_entry(i, i, 0);\n d_min[i] = i === 0 ? 1 : 0;\n for (let j = 0; j < N; ++j) {\n if (i === j) continue;\n if (distance_matrix.entry(i, d_min[i]) > distance_matrix.entry(i, j)) {\n d_min[i] = j;\n }\n }\n }\n }\n this._distance_matrix = distance_matrix;\n this._clusters = new Array(N);\n const clusters = this._clusters;\n this._c_size = new Uint16Array(N);\n const c_size = this._c_size;\n for (let i = 0; i < N; ++i) {\n clusters[i] = [];\n clusters[i][0] = new Cluster(this._id++, null, null, 0, A.row(i), i, 1, 0);\n c_size[i] = 1;\n }\n const D = this._distance_matrix;\n const linkage = this._parameters.linkage;\n const p_max = N - 1;\n for (let p = 0; p < p_max; ++p) {\n let c1 = -1;\n let min_dist = Infinity;\n for (let i = 0; i < N; ++i) {\n if (D.entry(i, i) === Infinity) continue;\n const dist = D.entry(i, d_min[i]);\n if (dist < min_dist) {\n min_dist = dist;\n c1 = i;\n }\n }\n if (c1 === -1) break;\n\n const c2 = d_min[c1];\n const c1_cluster = clusters[c1][0];\n const c2_cluster = clusters[c2][0];\n const c1_cluster_indices = c1_cluster.isLeaf ? [c1_cluster.index] : c1_cluster.index;\n const c2_cluster_indices = c2_cluster.isLeaf ? [c2_cluster.index] : c2_cluster.index;\n const indices = c1_cluster_indices.concat(c2_cluster_indices);\n const new_cluster = new Cluster(this._id++, c1_cluster, c2_cluster, D.entry(c1, c2), null, indices);\n c1_cluster.parent = new_cluster;\n c2_cluster.parent = new_cluster;\n clusters[c1].unshift(new_cluster);\n\n const size1 = c_size[c1];\n const size2 = c_size[c2];\n c_size[c1] += size2;\n\n for (let j = 0; j < N; ++j) {\n if (j === c1 || j === c2 || D.entry(j, j) === Infinity) continue;\n const D_c1_j = D.entry(c1, j);\n const D_c2_j = D.entry(c2, j);\n let value;\n switch (linkage) {\n case \"single\":\n value = Math.min(D_c1_j, D_c2_j);\n break;\n case \"complete\":\n value = Math.max(D_c1_j, D_c2_j);\n break;\n case \"average\":\n value = (size1 * D_c1_j + size2 * D_c2_j) / (size1 + size2);\n break;\n }\n D.set_entry(j, c1, value);\n D.set_entry(c1, j, value);\n }\n\n D.set_entry(c2, c2, Infinity);\n for (let i = 0; i < N; ++i) {\n D.set_entry(i, c2, Infinity);\n D.set_entry(c2, i, Infinity);\n }\n\n // Update d_min for all rows\n for (let i = 0; i < N; i++) {\n if (D.entry(i, i) === Infinity) continue;\n if (d_min[i] === c1 || d_min[i] === c2 || i === c1) {\n let min_j = 0;\n let min_d = Infinity;\n for (let j = 0; j < N; j++) {\n if (i === j || D.entry(j, j) === Infinity) continue;\n const d = D.entry(i, j);\n if (d < min_d) {\n min_d = d;\n min_j = j;\n }\n }\n d_min[i] = min_j;\n } else {\n if (D.entry(i, c1) < D.entry(i, d_min[i])) {\n d_min[i] = c1;\n }\n }\n }\n\n this.root = new_cluster;\n }\n }\n\n /**\n * @param {number} value - Value where to cut the tree.\n * @param {\"distance\" | \"depth\"} [type=\"distance\"] - Type of value. Default is `\"distance\"`\n * @returns {Cluster[][]} - Array of clusters with the indices of the rows in given points.\n */\n get_clusters_raw(value, type = \"distance\") {\n /** @type {Cluster[][]} */\n const clusters = [];\n /** @type {(d: {dist: number, depth: number}) => number} */\n let accessor;\n switch (type) {\n case \"distance\":\n accessor = (d) => d.dist;\n break;\n case \"depth\":\n accessor = (d) => d.depth;\n break;\n default:\n throw new Error(\"invalid type\");\n }\n this._traverse(/** @type {Cluster} */ (this.root), accessor, value, clusters);\n return clusters;\n }\n\n /**\n * @param {number} value - Value where to cut the tree.\n * @param {\"distance\" | \"depth\"} [type=\"distance\"] - Type of value. Default is `\"distance\"`\n * @returns {number[][]} - Array of clusters with the indices of the rows in given points.\n */\n get_clusters(value, type = \"distance\") {\n /** @type {Cluster[][]} */\n const clusters = [];\n /** @type {(d: {dist: number, depth: number}) => number} */\n let accessor;\n switch (type) {\n case \"distance\":\n accessor = (d) => d.dist;\n break;\n case \"depth\":\n accessor = (d) => d.depth;\n break;\n default:\n throw new Error(\"invalid type\");\n }\n if (this.root) this._traverse(this.root, accessor, value, clusters);\n return clusters.map((cluster) => cluster.map((d) => d.index));\n }\n\n /**\n * @param {number} value - Value where to cut the tree.\n * @param {\"distance\" | \"depth\"} [type=\"distance\"] - Type of value. Default is `\"distance\"`\n * @returns {number[]} - Array of clusters with the indices of the rows in given points.\n */\n get_cluster_list(value, type = \"distance\") {\n const clusters = this.get_clusters(value, type);\n /** @type {number[]} */\n const list = new Array(this._N).fill(0);\n for (let i = 0; i < clusters.length; ++i) {\n const cluster = clusters[i];\n for (let j = 0; j < cluster.length; ++j) {\n const index = cluster[j];\n list[index] = i;\n }\n }\n return list;\n }\n\n /**\n * @private\n * @param {Cluster} node\n * @param {(d: {dist: number, depth: number}) => number} f\n * @param {number} value\n * @param {Cluster[][]} result\n */\n _traverse(node, f, value, result) {\n if (f(node) <= value) {\n result.push(node.leaves());\n } else {\n if (node.left) this._traverse(node.left, f, value, result);\n if (node.right) this._traverse(node.right, f, value, result);\n }\n }\n}\n\n/** @private */\nclass Cluster {\n /**@type {number} */\n size;\n /**@type {number} */\n depth;\n /**@type {Cluster | null} */\n parent;\n\n /**\n *\n * @param {number} id\n * @param {Cluster?} left\n * @param {Cluster?} right\n * @param {number} dist\n * @param {Float64Array?} centroid\n * @param {number} index\n * @param {number} [size]\n * @param {number} [depth]\n */\n constructor(id, left, right, dist, centroid, index, size, depth) {\n this.id = id;\n this.left = left;\n this.right = right;\n this.dist = dist;\n this.index = index;\n if (size) {\n this.size = size;\n } else {\n if (!left || !right) throw new Error(\"If size is not given, left & right cannot be null!\");\n this.size = left.size + right.size;\n }\n\n if (depth !== undefined) {\n this.depth = depth;\n } else {\n if (!left || !right) throw new Error(\"If depth is not given, left & right cannot be null!\");\n this.depth = Math.max(left.depth, right.depth) + 1;\n }\n\n if (centroid !== undefined && centroid !== null) {\n this.centroid = centroid;\n } else {\n if (!left || !right) throw new Error(\"If centroid is not given, left & right cannot be null!\");\n\n this.centroid = this._calculate_centroid(left, right);\n }\n\n this.parent = null;\n }\n\n /**\n *\n * @param {Cluster} left\n * @param {Cluster} right\n * @returns {Float64Array}\n */\n _calculate_centroid(left, right) {\n const l_size = left.size;\n const r_size = right.size;\n const l_centroid = left.centroid;\n const r_centroid = right.centroid;\n const size = this.size;\n const n = left.centroid.length;\n const new_centroid = new Float64Array(n);\n for (let i = 0; i < n; ++i) {\n new_centroid[i] = (l_size * l_centroid[i] + r_size * r_centroid[i]) / size;\n }\n return new_centroid;\n }\n\n get isLeaf() {\n return this.depth === 0;\n }\n\n /**\n *\n * @returns {Cluster[]}\n */\n leaves() {\n if (this.isLeaf) return [this];\n const left = this.left;\n const right = this.right;\n return (left ? (left.isLeaf ? [left] : left.leaves()) : []).concat(\n right ? (right.isLeaf ? [right] : right.leaves()) : [],\n );\n }\n\n /**\n *\n * @returns {Cluster[]}\n */\n descendants() {\n if (this.isLeaf) return [this];\n const left_descendants = this.left ? this.left.descendants() : [];\n const right_descendants = this.right ? this.right.descendants() : [];\n return left_descendants.concat(right_descendants).concat([this]);\n }\n}\n","/**\n * @template T\n * @typedef {Object} DisjointSetPayload\n * @property {T} parent\n * @property {Set} children\n * @property {number} size\n */\n\n/**\n * @template T\n * @class\n * @category Data Structures\n * @see {@link https://en.wikipedia.org/wiki/Disjoint-set_data_structure}\n */\nexport class DisjointSet {\n /**\n * @param {T[]?} elements\n */\n constructor(elements = null) {\n /**\n * @private\n * @type {Map>}\n */\n this._list = new Map();\n if (elements) {\n for (const e of elements) {\n this.make_set(e);\n }\n }\n }\n\n /**\n * @private\n * @param {T} x\n * @returns {DisjointSet}\n */\n make_set(x) {\n const list = this._list;\n if (!list.has(x)) {\n list.set(x, { parent: x, children: new Set([x]), size: 1 });\n }\n return this;\n }\n\n /**\n * @param {T} x\n * @returns\n */\n find(x) {\n const list = this._list;\n const disjoint_set = list.get(x);\n if (disjoint_set) {\n if (disjoint_set.parent !== x) {\n disjoint_set.children.add(x);\n const new_parent = this.find(disjoint_set.parent);\n if (!new_parent) throw new Error(\"should not happen!\");\n disjoint_set.parent = new_parent;\n return disjoint_set.parent;\n } else {\n return x;\n }\n } else {\n return null;\n }\n }\n\n /**\n * @param {T} x\n * @param {T} y\n * @returns\n */\n union(x, y) {\n let node_x = this.find(x);\n let node_y = this.find(y);\n\n if (!node_x || !node_y) throw new Error(\"x or y not found!\");\n\n let disjoint_set_x = this._list.get(node_x);\n let disjoint_set_y = this._list.get(node_y);\n\n if (!disjoint_set_x || !disjoint_set_y) throw new Error(\"should not happen!\");\n\n if (node_x === node_y) return this;\n if (disjoint_set_x.size < disjoint_set_y.size) {\n [node_x, node_y] = [node_y, node_x];\n [disjoint_set_x, disjoint_set_y] = [disjoint_set_y, disjoint_set_x];\n }\n\n disjoint_set_y.parent = node_x;\n // keep track of children\n disjoint_set_y.children.forEach(disjoint_set_x.children.add, disjoint_set_x.children);\n disjoint_set_x.size += disjoint_set_y.size;\n\n return this;\n }\n\n /** @param {T} x */\n get_children(x) {\n const node = this._list.get(x);\n if (node) {\n return node.children;\n } else {\n return null;\n }\n }\n}\n","/** @import { Comparator } from \"./index.js\" */\n\n/**\n * @template T\n * @class\n * @category Data Structures\n */\nexport class Heap {\n /** @type {{ element: T; value: number }[]} */\n _container;\n\n /** @type {Comparator} */\n _comparator;\n\n /**\n * A heap is a datastructure holding its elements in a specific way, so that the top element would be the first\n * entry of an ordered list.\n *\n * @param {T[]?} elements - Contains the elements for the Heap. `elements` can be null.\n * @param {(d: T) => number} accessor - Function returns the value of the element.\n * @param {\"min\" | \"max\" | Comparator} [comparator=\"min\"] - Function returning true or false\n * defining the wished order of the Heap, or String for predefined function. (\"min\" for a Min-Heap, \"max\" for a\n * Max_heap). Default is `\"min\"`\n * @see {@link https://en.wikipedia.org/wiki/Binary_heap}\n */\n constructor(elements = null, accessor, comparator = \"min\") {\n /** @type {(d: T) => number} */\n this._accessor = accessor;\n this._container = [];\n if (comparator === \"min\") {\n this._comparator = (a, b) => a < b;\n } else if (comparator === \"max\") {\n this._comparator = (a, b) => a > b;\n } else {\n this._comparator = comparator;\n }\n if (elements) {\n this._container = [];\n for (const e of elements) {\n this._container.push({\n element: e,\n value: accessor(e),\n });\n }\n for (let i = Math.floor(elements.length / 2 - 1); i >= 0; --i) {\n this._heapify_down(i);\n }\n }\n }\n\n /**\n * Creates a Heap from an Array\n *\n * @template T\n * @param {T[]} elements - Contains the elements for the Heap.\n * @param {(d: T) => number} accessor - Function returns the value of the element.\n * @param {\"min\" | \"max\" | Comparator} [comparator=\"min\"] - Function returning true or false\n * defining the wished order of the Heap, or String for predefined function. (\"min\" for a Min-Heap, \"max\" for a\n * Max_heap). Default is `\"min\"`\n * @returns {Heap}\n */\n static heapify(elements, accessor, comparator = \"min\") {\n const heap = new Heap(null, accessor, comparator);\n const container = heap._container;\n for (const e of elements) {\n container.push({\n element: e,\n value: accessor(e),\n });\n }\n for (let i = Math.floor(elements.length / 2 - 1); i >= 0; --i) {\n heap._heapify_down(i);\n }\n return heap;\n }\n\n /**\n * Swaps elements of container array.\n *\n * @private\n * @param {number} index_a\n * @param {number} index_b\n */\n _swap(index_a, index_b) {\n const container = this._container;\n [container[index_b], container[index_a]] = [container[index_a], container[index_b]];\n return;\n }\n\n /** @private */\n _heapify_up() {\n const container = this._container;\n let index = container.length - 1;\n while (index > 0) {\n const parentIndex = Math.floor((index - 1) / 2);\n if (!this._comparator(container[index].value, container[parentIndex].value)) {\n break;\n } else {\n this._swap(parentIndex, index);\n index = parentIndex;\n }\n }\n }\n\n /**\n * Pushes the element to the heap.\n *\n * @param {T} element\n * @returns {Heap}\n */\n push(element) {\n const value = this._accessor(element);\n //const node = new Node(element, value);\n const node = { element: element, value: value };\n this._container.push(node);\n this._heapify_up();\n return this;\n }\n\n /**\n * @private\n * @param {Number} [start_index=0] Default is `0`\n */\n _heapify_down(start_index = 0) {\n const container = this._container;\n const comparator = this._comparator;\n const length = container.length;\n const left = 2 * start_index + 1;\n const right = 2 * start_index + 2;\n let index = start_index;\n if (index >= length) throw \"index higher than length\";\n if (left < length && comparator(container[left].value, container[index].value)) {\n index = left;\n }\n if (right < length && comparator(container[right].value, container[index].value)) {\n index = right;\n }\n if (index !== start_index) {\n this._swap(start_index, index);\n this._heapify_down(index);\n }\n }\n\n /**\n * Removes and returns the top entry of the heap.\n *\n * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by\n * `accessor`}).\n */\n pop() {\n const container = this._container;\n if (container.length === 0) {\n return null;\n } else if (container.length === 1) {\n const item = container.pop();\n if (!item) throw new Error(\"Cannot happen!\");\n return item;\n }\n this._swap(0, container.length - 1);\n const item = container.pop();\n this._heapify_down();\n return item ?? null;\n }\n\n /**\n * Returns the top entry of the heap without removing it.\n *\n * @returns {{ element: T; value: number } | null} Object consists of the element and its value (computed by\n * `accessor`).\n */\n get first() {\n return this._container.length > 0 ? this._container[0] : null;\n }\n\n /**\n * Yields the raw data\n *\n * @yields {T} Object consists of the element and its value (computed by `accessor`}).\n */\n *iterate() {\n for (let i = 0, n = this._container.length; i < n; ++i) {\n yield this._container[i].element;\n }\n }\n\n /**\n * Returns the heap as ordered array.\n *\n * @returns {T[]} Array consisting the elements ordered by `comparator`.\n */\n toArray() {\n return this._container.sort((a, b) => (this._comparator(a.value, b.value) ? -1 : 1)).map((d) => d.element);\n }\n\n /**\n * Returns elements of container array.\n *\n * @returns {T[]} Array consisting the elements.\n */\n data() {\n return this._container.map((d) => d.element);\n }\n\n /**\n * Returns the container array.\n *\n * @returns {{ element: T; value: number }[]} The container array.\n */\n raw_data() {\n return this._container;\n }\n\n /**\n * The size of the heap.\n *\n * @returns {number}\n */\n get length() {\n return this._container.length;\n }\n\n /**\n * Returns false if the the heap has entries, true if the heap has no entries.\n *\n * @returns {boolean}\n */\n get empty() {\n return this.length === 0;\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { linspace, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { Clustering } from \"./Clustering.js\";\n\n/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersKMeans } from \"./index.js\" */\n/**\n * K-Means Clustering\n *\n * A popular clustering algorithm that partitions data into K clusters where each point\n * belongs to the cluster with the nearest mean (centroid).\n *\n * @class\n * @extends Clustering\n * @category Clustering\n * @see {@link KMedoids} for a more robust alternative\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const points = [[1, 1], [1.5, 1.5], [5, 5], [5.5, 5.5]];\n * const kmeans = new druid.KMeans(points, { K: 2 });\n *\n * const clusters = kmeans.get_cluster_list(); // [0, 0, 1, 1]\n * const centroids = kmeans.centroids; // center points\n */\nexport class KMeans extends Clustering {\n /**\n * @param {InputType} points\n * @param {Partial} parameters\n */\n constructor(points, parameters = {}) {\n super(\n points,\n /** @type {ParametersKMeans} */ (Object.assign({ K: 4, metric: euclidean, seed: 1212 }, parameters)),\n );\n\n const K = this._parameters.K;\n const seed = parameters.seed;\n\n // Convert points to Matrix if needed\n if (points instanceof Matrix) {\n this._matrix = points;\n } else {\n this._matrix = Matrix.from(points);\n }\n\n const [N, D] = this._matrix.shape;\n this._N = N;\n this._D = D;\n\n this._K = K > N ? N : K;\n this._randomizer = new Randomizer(seed);\n\n /** @type {number[]} */\n this._clusters = new Array(N).fill(0);\n\n this._cluster_centroids = parameters.initial_centroids\n ? parameters.initial_centroids.map((c) => new Float64Array(c))\n : this._get_random_centroids(this._K);\n let cluster_centroids = this._cluster_centroids;\n let iterations = 0;\n const max_iterations = 300;\n let clusters_changed = true;\n\n while (clusters_changed && iterations < max_iterations) {\n const iteration_result = this._iteration(cluster_centroids);\n cluster_centroids = iteration_result.cluster_centroids;\n clusters_changed = iteration_result.clusters_changed;\n iterations++;\n }\n\n this._cluster_centroids = cluster_centroids;\n }\n\n /** @returns {number} The number of clusters */\n get k() {\n return this._K;\n }\n\n /** @returns {Float64Array[]} The cluster centroids */\n get centroids() {\n return this._cluster_centroids;\n }\n\n /** @returns {number[]} The cluster list */\n get_cluster_list() {\n return this._clusters;\n }\n\n /** @returns {number[][]} An Array of clusters with the indices of the points. */\n get_clusters() {\n const K = this._K;\n const clusters = this._clusters;\n /** @type {number[][]} */\n const result = new Array(K).fill(0).map(() => []);\n clusters.forEach((c, i) => {\n if (c >= 0 && c < K) {\n result[c].push(i);\n }\n });\n return result;\n }\n\n /**\n * @private\n * @param {number[]} point_indices\n * @param {number[]} candidates\n * @returns {number}\n */\n _furthest_point(point_indices, candidates) {\n const A = this._matrix;\n const metric = this._parameters.metric;\n\n if (point_indices.length === 0 || candidates.length === 0) {\n return candidates[0] ?? 0;\n }\n\n const H = Heap.heapify(\n candidates,\n (d) => {\n const Ad = A.row(d);\n let sum = 0;\n for (let j = 0; j < point_indices.length; ++j) {\n sum += metric(Ad, A.row(point_indices[j]));\n }\n return sum;\n },\n \"max\",\n );\n\n const furthest = H.pop();\n if (!furthest) throw new Error(\"Should not happen!\");\n\n return furthest.element;\n }\n\n /**\n * @private\n * @param {number} K\n * @returns {Float64Array[]}\n */\n _get_random_centroids(K) {\n const N = this._N;\n const randomizer = this._randomizer;\n const A = this._matrix;\n /** @type {Float64Array[]} */\n const cluster_centroids = new Array(K);\n const indices = linspace(0, N - 1);\n\n // First centroid: random selection\n const random_point = randomizer.random_int % N;\n cluster_centroids[0] = A.row(random_point);\n const init_points = [random_point];\n\n const sample_size = Math.max(1, Math.floor((N - K) / K));\n\n for (let i = 1; i < K; ++i) {\n const remaining = indices.filter((d) => !init_points.includes(d));\n if (remaining.length === 0) break;\n\n const sample = randomizer.choice(remaining, Math.min(sample_size, remaining.length));\n const furthest_point = this._furthest_point(init_points, sample);\n\n init_points.push(furthest_point);\n cluster_centroids[i] = A.row(furthest_point);\n }\n\n return cluster_centroids;\n }\n\n /**\n * @private\n * @param {Float64Array[]} cluster_centroids\n * @returns {{ clusters_changed: boolean; cluster_centroids: Float64Array[] }}\n */\n _iteration(cluster_centroids) {\n const K = cluster_centroids.length;\n const N = this._N;\n const metric = this._parameters.metric;\n const A = this._matrix;\n const clusters = this._clusters;\n let clusters_changed = false;\n\n // Find nearest cluster centroid for each point\n for (let i = 0; i < N; ++i) {\n const Ai = A.row(i);\n let min_dist = Infinity;\n let min_cluster = 0;\n\n for (let j = 0; j < K; ++j) {\n const d = metric(cluster_centroids[j], Ai);\n if (d < min_dist) {\n min_dist = d;\n min_cluster = j;\n }\n }\n\n if (clusters[i] !== min_cluster) {\n clusters_changed = true;\n clusters[i] = min_cluster;\n }\n }\n\n // Update cluster centroids\n const new_centroids = this._compute_centroid(K);\n\n return {\n clusters_changed: clusters_changed,\n cluster_centroids: new_centroids,\n };\n }\n\n /**\n * @private\n * @param {number} K\n * @returns {Float64Array[]}\n */\n _compute_centroid(K) {\n const N = this._N;\n const D = this._D;\n const A = this._matrix;\n const clusters = this._clusters;\n\n // Initialize new centroids and counters\n /** @type {Float64Array[]} */\n const new_centroids = new Array(K);\n const cluster_counter = new Array(K).fill(0);\n\n for (let i = 0; i < K; ++i) {\n new_centroids[i] = new Float64Array(D);\n }\n\n // Sum up all points in each cluster\n for (let i = 0; i < N; ++i) {\n const Ai = A.row(i);\n const ci = clusters[i];\n if (ci >= 0 && ci < K) {\n cluster_counter[ci]++;\n const centroid = new_centroids[ci];\n for (let j = 0; j < D; ++j) {\n centroid[j] += Ai[j];\n }\n }\n }\n\n // Divide by count to get mean\n for (let i = 0; i < K; ++i) {\n const n = cluster_counter[i];\n if (n > 0) {\n const centroid = new_centroids[i];\n for (let j = 0; j < D; ++j) {\n centroid[j] /= n;\n }\n }\n }\n\n return new_centroids;\n }\n}\n","import { linspace, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { Clustering } from \"./Clustering.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import { ParametersKMedoids } from \"./index.js\" */\n\n/**\n * K-Medoids (PAM - Partitioning Around Medoids)\n *\n * A robust clustering algorithm similar to K-Means, but uses actual data points (medoids)\n * as cluster centers and can work with any distance metric.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n * @see {@link KMeans} for a faster but less robust alternative\n */\nexport class KMedoids extends Clustering {\n /**\n * @param {InputType} points - Data matrix\n * @param {Partial} parameters\n * @see {@link https://link.springer.com/chapter/10.1007/978-3-030-32047-8_16} Faster k-Medoids Clustering: Improving the PAM, CLARA, and CLARANS Algorithms\n */\n constructor(points, parameters = {}) {\n super(points, Object.assign({ K: 4, max_iter: null, metric: euclidean, seed: 1212 }, parameters));\n this._A = this._matrix.to2dArray();\n let K = this._parameters.K;\n const N = this._N;\n this._max_iter = this._parameters.max_iter ?? 10 * Math.log10(N);\n this._distance_matrix = new Matrix(N, N, \"zeros\");\n\n if (K > N) {\n this._parameters.K = K = N;\n }\n this._randomizer = new Randomizer(this._parameters.seed);\n this._clusters = new Array(N).fill(-1);\n this._cluster_medoids = this._get_random_medoids(K);\n this._is_initialized = false;\n }\n\n /** @returns {number[]} The cluster list */\n get_cluster_list() {\n if (!this._is_initialized) {\n this.get_clusters();\n }\n return this._clusters;\n }\n\n /** @returns {number[][]} - Array of clusters with the indices of the rows in given points. */\n get_clusters() {\n const K = this._parameters.K;\n const A = this._A;\n const N = this._N;\n if (!this._is_initialized) {\n this.init(K, this._cluster_medoids);\n }\n /** @type {number[][]} */\n const result = new Array(K).fill(0).map(() => []);\n for (let j = 0; j < N; j++) {\n const nearest = this._nearest_medoid(A[j], j);\n const cluster_idx = nearest.index_nearest;\n result[cluster_idx].push(j);\n this._clusters[j] = cluster_idx;\n }\n return result;\n }\n\n /** @returns {number} */\n get k() {\n return this._parameters.K;\n }\n\n /** @returns {number[]} */\n get medoids() {\n return this.get_medoids();\n }\n\n /** @returns {number[]} */\n get_medoids() {\n const K = this._parameters.K;\n if (!this._is_initialized) {\n this.init(K, this._cluster_medoids);\n }\n return this._cluster_medoids;\n }\n\n async *generator() {\n const max_iter = this._max_iter;\n if (!this._is_initialized) {\n this.get_clusters();\n }\n yield this.get_clusters();\n let i = 0;\n while (i < max_iter) {\n const finish = this._iteration();\n this._update_clusters();\n yield this.get_clusters();\n if (finish) break;\n i++;\n }\n }\n\n /** Algorithm 1. FastPAM1: Improved SWAP algorithm */\n /* _iteration_1() {\n const A = this._A;\n const N = this._N;\n const K = this._K;\n const medoids = this._cluster_medoids;\n let DeltaTD = 0;\n let m0 = null;\n let x0 = null;\n A.forEach((x_j, j) => {\n if (medoids.findIndex(m => m === j) < 0) {\n const nearest_medoid = this._nearest_medoid(x_j, j);\n const d_j = nearest_medoid.distance_nearest; // distance to current medoid\n const deltaTD = new Array(K).fill(-d_j); // change if making j a medoid\n A.forEach((x_o, o) => {\n // disance to new medoid\n const d_oj = this._get_distance(o, j, x_o, x_j);\n const {\n \"index_nearest\": n,\n \"distance_nearest\": d_n,\n \"distance_second\": d_s,\n } = this._nearest_medoid(x_o, o);\n this._clusters[o] = n; // cached values\n deltaTD[n] += Math.min(d_oj, d_s) - d_n; // loss change\n if (d_oj < d_n) { // reassignment check\n deltaTD.forEach((d_i, i) => {\n if (n !== i) {\n deltaTD[i] = d_i + d_oj - d_n; // update loss change\n }\n });\n }\n });\n // choose best medoid i;\n const i = deltaTD\n .map((d, i) => [d, i])\n .sort((d1, d2) => d1[0] - d2[0])[0][1];\n const deltaTD_i = deltaTD[i];\n // store\n if (deltaTD_i < DeltaTD) {\n DeltaTD = deltaTD_i;\n m0 = i;\n x0 = j;\n }\n }\n });\n\n if (DeltaTD >= 0) {\n return true // break loop if DeltaTD >= 0\n }\n // swap roles of medoid m and non-medoid x;\n medoids[m0] = x0;\n this._cluster_medoids = medoids;\n return false\n } */\n\n /**\n * FastPAM1: One best swap per iteration\n * @private\n * @returns {boolean}\n */\n _iteration() {\n const A = this._A;\n const K = this._parameters.K;\n const medoids = this._cluster_medoids;\n const N = this._N;\n\n // Precompute nearest and second nearest medoid for all points\n const cache = new Array(N);\n for (let i = 0; i < N; i++) {\n cache[i] = this._nearest_medoid(A[i], i);\n }\n\n let best_delta = 0;\n let best_swap = null; // { m_idx: index in medoids, x_idx: index in A }\n\n // For each non-medoid point j, evaluate swapping it with each medoid i\n const medoid_set = new Set(medoids);\n for (let j = 0; j < N; j++) {\n if (medoid_set.has(j)) continue;\n\n const x_j = A[j];\n const d_j = cache[j].distance_nearest;\n\n // deltaTD[i] will store the change in total distance if we swap medoid[i] with j\n const deltaTD = new Array(K).fill(-d_j);\n\n for (let o = 0; o < N; o++) {\n if (o === j) continue;\n const dist_o_j = this._get_distance(o, j, A[o], x_j);\n const { index_nearest: n, distance_nearest: d_n, distance_second: d_s } = cache[o];\n\n // If o is assigned to the current medoid being swapped out (n)\n deltaTD[n] += Math.min(dist_o_j, d_s) - d_n;\n\n // For all other medoids i != n, if j is closer to o than its current medoid\n if (dist_o_j < d_n) {\n for (let i = 0; i < K; i++) {\n if (i !== n) {\n deltaTD[i] += dist_o_j - d_n;\n }\n }\n }\n }\n\n // Find best medoid to swap with j\n for (let i = 0; i < K; i++) {\n if (deltaTD[i] < best_delta) {\n best_delta = deltaTD[i];\n best_swap = { m_idx: i, x_idx: j };\n }\n }\n }\n\n if (best_swap && best_delta < 0) {\n medoids[best_swap.m_idx] = best_swap.x_idx;\n this._cluster_medoids = medoids;\n return false; // not finished\n }\n\n return true; // finished\n }\n\n /**\n * @private\n * Get distance between two points\n * @param {number} i\n * @param {number} j\n * @param {Float64Array?} x_i\n * @param {Float64Array?} x_j\n * @returns {number}\n */\n _get_distance(i, j, x_i = null, x_j = null) {\n if (i === j) return 0;\n const D = this._distance_matrix;\n const A = this._A;\n const metric = this._parameters.metric;\n let d_ij = D.entry(i, j);\n if (d_ij === 0) {\n d_ij = metric(x_i || A[i], x_j || A[j]);\n D.set_entry(i, j, d_ij);\n D.set_entry(j, i, d_ij);\n }\n return d_ij;\n }\n\n /**\n * @private\n * @param {Float64Array} x_j\n * @param {number} j\n * @returns\n */\n _nearest_medoid(x_j, j) {\n const medoids = this._cluster_medoids;\n const A = this._A;\n if (medoids.length === 0) {\n throw new Error(\"No medoids available. Initialization failed.\");\n }\n\n let d_n = Infinity;\n let n = -1;\n let d_s = Infinity;\n let s = -1;\n\n for (let i = 0; i < medoids.length; i++) {\n const m = medoids[i];\n const d = this._get_distance(j, m, x_j, A[m]);\n if (d < d_n) {\n d_s = d_n;\n s = n;\n d_n = d;\n n = i;\n } else if (d < d_s) {\n d_s = d;\n s = i;\n }\n }\n\n if (s === -1) s = n;\n\n return {\n distance_nearest: d_n,\n index_nearest: n,\n distance_second: d_s,\n index_second: s,\n };\n }\n\n /**\n * @private\n */\n _update_clusters() {\n const N = this._N;\n const A = this._A;\n for (let j = 0; j < N; j++) {\n const nearest = this._nearest_medoid(A[j], j);\n this._clusters[j] = nearest.index_nearest;\n }\n }\n\n /**\n * Computes `K` clusters out of the `matrix`.\n * @param {number} K - Number of clusters.\n * @param {number[]} cluster_medoids\n */\n init(K, cluster_medoids) {\n if (!K) K = this._parameters.K;\n if (!cluster_medoids) cluster_medoids = this._get_random_medoids(K);\n this._cluster_medoids = cluster_medoids;\n const max_iter = this._max_iter;\n let finish = false;\n let i = 0;\n do {\n finish = this._iteration();\n } while (!finish && ++i < max_iter);\n this._update_clusters();\n this._is_initialized = true;\n return this;\n }\n\n /**\n * Algorithm 3. FastPAM LAB: Linear Approximate BUILD initialization.\n * @private\n * @param {number} K - Number of clusters\n * @returns {number[]}\n */\n _get_random_medoids(K) {\n const N = this._N;\n const A = this._A;\n const indices = linspace(0, N - 1);\n const randomizer = this._randomizer;\n const n = Math.min(N, 10 + Math.ceil(Math.sqrt(N)));\n\n // Handle case where K >= N\n if (K >= N) {\n return indices.slice(0, N);\n }\n\n /** @type {number[]} */\n const medoids = [];\n\n // first medoid: select from a random sample of size n\n let best_j = -1;\n let min_td = Infinity;\n let S = randomizer.choice(indices, n);\n for (let j = 0; j < S.length; ++j) {\n let td = 0;\n const S_j = S[j];\n const x_j = A[S_j];\n for (let o = 0; o < S.length; ++o) {\n if (o === j) continue;\n td += this._get_distance(S_j, S[o], x_j, A[S[o]]);\n }\n if (td < min_td) {\n min_td = td;\n best_j = S_j;\n }\n }\n medoids.push(best_j);\n\n // other medoids: greedy additive selection (Algorithm LAB)\n for (let i = 1; i < K; ++i) {\n let best_idx = -1;\n let best_delta = Infinity;\n\n const remainingIndices = indices.filter((idx) => !medoids.includes(idx));\n if (remainingIndices.length === 0) break;\n\n S = randomizer.choice(remainingIndices, Math.min(n, remainingIndices.length));\n for (let j = 0; j < S.length; ++j) {\n let deltaTD = 0;\n const S_j = S[j];\n const x_j = A[S_j];\n\n // Estimate TD reduction on the sample S\n for (let o = 0; o < S.length; ++o) {\n if (o === j) continue;\n const S_o = S[o];\n const x_o = A[S_o];\n\n // Closest distance to current medoids\n let min_d_existing = Infinity;\n for (let m = 0; m < medoids.length; m++) {\n const d = this._get_distance(S_o, medoids[m], x_o, A[medoids[m]]);\n if (d < min_d_existing) min_d_existing = d;\n }\n\n const delta = this._get_distance(S_j, S_o, x_j, x_o) - min_d_existing;\n if (delta < 0) {\n deltaTD += delta;\n }\n }\n\n if (deltaTD < best_delta) {\n best_delta = deltaTD;\n best_idx = S_j;\n }\n }\n if (best_idx !== -1) {\n medoids.push(best_idx);\n }\n }\n return medoids;\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Clustering } from \"./Clustering.js\";\n\n/** @import { ParametersMeanShift } from \"./index.js\" */\n/** @import { InputType } from \"../index.js\" */\n\n/**\n * Mean Shift Clustering\n *\n * A non-parametric clustering technique that does not require prior knowledge of the\n * number of clusters. It identifies centers of density in the data.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class MeanShift extends Clustering {\n /**\n * @private\n * @type {number}\n */\n _bandwidth;\n /**\n * @private\n * @type {number}\n */\n _max_iter;\n /**\n * @private\n * @type {number}\n */\n _tolerance;\n /**\n * @private\n * @type {(dist: number) => number}\n */\n _kernel;\n /**\n * @type {Matrix}\n */\n _points;\n /**\n * @private\n * @type {number[] | undefined}\n */\n _clusters;\n /**\n * @private\n * @type {number[][] | undefined}\n */\n _cluster_list;\n\n /**\n *\n * @param {InputType} points\n * @param {Partial} parameters\n */\n constructor(points, parameters = {}) {\n super(\n points,\n /** @type {ParametersMeanShift} */ (\n Object.assign({ seed: 1212, metric: euclidean, bandwidth: 0, kernel: \"gaussian\" }, parameters)\n ),\n );\n\n // Ensure bandwidth is positive\n this._bandwidth = parameters.bandwidth ?? this._compute_bandwidth(this._matrix);\n this._max_iter = parameters.max_iter ?? Math.max(10, Math.floor(10 * Math.log10(this._N)));\n this._tolerance = parameters.tolerance ?? 1e-3;\n const kernel_param = parameters.kernel ?? \"gaussian\";\n // If kernel is a string, map to function\n if (typeof kernel_param === \"string\") {\n if (kernel_param === \"flat\") {\n this._kernel = (dist) => (dist <= this._bandwidth ? 1 : 0);\n } else {\n // gaussian (default)\n this._kernel = (dist) => Math.exp(-(dist * dist) / (2 * this._bandwidth * this._bandwidth));\n }\n } else {\n // custom function\n this._kernel = kernel_param;\n }\n\n // Copy points to a mutable matrix\n this._points = this._matrix.clone();\n\n this._mean_shift();\n this._assign_clusters();\n }\n\n /**\n * Helper to compute bandwidth if not provided\n * @private\n * @param {Matrix} matrix\n * @returns {number}\n */\n _compute_bandwidth(matrix) {\n const N = matrix.shape[0];\n //const D = matrix.shape[1];\n // Compute average pairwise distance\n let totalDist = 0;\n for (let i = 0; i < N; ++i) {\n const row_i = matrix.row(i);\n for (let j = i + 1; j < N; ++j) {\n const row_j = matrix.row(j);\n const dist = this._parameters.metric(row_i, row_j);\n totalDist += dist;\n }\n }\n const avgDist = totalDist / ((N * (N - 1)) / 2);\n // Use a fraction of avgDist as bandwidth\n return avgDist / 2;\n }\n\n /**\n * Compute kernel weight\n * @private\n * @param {number} dist\n * @returns {number}\n */\n _kernel_weight(dist) {\n return this._kernel(dist);\n }\n\n /**\n * Perform mean shift iterations\n * @private\n */\n _mean_shift() {\n const N = this._N;\n const D = this._D;\n const points = this._points;\n const metric = this._parameters.metric;\n //const bandwidth = this._bandwidth;\n const kernel = this._kernel_weight.bind(this);\n const tolerance = this._tolerance;\n\n for (let iter = 0; iter < this._max_iter; ++iter) {\n let max_shift = 0;\n // For each point compute shift\n for (let i = 0; i < N; ++i) {\n const row_i = points.row(i);\n let sum_weights = 0;\n const weighted_sum = new Float64Array(D);\n for (let j = 0; j < N; ++j) {\n const row_j = points.row(j);\n const dist = metric(row_i, row_j);\n const weight = kernel(dist);\n sum_weights += weight;\n for (let d = 0; d < D; ++d) {\n weighted_sum[d] += weight * row_j[d];\n }\n }\n if (sum_weights === 0) {\n // No neighbors within kernel, shift is zero\n //const shift = new Float64Array(D);\n // Compute shift magnitude\n const shift_norm = Math.sqrt(weighted_sum.reduce((acc, v) => acc + v * v, 0));\n max_shift = Math.max(max_shift, shift_norm);\n } else {\n const shift = new Float64Array(D);\n for (let d = 0; d < D; ++d) {\n shift[d] = weighted_sum[d] / sum_weights - row_i[d];\n }\n const shift_norm = Math.sqrt(shift.reduce((acc, v) => acc + v * v, 0));\n max_shift = Math.max(max_shift, shift_norm);\n // Update point\n for (let d = 0; d < D; ++d) {\n row_i[d] += shift[d];\n }\n }\n }\n if (max_shift < tolerance) {\n // Converged\n break;\n }\n }\n }\n\n /**\n * After convergence, assign clusters based on nearest mode\n * @private\n */\n _assign_clusters() {\n const N = this._N;\n const metric = this._parameters.metric;\n const bandwidth = this._bandwidth;\n\n // Group points that converged to the same mode\n // Two points are in the same mode if they're within bandwidth/2 of each other\n const mode_threshold = bandwidth * 0.5;\n /** @type {number[][]} */\n const modes = []; // Each mode contains indices of points in that mode\n const point_to_mode = new Array(N).fill(-1);\n\n for (let i = 0; i < N; ++i) {\n if (point_to_mode[i] !== -1) continue; // Already assigned to a mode\n\n const row_i = this._points.row(i);\n const mode = [i];\n point_to_mode[i] = modes.length;\n\n // Find all points close to this mode\n for (let j = i + 1; j < N; ++j) {\n if (point_to_mode[j] !== -1) continue;\n\n const row_j = this._points.row(j);\n const dist = metric(row_i, row_j);\n\n if (dist < mode_threshold) {\n mode.push(j);\n point_to_mode[j] = modes.length;\n }\n }\n\n modes.push(mode);\n }\n\n // Build final clusters - each mode becomes a cluster\n /** @type {number[][]} */\n const clusters = [];\n const cluster_ids = new Array(N).fill(-1);\n\n for (let mode_idx = 0; mode_idx < modes.length; ++mode_idx) {\n const mode = modes[mode_idx];\n clusters.push([...mode]);\n for (const point_idx of mode) {\n cluster_ids[point_idx] = mode_idx;\n }\n }\n\n this._clusters = cluster_ids;\n this._cluster_list = clusters;\n }\n\n /**\n * @returns {number[][]}\n */\n get_clusters() {\n // Ensure algorithm has been run\n if (!this._cluster_list) {\n this._mean_shift();\n this._assign_clusters();\n }\n return /** @type {number[][]} */ (this._cluster_list);\n }\n\n /**\n *\n * @returns {number[]}\n */\n get_cluster_list() {\n if (!this._clusters) {\n this._mean_shift();\n this._assign_clusters();\n }\n return /** @type {number[]} */ (this._clusters);\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Clustering } from \"./Clustering.js\";\n\n/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersOptics } from \"./index.js\" */\n\n/** @typedef {Object} DBEntry\n * @property {Float64Array} element\n * @property {number} index\n * @property {number} [reachability_distance]\n * @property {boolean} processed\n * @property {DBEntry[]} [neighbors]\n */\n\n/**\n * OPTICS (Ordering Points To Identify the Clustering Structure)\n *\n * A density-based clustering algorithm that extends DBSCAN. It handles clusters of varying\n * densities and produces a reachability plot that can be used to extract clusters.\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class OPTICS extends Clustering {\n /**\n * **O**rdering **P**oints **T**o **I**dentify the **C**lustering **S**tructure.\n *\n * @param {InputType} points - The data.\n * @param {Partial} [parameters={}]\n * @see {@link https://www.dbs.ifi.lmu.de/Publikationen/Papers/OPTICS.pdf}\n * @see {@link https://en.wikipedia.org/wiki/OPTICS_algorithm}\n */\n constructor(points, parameters = {}) {\n super(\n points,\n /** @type {ParametersOptics} */ (\n Object.assign({ epsilon: 1, min_points: 4, metric: euclidean }, parameters)\n ),\n );\n const matrix = this._matrix;\n /**\n * @private\n * @type {DBEntry[]}\n */\n this._ordered_list = [];\n const ordered_list = this._ordered_list;\n /** @type {number[][]} */\n this._clusters = [];\n const clusters = this._clusters;\n\n const N = this._N;\n\n /**\n * @private\n * @type {DBEntry[]}\n */\n this._DB = new Array(N).fill(0).map((_, i) => {\n return {\n element: matrix.row(i),\n index: i,\n reachability_distance: undefined,\n processed: false,\n };\n });\n const DB = this._DB;\n\n this._cluster_index = 0;\n let cluster_index = this._cluster_index;\n\n for (const p of DB) {\n if (p.processed) continue;\n p.neighbors = this._get_neighbors(p);\n p.processed = true;\n clusters.push([p.index]);\n cluster_index = clusters.length - 1;\n ordered_list.push(p);\n if (this._core_distance(p) !== undefined) {\n const seeds = new Heap(null, (d) => d.reachability_distance, \"min\");\n this._update(p, seeds);\n this._expand_cluster(seeds, clusters[cluster_index]);\n }\n }\n }\n\n /**\n * @private\n * @param {DBEntry} p - A point of the data.\n * @returns {DBEntry[]} An array consisting of the `epsilon`-neighborhood of `p`.\n */\n _get_neighbors(p) {\n if (p?.neighbors) return p.neighbors;\n const DB = this._DB;\n const metric = this._parameters.metric;\n const epsilon = this._parameters.epsilon;\n const neighbors = [];\n for (const q of DB) {\n if (q.index === p.index) continue;\n if (metric(p.element, q.element) <= epsilon) {\n neighbors.push(q);\n }\n }\n return neighbors;\n }\n\n /**\n * @private\n * @param {DBEntry} p - A point of `matrix`.\n * @returns {number|undefined} The distance to the `min_points`-th nearest point of `p`, or undefined if the\n * `epsilon`-neighborhood has fewer elements than `min_points`.\n */\n _core_distance(p) {\n const min_points = this._parameters.min_points;\n const metric = this._parameters.metric;\n // Need min_points - 1 other points plus the point itself\n if (!p.neighbors || p.neighbors.length < min_points - 1) {\n return undefined;\n }\n // Sort neighbors by distance to find the MinPts-th closest\n const sortedNeighbors = p.neighbors.toSorted(\n (a, b) => metric(p.element, a.element) - metric(p.element, b.element),\n );\n // MinPts-th closest is at index min_points - 2 (0-indexed, excluding p itself)\n return metric(p.element, sortedNeighbors[min_points - 2].element);\n }\n\n /**\n * Updates the reachability distance of the points.\n *\n * @private\n * @param {DBEntry} p\n * @param {Heap} seeds\n */\n _update(p, seeds) {\n const metric = this._parameters.metric;\n const core_distance = this._core_distance(p);\n // If p is not a core point, don't update seeds\n if (core_distance === undefined) {\n return;\n }\n const neighbors = this._get_neighbors(p); //p.neighbors;\n for (const q of neighbors) {\n if (q.processed) continue;\n const new_reachability_distance = Math.max(core_distance, metric(p.element, q.element));\n //if (q.reachability_distance == undefined) { // q is not in seeds\n if (seeds.raw_data().findIndex((d) => d.element === q) < 0) {\n q.reachability_distance = new_reachability_distance;\n seeds.push(q);\n } else {\n // q is in seeds\n if (new_reachability_distance < (q.reachability_distance ?? Infinity)) {\n q.reachability_distance = new_reachability_distance;\n seeds = Heap.heapify(seeds.data(), (d) => d.reachability_distance ?? Infinity, \"min\"); // seeds change key =/\n }\n }\n }\n }\n\n /**\n * Expands the `cluster` with points in `seeds`.\n *\n * @private\n * @param {Heap} seeds\n * @param {number[]} cluster\n */\n _expand_cluster(seeds, cluster) {\n const ordered_list = this._ordered_list;\n while (!seeds.empty) {\n const q = /** @type {{ element: DBEntry, value: number}} */ (seeds.pop()).element;\n q.neighbors = this._get_neighbors(q);\n q.processed = true;\n cluster.push(q.index);\n ordered_list.push(q);\n if (this._core_distance(q) !== undefined) {\n this._update(q, seeds);\n // Recursive call removed - while loop handles iteration correctly\n }\n }\n }\n\n /**\n * Returns an array of clusters.\n *\n * @returns {number[][]} Array of clusters with the indices of the rows in given `matrix`.\n */\n get_clusters() {\n const clusters = [];\n const outliers = [];\n const min_points = this._parameters.min_points;\n for (const cluster of this._clusters) {\n if (cluster.length < min_points) {\n outliers.push(...cluster);\n } else {\n clusters.push(cluster);\n }\n }\n clusters.push(outliers);\n return clusters;\n }\n\n /**\n * @returns {number[]} Returns an array, where the ith entry defines the cluster affirmation of the ith point of\n * given data. (-1 stands for outlier)\n */\n get_cluster_list() {\n const N = this._matrix.shape[0];\n /** @type {number[]} */\n const result = new Array(N).fill(0);\n const clusters = this.get_clusters();\n for (let i = 0, n = clusters.length; i < n; ++i) {\n const cluster = clusters[i];\n for (const index of cluster) {\n result[index] = i < n - 1 ? i : -1;\n }\n }\n return result;\n }\n}\n","import { euclidean, euclidean_squared } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { Clustering } from \"./Clustering.js\";\nimport { KMeans } from \"./KMeans.js\";\n\n/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersXMeans } from \"./index.js\" */\n\n/**\n * @typedef SplitResult\n * @property {number} index - Index of the cluster being split\n * @property {number} bic_parent - BIC score of the parent cluster\n * @property {number} bic_children - BIC score of the split children\n * @property {number[][]} child_clusters - Clusters after splitting\n * @property {Float64Array[]} child_centroids - Centroids of child clusters\n */\n\n/**\n * @typedef CandidateResult\n * @property {KMeans} kmeans - The KMeans instance for this K\n * @property {number} score - BIC score\n */\n\n/**\n * X-Means Clustering\n *\n * An extension of K-Means that automatically determines the number of clusters (K)\n * using the Bayesian Information Criterion (BIC).\n *\n * @class\n * @extends Clustering\n * @category Clustering\n */\nexport class XMeans extends Clustering {\n /**\n * XMeans clustering algorithm that automatically determines the optimal number of clusters.\n *\n * X-Means extends K-Means by starting with a minimum number of clusters and iteratively\n * splitting clusters to improve the Bayesian Information Criterion (BIC).\n *\n * Algorithm:\n * 1. Start with K_min clusters using KMeans\n * 2. For each cluster, try splitting it into 2 sub-clusters\n * 3. If BIC improves after splitting, keep the split\n * 4. Run KMeans again with all (old + new) centroids\n * 5. Repeat until K_max is reached or no more improvements\n *\n * @param {InputType} points - The data points to cluster\n * @param {Partial} [parameters={}] - Configuration parameters\n * @see {@link https://www.cs.cmu.edu/~dpelleg/download/xmeans.pdf}\n * @see {@link https://github.com/annoviko/pyclustering/blob/master/pyclustering/cluster/xmeans.py}\n * @see {@link https://github.com/haifengl/smile/blob/master/core/src/main/java/smile/clustering/XMeans.java}\n */\n constructor(points, parameters = {}) {\n const defaults = {\n K_max: 10,\n K_min: 2,\n metric: euclidean,\n seed: 1212,\n min_cluster_size: 35,\n tolerance: 0.001,\n };\n super(points, /** @type {ParametersXMeans} */ (Object.assign(defaults, parameters)));\n this._randomizer = new Randomizer(this._parameters.seed);\n\n /** @type {KMeans | null} */\n this._best_kmeans = null;\n\n // Run XMeans algorithm\n this._run();\n }\n\n /**\n * Run the XMeans algorithm\n *\n * @private\n */\n _run() {\n /** @type {Map} */\n const candidates = new Map();\n const A = this._matrix;\n\n // Initialize with K_min clusters\n let current_kmeans = new KMeans(this._points, {\n K: this._parameters.K_min,\n metric: this._parameters.metric,\n seed: this._parameters.seed,\n });\n\n let K = this._parameters.K_min;\n\n candidates.set(K, {\n kmeans: current_kmeans,\n score: -Infinity,\n });\n\n // Iteratively improve clustering\n while (K < this._parameters.K_max) {\n const clusters = current_kmeans.get_clusters();\n const centroids = current_kmeans.centroids;\n\n // Try splitting each cluster\n /** @type {SplitResult[]} */\n const split_results = [];\n\n for (let j = 0; j < clusters.length; ++j) {\n const cluster = clusters[j];\n\n // Skip small clusters - need enough points for reliable BIC\n if (cluster.length < this._parameters.min_cluster_size) {\n continue;\n }\n\n // Get subset data for this cluster\n /** @type {number[][]} */\n const subset_points = cluster.map((idx) => {\n const row = A.row(idx);\n return Array.from(row);\n });\n\n // Calculate BIC for parent (single cluster)\n const parent_bic = this._bic([cluster], [centroids[j]]);\n\n // Run KMeans with K=2 on subset\n const subset_kmeans = new KMeans(subset_points, {\n K: 2,\n metric: this._parameters.metric,\n seed: this._randomizer.seed,\n });\n\n const child_clusters_local = subset_kmeans.get_clusters();\n const child_centroids = subset_kmeans.centroids;\n\n // Map local indices back to global indices\n /** @type {number[][]} */\n const child_clusters_global = child_clusters_local.map((local_cluster) =>\n local_cluster.map((local_idx) => cluster[local_idx]),\n );\n\n // Calculate BIC for children (split into 2 clusters)\n const children_bic = this._bic(child_clusters_global, child_centroids);\n\n split_results.push({\n index: j,\n bic_parent: parent_bic,\n bic_children: children_bic,\n child_clusters: child_clusters_global,\n child_centroids: child_centroids,\n });\n }\n\n // Keep all splits that improve BIC (BIC_children > BIC_parent)\n /** @type {SplitResult[]} */\n const accepted_splits = split_results.filter((result) => result.bic_children > result.bic_parent);\n\n // If no splits improve BIC, we're done\n if (accepted_splits.length === 0) {\n break;\n }\n\n // Build new centroids array: keep non-split centroids + add split centroids\n /** @type {Float64Array[]} */\n const new_centroids = [];\n const split_indices = new Set();\n\n // Sort accepted splits by improvement (descending)\n accepted_splits.sort((a, b) => b.bic_children - b.bic_parent - (a.bic_children - a.bic_parent));\n\n for (const split of accepted_splits) {\n if (centroids.length + split_indices.size + 1 <= this._parameters.K_max) {\n split_indices.add(split.index);\n } else {\n break;\n }\n }\n\n for (let i = 0; i < centroids.length; ++i) {\n if (split_indices.has(i)) {\n // This cluster was split - add both child centroids\n const split_result = accepted_splits.find((s) => s.index === i);\n if (split_result) {\n new_centroids.push(...split_result.child_centroids);\n }\n } else {\n // This cluster wasn't split - keep its centroid\n new_centroids.push(centroids[i]);\n }\n }\n\n // Run KMeans on full dataset with new centroids as initialization\n // This is crucial - we need to reassign all points to all clusters\n const newK = new_centroids.length;\n\n // Create a new KMeans instance with K set to new number of clusters\n current_kmeans = new KMeans(this._matrix, {\n K: newK,\n metric: this._parameters.metric,\n seed: this._randomizer.seed,\n initial_centroids: new_centroids,\n });\n\n // Store the candidate with the BIC of the FULL dataset\n candidates.set(newK, {\n kmeans: current_kmeans,\n score: this._bic(current_kmeans.get_clusters(), current_kmeans.centroids),\n });\n\n K = newK;\n }\n\n // Select best candidate based on BIC score\n this._best_kmeans = this._select_best_candidate(candidates);\n }\n\n /**\n * Select the best candidate based on BIC score\n *\n * @private\n * @param {Map} candidates\n * @returns {KMeans}\n */\n _select_best_candidate(candidates) {\n if (candidates.size === 0) {\n throw new Error(\"No candidates found\");\n }\n\n const first_candidate = candidates.get(this._parameters.K_min);\n if (!first_candidate) {\n throw new Error(\"Missing initial candidate\");\n }\n\n let best_score = first_candidate.score;\n /** @type {KMeans} */\n let best_kmeans = first_candidate.kmeans;\n\n for (const candidate of candidates.values()) {\n if (candidate.score > best_score) {\n best_score = candidate.score;\n best_kmeans = candidate.kmeans;\n }\n }\n\n return best_kmeans;\n }\n\n /**\n * Calculate Bayesian Information Criterion for a set of clusters.\n *\n * Uses Kass's formula for BIC calculation:\n * BIC(θ) = L(D) - 0.5 * p * ln(N)\n *\n * Where:\n * - L(D) is the log-likelihood of the data\n * - p is the number of free parameters: (K-1) + D*K + 1\n * - N is the total number of points\n *\n * @private\n * @param {number[][]} clusters - Array of clusters with point indices\n * @param {Float64Array[]} centroids - Array of centroids\n * @returns {number} BIC score (higher is better)\n */\n _bic(clusters, centroids) {\n const A = this._matrix;\n const D = this._D;\n const K = centroids.length;\n\n let total_variance = 0;\n let N = 0;\n\n // Calculate total variance (sum of squared distances)\n for (let i = 0; i < K; ++i) {\n const cluster = clusters[i];\n const centroid = centroids[i];\n N += cluster.length;\n\n for (let j = 0; j < cluster.length; ++j) {\n const point_idx = cluster[j];\n const point = A.row(point_idx);\n // Sum of squared distances (variance term)\n total_variance += euclidean_squared(centroid, point);\n }\n }\n\n // Not enough points for meaningful BIC\n if (N <= K) {\n return -Infinity;\n }\n\n // Estimate variance (ML estimate)\n const variance = total_variance / (N - K);\n\n // Handle case of zero variance (all points identical)\n if (variance <= 0) {\n return -Infinity;\n }\n\n // Number of free parameters: (K-1) cluster weights + K*D centroid coordinates + 1 variance\n const p = K - 1 + D * K + 1;\n\n // Calculate log-likelihood\n let log_likelihood = 0;\n const log_2pi = Math.log(2 * Math.PI);\n\n for (let i = 0; i < K; ++i) {\n const n = clusters[i].length;\n if (n <= 1) continue;\n\n // Log-likelihood for cluster i\n const cluster_log_likelihood =\n n * Math.log(n / N) - 0.5 * n * log_2pi - 0.5 * n * D * Math.log(variance) - 0.5 * (n - 1);\n\n log_likelihood += cluster_log_likelihood;\n }\n\n // BIC = log_likelihood - 0.5 * p * ln(N)\n return log_likelihood - 0.5 * p * Math.log(N);\n }\n\n /**\n * Get the computed clusters\n *\n * @returns {number[][]} Array of clusters, each containing indices of points\n */\n get_clusters() {\n if (!this._best_kmeans) {\n throw new Error(\"XMeans has not been run\");\n }\n return this._best_kmeans.get_clusters();\n }\n\n /** @returns {number[]} The cluster list */\n get_cluster_list() {\n if (!this._best_kmeans) {\n throw new Error(\"XMeans has not been run\");\n }\n return this._best_kmeans.get_cluster_list();\n }\n\n /**\n * Get the final centroids\n *\n * @returns {Float64Array[]} Array of centroids\n */\n get centroids() {\n if (!this._best_kmeans) {\n throw new Error(\"XMeans has not been run\");\n }\n return this._best_kmeans.centroids;\n }\n\n /**\n * Get the optimal number of clusters found\n *\n * @returns {number} The number of clusters\n */\n get k() {\n if (!this._best_kmeans) {\n throw new Error(\"XMeans has not been run\");\n }\n return this._best_kmeans.k;\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { Randomizer } from \"../util/index.js\";\n\n/** @import {InputType} from \"../index.js\" */\n\n/**\n * @abstract\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n *\n * Base class for all Dimensionality Reduction (DR) algorithms.\n *\n * Provides a common interface for parameters management, data initialization,\n * and transformation (both synchronous and asynchronous).\n *\n * @class\n */\nexport class DR {\n /** @type {number} */\n _D;\n /** @type {number} */\n _N;\n /** @type {Randomizer} */\n _randomizer;\n /** @type {boolean} */\n _is_initialized;\n\n /**\n * Takes the default parameters and seals them, remembers the type of input `X`, and initializes the random number\n * generator.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Para} default_parameters - Object containing default parameterization of the DR method.\n * @param {Partial} parameters - Object containing parameterization of the DR method to override defaults.\n */\n constructor(X, default_parameters, parameters = {}) {\n /** @type {T} */\n this.__input = X;\n\n /** @type {Para} */\n this._parameters = /** @type {Para} */ Object.seal({\n ...default_parameters,\n ...parameters,\n });\n /** @type {\"array\" | \"matrix\" | \"typed\"} */\n this._type;\n /** @type {Matrix} */\n this.X;\n /** @type {Matrix} */\n this.Y;\n\n if (Array.isArray(X)) {\n if (X[0] instanceof Float64Array) {\n this._type = \"typed\";\n } else {\n this._type = \"array\";\n }\n this.X = Matrix.from(X);\n } else if (X instanceof Matrix) {\n this._type = \"matrix\";\n this.X = X;\n } else {\n throw new Error(\"No valid type for X!\");\n }\n const [N, D] = this.X.shape;\n this._N = N;\n this._D = D;\n this._randomizer = new Randomizer(this._parameters.seed);\n this._is_initialized = false;\n }\n\n /**\n * Get all Parameters.\n * @overload\n * @returns {Para}\n */\n /**\n * Get value of given parameter.\n * @template {keyof Para} K\n * @overload\n * @param {K} name - Name of the parameter.\n * @returns {Para[K]}\n */\n /**\n * Set value of given parameter.\n * @template {keyof Para} K\n * @overload\n * @param {K} name - Name of the parameter.\n * @param {Para[K]} value - Value of the parameter to set.\n * @returns {this}\n */\n /**\n * @param {keyof Para} [name] - Name of the parameter. If null, returns all parameters as an Object.\n * @param {Para[keyof Para]} [value] - Value of the parameter to set. If name is set and value is not given, returns the\n * current value.\n * @returns {Para | Para[keyof Para] | this} On setting a parameter, returns the DR object. If name is set and value is not\n * given, returns the parameter value. If name is null, returns all parameters. On setting a parameter, this\n * function returns the DR object. If `name` is set and `value == null` then return actual parameter value. If\n * `name` is not given, then returns all parameters as an Object.\n * @example\n * ```js\n * const DR = new druid.TSNE(X, {d: 3}); // creates a new DR object, with parameter for `d = 3`.\n * DR.parameter(\"d\"); // returns 3\n * DR.parameter(\"d\", 2); // sets parameter `d` to 2 and returns `DR`.\n * ```\n *\n */\n parameter(name, value) {\n if (name === undefined && value === undefined) {\n return Object.assign({}, this._parameters);\n }\n if (name && !Object.hasOwn(this._parameters, name)) {\n throw new Error(`${String(name)} is not a valid parameter!`);\n }\n if (name && value !== undefined) {\n this._parameters[name] = value;\n this._is_initialized = false;\n return this;\n } else if (name) {\n return this._parameters[name];\n }\n throw new Error(\"Should not happen!\");\n }\n\n /**\n * Computes the projection.\n *\n * @abstract\n * @param {...unknown} args\n * @returns {T} The projection.\n */\n transform(...args) {\n args;\n this.check_init();\n return this.projection;\n }\n\n /**\n * Computes the projection.\n *\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.\n * @returns {T} The dimensionality reduced dataset.\n */\n static transform(X, parameters, ...args) {\n args;\n const dr = new DR(X, parameters, parameters);\n return /** @type {T} */ (dr.transform());\n }\n\n /**\n * Computes the projection.\n *\n * @abstract\n * @param {...unknown} args\n * @returns {Generator} The intermediate steps of the projection.\n */\n *generator(...args) {\n const R = this.transform(...args);\n yield R;\n return R;\n }\n\n /**\n * Computes the projection.\n *\n * @template {{ seed?: number }} Para\n * @param {InputType} X\n * @param {Para} parameters\n * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.\n * @returns {Generator} A generator yielding the intermediate steps of the dimensionality\n * reduction method.\n */\n static *generator(X, parameters, ...args) {\n const dr = new DR(X, parameters, parameters);\n const generator = dr.generator(...args);\n let result;\n do {\n result = generator.next();\n yield result.value;\n } while (!result.done);\n\n return result.value;\n }\n\n /**\n * @abstract\n * @param {...unknown} args\n */\n init(...args) {\n args;\n }\n\n /**\n * If the respective DR method has an `init` function, call it before `transform`.\n *\n * @returns {DR}\n */\n check_init() {\n if (!this._is_initialized && typeof this.init === \"function\") {\n this.init();\n this._is_initialized = true;\n }\n return this;\n }\n\n /** @returns {T} The projection in the type of input `X`. */\n get projection() {\n if (Object.hasOwn(this, \"Y\")) {\n this.check_init();\n //return this._type === \"matrix\" ? this.Y : this.Y.to2dArray();\n if (this._type === \"matrix\") {\n return /** @type {T} */ (/** @type {any} */ (this.Y));\n } else if (this._type === \"typed\") {\n return /** @type {T} */ (/** @type {any} */ (this.Y.to2dArray()));\n } else {\n return /** @type {T} */ (/** @type {any} */ (this.Y.asArray()));\n }\n } else {\n throw new Error(\"The dataset is not transformed yet!\");\n }\n }\n\n /**\n * Computes the projection.\n *\n * @param {...unknown} args - Arguments the transform method of the respective DR method takes.\n * @returns {Promise} The dimensionality reduced dataset.\n */\n async transform_async(...args) {\n return this.transform(...args);\n }\n\n /**\n * Computes the projection.\n *\n * @template {{ seed?: number }} Para\n * @param {InputType} X\n * @param {Para} parameters\n * @param {...unknown} args - Takes the same arguments of the constructor of the respective DR method.\n * @returns {Promise} A promise yielding the dimensionality reduced dataset.\n */\n static async transform_async(X, parameters, ...args) {\n return DR.transform(X, parameters, ...args);\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import { InputType } from \"../index.js\" */\n/** @import { ParametersFASTMAP } from \"./index.js\"; */\n\n/**\n * FastMap algorithm for dimensionality reduction.\n *\n * A very fast algorithm for projecting high-dimensional data into a lower-dimensional\n * space while preserving pairwise distances. It works similarly to PCA but uses\n * only a subset of the data to find projection axes.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class FASTMAP extends DR {\n /**\n * FastMap: a fast algorithm for indexing, data-mining and visualization of traditional and multimedia datasets.\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://doi.org/10.1145/223784.223812}\n */\n constructor(X, parameters) {\n super(X, { d: 2, metric: euclidean, seed: 1212 }, parameters);\n }\n\n /**\n * Chooses two points which are the most distant in the actual projection.\n *\n * @private\n * @param {(a: number, b: number) => number} dist\n * @returns {[number, number, number]} An array consisting of first index, second index, and distance between the\n * two points.\n */\n _choose_distant_objects(dist) {\n const X = this.X;\n const N = X.shape[0];\n let a_index = this._randomizer.random_int % N;\n /** @type {number | null} */\n let b_index = null;\n let max_dist = -Infinity;\n for (let i = 0; i < N; ++i) {\n const d_ai = dist(a_index, i);\n if (d_ai > max_dist) {\n max_dist = d_ai;\n b_index = i;\n }\n }\n if (b_index === null) throw new Error(\"should not happen!\");\n max_dist = -Infinity;\n for (let i = 0; i < N; ++i) {\n const d_bi = dist(b_index, i);\n if (d_bi > max_dist) {\n max_dist = d_bi;\n a_index = i;\n }\n }\n return [a_index, b_index, max_dist];\n }\n\n /**\n * Computes the projection.\n *\n * @returns {T} The `d`-dimensional projection of the data matrix `X`.\n */\n transform() {\n const X = this.X;\n const N = X.shape[0];\n const d = /** @type {number} */ (this._parameters.d);\n const metric = /** @type {typeof euclidean} */ (this._parameters.metric);\n const Y = new Matrix(N, d, 0);\n /** @type {(a: number, b: number) => number} */\n let dist = (a, b) => metric(X.row(a), X.row(b));\n\n for (let _col = 0; _col < d; ++_col) {\n const old_dist = dist;\n // choose pivot objects\n const [a_index, b_index, d_ab] = this._choose_distant_objects(dist);\n if (d_ab !== 0) {\n // project the objects on the line (O_a, O_b)\n for (let i = 0; i < N; ++i) {\n const d_ai = dist(a_index, i);\n const d_bi = dist(b_index, i);\n const y_i = (d_ai ** 2 + d_ab ** 2 - d_bi ** 2) / (2 * d_ab);\n Y.set_entry(i, _col, y_i);\n }\n // consider the projections of the objects on a\n // hyperplane perpendicluar to the line (a, b);\n // the distance function D'() between two\n // projections is given by Eq.4\n dist = (a, b) => Math.sqrt(old_dist(a, b) ** 2 - (Y.entry(a, _col) - Y.entry(b, _col)) ** 2);\n }\n }\n // return embedding.\n this.Y = Y;\n return this.projection;\n }\n\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new FASTMAP(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new FASTMAP(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new FASTMAP(X, parameters);\n return dr.transform_async();\n }\n}\n","/**\n * Base class for all K-Nearest Neighbors (KNN) search algorithms.\n *\n * Provides a common interface for elements management and search operations.\n *\n * @abstract\n * @category KNN\n * @template {number[] | Float64Array} T - Type of elements\n * @template {Object} Para - Type of parameters\n * @class\n */\nexport class KNN {\n /** @type {T[]} */\n _elements;\n /** @type {Para} */\n _parameters;\n /** @type {\"typed\" | \"array\"} */\n _type;\n\n /**\n * @param {T[]} elements\n * @param {Para} parameters\n */\n constructor(elements, parameters) {\n if (elements.length === 0) throw new Error(\"Elements needs to contain at least one element!\");\n if (elements[0] instanceof Float64Array) {\n this._type = \"typed\";\n } else {\n this._type = \"array\";\n }\n this._parameters = parameters;\n this._elements = elements;\n }\n\n /**\n * @abstract\n * @param {T} t\n * @param {number} k\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search(t, k) {\n t;\n k;\n throw new Error(\"The function search must be implemented!\");\n }\n\n /**\n * @abstract\n * @param {number} i\n * @param {number} k\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i, k) {\n i;\n k;\n throw new Error(\"The function search_by_index must be implemented!\");\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersAnnoy } from \"./index.js\" */\n\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} AnnoyNode\n * @property {boolean} isLeaf - Whether this is a leaf node\n * @property {number[]} indices - Indices of points in this node (leaf) or children (internal)\n * @property {number[]} normal - Hyperplane normal vector (internal nodes only)\n * @property {number} offset - Hyperplane offset (internal nodes only)\n * @property {AnnoyNode | null} left - Left child (internal nodes only)\n * @property {AnnoyNode | null} right - Right child (internal nodes only)\n */\n\n/**\n * Annoy-style (Approximate Nearest Neighbors Oh Yeah) implementation using Random Projection Trees.\n *\n * This implementation builds multiple random projection trees where each tree randomly selects\n * two points and splits the space based on a hyperplane equidistant between them.\n *\n * Key features:\n * - Multiple random projection trees for better recall\n * - Each tree uses random hyperplanes for splitting\n * - Priority queue search for better recall\n * - Combines results from all trees\n *\n * Best suited for:\n * - High-dimensional data\n * - Approximate nearest neighbor search\n * - Large datasets\n * - When high recall is needed with approximate methods\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link https://github.com/spotify/annoy}\n * @see {@link https://erikbern.com/2015/09/24/nearest-neighbors-and-vector-models-epilogue-curse-of-dimensionality.html}\n */\nexport class Annoy extends KNN {\n /**\n * Creates a new Annoy-style index with random projection trees.\n *\n * @param {T[]} elements - Elements to index\n * @param {ParametersAnnoy} [parameters={}] - Configuration parameters\n */\n constructor(\n elements,\n parameters = {\n metric: euclidean,\n numTrees: 10,\n maxPointsPerLeaf: 10,\n seed: 1212,\n },\n ) {\n // Handle empty initialization - use dummy element\n const hasElements = elements && elements.length > 0;\n const firstElement = /** @type {T} */ (hasElements ? elements[0] : new Float64Array([0]));\n\n super([firstElement], parameters);\n\n this._metric = this._parameters.metric ?? euclidean;\n this._numTrees = this._parameters.numTrees ?? 10;\n this._maxPointsPerLeaf = this._parameters.maxPointsPerLeaf ?? 10;\n this._seed = this._parameters.seed ?? 1212;\n this._randomizer = new Randomizer(this._seed);\n\n /**\n * @private\n * @type {AnnoyNode[]}\n */\n this._trees = [];\n\n // Build trees\n if (hasElements) {\n // Reset elements and rebuild properly\n /** @type {T[]} */\n this._elements = [];\n this._trees = [];\n this.add(elements);\n }\n }\n\n /**\n * Get the number of trees in the index.\n * @returns {number}\n */\n get num_trees() {\n return this._trees.length;\n }\n\n /**\n * Get the total number of nodes in all trees.\n * @returns {number}\n */\n get num_nodes() {\n let total = 0;\n for (const tree of this._trees) {\n total += this._countNodes(tree);\n }\n return total;\n }\n\n /**\n * @private\n * @param {any} node\n * @returns {number}\n */\n _countNodes(node) {\n if (!node) return 0;\n return 1 + this._countNodes(node.left) + this._countNodes(node.right);\n }\n\n /**\n * Add elements to the Annoy index.\n * @param {T[]} elements\n * @returns {this}\n */\n add(elements) {\n // Extend elements array\n this._elements = this._elements.concat(elements);\n\n // Rebuild all trees with new elements\n this._trees = [];\n this._buildTrees();\n\n return this;\n }\n\n /**\n * Build all random projection trees.\n * @private\n */\n _buildTrees() {\n const elements = this._elements;\n const n = elements.length;\n\n for (let t = 0; t < this._numTrees; t++) {\n // Create index array for this tree\n const indices = Array.from({ length: n }, (_, i) => i);\n const tree = this._buildTreeRecursive(indices);\n this._trees.push(tree);\n }\n }\n\n /**\n * Recursively build a random projection tree.\n * @private\n * @param {number[]} indices - Indices of elements to include\n * @returns {AnnoyNode}\n */\n _buildTreeRecursive(indices) {\n const elements = this._elements;\n\n // Base case: small enough to be a leaf\n if (indices.length <= this._maxPointsPerLeaf) {\n return {\n isLeaf: true,\n indices: indices,\n normal: [],\n offset: 0,\n left: null,\n right: null,\n };\n }\n\n // Select two random points to define the splitting hyperplane\n const idx1 = indices[Math.floor(this._randomizer.random * indices.length)];\n const idx2 = indices[Math.floor(this._randomizer.random * indices.length)];\n\n const point1 = elements[idx1];\n const point2 = elements[idx2];\n\n // Compute normal vector (point2 - point1)\n const dim = point1.length;\n /** @type {number[]} */\n const normal = new Array(dim);\n for (let i = 0; i < dim; i++) {\n normal[i] = point2[i] - point1[i];\n }\n\n // Normalize\n let norm = 0;\n for (let i = 0; i < dim; i++) {\n norm += normal[i] * normal[i];\n }\n norm = Math.sqrt(norm);\n\n if (norm > 1e-10) {\n for (let i = 0; i < dim; i++) {\n normal[i] /= norm;\n }\n }\n\n // Compute midpoint and offset\n /** @type {number[]} */\n const midpoint = new Array(dim);\n for (let i = 0; i < dim; i++) {\n midpoint[i] = (point1[i] + point2[i]) / 2;\n }\n\n // Compute offset: dot(normal, midpoint)\n let offset = 0;\n for (let i = 0; i < dim; i++) {\n offset += normal[i] * midpoint[i];\n }\n\n // Split points based on which side of hyperplane they fall\n const leftIndices = [];\n const rightIndices = [];\n\n for (const idx of indices) {\n const point = elements[idx];\n let dot = 0;\n for (let i = 0; i < dim; i++) {\n dot += normal[i] * point[i];\n }\n\n if (dot < offset) {\n leftIndices.push(idx);\n } else {\n rightIndices.push(idx);\n }\n }\n\n // Handle edge case where all points fall on one side\n if (leftIndices.length === 0 || rightIndices.length === 0) {\n return {\n isLeaf: true,\n indices: indices,\n normal: [],\n offset: 0,\n left: null,\n right: null,\n };\n }\n\n // Recursively build subtrees\n const left = this._buildTreeRecursive(leftIndices);\n const right = this._buildTreeRecursive(rightIndices);\n\n return {\n isLeaf: false,\n indices: [],\n normal: normal,\n offset: offset,\n left: left,\n right: right,\n };\n }\n\n /**\n * Compute distance from point to hyperplane.\n * @private\n * @param {T} point\n * @param {number[]} normal\n * @param {number} offset\n * @returns {number} Signed distance (positive = right side, negative = left side)\n */\n _distanceToHyperplane(point, normal, offset) {\n let dot = 0;\n for (let i = 0; i < point.length; i++) {\n dot += normal[i] * point[i];\n }\n return dot - offset;\n }\n\n /**\n * Search for k approximate nearest neighbors.\n * @param {T} query\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search(query, k = 5) {\n const metric = this._metric;\n const elements = this._elements;\n\n if (elements.length === 0) return [];\n\n // Collect candidates from all trees using priority queue\n const candidates = new Set();\n\n // Collect more candidates for better recall\n // Search at least k * numTrees * 2 candidates\n const minCandidates = Math.min(k * this._numTrees * 3, elements.length);\n\n for (const tree of this._trees) {\n this._searchTreePriority(tree, query, candidates, minCandidates);\n }\n\n // Compute exact distances for all candidates\n /** @type {Heap<{ index: number; distance: number }>} */\n const best = new Heap(null, (d) => d.distance, \"max\");\n\n for (const idx of candidates) {\n const element = elements[idx];\n if (!element || element.length !== query.length) continue;\n\n const dist = metric(query, element);\n\n if (best.length < k) {\n best.push({ index: idx, distance: dist });\n } else if (dist < (best.first?.value ?? Infinity)) {\n best.pop();\n best.push({ index: idx, distance: dist });\n }\n }\n\n // If we still don't have enough candidates, do a linear scan fallback\n if (best.length < k) {\n for (let i = 0; i < elements.length && best.length < k; i++) {\n if (candidates.has(i)) continue;\n\n const element = elements[i];\n if (!element || element.length !== query.length) continue;\n\n const dist = metric(query, element);\n best.push({ index: i, distance: dist });\n }\n }\n\n // Convert to result format\n /** @type {{ element: T; index: number; distance: number }[]} */\n const result = [];\n while (best.length > 0) {\n const item = /** @type {{ element: { index: number; distance: number }; value: number }} */ (best.pop());\n result.push({\n element: elements[item.element.index],\n index: item.element.index,\n distance: item.value,\n });\n }\n\n return result.reverse();\n }\n\n /**\n * Search tree using priority queue for better recall.\n * Explores nodes in order of distance to hyperplane.\n * @private\n * @param {AnnoyNode} node\n * @param {T} query\n * @param {Set} candidates\n * @param {number} maxCandidates\n */\n _searchTreePriority(node, query, candidates, maxCandidates) {\n if (!node) return;\n\n // Priority queue entry: { node, distance }\n /** @type {Heap<{ node: AnnoyNode; dist: number }>} */\n const pq = new Heap(null, (d) => d.dist, \"min\");\n pq.push({ node: node, dist: 0 });\n\n while (!pq.empty && candidates.size < maxCandidates) {\n const entry = pq.pop();\n if (!entry) continue;\n\n const currentNode = entry.element.node;\n\n // Leaf node: add all points\n if (currentNode.isLeaf) {\n for (const idx of currentNode.indices) {\n candidates.add(idx);\n if (candidates.size >= maxCandidates) return;\n }\n continue;\n }\n\n // Internal node: compute distance to hyperplane\n const dist = this._distanceToHyperplane(query, currentNode.normal, currentNode.offset);\n\n // Determine which side is closer\n const closerSide = dist < 0 ? currentNode.left : currentNode.right;\n const fartherSide = dist < 0 ? currentNode.right : currentNode.left;\n\n // Add closer side with priority 0 (explore first)\n if (closerSide) {\n pq.push({ node: closerSide, dist: 0 });\n }\n\n // Add farther side with priority = |dist| (explore later if needed)\n if (fartherSide && candidates.size < maxCandidates) {\n pq.push({ node: fartherSide, dist: Math.abs(dist) });\n }\n }\n }\n\n /**\n * @param {number} i\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i, k = 5) {\n if (i < 0 || i >= this._elements.length) return [];\n return this.search(this._elements[i], k);\n }\n\n /**\n * Alias for search_by_index for backward compatibility.\n *\n * @param {number} i - Index of the query element\n * @param {number} [k=5] - Number of nearest neighbors to return\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_index(i, k = 5) {\n return this.search_by_index(i, k);\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersBallTree } from \"./index.js\" */\n\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} ElementWithIndex\n * @property {number} index\n * @property {T} element\n */\n\n/**\n * Ball Tree for efficient nearest neighbor search.\n *\n * A Ball Tree is a metric tree that partitions points into a nested set of\n * hyperspheres (balls). It is particularly effective for high-dimensional\n * data and supports any valid metric.\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n */\nexport class BallTree extends KNN {\n /**\n * Generates a BallTree with given `elements`.\n *\n * @param {T[]} elements - Elements which should be added to the BallTree\n * @param {ParametersBallTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}`\n * @see {@link https://en.wikipedia.org/wiki/Ball_tree}\n * @see {@link https://github.com/invisal/noobjs/blob/master/src/tree/BallTree.js}\n */\n constructor(elements, parameters = { metric: euclidean, seed: 1212 }) {\n super(elements, Object.assign({ seed: 1212 }, parameters));\n /**\n * @private\n * @type {BallTreeNode | BallTreeLeaf}\n */\n this._root = this._construct(elements.map((element, index) => ({ index, element })));\n }\n\n /** @returns {Metric} */\n get _metric() {\n return this._parameters.metric;\n }\n\n /**\n * @private\n * @param {ElementWithIndex[]} elements\n * @returns {BallTreeNode | BallTreeLeaf} Root of balltree.\n */\n _construct(elements) {\n if (elements.length === 1) {\n return new BallTreeLeaf(elements);\n } else {\n const c = this._greatest_spread(elements);\n const sorted_elements = elements.sort((a, b) => a.element[c] - b.element[c]);\n const n = sorted_elements.length;\n const p_index = Math.floor(n / 2);\n const p = sorted_elements[p_index];\n const L = sorted_elements.slice(0, p_index);\n const R = sorted_elements.slice(p_index, n);\n const radius = Math.max(...elements.map((d) => this._metric(p.element, d.element)));\n let B;\n if (L.length > 0 && R.length > 0) {\n B = new BallTreeNode(p, this._construct(L), this._construct(R), radius);\n } else {\n B = new BallTreeLeaf(elements);\n }\n return B;\n }\n }\n\n /**\n * @private\n * @param {ElementWithIndex[]} B\n * @returns {number}\n */\n _greatest_spread(B) {\n const d = B[0].element.length;\n const start = new Array(d);\n\n for (let i = 0; i < d; ++i) {\n start[i] = [Infinity, -Infinity];\n }\n\n let spread = B.reduce((acc, current) => {\n for (let i = 0; i < d; ++i) {\n acc[i][0] = Math.min(acc[i][0], current.element[i]);\n acc[i][1] = Math.max(acc[i][1], current.element[i]);\n }\n return acc;\n }, start);\n spread = spread.map((d) => d[1] - d[0]);\n\n let c = 0;\n for (let i = 0; i < d; ++i) {\n c = spread[i] > spread[c] ? i : c;\n }\n return c;\n }\n\n /**\n * @param {number} i\n * @param {number} k\n */\n search_by_index(i, k = 5) {\n return this.search(this._elements[i], k);\n }\n\n /**\n * @param {T} t - Query element.\n * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors.\n */\n search(t, k = 5) {\n /** @type {Heap>} */\n const heap = new Heap(null, (d) => this._metric(d.element, t), \"max\");\n this._search(t, k, heap, this._root);\n\n // Convert heap to result array\n /** @type {{ element: T; index: number; distance: number }[]} */\n const result = [];\n while (heap.length > 0) {\n const item = /** @type {{ element: ElementWithIndex; value: number }} */ (heap.pop());\n result.push({\n element: item.element.element,\n index: item.element.index,\n distance: item.value,\n });\n }\n return result.reverse(); // Reverse to get closest first\n }\n\n /**\n * @private\n * @param {T} t - Query element.\n * @param {number} k - Number of nearest neighbors to return.\n * @param {Heap>} Q - Heap consists of the currently found `k` nearest neighbors.\n * @param {BallTreeNode | BallTreeLeaf} B\n */\n _search(t, k, Q, B) {\n if (!B) return;\n\n if (B instanceof BallTreeNode) {\n const dist_to_pivot = this._metric(t, B.pivot.element);\n if (Q.length >= k && dist_to_pivot - B.radius >= (Q.first?.value ?? -Infinity)) {\n return;\n }\n\n const c1 = B.child1;\n const c2 = B.child2;\n\n let d1 = Infinity;\n let d2 = Infinity;\n\n if (c1 instanceof BallTreeNode) d1 = this._metric(t, c1.pivot.element);\n else if (c1 instanceof BallTreeLeaf) d1 = this._metric(t, c1.points[0].element);\n\n if (c2 instanceof BallTreeNode) d2 = this._metric(t, c2.pivot.element);\n else if (c2 instanceof BallTreeLeaf) d2 = this._metric(t, c2.points[0].element);\n\n if (d1 < d2) {\n if (c1) this._search(t, k, Q, c1);\n if (c2) this._search(t, k, Q, c2);\n } else {\n if (c2) this._search(t, k, Q, c2);\n if (c1) this._search(t, k, Q, c1);\n }\n } else if (B instanceof BallTreeLeaf) {\n for (let i = 0, n = B.points.length; i < n; ++i) {\n const p = B.points[i];\n const dist = this._metric(p.element, t);\n if (Q.length < k) {\n Q.push(p);\n } else if (dist < (Q.first?.value ?? Infinity)) {\n Q.pop();\n Q.push(p);\n }\n }\n }\n }\n}\n\n/**\n * @private\n * @template {number[] | Float64Array} T\n */\nclass BallTreeNode {\n /**\n * @param {ElementWithIndex} pivot\n * @param {BallTreeNode | BallTreeLeaf | null} child1\n * @param {BallTreeNode | BallTreeLeaf | null} child2\n * @param {number} radius\n */\n constructor(pivot, child1 = null, child2 = null, radius = 0) {\n this.pivot = pivot;\n this.child1 = child1;\n this.child2 = child2;\n this.radius = radius;\n }\n}\n\n/**\n * @private\n * @template {number[] | Float64Array} T\n */\nclass BallTreeLeaf {\n /** @param {ElementWithIndex[]} points */\n constructor(points) {\n this.points = points;\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersHNSW } from \"./index.js\" */\n\n/**\n * @typedef {Object} Layer\n * @property {number} l_c - Layer number\n * @property {number[]} point_indices - Global indices of points in this layer\n * @property {Map} edges - Global index -> array of connected global indices\n */\n\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} Candidate\n * @property {T} element - The actual data point\n * @property {number} index - Global index in the dataset\n * @property {number} distance - Distance from query\n */\n\n/**\n * Hierarchical Navigable Small World (HNSW) graph for approximate nearest neighbor search.\n *\n * HNSW builds a multi-layer graph structure where each layer is a navigable small world graph.\n * The top layers serve as \"highways\" for fast traversal, while lower layers provide accuracy.\n * Each element is assigned to a random level, allowing logarithmic search complexity.\n *\n * Key parameters:\n * - `m`: Controls the number of connections per element (affects accuracy/memory)\n * - `ef_construction`: Controls the quality of the graph during construction (higher = better but slower)\n * - `ef`: Controls the quality of search (higher = better recall but slower)\n *\n * Based on:\n * - \"Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs\"\n * by Malkov & Yashunin (2016)\n * - \"Approximate Nearest Neighbor Search on High Dimensional Data\"\n * by Li et al. (2019)\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const points = [[1, 2], [3, 4], [5, 6], [7, 8]];\n * const hnsw = new druid.HNSW(points, {\n * metric: druid.euclidean,\n * m: 16,\n * ef_construction: 200\n * });\n *\n * const query = [2, 3];\n * const neighbors = hnsw.search(query, 2);\n * // [{ element: [1, 2], index: 0, distance: 1.41 }, ...]\n */\nexport class HNSW extends KNN {\n /**\n * Creates a new HNSW index.\n *\n * @param {T[]} points - Initial points to add to the index\n * @param {ParametersHNSW} [parameters={}] - Configuration parameters\n */\n constructor(\n points,\n parameters = {\n metric: euclidean,\n heuristic: true,\n m: 16,\n ef_construction: 200,\n m0: null,\n mL: null,\n seed: 1212,\n ef: 50,\n },\n ) {\n // Handle empty initialization - use dummy element\n const hasElements = points && points.length > 0;\n let firstElement = /** @type {T} */ (hasElements ? points[0] : new Float64Array([0]));\n\n // Validate all points have consistent dimensions\n if (hasElements) {\n const expected_dim = firstElement.length;\n for (let i = 1; i < points.length; i++) {\n if (!points[i] || points[i].length !== expected_dim) {\n console.warn(\n `HNSW: Point ${i} has inconsistent dimensions (expected ${expected_dim}, got ${points[i]?.length})`,\n );\n // Remove invalid points\n points = points.filter((_, idx) => idx === 0 || points[idx]?.length === expected_dim);\n firstElement = points[0];\n }\n }\n }\n\n super([firstElement], parameters);\n\n // Store reference to elements before clearing\n const elementsToAdd = hasElements ? [...points] : [];\n /** @type {T[]} */\n this._elements = [];\n\n /** @type {Metric} */\n this._metric = this._parameters.metric || euclidean;\n\n /** @type {Function} */\n this._select = this._parameters.heuristic ? this._select_heuristic.bind(this) : this._select_simple.bind(this);\n\n /**\n * @private\n * @type {Map}\n */\n this._graph = new Map();\n\n /** @type {number} */\n this._next_index = 0;\n\n // Validate and set parameters\n const m_param = this._parameters.m ?? 16;\n if (m_param <= 0 || !Number.isInteger(m_param)) {\n throw new Error(\"HNSW: parameter 'm' must be a positive integer\");\n }\n /** @type {number} */\n this._m = Math.max(2, m_param);\n\n const ef_construction_param = this._parameters.ef_construction ?? 200;\n if (ef_construction_param <= 0 || !Number.isInteger(ef_construction_param)) {\n throw new Error(\"HNSW: parameter 'ef_construction' must be a positive integer\");\n }\n /** @type {number} */\n this._ef_construction = ef_construction_param;\n\n const ef_param = this._parameters.ef ?? 50;\n if (ef_param <= 0 || !Number.isInteger(ef_param)) {\n throw new Error(\"HNSW: parameter 'ef' must be a positive integer\");\n }\n /** @type {number} */\n this._ef = ef_param;\n\n const m0_param = this._parameters.m0 ?? 2 * this._m;\n if (m0_param <= 0 || !Number.isInteger(m0_param)) {\n throw new Error(\"HNSW: parameter 'm0' must be a positive integer\");\n }\n /** @type {number} */\n this._m0 = m0_param;\n\n /** @type {number} */\n this._mL = this._parameters.mL ?? 1 / Math.log(this._m);\n\n /** @type {Randomizer} */\n this._randomizer = new Randomizer(this._parameters.seed);\n\n /** @type {number} - Current maximum layer in the graph */\n this._L = -1;\n\n /** @type {number[] | null} - Entry point indices for search */\n this._ep = null;\n\n // Add initial points\n if (elementsToAdd && elementsToAdd.length > 0) {\n this.add(elementsToAdd);\n }\n }\n\n /**\n * Add a single element to the index.\n *\n * @param {T} element - Element to add\n * @returns {HNSW} This instance for chaining\n */\n addOne(element) {\n return this.add([element]);\n }\n\n /**\n * Add multiple elements to the index.\n *\n * @param {T[]} new_elements - Elements to add\n * @returns {HNSW} This instance for chaining\n */\n add(new_elements) {\n // Handle empty array\n if (!new_elements || new_elements.length === 0) {\n return this;\n }\n\n const m = this._m;\n const ef_construction = this._ef_construction;\n const m0 = this._m0;\n const mL = this._mL;\n const randomizer = this._randomizer;\n const graph = this._graph;\n\n // Ensure _elements is a proper array that supports push\n if (!Array.isArray(this._elements)) {\n this._elements = Array.from(this._elements);\n }\n const elements = this._elements;\n\n // Get expected dimension from first existing element or first new element\n const expected_dim = elements.length > 0 ? elements[0].length : new_elements[0]?.length;\n\n for (const element of new_elements) {\n // Validate element\n if (!element || (!Array.isArray(element) && !(element instanceof Float64Array))) {\n console.warn(\"HNSW: Skipping invalid element (null, undefined, or not an array)\");\n continue;\n }\n\n // Validate dimensions\n if (element.length !== expected_dim) {\n console.warn(\n `HNSW: Skipping element with wrong dimensions (expected ${expected_dim}, got ${element.length})`,\n );\n continue;\n }\n\n elements.push(element);\n const global_index = elements.length - 1;\n\n // Assign random level to the element\n // Level is drawn from exponential distribution: l = floor(-ln(uniform(0,1)) * mL)\n const rand = Math.max(randomizer.random, 1e-10); // Avoid log(0)\n const l = Math.min(31, Math.floor(-Math.log(rand) * mL));\n\n let ep_indices = this._ep ? [...this._ep] : null;\n const L = this._L;\n\n if (L >= 0) {\n // Search from top layer down to min(L, l) + 1\n // These are the layers where element will NOT be inserted\n for (let l_c = L; l_c > l; --l_c) {\n const search_result = this._search_layer(element, ep_indices, 1, l_c);\n if (search_result.length > 0) {\n ep_indices = [search_result[0].index];\n }\n }\n\n // Insert element into layers l down to 0\n for (let l_c = Math.min(L, l); l_c >= 0; --l_c) {\n const layer = graph.get(l_c);\n if (!layer) continue;\n\n layer.point_indices.push(global_index);\n\n // Search for ef_construction nearest neighbors\n let W = this._search_layer(element, ep_indices, ef_construction, l_c);\n\n // If graph search returns no results (e.g., graph is empty or disconnected),\n // fall back to linear search over all existing elements\n if (W.length === 0 && elements.length > 1) {\n const fallbackCandidates = [];\n for (let i = 0; i < elements.length - 1; i++) {\n const elem = elements[i];\n if (elem && elem.length === element.length) {\n fallbackCandidates.push({\n element: elem,\n index: i,\n distance: this._metric(element, elem),\n });\n }\n }\n fallbackCandidates.sort((a, b) => a.distance - b.distance);\n W = fallbackCandidates.slice(0, ef_construction);\n // Update ep_indices for next layer based on fallback results\n if (l_c === Math.min(L, l)) {\n ep_indices = W.map((c) => c.index);\n }\n }\n\n // Select neighbors using heuristic or simple approach (respect heuristic setting on all layers)\n const neighbor_indices = this._select(element, W, l_c === 0 ? m0 : m, l_c);\n\n // Add bidirectional connections\n for (const neighbor_idx of neighbor_indices) {\n if (neighbor_idx === global_index) continue;\n\n // Add connection from element to neighbor\n if (!layer.edges.has(global_index)) {\n layer.edges.set(global_index, []);\n }\n layer.edges.get(global_index)?.push(neighbor_idx);\n\n // Add connection from neighbor to element\n if (!layer.edges.has(neighbor_idx)) {\n layer.edges.set(neighbor_idx, []);\n }\n const neighbor_edge_list = layer.edges.get(neighbor_idx);\n if (neighbor_edge_list && !neighbor_edge_list.includes(global_index)) {\n neighbor_edge_list.push(global_index);\n }\n\n // Prune connections if too many\n const max_conn = l_c === 0 ? m0 : m;\n const neighbor_edges = layer.edges.get(neighbor_idx);\n if (neighbor_edges && neighbor_edges.length > max_conn) {\n const neighbor_element = elements[neighbor_idx];\n // Filter out self-connections before pruning\n const valid_neighbor_edges = neighbor_edges.filter((idx) => idx !== neighbor_idx);\n const neighbor_candidates = valid_neighbor_edges.map((idx) => ({\n element: elements[idx],\n index: idx,\n distance: this._metric(neighbor_element, elements[idx]),\n }));\n const pruned =\n l_c === 0\n ? this._select_simple(neighbor_element, neighbor_candidates, max_conn)\n : this._select(neighbor_element, neighbor_candidates, max_conn, l_c);\n layer.edges.set(neighbor_idx, pruned);\n }\n }\n\n // Use closest neighbor as entry point for next layer (following HNSW paper)\n if (W.length > 0) {\n ep_indices = [W[0].index];\n }\n }\n }\n\n // If element's level is higher than current max, create new layers\n if (l > L) {\n for (let i = L + 1; i <= l; ++i) {\n graph.set(i, {\n l_c: i,\n point_indices: [global_index],\n edges: new Map(),\n });\n }\n // Element becomes the new entry point\n this._ep = [global_index];\n this._L = l;\n }\n\n // Special case: if this is the first element (L was -1),\n // we need to ensure layer 0 has proper structure for future insertions\n if (L === -1) {\n if (!graph.has(0)) {\n graph.set(0, {\n l_c: 0,\n point_indices: [global_index],\n edges: new Map(),\n });\n }\n const layer0 = graph.get(0);\n if (layer0 && !layer0.edges.has(global_index)) {\n layer0.edges.set(global_index, []);\n }\n }\n }\n\n return this;\n }\n\n /**\n * Select neighbors using the heuristic approach.\n *\n * The heuristic extends candidates with their neighbors and selects\n * points that are closer to the query than to already selected points.\n * This maintains graph connectivity better than simple selection.\n *\n * @private\n * @param {T} q - Query element\n * @param {Candidate[]} candidates - Candidate elements with distances\n * @param {number} M - Maximum number of neighbors to return\n * @param {number} l_c - Layer number\n * @param {boolean} [extend_candidates=true] - Whether to extend candidates with their neighbors\n * @param {boolean} [keep_pruned_connections=true] - Whether to add pruned connections back if needed\n * @returns {number[]} Selected neighbor indices\n */\n _select_heuristic(q, candidates, M, l_c, extend_candidates = true, keep_pruned_connections = true) {\n if (l_c > this._L) {\n return candidates.map((c) => c.index);\n }\n\n const metric = this._metric;\n const layer = this._graph.get(l_c);\n const elements = this._elements;\n\n // Extend candidate set with neighbors of candidates\n const W_set = new Set(candidates.map((c) => c.index));\n if (extend_candidates) {\n for (const c of candidates) {\n const edges = layer?.edges.get(c.index);\n if (edges) {\n for (const neighbor_idx of edges) {\n W_set.add(neighbor_idx);\n }\n }\n }\n }\n\n // Create extended candidates with distances\n const W = [...W_set]\n .map((idx) => ({\n element: elements[idx],\n index: idx,\n distance: metric(elements[idx], q),\n }))\n .sort((a, b) => a.distance - b.distance);\n\n const R = [];\n const W_discarded = [];\n\n // Select neighbors: prefer points closer to query than to already selected points\n for (const e of W) {\n if (R.length >= M) break;\n\n let should_add = true;\n\n // Check if e is closer to query than to any already selected point\n for (const r of R) {\n const dist_er = metric(e.element, r.element);\n if (dist_er < e.distance) {\n should_add = false;\n break;\n }\n }\n\n if (should_add) {\n R.push(e);\n } else {\n W_discarded.push(e);\n }\n }\n\n // Add discarded connections if we need more\n if (keep_pruned_connections && R.length < M) {\n for (const e of W_discarded) {\n if (R.length >= M) break;\n R.push(e);\n }\n }\n\n return R.map((c) => c.index);\n }\n\n /**\n * Select neighbors using simple distance-based selection.\n *\n * Simply returns the M closest candidates to the query.\n *\n * @private\n * @param {T} q - Query element\n * @param {Candidate[]} C - Candidate elements with distances\n * @param {number} M - Maximum number of neighbors to return\n * @returns {number[]} M nearest candidate indices\n */\n _select_simple(q, C, M) {\n if (C.length <= M) return C.map((c) => c.index);\n\n // Candidates already have distance computed, use it directly\n return C.slice()\n .sort((a, b) => a.distance - b.distance)\n .slice(0, M)\n .map((c) => c.index);\n }\n\n /**\n * Search a single layer for nearest neighbors.\n *\n * Implements the greedy search algorithm: start from entry points,\n * always expand the closest unvisited candidate, maintain a list\n * of the ef closest found neighbors.\n *\n * @private\n * @param {T} q - Query element\n * @param {number[] | null} ep_indices - Entry point indices\n * @param {number} ef - Number of nearest neighbors to find\n * @param {number} l_c - Layer number to search\n * @returns {Candidate[]} ef nearest neighbors found with their distances\n */\n _search_layer(q, ep_indices, ef, l_c) {\n const metric = this._metric;\n const layer = this._graph.get(l_c);\n const elements = this._elements;\n\n if (!layer || layer.edges.size === 0 || !ep_indices || ep_indices.length === 0) {\n return [];\n }\n\n // Filter out invalid indices\n const valid_ep_indices = ep_indices.filter((idx) => elements[idx] !== undefined);\n if (valid_ep_indices.length === 0) {\n return [];\n }\n\n // Visited set to avoid cycles\n const visited = new Set(valid_ep_indices);\n\n // Candidate set (min-heap): closest unvisited candidates to expand\n const C = new Heap(\n valid_ep_indices.map((idx) => ({\n element: elements[idx],\n index: idx,\n distance: metric(elements[idx], q),\n })),\n (item) => item.distance,\n \"min\",\n );\n\n // Result set (max-heap): ef closest found neighbors\n const W = new Heap(\n valid_ep_indices.map((idx) => ({\n element: elements[idx],\n index: idx,\n distance: metric(elements[idx], q),\n })),\n (item) => item.distance,\n \"max\",\n );\n\n // Algorithm 2 stops when the distance from query to the next candidate is greater\n // than the distance to the furthest element in the result set W.\n while (!C.empty) {\n const c = C.pop();\n if (!c) break;\n const furthest_dist = W.first?.value ?? Infinity;\n\n // Stop if current candidate is farther than furthest result\n if (c.value > furthest_dist) {\n break;\n }\n\n const edges = layer.edges.get(c.element.index);\n if (!edges) continue;\n\n for (const neighbor_idx of edges) {\n if (!visited.has(neighbor_idx)) {\n const neighbor_element = elements[neighbor_idx];\n // Skip invalid elements or elements with different dimensions\n if (!neighbor_element || neighbor_element.length !== q.length) continue;\n\n // Skip self-connections\n if (neighbor_idx === c.element.index) continue;\n\n visited.add(neighbor_idx);\n const dist_e = metric(neighbor_element, q);\n\n const current_furthest = W.first?.value ?? Infinity;\n if (dist_e < current_furthest || W.length < ef) {\n C.push({\n element: neighbor_element,\n index: neighbor_idx,\n distance: dist_e,\n });\n W.push({\n element: neighbor_element,\n index: neighbor_idx,\n distance: dist_e,\n });\n\n if (W.length > ef) {\n W.pop();\n }\n }\n }\n }\n }\n\n // Return sorted results for consistent entry point selection\n return W.data().sort((a, b) => a.distance - b.distance);\n }\n\n /**\n * Searches for the K nearest neighbors to a query element in the HNSW graph.\n *\n * Performs a multi-layer search starting from the entry point and traversing\n * each layer as entry points for the next.\n *\n * @param {T} q - Query element\n * @param {number} K - Number of nearest neighbors to return\n * @returns {Candidate[]} K nearest neighbors with their distances\n */\n search(q, K) {\n // Validate K\n if (!Number.isInteger(K) || K <= 0) {\n throw new Error(\"HNSW: parameter 'K' must be a positive integer\");\n }\n\n // Validate query dimensions\n if (!q || (!Array.isArray(q) && !(q instanceof Float64Array))) {\n throw new Error(\"HNSW: query must be an array\");\n }\n\n const search_ef = this._ef;\n\n // Fallback to linear search if graph is not properly initialized\n if (this._L < 0 || !this._ep || this._elements.length === 0) {\n return this._linear_search(q, K);\n }\n\n let ep_indices = [...this._ep];\n\n // Search from top layer down to layer 1\n for (let l_c = this._L; l_c > 0; --l_c) {\n const result = this._search_layer(q, ep_indices, 1, l_c);\n if (result.length > 0) {\n ep_indices = [result[0].index];\n }\n }\n\n // Search layer 0 with ef candidates\n const result = this._search_layer(q, ep_indices, Math.max(search_ef, K), 0);\n\n // If graph search returns no results, fallback to linear search\n if (result.length === 0) {\n return this._linear_search(q, K);\n }\n\n // Return K closest\n return result.slice(0, K);\n }\n\n /**\n * Fallback linear search when graph search fails\n * @private\n * @param {T} q - Query element\n * @param {number} K - Number of nearest neighbors to return\n * @returns {Candidate[]}\n */\n _linear_search(q, K) {\n const metric = this._metric;\n const elements = this._elements;\n const N = elements.length;\n\n if (N === 0) return [];\n\n /** @type {Candidate[]} */\n const candidates = [];\n for (let i = 0; i < N; i++) {\n const element = elements[i];\n // Skip elements with different dimensions (can happen with inconsistent data)\n if (!element || element.length !== q.length) continue;\n\n candidates.push({\n element: element,\n index: i,\n distance: metric(q, element),\n });\n }\n\n candidates.sort((a, b) => a.distance - b.distance);\n return candidates.slice(0, K);\n }\n\n /**\n * Iterator for searching the HNSW graph layer by layer.\n *\n * Yields intermediate results at each layer for debugging or visualization.\n *\n * @param {T} q - Query element\n * @param {number} K - Number of nearest neighbors to return\n * @param {number?} [ef] - Size of dynamic candidate list\n * @yields {{layer: number, candidates: Candidate[]}}\n */\n *search_iter(q, K, ef = null) {\n const search_ef = ef ?? this._ef;\n\n if (this._L < 0 || !this._ep) {\n return;\n }\n\n let ep_indices = [...this._ep];\n\n // Yield entry points at top layer instead of query itself\n const top_layer = this._graph.get(this._L);\n if (top_layer && this._ep && this._ep.length > 0) {\n const entry_candidates = this._ep\n .filter((idx) => this._elements[idx] !== undefined)\n .map((idx) => ({\n element: this._elements[idx],\n index: idx,\n distance: this._metric(this._elements[idx], q),\n }));\n yield {\n layer: this._L,\n candidates: entry_candidates,\n };\n }\n\n for (let l_c = this._L; l_c > 0; --l_c) {\n const result = this._search_layer(q, ep_indices, 1, l_c);\n yield { layer: l_c, candidates: result };\n // Use closest candidate as entry point for next layer (following HNSW paper)\n ep_indices = result.length > 0 ? [result[0].index] : ep_indices;\n }\n\n const result = this._search_layer(q, ep_indices, Math.max(search_ef, K), 0);\n yield { layer: 0, candidates: result };\n }\n\n /**\n * Get the number of elements in the index.\n *\n * @returns {number} Number of elements\n */\n get size() {\n return this._elements?.length ?? 0;\n }\n\n /**\n * Get the number of layers in the graph.\n *\n * @returns {number} Number of layers\n */\n get num_layers() {\n return this._L + 1;\n }\n\n /**\n * Get an element by its index.\n *\n * @param {number} index - Element index\n * @returns {T} The element at the given index\n */\n get_element(index) {\n return this._elements[index];\n }\n\n /**\n * Search for nearest neighbors using an element index as the query.\n *\n * @param {number} i - Index of the query element\n * @param {number} [K=5] - Number of nearest neighbors to return\n * @returns {Candidate[]} K nearest neighbors\n */\n search_by_index(i, K = 5) {\n const elements = this._elements;\n if (i < 0 || i >= elements.length) return [];\n\n const element = elements[i];\n if (!element) return [];\n\n return this.search(element, K);\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersKDTree } from \"./index.js\" */\n\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} ElementWithIndex\n * @property {number} index\n * @property {T} element\n */\n\n/**\n * KD-Tree (K-dimensional Tree) for efficient nearest neighbor search.\n *\n * KD-Trees partition k-dimensional space by recursively splitting along coordinate axes.\n * At each level, the tree splits points based on the median of the coordinate with the largest spread.\n * This creates a balanced binary tree structure that enables efficient O(log n) search on average.\n *\n * Best suited for:\n * - Low to moderate dimensional data (d < 20-30)\n * - When exact nearest neighbors are needed\n * - When dimensionality is not too high\n *\n * Performance degrades in high dimensions (curse of dimensionality) where approximate\n * methods like HNSW or LSH become more effective.\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link https://en.wikipedia.org/wiki/K-d_tree}\n */\nexport class KDTree extends KNN {\n /**\n * Generates a KD-Tree with given `elements`.\n *\n * @param {T[]} elements - Elements which should be added to the KD-Tree\n * @param {ParametersKDTree} [parameters={metric: euclidean}] Default is `{metric: euclidean}`\n */\n constructor(elements, parameters = { metric: euclidean, seed: 1212 }) {\n super(elements, Object.assign({ seed: 1212 }, parameters));\n /**\n * @private\n * @type {KDTreeNode | KDTreeLeaf | null}\n */\n this._root = this._construct(\n elements.map((element, index) => ({ index, element })),\n 0,\n );\n }\n\n /** @returns {Metric} */\n get _metric() {\n return this._parameters.metric;\n }\n\n /**\n * @private\n * @param {ElementWithIndex[]} elements\n * @param {number} depth - Current depth in the tree (determines splitting axis)\n * @returns {KDTreeNode | KDTreeLeaf | null} Root of KD-Tree.\n */\n _construct(elements, depth) {\n if (elements.length === 0) {\n return null;\n }\n\n if (elements.length === 1) {\n return new KDTreeLeaf(elements[0]);\n }\n\n const k = elements[0].element.length;\n const axis = depth % k;\n\n // Sort by the splitting axis and find median\n elements.sort((a, b) => a.element[axis] - b.element[axis]);\n const medianIndex = Math.floor(elements.length / 2);\n const medianPoint = elements[medianIndex];\n\n // Recursively build left and right subtrees\n const leftElements = elements.slice(0, medianIndex);\n const rightElements = elements.slice(medianIndex + 1);\n\n const left = this._construct(leftElements, depth + 1);\n const right = this._construct(rightElements, depth + 1);\n\n return new KDTreeNode(medianPoint, axis, left, right);\n }\n\n /**\n * @param {number} i\n * @param {number} k\n */\n search_by_index(i, k = 5) {\n return this.search(this._elements[i], k);\n }\n\n /**\n * @param {T} t - Query element.\n * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors.\n */\n search(t, k = 5) {\n /** @type {Heap<{ point: ElementWithIndex; distance: number }>} */\n const best = new Heap(null, (d) => d.distance, \"max\");\n\n this._search_recursive(t, k, this._root, best);\n\n // Convert heap to result array (closest first)\n /** @type {{ element: T; index: number; distance: number }[]} */\n const result = [];\n while (best.length > 0) {\n const item = /** @type {{ element: { point: ElementWithIndex; distance: number }; value: number }} */ (\n best.pop()\n );\n result.push({\n element: item.element.point.element,\n index: item.element.point.index,\n distance: item.value,\n });\n }\n return result.reverse();\n }\n\n /**\n * @private\n * @param {T} target - Query element.\n * @param {number} k - Number of nearest neighbors to return.\n * @param {KDTreeNode | KDTreeLeaf | null} node - Current node.\n * @param {Heap<{ point: ElementWithIndex; distance: number }>} best - Heap of k best found so far.\n */\n _search_recursive(target, k, node, best) {\n if (node === null) return;\n\n if (node instanceof KDTreeLeaf) {\n const dist = this._metric(target, node.point.element);\n if (best.length < k) {\n best.push({ point: node.point, distance: dist });\n } else if (dist < (best.first?.value ?? Infinity)) {\n best.pop();\n best.push({ point: node.point, distance: dist });\n }\n return;\n }\n\n // Node is an internal node\n const axis = node.axis;\n const point = node.point;\n const pointValue = point.element[axis];\n const targetValue = target[axis];\n\n // Determine which subtree to search first\n const firstSubtree = targetValue < pointValue ? node.left : node.right;\n const secondSubtree = targetValue < pointValue ? node.right : node.left;\n\n // Search the nearer subtree\n this._search_recursive(target, k, firstSubtree, best);\n\n // Check if we need to search the other subtree\n // The hyperplane could contain closer points\n const distToHyperplane = Math.abs(targetValue - pointValue);\n const currentMaxDist = best.first?.value ?? Infinity;\n\n // Calculate distance to current point\n const distToPoint = this._metric(target, point.element);\n if (best.length < k) {\n best.push({ point: point, distance: distToPoint });\n } else if (distToPoint < currentMaxDist) {\n best.pop();\n best.push({ point: point, distance: distToPoint });\n }\n\n // Check if we need to explore the other side of the hyperplane\n if (best.length < k || distToHyperplane < (best.first?.value ?? Infinity)) {\n this._search_recursive(target, k, secondSubtree, best);\n }\n }\n}\n\n/**\n * @private\n * @template {number[] | Float64Array} T\n */\nclass KDTreeNode {\n /**\n * @param {ElementWithIndex} point\n * @param {number} axis - The splitting axis\n * @param {KDTreeNode | KDTreeLeaf | null} left\n * @param {KDTreeNode | KDTreeLeaf | null} right\n */\n constructor(point, axis, left = null, right = null) {\n this.point = point;\n this.axis = axis;\n this.left = left;\n this.right = right;\n }\n}\n\n/**\n * @private\n * @template {number[] | Float64Array} T\n */\nclass KDTreeLeaf {\n /**\n * @param {ElementWithIndex} point\n */\n constructor(point) {\n this.point = point;\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import { Metric } from \"../metrics/index.js\" */\n/** @import { ParametersLSH } from \"./index.js\" */\n\n/**\n * Locality Sensitive Hashing (LSH) for approximate nearest neighbor search.\n *\n * LSH uses hash functions that map similar items to the same buckets with high probability.\n * This implementation uses Random Projection hashing (SimHash-style) which works well for\n * cosine similarity and Euclidean distance.\n *\n * Key concepts:\n * - Multiple hash tables increase recall probability\n * - Each hash function projects data onto random hyperplanes\n * - Points on the same side of hyperplanes are hashed together\n * - Combines results from all tables for better accuracy\n *\n * Best suited for:\n * - High-dimensional data where exact methods fail\n * - Approximate nearest neighbor needs\n * - Large datasets where linear scan is too slow\n * - When some false positives/negatives are acceptable\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link https://en.wikipedia.org/wiki/Locality-sensitive_hashing}\n */\nexport class LSH extends KNN {\n /**\n * Creates a new LSH index.\n *\n * @param {T[]} elements - Elements to index\n * @param {ParametersLSH} [parameters={}] - Configuration parameters\n */\n constructor(\n elements,\n parameters = {\n metric: euclidean,\n numHashTables: 10,\n numHashFunctions: 10,\n seed: 1212,\n },\n ) {\n // Handle empty initialization - use dummy element\n const hasElements = elements && elements.length > 0;\n const firstElement = /** @type {T} */ (hasElements ? elements[0] : new Float64Array([0]));\n\n super([firstElement], parameters);\n\n this._metric = this._parameters.metric ?? euclidean;\n this._numHashTables = this._parameters.numHashTables ?? 10;\n this._numHashFunctions = this._parameters.numHashFunctions ?? 10;\n this._seed = this._parameters.seed ?? 1212;\n this._randomizer = new Randomizer(this._seed);\n\n // Hash tables: array of Maps where key is hash bucket, value is array of element indices\n /** @type {Map[]} */\n this._hashTables = [];\n\n // Random projection vectors for each hash table and hash function\n /** @type {Float64Array[][]} */\n this._projections = [];\n\n // Random offsets for each hash table and hash function (for quantization)\n /** @type {number[][]} */\n this._offsets = [];\n\n // Store dimensionality for later\n /** @type {number} */\n this._dim = firstElement.length;\n\n // Initialize hash functions\n this._initializeHashFunctions();\n\n // Reset elements if we were initialized with dummy\n if (!hasElements) {\n /** @type {T[]} */\n this._elements = [];\n } else {\n // Clear and re-add elements properly\n /** @type {T[]} */\n this._elements = [];\n this._hashTables = [];\n this._projections = [];\n this._offsets = [];\n this._initializeHashFunctions();\n this.add(elements);\n }\n }\n\n /**\n * Initialize random projection vectors for all hash tables.\n * @private\n */\n _initializeHashFunctions() {\n const dim = this._elements[0]?.length ?? 0;\n\n for (let t = 0; t < this._numHashTables; t++) {\n const tableProjections = [];\n const tableOffsets = [];\n\n for (let h = 0; h < this._numHashFunctions; h++) {\n // Generate random projection vector (normalized)\n const projection = new Float64Array(dim);\n let norm = 0;\n for (let i = 0; i < dim; i++) {\n // Box-Muller transform for normal distribution\n const u1 = this._randomizer.random;\n const u2 = this._randomizer.random;\n const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);\n projection[i] = z;\n norm += z * z;\n }\n // Normalize\n norm = Math.sqrt(norm);\n for (let i = 0; i < dim; i++) {\n projection[i] /= norm;\n }\n\n tableProjections.push(projection);\n // Random offset for quantization buckets\n tableOffsets.push(this._randomizer.random);\n }\n\n this._projections.push(tableProjections);\n this._offsets.push(tableOffsets);\n this._hashTables.push(new Map());\n }\n }\n\n /**\n * Compute hash signature for an element using random projections.\n * @private\n * @param {T} element\n * @param {number} tableIndex\n * @returns {string} Hash signature\n */\n _computeHash(element, tableIndex) {\n const projections = this._projections[tableIndex];\n const offsets = this._offsets[tableIndex];\n const bits = [];\n\n for (let i = 0; i < this._numHashFunctions; i++) {\n // Compute dot product\n let dot = 0;\n const proj = projections[i];\n for (let j = 0; j < element.length; j++) {\n dot += element[j] * proj[j];\n }\n // Quantize with offset\n const bucket = Math.floor(dot + offsets[i]);\n bits.push(bucket);\n }\n\n return bits.join(\",\");\n }\n\n /**\n * Add elements to the LSH index.\n * @param {T[]} elements\n * @returns {this}\n */\n add(elements) {\n // Extend elements array\n const startIndex = this._elements.length;\n this._elements = this._elements.concat(elements);\n\n // Hash each new element and add to tables\n for (let i = 0; i < elements.length; i++) {\n const globalIndex = startIndex + i;\n const element = elements[i];\n\n for (let t = 0; t < this._numHashTables; t++) {\n const hash = this._computeHash(element, t);\n const table = this._hashTables[t];\n\n if (!table.has(hash)) {\n table.set(hash, []);\n }\n const bucket = table.get(hash);\n if (bucket) {\n bucket.push(globalIndex);\n }\n }\n }\n\n return this;\n }\n\n /**\n * Search for k approximate nearest neighbors.\n * @param {T} query\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search(query, k = 5) {\n const metric = this._metric;\n const elements = this._elements;\n\n if (elements.length === 0) return [];\n\n // Collect candidate indices from all hash tables\n const candidates = new Set();\n\n for (let t = 0; t < this._numHashTables; t++) {\n const hash = this._computeHash(query, t);\n const table = this._hashTables[t];\n const bucket = table.get(hash);\n\n if (bucket) {\n for (const idx of bucket) {\n if (idx !== undefined) {\n candidates.add(idx);\n }\n }\n }\n }\n\n // If insufficient candidates found, fall back to linear search\n if (candidates.size < k) {\n // Add more candidates from all buckets or entire dataset\n //const needed = k - candidates.size;\n\n // First, try to add from neighboring buckets (different hashes)\n for (let t = 0; t < this._numHashTables && candidates.size < k; t++) {\n const table = this._hashTables[t];\n for (const [, bucket] of table) {\n for (const idx of bucket) {\n if (idx !== undefined) {\n candidates.add(idx);\n if (candidates.size >= k) break;\n }\n }\n if (candidates.size >= k) break;\n }\n }\n\n // If still not enough, add from entire dataset\n for (let i = 0; i < elements.length && candidates.size < k; i++) {\n candidates.add(i);\n }\n }\n\n // Compute exact distances for candidates\n /** @type {Heap<{ index: number; distance: number }>} */\n const best = new Heap(null, (d) => d.distance, \"max\");\n\n for (const idx of candidates) {\n const element = elements[idx];\n if (!element || element.length !== query.length) continue;\n\n const dist = metric(query, element);\n\n if (best.length < k) {\n best.push({ index: idx, distance: dist });\n } else if (dist < (best.first?.value ?? Infinity)) {\n best.pop();\n best.push({ index: idx, distance: dist });\n }\n }\n\n // Convert to result format\n /** @type {{ element: T; index: number; distance: number }[]} */\n const result = [];\n while (best.length > 0) {\n const item = /** @type {{ element: { index: number; distance: number }; value: number }} */ (best.pop());\n result.push({\n element: elements[item.element.index],\n index: item.element.index,\n distance: item.value,\n });\n }\n\n return result.reverse();\n }\n\n /**\n * @param {number} i\n * @param {number} [k=5]\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i, k = 5) {\n if (i < 0 || i >= this._elements.length) return [];\n return this.search(this._elements[i], k);\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { distance_matrix, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import { ParametersNaiveKNN } from \"./index.js\" */\n\n/**\n * Naive KNN implementation using a distance matrix.\n *\n * This implementation pre-computes the entire distance matrix and performs\n * an exhaustive search. Best suited for small datasets or when a distance\n * matrix is already available.\n *\n * @template {number[] | Float64Array} T\n * @category KNN\n * @class\n * @extends KNN\n */\nexport class NaiveKNN extends KNN {\n /**\n * Generates a KNN list with given `elements`.\n *\n * @param {T[]} elements - Elements which should be added to the KNN list\n * @param {ParametersNaiveKNN} parameters\n */\n constructor(elements, parameters = {}) {\n const params = Object.assign({ metric: euclidean, seed: 1212 }, parameters);\n super(elements, params);\n const N =\n this._elements instanceof Matrix ? /** @type {any} */ (this._elements).shape[0] : this._elements.length;\n if (this._parameters.metric === \"precomputed\") {\n this._D = Matrix.from(/** @type {number[][] | Float64Array[]} */ (/** @type {any} */ (this._elements)));\n } else {\n this._D = distance_matrix(\n /** @type {number[][] | Float64Array[]} */ (this._elements),\n this._parameters.metric,\n );\n }\n\n /** @type {Heap<{ value: number; index: number }>[]} */\n this.KNN = [];\n for (let row = 0; row < N; ++row) {\n const distances = this._D.row(row);\n /** @type {Heap<{ value: number; index: number }>} */\n const H = new Heap(null, (d) => d.value, \"min\");\n for (let j = 0; j < N; ++j) {\n H.push({\n value: distances[j],\n index: j,\n });\n }\n this.KNN.push(H);\n }\n }\n\n /**\n * @param {number} i\n * @param {number} k\n */\n search_by_index(i, k = 5) {\n if (this._parameters.metric === \"precomputed\") {\n const H = this.KNN[i];\n /** @type {{ element: T; index: number; distance: number }[]} */\n const result = [];\n const data = H.toArray(); // Get array representation\n const temp_heap = new Heap(data, (d) => d.value, \"min\");\n const N =\n this._elements instanceof Matrix ? /** @type {any} */ (this._elements).shape[0] : this._elements.length;\n for (let j = 0; j < Math.min(k, N); ++j) {\n const node = temp_heap.pop();\n if (!node) break;\n result.push({\n element: /** @type {T} */ (\n this._elements instanceof Matrix\n ? /** @type {any} */ (this._elements).row(node.element.index)\n : this._elements[node.element.index]\n ),\n index: /** @type {number} */ (node.element.index),\n distance: /** @type {number} */ (node.value),\n });\n }\n return result;\n }\n return this.search(\n /** @type {T} */ (\n this._elements instanceof Matrix ? /** @type {any} */ (this._elements).row(i) : this._elements[i]\n ),\n k,\n );\n }\n\n /**\n * @param {T} t - Query element.\n * @param {number} [k=5] - Number of nearest neighbors to return. Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]} - List consists of the `k` nearest neighbors.\n */\n search(t, k = 5) {\n if (this._parameters.metric === \"precomputed\") {\n throw new Error(\"Search by query element is only possible when not using a precomputed distance matrix!\");\n }\n /** @type {import(\"../metrics/index.js\").Metric} */\n const metric = /** @type {any} */ (this._parameters.metric);\n\n const isMatrix = this._elements instanceof Matrix;\n const elementsAny = /** @type {any} */ (this._elements);\n const N = isMatrix ? elementsAny.shape[0] : this._elements.length;\n\n // Compute distances from query to ALL points\n const distances = [];\n for (let i = 0; i < N; i++) {\n const element = /** @type {T} */ (isMatrix ? elementsAny.row(i) : this._elements[i]);\n distances.push({\n element: element,\n index: i,\n distance: metric(t, element),\n });\n }\n\n // Sort by distance and return k nearest\n distances.sort((a, b) => a.distance - b.distance);\n return distances.slice(0, k);\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { Randomizer } from \"../util/index.js\";\nimport { KNN } from \"./KNN.js\";\n\n/** @import {ParametersNNDescent} from \"./index.js\" */\n/**\n *\n * @template {number[] | Float64Array} T\n * @typedef {Object} NNDescentElement\n * @property {T} value\n * @property {number} index\n * @property {boolean} flag\n */\n\n/**\n * @template {number[] | Float64Array} T\n * @typedef {Object} NNDescentNeighbor\n * @property {T} value\n * @property {number} index\n * @property {number} distance\n * @property {boolean} [flag]\n */\n\n/**\n * NN-Descent\n *\n * An efficient graph-based approximate nearest neighbor search algorithm.\n * It works by iteratively improving a neighbor graph using the fact that\n * \"neighbors of neighbors are likely to be neighbors\".\n *\n * @class\n * @category KNN\n * @template {number[] | Float64Array} T\n * @extends KNN\n * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf|NN-Descent Paper}\n */\nexport class NNDescent extends KNN {\n /**\n * @private\n * @type {KNNHeap[]}\n */\n _B = [];\n /**\n * @private\n * @type {NNDescentNeighbor[][]}\n */\n nn = [];\n\n /**\n * @param {T[]} elements - Called V in paper.\n * @param {Partial} parameters\n * @see {@link http://www.cs.princeton.edu/cass/papers/www11.pdf}\n */\n constructor(elements, parameters = {}) {\n super(\n elements,\n /** @type {ParametersNNDescent} */ (\n Object.assign({ metric: euclidean, K: 10, rho: 1, delta: 1e-3, seed: 1212 }, parameters)\n ),\n );\n this._N = elements.length;\n this._randomizer = new Randomizer(this._parameters.seed);\n this._sample_size = this._parameters.samples * this._parameters.rho;\n\n this._nndescent_elements = elements.map((e, i) => {\n return {\n value: e,\n index: i,\n flag: true,\n };\n });\n\n if (elements) {\n this.add(elements);\n }\n }\n\n /**\n * Samples Array A with sample size.\n *\n * @private\n * @template U\n * @param {U[]} A\n * @returns {U[]}\n */\n _sample(A) {\n const n = A.length;\n const sample_size = this._sample_size;\n if (sample_size > n) {\n return A;\n } else {\n const randomizer = this._randomizer;\n return randomizer.choice(A, sample_size);\n }\n }\n\n /**\n * @private\n * @param {KNNHeap} B\n * @param {NNDescentNeighbor} u\n * @returns {number}\n */\n _update(B, u) {\n if (B.set.has(u.index)) return 0;\n\n const worst = B.first;\n if (worst && B.length >= this._parameters.samples) {\n const dist = B._accessor(u);\n const worst_dist = B._accessor(worst.element);\n if (dist >= worst_dist) {\n return 0; // u is worse than the worst neighbor\n }\n }\n\n B.push(u);\n u.flag = true;\n if (B.length > this._parameters.samples) {\n B.pop();\n }\n return 1;\n }\n\n /**\n * @private\n * @param {(KNNHeap | null)[]} B\n * @returns {NNDescentNeighbor[][]}\n */\n _reverse(B) {\n const N = this._N;\n const R = new Array(N);\n for (let i = 0; i < N; i++) {\n R[i] = [];\n }\n for (let j = 0; j < N; j++) {\n const Bi = B[j];\n if (Bi) {\n const Bjdata = Bi.data();\n for (const neighbor of Bjdata) {\n const v = neighbor.index;\n R[v].push(neighbor);\n }\n }\n }\n return R;\n }\n\n /**\n * @param {T[]} elements\n * @returns {this}\n */\n add(elements) {\n const randomizer = this._randomizer;\n const metric = this._parameters.metric;\n const K = this._parameters.samples;\n const delta = this._parameters.delta;\n const N = elements.length;\n this._N = N;\n /** @type {KNNHeap[]} */\n const B = [];\n this._B = B;\n for (let i = 0; i < N; i++) {\n const e = elements[i];\n const sample = randomizer\n .choice(\n elements.map((el, idx) => ({ el, idx })),\n K,\n )\n .map((d) => {\n return { index: d.idx, distance: metric(d.el, e), value: d.el };\n });\n const Bi = new KNNHeap(sample, (d) => d.distance, \"max\");\n B.push(Bi);\n }\n\n let c = Infinity;\n let old_c = -Infinity;\n while (c > delta * N * K && c !== old_c) {\n const old_ = new Array(N);\n const new_ = new Array(N);\n for (let i = 0; i < N; i++) {\n const Bi = B[i].data();\n const falseBs = Bi.filter((d) => !d.flag);\n const trueBs = this._sample(Bi.filter((d) => d.flag));\n for (const d of trueBs) {\n d.flag = false;\n }\n old_[i] = new KNNHeap(falseBs, (d) => d.distance, \"max\");\n new_[i] = new KNNHeap(trueBs, (d) => d.distance, \"max\");\n }\n const old_reverse = this._reverse(old_);\n const new_reverse = this._reverse(new_);\n old_c = c;\n c = 0;\n for (let i = 0; i < N; i++) {\n for (const o of this._sample(old_reverse[i])) {\n old_[i].push(o);\n }\n for (const n of this._sample(new_reverse[i])) {\n new_[i].push(n);\n }\n\n const new_i = new_[i].data();\n const old_i = old_[i].data();\n const n1 = new_i.length;\n const n2 = old_i.length;\n for (let j = 0; j < n1; j++) {\n const u1 = new_i[j];\n const Bu1 = B[u1.index];\n for (let k = 0; k < n1; k++) {\n const u2 = new_i[k];\n if (u1.index === u2.index) continue;\n const Bu2 = B[u2.index];\n c += this._update(Bu2, u1);\n c += this._update(Bu1, u2);\n }\n for (let k = 0; k < n2; k++) {\n const u2 = old_i[k];\n if (u1.index === u2.index) continue;\n const Bu2 = B[u2.index];\n c += this._update(Bu2, u1);\n c += this._update(Bu1, u2);\n }\n }\n }\n }\n this.nn = this._B.map((heap) => heap.data());\n return this;\n }\n\n /**\n * @param {T} x\n * @param {number} [k=5] Default is `5`\n * @returns {{ element: T, index: number; distance: number }[]}\n */\n search(x, k = 5) {\n const metric = this._parameters.metric;\n const N = this._N;\n const elements = this._elements;\n\n if (N === 0) return [];\n const xLength = x.length;\n\n // Initialize candidate pool\n const visited = new Set();\n /** @type {{index: number, dist: number, evaluated: boolean}[]} */\n let pool = [];\n\n // Randomly pick initial candidates\n const randomizer = this._randomizer;\n for (let i = 0; i < Math.min(N, Math.max(k * 10, 50)); i++) {\n let rnd;\n do {\n rnd = randomizer.random_int % N;\n } while (visited.has(rnd));\n visited.add(rnd);\n\n const element = elements[rnd];\n if (!element || element.length !== xLength) continue;\n\n pool.push({\n index: rnd,\n dist: metric(x, element),\n evaluated: false,\n });\n }\n\n let searching = true;\n while (searching) {\n pool.sort((a, b) => a.dist - b.dist);\n // keep the top subset for exploration\n pool = pool.slice(0, Math.max(k * 5, 50));\n\n searching = false;\n for (let i = 0; i < pool.length; i++) {\n const candidate = pool[i];\n if (candidate.evaluated) continue;\n\n candidate.evaluated = true;\n searching = true;\n\n // get neighbors of this candidate from graph\n const neighbors = this.nn[candidate.index];\n if (!neighbors) continue;\n\n for (const neighbor of neighbors) {\n const n_idx = neighbor.index;\n if (!visited.has(n_idx)) {\n visited.add(n_idx);\n const element = elements[n_idx];\n if (element && element.length === xLength) {\n pool.push({\n index: n_idx,\n dist: metric(x, element),\n evaluated: false,\n });\n }\n }\n }\n // Don't break here! Look at more candidates per iteration for better convergence\n // break;\n }\n }\n\n pool.sort((a, b) => a.dist - b.dist);\n\n /** @type {{ element: T, index: number; distance: number }[]} */\n const result = [];\n for (let i = 0; i < Math.min(k, pool.length); i++) {\n const item = pool[i];\n result.push({\n element: elements[item.index],\n index: item.index,\n distance: item.dist,\n });\n }\n return result;\n }\n\n /**\n * @param {number} i\n * @param {number} [k=5] Default is `5`\n * @returns {{ element: T; index: number; distance: number }[]}\n */\n search_by_index(i, k = 5) {\n // Use regular search with the element at index i\n const elements = this._elements;\n if (i < 0 || i >= elements.length) return [];\n\n const element = elements[i];\n if (!element) return [];\n\n return this.search(element, k);\n }\n}\n\n/**\n * @template {number[] | Float64Array} U\n * @typedef {Object} HeapEntry\n * @property {NNDescentNeighbor} element\n * @property {number} value\n */\n\n/**\n * @template {number[] | Float64Array} U\n * @extends {Heap>}\n */\nclass KNNHeap extends Heap {\n /** @type {Set} */\n set;\n\n /**\n * @param {NNDescentNeighbor[]} elements\n * @param {(d: NNDescentNeighbor) => number} accessor\n * @param {\"max\" | \"min\"} comparator\n */\n constructor(elements, accessor, comparator) {\n super(null, accessor, comparator);\n this.set = new Set();\n if (elements) {\n for (const element of elements) {\n this.push(element);\n }\n }\n }\n\n /**\n * @param {NNDescentNeighbor} element\n * @returns {KNNHeap}\n */\n push(element) {\n const set = this.set;\n if (set.has(element.index)) {\n return this;\n } else {\n set.add(element.index);\n super.push(element);\n return this;\n }\n }\n\n /** @returns {{ element: NNDescentNeighbor; value: number } | null} */\n pop() {\n const result = super.pop();\n if (result?.element) {\n this.set.delete(result.element.index);\n return result;\n }\n return null;\n }\n\n /** @returns {NNDescentNeighbor[]} */\n data() {\n return this._container.map((d) => d.element);\n }\n}\n","import { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersPCA} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n\n/**\n * Principal Component Analysis (PCA)\n *\n * A linear dimensionality reduction technique that identifies the axes (principal components)\n * along which the variance of the data is maximized.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link MDS} for another linear alternative\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2], [3, 4], [5, 6]];\n * const pca = new druid.PCA(X, { d: 2 });\n * const Y = pca.transform();\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class PCA extends DR {\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X, parameters = {}) {\n super(X, { d: 2, seed: 1212, eig_args: {} }, parameters);\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n if (!Object.hasOwn(eig_args, \"seed\")) {\n eig_args.seed = this._randomizer;\n }\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T} - The projected data.\n */\n transform() {\n const V = this.principal_components();\n const X = this.X;\n this.Y = X.dot(V);\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new PCA(X, parameters);\n return dr.transform();\n }\n\n /**\n * Computes the `d` principal components of Matrix `X`.\n *\n * @returns {Matrix}\n */\n principal_components() {\n if (this.V) {\n return this.V;\n }\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n const X = this.X;\n const X_cent = X.sub(X.meanCols());\n const C = X_cent.transDot(X_cent);\n const { eigenvectors: V } = simultaneous_poweriteration(C, d, eig_args);\n this.V = Matrix.from(V).transpose();\n return this.V;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Matrix}\n */\n static principal_components(X, parameters) {\n const dr = new PCA(X, parameters);\n return dr.principal_components();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new PCA(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new PCA(X, parameters);\n return dr.transform_async();\n }\n}\n","import { BallTree } from \"../knn/index.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { euclidean, euclidean_squared } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\nimport { PCA } from \"./PCA.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersPaCMAP} from \"./index.js\" */\n\n/**\n * Pairwise Controlled Manifold Approximation Projection (PaCMAP)\n *\n * A dimensionality reduction technique that uses three types of point pairs —\n * nearest neighbor (NN), mid-near (MN), and further (FP) pairs — with a\n * dynamic three-phase weight schedule and Adam optimization to preserve both\n * local and global structure.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link https://arxiv.org/abs/2012.04456|PaCMAP Paper}\n * @see {@link https://github.com/YingfanWang/PaCMAP|PaCMAP GitHub}\n * @see {@link UMAP} for a related graph-based technique\n * @see {@link LocalMAP} for the local-refinement variant\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];\n * const pacmap = new druid.PaCMAP(X, {\n * n_neighbors: 10,\n * MN_ratio: 0.5,\n * FP_ratio: 2.0,\n * seed: 42\n * });\n *\n * const Y = pacmap.transform(); // 450 iterations (default)\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class PaCMAP extends DR {\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X, parameters) {\n super(\n X,\n {\n n_neighbors: 10,\n MN_ratio: 0.5,\n FP_ratio: 2.0,\n d: 2,\n metric: euclidean,\n lr: 1.0,\n num_iters: [100, 100, 250],\n seed: 1212,\n },\n parameters,\n );\n [this._N, this._D] = this.X.shape;\n const n_neighbors = /** @type {number} */ (this.parameter(\"n_neighbors\"));\n if (n_neighbors >= this._N) {\n throw new Error(\n `Parameter n_neighbors (=${n_neighbors}) needs to be smaller than dataset size (N=${this._N})!`,\n );\n }\n this._iter = 0;\n }\n\n /**\n * Samples mid-near pairs for each point.\n * For each point i, repeats n_MN times: samples 6 random non-neighbor\n * candidates, picks the 2nd closest by high-dim distance.\n *\n * @protected\n * @param {Set[]} nn_sets - Array of neighbor index sets per point\n * @param {number} n_MN - Number of mid-near pairs per point\n * @returns {Int32Array} Flat array of [i, j] pairs\n */\n _sample_mn_pairs(nn_sets, n_MN) {\n const N = this._N;\n const X = this.X;\n const randomizer = this._randomizer;\n const pairs = new Int32Array(N * n_MN * 2);\n let idx = 0;\n\n for (let i = 0; i < N; ++i) {\n const nn_set = nn_sets[i];\n const x_i = X.row(i);\n\n for (let k = 0; k < n_MN; ++k) {\n // Sample 6 random non-neighbor candidates\n /** @type {{idx: number, dist: number}[]} */\n const candidates = [];\n let attempts = 0;\n while (candidates.length < 6 && attempts < N * 2) {\n const j = randomizer.random_int % N;\n attempts++;\n if (j !== i && !nn_set.has(j)) {\n candidates.push({ idx: j, dist: euclidean_squared(x_i, X.row(j)) });\n }\n }\n if (candidates.length < 2) {\n // Fallback: use any available non-self point\n const j = (i + 1) % N;\n pairs[idx++] = i;\n pairs[idx++] = j;\n continue;\n }\n candidates.sort((a, b) => a.dist - b.dist);\n // Pick the 2nd closest (index 1)\n pairs[idx++] = i;\n pairs[idx++] = candidates[1].idx;\n }\n }\n return pairs.slice(0, idx);\n }\n\n /**\n * Samples further pairs for each point (random non-neighbors).\n *\n * @protected\n * @param {Set[]} nn_sets - Array of neighbor index sets per point\n * @param {number} n_FP - Number of further pairs per point\n * @returns {Int32Array} Flat array of [i, j] pairs\n */\n _sample_fp_pairs(nn_sets, n_FP) {\n const N = this._N;\n const randomizer = this._randomizer;\n const pairs = new Int32Array(N * n_FP * 2);\n let idx = 0;\n\n for (let i = 0; i < N; ++i) {\n const nn_set = nn_sets[i];\n let count = 0;\n let attempts = 0;\n while (count < n_FP && attempts < N * 3) {\n const j = randomizer.random_int % N;\n attempts++;\n if (j !== i && !nn_set.has(j)) {\n pairs[idx++] = i;\n pairs[idx++] = j;\n count++;\n }\n }\n }\n return pairs.slice(0, idx);\n }\n\n /**\n * Computes gradient coefficients and updates the gradient matrix for one pair type.\n *\n * @protected\n * @param {Float64Array} grad_flat - Flat N×d gradient accumulator (modified in place)\n * @param {Int32Array} pairs - Flat [i, j, i, j, ...] pair array\n * @param {number} w - Weight for this pair type\n * @param {number} attr_num - Numerator constant for attractive (10 for NN, 10000 for MN); 0 for repulsive\n * @param {boolean} repulsive - Whether this is a repulsive pair type\n */\n _accumulate_gradients(grad_flat, pairs, w, attr_num, repulsive) {\n if (w === 0) return;\n const Y = this.Y;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const n_pairs = pairs.length / 2;\n\n for (let p = 0; p < n_pairs; ++p) {\n const i = pairs[p * 2];\n const j = pairs[p * 2 + 1];\n const y_i = Y.row(i);\n const y_j = Y.row(j);\n\n // d_ij = 1 + ||y_i - y_j||²\n let sq_dist = 0;\n for (let k = 0; k < d; ++k) {\n const diff = y_i[k] - y_j[k];\n sq_dist += diff * diff;\n }\n const d_ij = 1 + sq_dist;\n\n /** @type {number} */\n let coeff;\n if (repulsive) {\n // FP loss: 1/(1+d_ij), gradient: -2/(1+d_ij)²\n coeff = (-w * 2) / (d_ij * d_ij);\n } else {\n // NN loss: d_ij/(attr_num+d_ij), gradient: 2*attr_num/(attr_num+d_ij)²\n const denom = attr_num + d_ij;\n coeff = (w * 2 * attr_num) / (denom * denom);\n }\n\n const base_i = i * d;\n const base_j = j * d;\n for (let k = 0; k < d; ++k) {\n const diff = y_i[k] - y_j[k];\n const g = coeff * diff;\n grad_flat[base_i + k] += g;\n grad_flat[base_j + k] -= g;\n }\n }\n }\n\n /**\n * Returns the weight schedule for the current iteration.\n *\n * @protected\n * @param {number} iter - Current iteration (0-indexed)\n * @returns {{ w_nn: number; w_mn: number; w_fp: number }}\n */\n _get_weights(iter) {\n const num_iters = /** @type {number[]} */ (this.parameter(\"num_iters\"));\n const [p1, p2] = num_iters;\n if (iter < p1) {\n // Phase 1: MN weight linearly decays from 1000 to 3\n const t = iter / p1;\n return { w_nn: 2.0, w_mn: 1000.0 * (1 - t) + 3.0 * t, w_fp: 1.0 };\n } else if (iter < p1 + p2) {\n // Phase 2: fixed weights\n return { w_nn: 3.0, w_mn: 3.0, w_fp: 1.0 };\n } else {\n // Phase 3: MN disabled\n return { w_nn: 1.0, w_mn: 0.0, w_fp: 1.0 };\n }\n }\n\n /**\n * Applies Adam optimizer update to Y using accumulated gradients.\n *\n * @protected\n * @param {Float64Array} grad_flat - Flat N×d gradient\n */\n _adam_update(grad_flat) {\n const lr = /** @type {number} */ (this.parameter(\"lr\"));\n const N = this._N;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const beta1 = 0.9;\n const beta2 = 0.999;\n const eps = 1e-7;\n this._adam_t = (this._adam_t ?? 0) + 1;\n const t = /** @type {number} */ (this._adam_t);\n const bc1 = 1 - beta1 ** t;\n const bc2 = 1 - beta2 ** t;\n const Y = this.Y;\n const m = /** @type {Float64Array} */ (this._adam_m);\n const v = /** @type {Float64Array} */ (this._adam_v);\n\n for (let i = 0; i < N; ++i) {\n const base = i * d;\n const y_i = Y.row(i);\n for (let k = 0; k < d; ++k) {\n const g = grad_flat[base + k];\n m[base + k] = beta1 * m[base + k] + (1 - beta1) * g;\n v[base + k] = beta2 * v[base + k] + (1 - beta2) * g * g;\n const m_hat = m[base + k] / bc1;\n const v_hat = v[base + k] / bc2;\n y_i[k] -= lr * (m_hat / (Math.sqrt(v_hat) + eps));\n }\n }\n }\n\n /**\n * Initializes PaCMAP: PCA embedding, KNN pairs, MN pairs, FP pairs, Adam state.\n *\n * @returns {PaCMAP}\n */\n init() {\n const X = this.X;\n const N = this._N;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const seed = /** @type {number} */ (this.parameter(\"seed\"));\n const metric = /** @type {Metric} */ (this.parameter(\"metric\"));\n const n_neighbors = /** @type {number} */ (this.parameter(\"n_neighbors\"));\n const MN_ratio = /** @type {number} */ (this.parameter(\"MN_ratio\"));\n const FP_ratio = /** @type {number} */ (this.parameter(\"FP_ratio\"));\n\n // 1. PCA initialization scaled by 0.01 (X is always Matrix here)\n const pca_init = /** @type {Matrix} */ (PCA.transform(X, { d, seed }));\n this.Y = new Matrix(N, d, (i, j) => pca_init.entry(i, j) * 0.01);\n\n // 2. Build KNN graph for NN pairs\n const knn = new BallTree(X.to2dArray(), { metric, seed });\n const n_MN = Math.max(1, Math.round(n_neighbors * MN_ratio));\n const n_FP = Math.max(1, Math.round(n_neighbors * FP_ratio));\n\n /** @type {Int32Array[]} */\n const nn_indices = [];\n /** @type {Set[]} */\n const nn_sets = [];\n // NN pairs: flat [i, j] pairs\n const nn_pairs = new Int32Array(N * n_neighbors * 2);\n let nn_idx = 0;\n\n for (let i = 0; i < N; ++i) {\n const neighbors = knn.search(X.row(i), n_neighbors + 1);\n /** @type {number[]} */\n const idxs = [];\n for (const nb of neighbors) {\n if (nb.index !== i) idxs.push(nb.index);\n if (idxs.length >= n_neighbors) break;\n }\n nn_indices[i] = new Int32Array(idxs);\n nn_sets[i] = new Set(idxs);\n for (const j of idxs) {\n nn_pairs[nn_idx++] = i;\n nn_pairs[nn_idx++] = j;\n }\n }\n this._nn_pairs = nn_pairs.slice(0, nn_idx);\n\n // 3. MN pairs (mid-near sampling)\n this._mn_pairs = this._sample_mn_pairs(nn_sets, n_MN);\n\n // 4. FP pairs (random non-neighbors)\n this._fp_pairs = this._sample_fp_pairs(nn_sets, n_FP);\n\n // 5. Adam optimizer state\n this._adam_m = new Float64Array(N * d);\n this._adam_v = new Float64Array(N * d);\n this._adam_t = 0;\n\n this._iter = 0;\n return this;\n }\n\n /**\n * Performs one optimization step.\n *\n * @returns {Matrix}\n */\n next() {\n if (!this._nn_pairs) throw new Error(\"Call init() first!\");\n const N = this._N;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const { w_nn, w_mn, w_fp } = this._get_weights(this._iter);\n\n const grad_flat = new Float64Array(N * d);\n this._accumulate_gradients(grad_flat, /** @type {Int32Array} */ (this._nn_pairs), w_nn, 10, false);\n this._accumulate_gradients(grad_flat, /** @type {Int32Array} */ (this._mn_pairs), w_mn, 10000, false);\n this._accumulate_gradients(grad_flat, /** @type {Int32Array} */ (this._fp_pairs), w_fp, 0, true);\n this._adam_update(grad_flat);\n\n this._iter++;\n return this.Y;\n }\n\n /**\n * @param {number} [iterations] - Total number of iterations. Defaults to sum of `num_iters`.\n * @returns {T}\n */\n transform(iterations) {\n const num_iters = /** @type {number[]} */ (this.parameter(\"num_iters\"));\n const total = iterations ?? num_iters.reduce((a, b) => a + b, 0);\n this.check_init();\n for (let i = 0; i < total; ++i) {\n this.next();\n }\n return this.projection;\n }\n\n /**\n * @param {number} [iterations] - Total number of iterations. Defaults to sum of `num_iters`.\n * @returns {Generator}\n */\n *generator(iterations) {\n const num_iters = /** @type {number[]} */ (this.parameter(\"num_iters\"));\n const total = iterations ?? num_iters.reduce((a, b) => a + b, 0);\n this.check_init();\n for (let i = 0; i < total; ++i) {\n this.next();\n yield this.projection;\n }\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new PaCMAP(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new PaCMAP(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new PaCMAP(X, parameters);\n return dr.transform_async();\n }\n}\n","import { BallTree } from \"../knn/index.js\";\nimport { euclidean_squared } from \"../metrics/index.js\";\nimport { PaCMAP } from \"./PaCMAP.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLocalMAP} from \"./index.js\" */\n\n/**\n * LocalMAP\n *\n * A variant of PaCMAP that improves local cluster separation by dynamically\n * resampling further pairs (FP) in phase 3 using nearby points in the current\n * low-dimensional embedding space, rather than randomly sampled non-neighbors.\n *\n * @class\n * @template {InputType} T\n * @extends PaCMAP\n * @category Dimensionality Reduction\n * @see {@link https://arxiv.org/abs/2012.04456|PaCMAP Paper}\n * @see {@link PaCMAP} for the base algorithm\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];\n * const localmap = new druid.LocalMAP(X, {\n * n_neighbors: 10,\n * low_dist_thres: 10,\n * seed: 42\n * });\n *\n * const Y = localmap.transform(); // 450 iterations (default)\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class LocalMAP extends PaCMAP {\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X, parameters = {}) {\n // Merge low_dist_thres into parameters before the seal in DR constructor.\n // DR.constructor does Object.seal({ ...defaults, ...parameters }), so\n // passing low_dist_thres here ensures it lands in the sealed object.\n super(X, { low_dist_thres: 10, ...parameters });\n }\n\n /**\n * Performs one optimization step.\n * In phase 3, resamples FP pairs from the current embedding space\n * and applies distance-based weight scaling.\n *\n * @returns {import(\"../matrix/index.js\").Matrix}\n */\n next() {\n if (!this._nn_pairs) throw new Error(\"Call init() first!\");\n const num_iters = /** @type {number[]} */ (this.parameter(\"num_iters\"));\n const phase3_start = num_iters[0] + num_iters[1];\n\n if (this._iter < phase3_start) {\n // Phases 1 and 2: identical to PaCMAP\n return super.next();\n }\n\n // Phase 3: resample FP pairs from embedding neighbors\n const N = this._N;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const low_dist_thres = /** @type {number} */ (this._low_dist_thres ?? 10);\n const low_dist_thres_sq = low_dist_thres * low_dist_thres;\n const { w_nn, w_mn, w_fp } = this._get_weights(this._iter);\n const Y = this.Y;\n\n // Build a KNN structure on the current embedding to find nearby pairs\n const y_array = Y.to2dArray();\n const seed = /** @type {number} */ (this.parameter(\"seed\"));\n const emb_knn = new BallTree(y_array, { metric: euclidean_squared, seed });\n const n_FP = /** @type {number} */ (this.parameter(\"FP_ratio\")) *\n /** @type {number} */ (this.parameter(\"n_neighbors\"));\n const n_FP_int = Math.max(1, Math.round(n_FP));\n\n // Build local FP pairs by finding nearby embedding neighbors\n // (these are not NN neighbors in high-dim space but nearby in low-dim)\n const nn_sets = this._nn_sets_cache;\n /** @type {Int32Array} */\n let local_fp_pairs;\n\n if (nn_sets) {\n const pair_buf = new Int32Array(N * n_FP_int * 2);\n let idx = 0;\n for (let i = 0; i < N; ++i) {\n const nn_set = nn_sets[i];\n // Search for nearby points in embedding space\n const neighbors = emb_knn.search(y_array[i], Math.min(n_FP_int * 3 + 1, N));\n let count = 0;\n for (const nb of neighbors) {\n if (nb.index === i || (nn_set && nn_set.has(nb.index))) continue;\n pair_buf[idx++] = i;\n pair_buf[idx++] = nb.index;\n count++;\n if (count >= n_FP_int) break;\n }\n }\n local_fp_pairs = pair_buf.slice(0, idx);\n } else {\n local_fp_pairs = /** @type {Int32Array} */ (this._fp_pairs);\n }\n\n // Accumulate gradients with local weight scaling for FP pairs\n const grad_flat = new Float64Array(N * d);\n this._accumulate_gradients(grad_flat, /** @type {Int32Array} */ (this._nn_pairs), w_nn, 10, false);\n this._accumulate_gradients(grad_flat, /** @type {Int32Array} */ (this._mn_pairs), w_mn, 10000, false);\n\n // FP pairs with local distance-based weight scaling\n this._accumulate_gradients_local_fp(\n grad_flat,\n local_fp_pairs,\n w_fp,\n low_dist_thres,\n low_dist_thres_sq,\n );\n\n this._adam_update(grad_flat);\n this._iter++;\n return this.Y;\n }\n\n /**\n * Accumulates FP gradients with LocalMAP's distance-based weight scaling.\n * For pairs within low_dist_thres, scales w_fp by low_dist_thres / (2 * sqrt(d_ij)).\n *\n * @private\n * @param {Float64Array} grad_flat - Flat N×d gradient accumulator (modified in place)\n * @param {Int32Array} pairs - Flat [i, j, i, j, ...] pair array\n * @param {number} w_fp - Base FP weight\n * @param {number} low_dist_thres - Distance threshold\n * @param {number} low_dist_thres_sq - Squared distance threshold\n */\n _accumulate_gradients_local_fp(grad_flat, pairs, w_fp, low_dist_thres, low_dist_thres_sq) {\n if (w_fp === 0) return;\n const Y = this.Y;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const n_pairs = pairs.length / 2;\n\n for (let p = 0; p < n_pairs; ++p) {\n const i = pairs[p * 2];\n const j = pairs[p * 2 + 1];\n const y_i = Y.row(i);\n const y_j = Y.row(j);\n\n let sq_dist = 0;\n for (let k = 0; k < d; ++k) {\n const diff = y_i[k] - y_j[k];\n sq_dist += diff * diff;\n }\n const d_ij = 1 + sq_dist;\n\n // Apply local weight scaling when pair is within distance threshold\n let w = w_fp;\n if (sq_dist < low_dist_thres_sq) {\n w *= low_dist_thres / (2 * Math.sqrt(d_ij));\n }\n\n // FP loss: 1/(1+d_ij), gradient: -2/(1+d_ij)²\n const coeff = (-w * 2) / (d_ij * d_ij);\n\n const base_i = i * d;\n const base_j = j * d;\n for (let k = 0; k < d; ++k) {\n const diff = y_i[k] - y_j[k];\n const g = coeff * diff;\n grad_flat[base_i + k] += g;\n grad_flat[base_j + k] -= g;\n }\n }\n }\n\n /**\n * Initializes LocalMAP (same as PaCMAP, but caches nn_sets for phase 3 resampling).\n *\n * @returns {LocalMAP}\n */\n init() {\n super.init();\n // Cache low_dist_thres from sealed parameters (avoids type indexing issues)\n this._low_dist_thres = /** @type {number} */ (/** @type {any} */ (this._parameters)[\"low_dist_thres\"] ?? 10);\n // Cache nn_sets for use in phase 3 FP resampling\n // We rebuild them from _nn_pairs\n const N = this._N;\n const nn_pairs = this._nn_pairs;\n if (!nn_pairs) return this;\n /** @type {Set[]} */\n const nn_sets = Array.from({ length: N }, () => new Set());\n for (let p = 0; p < nn_pairs.length; p += 2) {\n nn_sets[nn_pairs[p]].add(nn_pairs[p + 1]);\n }\n this._nn_sets_cache = nn_sets;\n return this;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new LocalMAP(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new LocalMAP(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new LocalMAP(X, parameters);\n return dr.transform_async();\n }\n}\n","import { distance_matrix, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersSMACOF} from \"./index.js\" */\n\n/**\n * Metric Multidimensional Scaling (MDS) via SMACOF.\n *\n * SMACOF (Scaling by Majorizing a Complicated Function) is an iterative majorization\n * algorithm for solving metric multidimensional scaling problems, which aims to\n * minimize the stress function.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link MDS} for the classical approach.\n */\nexport class SMACOF extends DR {\n /**\n * SMACOF for MDS.\n *\n * @param {T} X - The high-dimensional data or precomputed distance matrix.\n * @param {Partial} [parameters] - Object containing parameterization.\n */\n constructor(X, parameters = {}) {\n super(X, { d: 2, metric: euclidean, seed: 1212, iterations: 300, epsilon: 1e-4 }, parameters);\n }\n\n /**\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n this.check_init();\n const X = this.X;\n const rows = this._N;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const metric = /** @type {typeof euclidean | \"precomputed\"} */ (this.parameter(\"metric\"));\n const iterations = /** @type {number} */ (this.parameter(\"iterations\"));\n const epsilon = /** @type {number} */ (this.parameter(\"epsilon\"));\n\n const target_distances = metric === \"precomputed\" ? X : distance_matrix(X, metric);\n\n let Z = new Matrix(rows, d, () => (this._randomizer.random - 0.5) * 2);\n\n // Center Z\n for (let j = 0; j < d; ++j) {\n const col = Z.col(j);\n const mean = col.reduce((a, b) => a + b, 0) / rows;\n for (let i = 0; i < rows; ++i) {\n Z.sub_entry(i, j, mean);\n }\n }\n\n this.Y = /** @type {Matrix} */ (Z); // Initial state\n\n let prev_stress = Infinity;\n\n if (!(iterations > 0)) {\n yield this.projection;\n return this.projection;\n }\n\n for (let iter = 0; iter < iterations; ++iter) {\n const B = new Matrix(rows, rows, 0);\n\n for (let i = 0; i < rows; ++i) {\n let bii = 0;\n const z_i = Z.row(i);\n for (let j = 0; j < rows; ++j) {\n if (i === j) continue;\n const z_j = Z.row(j);\n const dist_Z = euclidean(z_i, z_j);\n const dist_target = target_distances.entry(i, j);\n\n let bij = 0;\n if (dist_Z > 1e-12) {\n bij = -dist_target / dist_Z;\n }\n B.set_entry(i, j, bij);\n bii -= bij;\n }\n B.set_entry(i, i, bii);\n }\n\n // Z_new = 1/N * B(Z) * Z\n const Z_new = B.dot(Z)._apply(rows, (val, n) => val / n);\n\n this.Y = /** @type {Matrix} */ (Z_new);\n Z = /** @type {Matrix} */ (Z_new);\n\n // Calculate stress\n let stress_num = 0;\n let stress_den = 0;\n for (let i = 0; i < rows; ++i) {\n const z_i = Z.row(i);\n for (let j = i + 1; j < rows; ++j) {\n const z_j = Z.row(j);\n const dist_Y = euclidean(z_i, z_j);\n const diff = target_distances.entry(i, j) - dist_Y;\n stress_num += diff * diff;\n stress_den += target_distances.entry(i, j) ** 2;\n }\n }\n const current_stress = Math.sqrt(stress_num / Math.max(stress_den, 1e-12));\n\n yield this.projection;\n\n if (Math.abs(prev_stress - current_stress) < epsilon) {\n break;\n }\n prev_stress = current_stress;\n }\n return this.projection;\n }\n\n /**\n * @returns {T}\n */\n transform() {\n const gen = this.generator();\n let res = /** @type {T} */ (this.X);\n for (const step of gen) {\n res = step;\n }\n return res;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new SMACOF(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new SMACOF(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new SMACOF(X, parameters);\n return dr.transform_async();\n }\n}\n","import { Heap } from \"../datastructure/index.js\";\nimport { BallTree } from \"../knn/index.js\";\nimport { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\nimport { SMACOF } from \"./SMACOF.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersISOMAP} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n\n/**\n * Isomap (Isometric Mapping)\n *\n * A nonlinear dimensionality reduction algorithm that uses geodesic distances\n * between points on a manifold to perform embedding. It builds a neighborhood\n * graph and uses MDS on the shortest-path distances.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link LLE} for another nonlinear alternative\n */\nexport class ISOMAP extends DR {\n /**\n * Isometric feature mapping (ISOMAP).\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n * @see {@link https://doi.org/10.1126/science.290.5500.2319}\n */\n constructor(X, parameters = {}) {\n /** @type {ParametersISOMAP} */\n const defaults = {\n neighbors: -Infinity,\n d: 2,\n metric: euclidean,\n seed: 1212,\n project: \"MDS\",\n eig_args: {},\n };\n super(X, defaults, parameters);\n\n this.defaults = defaults;\n\n if (this._parameters.neighbors === -Infinity) {\n this.parameter(\"neighbors\", Math.min(Math.max(Math.floor(this.X.shape[0] / 10), 2), this._N - 1));\n }\n\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n if (!Object.hasOwn(eig_args, \"seed\")) {\n eig_args.seed = this._randomizer;\n }\n }\n\n /**\n * Computes the projection.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * @returns {T}\n */\n transform() {\n this.check_init();\n const X = this.X;\n const rows = this._N;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const metric = /** @type {typeof euclidean} */ (this.parameter(\"metric\"));\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n const neighbors = /** @type {number} */ (this.parameter(\"neighbors\"));\n // TODO: make knn extern and parameter for constructor or transform?\n const D = new Matrix(rows, rows, 0);\n D.shape = [rows, rows, (i, j) => (i <= j ? metric(X.row(i), X.row(j)) : D.entry(j, i))];\n\n /** @type {{ index: number; distance: number }[][]} */\n const kNearestNeighbors = [];\n const tree = new BallTree(X.to2dArray(), {\n metric,\n seed: /** @type {number} */ (this.parameter(\"seed\")),\n });\n for (let i = 0; i < rows; ++i) {\n // BallTree search returns elements including the queried point itself (at distance 0).\n // Request neighbors + 1 and slice off the first one (which should be the query point).\n const neighborsList = tree.search_by_index(i, neighbors + 1);\n kNearestNeighbors.push(\n neighborsList.slice(1).map((n) => ({\n index: n.index,\n distance: n.distance,\n })),\n );\n }\n\n // ISOMAP requires an undirected/symmetric nearest neighbor graph.\n // If i is a nearest neighbor of j, then j should be connected to i as well.\n for (let i = 0; i < rows; ++i) {\n for (const neighbor of kNearestNeighbors[i]) {\n const j = neighbor.index;\n const d = neighbor.distance;\n const reciprocal_edge = kNearestNeighbors[j].find((n) => n.index === i);\n if (!reciprocal_edge) {\n kNearestNeighbors[j].push({ index: i, distance: d });\n }\n }\n }\n\n /*D = dijkstra(kNearestNeighbors);*/\n // compute shortest paths using Dijkstra's algorithm\n // TODO: make extern\n const G = new Matrix(rows, rows, Infinity);\n\n for (let i = 0; i < rows; ++i) {\n G.set_entry(i, i, 0);\n const H = new Heap([{ index: i, distance: 0 }], (d) => d.distance, \"min\");\n\n while (!H.empty) {\n const item = H.pop();\n if (!item) break;\n\n const u = item.element.index;\n const dist_u = item.element.distance;\n\n if (dist_u > G.entry(i, u)) continue;\n\n for (const neighbor of kNearestNeighbors[u]) {\n const v = neighbor.index;\n const alt = dist_u + neighbor.distance;\n if (alt < G.entry(i, v)) {\n G.set_entry(i, v, alt);\n H.push({ index: v, distance: alt });\n }\n }\n }\n }\n\n let max_val = 0;\n for (let i = 0; i < rows; i++) {\n for (let j = 0; j < rows; j++) {\n const val = G.entry(i, j);\n if (val !== Infinity && val > max_val) max_val = val;\n }\n }\n const big_val = max_val * 10;\n\n const project = /** @type {\"MDS\" | \"SMACOF\"} */ (this.parameter(\"project\"));\n\n if (project === \"SMACOF\") {\n // Apply SMACOF metric MDS to the distance matrix directly\n const D_matrix = new Matrix(rows, rows, (i, j) => {\n const val = G.entry(i, j);\n return val === Infinity ? big_val : val;\n });\n const smacof = new SMACOF(D_matrix, {\n metric: \"precomputed\",\n d,\n seed: this.parameter(\"seed\"),\n });\n smacof.transform();\n this.Y = smacof.Y;\n } else {\n // \"MDS\" (Classical MDS) via Eigendecomposition of double-centered squared distance matrix\n const D_sq = new Matrix(rows, rows, (i, j) => {\n let val = G.entry(i, j);\n if (val === Infinity) val = big_val;\n return val * val;\n });\n\n const ai_ = D_sq.meanCols();\n const a_j = D_sq.meanRows();\n const a__ = D_sq.mean();\n const B = new Matrix(rows, rows, (i, j) => -0.5 * (D_sq.entry(i, j) - ai_[i] - a_j[j] + a__));\n\n // compute d eigenvectors\n const { eigenvectors: V } = simultaneous_poweriteration(B, d, eig_args);\n this.Y = Matrix.from(V).transpose();\n }\n // return embedding\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new ISOMAP(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new ISOMAP(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new ISOMAP(X, parameters);\n return dr.transform_async();\n }\n}\n","import { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLDA} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n\n/**\n * Linear Discriminant Analysis (LDA)\n *\n * A supervised dimensionality reduction technique that finds the axes that\n * maximize the separation between multiple classes.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class LDA extends DR {\n /**\n * Linear Discriminant Analysis.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial & { labels: any[] | Float64Array }} parameters - Object containing parameterization of the DR method.\n * @see {@link https://onlinelibrary.wiley.com/doi/10.1111/j.1469-1809.1936.tb02137.x}\n */\n constructor(X, parameters) {\n super(X, { labels: parameters.labels, d: 2, seed: 1212, eig_args: {} }, parameters);\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n if (!Object.hasOwn(eig_args, \"seed\")) {\n eig_args.seed = this._randomizer;\n }\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T} - The projected data.\n */\n transform() {\n const X = this.X;\n const [rows, cols] = X.shape;\n const { d, labels, eig_args } = this._parameters;\n if (labels === null || labels.length !== rows) {\n throw new Error(\"LDA needs parameter label to every datapoint to work!\");\n }\n\n /** @type {Record} */\n const unique_labels = {};\n let label_id = 0;\n labels.forEach((l, i) => {\n if (l in unique_labels) {\n unique_labels[l].count++;\n unique_labels[l].rows.push(X.row(i));\n } else {\n unique_labels[l] = {\n id: label_id++,\n count: 1,\n rows: [X.row(i)],\n };\n }\n });\n\n // create X_mean and vector means;\n const X_mean = X.meanCols();\n const V_mean = new Matrix(label_id, cols);\n for (const label in unique_labels) {\n const V = Matrix.from(unique_labels[label].rows);\n const v_mean = V.meanCols();\n for (let j = 0; j < cols; ++j) {\n V_mean.set_entry(unique_labels[label].id, j, v_mean[j]);\n }\n }\n // scatter_between\n let S_b = new Matrix(cols, cols);\n for (const label in unique_labels) {\n const v = V_mean.row(unique_labels[label].id);\n const m = Matrix.from([v]).sub(Matrix.from([X_mean]));\n const N = unique_labels[label].count;\n S_b = S_b.add(m.transDot(m).mult(N));\n }\n\n // scatter_within\n let S_w = new Matrix(cols, cols);\n for (const label in unique_labels) {\n const v = V_mean.row(unique_labels[label].id);\n const R = unique_labels[label].rows;\n for (let i = 0, n = unique_labels[label].count; i < n; ++i) {\n const row_v = Matrix.from([R[i]]).sub(Matrix.from([v]));\n S_w = S_w.add(row_v.transDot(row_v));\n }\n }\n\n const { eigenvectors: EV } = simultaneous_poweriteration(\n S_w.inverse().dot(S_b),\n d || Math.min(cols, label_id - 1),\n eig_args,\n );\n const V = Matrix.from(EV).transpose();\n this.Y = X.dot(V);\n\n // return embedding\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @returns {T}\n */\n static transform(X, parameters) {\n // @ts-expect-error: LDA requires labels, but DR static transform doesn't\n const dr = new LDA(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n // @ts-expect-error: LDA requires labels, but DR static generator doesn't\n const dr = new LDA(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @template {{ seed?: number }} Para\n * @param {T} X\n * @param {Para} parameters\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n // @ts-expect-error: LDA requires labels, but DR static transform doesn't\n const dr = new LDA(X, parameters);\n return dr.transform_async();\n }\n}\n","import { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { k_nearest_neighbors, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { neumair_sum } from \"../numerical/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLLE} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n\n/**\n * Locally Linear Embedding (LLE)\n *\n * A nonlinear dimensionality reduction technique that preserves local\n * linear relationships between points. It represents each point as a linear\n * combination of its neighbors.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link ISOMAP} for another nonlinear alternative\n */\nexport class LLE extends DR {\n /**\n * Locally Linear Embedding.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://doi.org/10.1126/science.290.5500.2323}\n */\n constructor(X, parameters) {\n super(\n X,\n {\n neighbors: -Infinity,\n d: 2,\n metric: euclidean,\n seed: 1212,\n eig_args: {},\n },\n parameters,\n );\n if (this._parameters.neighbors === -Infinity) {\n this.parameter(\"neighbors\", Math.min(Math.max(Math.floor(this._N / 10), 2), this._N - 1));\n }\n\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n if (!Object.hasOwn(eig_args, \"seed\")) {\n eig_args.seed = this._randomizer;\n }\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T}\n */\n transform() {\n const X = this.X;\n const rows = this._N;\n const cols = this._D;\n const neighbors = /** @type {number} */ (this.parameter(\"neighbors\"));\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n const metric = /** @type {typeof euclidean} */ (this.parameter(\"metric\"));\n const nN = k_nearest_neighbors(X, neighbors, metric);\n const O = new Matrix(neighbors, 1, 1);\n const W = new Matrix(rows, rows);\n\n for (let row = 0; row < rows; ++row) {\n const nN_row = nN[row];\n const Z = new Matrix(neighbors, cols, (i, j) => X.entry(nN_row[i].j, j) - X.entry(row, j));\n const C = Z.dotTrans(Z);\n if (neighbors > cols) {\n const C_trace = neumair_sum(C.diag()) / 1000;\n for (let j = 0; j < neighbors; ++j) {\n C.add_entry(j, j, C_trace);\n }\n }\n // reconstruct;\n let w = Matrix.solve_CG(C, O, this._randomizer);\n w = w.divide(w.sum());\n for (let j = 0; j < neighbors; ++j) {\n W.set_entry(row, nN_row[j].j, w.entry(j, 0));\n }\n }\n // comp embedding\n const I = new Matrix(rows, rows, \"identity\");\n const IW = I.sub(W);\n const M = IW.transDot(IW);\n\n // M is symmetric positive semi-definite. Smallest eigenvalue is 0 (ones vector).\n // To find smallest eigenvalues of M, we can find largest of (C*I - M)\n // Upper bound for max eigenvalue: Frobenius norm or sum of absolute values\n const C = M.mean() * rows * 2; // Safe upper bound for a sparse-ish M in LLE\n const CI_M = new Matrix(rows, rows, (i, j) => (i === j ? C : 0) - M.entry(i, j));\n\n const { eigenvectors: V } = simultaneous_poweriteration(CI_M, d + 1, eig_args);\n // Skip the first eigenvector (the ones vector corresponding to eigenvalue C)\n this.Y = Matrix.from(V.slice(1, 1 + d)).T;\n\n // return embedding\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new LLE(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new LLE(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new LLE(X, parameters);\n return dr.transform_async();\n }\n}\n","import { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { distance_matrix, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersMDS} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n\n/**\n * Classical Multidimensional Scaling (MDS)\n *\n * A linear dimensionality reduction technique that seeks to preserve the\n * pairwise distances between points as much as possible in the lower-dimensional\n * space.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link PCA} for another linear alternative\n */\nexport class MDS extends DR {\n /**\n * Classical MDS.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X, parameters = {}) {\n super(X, { d: 2, metric: euclidean, seed: 1212, eig_args: {} }, parameters);\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n if (!Object.hasOwn(eig_args, \"seed\")) {\n eig_args.seed = this._randomizer;\n }\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {T}\n */\n transform() {\n const X = this.X;\n const rows = X.shape[0];\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const metric = /** @type {typeof euclidean | \"precomputed\"} */ (this.parameter(\"metric\"));\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n const A = metric === \"precomputed\" ? X : distance_matrix(X, metric);\n\n const D_sq = new Matrix(rows, rows, (i, j) => {\n const val = A.entry(i, j);\n return val * val;\n });\n\n const ai_ = D_sq.meanCols();\n const a_j = D_sq.meanRows();\n const a__ = D_sq.mean();\n\n this._d_X = A;\n const B = new Matrix(rows, rows, (i, j) => -0.5 * (D_sq.entry(i, j) - ai_[i] - a_j[j] + a__));\n\n const { eigenvectors: V } = simultaneous_poweriteration(B, d, eig_args);\n this.Y = Matrix.from(V).transpose();\n\n return this.projection;\n }\n\n /** @returns {number} - The stress of the projection. */\n stress() {\n const N = this.X.shape[0];\n const Y = this.Y;\n const d_X = this._d_X;\n if (!d_X) throw new Error(\"First transform!\");\n\n const d_Y = new Matrix(N, N, 0);\n d_Y.shape = [\n N,\n N,\n (i, j) => {\n return i < j ? euclidean(Y.row(i), Y.row(j)) : d_Y.entry(j, i);\n },\n ];\n let top_sum = 0;\n let bottom_sum = 0;\n for (let i = 0; i < N; ++i) {\n for (let j = i + 1; j < N; ++j) {\n top_sum += (d_X.entry(i, j) - d_Y.entry(i, j)) ** 2;\n bottom_sum += d_X.entry(i, j) ** 2;\n }\n }\n return Math.sqrt(top_sum / bottom_sum);\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new MDS(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new MDS(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new MDS(X, parameters);\n return dr.transform_async();\n }\n}\n","import { KMedoids } from \"../clustering/index.js\";\nimport { BallTree } from \"../knn/index.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\nimport { MDS } from \"./MDS.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLSP} from \"./index.js\" */\n\n/**\n * Least Square Projection (LSP)\n *\n * A dimensionality reduction technique that uses a small set of control points\n * (projected with MDS) to define the projection for the rest of the data\n * using a Laplacian-based optimization.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class LSP extends DR {\n /**\n * Least Squares Projection.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n * @see {@link https://ieeexplore.ieee.org/document/4378370}\n */\n constructor(X, parameters) {\n super(\n X,\n {\n neighbors: -Infinity,\n control_points: -Infinity,\n d: 2,\n metric: euclidean,\n seed: 1212,\n },\n parameters,\n );\n if (this.parameter(\"neighbors\") === -Infinity) {\n this.parameter(\"neighbors\", Math.min(Math.max(Math.floor(this._N / 10), 2), this._N - 1));\n }\n if (this.parameter(\"control_points\") === -Infinity) {\n this.parameter(\"control_points\", Math.min(Math.ceil(Math.sqrt(this._N)), this._N - 1));\n }\n this._is_initialized = false;\n }\n\n /**\n * @returns {LSP}\n */\n //\tinit(DR = MDS, DR_parameters = {}, KNN = BallTree) {\n init() {\n const DR = MDS;\n let DR_parameters = {};\n const KNN = BallTree;\n if (this._is_initialized) return this;\n const X = this.X;\n const N = this._N;\n const K = /** @type {number} */ (this.parameter(\"neighbors\"));\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const seed = /** @type {number} */ (this.parameter(\"seed\"));\n const metric = /** @type {typeof euclidean} */ (this.parameter(\"metric\"));\n DR_parameters = Object.assign({ d, metric, seed }, DR_parameters);\n const nc = /** @type {number} */ (this.parameter(\"control_points\"));\n const control_points = new KMedoids(X, { K: nc, metric }).get_medoids();\n const C = new Matrix(nc, N, \"zeros\");\n control_points.forEach((c_i, i) => {\n C.set_entry(i, c_i, 1);\n });\n\n const control_points_matrix = Matrix.from(control_points.map((c_i) => X.row(c_i)));\n const Y_C = new DR(control_points_matrix, DR_parameters).transform();\n\n const XA = X.to2dArray();\n const knn = new KNN(XA, { metric, seed });\n const L = new Matrix(N, N, \"I\");\n const alpha = -1 / K;\n XA.forEach((x_i, i) => {\n for (const { index: j } of knn.search(x_i, K)) {\n if (i === j) continue;\n L.set_entry(i, j, alpha);\n }\n });\n const A = L.concat(C, \"vertical\");\n\n const z = new Matrix(N, d, \"zeros\");\n const b = z.concat(Y_C, \"vertical\");\n\n this._A = A;\n this._b = b;\n this._is_initialized = true;\n return this;\n }\n\n /**\n * Computes the projection.\n *\n * @returns {T} Returns the projection.\n */\n transform() {\n this.check_init();\n const A = this._A;\n const b = this._b;\n\n if (!A || !b) throw new Error(\"Call init() first!\");\n const ATA = A.transDot(A);\n const ATb = A.transDot(b);\n this.Y = Matrix.solve_CG(ATA, ATb, this._randomizer);\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new LSP(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new LSP(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new LSP(X, parameters);\n return dr.transform_async();\n }\n}\n","import { simultaneous_poweriteration } from \"../linear_algebra/index.js\";\nimport { k_nearest_neighbors, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersLTSA} from \"./index.js\" */\n/** @import {EigenArgs} from \"../linear_algebra/index.js\" */\n\n/**\n * Local Tangent Space Alignment (LTSA)\n *\n * A nonlinear dimensionality reduction algorithm that represents the local\n * geometry of the manifold by tangent spaces and then aligns them to reveal\n * the global structure.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class LTSA extends DR {\n /**\n * Local Tangent Space Alignment\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://epubs.siam.org/doi/abs/10.1137/S1064827502419154}\n */\n constructor(X, parameters) {\n super(\n X,\n {\n neighbors: -Infinity,\n d: 2,\n metric: euclidean,\n seed: 1212,\n eig_args: {},\n },\n parameters,\n );\n if (this.parameter(\"neighbors\") === -Infinity) {\n this.parameter(\"neighbors\", Math.min(Math.max(Math.floor(this._N / 10), 2), this._N - 1));\n }\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n if (!Object.hasOwn(eig_args, \"seed\")) {\n eig_args.seed = this._randomizer;\n }\n\n const d = /** @type {number} */ (this.parameter(\"d\"));\n if (this._D <= d) {\n throw new Error(\n `Dimensionality of X (D = ${this._D}) must be greater than the required dimensionality of the result (d = ${d})!`,\n );\n }\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality `d`.\n *\n * @returns {Generator} A generator yielding the intermediate steps of the projection.\n */\n *generator() {\n yield this.transform();\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimenionality `d`.\n *\n * @returns {T}\n */\n transform() {\n const X = this.X;\n const [rows, D] = X.shape;\n const neighbors = /** @type {number} */ (this.parameter(\"neighbors\"));\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const eig_args = /** @type {Partial} */ (this.parameter(\"eig_args\"));\n const metric = /** @type {typeof euclidean} */ (this.parameter(\"metric\"));\n // 1.1 determine k nearest neighbors\n const nN = k_nearest_neighbors(X, neighbors, metric);\n // center matrix\n const O = new Matrix(D, D, \"center\");\n const B = new Matrix(rows, rows, 0);\n\n for (let row = 0; row < rows; ++row) {\n // 1.2 compute the d largest eigenvectors of the correlation matrix\n const I_i = [row, ...nN[row].map((n) => n.j)];\n let X_i = Matrix.from(I_i.map((n) => X.row(n)));\n // center X_i\n X_i = X_i.dot(O);\n // correlation matrix\n const C = X_i.dotTrans(X_i);\n const { eigenvectors: g } = simultaneous_poweriteration(C, d, eig_args);\n //g.push(linspace(0, k).map(_ => 1 / Math.sqrt(k + 1)));\n const G_i_t = Matrix.from(g);\n // 2. Constructing alignment matrix\n const W_i = G_i_t.transDot(G_i_t).add(1 / Math.sqrt(neighbors + 1));\n for (let i = 0; i < neighbors + 1; ++i) {\n for (let j = 0; j < neighbors + 1; ++j) {\n B.add_entry(I_i[i], I_i[j], W_i.entry(i, j) - (i === j ? 1 : 0));\n }\n }\n }\n\n // 3. Aligning global coordinates\n const { eigenvectors: Y } = simultaneous_poweriteration(B, d + 1, eig_args);\n this.Y = Matrix.from(Y.slice(1)).transpose();\n\n // return embedding\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new LTSA(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new LTSA(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new LTSA(X, parameters);\n return dr.transform_async();\n }\n}\n","import { distance_matrix, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\nimport { MDS, PCA } from \"./index.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersPCA, ParametersMDS, ParametersSAMMON} from \"./index.js\" */\n/** @typedef {\"PCA\" | \"MDS\" | \"random\"} AvailableInit */\n\n/** @typedef {{ PCA: ParametersPCA; MDS: ParametersMDS; random: {} }} ChooseDR */\n\n/**\n * Sammon's Mapping\n *\n * A nonlinear dimensionality reduction technique that minimizes a stress\n * function based on the ratio of pairwise distances in high and low dimensional spaces.\n *\n * @class\n * @template {InputType} T\n * @extends DR>\n * @category Dimensionality Reduction\n */\nexport class SAMMON extends DR {\n /** @type {Matrix | undefined} */\n distance_matrix;\n\n /**\n * SAMMON's Mapping\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial>} [parameters] - Object containing parameterization of the DR\n * method.\n * @see {@link https://arxiv.org/pdf/2009.01512.pdf}\n */\n constructor(X, parameters) {\n super(\n X,\n {\n magic: 0.1,\n d: 2,\n metric: euclidean,\n seed: 1212,\n init_DR: \"random\",\n init_parameters: {},\n },\n parameters,\n );\n }\n\n /**\n * Initializes the projection.\n *\n * @param {Matrix | undefined} D\n * @returns {asserts D is Matrix}\n */\n init(D) {\n const N = this.X.shape[0];\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const metric = /** @type {typeof euclidean | \"precomputed\"} */ (this.parameter(\"metric\"));\n const init_DR = /** @type {AvailableInit} */ (this.parameter(\"init_DR\"));\n const DR_parameters = this.parameter(\"init_parameters\");\n if (init_DR === \"random\") {\n const randomizer = this._randomizer;\n this.Y = new Matrix(N, d, () => randomizer.random);\n } else if (init_DR === \"PCA\") {\n this.Y = Matrix.from(PCA.transform(this.X, /** @type {ParametersPCA} */ (DR_parameters)));\n } else if (init_DR === \"MDS\") {\n this.Y = Matrix.from(MDS.transform(this.X, /** @type {ParametersMDS} */ (DR_parameters)));\n } else {\n throw new Error('init_DR needs to be either \"random\" or a DR method!');\n }\n D = metric === \"precomputed\" ? Matrix.from(this.X) : distance_matrix(this.X, metric);\n this.distance_matrix = D;\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality 2.\n *\n * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200`\n * @returns {T} The projection of `X`.\n */\n transform(max_iter = 200) {\n this.check_init();\n if (!this.distance_matrix) this.init(this.distance_matrix);\n for (let j = 0; j < max_iter; ++j) {\n this._step();\n }\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimenionality 2.\n *\n * @param {number} [max_iter=200] - Maximum number of iteration steps. Default is `200`\n * @returns {Generator} A generator yielding the intermediate steps of the projection of\n * `X`.\n */\n *generator(max_iter = 200) {\n this.check_init();\n if (!this.distance_matrix) this.init(this.distance_matrix);\n\n for (let j = 0; j < max_iter; ++j) {\n this._step();\n yield this.projection;\n }\n\n return this.projection;\n }\n\n _step() {\n if (!this.distance_matrix) this.init(this.distance_matrix);\n const MAGIC = /** @type {number} */ (this.parameter(\"magic\"));\n const D = /** @type {Matrix} */ (this.distance_matrix);\n const N = this.X.shape[0];\n const d = /** @type {number} */ (this.parameter(\"d\"));\n const Y = this.Y;\n\n const G = new Matrix(N, d, 0);\n\n const sum = new Float64Array(d);\n for (let i = 0; i < N; ++i) {\n const e1 = new Float64Array(d);\n const e2 = new Float64Array(d);\n const Yi = Y.row(i);\n for (let j = 0; j < N; ++j) {\n if (i === j) continue;\n const dX = D.entry(i, j);\n if (dX === 0) continue; // Skip identical points in high-dim\n\n const Yj = Y.row(j);\n const delta = new Float64Array(d);\n for (let k = 0; k < d; ++k) {\n delta[k] = Yi[k] - Yj[k];\n }\n const dY = Math.max(euclidean(Yi, Yj), 1e-6);\n const dq = dX - dY;\n const dr = dX * dY;\n for (let k = 0; k < d; ++k) {\n e1[k] += (delta[k] * dq) / dr;\n e2[k] += (dq - (delta[k] ** 2 * (1 + dq / dY)) / dY) / dr;\n }\n }\n for (let k = 0; k < d; ++k) {\n const val = Y.entry(i, k) + ((MAGIC * e1[k]) / Math.abs(e2[k]) || 0);\n G.set_entry(i, k, val);\n sum[k] += val;\n }\n }\n for (let k = 0; k < d; ++k) {\n sum[k] /= N;\n }\n\n for (let i = 0; i < N; ++i) {\n for (let k = 0; k < d; ++k) {\n Y.set_entry(i, k, G.entry(i, k) - sum[k]);\n }\n }\n return Y;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial>} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new SAMMON(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial>} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new SAMMON(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial>} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new SAMMON(X, parameters);\n return dr.transform_async();\n }\n}\n","import { linspace, Matrix, norm } from \"../matrix/index.js\";\nimport { euclidean, euclidean_squared } from \"../metrics/index.js\";\nimport { neumair_sum } from \"../numerical/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersSQDMDS} from \"./index.js\" */\n\n/**\n * SQuadMDS (Stochastic Quartet MDS)\n *\n * A lean Stochastic Quartet MDS improving global structure preservation in\n * neighbor embedding like t-SNE and UMAP.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class SQDMDS extends DR {\n /**\n * SQuadMDS: a lean Stochastic Quartet MDS improving global structure preservation in neighbor embedding like t-SNE\n * and UMAP.\n *\n * @param {T} X\n * @param {Partial} [parameters]\n * @see {@link https://arxiv.org/pdf/2202.12087.pdf}\n */\n constructor(X, parameters) {\n super(\n X,\n {\n d: 2,\n metric: euclidean,\n seed: 1212,\n decay_start: 0.1,\n decay_cte: 0.34, // 0.34\n },\n parameters,\n );\n\n this.init();\n if (this.parameter(\"metric\") === \"precomputed\" && this.X.shape[0] !== this.X.shape[1]) {\n throw new Error(\"SQDMDS input data must be a square Matrix\");\n }\n }\n\n init() {\n const N = this._N;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n\n // initialize helpers.\n this._add = this.__add(d);\n this._sub_div = this.__sub_div(d);\n this._minus = this.__minus(d);\n this._mult = this.__mult(d);\n this._LR_init = Math.max(2, 0.005 * N);\n this._LR = this._LR_init;\n const decay_cte = /** @type {number} */ (this.parameter(\"decay_cte\"));\n this._offset = -Math.exp(-1 / decay_cte);\n this._momentums = new Matrix(N, d, 0);\n this._grads = new Matrix(N, d, 0);\n this._indices = linspace(0, N - 1);\n // initialize projection.\n const R = this._randomizer;\n this.Y = new Matrix(N, d, () => R.random - 0.5);\n\n // preparing metric for optimization.\n const this_metric = /** @type {Metric | \"precomputed\"} */ (this.parameter(\"metric\"));\n if (this_metric === \"precomputed\") {\n /** @type {(i: number, j: number, X: Matrix) => number} */\n this._HD_metric = (i, j, X) => X.entry(i, j);\n /** @type {(i: number, j: number, X: Matrix) => number} */\n this._HD_metric_exaggeration = (i, j, X) => X.entry(i, j) ** 2;\n } else {\n this._HD_metric = (i, j, X) => this_metric(X.row(i), X.row(j));\n if (this_metric === euclidean) {\n this._HD_metric_exaggeration = (i, j, X) => euclidean_squared(X.row(i), X.row(j));\n } else {\n this._HD_metric_exaggeration = (i, j, X) => this_metric(X.row(i), X.row(j)) ** 2;\n }\n }\n return;\n }\n\n /**\n * Computes the projection.\n *\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {T} The projection.\n */\n transform(iterations = 500) {\n this.check_init();\n const decay_start = /** @type {number} */ (this.parameter(\"decay_start\"));\n this._decay_start = Math.round(decay_start * iterations);\n for (let i = 0; i < iterations; ++i) {\n this._step(i, iterations);\n }\n return this.projection;\n }\n\n /**\n * Computes the projection.\n *\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {Generator} The intermediate steps of the projection.\n */\n *generator(iterations = 500) {\n this.check_init();\n const decay_start = /** @type {number} */ (this.parameter(\"decay_start\"));\n this._decay_start = Math.round(decay_start * iterations);\n for (let i = 0; i < iterations; ++i) {\n this._step(i, iterations);\n yield this.projection;\n }\n\n return this.projection;\n }\n\n /**\n * Performs an optimization step.\n *\n * @private\n * @param {number} i - Acutal iteration.\n * @param {number} iterations - Number of iterations.\n */\n _step(i, iterations) {\n if (this._LR_init === undefined || this._offset === undefined) throw new Error(\"Call init() first!\");\n\n const decay_start = /** @type {number} */ (this.parameter(\"decay_start\"));\n if (i > decay_start) {\n const decay_cte = /** @type {number} */ (this.parameter(\"decay_cte\"));\n const offset = this._offset;\n const ratio = (i - decay_start) / (iterations - decay_start);\n this._LR = this._LR_init * (Math.exp(-(ratio * ratio) / decay_cte) + offset);\n this._distance_exaggeration = false;\n } else {\n this._distance_exaggeration = true;\n }\n this._nestrov_iteration(this._distance_exaggeration);\n }\n\n /**\n * Creates quartets of non overlapping indices.\n *\n * @private\n * @returns {Uint32Array[]}\n */\n __quartets() {\n if (!this._indices) throw new Error(\"Call init() first!\");\n if (this._offset === undefined) throw new Error(\"Call init() first!\");\n const N = this._N;\n const max_N = N - (N % 4);\n const R = this._randomizer;\n const shuffled_indices = R.choice(this._indices, max_N);\n const result = [];\n for (let i = 0; i < max_N; i += 4) {\n result.push(\n Uint32Array.of(\n shuffled_indices[i],\n shuffled_indices[i + 1],\n shuffled_indices[i + 2],\n shuffled_indices[i + 3],\n ),\n );\n }\n return result;\n }\n\n /**\n * Computes and applies gradients, and updates momentum.\n *\n * @private\n * @param {boolean} distance_exaggeration\n */\n _nestrov_iteration(distance_exaggeration) {\n if (!this._momentums || !this._grads || this._LR === undefined) throw new Error(\"Call init() first!\");\n const momentums = this._momentums.mult(0.99, { inline: true });\n const LR = this._LR;\n const grads = this._fill_MDS_grads(this.Y.add(momentums), this._grads, distance_exaggeration);\n const [n, d] = momentums.shape;\n for (let i = 0; i < n; ++i) {\n const g_i = grads.row(i);\n const g_i_norm = norm(g_i);\n if (g_i_norm === 0) continue;\n const mul = LR / g_i_norm;\n const m_i = momentums.row(i);\n for (let j = 0; j < d; ++j) {\n m_i[j] -= mul * g_i[j];\n }\n } // momentums -= (LR / norm) * grads\n this.Y.add(momentums, { inline: true });\n }\n\n /**\n * Computes the gradients.\n *\n * @param {Matrix} Y - The Projection.\n * @param {Matrix} grads - The gradients.\n * @param {boolean} [exaggeration=false] - Whether or not to use early exaggeration. Default is `false`\n * @param {boolean} [zero_grad=true] - Whether or not to reset the gradient in the beginning. Default is `true`\n * @returns {Matrix} The gradients.\n */\n _fill_MDS_grads(Y, grads, exaggeration = false, zero_grad = true) {\n if (!this._HD_metric || !this._HD_metric_exaggeration || !this._add) throw new Error(\"Call init() first!\");\n if (zero_grad) {\n // compute new gradients\n grads.values.fill(0);\n }\n const add = this._add;\n const X = this.X;\n let HD_metric;\n if (exaggeration === true) {\n HD_metric = this._HD_metric_exaggeration;\n } else {\n HD_metric = this._HD_metric;\n }\n\n const D_quartet = new Float64Array(6);\n const quartets = this.__quartets();\n for (const [i, j, k, l] of quartets) {\n // compute quartet's HD distances.\n D_quartet[0] = HD_metric(i, j, X);\n D_quartet[1] = HD_metric(i, k, X);\n D_quartet[2] = HD_metric(i, l, X);\n D_quartet[3] = HD_metric(j, k, X);\n D_quartet[4] = HD_metric(j, l, X);\n D_quartet[5] = HD_metric(k, l, X);\n\n const D_quartet_sum = neumair_sum(D_quartet);\n\n if (D_quartet_sum > 0) {\n for (let i = 0; i < 6; ++i) {\n D_quartet[i] /= D_quartet_sum;\n D_quartet[i] += 1e-11;\n }\n }\n const [gi, gj, gk, gl] = this._compute_quartet_grads(Y, [i, j, k, l], D_quartet);\n\n // add is inline, row acces the matrix\n add(grads.row(i), gi);\n add(grads.row(j), gj);\n add(grads.row(k), gk);\n add(grads.row(l), gl);\n }\n return grads;\n }\n\n /**\n * Quartet gradients for a projection.\n *\n * @private\n * @param {Matrix} Y - The acutal projection.\n * @param {number[]} quartet - The indices of the quartet.\n * @param {Float64Array} D_hd - The high-dimensional distances of the quartet.\n * @returns {Float64Array[]} The gradients for the quartet.\n */\n _compute_quartet_grads(Y, quartet, [p_ab, p_ac, p_ad, p_bc, p_bd, p_cd]) {\n const [a, b, c, d] = quartet.map((index) => Y.row(index));\n // LD distances, add a small number just in case\n const d_ab = euclidean(a, b) + 1e-12;\n const d_ac = euclidean(a, c) + 1e-12;\n const d_ad = euclidean(a, d) + 1e-12;\n const d_bc = euclidean(b, c) + 1e-12;\n const d_bd = euclidean(b, d) + 1e-12;\n const d_cd = euclidean(c, d) + 1e-12;\n const sum_LD_dist = neumair_sum([d_ab, d_ac, d_ad, d_bc, d_bd, d_cd]);\n\n // for each element of the sum: use the same gradient function and just permute the points given in input.\n const [gA1, gB1, gC1, gD1] = this._ABCD_grads(\n a,\n b,\n c,\n d,\n d_ab,\n d_ac,\n d_ad,\n d_bc,\n d_bd,\n d_cd,\n p_ab,\n sum_LD_dist,\n );\n const [gA2, gC2, gB2, gD2] = this._ABCD_grads(\n a,\n c,\n b,\n d,\n d_ac,\n d_ab,\n d_ad,\n d_bc,\n d_cd,\n d_bd,\n p_ac,\n sum_LD_dist,\n );\n const [gA3, gD3, gC3, gB3] = this._ABCD_grads(\n a,\n d,\n c,\n b,\n d_ad,\n d_ac,\n d_ab,\n d_cd,\n d_bd,\n d_bc,\n p_ad,\n sum_LD_dist,\n );\n const [gB4, gC4, gA4, gD4] = this._ABCD_grads(\n b,\n c,\n a,\n d,\n d_bc,\n d_ab,\n d_bd,\n d_ac,\n d_cd,\n d_ad,\n p_bc,\n sum_LD_dist,\n );\n const [gB5, gD5, gA5, gC5] = this._ABCD_grads(\n b,\n d,\n a,\n c,\n d_bd,\n d_ab,\n d_bc,\n d_ad,\n d_cd,\n d_ac,\n p_bd,\n sum_LD_dist,\n );\n const [gC6, gD6, gA6, gB6] = this._ABCD_grads(\n c,\n d,\n a,\n b,\n d_cd,\n d_ac,\n d_bc,\n d_ad,\n d_bd,\n d_ab,\n p_cd,\n sum_LD_dist,\n );\n\n if (!this._add) throw new Error(\"Call init() first!\");\n const add = this._add;\n const gA = add(gA1, gA2, gA3, gA4, gA5, gA6);\n const gB = add(gB1, gB2, gB3, gB4, gB5, gB6);\n const gC = add(gC1, gC2, gC3, gC4, gC5, gC6);\n const gD = add(gD1, gD2, gD3, gD4, gD5, gD6);\n\n return [gA, gB, gC, gD];\n }\n\n /**\n * Gradients for one element of the loss function's sum.\n *\n * @private\n * @param {Float64Array} a\n * @param {Float64Array} b\n * @param {Float64Array} c\n * @param {Float64Array} d\n * @param {number} d_ab\n * @param {number} d_ac\n * @param {number} d_ad\n * @param {number} d_bc\n * @param {number} d_bd\n * @param {number} d_cd\n * @param {number} p_ab\n * @param {number} sum_LD_dist\n * @returns {Float64Array[]}\n */\n _ABCD_grads(a, b, c, d, d_ab, d_ac, d_ad, d_bc, d_bd, d_cd, p_ab, sum_LD_dist) {\n if (!this._minus || !this._add || !this._mult || !this._sub_div) throw new Error(\"Call init() first!\");\n const ratio = d_ab / sum_LD_dist;\n const twice_ratio = 2 * ((p_ab - ratio) / sum_LD_dist);\n const minus = this._minus;\n const add = this._add;\n const mult = this._mult;\n const sub_div = this._sub_div;\n // no side effects because sub_div creates new arrays, and the inline functions work on this new created arrays.\n const gA = mult(\n minus(mult(add(sub_div(a, b, d_ab), sub_div(a, c, d_ac), sub_div(a, d, d_ad)), ratio), sub_div(a, b, d_ab)),\n twice_ratio,\n );\n const gB = mult(\n minus(mult(add(sub_div(b, a, d_ab), sub_div(b, c, d_bc), sub_div(b, d, d_bd)), ratio), sub_div(b, a, d_ab)),\n twice_ratio,\n );\n const gC = mult(add(sub_div(c, a, d_ac), sub_div(c, b, d_bc), sub_div(c, d, d_cd)), ratio * twice_ratio);\n const gD = mult(add(sub_div(d, a, d_ad), sub_div(d, b, d_bd), sub_div(d, c, d_cd)), ratio * twice_ratio);\n return [gA, gB, gC, gD];\n }\n\n /**\n * Inline!\n *\n * @param {number} d\n */\n __minus(d) {\n return /** @type {(a: Float64Array, b: Float64Array) => Float64Array} */ (a, b) => {\n for (let i = 0; i < d; ++i) {\n a[i] -= b[i];\n }\n return a;\n };\n }\n\n /**\n * Inline!\n *\n * @param {number} d\n */\n __add(d) {\n return /** @type {(...summands: Float64Array[]) => Float64Array} */ (...summands) => {\n const n = summands.length;\n const s1 = summands[0];\n for (let j = 1; j < n; ++j) {\n const summand = summands[j];\n for (let i = 0; i < d; ++i) {\n s1[i] += summand[i];\n }\n }\n return s1;\n };\n }\n\n /**\n * Inline!\n *\n * @param {number} d\n */\n __mult(d) {\n return /** @type {(a: Float64Array, v: number) => Float64Array} */ (a, v) => {\n for (let i = 0; i < d; ++i) {\n a[i] *= v;\n }\n return a;\n };\n }\n\n /**\n * Creates a new array `(x - y) / div`.\n *\n * @param {number} d\n */\n __sub_div(d) {\n return /** @type {(x: Float64Array, y: Float64Array, div: number) => Float64Array} */ (x, y, div) => {\n return Float64Array.from({ length: d }, (_, i) => (x[i] - y[i]) / div);\n };\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new SQDMDS(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new SQDMDS(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new SQDMDS(X, parameters);\n return dr.transform_async();\n }\n}\n","import { DisjointSet } from \"../datastructure/index.js\";\nimport { Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {ParametersTopoMap} from \"./index.js\" */\n\n/**\n * TopoMap\n *\n * A 0-dimensional Homology Preserving Projection of High-Dimensional Data.\n * It aims to preserve the topological structure of the data by maintaining\n * the connectivity of a minimum spanning tree.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class TopoMap extends DR {\n /**\n * TopoMap: A 0-dimensional Homology Preserving Projection of High-Dimensional Data.\n *\n * @param {T} X - The high-dimensional data.\n * @param {Partial} parameters - Object containing parameterization of the DR method.\n * @see {@link https://arxiv.org/pdf/2009.01512.pdf}\n */\n constructor(X, parameters) {\n super(X, { metric: euclidean, seed: 1212 }, parameters);\n [this._N, this._D] = this.X.shape;\n this._distance_matrix = new Matrix(this._N, this._N, -1);\n }\n\n /**\n * @private\n * @param {number} i\n * @param {number} j\n * @param {import(\"../metrics/index.js\").Metric} metric\n * @returns {number}\n */\n __lazy_distance_matrix(i, j, metric) {\n const D = this._distance_matrix;\n const X = this.X;\n const D_ij = D.entry(i, j);\n if (D_ij === -1 && i !== j) {\n const dist = metric(X.row(i), X.row(j));\n D.set_entry(i, j, dist);\n D.set_entry(j, i, dist);\n return dist;\n }\n return i === j ? 0 : D_ij;\n }\n\n /**\n * Computes the minimum spanning tree, using a given metric\n *\n * @private\n * @param {import(\"../metrics/index.js\").Metric} metric\n * @see {@link https://en.wikipedia.org/wiki/Kruskal%27s_algorithm}\n */\n _make_minimum_spanning_tree(metric = euclidean) {\n const N = this._N;\n const X = [...this.X];\n\n this._disjoint_set = new DisjointSet(X);\n const disjoint_set = this._disjoint_set;\n const F = [];\n let E = [];\n for (let i = 0; i < N; ++i) {\n for (let j = i + 1; j < N; ++j) {\n E.push([i, j, this.__lazy_distance_matrix(i, j, metric)]);\n }\n }\n E = E.sort((a, b) => a[2] - b[2]);\n\n for (const [u, v, w] of E) {\n const set_u = disjoint_set.find(X[u]);\n const set_v = disjoint_set.find(X[v]);\n if (!set_u || !set_v) throw new Error(\"Should not happen!\");\n if (set_u !== set_v) {\n F.push([u, v, w]);\n disjoint_set.union(set_u, set_v);\n }\n }\n\n return F.sort((a, b) => a[2] - b[2]);\n }\n\n /** Initializes TopoMap. Sets all projcted points to zero, and computes a minimum spanning tree. */\n init() {\n const { metric } = this._parameters;\n this.Y = new Matrix(this._N, 2, 0);\n this._Emst = this._make_minimum_spanning_tree(metric);\n this._is_initialized = true;\n return this;\n }\n\n /**\n * Returns true if Point C is left of line AB.\n *\n * @private\n * @param {Float64Array} PointA - Point A of line AB\n * @param {Float64Array} PointB - Point B of line AB\n * @param {Float64Array} PointC - Point C\n * @returns {boolean}\n */\n __hull_cross([ax, ay], [bx, by], [sx, sy]) {\n return (bx - ax) * (sy - ay) - (by - ay) * (sx - ax) <= 0;\n }\n\n /**\n * Computes the convex hull of the set of Points S\n *\n * @private\n * @param {Float64Array[]} S - Set of Points.\n * @returns {Float64Array[]} Convex hull of S. Starts at the bottom-most point and continues counter-clockwise.\n * @see {@link https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain#JavaScript}\n */\n __hull(S) {\n const points = S.sort(([x1, y1], [x2, y2]) => y1 - y2 || x1 - x2);\n const N = points.length;\n if (N <= 2) return points;\n\n const lower = [];\n for (let i = 0; i < N; ++i) {\n while (\n lower.length >= 2 &&\n this.__hull_cross(lower[lower.length - 2], lower[lower.length - 1], points[i])\n ) {\n lower.pop();\n }\n lower.push(points[i]);\n }\n const upper = [];\n for (let i = N - 1; i >= 0; --i) {\n while (\n upper.length >= 2 &&\n this.__hull_cross(upper[upper.length - 2], upper[upper.length - 1], points[i])\n ) {\n upper.pop();\n }\n upper.push(points[i]);\n }\n upper.pop();\n lower.pop();\n return lower.concat(upper);\n }\n\n /**\n * Finds the angle to rotate Point A and B to lie on a line parallel to the x-axis.\n *\n * @private\n * @param {Float64Array} PointA\n * @param {Float64Array} PointB\n * @returns {{ sin: number; cos: number }} Object containing the sinus- and cosinus-values for a rotation.\n */\n __findAngle([p1x, p1y], [p2x, p2y]) {\n const n = euclidean([p1x, p1y], [p2x, p2y]);\n if (n === 0)\n return {\n sin: 0,\n cos: 1,\n };\n const vec = [(p2x - p1x) / n, (p2y - p1y) / n];\n const cos = vec[0];\n let sin = Math.sqrt(1 - cos * cos);\n sin = vec[1] >= 0 ? -sin : sin;\n return {\n sin: sin,\n cos: cos,\n };\n }\n\n /**\n * @private\n * @param {Float64Array[]} hull\n * @param {Float64Array} p\n * @param {boolean} topEdge\n * @returns {{ sin: number; cos: number; tx: number; ty: number }}\n */\n __align_hull(hull, p, topEdge) {\n let v = -1;\n /** @type {number} */\n let d2 = -Infinity;\n for (let i = 0; i < hull.length; ++i) {\n const d = euclidean(hull[i], p);\n if (v === -1) {\n d2 = d;\n v = i;\n } else {\n if (d2 > d) {\n d2 = d;\n v = i;\n }\n }\n }\n\n const v1 = hull[v];\n let v2;\n if (topEdge) {\n v2 = hull[(v + 1) % hull.length];\n } else {\n v2 = hull[(v - 1 + hull.length) % hull.length];\n }\n\n /** @type {{ sin?: number; cos?: number; tx: number; ty: number }} */\n const transformation = {\n tx: -v1[0],\n ty: -v1[1],\n };\n\n if (hull.length >= 2) {\n const { sin, cos } = this.__findAngle(v1, v2);\n transformation.sin = sin;\n transformation.cos = cos;\n } else {\n transformation.sin = 0;\n transformation.cos = 1;\n }\n\n return /** @type {{ sin: number; cos: number; tx: number; ty: number }} */ (transformation);\n }\n\n /**\n * @private\n * @param {Float64Array} Point - The point which should get transformed.\n * @param {{ sin: number; cos: number; tx: number; ty: number }} Transformation - Contains the values for\n * translation and rotation.\n */\n __transform([px, py], { tx, ty, sin, cos }) {\n const x = px + tx;\n const y = py + ty;\n const xx = x * cos - y * sin;\n const yy = x * sin + y * cos;\n return [xx, yy];\n }\n\n /**\n * Calls `__transform` for each point in Set C\n *\n * @private\n * @param {Float64Array[]} C - Set of points.\n * @param {{ sin: number; cos: number; tx: number; ty: number }} t - Transform object.\n * @param {number} yOffset - Value to offset set C.\n */\n __transform_component(C, t, yOffset) {\n const N = C.length;\n for (let i = 0; i < N; ++i) {\n const c = C[i];\n const [cx, cy] = this.__transform(c, t);\n c[0] = cx;\n c[1] = cy + yOffset;\n }\n }\n\n /**\n * @private\n * @param {Float64Array} root_u - Root of component u\n * @param {Float64Array} root_v - Root of component v\n * @param {Float64Array} p_u - Point u\n * @param {Float64Array} p_v - Point v\n * @param {number} w - Edge weight w\n * @param {DisjointSet} components - The disjoint set containing the components\n */\n __align_components(root_u, root_v, p_u, p_v, w, components) {\n if (!components) throw new Error(\"components not provided!\");\n const u_children = components.get_children(root_u);\n const v_children = components.get_children(root_v);\n if (!u_children || !v_children) throw new Error(\"should not happen!\");\n\n const points_u = [...u_children];\n const points_v = [...v_children];\n\n const hull_u = this.__hull(points_u);\n const hull_v = this.__hull(points_v);\n\n const t_u = this.__align_hull(hull_u, p_u, false);\n const t_v = this.__align_hull(hull_v, p_v, true);\n\n this.__transform_component(points_u, t_u, 0);\n this.__transform_component(points_v, t_v, w);\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality 2.\n *\n * @returns {T}\n */\n transform() {\n if (!this._is_initialized) this.init();\n if (!this._Emst) throw new Error(\"Call init() first!\");\n const Emst = this._Emst;\n const Y = this.Y.to2dArray();\n /** @type {DisjointSet} */\n const components = new DisjointSet(\n Y,\n // Y.map((y, i) => {\n // y.i = i;\n // return y;\n // }),\n );\n\n for (const [u, v, w] of Emst) {\n const p_u = Y[u];\n const p_v = Y[v];\n const component_u = components.find(p_u);\n const component_v = components.find(p_v);\n if (!component_u || !component_v) throw new Error(\"Should not happen!\");\n if (component_u === component_v) continue;\n this.__align_components(component_u, component_v, p_u, p_v, w, components);\n components.union(component_u, component_v);\n }\n return this.projection;\n }\n\n /**\n * Transforms the inputdata `X` to dimensionality 2.\n *\n * @returns {Generator}\n */\n *generator() {\n if (!this._is_initialized) this.init();\n if (!this._Emst) throw new Error(\"call init() first!\");\n const Emst = this._Emst;\n const Y = this.Y.to2dArray();\n const components = new DisjointSet(\n Y,\n // Y.map((y, i) => {\n // y.i = i;\n // return y;\n // }),\n );\n\n for (const [u, v, w] of Emst) {\n const p_u = Y[u];\n const p_v = Y[v];\n const component_u = components.find(p_u);\n const component_v = components.find(p_v);\n if (!component_u || !component_v) throw new Error(\"should not happen!\");\n if (component_u === component_v) continue;\n this.__align_components(component_u, component_v, p_u, p_v, w, components);\n components.union(component_u, component_v);\n yield this.projection;\n }\n return this.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new TopoMap(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new TopoMap(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} parameters\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new TopoMap(X, parameters);\n return dr.transform_async();\n }\n}\n","import { BallTree } from \"../knn/index.js\";\nimport { linspace, Matrix } from \"../matrix/index.js\";\nimport { euclidean } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\nimport { PCA } from \"./PCA.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersTriMap} from \"./index.js\" */\n/** @import {KNN} from \"../knn/KNN.js\" */\n\n/**\n * TriMap\n *\n * A dimensionality reduction technique that preserves both local and global\n * structure using triplets. It is designed to be a more robust alternative\n * to t-SNE and UMAP.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n */\nexport class TriMap extends DR {\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n * @see {@link https://arxiv.org/pdf/1910.00204v1.pdf}\n * @see {@link https://github.com/eamid/trimap}\n */\n constructor(X, parameters) {\n super(\n X,\n {\n weight_adj: 500,\n n_inliers: 10,\n n_outliers: 5,\n n_random: 5,\n d: 2,\n metric: euclidean,\n tol: 1e-8,\n seed: 1212,\n },\n parameters,\n );\n }\n\n /**\n * @param {Matrix | null} [pca=null] - Initial Embedding (if null then PCA gets used). Default is `null`\n * @param {import(\"../knn/KNN.js\").KNN | null} [knn=null] - KNN Object (if null then BallTree gets used). Default is `null`\n */\n init(pca = null, knn = null) {\n const X = this.X;\n const N = X.shape[0];\n //const c = /** @type {number} */ (this._parameters.c);\n const d = /** @type {number} */ (this._parameters.d);\n const metric = /** @type {Metric} */ (this._parameters.metric);\n const seed = /** @type {number} */ (this._parameters.seed);\n this.n_inliers = /** @type {number} */ (this._parameters.n_inliers);\n this.n_outliers = /** @type {number} */ (this._parameters.n_outliers);\n this.n_random = /** @type {number} */ (this._parameters.n_random);\n this.Y = pca ?? PCA.transform(X, { d, seed });\n this.knn = knn ?? new BallTree(X.to2dArray(), { metric, seed });\n const { triplets, weights } = this._generate_triplets(this.n_inliers, this.n_outliers, this.n_random);\n this.triplets = triplets;\n this.weights = weights;\n this.lr = (1000 * N) / triplets.shape[0];\n this.C = Infinity;\n this.vel = new Matrix(N, d, 0);\n this.gain = new Matrix(N, d, 1);\n return this;\n }\n\n /**\n * Generates {@link n_inliers} x {@link n_outliers} x {@link n_random} triplets.\n *\n * @param {number} n_inliers\n * @param {number} n_outliers\n * @param {number} n_random\n */\n _generate_triplets(n_inliers, n_outliers, n_random) {\n const metric = /** @type {Metric} */ (this._parameters.metric);\n const weight_adj = /** @type {number} */ (this._parameters.weight_adj);\n const X = this.X;\n const N = X.shape[0];\n const knn = this.knn;\n if (!knn) throw new Error(\"Call init() first!\");\n const n_extra = Math.min(n_inliers + 20, N);\n const nbrs = new Matrix(N, n_extra);\n const knn_distances = new Matrix(N, n_extra);\n for (let i = 0; i < N; ++i) {\n const results = knn\n .search(X.row(i), n_extra + 1)\n .filter((d) => d.distance !== 0)\n .sort((a, b) => a.distance - b.distance);\n\n results.forEach((d, j) => {\n if (j < n_extra) {\n nbrs.set_entry(i, j, d.index);\n knn_distances.set_entry(i, j, d.distance);\n }\n });\n }\n // scale parameter\n const sig = new Float64Array(N);\n for (let i = 0; i < N; ++i) {\n sig[i] = Math.max(\n (knn_distances.entry(i, 3) + knn_distances.entry(i, 4) + knn_distances.entry(i, 5)) / 3,\n 1e-10,\n );\n }\n\n const P = this._find_p(knn_distances, sig, nbrs);\n\n let triplets = this._sample_knn_triplets(P, nbrs, n_inliers, n_outliers);\n let n_triplets = triplets.shape[0];\n const outlier_distances = new Float64Array(n_triplets);\n for (let i = 0; i < n_triplets; ++i) {\n const j = triplets.entry(i, 0);\n const k = triplets.entry(i, 2);\n outlier_distances[i] = metric(X.row(j), X.row(k));\n }\n let weights = this._find_weights(triplets, P, nbrs, outlier_distances, sig);\n\n if (n_random > 0) {\n const { random_triplets, random_weights } = this._sample_random_triplets(X, n_random, sig);\n triplets = triplets.concat(random_triplets, \"vertical\");\n weights = Float64Array.from([...weights, ...random_weights]);\n }\n n_triplets = triplets.shape[0];\n let max_weight = -Infinity;\n for (let i = 0; i < n_triplets; ++i) {\n if (Number.isNaN(weights[i])) {\n weights[i] = 0;\n }\n if (max_weight < weights[i]) max_weight = weights[i];\n }\n let max_weight_2 = -Infinity;\n for (let i = 0; i < n_triplets; ++i) {\n weights[i] /= max_weight;\n weights[i] += 0.0001;\n weights[i] = Math.log(1 + weight_adj * weights[i]);\n if (max_weight_2 < weights[i]) max_weight_2 = weights[i];\n }\n for (let i = 0; i < n_triplets; ++i) {\n weights[i] /= max_weight_2;\n }\n return {\n triplets: triplets,\n weights: weights,\n };\n }\n\n /**\n * Calculates the similarity matrix P\n *\n * @private\n * @param {Matrix} knn_distances - Matrix of pairwise knn distances\n * @param {Float64Array} sig - Scaling factor for the distances\n * @param {Matrix} nbrs - Nearest neighbors\n * @returns {Matrix} Pairwise similarity matrix\n */\n _find_p(knn_distances, sig, nbrs) {\n const [N, n_neighbors] = knn_distances.shape;\n return new Matrix(N, n_neighbors, (i, j) => {\n return Math.exp(-(knn_distances.entry(i, j) ** 2 / sig[i] / sig[nbrs.entry(i, j)]));\n });\n }\n\n /**\n * Sample nearest neighbors triplets based on the similarity values given in P.\n *\n * @private\n * @param {Matrix} P - Matrix of pairwise similarities between each point and its neighbors given in matrix nbrs.\n * @param {Matrix} nbrs - Nearest neighbors indices for each point. The similarity values are given in matrix\n * {@link P}. Row i corresponds to the i-th point.\n * @param {number} n_inliers - Number of inlier points.\n * @param {number} n_outliers - Number of outlier points.\n */\n _sample_knn_triplets(P, nbrs, n_inliers, n_outliers) {\n const N = nbrs.shape[0];\n const triplets_list = [];\n for (let i = 0; i < N; ++i) {\n const sort_indices = this.__argsort(P.row(i));\n for (let j = 0; j < n_inliers; ++j) {\n const sim = nbrs.entry(i, sort_indices[sort_indices[j] === i ? j + 1 : j]);\n const rejects = [i, ...Array.from(sort_indices.slice(0, j + 2)).map((idx) => nbrs.entry(i, idx))];\n const samples = this._rejection_sample(n_outliers, N, rejects);\n for (let k = 0; k < samples.length; ++k) {\n const out = samples[k];\n triplets_list.push([i, sim, out]);\n }\n }\n }\n const triplets = new Matrix(triplets_list.length, 3);\n for (let t = 0; t < triplets_list.length; ++t) {\n triplets.set_entry(t, 0, triplets_list[t][0]);\n triplets.set_entry(t, 1, triplets_list[t][1]);\n triplets.set_entry(t, 2, triplets_list[t][2]);\n }\n return triplets;\n }\n\n /**\n * Should do the same as np.argsort()\n *\n * @private\n * @param {Float64Array | number[]} A\n */\n __argsort(A) {\n return linspace(0, A.length - 1).sort((i, j) => A[j] - A[i]);\n }\n\n /**\n * Samples {@link n_samples} integers from a given interval [0, {@link max_int}] while rejection the values that are\n * in the {@link rejects}.\n *\n * @private\n * @param {number} n_samples\n * @param {number} max_int\n * @param {number[]} rejects\n */\n _rejection_sample(n_samples, max_int, rejects) {\n const randomizer = this._randomizer;\n const interval = linspace(0, max_int - 1).filter((d) => rejects.indexOf(d) < 0);\n return randomizer.choice(interval, Math.min(n_samples, interval.length));\n }\n\n /**\n * Calculates the weights for the sampled nearest neighbors triplets\n *\n * @private\n * @param {Matrix} triplets - Sampled Triplets.\n * @param {Matrix} P - Pairwise similarity matrix.\n * @param {Matrix} nbrs - Nearest Neighbors\n * @param {Float64Array} outlier_distances - Matrix of pairwise outlier distances\n * @param {Float64Array} sig - Scaling factor for the distances.\n */\n _find_weights(triplets, P, nbrs, outlier_distances, sig) {\n const n_triplets = triplets.shape[0];\n const weights = new Float64Array(n_triplets);\n for (let t = 0; t < n_triplets; ++t) {\n const i = triplets.entry(t, 0);\n const sim = nbrs.row(i).indexOf(triplets.entry(t, 1));\n const p_sim = P.entry(i, sim);\n let p_out = Math.exp(-(outlier_distances[t] ** 2 / (sig[i] * sig[triplets.entry(t, 2)])));\n if (p_out < 1e-20) p_out = 1e-20;\n weights[t] = p_sim / p_out;\n }\n return weights;\n }\n\n /**\n * Sample uniformly ranom triplets\n *\n * @private\n * @param {Matrix} X - Data matrix.\n * @param {number} n_random - Number of random triplets per point\n * @param {Float64Array} sig - Scaling factor for the distances\n */\n _sample_random_triplets(X, n_random, sig) {\n const metric = /** @type {Metric} */ (this.parameter(\"metric\"));\n const randomizer = this._randomizer;\n const N = X.shape[0];\n const random_triplets = new Matrix(N * n_random, 3);\n const random_weights = new Float64Array(N * n_random);\n for (let i = 0; i < N; ++i) {\n const n_i = i * n_random;\n const indices = Array.from({ length: N }, (_, idx) => idx).filter((idx) => idx !== i);\n for (let j = 0; j < n_random; ++j) {\n let [sim, out] = randomizer.choice(indices, 2);\n let p_sim = Math.exp(-(metric(X.row(i), X.row(sim)) ** 2 / (sig[i] * sig[sim])));\n if (p_sim < 1e-20) p_sim = 1e-20;\n let p_out = Math.exp(-(metric(X.row(i), X.row(out)) ** 2 / (sig[i] * sig[out])));\n if (p_out < 1e-20) p_out = 1e-20;\n\n if (p_sim < p_out) {\n [sim, out] = [out, sim];\n [p_sim, p_out] = [p_out, p_sim];\n }\n const index = n_i + j;\n random_triplets.set_entry(index, 0, i);\n random_triplets.set_entry(index, 1, sim);\n random_triplets.set_entry(index, 2, out);\n random_weights[index] = 0.1 * (p_sim / p_out);\n }\n }\n return {\n random_triplets: random_triplets,\n random_weights: random_weights,\n };\n }\n\n /**\n * Computes the gradient for updating the embedding.\n *\n * @param {Matrix} Y - The embedding\n */\n _grad(Y) {\n const n_inliers = this.n_inliers;\n const n_outliers = this.n_outliers;\n const triplets = this.triplets;\n const weights = this.weights;\n if (!triplets || n_inliers === undefined || n_outliers === undefined || !weights)\n throw new Error(\"Call init() first!\");\n const [N, dim] = Y.shape;\n const n_triplets = triplets.shape[0];\n const grad = new Matrix(N, dim, 0);\n const y_ij = new Float64Array(dim);\n const y_ik = new Float64Array(dim);\n let d_ij = 1;\n let d_ik = 1;\n let n_viol = 0;\n let loss = 0;\n const n_knn_triplets = N * n_inliers * n_outliers;\n\n for (let t = 0; t < n_triplets; ++t) {\n const [i, j, k] = triplets.row(t);\n // update y_ij, y_ik, d_ij, d_ik\n if (t % n_outliers === 0 || t >= n_knn_triplets) {\n d_ij = 1;\n d_ik = 1;\n for (let d = 0; d < dim; ++d) {\n const Y_id = Y.entry(i, d);\n const Y_jd = Y.entry(j, d);\n const Y_kd = Y.entry(k, d);\n y_ij[d] = Y_id - Y_jd;\n y_ik[d] = Y_id - Y_kd;\n d_ij += y_ij[d] ** 2;\n d_ik += y_ik[d] ** 2;\n }\n // update y_ik and d_ik only\n } else {\n d_ik = 1;\n for (let d = 0; d < dim; ++d) {\n const Y_id = Y.entry(i, d);\n const Y_kd = Y.entry(k, d);\n y_ik[d] = Y_id - Y_kd;\n d_ik += y_ik[d] ** 2;\n }\n }\n\n if (d_ij > d_ik) ++n_viol;\n loss += weights[t] / (1 + d_ik / d_ij);\n const w = weights[t] / (d_ij + d_ik) ** 2;\n for (let d = 0; d < dim; ++d) {\n const gs = y_ij[d] * d_ik * w;\n const go = y_ik[d] * d_ij * w;\n grad.add_entry(i, d, gs - go);\n grad.sub_entry(j, d, gs);\n grad.add_entry(k, d, go);\n }\n }\n return { grad, loss, n_viol };\n }\n\n /**\n * @param {number} max_iteration\n * @returns {T}\n */\n transform(max_iteration = 800) {\n this.check_init();\n for (let iter = 0; iter < max_iteration; ++iter) {\n this._next(iter);\n }\n return this.projection;\n }\n\n /**\n * @param {number} max_iteration\n * @returns {Generator}\n */\n *generator(max_iteration = 800) {\n this.check_init();\n for (let iter = 0; iter < max_iteration; ++iter) {\n this._next(iter);\n yield this.projection;\n }\n return this.projection;\n }\n\n /**\n * Does the iteration step.\n *\n * @private\n * @param {number} iter\n */\n _next(iter) {\n const gamma = iter > 250 ? 0.5 : 0.3;\n const old_C = this.C;\n const vel = this.vel;\n if (!vel || old_C === undefined || this.lr === undefined) throw new Error(\"Call init() first!\");\n const Y = this.Y.add(vel.mult(gamma));\n const { grad, loss } = this._grad(Y);\n this.C = loss;\n this.Y = this._update_embedding(Y, iter, grad);\n const tol = /** @type {number} */ (this.parameter(\"tol\"));\n this.lr *= old_C > loss + tol ? 1.01 : 0.9;\n return this.Y;\n }\n\n /**\n * Updates the embedding.\n *\n * @private\n * @param {Matrix} Y\n * @param {number} iter\n * @param {Matrix} grad\n */\n _update_embedding(Y, iter, grad) {\n const [N, dim] = Y.shape;\n const gamma = iter > 250 ? 0.8 : 0.5; // moment parameter\n const min_gain = 0.01;\n const gain = this.gain;\n const vel = this.vel;\n const lr = this.lr;\n if (!vel || !gain || lr === undefined) throw new Error(\"Call init() first!\");\n for (let i = 0; i < N; ++i) {\n for (let d = 0; d < dim; ++d) {\n const new_gain =\n Math.sign(vel.entry(i, d)) !== Math.sign(grad.entry(i, d))\n ? gain.entry(i, d) + 0.2\n : Math.max(gain.entry(i, d) * 0.8, min_gain);\n gain.set_entry(i, d, new_gain);\n vel.set_entry(i, d, gamma * vel.entry(i, d) - lr * gain.entry(i, d) * grad.entry(i, d));\n Y.set_entry(i, d, Y.entry(i, d) + vel.entry(i, d));\n }\n }\n return Y;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new TriMap(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new TriMap(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new TriMap(X, parameters);\n return dr.transform_async();\n }\n}\n","import { Matrix } from \"../matrix/index.js\";\nimport { euclidean_squared } from \"../metrics/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersTSNE} from \"./index.js\" */\n/**\n * t-SNE (t-Distributed Stochastic Neighbor Embedding)\n *\n * A nonlinear dimensionality reduction technique particularly well-suited\n * for visualizing high-dimensional data in 2D or 3D. Preserves local\n * structure while revealing global patterns.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link https://lvdmaaten.github.io/tsne/|t-SNE Paper}\n * @see {@link UMAP} for faster alternative with similar results\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];\n * const tsne = new druid.TSNE(X, {\n * perplexity: 30,\n * epsilon: 10,\n * d: 2,\n * seed: 42\n * });\n *\n * const Y = tsne.transform(500); // 500 iterations\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class TSNE extends DR {\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X, parameters) {\n super(\n X,\n {\n perplexity: 50,\n epsilon: 10,\n d: 2,\n metric: euclidean_squared,\n seed: 1212,\n },\n parameters,\n );\n [this._N, this._D] = this.X.shape;\n this._iter = 0;\n const d = /** @type {number} */ (this.parameter(\"d\"));\n this.Y = new Matrix(this._N, d, () => this._randomizer.gauss_random() * 1e-4);\n }\n\n init() {\n // init\n const perplexity = /** @type {number} */ (this.parameter(\"perplexity\"));\n const Htarget = Math.log(perplexity);\n const N = this._N;\n const D = this._D;\n const metric = /** @type {Metric | \"precomputed\"} */ (this._parameters.metric);\n const X = this.X;\n let Delta;\n if (metric === \"precomputed\") {\n Delta = Matrix.from(X);\n } else {\n Delta = new Matrix(N, N);\n for (let i = 0; i < N; ++i) {\n const X_i = X.row(i);\n for (let j = i + 1; j < N; ++j) {\n const distance = metric(X_i, X.row(j));\n Delta.set_entry(i, j, distance);\n Delta.set_entry(j, i, distance);\n }\n }\n }\n\n const P = new Matrix(N, N, 0);\n\n this._ystep = new Matrix(N, D, 0);\n this._gains = new Matrix(N, D, 1);\n\n // search for fitting sigma\n const tol = 1e-4;\n const maxtries = 50;\n for (let i = 0; i < N; ++i) {\n const dist_i = Delta.row(i);\n const prow = P.row(i);\n let betamin = -Infinity;\n let betamax = Infinity;\n let beta = 1;\n let cnt = maxtries;\n let done = false;\n let psum = 0;\n\n while (!done && cnt--) {\n // compute entropy and kernel row with beta precision\n psum = 0;\n let dp_sum = 0;\n for (let j = 0; j < N; ++j) {\n const dist = dist_i[j];\n const pj = i !== j ? Math.exp(-dist * beta) : 0;\n dp_sum += dist * pj;\n prow[j] = pj;\n psum += pj;\n }\n // compute entropy\n const H = psum > 0 ? Math.log(psum) + (beta * dp_sum) / psum : 0;\n if (H > Htarget) {\n betamin = beta;\n beta = betamax === Infinity ? beta * 2 : (beta + betamax) / 2;\n } else {\n betamax = beta;\n beta = betamin === -Infinity ? beta / 2 : (beta + betamin) / 2;\n }\n done = Math.abs(H - Htarget) < tol;\n }\n // normalize p\n for (let j = 0; j < N; ++j) {\n prow[j] /= psum;\n }\n }\n\n // compute probabilities\n const N2 = N * 2;\n for (let i = 0; i < N; ++i) {\n for (let j = i; j < N; ++j) {\n const p = Math.max((P.entry(i, j) + P.entry(j, i)) / N2, 1e-100);\n P.set_entry(i, j, p);\n P.set_entry(j, i, p);\n }\n }\n this._P = P;\n return this;\n }\n\n /**\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {T} The projection.\n */\n transform(iterations = 500) {\n this.check_init();\n for (let i = 0; i < iterations; ++i) {\n this.next();\n }\n return this.projection;\n }\n\n /**\n * @param {number} [iterations=500] - Number of iterations. Default is `500`\n * @returns {Generator} - The projection.\n */\n *generator(iterations = 500) {\n this.check_init();\n for (let i = 0; i < iterations; ++i) {\n this.next();\n yield this.projection;\n }\n return this.projection;\n }\n\n /**\n * Performs a optimization step\n *\n * @private\n * @returns {Matrix}\n */\n next() {\n const iter = ++this._iter;\n if (!this._P || !this._ystep || !this._gains) throw new Error(\"Call init() first!\");\n const P = this._P;\n const ystep = this._ystep;\n const gains = this._gains;\n const N = this._N;\n const dim = /** @type {number} */ (this._parameters.d);\n const epsilon = /** @type {number} */ (this._parameters.epsilon);\n const Y = this.Y;\n\n //calc cost gradient;\n const pmul = iter < 100 ? 4 : 1;\n\n // compute Q dist (unnormalized)\n const Qu = new Matrix(N, N, \"zeros\");\n let qsum = 0;\n for (let i = 0; i < N; ++i) {\n for (let j = i + 1; j < N; ++j) {\n let dsum = 0;\n for (let d = 0; d < dim; ++d) {\n const dhere = Y.entry(i, d) - Y.entry(j, d);\n dsum += dhere * dhere;\n }\n const qu = 1 / (1 + dsum);\n Qu.set_entry(i, j, qu);\n Qu.set_entry(j, i, qu);\n qsum += 2 * qu;\n }\n }\n\n // normalize Q dist\n const Q = new Matrix(N, N, 0);\n for (let i = 0; i < N; ++i) {\n for (let j = i + 1; j < N; ++j) {\n const val = Math.max(Qu.entry(i, j) / qsum, 1e-100);\n Q.set_entry(i, j, val);\n Q.set_entry(j, i, val);\n }\n }\n\n const grad = new Matrix(N, dim, \"zeros\");\n for (let i = 0; i < N; ++i) {\n for (let j = 0; j < N; ++j) {\n const premult = 4 * (pmul * P.entry(i, j) - Q.entry(i, j)) * Qu.entry(i, j);\n for (let d = 0; d < dim; ++d) {\n grad.add_entry(i, d, premult * (Y.entry(i, d) - Y.entry(j, d)));\n }\n }\n }\n\n // perform gradient step\n const ymean = new Float64Array(dim);\n for (let i = 0; i < N; ++i) {\n for (let d = 0; d < dim; ++d) {\n const gid = grad.entry(i, d);\n const sid = ystep.entry(i, d);\n const gainid = gains.entry(i, d);\n\n let newgain = Math.sign(gid) === Math.sign(sid) ? gainid * 0.8 : gainid + 0.2;\n if (newgain < 0.01) newgain = 0.01;\n gains.set_entry(i, d, newgain);\n\n const momval = iter < 250 ? 0.5 : 0.8;\n const newsid = momval * sid - epsilon * newgain * gid;\n ystep.set_entry(i, d, newsid);\n\n Y.add_entry(i, d, newsid);\n ymean[d] += Y.entry(i, d);\n }\n }\n\n for (let i = 0; i < N; ++i) {\n for (let d = 0; d < dim; ++d) {\n Y.sub_entry(i, d, ymean[d] / N);\n }\n }\n\n return this.Y;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new TSNE(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new TSNE(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new TSNE(X, parameters);\n return dr.transform_async();\n }\n}\n","/**\n * @template {Float64Array | number[]} T\n * @category Optimization\n * @param {(d: T) => number} f\n * @param {T} x0\n * @param {number} [max_iter=300] Default is `300`\n * @returns {T}\n * @see http://optimization-js.github.io/optimization-js/optimization.js.html#line438\n */\nexport function powell(f, x0, max_iter = 300) {\n const epsilon = 1e-2;\n const n = x0.length;\n let alpha = 1e-3;\n let pfx = 10000;\n const x = /** @type {T} */ (x0.slice());\n let fx = f(x);\n let convergence = false;\n\n while (max_iter-- >= 0 && !convergence) {\n convergence = true;\n for (let i = 0; i < n; ++i) {\n x[i] += 1e-6;\n const fxi = f(x);\n x[i] -= 1e-6;\n const dx = (fxi - fx) / 1e-6;\n if (Math.abs(dx) > epsilon) {\n convergence = false;\n }\n x[i] -= alpha * dx;\n fx = f(x);\n }\n alpha *= pfx >= fx ? 1.05 : 0.4;\n pfx = fx;\n }\n return x;\n}\n","import { BallTree, NaiveKNN } from \"../knn/index.js\";\nimport { linspace, Matrix } from \"../matrix/index.js\";\nimport { euclidean, euclidean_squared } from \"../metrics/index.js\";\nimport { neumair_sum } from \"../numerical/index.js\";\nimport { powell } from \"../optimization/index.js\";\nimport { max } from \"../util/index.js\";\nimport { DR } from \"./DR.js\";\n\n/** @import {InputType} from \"../index.js\" */\n/** @import {Metric} from \"../metrics/index.js\" */\n/** @import {ParametersUMAP} from \"./index.js\" */\n\n/**\n * Uniform Manifold Approximation and Projection (UMAP)\n *\n * A novel manifold learning technique for dimensionality reduction. UMAP is constructed\n * from a theoretical framework based on Riemannian geometry and algebraic topology.\n * It is often faster than t-SNE while preserving more of the global structure.\n *\n * @class\n * @template {InputType} T\n * @extends DR\n * @category Dimensionality Reduction\n * @see {@link https://arxiv.org/abs/1802.03426|UMAP Paper}\n * @see {@link TSNE} for a similar visualization technique\n *\n * @example\n * import * as druid from \"@saehrimnir/druidjs\";\n *\n * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];\n * const umap = new druid.UMAP(X, {\n * n_neighbors: 15,\n * min_dist: 0.1,\n * d: 2,\n * seed: 42\n * });\n *\n * const Y = umap.transform(500); // 500 iterations\n * // [[x1, y1], [x2, y2], [x3, y3]]\n */\nexport class UMAP extends DR {\n /**\n * @param {T} X - The high-dimensional data.\n * @param {Partial} [parameters] - Object containing parameterization of the DR method.\n */\n constructor(X, parameters) {\n super(\n X,\n {\n n_neighbors: 15,\n local_connectivity: 1,\n min_dist: 1,\n d: 2,\n metric: euclidean,\n seed: 1212,\n _spread: 1,\n _set_op_mix_ratio: 1,\n _repulsion_strength: 1,\n _negative_sample_rate: 5,\n _n_epochs: 350,\n _initial_alpha: 1,\n },\n parameters,\n );\n [this._N, this._D] = this.X.shape;\n const n_neighbors = /** @type {number} */ (this.parameter(\"n_neighbors\"));\n const local_connectivity = /** @type {number} */ (this.parameter(\"local_connectivity\"));\n const d = /** @type {number} */ (this.parameter(\"d\"));\n /* let n_neighbors = Math.min(this._N - 1, parameters.n_neighbors);\n this.parameter(\"n_neighbors\", n_neighbors);\n this.parameter(\"local_connectivity\", Math.min(this.parameter(\"local_connectivity\"), n_neighbors - 1)); */\n if (n_neighbors > this._N) {\n throw new Error(\n `Parameter n_neighbors (=${n_neighbors}) needs to be smaller than dataset size (N=${this._N})!`,\n );\n }\n if (local_connectivity > n_neighbors) {\n throw new Error(\n `Parameter local_connectivity (=${local_connectivity}) needs to be smaller than parameter n_neighbors (=${n_neighbors})`,\n );\n }\n this._iter = 0;\n const randomizer = this._randomizer;\n this.Y = new Matrix(this._N, d, () => randomizer.random);\n }\n\n /**\n * @private\n * @param {number} spread\n * @param {number} min_dist\n * @returns {number[]}\n */\n _find_ab_params(spread, min_dist) {\n /** @type {(x: number, a: number, b: number) => number} */\n const curve = (x, a, b) => 1 / (1 + a * x ** (2 * b));\n const xv = linspace(0, spread * 3, 300);\n const yv = linspace(0, spread * 3, 300);\n\n for (let i = 0, n = xv.length; i < n; ++i) {\n const xv_i = xv[i];\n yv[i] = xv_i < min_dist ? 1 : Math.exp(-(xv_i - min_dist) / spread);\n }\n\n /** @type {(p: [number, number]) => number} */\n const err = (p) => {\n const error = linspace(1, 300).map((_, i) => yv[i] - curve(xv[i], p[0], p[1]));\n return Math.sqrt(neumair_sum(error.map((e) => e * e)));\n };\n\n return powell(err, [1, 1]);\n }\n\n /**\n * @private\n * @param {{ element: Float64Array; index: number; distance: number }[][]} distances\n * @param {number[]} sigmas\n * @param {number[]} rhos\n * @returns {{ element: Float64Array; index: number; distance: number }[][]}\n */\n _compute_membership_strengths(distances, sigmas, rhos) {\n for (let i = 0, n = distances.length; i < n; ++i) {\n const rho = rhos[i];\n const curr_dist = distances[i];\n for (let j = 0, m = curr_dist.length; j < m; ++j) {\n const v = curr_dist[j].distance - rho;\n curr_dist[j].distance = v > 0 ? Math.exp(-v / sigmas[i]) : 1.0;\n }\n }\n return distances;\n }\n\n /**\n * @private\n * @param {NaiveKNN | BallTree} knn\n * @param {number} k\n * @returns {{\n * distances: { element: Float64Array; index: number; distance: number }[][];\n * sigmas: number[];\n * rhos: number[];\n * }}\n */\n _smooth_knn_dist(knn, k) {\n const SMOOTH_K_TOLERANCE = 1e-5;\n const MIN_K_DIST_SCALE = 1e-3;\n const n_iter = 64;\n const local_connectivity = /** @type {number} */ (this._parameters.local_connectivity);\n const metric = /** @type {Metric | \"precomputed\"} */ (this._parameters.metric);\n const target = Math.log2(k);\n const rhos = [];\n const sigmas = [];\n const X = this.X;\n const N = X.shape[0];\n //const distances = [...X].map(x_i => knn.search(x_i, k).raw_data().reverse());\n\n /** @type {{ element: Float64Array; index: number; distance: number }[][]} */\n const distances = [];\n if (metric === \"precomputed\" || knn instanceof NaiveKNN) {\n for (let i = 0; i < N; ++i) {\n distances.push(knn.search_by_index(i, k).reverse());\n }\n } else {\n for (const x_i of X) {\n distances.push(knn.search(x_i, k).reverse());\n }\n }\n\n const index = Math.floor(local_connectivity);\n const interpolation = local_connectivity - index;\n for (let i = 0; i < N; ++i) {\n let lo = 0;\n let hi = Infinity;\n let mid = 1;\n let rho = 0;\n\n const search_result = distances[i];\n const non_zero_dist = search_result.filter((d) => d.distance > 0);\n const non_zero_dist_length = non_zero_dist.length;\n if (non_zero_dist_length >= local_connectivity) {\n if (index > 0) {\n rho = non_zero_dist[index - 1].distance;\n if (interpolation > SMOOTH_K_TOLERANCE) {\n rho += interpolation * (non_zero_dist[index].distance - non_zero_dist[index - 1].distance);\n }\n } else {\n rho = interpolation * non_zero_dist[0].distance;\n }\n } else if (non_zero_dist_length > 0) {\n rho = non_zero_dist[non_zero_dist_length - 1].distance;\n }\n for (let x = 0; x < n_iter; ++x) {\n let psum = 0;\n for (let j = 0; j < k; ++j) {\n const d = search_result[j].distance - rho;\n psum += d > 0 ? Math.exp(-(d / mid)) : 1;\n }\n if (Math.abs(psum - target) < SMOOTH_K_TOLERANCE) {\n break;\n }\n if (psum > target) {\n [hi, mid] = [mid, (lo + hi) / 2];\n } else {\n if (hi === Infinity) {\n [lo, mid] = [mid, mid * 2];\n } else {\n [lo, mid] = [mid, (lo + hi) / 2];\n }\n }\n }\n\n //let mean_d = null;\n if (rho > 0) {\n const mean_ithd = search_result.reduce((a, b) => a + b.distance, 0) / search_result.length;\n if (mid < MIN_K_DIST_SCALE * mean_ithd) {\n mid = MIN_K_DIST_SCALE * mean_ithd;\n }\n } else {\n const mean_d = distances.reduce(\n (acc, res) => acc + res.reduce((a, b) => a + b.distance, 0) / res.length,\n 0,\n );\n if (mid < MIN_K_DIST_SCALE * mean_d) {\n mid = MIN_K_DIST_SCALE * mean_d;\n }\n }\n rhos[i] = rho;\n sigmas[i] = mid;\n }\n return {\n distances: distances,\n sigmas: sigmas,\n rhos: rhos,\n };\n }\n\n /**\n * @private\n * @param {Matrix} X\n * @param {number} n_neighbors\n * @returns {Matrix}\n */\n _fuzzy_simplicial_set(X, n_neighbors) {\n const N = X.shape[0];\n const metric = /** @type {Metric | \"precomputed\"} */ (this._parameters.metric);\n const _set_op_mix_ratio = /** @type {number} */ (this._parameters._set_op_mix_ratio);\n\n const knn =\n metric === \"precomputed\"\n ? new NaiveKNN(X.to2dArray(), {\n metric: \"precomputed\",\n seed: /** @type {number} */ (this._parameters.seed),\n })\n : new BallTree(X.to2dArray(), {\n metric,\n seed: /** @type {number} */ (this._parameters.seed),\n });\n let { distances, sigmas, rhos } = this._smooth_knn_dist(knn, n_neighbors);\n distances = this._compute_membership_strengths(distances, sigmas, rhos);\n const result = new Matrix(N, N, \"zeros\");\n for (let i = 0; i < N; ++i) {\n const distances_i = distances[i];\n for (let j = 0; j < distances_i.length; ++j) {\n result.set_entry(i, distances_i[j].index, distances_i[j].distance);\n }\n }\n\n const transposed_result = result.T;\n const prod_matrix = result.mult(transposed_result);\n return result\n .add(transposed_result)\n .sub(prod_matrix)\n .mult(_set_op_mix_ratio)\n .add(prod_matrix.mult(1 - _set_op_mix_ratio));\n }\n\n /**\n * @private\n * @param {number} n_epochs\n * @returns {Float32Array}\n */\n _make_epochs_per_sample(n_epochs) {\n if (!this._weights) throw new Error(\"Call init() first!\");\n const weights = this._weights;\n const result = new Float32Array(weights.length).fill(-1);\n const weight_scl = n_epochs / max(weights);\n weights.forEach((w, i) => {\n const sample = w * weight_scl;\n if (sample > 0) result[i] = Math.round(n_epochs / sample);\n });\n return result;\n }\n\n /**\n * @private\n * @param {Matrix} graph\n * @returns {{ rows: number[]; cols: number[]; data: number[] }}\n */\n _tocoo(graph) {\n const rows = [];\n const cols = [];\n const data = [];\n const [rows_n, cols_n] = graph.shape;\n for (let row = 0; row < rows_n; ++row) {\n for (let col = 0; col < cols_n; ++col) {\n const entry = graph.entry(row, col);\n if (entry !== 0) {\n rows.push(row);\n cols.push(col);\n data.push(entry);\n }\n }\n }\n return {\n rows: rows,\n cols: cols,\n data: data,\n };\n }\n\n /**\n * Computes all necessary\n *\n * @returns {UMAP}\n */\n init() {\n const _spread = /** @type {number} */ (this._parameters._spread);\n const min_dist = /** @type {number} */ (this._parameters.min_dist);\n const n_neighbors = /** @type {number} */ (this._parameters.n_neighbors);\n const _n_epochs = /** @type {number} */ (this._parameters._n_epochs);\n const _negative_sample_rate = /** @type {number} */ (this._parameters._negative_sample_rate);\n const [a, b] = this._find_ab_params(_spread, min_dist);\n this._a = a;\n this._b = b;\n this._graph = this._fuzzy_simplicial_set(this.X, n_neighbors);\n const { rows, cols, data: weights } = this._tocoo(this._graph);\n this._head = rows;\n this._tail = cols;\n this._weights = weights;\n this._epochs_per_sample = this._make_epochs_per_sample(_n_epochs);\n this._epochs_per_negative_sample = this._epochs_per_sample.map((d) => d * _negative_sample_rate);\n this._epoch_of_next_sample = this._epochs_per_sample.slice();\n this._epoch_of_next_negative_sample = this._epochs_per_negative_sample.slice();\n return this;\n }\n\n graph() {\n this.check_init();\n return { cols: this._head, rows: this._tail, weights: this._weights };\n }\n\n /**\n * @param {number} [iterations=350] - Number of iterations. Default is `350`\n * @returns {T}\n */\n transform(iterations = 350) {\n if (this.parameter(\"_n_epochs\") !== iterations) {\n this.parameter(\"_n_epochs\", iterations);\n this.init();\n }\n this.check_init();\n for (let i = 0; i < iterations; ++i) {\n this.next();\n }\n return this.projection;\n }\n\n /**\n * @param {number} [iterations=350] - Number of iterations. Default is `350`\n * @returns {Generator}\n */\n *generator(iterations = 350) {\n if (this.parameter(\"_n_epochs\") !== iterations) {\n this.parameter(\"_n_epochs\", iterations);\n this.init();\n }\n this.check_init();\n for (let i = 0; i < iterations; ++i) {\n this.next();\n yield this.projection;\n }\n return this.projection;\n }\n\n /**\n * @private\n * @param {number} x\n * @returns {number}\n */\n _clip(x) {\n if (x > 4) return 4;\n if (x < -4) return -4;\n return x;\n }\n\n /**\n * Performs the optimization step.\n *\n * @private\n * @param {Matrix} head_embedding\n * @param {Matrix} tail_embedding\n * @param {number[]} head\n * @param {number[]} tail\n * @returns {Matrix}\n */\n _optimize_layout(head_embedding, tail_embedding, head, tail) {\n const randomizer = this._randomizer;\n const _repulsion_strength = /** @type {number} */ (this.parameter(\"_repulsion_strength\"));\n const dim = /** @type {number} */ (this.parameter(\"d\"));\n const {\n _alpha: alpha,\n _a: a,\n _b: b,\n _epochs_per_sample: epochs_per_sample,\n _epochs_per_negative_sample: epochs_per_negative_sample,\n _epoch_of_next_negative_sample: epoch_of_next_negative_sample,\n _epoch_of_next_sample: epoch_of_next_sample,\n _clip: clip,\n } = this;\n if (\n alpha === undefined ||\n a === undefined ||\n b === undefined ||\n epochs_per_sample === undefined ||\n epochs_per_negative_sample === undefined ||\n epoch_of_next_negative_sample === undefined ||\n epoch_of_next_sample === undefined ||\n clip === undefined\n ) {\n throw new Error(\"call init() first!\");\n }\n const tail_length = tail.length;\n\n for (let i = 0, n = epochs_per_sample.length; i < n; ++i) {\n if (epoch_of_next_sample[i] <= this._iter) {\n const j = head[i];\n const k = tail[i];\n const current = head_embedding.row(j);\n const other = tail_embedding.row(k);\n const dist = euclidean_squared(current, other);\n if (dist > 0) {\n const grad_coeff = (-2 * a * b * dist ** (b - 1)) / (a * dist ** b + 1);\n for (let d = 0; d < dim; ++d) {\n const grad_d = clip(grad_coeff * (current[d] - other[d])) * alpha;\n current[d] += grad_d;\n other[d] -= grad_d;\n }\n }\n epoch_of_next_sample[i] += epochs_per_sample[i];\n const n_neg_samples = (this._iter - epoch_of_next_negative_sample[i]) / epochs_per_negative_sample[i];\n for (let p = 0; p < n_neg_samples; ++p) {\n const k = randomizer.random_int % tail_length;\n const other = tail_embedding.row(tail[k]);\n const dist = euclidean_squared(current, other);\n if (dist > 0) {\n const grad_coeff = (2 * _repulsion_strength * b) / ((0.01 + dist) * (a * dist ** b + 1));\n for (let d = 0; d < dim; ++d) {\n const grad_d = clip(grad_coeff * (current[d] - other[d])) * alpha;\n current[d] += grad_d;\n other[d] -= grad_d;\n }\n } else if (j === k) {\n }\n }\n epoch_of_next_negative_sample[i] += n_neg_samples * epochs_per_negative_sample[i];\n }\n }\n return head_embedding;\n }\n\n /**\n * @private\n * @returns {Matrix}\n */\n next() {\n if (!this._head || !this._tail) throw new Error(\"Call init() first!\");\n const iter = ++this._iter;\n const Y = this.Y;\n const _initial_alpha = /** @type {number} */ (this._parameters._initial_alpha);\n const _n_epochs = /** @type {number} */ (this._parameters._n_epochs);\n this._alpha = _initial_alpha * (1 - iter / _n_epochs);\n this.Y = this._optimize_layout(Y, Y, this._head, this._tail);\n\n return this.Y;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {T}\n */\n static transform(X, parameters) {\n const dr = new UMAP(X, parameters);\n return dr.transform();\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Generator}\n */\n static *generator(X, parameters) {\n const dr = new UMAP(X, parameters);\n yield* dr.generator();\n return dr.projection;\n }\n\n /**\n * @template {InputType} T\n * @param {T} X\n * @param {Partial} [parameters]\n * @returns {Promise}\n */\n static async transform_async(X, parameters) {\n const dr = new UMAP(X, parameters);\n return dr.transform_async();\n }\n}\n","import pkg from \"../package.json\" with { type: \"json\" };\n\nconst version = pkg.version;\nexport { version };\n\n/** @import {Matrix} from \"./matrix/index.js\" */\n/** @typedef {Matrix | Float64Array[] | number[][]} InputType*/\n\n//export { version } from \"../package.json\" with { type: \"json\" };\nexport * from \"./clustering/index.js\";\nexport * from \"./datastructure/index.js\";\nexport * from \"./dimred/index.js\";\nexport * from \"./knn/index.js\";\nexport * from \"./linear_algebra/index.js\";\nexport * from \"./matrix/index.js\";\nexport * from \"./metrics/index.js\";\nexport * from \"./numerical/index.js\";\nexport * from \"./optimization/index.js\";\nexport * from \"./util/index.js\";\n"],"names":["qr","qr_gramschmidt"],"mappings":"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"} \ No newline at end of file diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 56c50ef..7c52955 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -100,6 +100,14 @@ export default defineConfig({ text: "UMAP", link: "/dimred/umap", }, + { + text: "PaCMAP", + link: "/dimred/pacmap", + }, + { + text: "LocalMAP", + link: "/dimred/localmap", + }, ], }, { diff --git a/docs/dimred/localmap.md b/docs/dimred/localmap.md new file mode 100644 index 0000000..5157834 --- /dev/null +++ b/docs/dimred/localmap.md @@ -0,0 +1,48 @@ + + +# LocalMAP + +LocalMAP is a variant of PaCMAP that improves local cluster separation by dynamically resampling further pairs (FP) in the third optimization phase using nearby points in the current low-dimensional embedding, rather than random non-neighbors. + +## How It Works + +LocalMAP runs identically to PaCMAP for the first two phases. In phase 3, instead of fixed random further pairs, it rebuilds the FP pairs from embedding-space neighbors and applies a distance-based weight scaling (`low_dist_thres / (2 × √d_ij)`) for pairs that are close in the current embedding. This pushes nearby clusters apart more aggressively, sharpening local boundaries. + +## Why or When to Use + +Use LocalMAP when PaCMAP produces clusters that are still somewhat merged or when fine-grained local separation is important. It adds negligible overhead over PaCMAP and generally produces crisper cluster boundaries. + +## Example + + + +## How-to (Code) + +```javascript +import * as druid from "@saehrimnir/druidjs"; + +const data = [ + /* ... multi-dimensional data ... */ +]; + +// 1. Initialize the algorithm +const localmap = new druid.LocalMAP(data, { + n_neighbors: 10, + low_dist_thres: 10 // distance threshold for local FP resampling in phase 3 +}); + +// 2. Compute the projection (450 iterations across 3 phases by default) +const projection = localmap.transform(); + +// Alternatively, use a generator for animation: +// for (const proj of localmap.generator()) { ... } +``` diff --git a/docs/dimred/pacmap.md b/docs/dimred/pacmap.md new file mode 100644 index 0000000..b47e456 --- /dev/null +++ b/docs/dimred/pacmap.md @@ -0,0 +1,45 @@ + + +# PaCMAP + +Pairwise Controlled Manifold Approximation Projection (PaCMAP) is a dimensionality reduction technique that uses three explicit types of point pairs — nearest neighbor (NN), mid-near (MN), and further (FP) pairs — with a dynamic three-phase weight schedule to preserve both local and global structure. + +## How It Works + +PaCMAP constructs three categories of point pairs in the high-dimensional space: nearest neighbor pairs that capture local structure, mid-near pairs (the second-closest among random candidates) that capture intermediate-range relationships, and further pairs that act as repulsive anchors. A three-phase optimization schedule progressively shifts focus from global structure (via high MN weights) to local refinement (MN disabled), using Adam optimization throughout. + +## Why or When to Use + +A strong alternative to UMAP and t-SNE that explicitly controls global structure preservation through its MN pair mechanism. Often produces cleaner cluster separation and is less sensitive to hyperparameter choices than UMAP. + +## Example + + + +## How-to (Code) + +```javascript +import * as druid from "@saehrimnir/druidjs"; + +const data = [ + /* ... multi-dimensional data ... */ +]; + +// 1. Initialize the algorithm +const pacmap = new druid.PaCMAP(data, { n_neighbors: 10 }); + +// 2. Compute the projection (450 iterations across 3 phases by default) +const projection = pacmap.transform(); + +// Alternatively, use a generator for animation: +// for (const proj of pacmap.generator()) { ... } +``` diff --git a/src/dimred/LocalMAP.js b/src/dimred/LocalMAP.js new file mode 100644 index 0000000..a7eef02 --- /dev/null +++ b/src/dimred/LocalMAP.js @@ -0,0 +1,232 @@ +import { BallTree } from "../knn/index.js"; +import { euclidean_squared } from "../metrics/index.js"; +import { PaCMAP } from "./PaCMAP.js"; + +/** @import {InputType} from "../index.js" */ +/** @import {ParametersLocalMAP} from "./index.js" */ + +/** + * LocalMAP + * + * A variant of PaCMAP that improves local cluster separation by dynamically + * resampling further pairs (FP) in phase 3 using nearby points in the current + * low-dimensional embedding space, rather than randomly sampled non-neighbors. + * + * @class + * @template {InputType} T + * @extends PaCMAP + * @category Dimensionality Reduction + * @see {@link https://arxiv.org/abs/2012.04456|PaCMAP Paper} + * @see {@link PaCMAP} for the base algorithm + * + * @example + * import * as druid from "@saehrimnir/druidjs"; + * + * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]; + * const localmap = new druid.LocalMAP(X, { + * n_neighbors: 10, + * low_dist_thres: 10, + * seed: 42 + * }); + * + * const Y = localmap.transform(); // 450 iterations (default) + * // [[x1, y1], [x2, y2], [x3, y3]] + */ +export class LocalMAP extends PaCMAP { + /** + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + */ + constructor(X, parameters = {}) { + // Merge low_dist_thres into parameters before the seal in DR constructor. + // DR.constructor does Object.seal({ ...defaults, ...parameters }), so + // passing low_dist_thres here ensures it lands in the sealed object. + super(X, { low_dist_thres: 10, ...parameters }); + } + + /** + * Performs one optimization step. + * In phase 3, resamples FP pairs from the current embedding space + * and applies distance-based weight scaling. + * + * @returns {import("../matrix/index.js").Matrix} + */ + next() { + if (!this._nn_pairs) throw new Error("Call init() first!"); + const num_iters = /** @type {number[]} */ (this.parameter("num_iters")); + const phase3_start = num_iters[0] + num_iters[1]; + + if (this._iter < phase3_start) { + // Phases 1 and 2: identical to PaCMAP + return super.next(); + } + + // Phase 3: resample FP pairs from embedding neighbors + const N = this._N; + const d = /** @type {number} */ (this.parameter("d")); + const low_dist_thres = /** @type {number} */ (this._low_dist_thres ?? 10); + const low_dist_thres_sq = low_dist_thres * low_dist_thres; + const { w_nn, w_mn, w_fp } = this._get_weights(this._iter); + const Y = this.Y; + + // Build a KNN structure on the current embedding to find nearby pairs + const y_array = Y.to2dArray(); + const seed = /** @type {number} */ (this.parameter("seed")); + const emb_knn = new BallTree(y_array, { metric: euclidean_squared, seed }); + const n_FP = /** @type {number} */ (this.parameter("FP_ratio")) * + /** @type {number} */ (this.parameter("n_neighbors")); + const n_FP_int = Math.max(1, Math.round(n_FP)); + + // Build local FP pairs by finding nearby embedding neighbors + // (these are not NN neighbors in high-dim space but nearby in low-dim) + const nn_sets = this._nn_sets_cache; + /** @type {Int32Array} */ + let local_fp_pairs; + + if (nn_sets) { + const pair_buf = new Int32Array(N * n_FP_int * 2); + let idx = 0; + for (let i = 0; i < N; ++i) { + const nn_set = nn_sets[i]; + // Search for nearby points in embedding space + const neighbors = emb_knn.search(y_array[i], Math.min(n_FP_int * 3 + 1, N)); + let count = 0; + for (const nb of neighbors) { + if (nb.index === i || (nn_set && nn_set.has(nb.index))) continue; + pair_buf[idx++] = i; + pair_buf[idx++] = nb.index; + count++; + if (count >= n_FP_int) break; + } + } + local_fp_pairs = pair_buf.slice(0, idx); + } else { + local_fp_pairs = /** @type {Int32Array} */ (this._fp_pairs); + } + + // Accumulate gradients with local weight scaling for FP pairs + const grad_flat = new Float64Array(N * d); + this._accumulate_gradients(grad_flat, /** @type {Int32Array} */ (this._nn_pairs), w_nn, 10, false); + this._accumulate_gradients(grad_flat, /** @type {Int32Array} */ (this._mn_pairs), w_mn, 10000, false); + + // FP pairs with local distance-based weight scaling + this._accumulate_gradients_local_fp( + grad_flat, + local_fp_pairs, + w_fp, + low_dist_thres, + low_dist_thres_sq, + ); + + this._adam_update(grad_flat); + this._iter++; + return this.Y; + } + + /** + * Accumulates FP gradients with LocalMAP's distance-based weight scaling. + * For pairs within low_dist_thres, scales w_fp by low_dist_thres / (2 * sqrt(d_ij)). + * + * @private + * @param {Float64Array} grad_flat - Flat N×d gradient accumulator (modified in place) + * @param {Int32Array} pairs - Flat [i, j, i, j, ...] pair array + * @param {number} w_fp - Base FP weight + * @param {number} low_dist_thres - Distance threshold + * @param {number} low_dist_thres_sq - Squared distance threshold + */ + _accumulate_gradients_local_fp(grad_flat, pairs, w_fp, low_dist_thres, low_dist_thres_sq) { + if (w_fp === 0) return; + const Y = this.Y; + const d = /** @type {number} */ (this.parameter("d")); + const n_pairs = pairs.length / 2; + + for (let p = 0; p < n_pairs; ++p) { + const i = pairs[p * 2]; + const j = pairs[p * 2 + 1]; + const y_i = Y.row(i); + const y_j = Y.row(j); + + let sq_dist = 0; + for (let k = 0; k < d; ++k) { + const diff = y_i[k] - y_j[k]; + sq_dist += diff * diff; + } + const d_ij = 1 + sq_dist; + + // Apply local weight scaling when pair is within distance threshold + let w = w_fp; + if (sq_dist < low_dist_thres_sq) { + w *= low_dist_thres / (2 * Math.sqrt(d_ij)); + } + + // FP loss: 1/(1+d_ij), gradient: -2/(1+d_ij)² + const coeff = (-w * 2) / (d_ij * d_ij); + + const base_i = i * d; + const base_j = j * d; + for (let k = 0; k < d; ++k) { + const diff = y_i[k] - y_j[k]; + const g = coeff * diff; + grad_flat[base_i + k] += g; + grad_flat[base_j + k] -= g; + } + } + } + + /** + * Initializes LocalMAP (same as PaCMAP, but caches nn_sets for phase 3 resampling). + * + * @returns {LocalMAP} + */ + init() { + super.init(); + // Cache low_dist_thres from sealed parameters (avoids type indexing issues) + this._low_dist_thres = /** @type {number} */ (/** @type {any} */ (this._parameters)["low_dist_thres"] ?? 10); + // Cache nn_sets for use in phase 3 FP resampling + // We rebuild them from _nn_pairs + const N = this._N; + const nn_pairs = this._nn_pairs; + if (!nn_pairs) return this; + /** @type {Set[]} */ + const nn_sets = Array.from({ length: N }, () => new Set()); + for (let p = 0; p < nn_pairs.length; p += 2) { + nn_sets[nn_pairs[p]].add(nn_pairs[p + 1]); + } + this._nn_sets_cache = nn_sets; + return this; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X, parameters) { + const dr = new LocalMAP(X, parameters); + return dr.transform(); + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new LocalMAP(X, parameters); + yield* dr.generator(); + return dr.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new LocalMAP(X, parameters); + return dr.transform_async(); + } +} diff --git a/src/dimred/PaCMAP.js b/src/dimred/PaCMAP.js new file mode 100644 index 0000000..d39c238 --- /dev/null +++ b/src/dimred/PaCMAP.js @@ -0,0 +1,409 @@ +import { BallTree } from "../knn/index.js"; +import { Matrix } from "../matrix/index.js"; +import { euclidean, euclidean_squared } from "../metrics/index.js"; +import { DR } from "./DR.js"; +import { PCA } from "./PCA.js"; + +/** @import {InputType} from "../index.js" */ +/** @import {Metric} from "../metrics/index.js" */ +/** @import {ParametersPaCMAP} from "./index.js" */ + +/** + * Pairwise Controlled Manifold Approximation Projection (PaCMAP) + * + * A dimensionality reduction technique that uses three types of point pairs — + * nearest neighbor (NN), mid-near (MN), and further (FP) pairs — with a + * dynamic three-phase weight schedule and Adam optimization to preserve both + * local and global structure. + * + * @class + * @template {InputType} T + * @extends DR + * @category Dimensionality Reduction + * @see {@link https://arxiv.org/abs/2012.04456|PaCMAP Paper} + * @see {@link https://github.com/YingfanWang/PaCMAP|PaCMAP GitHub} + * @see {@link UMAP} for a related graph-based technique + * @see {@link LocalMAP} for the local-refinement variant + * + * @example + * import * as druid from "@saehrimnir/druidjs"; + * + * const X = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]; + * const pacmap = new druid.PaCMAP(X, { + * n_neighbors: 10, + * MN_ratio: 0.5, + * FP_ratio: 2.0, + * seed: 42 + * }); + * + * const Y = pacmap.transform(); // 450 iterations (default) + * // [[x1, y1], [x2, y2], [x3, y3]] + */ +export class PaCMAP extends DR { + /** + * @param {T} X - The high-dimensional data. + * @param {Partial} [parameters] - Object containing parameterization of the DR method. + */ + constructor(X, parameters) { + super( + X, + { + n_neighbors: 10, + MN_ratio: 0.5, + FP_ratio: 2.0, + d: 2, + metric: euclidean, + lr: 1.0, + num_iters: [100, 100, 250], + seed: 1212, + }, + parameters, + ); + [this._N, this._D] = this.X.shape; + const n_neighbors = /** @type {number} */ (this.parameter("n_neighbors")); + if (n_neighbors >= this._N) { + throw new Error( + `Parameter n_neighbors (=${n_neighbors}) needs to be smaller than dataset size (N=${this._N})!`, + ); + } + this._iter = 0; + } + + /** + * Samples mid-near pairs for each point. + * For each point i, repeats n_MN times: samples 6 random non-neighbor + * candidates, picks the 2nd closest by high-dim distance. + * + * @protected + * @param {Set[]} nn_sets - Array of neighbor index sets per point + * @param {number} n_MN - Number of mid-near pairs per point + * @returns {Int32Array} Flat array of [i, j] pairs + */ + _sample_mn_pairs(nn_sets, n_MN) { + const N = this._N; + const X = this.X; + const randomizer = this._randomizer; + const pairs = new Int32Array(N * n_MN * 2); + let idx = 0; + + for (let i = 0; i < N; ++i) { + const nn_set = nn_sets[i]; + const x_i = X.row(i); + + for (let k = 0; k < n_MN; ++k) { + // Sample 6 random non-neighbor candidates + /** @type {{idx: number, dist: number}[]} */ + const candidates = []; + let attempts = 0; + while (candidates.length < 6 && attempts < N * 2) { + const j = randomizer.random_int % N; + attempts++; + if (j !== i && !nn_set.has(j)) { + candidates.push({ idx: j, dist: euclidean_squared(x_i, X.row(j)) }); + } + } + if (candidates.length < 2) { + // Fallback: use any available non-self point + const j = (i + 1) % N; + pairs[idx++] = i; + pairs[idx++] = j; + continue; + } + candidates.sort((a, b) => a.dist - b.dist); + // Pick the 2nd closest (index 1) + pairs[idx++] = i; + pairs[idx++] = candidates[1].idx; + } + } + return pairs.slice(0, idx); + } + + /** + * Samples further pairs for each point (random non-neighbors). + * + * @protected + * @param {Set[]} nn_sets - Array of neighbor index sets per point + * @param {number} n_FP - Number of further pairs per point + * @returns {Int32Array} Flat array of [i, j] pairs + */ + _sample_fp_pairs(nn_sets, n_FP) { + const N = this._N; + const randomizer = this._randomizer; + const pairs = new Int32Array(N * n_FP * 2); + let idx = 0; + + for (let i = 0; i < N; ++i) { + const nn_set = nn_sets[i]; + let count = 0; + let attempts = 0; + while (count < n_FP && attempts < N * 3) { + const j = randomizer.random_int % N; + attempts++; + if (j !== i && !nn_set.has(j)) { + pairs[idx++] = i; + pairs[idx++] = j; + count++; + } + } + } + return pairs.slice(0, idx); + } + + /** + * Computes gradient coefficients and updates the gradient matrix for one pair type. + * + * @protected + * @param {Float64Array} grad_flat - Flat N×d gradient accumulator (modified in place) + * @param {Int32Array} pairs - Flat [i, j, i, j, ...] pair array + * @param {number} w - Weight for this pair type + * @param {number} attr_num - Numerator constant for attractive (10 for NN, 10000 for MN); 0 for repulsive + * @param {boolean} repulsive - Whether this is a repulsive pair type + */ + _accumulate_gradients(grad_flat, pairs, w, attr_num, repulsive) { + if (w === 0) return; + const Y = this.Y; + const d = /** @type {number} */ (this.parameter("d")); + const n_pairs = pairs.length / 2; + + for (let p = 0; p < n_pairs; ++p) { + const i = pairs[p * 2]; + const j = pairs[p * 2 + 1]; + const y_i = Y.row(i); + const y_j = Y.row(j); + + // d_ij = 1 + ||y_i - y_j||² + let sq_dist = 0; + for (let k = 0; k < d; ++k) { + const diff = y_i[k] - y_j[k]; + sq_dist += diff * diff; + } + const d_ij = 1 + sq_dist; + + /** @type {number} */ + let coeff; + if (repulsive) { + // FP loss: 1/(1+d_ij), gradient: -2/(1+d_ij)² + coeff = (-w * 2) / (d_ij * d_ij); + } else { + // NN loss: d_ij/(attr_num+d_ij), gradient: 2*attr_num/(attr_num+d_ij)² + const denom = attr_num + d_ij; + coeff = (w * 2 * attr_num) / (denom * denom); + } + + const base_i = i * d; + const base_j = j * d; + for (let k = 0; k < d; ++k) { + const diff = y_i[k] - y_j[k]; + const g = coeff * diff; + grad_flat[base_i + k] += g; + grad_flat[base_j + k] -= g; + } + } + } + + /** + * Returns the weight schedule for the current iteration. + * + * @protected + * @param {number} iter - Current iteration (0-indexed) + * @returns {{ w_nn: number; w_mn: number; w_fp: number }} + */ + _get_weights(iter) { + const num_iters = /** @type {number[]} */ (this.parameter("num_iters")); + const [p1, p2] = num_iters; + if (iter < p1) { + // Phase 1: MN weight linearly decays from 1000 to 3 + const t = iter / p1; + return { w_nn: 2.0, w_mn: 1000.0 * (1 - t) + 3.0 * t, w_fp: 1.0 }; + } else if (iter < p1 + p2) { + // Phase 2: fixed weights + return { w_nn: 3.0, w_mn: 3.0, w_fp: 1.0 }; + } else { + // Phase 3: MN disabled + return { w_nn: 1.0, w_mn: 0.0, w_fp: 1.0 }; + } + } + + /** + * Applies Adam optimizer update to Y using accumulated gradients. + * + * @protected + * @param {Float64Array} grad_flat - Flat N×d gradient + */ + _adam_update(grad_flat) { + const lr = /** @type {number} */ (this.parameter("lr")); + const N = this._N; + const d = /** @type {number} */ (this.parameter("d")); + const beta1 = 0.9; + const beta2 = 0.999; + const eps = 1e-7; + this._adam_t = (this._adam_t ?? 0) + 1; + const t = /** @type {number} */ (this._adam_t); + const bc1 = 1 - beta1 ** t; + const bc2 = 1 - beta2 ** t; + const Y = this.Y; + const m = /** @type {Float64Array} */ (this._adam_m); + const v = /** @type {Float64Array} */ (this._adam_v); + + for (let i = 0; i < N; ++i) { + const base = i * d; + const y_i = Y.row(i); + for (let k = 0; k < d; ++k) { + const g = grad_flat[base + k]; + m[base + k] = beta1 * m[base + k] + (1 - beta1) * g; + v[base + k] = beta2 * v[base + k] + (1 - beta2) * g * g; + const m_hat = m[base + k] / bc1; + const v_hat = v[base + k] / bc2; + y_i[k] -= lr * (m_hat / (Math.sqrt(v_hat) + eps)); + } + } + } + + /** + * Initializes PaCMAP: PCA embedding, KNN pairs, MN pairs, FP pairs, Adam state. + * + * @returns {PaCMAP} + */ + init() { + const X = this.X; + const N = this._N; + const d = /** @type {number} */ (this.parameter("d")); + const seed = /** @type {number} */ (this.parameter("seed")); + const metric = /** @type {Metric} */ (this.parameter("metric")); + const n_neighbors = /** @type {number} */ (this.parameter("n_neighbors")); + const MN_ratio = /** @type {number} */ (this.parameter("MN_ratio")); + const FP_ratio = /** @type {number} */ (this.parameter("FP_ratio")); + + // 1. PCA initialization scaled by 0.01 (X is always Matrix here) + const pca_init = /** @type {Matrix} */ (PCA.transform(X, { d, seed })); + this.Y = new Matrix(N, d, (i, j) => pca_init.entry(i, j) * 0.01); + + // 2. Build KNN graph for NN pairs + const knn = new BallTree(X.to2dArray(), { metric, seed }); + const n_MN = Math.max(1, Math.round(n_neighbors * MN_ratio)); + const n_FP = Math.max(1, Math.round(n_neighbors * FP_ratio)); + + /** @type {Int32Array[]} */ + const nn_indices = []; + /** @type {Set[]} */ + const nn_sets = []; + // NN pairs: flat [i, j] pairs + const nn_pairs = new Int32Array(N * n_neighbors * 2); + let nn_idx = 0; + + for (let i = 0; i < N; ++i) { + const neighbors = knn.search(X.row(i), n_neighbors + 1); + /** @type {number[]} */ + const idxs = []; + for (const nb of neighbors) { + if (nb.index !== i) idxs.push(nb.index); + if (idxs.length >= n_neighbors) break; + } + nn_indices[i] = new Int32Array(idxs); + nn_sets[i] = new Set(idxs); + for (const j of idxs) { + nn_pairs[nn_idx++] = i; + nn_pairs[nn_idx++] = j; + } + } + this._nn_pairs = nn_pairs.slice(0, nn_idx); + + // 3. MN pairs (mid-near sampling) + this._mn_pairs = this._sample_mn_pairs(nn_sets, n_MN); + + // 4. FP pairs (random non-neighbors) + this._fp_pairs = this._sample_fp_pairs(nn_sets, n_FP); + + // 5. Adam optimizer state + this._adam_m = new Float64Array(N * d); + this._adam_v = new Float64Array(N * d); + this._adam_t = 0; + + this._iter = 0; + return this; + } + + /** + * Performs one optimization step. + * + * @returns {Matrix} + */ + next() { + if (!this._nn_pairs) throw new Error("Call init() first!"); + const N = this._N; + const d = /** @type {number} */ (this.parameter("d")); + const { w_nn, w_mn, w_fp } = this._get_weights(this._iter); + + const grad_flat = new Float64Array(N * d); + this._accumulate_gradients(grad_flat, /** @type {Int32Array} */ (this._nn_pairs), w_nn, 10, false); + this._accumulate_gradients(grad_flat, /** @type {Int32Array} */ (this._mn_pairs), w_mn, 10000, false); + this._accumulate_gradients(grad_flat, /** @type {Int32Array} */ (this._fp_pairs), w_fp, 0, true); + this._adam_update(grad_flat); + + this._iter++; + return this.Y; + } + + /** + * @param {number} [iterations] - Total number of iterations. Defaults to sum of `num_iters`. + * @returns {T} + */ + transform(iterations) { + const num_iters = /** @type {number[]} */ (this.parameter("num_iters")); + const total = iterations ?? num_iters.reduce((a, b) => a + b, 0); + this.check_init(); + for (let i = 0; i < total; ++i) { + this.next(); + } + return this.projection; + } + + /** + * @param {number} [iterations] - Total number of iterations. Defaults to sum of `num_iters`. + * @returns {Generator} + */ + *generator(iterations) { + const num_iters = /** @type {number[]} */ (this.parameter("num_iters")); + const total = iterations ?? num_iters.reduce((a, b) => a + b, 0); + this.check_init(); + for (let i = 0; i < total; ++i) { + this.next(); + yield this.projection; + } + return this.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {T} + */ + static transform(X, parameters) { + const dr = new PaCMAP(X, parameters); + return dr.transform(); + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Generator} + */ + static *generator(X, parameters) { + const dr = new PaCMAP(X, parameters); + yield* dr.generator(); + return dr.projection; + } + + /** + * @template {InputType} T + * @param {T} X + * @param {Partial} [parameters] + * @returns {Promise} + */ + static async transform_async(X, parameters) { + const dr = new PaCMAP(X, parameters); + return dr.transform_async(); + } +} diff --git a/src/dimred/index.js b/src/dimred/index.js index f93754a..2d5594e 100755 --- a/src/dimred/index.js +++ b/src/dimred/index.js @@ -2,6 +2,8 @@ * @module dimred */ export { FASTMAP } from "./FASTMAP.js"; +export { LocalMAP } from "./LocalMAP.js"; +export { PaCMAP } from "./PaCMAP.js"; export { ISOMAP } from "./ISOMAP.js"; export { LDA } from "./LDA.js"; export { LLE } from "./LLE.js"; @@ -145,6 +147,31 @@ export { UMAP } from "./UMAP.js"; * @property {number} [seed=1212] - the seed for the random number generator. */ +/** + * @typedef {Object} ParametersPaCMAP + * @property {number} [n_neighbors=10] - Number of nearest neighbors for NN pairs. + * @property {number} [MN_ratio=0.5] - Ratio of mid-near pairs to n_neighbors. + * @property {number} [FP_ratio=2.0] - Ratio of further pairs to n_neighbors. + * @property {number} [d=2] - The dimensionality of the projection. + * @property {Metric} [metric=euclidean] - The metric which defines the distance between two points. + * @property {number} [lr=1.0] - Learning rate for the Adam optimizer. + * @property {number[]} [num_iters=[100,100,250]] - Number of iterations for each of the three phases. + * @property {number} [seed=1212] - The seed for the random number generator. + */ + +/** + * @typedef {Object} ParametersLocalMAP + * @property {number} [n_neighbors=10] - Number of nearest neighbors for NN pairs. + * @property {number} [MN_ratio=0.5] - Ratio of mid-near pairs to n_neighbors. + * @property {number} [FP_ratio=2.0] - Ratio of further pairs to n_neighbors. + * @property {number} [d=2] - The dimensionality of the projection. + * @property {Metric} [metric=euclidean] - The metric which defines the distance between two points. + * @property {number} [lr=1.0] - Learning rate for the Adam optimizer. + * @property {number[]} [num_iters=[100,100,250]] - Number of iterations for each of the three phases. + * @property {number} [low_dist_thres=10] - Distance threshold for local FP pair resampling in phase 3. + * @property {number} [seed=1212] - The seed for the random number generator. + */ + /** * @typedef {Object} ParametersUMAP * @property {number} [n_neighbors=15] - size of the local neighborhood. diff --git a/test/dimred/LocalMAP.test.js b/test/dimred/LocalMAP.test.js new file mode 100644 index 0000000..76648b2 --- /dev/null +++ b/test/dimred/LocalMAP.test.js @@ -0,0 +1,75 @@ +import { describe, expect, it } from "vitest"; +import { LocalMAP } from "../../src/dimred/index.js"; +import { generateTestData } from "../utils/data-generators.js"; +import { expectValidValues } from "../utils/helpers.js"; + +describe("LocalMAP", () => { + it("should reduce dimensionality to d=2 by default", { timeout: 30000 }, () => { + const data = generateTestData(15, 4); + const localmap = new LocalMAP(data, { n_neighbors: 4, seed: 42 }); + const result = localmap.transform(50); + + expect(result).toHaveLength(15); + expect(result[0]).toHaveLength(2); + }); + + it("should complete within timeout", { timeout: 30000 }, () => { + const data = generateTestData(20, 5); + const localmap = new LocalMAP(data, { n_neighbors: 5, d: 2, seed: 42 }); + const result = localmap.transform(50); + + expect(result).toHaveLength(20); + expect(result[0]).toHaveLength(2); + }); + + it("generator should yield intermediate results", { timeout: 30000 }, () => { + const data = generateTestData(15, 4); + const localmap = new LocalMAP(data, { n_neighbors: 5, d: 2, seed: 42 }); + const gen = localmap.generator(10); + + let count = 0; + for (const result of gen) { + count++; + expect(result).toHaveLength(15); + expect(result[0]).toHaveLength(2); + } + expect(count).toBe(10); + }); + + it("should produce valid values", { timeout: 30000 }, () => { + const data = generateTestData(15, 4); + const localmap = new LocalMAP(data, { n_neighbors: 4, d: 2, seed: 42 }); + const result = localmap.transform(50); + expectValidValues(result, "LocalMAP"); + }); + + it("should respect low_dist_thres parameter", { timeout: 30000 }, () => { + const data = generateTestData(15, 4); + const localmap = new LocalMAP(data, { n_neighbors: 4, low_dist_thres: 5, seed: 42 }); + const result = localmap.transform(50); + + expect(result).toHaveLength(15); + expect(result[0]).toHaveLength(2); + expectValidValues(result, "LocalMAP low_dist_thres=5"); + }); + + it("should work with static transform", { timeout: 30000 }, () => { + const data = generateTestData(12, 5); + const result = LocalMAP.transform(data, { n_neighbors: 4 }); + expect(result).toHaveLength(12); + expect(result[0]).toHaveLength(2); + }); + + it("should work with static generator", { timeout: 30000 }, () => { + const data = generateTestData(12, 5); + const gen = LocalMAP.generator(data, { n_neighbors: 4 }); + const result = gen.next().value; + expect(result).toHaveLength(12); + }); + + it("should work with static transform_async", { timeout: 30000 }, async () => { + const data = generateTestData(12, 5); + const result = await LocalMAP.transform_async(data, { n_neighbors: 4 }); + expect(result).toHaveLength(12); + }); +}); diff --git a/test/dimred/PaCMAP.test.js b/test/dimred/PaCMAP.test.js new file mode 100644 index 0000000..0a08976 --- /dev/null +++ b/test/dimred/PaCMAP.test.js @@ -0,0 +1,79 @@ +import { describe, expect, it } from "vitest"; +import { PaCMAP } from "../../src/dimred/index.js"; +import { generateTestData } from "../utils/data-generators.js"; +import { expectValidValues } from "../utils/helpers.js"; + +describe("PaCMAP", () => { + it("should reduce dimensionality to d=2 by default", { timeout: 30000 }, () => { + const data = generateTestData(15, 4); + const pacmap = new PaCMAP(data, { n_neighbors: 4, seed: 42 }); + const result = pacmap.transform(50); + + expect(result).toHaveLength(15); + expect(result[0]).toHaveLength(2); + }); + + it("should complete within timeout", { timeout: 30000 }, () => { + const data = generateTestData(20, 5); + const pacmap = new PaCMAP(data, { n_neighbors: 5, d: 2, seed: 42 }); + const result = pacmap.transform(50); + + expect(result).toHaveLength(20); + expect(result[0]).toHaveLength(2); + }); + + it("generator should yield intermediate results", { timeout: 30000 }, () => { + const data = generateTestData(15, 4); + const pacmap = new PaCMAP(data, { n_neighbors: 5, d: 2, seed: 42 }); + const gen = pacmap.generator(10); + + let count = 0; + for (const result of gen) { + count++; + expect(result).toHaveLength(15); + expect(result[0]).toHaveLength(2); + } + expect(count).toBe(10); + }); + + it("should produce valid values", { timeout: 30000 }, () => { + const data = generateTestData(15, 4); + const pacmap = new PaCMAP(data, { n_neighbors: 4, d: 2, seed: 42 }); + const result = pacmap.transform(50); + expectValidValues(result, "PaCMAP"); + }); + + it("should work with static transform", { timeout: 30000 }, () => { + const data = generateTestData(12, 5); + const result = PaCMAP.transform(data, { n_neighbors: 4 }); + expect(result).toHaveLength(12); + expect(result[0]).toHaveLength(2); + }); + + it("should work with static generator", { timeout: 30000 }, () => { + const data = generateTestData(12, 5); + const gen = PaCMAP.generator(data, { n_neighbors: 4 }); + const result = gen.next().value; + expect(result).toHaveLength(12); + }); + + it("should work with static transform_async", { timeout: 30000 }, async () => { + const data = generateTestData(12, 5); + const result = await PaCMAP.transform_async(data, { n_neighbors: 4 }); + expect(result).toHaveLength(12); + }); + + it("should respect d=3 parameter", { timeout: 30000 }, () => { + const data = generateTestData(15, 6); + const pacmap = new PaCMAP(data, { n_neighbors: 4, d: 3, seed: 42 }); + const result = pacmap.transform(30); + + expect(result).toHaveLength(15); + expect(result[0]).toHaveLength(3); + }); + + it("should throw if n_neighbors >= N", () => { + const data = generateTestData(10, 4); + expect(() => new PaCMAP(data, { n_neighbors: 10 })).toThrow(); + }); +}); From 1500cc457e2c8049ddb738101c1ae97f1250b96f Mon Sep 17 00:00:00 2001 From: Patrick Connolly Date: Mon, 13 Apr 2026 22:25:03 -0400 Subject: [PATCH 3/4] Mention PaCMAP and LocalMAP alongside UMAP in docs Updates all doc pages that list or reference UMAP as a representative DR algorithm to also include PaCMAP and LocalMAP, and adds a cross- reference from the UMAP page to its newer alternatives. Co-Authored-By: Claude Sonnet 4.6 --- docs/dimred/index.md | 1 + docs/dimred/umap.md | 2 +- docs/showcase.md | 6 +++--- docs/showcase/clustering.md | 4 ++-- docs/showcase/knn.md | 2 +- docs/showcase/optimization.md | 2 +- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/docs/dimred/index.md b/docs/dimred/index.md index 2f535fb..ed82dda 100644 --- a/docs/dimred/index.md +++ b/docs/dimred/index.md @@ -18,6 +18,7 @@ Real-world data is rarely a straight line; it's often twisted and curved (like a - **t-SNE (t-Distributed Stochastic Neighbor Embedding):** This is excellent for **visualization**. It focuses on keeping similar data points close together in the new lower-dimensional space. It's famous for taking complex high-dimensional data (like pixels of handwritten digits) and clustering them perfectly in 2D. - **UMAP (Uniform Manifold Approximation and Projection):** Similar to t-SNE but generally faster and better at preserving the "global structure" (the relationship between distant clusters), not just local neighbors. +- **PaCMAP / LocalMAP:** Newer alternatives that use explicit pair types (nearest-neighbor, mid-near, and further pairs) with a three-phase optimization schedule, often producing cleaner cluster separation than UMAP with less hyperparameter sensitivity. ## Why Focus on Extraction? diff --git a/docs/dimred/umap.md b/docs/dimred/umap.md index 23bc8d5..58fdba3 100644 --- a/docs/dimred/umap.md +++ b/docs/dimred/umap.md @@ -19,7 +19,7 @@ Uniform Manifold Approximation and Projection (UMAP) constructs a high-dimension ## Why or When to Use -An excellent, fast alternative to t-SNE that scales well to large datasets and tends to preserve both local and global data structures effectively. +An excellent, fast alternative to t-SNE that scales well to large datasets and tends to preserve both local and global data structures effectively. For a more recent alternative with explicit global structure control, see [PaCMAP](/dimred/pacmap) and [LocalMAP](/dimred/localmap). ## Example diff --git a/docs/showcase.md b/docs/showcase.md index bfa98fd..8005da3 100644 --- a/docs/showcase.md +++ b/docs/showcase.md @@ -5,15 +5,15 @@ Explore the capabilities of DruidJS through our interactive showcases. We've org ## Explore by Category - [**Standard Projections**](/showcase/projections) - A gallery of classic dimensionality reduction algorithms on the Iris dataset. Include methods like [PCA](/dimred/pca), [t-SNE](/dimred/tsne), [UMAP](/dimred/umap), [MDS](/dimred/mds), [TriMap](/dimred/trimap), [ISOMAP](/dimred/isomap), [TopoMap](/dimred/topomap), [Sammon](/dimred/sammon), [LLE](/dimred/lle), [FastMap](/dimred/fastmap), [SMACOF](/dimred/smacof), [LDA](/dimred/lda), [LSP](/dimred/lsp), [LTSA](/dimred/ltsa), [SQDMDS](/dimred/sqdmds). + A gallery of classic dimensionality reduction algorithms on the Iris dataset. Include methods like [PCA](/dimred/pca), [t-SNE](/dimred/tsne), [UMAP](/dimred/umap), [PaCMAP](/dimred/pacmap), [LocalMAP](/dimred/localmap), [MDS](/dimred/mds), [TriMap](/dimred/trimap), [ISOMAP](/dimred/isomap), [TopoMap](/dimred/topomap), [Sammon](/dimred/sammon), [LLE](/dimred/lle), [FastMap](/dimred/fastmap), [SMACOF](/dimred/smacof), [LDA](/dimred/lda), [LSP](/dimred/lsp), [LTSA](/dimred/ltsa), [SQDMDS](/dimred/sqdmds). - [**Clustering Pipelines**](/showcase/clustering) - Learn how to build pipelines using powerful clustering algorithms (including K-Means, OPTICS, CURE, and Hierarchical Clustering) combined with UMAP to project high-dimensional structure. + Learn how to build pipelines using powerful clustering algorithms (including K-Means, OPTICS, CURE, and Hierarchical Clustering) combined with UMAP, PaCMAP, or LocalMAP to project high-dimensional structure. - [**Hierarchical Dendrograms**](/showcase/dendrogram) A visual interactive representation of the internal recursive nested-cluster logic powering the [**Hierarchical Clustering**](/api/classes/HierarchicalClustering) algorithm, rendered natively in D3. - [**Interactive Optimization**](/showcase/optimization) - Watch iterative algorithms (t-SNE, UMAP, TriMap, Sammon, SMACOF, SQDMDS) in action on synthetic and real datasets, and see how they optimize embeddings over time. + Watch iterative algorithms (t-SNE, UMAP, PaCMAP, LocalMAP, TriMap, Sammon, SMACOF, SQDMDS) in action on synthetic and real datasets, and see how they optimize embeddings over time. - [**Metric Sensitivity**](/showcase/metrics) Discover how the choice of distance metrics (Euclidean, Cosine, Manhattan, Chebyshev) influences the final spatial layout in a Sammon projection. diff --git a/docs/showcase/clustering.md b/docs/showcase/clustering.md index c6fefea..28a9234 100644 --- a/docs/showcase/clustering.md +++ b/docs/showcase/clustering.md @@ -1,6 +1,6 @@ # Clustering Pipelines -A frequent task in data science is identifying clusters in high-dimensional space and then visualizing the learned structural manifolds. This showcase allows you to run multiple clustering algorithms—such as [**K-Means**](/api/classes/KMeans), [**OPTICS**](/api/classes/OPTICS), [**CURE**](/api/classes/CURE), and [**Hierarchical Clustering**](/api/classes/HierarchicalClustering)—on various datasets. It computes the assignments intrinsically and then uses [**UMAP**](/api/classes/UMAP) for the 2D visual projection. +A frequent task in data science is identifying clusters in high-dimensional space and then visualizing the learned structural manifolds. This showcase allows you to run multiple clustering algorithms—such as [**K-Means**](/api/classes/KMeans), [**OPTICS**](/api/classes/OPTICS), [**CURE**](/api/classes/CURE), and [**Hierarchical Clustering**](/api/classes/HierarchicalClustering)—on various datasets. It computes the assignments intrinsically and then uses [**UMAP**](/api/classes/UMAP), [**PaCMAP**](/api/classes/PaCMAP), or [**LocalMAP**](/api/classes/LocalMAP) for the 2D visual projection.