From 7b799f71839b896fcbafd21e428cd2d675724184 Mon Sep 17 00:00:00 2001 From: Glen Whitney Date: Mon, 28 Apr 2025 21:25:02 -0700 Subject: [PATCH] feat: Add vector deepEqual --- src/generic/relational.js | 3 +++ src/vector/__test__/relational.spec.js | 16 +++++++++++++++ src/vector/__test__/{type.js => type.spec.js} | 0 src/vector/all.js | 1 + src/vector/relational.js | 20 +++++++++++++++++++ src/vector/type.js | 2 +- 6 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 src/vector/__test__/relational.spec.js rename src/vector/__test__/{type.js => type.spec.js} (100%) create mode 100644 src/vector/relational.js diff --git a/src/generic/relational.js b/src/generic/relational.js index 2d70a1e..0455ddb 100644 --- a/src/generic/relational.js +++ b/src/generic/relational.js @@ -39,6 +39,9 @@ export const equal = match([Any, Any], (math, [T, U]) => { // now that we have `equal` and `exceeds`, pretty much everything else should // be easy: +export const deepEqual = match( + Passthru, (math, types, strategy) => math.equal.resolve(types, strategy)) + export const compare = match([Any, Any], (math, [T, U]) => { const eq = math.equal.resolve([T, U]) const gt = math.exceeds.resolve([T, U]) diff --git a/src/vector/__test__/relational.spec.js b/src/vector/__test__/relational.spec.js new file mode 100644 index 0000000..308ec80 --- /dev/null +++ b/src/vector/__test__/relational.spec.js @@ -0,0 +1,16 @@ +import assert from 'assert' +import math from '#nanomath' + +describe('Vector relational functions', () => { + it('can test two vectors for deep equality', () => { + const dEq = math.deepEqual + const pyth = [3, 4, 5] + assert.strictEqual(dEq(pyth, [3, 4, 5]), true) + assert.strictEqual(dEq(pyth, [3, 4, 6]), false) + assert.strictEqual(dEq(pyth, [3, 4, [5]]), false) + assert.strictEqual(dEq(3, 3 + 1e-13), true) + assert.strictEqual(dEq(pyth, [3+1e-13, 4-1e-13, 5]), true) + assert.strictEqual(dEq([pyth, pyth], [pyth, [3, 4, 5]]), true) + assert.strictEqual(dEq([3], 3), false) + }) +}) diff --git a/src/vector/__test__/type.js b/src/vector/__test__/type.spec.js similarity index 100% rename from src/vector/__test__/type.js rename to src/vector/__test__/type.spec.js diff --git a/src/vector/all.js b/src/vector/all.js index cd390fa..374601f 100644 --- a/src/vector/all.js +++ b/src/vector/all.js @@ -1,4 +1,5 @@ export * as typeDefinition from './Vector.js' +export * as relational from './relational.js' export * as type from './type.js' export * as utilities from './utils.js' diff --git a/src/vector/relational.js b/src/vector/relational.js new file mode 100644 index 0000000..11272ed --- /dev/null +++ b/src/vector/relational.js @@ -0,0 +1,20 @@ +import {Vector} from './Vector.js' +import {NotAType, Returns} from '#core/Type.js' +import {Any, match} from '#core/TypePatterns.js' +import {BooleanT} from '#boolean/BooleanT.js' + +export const deepEqual = [ + match([Vector, Any], Returns(BooleanT, () => false)), + match([Any, Vector], Returns(BooleanT, () => false)), + match([Vector, Vector], (math, [V, W]) => { + if (V.Component === NotAType || W.Component === NotAType) { + return Returns(BooleanT, (v, w) => v === w + || (v.length === w.length + && v.every((e, i) => math.deepEqual(e, w[i])))) + } + const compDeep = math.deepEqual.resolve([V.Component, W.Component]) + return Returns(BooleanT, (v,w) => v === w + || (v.length === w.length + && v.every((e, i) => compDeep(e, w[i])))) + }) +] diff --git a/src/vector/type.js b/src/vector/type.js index d826372..bad1b64 100644 --- a/src/vector/type.js +++ b/src/vector/type.js @@ -2,7 +2,7 @@ import {Vector} from './Vector.js' import {NotAType, Returns} from '#core/Type.js' import {Any, Multiple, match} from '#core/TypePatterns.js' -export const vector = match(Multiple(Any), (math, TV) => { +export const vector = match(Multiple(Any), (math, [TV]) => { if (!TV.length) return Returns(Vector(NotAType), () => []) let CompType = TV[0] if (TV.some(T => T !== CompType)) CompType = NotAType