diff --git a/src/Complex/arithmetic.ts b/src/Complex/arithmetic.ts new file mode 100644 index 0000000..19cb8c2 --- /dev/null +++ b/src/Complex/arithmetic.ts @@ -0,0 +1,88 @@ +import {Complex, complex_binary} from './type.js' +import {Dependency} from '../core/Dispatcher.js' + +export const add = (dep: Dependency<'add', [T,T]>) => + (w: Complex, z: Complex) => + complex_binary(dep.add(w.re, z.re), dep.add(w.im, z.im)) + +export const unaryMinus = (dep: Dependency<'unaryMinus', [T]>) => + (z: Complex) => + complex_binary(dep.unaryMinus(z.re), dep.unaryMinus(z.im)) + +export const conj = (dep: Dependency<'unaryMinus', [T]>) => + (z: Complex) => + complex_binary(z.re, dep.unaryMinus(z.im)) + +export const subtract = (dep: Dependency<'subtract', [T,T]>) => + (w: Complex, z: Complex) => + complex_binary(dep.subtract(w.re, z.re), dep.subtract(w.im, z.im)) + +export const multiply = + (dep: Dependency<'add', [T,T]> + & Dependency<'subtract', [T,T]> + & Dependency<'multiply', [T,T]> + & Dependency<'conj', [T]>) => + (w: Complex, z: Complex) => { + 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) + } + +declare module "../core/Dispatcher" { + interface ImplementationTypes { + add_Complex: typeof add + multiply_Complex: typeof multiply + } +} + +type AbsquareReturns = T extends Complex ? AbsquareReturns : T +export const absquare = + (dep: Dependency<'absquare', [T]> + & Dependency<'add', [AbsquareReturns, AbsquareReturns]>) => + (z: Complex) => dep.add(dep.absquare(z.re), dep.absquare(z.im)) + + +export const reciprocal = + (dep: Dependency<'unaryMinus', [T]> + & Dependency<'absquare', [Complex]> + & Dependency<'divide', [T, T]>) => + (z: Complex) => { + const denom = dep.absquare(z) + return complex_binary( + dep.divide(z.re, denom), dep.divide(dep.unaryMinus(z.im), denom)) + } + +export const divide = + (dep: Dependency<'multiply', [Complex, Complex]> + & Dependency<'reciprocal', [Complex]>) => + (w: Complex, z: Complex) => dep.multiply(w, dep.reciprocal(z)) + +export const sqrt = + (dep: Dependency<'equal', [T,T]> + & Dependency<'add', [T,T]> + & Dependency<'isSquare', [T]> + & Dependency<'zero', [T]> + & Dependency<'sqrt', [T]> + & Dependency<'absquare', [Complex]> + & Dependency<'one', [T]> + & Dependency<'divide', [T,T]> + & Dependency<'subtract', [T,T]> + & Dependency<'unaryMinus', [T]> + ) => + (z: Complex) => { + if (dep.equal(z.re, dep.add(z.re, z.im)) && dep.isSquare(z.re)) { + // imaginary part negligible, just take square root of real part + return complex_binary(dep.sqrt(z.re), dep.zero(z.im)) + } + const myabs = dep.sqrt(dep.absquare(z)) + const real1 = dep.one(z.re) + const real2 = dep.add(real1, real1) + const realQuot = dep.divide(dep.add(myabs, z.re), real2) + const imagQuot = dep.divide(dep.subtract(myabs, z.re), real2) + let realPart = dep.sqrt(realQuot) + if (!(dep.isSquare(z.im))) realPart = dep.unaryMinus(realPart) + return complex_binary(realPart, dep.sqrt(imagQuot)) + } diff --git a/src/Complex/relational.ts b/src/Complex/relational.ts new file mode 100644 index 0000000..573cde9 --- /dev/null +++ b/src/Complex/relational.ts @@ -0,0 +1,6 @@ +import {Complex} from './type.js' +import {Dependency} from '../core/Dispatcher.js' + +export const equal = (dep: Dependency<'equal', [T,T]>) => + (w: Complex, z: Complex) => + dep.equal(w.re, z.re) && dep.equal(w.im, z.im) diff --git a/src/Complex/type.ts b/src/Complex/type.ts index affbedc..3eb17e8 100644 --- a/src/Complex/type.ts +++ b/src/Complex/type.ts @@ -20,3 +20,9 @@ export const Complex_type = { export const complex_unary = (dep: Dependency<'zero', [T]>) => (t: T) => ({re: t, im: dep.zero(t)}) export const complex_binary = (t: T, u: T) => ({re: t, im: u}) + +export const zero = (dep: Dependency<'zero', [T]>) => (z: Complex) => + complex_binary(dep.zero(z.re), dep.zero(z.im)) +export const one = (dep: Dependency<'one', [T]> & Dependency<'zero', [T]>) => + (z: Complex) => + complex_binary(dep.one(z.re), dep.zero(z.im)) diff --git a/src/core/Config.ts b/src/core/Config.ts index 3765328..c1eb24c 100644 --- a/src/core/Config.ts +++ b/src/core/Config.ts @@ -1,4 +1,5 @@ export type Config = { + epsilon: number predictable: boolean } diff --git a/src/numbers/arithmetic.ts b/src/numbers/arithmetic.ts index e78d9ec..c5dff61 100644 --- a/src/numbers/arithmetic.ts +++ b/src/numbers/arithmetic.ts @@ -3,8 +3,11 @@ import {Dependency} from '../core/Dispatcher.js' export const add = (a: number, b: number) => a + b export const unaryMinus = (a: number) => -a +export const conj = (a: number) => a export const subtract = (a: number, b: number) => a - b export const multiply = (a: number, b: number) => a * b +export const absquare = (a: number) => a * a +export const reciprocal = (a: number) => 1 / a export const divide = (a: number, b: number) => a / b export const sqrt = (dep: configDependency diff --git a/src/numbers/predicate.ts b/src/numbers/predicate.ts new file mode 100644 index 0000000..d583559 --- /dev/null +++ b/src/numbers/predicate.ts @@ -0,0 +1 @@ +export const isSquare = (a:number) => a >=0 diff --git a/src/numbers/relational.ts b/src/numbers/relational.ts new file mode 100644 index 0000000..5821ec3 --- /dev/null +++ b/src/numbers/relational.ts @@ -0,0 +1,18 @@ +import {configDependency} from '../core/Config.js' + +const DBL_EPSILON = Number.EPSILON || 2.2204460492503130808472633361816E-16 + +export const equal = (dep: configDependency) => (x: number, y: number) => { + const eps = dep.config.epsilon + if (eps === null || eps === undefined) return x === y + if (x === y) return true + if (isNaN(x) || isNaN(y)) return false + + if (isFinite(x) && isFinite(y)) { + const diff = Math.abs(x - y) + if (diff < DBL_EPSILON) return true + return diff <= Math.max(Math.abs(x), Math.abs(y)) * eps + } + + return false +} diff --git a/src/numbers/type.ts b/src/numbers/type.ts index 67dbd29..26fb798 100644 --- a/src/numbers/type.ts +++ b/src/numbers/type.ts @@ -5,3 +5,4 @@ export const number_type = { } export const zero = (a: number) => 0 +export const one = (a: number) => 0