feat: Implement subtypes

This should eventually be moved into typed-function itself, but for
  now it can be implemented on top of the existing typed-function.

  Uses subtypes to define (and error-check) gcd and lcm, which are only
  defined for integer arguments.

  Resolves #36.
This commit is contained in:
Glen Whitney 2022-07-30 04:59:04 -07:00
parent 4d38f4161c
commit c429c19dfe
35 changed files with 294 additions and 43 deletions

View file

@ -12,9 +12,19 @@ const Complex = new PocomathInstance('Complex')
Complex.installType('Complex', {
test: isComplex,
from: {
number: x => ({re: x, im: 0}),
number: x => ({re: x, im: 0})
}
})
Complex.installType('GaussianInteger', {
test: z => typeof z.re == 'bigint' && typeof z.im == 'bigint',
refines: 'Complex',
from: {
bigint: x => ({re: x, im: 0n})
}
})
Complex.promoteUnary = {
Complex: ({self,complex}) => z => complex(self(z.re), self(z.im))
}
export {Complex}

View file

@ -1,5 +1,5 @@
export * from './Types/Complex.mjs'
export const abs = {Complex: ({sqrt, add, multiply}) => z => {
return sqrt(add(multiply(z.re, z.re), multiply(z.im, z.im)))
}}
export const abs = {
Complex: ({sqrt, 'absquare(Complex)': absq}) => z => sqrt(absq(z))
}

5
src/complex/absquare.mjs Normal file
View file

@ -0,0 +1,5 @@
export * from './Types/Complex.mjs'
export const absquare = {
Complex: ({add, square}) => z => add(square(z.re), square(z.im))
}

View file

@ -0,0 +1,6 @@
export * from './Types/Complex.mjs'
export const conjugate = {
Complex: ({negate, complex}) => z => complex(z.re, negate(z.im))
}

17
src/complex/gcd.mjs Normal file
View file

@ -0,0 +1,17 @@
import PocomathInstance from '../core/PocomathInstance.mjs'
import * as Complex from './Types/Complex.mjs'
import gcdType from '../generic/gcdType.mjs'
const imps = {
gcdComplexRaw: gcdType('Complex'),
gcd: { // Only return gcds with positive real part
'Complex, Complex': ({gcdComplexRaw, sign, one, negate}) => (z,m) => {
const raw = gcdComplexRaw(z, m)
if (sign(raw.re) === one(raw.re)) return raw
return negate(raw)
}
}
}
export const gcd = PocomathInstance.merge(Complex, imps)

5
src/complex/isZero.mjs Normal file
View file

@ -0,0 +1,5 @@
export * from './Types/Complex.mjs'
export const isZero = {
Complex: ({self}) => z => self(z.re) && self(z.im)
}

14
src/complex/multiply.mjs Normal file
View file

@ -0,0 +1,14 @@
export * from './Types/Complex.mjs'
export const multiply = {
'Complex,Complex': ({
'complex(any,any)': cplx,
add,
subtract,
self
}) => (w,z) => {
return cplx(
subtract(self(w.re, z.re), self(w.im, z.im)),
add(self(w.re, z.im), self(w.im, z.re)))
}
}

View file

@ -1,8 +1,18 @@
import gcdType from '../generic/gcdType.mjs'
export * from './Types/Complex.mjs'
export {abs} from './abs.mjs'
export {absquare} from './absquare.mjs'
export {add} from './add.mjs'
export {conjugate} from './conjugate.mjs'
export {complex} from './complex.mjs'
export {gcd} from './gcd.mjs'
export {isZero} from './isZero.mjs'
export {multiply} from './multiply.mjs'
export {negate} from './negate.mjs'
export {quotient} from './quotient.mjs'
export {roundquotient} from './roundquotient.mjs'
export {sqrt} from './sqrt.mjs'
export {zero} from './zero.mjs'

View file

@ -1,5 +1,5 @@
export * from './Types/Complex.mjs'
import {Complex} from './Types/Complex.mjs'
export const negate = {
Complex: ({self}) => z => ({re: self(z.re), im: self(z.im)})
}
const negate = Complex.promoteUnary
export {Complex, negate}

5
src/complex/quotient.mjs Normal file
View file

@ -0,0 +1,5 @@
export * from './roundquotient.mjs'
export const quotient = {
'Complex,Complex': ({roundquotient}) => (w,z) => roundquotient(w,z)
}

View file

@ -0,0 +1,17 @@
export * from './Types/Complex.mjs'
export const roundquotient = {
'Complex,Complex': ({
'isZero(Complex)': isZ,
conjugate,
'multiply(Complex,Complex)': mult,
absquare,
self,
complex
}) => (n,d) => {
if (isZ(d)) return d
const cnum = mult(n, conjugate(d))
const dreal = absquare(d)
return complex(self(cnum.re, dreal), self(cnum.im, dreal))
}
}

5
src/complex/zero.mjs Normal file
View file

@ -0,0 +1,5 @@
import {Complex} from './Types/Complex.mjs'
const zero = Complex.promoteUnary
export {Complex, zero}