feat: Template types (#45)
Includes a full implementation of a type-homogeneous Tuple type, using the template types feature, as a demonstration/check of its operation. Co-authored-by: Glen Whitney <glen@studioinfinity.org> Reviewed-on: #45
This commit is contained in:
parent
fd32ee1f10
commit
845a2354c9
28 changed files with 920 additions and 129 deletions
|
@ -103,4 +103,13 @@ describe('The default full pocomath instance "math"', () => {
|
|||
assert.strictEqual(math.choose(21n, 2n), 210n)
|
||||
})
|
||||
|
||||
it('calculates multi-way gcds and lcms', () => {
|
||||
assert.strictEqual(math.gcd(30,105,42), 3)
|
||||
assert.ok(
|
||||
math.associate(
|
||||
math.lcm(
|
||||
math.complex(2n,1n), math.complex(1n,1n), math.complex(0n,1n)),
|
||||
math.complex(1n,3n)))
|
||||
})
|
||||
|
||||
})
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import assert from 'assert'
|
||||
import dependencyExtractor from '../../src/core/dependencyExtractor.mjs'
|
||||
import {dependencyExtractor} from '../../src/core/extractors.mjs'
|
||||
|
||||
describe('dependencyExtractor', () => {
|
||||
it('will record the keys of a destructuring function', () => {
|
|
@ -8,6 +8,7 @@ import * as complex from '../src/complex/all.mjs'
|
|||
import * as complexAdd from '../src/complex/add.mjs'
|
||||
import * as complexNegate from '../src/complex/negate.mjs'
|
||||
import * as complexComplex from '../src/complex/complex.mjs'
|
||||
import * as bigintAdd from '../src/bigint/add.mjs'
|
||||
import * as concreteSubtract from '../src/generic/subtract.concrete.mjs'
|
||||
import * as genericSubtract from '../src/generic/subtract.mjs'
|
||||
import extendToComplex from '../src/complex/extendToComplex.mjs'
|
||||
|
@ -17,9 +18,10 @@ describe('A custom instance', () => {
|
|||
it("works when partially assembled", () => {
|
||||
bw.install(complex)
|
||||
// Not much we can call without any number types:
|
||||
const i3 = {re: 0, im: 3}
|
||||
assert.deepStrictEqual(bw.complex(0, 3), i3)
|
||||
assert.deepStrictEqual(bw.chain(0).complex(3).value, i3)
|
||||
assert.deepStrictEqual(bw.complex(undefined, undefined), undefined)
|
||||
assert.deepStrictEqual(
|
||||
bw.chain(undefined).complex(undefined).value,
|
||||
undefined)
|
||||
// Don't have a way to negate things, for example:
|
||||
assert.throws(() => bw.negate(2), TypeError)
|
||||
})
|
||||
|
@ -33,7 +35,7 @@ describe('A custom instance', () => {
|
|||
assert.deepStrictEqual(
|
||||
bw.subtract(16, bw.add(3, bw.complex(0,4), 2)),
|
||||
math.complex(11, -4)) // note both instances coexist
|
||||
assert.deepStrictEqual(bw.negate(math.complex(3, '8')).im, -8)
|
||||
assert.deepStrictEqual(bw.negate(bw.complex(3, '8')).im, -8)
|
||||
})
|
||||
|
||||
it("can be assembled piecemeal", () => {
|
||||
|
@ -112,4 +114,30 @@ describe('A custom instance', () => {
|
|||
math.complex(1n, -3n))
|
||||
})
|
||||
|
||||
it("instantiates templates correctly", () => {
|
||||
const inst = new PocomathInstance('InstantiateTemplates')
|
||||
inst.install(numberAdd)
|
||||
inst.install({typeMerge: {'T,T': ({T}) => (t,u) => 'Merge to ' + T }})
|
||||
assert.strictEqual(inst.typeMerge(7,6.28), 'Merge to number')
|
||||
assert.strictEqual(inst.typeMerge(7,6), 'Merge to NumInt')
|
||||
assert.strictEqual(inst.typeMerge(7.35,6), 'Merge to number')
|
||||
inst.install(complexAdd)
|
||||
inst.install(complexComplex)
|
||||
inst.install(bigintAdd)
|
||||
assert.strictEqual(
|
||||
inst.typeMerge(6n, inst.complex(3n, 2n)),
|
||||
'Merge to GaussianInteger')
|
||||
assert.strictEqual(
|
||||
inst.typeMerge(3, inst.complex(4.5,2.1)),
|
||||
'Merge to Complex')
|
||||
// The following is the current behavior, since 3 converts to 3+0i
|
||||
// which is technically the same Complex type as 3n+0ni.
|
||||
// This should clear up when Complex is templatized
|
||||
assert.strictEqual(inst.typeMerge(3, inst.complex(3n)), 'Merge to Complex')
|
||||
// But types that truly cannot be merged should throw a TypeError
|
||||
// Should add a variation of this with a more usual type once there is
|
||||
// one not interconvertible with others...
|
||||
inst.install(genericSubtract)
|
||||
assert.throws(() => inst.typeMerge(3, undefined), TypeError)
|
||||
})
|
||||
})
|
||||
|
|
114
test/tuple/_native.mjs
Normal file
114
test/tuple/_native.mjs
Normal file
|
@ -0,0 +1,114 @@
|
|||
import assert from 'assert'
|
||||
import math from '../../src/pocomath.mjs'
|
||||
|
||||
describe('tuple', () => {
|
||||
it('can be created and provide its length', () => {
|
||||
assert.strictEqual(math.length(math.tuple(3, 5.2, 2)), 3)
|
||||
})
|
||||
|
||||
it('does not allow unification by converting consecutive arguments', () => {
|
||||
assert.throws(() => math.tuple(3, 5.2, 2n), /TypeError.*unif/)
|
||||
// Hence, the order matters in a slightly unfortunate way,
|
||||
// but I think being a little ragged in these edge cases is OK:
|
||||
assert.throws(
|
||||
() => math.tuple(3, 2n, math.complex(5.2)),
|
||||
/TypeError.*unif/)
|
||||
assert.deepStrictEqual(
|
||||
math.tuple(3, math.complex(2n), 5.2),
|
||||
{elts: [math.complex(3), math.complex(2n), math.complex(5.2)]})
|
||||
})
|
||||
|
||||
it('can be tested for zero and equality', () => {
|
||||
assert.strictEqual(math.isZero(math.tuple(0,1)), false)
|
||||
assert.strictEqual(math.isZero(math.tuple(0n,0n,0n,0n)), true)
|
||||
assert.strictEqual(math.isZero(math.tuple(0,0.001,0)), false)
|
||||
assert.deepStrictEqual(math.complex(0,0), {re: 0, im:0})
|
||||
assert.strictEqual(math.isZero(math.tuple(0,math.complex(0,0))), true)
|
||||
assert.strictEqual(
|
||||
math.equal(
|
||||
math.tuple(0,math.complex(0,0.1)),
|
||||
math.complex(math.tuple(0,0), math.tuple(0,0.1))),
|
||||
true)
|
||||
assert.strictEqual(
|
||||
math.equal(math.tuple(3n,2n), math.tuple(3,2)),
|
||||
false)
|
||||
})
|
||||
|
||||
it('supports addition', () => {
|
||||
assert.deepStrictEqual(
|
||||
math.add(math.tuple(3,4,5), math.tuple(2,1,0)),
|
||||
math.tuple(5,5,5))
|
||||
assert.deepStrictEqual(
|
||||
math.add(math.tuple(3.25,4.5,5), math.tuple(3,3)),
|
||||
math.tuple(6.25,7.5,5))
|
||||
assert.deepStrictEqual(
|
||||
math.add(math.tuple(math.complex(2,3), 7), math.tuple(4, 5, 6)),
|
||||
math.tuple(math.complex(6,3), math.complex(12), math.complex(6)))
|
||||
assert.deepStrictEqual(
|
||||
math.add(math.tuple(5,6), 7),
|
||||
math.tuple(12,6))
|
||||
assert.deepStrictEqual(
|
||||
math.add(math.tuple(math.complex(5,4),6), 7),
|
||||
math.tuple(math.complex(12,4),math.complex(6)))
|
||||
})
|
||||
|
||||
it('supports subtraction', () => {
|
||||
assert.deepStrictEqual(
|
||||
math.subtract(math.tuple(3n,4n,5n), math.tuple(2n,1n,0n)),
|
||||
math.tuple(1n,3n,5n))
|
||||
assert.throws(
|
||||
() => math.subtract(math.tuple(5,6), math.tuple(7)),
|
||||
/RangeError/)
|
||||
})
|
||||
|
||||
it('makes a tuple of complex and conjugates it', () => {
|
||||
const complexTuple = math.tuple(
|
||||
math.complex(3,1), math.complex(4,2.2), math.complex(5,3))
|
||||
assert.deepStrictEqual(
|
||||
math.complex(math.tuple(3,4,5), math.tuple(1,2.2,3)),
|
||||
complexTuple)
|
||||
assert.deepStrictEqual(
|
||||
math.conjugate(complexTuple),
|
||||
math.tuple(math.complex(3,-1), math.complex(4,-2.2), math.complex(5,-3)))
|
||||
})
|
||||
|
||||
it('supports division', () => {
|
||||
assert.deepStrictEqual(
|
||||
math.divide(math.tuple(3,4,5),math.tuple(1,2,2)),
|
||||
math.tuple(3,2,2.5))
|
||||
})
|
||||
|
||||
it('supports multiplication', () => {
|
||||
assert.deepStrictEqual(
|
||||
math.multiply(math.tuple(3,4,5), math.tuple(1,2,2)),
|
||||
math.tuple(3,8,10))
|
||||
})
|
||||
|
||||
it('supports one and zero', () => {
|
||||
assert.deepStrictEqual(
|
||||
math.one(math.tuple(2n,3n,0n)),
|
||||
math.tuple(1n,1n,1n))
|
||||
assert.deepStrictEqual(
|
||||
math.zero(math.tuple(math.complex(5,2), 3.4)),
|
||||
math.tuple(math.complex(0), math.complex(0)))
|
||||
})
|
||||
|
||||
it('supports quotient and roundquotient', () => {
|
||||
const bigTuple = math.tuple(1n,2n,3n,4n,5n)
|
||||
const bigOnes = math.one(bigTuple)
|
||||
const threes = math.add(bigOnes, bigOnes, bigOnes)
|
||||
assert.deepStrictEqual(
|
||||
math.quotient(bigTuple, threes),
|
||||
math.tuple(0n, 0n, 1n, 1n, 1n))
|
||||
assert.deepStrictEqual(
|
||||
math.roundquotient(bigTuple, threes),
|
||||
math.tuple(0n, 1n, 1n, 1n, 2n))
|
||||
})
|
||||
|
||||
it('supports sqrt', () => {
|
||||
assert.deepStrictEqual(
|
||||
math.sqrt(math.tuple(4,-4,2.25)),
|
||||
math.tuple(2, math.complex(0,2), 1.5))
|
||||
})
|
||||
|
||||
})
|
Loading…
Add table
Add a link
Reference in a new issue