70 lines
2.7 KiB
JavaScript
70 lines
2.7 KiB
JavaScript
|
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')
|