diff --git a/.gitignore b/.gitignore index 0dc139f..df7c548 100644 --- a/.gitignore +++ b/.gitignore @@ -129,6 +129,9 @@ dist # Stores VSCode versions used for testing VSCode extensions .vscode-test +# Webstiorm +.idea + # yarn v2 .yarn/cache .yarn/unplugged diff --git a/src/Complex/all.ts b/src/Complex/all.ts index b0ec237..3ff6311 100644 --- a/src/Complex/all.ts +++ b/src/Complex/all.ts @@ -1,3 +1,6 @@ import * as Complex from './native.js' +import * as complex from './arithmetic.js' + +export { complex } export {Complex} diff --git a/src/Complex/arithmetic.ts b/src/Complex/arithmetic.ts index 941a654..0987779 100644 --- a/src/Complex/arithmetic.ts +++ b/src/Complex/arithmetic.ts @@ -1,49 +1,54 @@ -import { Complex, complex_binary } from './type.js' +import {Complex, complex_binary, FnComplexUnary} from './type.js' +import type { + FnAbsSquare, + FnAdd, + FnAddReal, + FnConj, FnConservativeSqrt, FnDivide, + FnDivideByReal, FnIsReal, FnIsSquare, + FnMultiply, FnNaN, FnRe, FnReciprocal, FnSqrt, + FnSubtract, + FnUnaryMinus, FnZero +} from '../interfaces/arithmetic' export const add = (dep: { - add: (a: T, b: T) => T - }) => - (w: Complex, z: Complex): Complex => - complex_binary(dep.add(w.re, z.re), dep.add(w.im, z.im)) + add: FnAdd + }): FnAdd> => + (w, z) => complex_binary(dep.add(w.re, z.re), dep.add(w.im, z.im)) export const addReal = (dep: { - addReal: (a: T, b: T) => T - }) => - (z: Complex, r: T): Complex => - complex_binary(dep.addReal(z.re, r), z.im) + addReal: FnAddReal + }): FnAddReal, T> => + (z, r) => complex_binary(dep.addReal(z.re, r), z.im) export const unaryMinus = (dep: { - unaryMinus: (z: T) => T - }) => - (z: Complex): Complex => - complex_binary(dep.unaryMinus(z.re), dep.unaryMinus(z.im)) + unaryMinus: FnUnaryMinus + }): FnUnaryMinus> => + (z) => complex_binary(dep.unaryMinus(z.re), dep.unaryMinus(z.im)) export const conj = (dep: { - unaryMinus: (z: T) => T, - conj: (z: T) => T - }) => - (z: Complex): Complex => - complex_binary(dep.conj(z.re), dep.unaryMinus(z.im)) + unaryMinus: FnUnaryMinus, + conj: FnConj + }) : FnConj> => + (z) => complex_binary(dep.conj(z.re), dep.unaryMinus(z.im)) export const subtract = (dep: { - subtract: (a: T, b: T) => T - }) => - (w: Complex, z: Complex): Complex => - complex_binary(dep.subtract(w.re, z.re), dep.subtract(w.im, z.im)) + subtract: FnSubtract + }): FnSubtract> => + (w, z) => complex_binary(dep.subtract(w.re, z.re), dep.subtract(w.im, z.im)) export const multiply = (dep: { - add: (a: T, b: T) => T, - subtract: (a: T, b: T) => T, - multiply: (a: T, b: T) => T, - conj: (z: T) => T + add: FnAdd, + subtract: FnSubtract, + multiply: FnMultiply, + conj: FnConj }) => - (w: Complex, z: Complex): Complex => { + (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)) @@ -52,44 +57,42 @@ export const multiply = export const absquare = (dep: { - add: (a: T, b: T) => T, - absquare: (z: T) => T - }) => - (z: Complex): T => dep.add(dep.absquare(z.re), dep.absquare(z.im)) + add: FnAdd, + absquare: FnAbsSquare + }): FnAbsSquare, T> => + (z) => dep.add(dep.absquare(z.re), dep.absquare(z.im)) export const divideByReal = (dep: { - divideByReal: (a: T, b: T) => T - }) => - (z: Complex, r: T) => - complex_binary(dep.divideByReal(z.re, r), dep.divideByReal(z.im, r)) + divideByReal: FnDivideByReal + }): FnDivideByReal, T> => + (z, r) => complex_binary(dep.divideByReal(z.re, r), dep.divideByReal(z.im, r)) export const reciprocal = (dep: { - conj: (z: Complex) => Complex, - absquare: (z: Complex) => T, - divideByReal: (a: Complex, b: T) => Complex, - zero: (z: T) => T, - }) => - (z: Complex): Complex => dep.divideByReal(dep.conj(z), dep.absquare(z)) + conj: FnConj>, + absquare: FnAbsSquare, T>, + divideByReal: FnDivideByReal, T> + }): FnReciprocal> => + (z) => dep.divideByReal(dep.conj(z), dep.absquare(z)) export const divide = (dep: { - multiply: (a: Complex, b: Complex) => Complex, - reciprocal: (z: Complex) => Complex, - }) => - (w: Complex, z: Complex) => dep.multiply(w, dep.reciprocal(z)) + multiply: FnMultiply>, + reciprocal: FnReciprocal>, + }): FnDivide> => + (w, z) => dep.multiply(w, dep.reciprocal(z)) export const complexSqrt = (dep: { - conservativeSqrt: (a: T) => T, - isSquare: (a: T) => boolean, - complex: (a: T) => Complex, - unaryMinus: (a: T) => T, - zero: (a: T) => T, - nan: (a: Complex) => Complex + conservativeSqrt: FnConservativeSqrt, + isSquare: FnIsSquare, + complex: FnComplexUnary, + unaryMinus: FnUnaryMinus, + zero: FnZero, + nan: FnNaN> }) => - (r: T): Complex => { + (r) => { if (dep.isSquare(r)) return dep.complex(dep.conservativeSqrt(r)) const negative = dep.unaryMinus(r) if (dep.isSquare(negative)) { @@ -104,17 +107,16 @@ export const complexSqrt = export const sqrt = (dep: { - isReal: (z: Complex) => boolean, - complexSqrt: (a: T) => Complex, - conservativeSqrt: (a: T) => T, - absquare: (a: Complex) => T, - addReal: (a: Complex, b: T) => Complex, - divideByReal: (a: Complex, b: T) => Complex, - add: (a: T, b: T) => T, - re: (a: Complex) => T, - + isReal: FnIsReal>, + complexSqrt: FnSqrt, + conservativeSqrt: FnConservativeSqrt, + absquare: FnAbsSquare, T>, + addReal: FnAddReal, T>, + divideByReal: FnDivideByReal, T>, + add: FnAdd, + re: FnRe, T>, }) => - (z: Complex) => { + (z: Complex): Complex | T => { if (dep.isReal(z)) return dep.complexSqrt(z.re) const myabs = dep.conservativeSqrt(dep.absquare(z)) const num = dep.addReal(z, myabs) diff --git a/src/Complex/predicate.ts b/src/Complex/predicate.ts index 47365fb..557ea83 100644 --- a/src/Complex/predicate.ts +++ b/src/Complex/predicate.ts @@ -1,12 +1,14 @@ import { Complex } from './type.js' +import {FnEqual} from '../interfaces/relational' +import {FnAdd, FnIsReal, FnIsSquare} from '../interfaces/arithmetic' export const isReal = (dep: { - equal: (a: T, b: T) => boolean, - add: (a: T, b: T) => T, - isReal: (z: T) => boolean - }) => - (z: Complex) => dep.isReal(z.re) && dep.equal(z.re, dep.add(z.re, z.im)) + equal: FnEqual, + add: FnAdd, + isReal: FnIsReal + }): FnIsReal> => + (z) => dep.isReal(z.re) && dep.equal(z.re, dep.add(z.re, z.im)) export const isSquare = - (z: Complex) => true // FIXME: not correct for Complex once we get there + (): FnIsSquare> => (z) => true // FIXME: not correct for Complex once we get there diff --git a/src/Complex/relational.ts b/src/Complex/relational.ts index 2621972..9807d71 100644 --- a/src/Complex/relational.ts +++ b/src/Complex/relational.ts @@ -1,7 +1,8 @@ import { Complex } from './type.js' +import {FnEqual} from '../interfaces/relational' export const equal = (dep: { - equal: (a: T, b: T) => boolean - }) => - (w: Complex, z: Complex): boolean => dep.equal(w.re, z.re) && dep.equal(w.im, z.im) + equal: FnEqual + }): FnEqual> => + (w, z) => 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 50a231f..3b4e82d 100644 --- a/src/Complex/type.ts +++ b/src/Complex/type.ts @@ -1,6 +1,7 @@ import { joinTypes, typeOfDependency, Dependency, } from '../core/Dispatcher.js' +import type {FnNaN, FnOne, FnRe, FnZero} from '../interfaces/arithmetic.js' export type Complex = { re: T; im: T; } @@ -8,7 +9,7 @@ export const Complex_type = { test: (dep: { testT: (z: unknown) => z is T }) => (z: unknown): z is Complex => typeof z === 'object' && z != null && 're' in z && 'im' in z - && dep.testT(z.re) && dep.testT(z.im), + && dep.testT(z['re']) && dep.testT(z['im']), infer: (dep: typeOfDependency) => (z: Complex) => joinTypes(dep.typeOf(z.re), dep.typeOf(z.im)), from: { @@ -19,36 +20,39 @@ export const Complex_type = { } } +export type FnComplexUnary = (t: T) => Complex + export const complex_unary = (dep: { - zero: (z: T) => Complex - }) => - (t: T) => ({ re: t, im: dep.zero(t) }) + zero: FnZero + }): FnComplexUnary => + (t) => ({ re: t, im: dep.zero(t) }) -export const complex_binary = - (t: T, u: T): Complex => ({ re: t, im: u }) +export type FnComplexBinary = (re: T, im: T) => Complex + +export const complex_binary = (t: T, u: T): Complex => ({ re: t, im: u }) export const zero = (dep: { - zero: (z: T) => T - }) => - (z: Complex): Complex => complex_binary(dep.zero(z.re), dep.zero(z.im)) + zero: FnZero + }): FnZero> => + (z) => complex_binary(dep.zero(z.re), dep.zero(z.im)) export const one = (dep: { - zero: (z: T) => T, - one: (z: T) => T - }) => - (z: Complex): Complex => complex_binary(dep.one(z.re), dep.zero(z.im)) + zero: FnZero, + one: FnOne + }): FnOne> => + (z) => complex_binary(dep.one(z.re), dep.zero(z.im)) export const nan = (dep: { - nan: (z: T) => T - }) => - (z: Complex): Complex => complex_binary(dep.nan(z.re), dep.nan(z.im)) + nan: FnNaN + }): FnNaN> => + (z) => complex_binary(dep.nan(z.re), dep.nan(z.im)) export const re = (dep: { - re: (z: T) => T - }) => - (z: Complex): T => dep.re(z.re) + re: FnRe + }): FnRe, T> => + (z) => dep.re(z.re) diff --git a/src/generic/arithmetic.ts b/src/generic/arithmetic.ts index 99a7aab..a1379df 100644 --- a/src/generic/arithmetic.ts +++ b/src/generic/arithmetic.ts @@ -1,5 +1,7 @@ +import type { FnMultiply, FnSquare } from "../interfaces/arithmetic" + export const square = (dep: { - multiply: (x: T, y: T) => T - }) => - (z: T): T => dep.multiply(z, z) + multiply: FnMultiply + }): FnSquare => + (z) => dep.multiply(z, z) diff --git a/src/interfaces/arithmetic.ts b/src/interfaces/arithmetic.ts new file mode 100644 index 0000000..91b59bf --- /dev/null +++ b/src/interfaces/arithmetic.ts @@ -0,0 +1,28 @@ +// shared interfaces + +import { Complex } from "../Complex/type" + +// Note: right now I've added an 'Fn*' prefix, +// so it is clear that the type hold a function type definition +// This is not necessary though, it is just a naming convention. +export type FnAdd = (a: T, b: T) => T +export type FnAddReal = (a: T, b: U) => T +export type FnUnaryMinus = (a: T) => T +export type FnConj = (a: T) => T +export type FnSubtract = (a: T, b: T) => T +export type FnMultiply = (a: T, b: T) => T +export type FnAbsSquare = (a: T) => U +export type FnReciprocal = (a: T) => T +export type FnDivide = (a: T, b: T) => T +export type FnDivideByReal = (a: T, b: U) => T +export type FnConservativeSqrt = (a: T) => T +export type FnSqrt = (a: T) => T | Complex +export type FnSquare = (z: T) => T + +export type FnIsReal = (a: T) => boolean +export type FnIsSquare = (a: T) => boolean + +export type FnZero = (a: T) => T +export type FnOne = (a: T) => T +export type FnNaN = (a: T) => T +export type FnRe = (a: T) => U diff --git a/src/interfaces/relational.ts b/src/interfaces/relational.ts new file mode 100644 index 0000000..2865f77 --- /dev/null +++ b/src/interfaces/relational.ts @@ -0,0 +1,3 @@ + +export type FnEqual = (a: T, b: T) => boolean +export type FnUnequal = (a: T, b: T) => boolean diff --git a/src/numbers/arithmetic.ts b/src/numbers/arithmetic.ts index 499a942..7142797 100644 --- a/src/numbers/arithmetic.ts +++ b/src/numbers/arithmetic.ts @@ -1,24 +1,25 @@ import { Config } from '../core/Config.js' -import type { Complex } from '../Complex/type.js' +import type { FnComplexBinary } from '../Complex/type.js' +import { FnAdd, FnConj, FnSubtract, FnUnaryMinus, FnMultiply, FnAbsSquare, FnReciprocal, FnDivide, FnConservativeSqrt, FnSqrt } from '../interfaces/arithmetic.js' -export const add = (a: number, b: number): number => a + b +export const add: FnAdd = (a, b) => a + b export const addReal = add -export const unaryMinus = (a: number): number => -a -export const conj = (a: number): number => a -export const subtract = (a: number, b: number): number => a - b -export const multiply = (a: number, b: number): number => a * b -export const absquare = (a: number): number => a * a -export const reciprocal = (a: number): number => 1 / a -export const divide = (a: number, b: number): number => a / b +export const unaryMinus: FnUnaryMinus = (a) => -a +export const conj: FnConj = (a) => a +export const subtract: FnSubtract = (a, b) => a - b +export const multiply: FnMultiply = (a, b) => a * b +export const absquare: FnAbsSquare = (a) => a * a +export const reciprocal: FnReciprocal = (a) => 1 / a +export const divide: FnDivide = (a, b) => a / b export const divideByReal = divide -export const conservativeSqrt = (a: number): number => isNaN(a) ? NaN : Math.sqrt(a) +export const conservativeSqrt: FnConservativeSqrt = (a) => isNaN(a) ? NaN : Math.sqrt(a) export const sqrt = (dep: { config: Config, - complex: (re: number, im: number) => Complex - }): (a: number) => number | Complex => { + complex: FnComplexBinary + }): FnSqrt => { if (dep.config.predictable || !dep.complex) return conservativeSqrt return a => { if (isNaN(a)) return NaN diff --git a/src/numbers/predicate.ts b/src/numbers/predicate.ts index 483b103..4015c55 100644 --- a/src/numbers/predicate.ts +++ b/src/numbers/predicate.ts @@ -1,2 +1,4 @@ -export const isReal = (a: number) : boolean => true -export const isSquare = (a: number) : boolean => a >= 0 +import type { FnIsReal, FnIsSquare } from "../interfaces/arithmetic" + +export const isReal: FnIsReal = (a) => true +export const isSquare: FnIsSquare = (a) => a >= 0 diff --git a/src/numbers/relational.ts b/src/numbers/relational.ts index dac949a..ae9a63d 100644 --- a/src/numbers/relational.ts +++ b/src/numbers/relational.ts @@ -1,11 +1,12 @@ import { Config } from '../core/Config.js' +import type { FnEqual, FnUnequal } from '../interfaces/relational.js' const DBL_EPSILON = Number.EPSILON || 2.2204460492503130808472633361816E-16 export const equal = (dep: { config: Config - }) => (x: number, y: number): boolean => { + }): FnEqual => (x, y) => { const eps = dep.config.epsilon if (eps === null || eps === undefined) return x === y if (x === y) return true @@ -21,6 +22,6 @@ export const equal = } export const unequal = (dep: { - equal: (x: number, y: number) => boolean -}) => - (x: number, y: number): boolean => !dep.equal(x, y) + equal: FnEqual +}): FnUnequal => + (x, y) => !dep.equal(x, y) diff --git a/src/numbers/type.ts b/src/numbers/type.ts index 46fbf6f..77336ef 100644 --- a/src/numbers/type.ts +++ b/src/numbers/type.ts @@ -1,10 +1,12 @@ +import type { FnNaN, FnOne, FnZero, FnRe } from "../interfaces/arithmetic" + export const number_type = { before: ['Complex'], test: (n: unknown): n is number => typeof n === 'number', from: { string: (s: string) => +s } } -export const zero = (a: number): number => 0 -export const one = (a: number): number => 1 -export const nan = (a: number): number => NaN -export const re = (a: number): number => a +export const zero: FnZero = (a) => 0 +export const one: FnOne = (a) => 1 +export const nan: FnNaN = (a) => NaN +export const re: FnRe = (a) => a