2022-07-19 16:52:16 +00:00
|
|
|
import assert from 'assert'
|
2022-07-22 20:49:14 +00:00
|
|
|
import math from '../src/pocomath.mjs'
|
|
|
|
import PocomathInstance from '../src/core/PocomathInstance.mjs'
|
|
|
|
import * as numbers from '../src/number/all.mjs'
|
|
|
|
import * as numberAdd from '../src/number/add.mjs'
|
2022-08-06 15:27:44 +00:00
|
|
|
import * as numberZero from '../src/number/zero.mjs'
|
2022-08-01 10:09:32 +00:00
|
|
|
import {add as genericAdd} from '../src/generic/arithmetic.mjs'
|
2022-07-22 20:49:14 +00:00
|
|
|
import * as complex from '../src/complex/all.mjs'
|
|
|
|
import * as complexAdd from '../src/complex/add.mjs'
|
|
|
|
import * as complexNegate from '../src/complex/negate.mjs'
|
2022-07-23 02:41:59 +00:00
|
|
|
import * as complexComplex from '../src/complex/complex.mjs'
|
2022-08-05 12:48:57 +00:00
|
|
|
import * as bigintAdd from '../src/bigint/add.mjs'
|
2022-08-06 15:27:44 +00:00
|
|
|
import * as bigintZero from '../src/bigint/zero.mjs'
|
2022-07-23 02:41:59 +00:00
|
|
|
import * as concreteSubtract from '../src/generic/subtract.concrete.mjs'
|
|
|
|
import * as genericSubtract from '../src/generic/subtract.mjs'
|
2022-07-22 20:49:14 +00:00
|
|
|
import extendToComplex from '../src/complex/extendToComplex.mjs'
|
2022-07-19 16:52:16 +00:00
|
|
|
|
|
|
|
const bw = new PocomathInstance('backwards')
|
|
|
|
describe('A custom instance', () => {
|
|
|
|
it("works when partially assembled", () => {
|
|
|
|
bw.install(complex)
|
2022-07-22 20:49:14 +00:00
|
|
|
// Not much we can call without any number types:
|
2022-08-05 12:48:57 +00:00
|
|
|
assert.deepStrictEqual(bw.complex(undefined, undefined), undefined)
|
|
|
|
assert.deepStrictEqual(
|
|
|
|
bw.chain(undefined).complex(undefined).value,
|
|
|
|
undefined)
|
2022-07-22 20:49:14 +00:00
|
|
|
// Don't have a way to negate things, for example:
|
|
|
|
assert.throws(() => bw.negate(2), TypeError)
|
2022-07-19 16:52:16 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
it("can be assembled in any order", () => {
|
|
|
|
bw.install(numbers)
|
2022-07-28 05:28:40 +00:00
|
|
|
bw.installType('string', {test: s => typeof s === 'string'})
|
2022-07-19 16:52:16 +00:00
|
|
|
assert.strictEqual(bw.subtract(16, bw.add(3,4,2)), 7)
|
|
|
|
assert.strictEqual(bw.negate('8'), -8)
|
|
|
|
assert.deepStrictEqual(bw.add(bw.complex(1,3), 1), {re: 2, im: 3})
|
2022-07-19 18:54:22 +00:00
|
|
|
assert.deepStrictEqual(
|
|
|
|
bw.subtract(16, bw.add(3, bw.complex(0,4), 2)),
|
|
|
|
math.complex(11, -4)) // note both instances coexist
|
2022-08-05 12:48:57 +00:00
|
|
|
assert.deepStrictEqual(bw.negate(bw.complex(3, '8')).im, -8)
|
2022-07-19 18:54:22 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
it("can be assembled piecemeal", () => {
|
|
|
|
const pm = new PocomathInstance('piecemeal')
|
|
|
|
pm.install(numbers)
|
|
|
|
assert.strictEqual(pm.subtract(5, 10), -5)
|
2022-08-01 15:28:21 +00:00
|
|
|
assert.strictEqual(pm.floor(3.7), 3)
|
|
|
|
assert.throws(() => pm.floor(10n), TypeError)
|
2022-08-01 23:24:20 +00:00
|
|
|
assert.strictEqual(pm.chain(5).add(7).value, 12)
|
2022-07-19 18:54:22 +00:00
|
|
|
pm.install(complexAdd)
|
|
|
|
pm.install(complexNegate)
|
2022-07-30 11:59:04 +00:00
|
|
|
pm.install(complexComplex)
|
2022-07-22 20:49:14 +00:00
|
|
|
// Should be enough to allow complex subtraction, as subtract is generic:
|
2022-07-19 18:54:22 +00:00
|
|
|
assert.deepStrictEqual(
|
2022-08-01 15:28:21 +00:00
|
|
|
pm.subtract(pm.complex(5, 0), pm.complex(10, 1)),
|
|
|
|
math.complex(-5, -1))
|
|
|
|
// And now floor has been activated for Complex as well, since the type
|
|
|
|
// is present
|
2022-08-06 15:27:44 +00:00
|
|
|
const fracComplex = math.complex(1.9, 0)
|
|
|
|
const intComplex = math.complex(1)
|
|
|
|
assert.deepStrictEqual(pm.floor(fracComplex), intComplex)
|
2022-08-01 23:24:20 +00:00
|
|
|
// And the chain functions refresh themselves:
|
|
|
|
assert.deepStrictEqual(
|
|
|
|
pm.chain(5).add(pm.chain(0).complex(7).value).value, math.complex(5,7))
|
2022-07-19 16:52:16 +00:00
|
|
|
})
|
2022-07-19 19:37:52 +00:00
|
|
|
|
2022-07-24 19:52:05 +00:00
|
|
|
it("can defer definition of (even used) types", () => {
|
|
|
|
const dt = new PocomathInstance('Deferred Types')
|
|
|
|
dt.install(numberAdd)
|
2022-08-06 15:27:44 +00:00
|
|
|
dt.install(numberZero) // for promoting numbers to complex, to fill in im
|
2022-07-24 19:52:05 +00:00
|
|
|
dt.install({times: {
|
|
|
|
'number,number': () => (m,n) => m*n,
|
2022-08-06 15:27:44 +00:00
|
|
|
'Complex<T>,Complex<T>': ({'complex(T,T)': cplx}) => (w,z) => {
|
|
|
|
return cplx(w.re*z.re - w.im*z.im, w.re*z.im + w.im*z.re)
|
2022-07-24 19:52:05 +00:00
|
|
|
}
|
|
|
|
}})
|
|
|
|
// complex type not present but should still be able to add numbers:
|
|
|
|
assert.strictEqual(dt.times(3,5), 15)
|
|
|
|
dt.install(complexComplex)
|
|
|
|
// times should now rebundle to allow complex:
|
|
|
|
assert.deepStrictEqual(
|
|
|
|
dt.times(dt.complex(2,3), dt.complex(2,-3)), dt.complex(13))
|
|
|
|
})
|
|
|
|
|
2022-07-19 19:37:52 +00:00
|
|
|
it("can selectively import in cute ways", async function () {
|
|
|
|
const cherry = new PocomathInstance('cherry')
|
|
|
|
cherry.install(numberAdd)
|
2022-08-06 15:27:44 +00:00
|
|
|
cherry.install(numberZero) // for complex promotion
|
2022-07-19 19:37:52 +00:00
|
|
|
await extendToComplex(cherry)
|
2022-08-01 10:09:32 +00:00
|
|
|
cherry.install({add: genericAdd})
|
2022-07-22 20:49:14 +00:00
|
|
|
/* Now we have an instance that supports addition for number and complex
|
|
|
|
and little else:
|
|
|
|
*/
|
2022-07-19 19:37:52 +00:00
|
|
|
assert.strictEqual(cherry.add(3, 4, 2), 9)
|
|
|
|
assert.deepStrictEqual(
|
|
|
|
cherry.add(cherry.complex(3, 3), 4, cherry.complex(2, 2)),
|
|
|
|
math.complex(9,5))
|
|
|
|
assert.strictEqual('subtract' in cherry, false)
|
|
|
|
assert.strictEqual('negate' in cherry, false)
|
|
|
|
})
|
2022-07-23 02:41:59 +00:00
|
|
|
|
|
|
|
it("can use bundles that are closed under dependency", () => {
|
|
|
|
const ok = new PocomathInstance('concrete')
|
|
|
|
ok.install(concreteSubtract)
|
|
|
|
assert.strictEqual(ok.subtract(7, 5), 2)
|
|
|
|
})
|
|
|
|
|
|
|
|
it("can load generics and then import their dependences", async function () {
|
|
|
|
const chase = new PocomathInstance('Chase Dependencies')
|
|
|
|
chase.install(genericSubtract)
|
|
|
|
chase.install(complexComplex) // for convenience to build complex numbers
|
|
|
|
await chase.importDependencies(['bigint', 'complex'])
|
|
|
|
/* Now we have an instance that supports subtraction for Gaussian
|
|
|
|
integers.
|
|
|
|
*/
|
|
|
|
assert.deepStrictEqual(
|
|
|
|
chase.subtract(chase.complex(3n, 2n), chase.complex(2n, 5n)),
|
|
|
|
math.complex(1n, -3n))
|
|
|
|
})
|
|
|
|
|
2022-08-05 12:48:57 +00:00
|
|
|
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)
|
2022-08-06 15:27:44 +00:00
|
|
|
inst.install(bigintZero) // for complex promotion
|
2022-08-05 12:48:57 +00:00
|
|
|
assert.strictEqual(
|
|
|
|
inst.typeMerge(6n, inst.complex(3n, 2n)),
|
2022-08-06 15:27:44 +00:00
|
|
|
'Merge to Complex<bigint>')
|
2022-08-05 12:48:57 +00:00
|
|
|
assert.strictEqual(
|
|
|
|
inst.typeMerge(3, inst.complex(4.5,2.1)),
|
2022-08-06 15:27:44 +00:00
|
|
|
'Merge to Complex<number>')
|
2022-08-29 13:30:07 +00:00
|
|
|
assert.throws(
|
|
|
|
() => inst.typeMerge(3, inst.complex(3n)), TypeError)
|
2022-08-05 12:48:57 +00:00
|
|
|
inst.install(genericSubtract)
|
|
|
|
assert.throws(() => inst.typeMerge(3, undefined), TypeError)
|
|
|
|
})
|
2022-07-19 16:52:16 +00:00
|
|
|
})
|