From 640877f39b1b9487aa5692d1a2931ad85a516b26 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Tue, 17 Aug 2021 14:17:35 +0200 Subject: [PATCH] feat(vectors): add mean, minBounds, maxBounds - add ensureInputs() assertion helper --- packages/vectors/src/index.ts | 3 +++ packages/vectors/src/internal/ensure.ts | 9 ++++++++ packages/vectors/src/max-bounds.ts | 19 ++++++++++++++++ packages/vectors/src/mean.ts | 30 +++++++++++++++++++++++++ packages/vectors/src/median.ts | 2 ++ packages/vectors/src/min-bounds.ts | 19 ++++++++++++++++ 6 files changed, 82 insertions(+) create mode 100644 packages/vectors/src/internal/ensure.ts create mode 100644 packages/vectors/src/max-bounds.ts create mode 100644 packages/vectors/src/mean.ts create mode 100644 packages/vectors/src/min-bounds.ts diff --git a/packages/vectors/src/index.ts b/packages/vectors/src/index.ts index 83d88dbcde..62fa627d54 100644 --- a/packages/vectors/src/index.ts +++ b/packages/vectors/src/index.ts @@ -101,8 +101,11 @@ export * from "./major"; export * from "./map"; export * from "./map-vectors"; export * from "./max"; +export * from "./max-bounds"; +export * from "./mean"; export * from "./median"; export * from "./min"; +export * from "./min-bounds"; export * from "./minor"; export * from "./mix-bilinear"; export * from "./mix-cubic"; diff --git a/packages/vectors/src/internal/ensure.ts b/packages/vectors/src/internal/ensure.ts new file mode 100644 index 0000000000..a8d84d8d2c --- /dev/null +++ b/packages/vectors/src/internal/ensure.ts @@ -0,0 +1,9 @@ +import { assert } from "@thi.ng/api"; + +/** + * Asserts that `src` has at least 1 item. + * + * @internal + */ +export const ensureInputs = (src: any[]) => + assert(src.length > 0, `no inputs given`); diff --git a/packages/vectors/src/max-bounds.ts b/packages/vectors/src/max-bounds.ts new file mode 100644 index 0000000000..76d55bc601 --- /dev/null +++ b/packages/vectors/src/max-bounds.ts @@ -0,0 +1,19 @@ +import type { ReadonlyVec, Vec } from "./api"; +import { ensureInputs } from "./internal/ensure"; +import { max } from "./max"; +import { setN } from "./setn"; +import { vecOf } from "./vec-of"; + +/** + * Takes an array of vectors and computes componentwise maximum. Writes result + * to `out` (or a new vector). + * + * @param out + * @param src + */ +export const maxBounds = (out: Vec | null, src: ReadonlyVec[]) => { + ensureInputs(src); + out = out ? setN(out, -Infinity) : vecOf(src[0].length, -Infinity); + for (let i = src.length; --i >= 0; ) max(out, out, src[i]); + return out; +}; diff --git a/packages/vectors/src/mean.ts b/packages/vectors/src/mean.ts new file mode 100644 index 0000000000..8302f2604a --- /dev/null +++ b/packages/vectors/src/mean.ts @@ -0,0 +1,30 @@ +import { add } from "./add"; +import type { ReadonlyVec, Vec } from "./api"; +import { ensureInputs } from "./internal/ensure"; +import { mulN } from "./muln"; +import { set } from "./set"; + +/** + * Takes an array of vectors (of uniform dimensions) and computes the + * componentwise mean. Writes result to `out` (or a new vector). + * + * @remarks + * Also see {@link median}. + * + * @example + * ```ts + * mean([], [[3, 10, 400], [4, 30, 100], [1, 40, 200], [2, 20, 300]]) + * // [ 2.5, 25, 250 ] + * ``` + * + * @param out + * @param src + */ +export const mean = (out: Vec | null, src: ReadonlyVec[]) => { + ensureInputs(src); + out = set(out || [], src[0]); + for (let i = src.length; --i >= 1; ) { + add(out, out, src[i]); + } + return mulN(out, out, 1 / src.length); +}; diff --git a/packages/vectors/src/median.ts b/packages/vectors/src/median.ts index cee83109c3..d66eb3ba6e 100644 --- a/packages/vectors/src/median.ts +++ b/packages/vectors/src/median.ts @@ -1,4 +1,5 @@ import type { ReadonlyVec, Vec } from "./api"; +import { ensureInputs } from "./internal/ensure"; /** * Takes an array of vectors (of uniform dimensions) and computes the @@ -15,6 +16,7 @@ import type { ReadonlyVec, Vec } from "./api"; * @param src */ export const median = (out: Vec | null, src: ReadonlyVec[]) => { + ensureInputs(src); out = out || []; const m = src.length >> 1; for (let i = src[0].length; --i >= 0; ) { diff --git a/packages/vectors/src/min-bounds.ts b/packages/vectors/src/min-bounds.ts new file mode 100644 index 0000000000..68030d8950 --- /dev/null +++ b/packages/vectors/src/min-bounds.ts @@ -0,0 +1,19 @@ +import type { ReadonlyVec, Vec } from "./api"; +import { ensureInputs } from "./internal/ensure"; +import { min } from "./min"; +import { setN } from "./setn"; +import { vecOf } from "./vec-of"; + +/** + * Takes an array of vectors and computes componentwise minimum. Writes result + * to `out` (or a new vector). + * + * @param out + * @param src + */ +export const minBounds = (out: Vec | null, src: ReadonlyVec[]) => { + ensureInputs(src); + out = out ? setN(out, Infinity) : vecOf(src[0].length, Infinity); + for (let i = src.length; --i >= 0; ) min(out, out, src[i]); + return out; +};