140 lines
5.3 KiB
TypeScript
140 lines
5.3 KiB
TypeScript
import {Complex, UnderlyingReal, complex_binary} from './type.js'
|
|
import {
|
|
BBinary, Dependency, ConservativeUnary, ConservativeBinary, ImpType
|
|
} from '../core/Dispatcher.js'
|
|
|
|
declare module "./type" {
|
|
interface ComplexReturn<Params> {
|
|
add: ConservativeBinary<Params, Complex<any>>
|
|
addReal: Params extends [infer Z, infer R]
|
|
? [R] extends [UnderlyingReal<Z>] ? Z : never
|
|
: never
|
|
unaryMinus: ConservativeUnary<Params, Complex<any>>
|
|
conj: ConservativeUnary<Params, Complex<any>>
|
|
subtract: ConservativeBinary<Params, Complex<any>>
|
|
multiply: ConservativeBinary<Params, Complex<any>>
|
|
absquare: Params extends [infer Z]
|
|
? Z extends Complex<any> ? UnderlyingReal<Z> : never
|
|
: never
|
|
reciprocal: ConservativeUnary<Params, Complex<any>>
|
|
divide: ConservativeBinary<Params, Complex<any>>
|
|
divideByReal: Params extends [infer Z, infer R]
|
|
? [R] extends [UnderlyingReal<Z>] ? Z : never
|
|
: never
|
|
// square root that remains the same type
|
|
conservativeSqrt: ConservativeUnary<Params, Complex<any>>
|
|
// Same as conservativeSqrt for complex numbers:
|
|
sqrt: ConservativeUnary<Params, Complex<any>>
|
|
|
|
// complex square root of the real type of a complex:
|
|
complexSqrt: Params extends [infer T] ? Complex<T> : never
|
|
}
|
|
}
|
|
|
|
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 addReal =
|
|
<T>(dep: Dependency<'addReal', [T, UnderlyingReal<T>]>):
|
|
ImpType<'addReal', [Complex<T>, UnderlyingReal<T>]> =>
|
|
(z, r) => complex_binary(dep.addReal(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', BBinary<UnderlyingReal<T>>>):
|
|
ImpType<'absquare', [Complex<T>]> =>
|
|
z => dep.add(dep.absquare(z.re), dep.absquare(z.im))
|
|
|
|
export const divideByReal =
|
|
<T>(dep: Dependency<'divideByReal', [T, UnderlyingReal<T>]>):
|
|
ImpType<'divideByReal', [Complex<T>, UnderlyingReal<T>]> =>
|
|
(z, r) => complex_binary(
|
|
dep.divideByReal(z.re, r), dep.divideByReal(z.im, r))
|
|
|
|
export const reciprocal =
|
|
<T>(dep: Dependency<'conj', [Complex<T>]>
|
|
& Dependency<'absquare', [Complex<T>]>
|
|
& Dependency<'divideByReal', [Complex<T>, UnderlyingReal<T>]>):
|
|
ImpType<'reciprocal', [Complex<T>]> =>
|
|
z => dep.divideByReal(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 complexSqrt =
|
|
<T>(dep: Dependency<'conservativeSqrt', [T]>
|
|
& Dependency<'isSquare', [T]>
|
|
& Dependency<'complex', [T]>
|
|
& Dependency<'unaryMinus', [T]>
|
|
& Dependency<'zero', [T]>
|
|
& Dependency<'nan', [Complex<T>]>): ImpType<'complexSqrt', [T]> =>
|
|
r => {
|
|
if (dep.isSquare(r)) return dep.complex(dep.conservativeSqrt(r))
|
|
const negative = dep.unaryMinus(r)
|
|
if (dep.isSquare(negative)) {
|
|
return complex_binary(
|
|
dep.zero(r), dep.conservativeSqrt(negative))
|
|
}
|
|
// neither the real number or its negative is a square; could happen
|
|
// for example with bigint. So there is no square root. So we have to
|
|
// return the NaN of the type.
|
|
return dep.nan(dep.complex(r))
|
|
}
|
|
|
|
export const sqrt =
|
|
<T>(dep: Dependency<'isReal', [Complex<T>]>
|
|
& Dependency<'complexSqrt', [T]>
|
|
& Dependency<'absquare', [Complex<T>]>
|
|
& Dependency<'conservativeSqrt', [UnderlyingReal<T>]>
|
|
& Dependency<'addReal', [Complex<T>,UnderlyingReal<T>]>
|
|
& Dependency<'re', [Complex<T>]>
|
|
& Dependency<'add', [UnderlyingReal<T>,UnderlyingReal<T>]>
|
|
& Dependency<'divideByReal', [Complex<T>,UnderlyingReal<T>]>
|
|
): ImpType<'sqrt', [Complex<T>]> =>
|
|
z => {
|
|
if (dep.isReal(z)) return dep.complexSqrt(z.re)
|
|
const myabs = dep.conservativeSqrt(dep.absquare(z))
|
|
const num = dep.addReal(z, myabs)
|
|
const r = dep.re(z)
|
|
const denomsq = dep.add(dep.add(myabs, myabs), dep.add(r, r))
|
|
const denom = dep.conservativeSqrt(denomsq)
|
|
return dep.divideByReal(num, denom)
|
|
}
|
|
|
|
export const conservativeSqrt = sqrt
|