typocomath/src/Complex/arithmetic.ts

128 lines
3.9 KiB
TypeScript

import { Complex, complex_binary } from './type.js'
export const add =
<T>(dep: {
add: (a: T, b: T) => T
}) =>
(w: Complex<T>, z: Complex<T>): Complex<T> =>
complex_binary(dep.add(w.re, z.re), dep.add(w.im, z.im))
export const addReal =
<T>(dep: {
addReal: (a: T, b: T) => T
}) =>
(z: Complex<T>, r: T): Complex<T> =>
complex_binary(dep.addReal(z.re, r), z.im)
export const unaryMinus =
<T>(dep: {
unaryMinus: (z: T) => T
}) =>
(z: Complex<T>): Complex<T> =>
complex_binary(dep.unaryMinus(z.re), dep.unaryMinus(z.im))
export const conj =
<T>(dep: {
unaryMinus: (z: T) => T,
conj: (z: T) => T
}) =>
(z: Complex<T>): Complex<T> =>
complex_binary(dep.conj(z.re), dep.unaryMinus(z.im))
export const subtract =
<T>(dep: {
subtract: (a: T, b: T) => T
}) =>
(w: Complex<T>, z: Complex<T>): Complex<T> =>
complex_binary(dep.subtract(w.re, z.re), dep.subtract(w.im, z.im))
export const multiply =
<T>(dep: {
add: (a: T, b: T) => T,
subtract: (a: T, b: T) => T,
multiply: (a: T, b: T) => T,
conj: (z: T) => T
}) =>
(w: Complex<T>, z: Complex<T>): Complex<T> => {
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, U>(dep: {
add: (a: U, b: U) => U,
absquare: (z: T) => U
}) =>
(z: Complex<T>): U => dep.add(dep.absquare(z.re), dep.absquare(z.im))
export const divideByReal =
<T>(dep: {
divideByReal: (a: T, b: T) => T
}) =>
(z: Complex<T>, r: T) =>
complex_binary(dep.divideByReal(z.re, r), dep.divideByReal(z.im, r))
export const reciprocal =
<T>(dep: {
conj: (z: Complex<T>) => Complex<T>,
absquare: (z: Complex<T>) => T,
divideByReal: (a: Complex<T>, b: T) => Complex<T>,
zero: (z: T) => T,
}) =>
(z: Complex<T>): Complex<T> => dep.divideByReal(dep.conj(z), dep.absquare(z))
export const divide =
<T>(dep: {
multiply: (a: Complex<T>, b: Complex<T>) => Complex<T>,
reciprocal: (z: Complex<T>) => Complex<T>,
}) =>
(w: Complex<T>, z: Complex<T>) => dep.multiply(w, dep.reciprocal(z))
export const complexSqrt =
<T>(dep: {
conservativeSqrt: (a: T) => T,
isSquare: (a: T) => boolean,
complex: (a: T) => Complex<T>,
unaryMinus: (a: T) => T,
zero: (a: T) => T,
nan: (a: Complex<T>) => Complex<T>
}) =>
(r: T): Complex<T> => {
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: {
isReal: (z: Complex<T>) => boolean,
complexSqrt: (a: T) => Complex<T>,
conservativeSqrt: (a: T) => T,
absquare: (a: Complex<T>) => T,
addReal: (a: Complex<T>, b: T) => Complex<T>,
divideByReal: (a: Complex<T>, b: T) => Complex<T>,
add: (a: T, b: T) => T,
re: (a: Complex<T>) => T,
}) =>
(z: Complex<T>) => {
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