typocomath/src/Complex/arithmetic.ts

125 lines
4.6 KiB
TypeScript

import {Complex, UnderlyingReal, complex_binary} from './type.js'
import {Dependency, ImpType} from '../core/Dispatcher.js'
type ComplexUnary<T> =
T extends Complex<infer R> ? (a: Complex<R>) => Complex<R> : never
type ComplexBinary<T> =
T extends Complex<infer R>
? (a: Complex<R>, b: Complex<R>) => Complex<R>
: never
type ComplexReal<T> = T extends Complex<infer R>
? (a: Complex<R>, b: UnderlyingReal<R>) => Complex<R>
: never
declare module "./type" {
interface ComplexImpTypes<T> {
add: ComplexBinary<T>
add_real: ComplexReal<T>
unaryMinus: ComplexUnary<T>
conj: ComplexUnary<T>
subtract: ComplexBinary<T>
multiply: ComplexBinary<T>
absquare: T extends Complex<infer R> ? (a: T) => UnderlyingReal<R> : never
reciprocal: ComplexUnary<T>
divide: ComplexBinary<T>
divide_real: ComplexReal<T>
// square root that remains the same type
conservativeSqrt: ComplexUnary<T>
// Same as conservativeSqrt for complex numbers:
sqrt: ComplexUnary<T>
}
}
export const add =
<T>(dep: Dependency<'add', [T,T]>):
ImpType<'add', [Complex<T>, Complex<T>]> =>
(w, z) => complex_binary(dep.add(w.re, z.re), dep.add(w.im, z.im))
export const add_real =
<T>(dep: Dependency<'add_real', [T, UnderlyingReal<T>]>):
ImpType<'add_real', [Complex<T>, UnderlyingReal<T>]> =>
(z, r) => complex_binary(dep.add_real(z.re, r), z.im)
export const unaryMinus =
<T>(dep: Dependency<'unaryMinus', [T]>):
ImpType<'unaryMinus', [Complex<T>]> =>
z => complex_binary(dep.unaryMinus(z.re), dep.unaryMinus(z.im))
export const conj =
<T>(dep: Dependency<'unaryMinus'|'conj', [T]>):
ImpType<'conj', [Complex<T>]> =>
z => complex_binary(dep.conj(z.re), dep.unaryMinus(z.im))
export const subtract =
<T>(dep: Dependency<'subtract', [T,T]>):
ImpType<'subtract', [Complex<T>, Complex<T>]> =>
(w, z) => complex_binary(dep.subtract(w.re, z.re), dep.subtract(w.im, z.im))
export const multiply =
<T>(dep: Dependency<'add', [T,T]>
& Dependency<'subtract', [T,T]>
& Dependency<'multiply', [T,T]>
& Dependency<'conj', [T]>):
ImpType<'multiply', [Complex<T>, Complex<T>]> =>
(w, z) => {
const mult = dep.multiply
const realpart = dep.subtract(
mult( w.re, z.re), mult(dep.conj(w.im), z.im))
const imagpart = dep.add(
mult(dep.conj(w.re), z.im), mult( w.im, z.re))
return complex_binary(realpart, imagpart)
}
export const absquare =
<T>(dep: Dependency<'absquare', [T]>
& Dependency<'add', [UnderlyingReal<T>, UnderlyingReal<T>]>):
ImpType<'absquare', [Complex<T>]> =>
z => dep.add(dep.absquare(z.re), dep.absquare(z.im))
export const divide_real =
<T>(dep: Dependency<'divide_real', [T, UnderlyingReal<T>]>):
ImpType<'divide_real', [Complex<T>, UnderlyingReal<T>]> =>
(z, r) => complex_binary(
dep.divide_real(z.re, r), dep.divide_real(z.im, r))
export const reciprocal =
<T>(dep: Dependency<'conj', [Complex<T>]>
& Dependency<'absquare', [Complex<T>]>
& Dependency<'divide_real', [Complex<T>, UnderlyingReal<T>]>):
ImpType<'reciprocal', [Complex<T>]> =>
z => dep.divide_real(dep.conj(z), dep.absquare(z))
export const divide =
<T>(dep: Dependency<'multiply', [Complex<T>, Complex<T>]>
& Dependency<'reciprocal', [Complex<T>]>):
ImpType<'divide', [Complex<T>, Complex<T>]> =>
(w, z) => dep.multiply(w, dep.reciprocal(z))
export const sqrt =
<T>(dep: Dependency<'absquare' | 're', [Complex<T>]>
& Dependency<'conservativeSqrt' | 'unaryMinus', [UnderlyingReal<T>]>
& Dependency<'divide_real', [Complex<T>, UnderlyingReal<T>]>
& Dependency<'add_real', [T, UnderlyingReal<T>]>
& {add_complex_real:
ImpType<'add_real', [Complex<T>, UnderlyingReal<T>]>}
& Dependency<'equal' | 'add', [UnderlyingReal<T>, UnderlyingReal<T>]>
& Dependency<'complex', [T, T]>
& Dependency<'zero', [T]>
): ImpType<'sqrt', [Complex<T>]> =>
z => {
const myabs = dep.conservativeSqrt(dep.absquare(z))
const r = dep.re(z)
const negr = dep.unaryMinus(r)
if (dep.equal(myabs, negr)) {
// pure imaginary square root; z.im already zero
return dep.complex(
dep.zero(z.re), dep.add_real(z.im, dep.conservativeSqrt(negr)))
}
const num = dep.add_complex_real(z, myabs)
const denomsq = dep.add(dep.add(myabs, myabs), dep.add(r, r))
const denom = dep.conservativeSqrt(denomsq)
return dep.divide_real(num, denom)
}
export const conservativeSqrt = sqrt