feat(Complex): Define return types of all operations

This commit is contained in:
Glen Whitney 2022-08-29 11:10:34 -04:00
parent de42c22ab4
commit 23b3ef4fdd
9 changed files with 44 additions and 16 deletions

View File

@ -1,9 +1,11 @@
import Returns from '../core/Returns.mjs'
export * from './Types/Complex.mjs' export * from './Types/Complex.mjs'
export const conjugate = { export const conjugate = {
'Complex<T>': ({ 'Complex<T>': ({
T,
'negate(T)': neg, 'negate(T)': neg,
'complex(T,T)': cplx 'complex(T,T)': cplx
}) => z => cplx(z.re, neg(z.im)) }) => Returns(`Complex<${T}>`, z => cplx(z.re, neg(z.im)))
} }

View File

@ -1,9 +1,10 @@
import Returns from '../core/Returns.mjs'
export * from './Types/Complex.mjs' export * from './Types/Complex.mjs'
export const equalTT = { export const equalTT = {
'Complex<T>,Complex<T>': ({ 'Complex<T>,Complex<T>': ({
'self(T,T)': me 'self(T,T)': me
}) => (w,z) => me(w.re, z.re) && me(w.im, z.im), }) => Returns('boolean', (w, z) => me(w.re, z.re) && me(w.im, z.im)),
// NOTE: Although I do not understand exactly why, with typed-function@3.0's // NOTE: Although I do not understand exactly why, with typed-function@3.0's
// matching algorithm, the above template must come first to ensure the // matching algorithm, the above template must come first to ensure the
// most specific match to a template call. I.e, if one of the below // most specific match to a template call. I.e, if one of the below
@ -11,16 +12,16 @@ export const equalTT = {
// with (Complex<Complex<number>>, Complex<number>) (!, hopefully in some // with (Complex<Complex<number>>, Complex<number>) (!, hopefully in some
// future iteration typed-function will be smart enough to prefer // future iteration typed-function will be smart enough to prefer
// Complex<T>, Complex<T>. Possibly the problem is in Pocomath's bolted-on // Complex<T>, Complex<T>. Possibly the problem is in Pocomath's bolted-on
// type resolution and the difficulty will go away when features are moved into // type resolution and the difficulty will go away when features are moved
// typed-function. // into typed-function.
'Complex<T>,T': ({ 'Complex<T>,T': ({
'isZero(T)': isZ, 'isZero(T)': isZ,
'self(T,T)': eqReal 'self(T,T)': eqReal
}) => (z, x) => eqReal(z.re, x) && isZ(z.im), }) => Returns('boolean', (z, x) => eqReal(z.re, x) && isZ(z.im)),
'T,Complex<T>': ({ 'T,Complex<T>': ({
'isZero(T)': isZ, 'isZero(T)': isZ,
'self(T,T)': eqReal 'self(T,T)': eqReal
}) => (b, z) => eqReal(z.re, b) && isZ(z.im), }) => Returns('boolean', (b, z) => eqReal(z.re, b) && isZ(z.im)),
} }

View File

@ -1,4 +1,5 @@
import PocomathInstance from '../core/PocomathInstance.mjs' import PocomathInstance from '../core/PocomathInstance.mjs'
import Returns from '../core/Returns.mjs'
import * as Complex from './Types/Complex.mjs' import * as Complex from './Types/Complex.mjs'
import gcdType from '../generic/gcdType.mjs' import gcdType from '../generic/gcdType.mjs'
@ -9,15 +10,16 @@ const imps = {
gcdComplexRaw, gcdComplexRaw,
gcd: { // Only return gcds with positive real part gcd: { // Only return gcds with positive real part
'Complex<T>,Complex<T>': ({ 'Complex<T>,Complex<T>': ({
T,
'gcdComplexRaw(Complex<T>,Complex<T>)': gcdRaw, 'gcdComplexRaw(Complex<T>,Complex<T>)': gcdRaw,
'sign(T)': sgn, 'sign(T)': sgn,
'one(T)': uno, 'one(T)': uno,
'negate(Complex<T>)': neg 'negate(Complex<T>)': neg
}) => (z,m) => { }) => Returns(`Complex<${T}>`, (z,m) => {
const raw = gcdRaw(z, m) const raw = gcdRaw(z, m)
if (sgn(raw.re) === uno(raw.re)) return raw if (sgn(raw.re) === uno(raw.re)) return raw
return neg(raw) return neg(raw)
} })
} }
} }

View File

