Adds all of the pocomath functions on Complex that do not depend on any unimplemented types or config properties, except quotient and roundquotient, where the design is murky. To get this working, adds some additional features: * Allows conversions to generic types, with the matched type determined from the return value of the built convertor * Adds predicate-based type patterns * Adds conversion from any non-complex type T to Complex(T) * Adds check for recursive loops in resolve (a key/signature depending on itself) Reviewed-on: #24 Co-authored-by: Glen Whitney <glen@studioinfinity.org> Co-committed-by: Glen Whitney <glen@studioinfinity.org>
This commit is contained in:
parent
0ff00ff8cb
commit
aad62df8ac
33 changed files with 428 additions and 106 deletions
69
src/complex/arithmetic.js
Normal file
69
src/complex/arithmetic.js
Normal file
|
@ -0,0 +1,69 @@
|
|||
import {Complex} from './Complex.js'
|
||||
import {promoteBinary, promoteUnary} from './helpers.js'
|
||||
import {ResolutionError} from '#core/helpers.js'
|
||||
import {match} from '#core/TypePatterns.js'
|
||||
import {ReturnsAs} from '#generic/helpers.js'
|
||||
|
||||
export const absquare = match(Complex, (math, C) => {
|
||||
const compAbsq = math.absquare.resolve([C.Component])
|
||||
const R = compAbsq.returns
|
||||
const add = math.add.resolve([R,R])
|
||||
return ReturnsAs(add, z => add(compAbsq(z.re), compAbsq(z.im)))
|
||||
})
|
||||
|
||||
export const add = promoteBinary('add')
|
||||
|
||||
export const conj = match(Complex, (math, C) => {
|
||||
const neg = math.negate.resolve(C.Component)
|
||||
const compConj = math.conj.resolve(C.Component)
|
||||
const cplx = math.complex.resolve([compConj.returns, neg.returns])
|
||||
return ReturnsAs(cplx, z => cplx(compConj(z.re), neg(z.im)))
|
||||
})
|
||||
|
||||
export const divide = [
|
||||
match([Complex, T => !T.complex], (math, [C, R]) => {
|
||||
const div = math.divide.resolve([C.Component, R])
|
||||
const cplx = math.complex.resolve([div.returns, div.returns])
|
||||
return ReturnsAs(cplx, (z, r) => cplx(div(z.re, r), div(z.im, r)))
|
||||
}),
|
||||
match([Complex, Complex], (math, [W, Z]) => {
|
||||
const inv = math.invert.resolve(Z)
|
||||
const mult = math.multiply.resolve([W, inv.returns])
|
||||
return ReturnsAs(mult, (w, z) => mult(w, inv(z)))
|
||||
})
|
||||
]
|
||||
|
||||
export const invert = match(Complex, (math, C) => {
|
||||
const conj = math.conj.resolve(C)
|
||||
const norm = math.absquare.resolve(C)
|
||||
const div = math.divide.resolve([C.Component, norm.returns])
|
||||
const cplx = math.complex.resolve([div.returns, div.returns])
|
||||
return ReturnsAs(cplx, z => {
|
||||
const c = conj(z)
|
||||
const d = norm(z)
|
||||
return cplx(div(c.re, d), div(c.im, d))
|
||||
})
|
||||
})
|
||||
|
||||
// We want this to work for complex numbers, quaternions, octonions, etc
|
||||
// See https://math.ucr.edu/home/baez/octonions/node5.html
|
||||
export const multiply = match([Complex, Complex], (math, [W, Z]) => {
|
||||
const conj = math.conj.resolve(W.Component)
|
||||
if (conj.returns !== W.Component) {
|
||||
throw new ResolutionError(
|
||||
`conjugation on ${W.Component} returns other type (${conj.returns})`)
|
||||
}
|
||||
const mWZ = math.multiply.resolve([W.Component, Z.Component])
|
||||
const mZW = math.multiply.resolve([Z.Component, W.Component])
|
||||
const sub = math.subtract.resolve([mWZ.returns, mZW.returns])
|
||||
const add = math.add.resolve([mWZ.returns, mZW.returns])
|
||||
const cplx = math.complex.resolve([sub.returns, add.returns])
|
||||
return ReturnsAs(cplx, (w, z) => {
|
||||
const real = sub(mWZ( w.re, z.re), mZW(z.im, conj(w.im)))
|
||||
const imag = add(mWZ(conj(w.re), z.im), mZW(z.re, w.im))
|
||||
return cplx(real, imag)
|
||||
})
|
||||
})
|
||||
|
||||
export const negate = promoteUnary('negate')
|
||||
export const subtract = promoteBinary('subtract')
|
Loading…
Add table
Add a link
Reference in a new issue