@ -1,14 +1,16 @@
import Returns from '../core/Returns.mjs'
export * from './Types/Complex.mjs' export * from './Types/Complex.mjs'
export const invert = { export const invert = {
'Complex<T>': ({ 'Complex<T>': ({
T,
'conjugate(Complex<T>)': conj, 'conjugate(Complex<T>)': conj,
'absquare(Complex<T>)': asq, 'absquare(Complex<T>)': asq,
'complex(T,T)': cplx, 'complex(T,T)': cplx,
'divide(T,T)': div 'divide(T,T)': div
}) => z => { }) => Returns(`Complex<${T}>`, z => {
const c = conj(z) const c = conj(z)
const d = asq(z) const d = asq(z)
return cplx(div(c.re, d), div(c.im, d)) return cplx(div(c.re, d), div(c.im, d))
} })
} }

View File

@ -1,5 +1,7 @@
import Returns from '../core/Returns.mjs'
export * from './Types/Complex.mjs' export * from './Types/Complex.mjs'
export const isZero = { export const isZero = {
'Complex<T>': ({'self(T)': me}) => z => me(z.re) && me(z.im) 'Complex<T>': ({'self(T)': me}) => Returns(
'boolean', z => me(z.re) && me(z.im))
} }

View File

@ -1,5 +1,14 @@
import Returns from '../core/Returns.mjs'
export * from './Types/Complex.mjs' export * from './Types/Complex.mjs'
// Might be nice to have type aliases!
export const quaternion = { export const quaternion = {
'T,T,T,T': ({complex}) => (r,i,j,k) => complex(complex(r,j), complex(i,k)) 'T,T,T,T': ({
T,
'complex(T,T)': cplxT,
'complex(Complex<T>,Complex<T>)': quat
}) => Returns(
`Complex<Complex<${T}>>`,
(r,i,j,k) => quat(cplxT(r,j), cplxT(i,k))
)
} }

View File

@ -1,7 +1,9 @@
import Returns from '../core/Returns.mjs'
export * from './roundquotient.mjs' export * from './roundquotient.mjs'
export const quotient = { export const quotient = {
'Complex<T>,Complex<T>': ({ 'Complex<T>,Complex<T>': ({
T,
'roundquotient(Complex<T>,Complex<T>)': rq 'roundquotient(Complex<T>,Complex<T>)': rq
}) => (w,z) => rq(w,z) }) => Returns(`Complex<${T}>`, (w,z) => rq(w,z))
} }

View File

@ -1,17 +1,19 @@
import Returns from '../core/Returns.mjs'
export * from './Types/Complex.mjs' export * from './Types/Complex.mjs'
export const roundquotient = { export const roundquotient = {
'Complex<T>,Complex<T>': ({ 'Complex<T>,Complex<T>': ({
T,
'isZero(Complex<T>)': isZ, 'isZero(Complex<T>)': isZ,
'conjugate(Complex<T>)': conj, 'conjugate(Complex<T>)': conj,
'multiply(Complex<T>,Complex<T>)': mult, 'multiply(Complex<T>,Complex<T>)': mult,
'absquare(Complex<T>)': asq, 'absquare(Complex<T>)': asq,
'self(T,T)': me, 'self(T,T)': me,
'complex(T,T)': cplx 'complex(T,T)': cplx
}) => (n,d) => { }) => Returns(`Complex<${T}>`, (n,d) => {
if (isZ(d)) return d if (isZ(d)) return d
const cnum = mult(n, conj(d)) const cnum = mult(n, conj(d))
const dreal = asq(d) const dreal = asq(d)
return cplx(me(cnum.re, dreal), me(cnum.im, dreal)) return cplx(me(cnum.re, dreal), me(cnum.im, dreal))
} })
} }

View File

@ -49,6 +49,12 @@ describe('The default full pocomath instance "math"', () => {
math.abs(math.complex(2,1)) //TODO: ditto math.abs(math.complex(2,1)) //TODO: ditto
assert.strictEqual( assert.strictEqual(
math.returnTypeOf('abs','Complex<NumInt>'), 'number') math.returnTypeOf('abs','Complex<NumInt>'), 'number')
math.multiply(math.quaternion(1,1,1,1), math.quaternion(1,-1,1,-1)) // dit
const quatType = math.returnTypeOf(
'quaternion', 'NumInt,NumInt,NumInt,NumInt')
assert.strictEqual(quatType, 'Complex<Complex<NumInt>>')
assert.strictEqual(
math.returnTypeOf('multiply', quatType + ',' + quatType), quatType)
}) })
it('can subtract numbers', () => { it('can subtract numbers', () => {