Declare implementations and dependencies via standard interfaces for operations #8
@ -1,129 +1,120 @@
|
||||
import {Complex, complex_binary, FnComplexUnary} from './type.js'
|
||||
import {Complex, ComplexOp} 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'
|
||||
AbsquareOp, AddOp, AddRealOp, ConjOp, ConservativeSqrtOp, DivideOp,
|
||||
DivideByRealOp, MultiplyOp, ReciprocalOp, SqrtOp, SubtractOp,
|
||||
UnaryMinusOp
|
||||
} from '../interfaces/arithmetic.js'
|
||||
import type {
|
||||
NanOp, ReOp, ZeroOp, Depends, RealType, WithConstants, NaNType
|
||||
} from '../interfaces/type.js'
|
||||
import type {IsSquareOp, IsRealOp} from '../interfaces/predicate.js'
|
||||
|
||||
export const add =
|
||||
<T>(dep: {
|
||||
add: FnAdd<T>
|
||||
}): FnAdd<Complex<T>> =>
|
||||
(w, z) => complex_binary(dep.add(w.re, z.re), dep.add(w.im, z.im))
|
||||
<T>(dep: Depends<AddOp<T>> & Depends<ComplexOp<T>>): AddOp<Complex<T>> =>
|
||||
(w, z) => dep.complex(dep.add(w.re, z.re), dep.add(w.im, z.im))
|
||||
|
||||
export const addReal =
|
||||
<T>(dep: {
|
||||
addReal: FnAddReal<T, T>
|
||||
}): FnAddReal<Complex<T>, T> =>
|
||||
(z, r) => complex_binary(dep.addReal(z.re, r), z.im)
|
||||
<T>(dep: Depends<AddRealOp<T>> & Depends<ComplexOp<T>>):
|
||||
AddRealOp<Complex<T>> =>
|
||||
(z, r) => dep.complex(dep.addReal(z.re, r), z.im)
|
||||
|
||||
export const unaryMinus =
|
||||
<T>(dep: {
|
||||
unaryMinus: FnUnaryMinus<T>
|
||||
}): FnUnaryMinus<Complex<T>> =>
|
||||
(z) => complex_binary(dep.unaryMinus(z.re), dep.unaryMinus(z.im))
|
||||
<T>(dep: Depends<UnaryMinusOp<T>> & Depends<ComplexOp<T>>):
|
||||
UnaryMinusOp<Complex<T>> =>
|
||||
z => dep.complex(dep.unaryMinus(z.re), dep.unaryMinus(z.im))
|
||||
|
||||
export const conj =
|
||||
<T>(dep: {
|
||||
unaryMinus: FnUnaryMinus<T>,
|
||||
conj: FnConj<T>
|
||||
}) : FnConj<Complex<T>> =>
|
||||
(z) => complex_binary(dep.conj(z.re), dep.unaryMinus(z.im))
|
||||
<T>(dep: Depends<UnaryMinusOp<T>>
|
||||
& Depends<ConjOp<T>>
|
||||
& Depends<ComplexOp<T>>):
|
||||
ConjOp<Complex<T>> =>
|
||||
z => dep.complex(dep.conj(z.re), dep.unaryMinus(z.im))
|
||||
|
||||
export const subtract =
|
||||
<T>(dep: {
|
||||
subtract: FnSubtract<T>
|
||||
}): FnSubtract<Complex<T>> =>
|
||||
(w, z) => complex_binary(dep.subtract(w.re, z.re), dep.subtract(w.im, z.im))
|
||||
<T>(dep: Depends<SubtractOp<T>> & Depends<ComplexOp<T>>):
|
||||
SubtractOp<Complex<T>> =>
|
||||
(w, z) => dep.complex(dep.subtract(w.re, z.re), dep.subtract(w.im, z.im))
|
||||
|
||||
export const multiply =
|
||||
<T>(dep: {
|
||||
add: FnAdd<T>,
|
||||
subtract: FnSubtract<T>,
|
||||
multiply: FnMultiply<T>,
|
||||
conj: FnConj<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)
|
||||
}
|
||||
<T>(dep: Depends<AddOp<T>>
|
||||
& Depends<SubtractOp<T>>
|
||||
& Depends<MultiplyOp<T>>
|
||||
& Depends<ConjOp<T>>
|
||||
& Depends<ComplexOp<T>>):
|
||||
MultiplyOp<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 dep.complex(realpart, imagpart)
|
||||
}
|
||||
|
||||
export const absquare =
|
||||
<T, U>(dep: {
|
||||
add: FnAdd<U>,
|
||||
absquare: FnAbsSquare<T, U>
|
||||
}): FnAbsSquare<Complex<T>, U> =>
|
||||
(z) => dep.add(dep.absquare(z.re), dep.absquare(z.im))
|
||||
<T>(dep: Depends<AddOp<RealType<T>>> & Depends<AbsquareOp<T>>):
|
||||
AbsquareOp<Complex<T>> =>
|
||||
z => dep.add(dep.absquare(z.re), dep.absquare(z.im))
|
||||
|
||||
export const divideByReal =
|
||||
<T>(dep: {
|
||||
divideByReal: FnDivideByReal<T, T>
|
||||
}): FnDivideByReal<Complex<T>, T> =>
|
||||
(z, r) => complex_binary(dep.divideByReal(z.re, r), dep.divideByReal(z.im, r))
|
||||
<T>(dep: Depends<DivideByRealOp<T>> & Depends<ComplexOp<T>>):
|
||||
DivideByRealOp<Complex<T>> =>
|
||||
(z, r) => dep.complex(dep.divideByReal(z.re, r), dep.divideByReal(z.im, r))
|
||||
|
||||
export const reciprocal =
|
||||
<T>(dep: {
|
||||
conj: FnConj<Complex<T>>,
|
||||
absquare: FnAbsSquare<Complex<T>, T>,
|
||||
divideByReal: FnDivideByReal<Complex<T>, T>
|
||||
}): FnReciprocal<Complex<T>> =>
|
||||
(z) => dep.divideByReal(dep.conj(z), dep.absquare(z))
|
||||
<T>(dep: Depends<ConjOp<Complex<T>>>
|
||||
& Depends<AbsquareOp<Complex<T>>>
|
||||
& Depends<DivideByRealOp<Complex<T>>>):
|
||||
ReciprocalOp<Complex<T>> =>
|
||||
z => dep.divideByReal(dep.conj(z), dep.absquare(z))
|
||||
|
||||
export const divide =
|
||||
<T>(dep: {
|
||||
multiply: FnMultiply<Complex<T>>,
|
||||
reciprocal: FnReciprocal<Complex<T>>,
|
||||
}): FnDivide<Complex<T>> =>
|
||||
(w, z) => dep.multiply(w, dep.reciprocal(z))
|
||||
<T>(dep: Depends<MultiplyOp<Complex<T>>>
|
||||
& Depends<ReciprocalOp<Complex<T>>>):
|
||||
DivideOp<Complex<T>> =>
|
||||
(w, z) => dep.multiply(w, dep.reciprocal(z))
|
||||
|
||||
export type ComplexSqrtOp<T> = {
|
||||
op?: 'complexSqrt',
|
||||
(a: T): Complex<WithConstants<T> | NaNType<WithConstants<T>>>
|
||||
}
|
||||
// Complex square root of a real type T
|
||||
export const complexSqrt =
|
||||
<T>(dep: {
|
||||
conservativeSqrt: FnConservativeSqrt<T>,
|
||||
isSquare: FnIsSquare<T>,
|
||||
complex: FnComplexUnary<T>,
|
||||
unaryMinus: FnUnaryMinus<T>,
|
||||
zero: FnZero<T>,
|
||||
nan: FnNaN<Complex<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))
|
||||
<T>(dep: Depends<ConservativeSqrtOp<T>>
|
||||
& Depends<IsSquareOp<T>>
|
||||
& Depends<UnaryMinusOp<T>>
|
||||
& Depends<ComplexOp<WithConstants<T>>>
|
||||
& Depends<ZeroOp<T>>
|
||||
& Depends<NanOp<Complex<WithConstants<T>>>>): ComplexSqrtOp<T> =>
|
||||
r => {
|
||||
if (dep.isSquare(r)) return dep.complex(dep.conservativeSqrt(r))
|
||||
const negative = dep.unaryMinus(r)
|
||||
if (dep.isSquare(negative)) {
|
||||
return dep.complex(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: FnIsReal<Complex<T>>,
|
||||
complexSqrt: FnSqrt<T>,
|
||||
conservativeSqrt: FnConservativeSqrt<T>,
|
||||
absquare: FnAbsSquare<Complex<T>, T>,
|
||||
addReal: FnAddReal<Complex<T>, T>,
|
||||
divideByReal: FnDivideByReal<Complex<T>, T>,
|
||||
add: FnAdd<T>,
|
||||
re: FnRe<Complex<T>, T>,
|
||||
}) =>
|
||||
(z: Complex<T>): Complex<T> | 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)
|
||||
}
|
||||
<T>(dep: Depends<IsRealOp<Complex<T>>>
|
||||
& Depends<ComplexSqrtOp<T>>
|
||||
& Depends<ConservativeSqrtOp<RealType<T>>>
|
||||
& Depends<AbsquareOp<Complex<T>>>
|
||||
& Depends<AddRealOp<Complex<T>>>
|
||||
& Depends<DivideByRealOp<Complex<T>>>
|
||||
& Depends<AddOp<RealType<T>>>
|
||||
& Depends<ReOp<Complex<T>>>): SqrtOp<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
|
||||
|
@ -1,14 +1,12 @@
|
||||
import { Complex } from './type.js'
|
||||
import {FnEqual} from '../interfaces/relational'
|
||||
import {FnAdd, FnIsReal, FnIsSquare} from '../interfaces/arithmetic'
|
||||
import {Complex} from './type.js'
|
||||
import {EqualOp} from '../interfaces/relational.js'
|
||||
import {AddOp} from '../interfaces/arithmetic.js'
|
||||
import type {Depends} from '../interfaces/type.js'
|
||||
import type {IsRealOp, IsSquareOp} from '../interfaces/predicate.js'
|
||||
|
||||
export const isReal =
|
||||
<T>(dep: {
|
||||
equal: FnEqual<T>,
|
||||
add: FnAdd<T>,
|
||||
isReal: FnIsReal<T>
|
||||
}): FnIsReal<Complex<T>> =>
|
||||
(z) => dep.isReal(z.re) && dep.equal(z.re, dep.add(z.re, z.im))
|
||||
<T>(dep: Depends<AddOp<T>> & Depends<EqualOp<T>> & Depends<IsRealOp<T>>):
|
||||
IsRealOp<Complex<T>> =>
|
||||
z => dep.isReal(z.re) && dep.equal(z.re, dep.add(z.re, z.im))
|
||||
|
||||
export const isSquare =
|
||||
<T>(): FnIsSquare<Complex<T>> => (z) => true // FIXME: not correct for Complex<bigint> once we get there
|
||||
export const isSquare: IsSquareOp<Complex<any>> = z => true // FIXME: not correct for Complex<bigint> once we get there
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { Complex } from './type.js'
|
||||
import {FnEqual} from '../interfaces/relational'
|
||||
import {Complex} from './type.js'
|
||||
import {Depends} from '../interfaces/type.js'
|
||||
import {EqualOp} from '../interfaces/relational.js'
|
||||
|
||||
export const equal =
|
||||
<T>(dep: {
|
||||
equal: FnEqual<T>
|
||||
}): FnEqual<Complex<T>> =>
|
||||
(w, z) => dep.equal(w.re, z.re) && dep.equal(w.im, z.im)
|
||||
<T>(dep: Depends<EqualOp<T>>): EqualOp<Complex<T>> =>
|
||||
(w, z) => dep.equal(w.re, z.re) && dep.equal(w.im, z.im)
|
||||
|
@ -1,7 +1,9 @@
|
||||
import {
|
||||
joinTypes, typeOfDependency, Dependency,
|
||||
} from '../core/Dispatcher.js'
|
||||
import type {FnNaN, FnOne, FnRe, FnZero} from '../interfaces/arithmetic.js'
|
||||
import type {
|
||||
OneOp, ZeroOp, NanOp, ReOp, ZeroType, OneType, NaNType, Depends
|
||||
} from '../interfaces/type.js'
|
||||
|
||||
export type Complex<T> = { re: T; im: T; }
|
||||
|
||||
@ -20,39 +22,41 @@ export const Complex_type = {
|
||||
}
|
||||
}
|
||||
|
||||
export type FnComplexUnary<T> = (t: T) => Complex<T>
|
||||
declare module "../interfaces/type" {
|
||||
interface AssociatedTypes<T> {
|
||||
Complex: T extends Complex<infer R> ? {
|
||||
type: Complex<R>
|
||||
zero: Complex<ZeroType<R>>
|
||||
one: Complex<OneType<R> | ZeroType<R>>
|
||||
nan: Complex<NaNType<R>>
|
||||
real: RealType<R>
|
||||
} : never
|
||||
}
|
||||
}
|
||||
|
||||
export const complex_unary =
|
||||
<T>(dep: {
|
||||
zero: FnZero<T>
|
||||
}): FnComplexUnary<T> =>
|
||||
(t) => ({ re: t, im: dep.zero(t) })
|
||||
export type ComplexOp<T> = {op?: 'complex', (a: T, b?: T): Complex<T>}
|
||||
|
||||
export type FnComplexBinary<T> = (re: T, im: T) => Complex<T>
|
||||
|
||||
export const complex_binary = <T>(t: T, u: T): Complex<T> => ({ re: t, im: u })
|
||||
export const complex =
|
||||
<T>(dep: Depends<ZeroOp<T>>): ComplexOp<T | ZeroType<T>> =>
|
||||
(a, b) => ({re: a, im: b || dep.zero(a)})
|
||||
|
||||
export const zero =
|
||||
<T>(dep: {
|
||||
zero: FnZero<T>
|
||||
}): FnZero<Complex<T>> =>
|
||||
(z) => complex_binary(dep.zero(z.re), dep.zero(z.im))
|
||||
<T>(dep: Depends<ZeroOp<T>> & Depends<ComplexOp<ZeroType<T>>>):
|
||||
ZeroOp<Complex<T>> =>
|
||||
z => dep.complex(dep.zero(z.re), dep.zero(z.im))
|
||||
|
||||
export const one =
|
||||
<T>(dep: {
|
||||
zero: FnZero<T>,
|
||||
one: FnOne<T>
|
||||
}): FnOne<Complex<T>> =>
|
||||
(z) => complex_binary(dep.one(z.re), dep.zero(z.im))
|
||||
<T>(dep: Depends<OneOp<T>>
|
||||
& Depends<ZeroOp<T>>
|
||||
& Depends<ComplexOp<ZeroType<T>|OneType<T>>>):
|
||||
OneOp<Complex<T>> =>
|
||||
z => dep.complex(dep.one(z.re), dep.zero(z.im))
|
||||
|
||||
export const nan =
|
||||
<T>(dep: {
|
||||
nan: FnNaN<T>
|
||||
}): FnNaN<Complex<T>> =>
|
||||
(z) => complex_binary(dep.nan(z.re), dep.nan(z.im))
|
||||
<T>(dep: Depends<NanOp<T>> & Depends<ComplexOp<NaNType<T>>>):
|
||||
NanOp<Complex<T>> =>
|
||||
z => dep.complex(dep.nan(z.re), dep.nan(z.im))
|
||||
|
||||
export const re =
|
||||
<T>(dep: {
|
||||
re: FnRe<T,T>
|
||||
}): FnRe<Complex<T>, T> =>
|
||||
(z) => dep.re(z.re)
|
||||
<T>(dep: Depends<ReOp<T>>): ReOp<Complex<T>> =>
|
||||
z => dep.re(z.re)
|
||||
|
@ -1,3 +1 @@
|
||||
import * as generic from './arithmetic.js'
|
||||
|
||||
export { generic }
|
||||
export * as generic from './native.js'
|
||||
|
@ -1,7 +1,6 @@
|
||||
import type { FnMultiply, FnSquare } from "../interfaces/arithmetic"
|
||||
import type {Depends} from '../interfaces/type.js'
|
||||
import type {MultiplyOp, SquareOp} from '../interfaces/arithmetic.js'
|
||||
|
||||
export const square =
|
||||
<T>(dep: {
|
||||
multiply: FnMultiply<T>
|
||||
}): FnSquare<T> =>
|
||||
(z) => dep.multiply(z, z)
|
||||
<T>(dep: Depends<MultiplyOp<T>>): SquareOp<T> =>
|
||||
z => dep.multiply(z, z)
|
||||
|
2
src/generic/native.ts
Normal file
2
src/generic/native.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './arithmetic.js'
|
||||
export * from './relational.js'
|
5
src/generic/relational.ts
Normal file
5
src/generic/relational.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import {Depends} from '../interfaces/type.js'
|
||||
import type {EqualOp, UnequalOp} from '../interfaces/relational.js'
|
||||
|
||||
export const unequal = <T>(dep: Depends<EqualOp<T>>): UnequalOp<T> =>
|
||||
(x, y) => !dep.equal(x, y)
|
@ -1,28 +1,25 @@
|
||||
// shared interfaces
|
||||
import type {Complex} from '../Complex/type.js'
|
||||
import type {RealType, WithConstants, NaNType} from './type.js'
|
||||
|
||||
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
|
||||
// Note: right now I've added an 'Op' suddix,
|
||||
// so it is clear that the type holds the function type of an operation
|
||||
// This is not necessary though, it is just a naming convention.
|
||||
export type FnAdd<T> = (a: T, b: T) => T
|
||||
export type FnAddReal<T, U> = (a: T, b: U) => T
|
||||
export type FnUnaryMinus<T> = (a: T) => T
|
||||
export type FnConj<T> = (a: T) => T
|
||||
export type FnSubtract<T> = (a: T, b: T) => T
|
||||
export type FnMultiply<T> = (a: T, b: T) => T
|
||||
export type FnAbsSquare<T, U> = (a: T) => U
|
||||
export type FnReciprocal<T> = (a: T) => T
|
||||
export type FnDivide<T> = (a: T, b: T) => T
|
||||
export type FnDivideByReal<T, U> = (a: T, b: U) => T
|
||||
export type FnConservativeSqrt<T> = (a: T) => T
|
||||
export type FnSqrt<T> = (a: T) => T | Complex<T>
|
||||
export type FnSquare<T> = (z: T) => T
|
||||
export type AddOp<T> = {op?: 'add', (a: T, b: T): T}
|
||||
export type AddRealOp<T> = {op?: 'addReal', (a: T, b: RealType<T>): T}
|
||||
export type UnaryMinusOp<T> = {op?: 'unaryMinus', (a: T): T}
|
||||
export type ConjOp<T> = {op?: 'conj', (a: T): T}
|
||||
export type SubtractOp<T> = {op?: 'subtract', (a: T, b: T): T}
|
||||
export type MultiplyOp<T> = {op?: 'multiply', (a: T, b: T): T}
|
||||
export type AbsquareOp<T> = {op?: 'absquare', (a: T): RealType<T>}
|
||||
export type ReciprocalOp<T> = {op?: 'reciprocal', (a: T): T}
|
||||
export type DivideOp<T> = {op?: 'divide', (a: T, b: T): T}
|
||||
export type DivideByRealOp<T> = {op?: 'divideByReal', (a: T, b: RealType<T>): T}
|
||||
export type ConservativeSqrtOp<T> = {op?: 'conservativeSqrt', (a: T): T}
|
||||
export type SqrtOp<T> = {
|
||||
op?: 'sqrt',
|
||||
(a: T): T extends Complex<infer R>
|
||||
? Complex<WithConstants<R> | NaNType<WithConstants<R>>>
|
||||
: T | Complex<T>
|
||||
}
|
||||
export type SquareOp<T> = {op?: 'square', (z: T): T}
|
||||
|
||||
export type FnIsReal<T> = (a: T) => boolean
|
||||
export type FnIsSquare<T> = (a: T) => boolean
|
||||
|
||||
export type FnZero<T> = (a: T) => T
|
||||
export type FnOne<T> = (a: T) => T
|
||||
export type FnNaN<T> = (a: T) => T
|
||||
export type FnRe<T, U> = (a: T) => U
|
||||
|
2
src/interfaces/predicate.ts
Normal file
2
src/interfaces/predicate.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export type IsRealOp<T> = {op?: 'isReal', (a: T): boolean}
|
||||
export type IsSquareOp<T> = {op?: 'isSquare', (a: T): boolean}
|
@ -1,3 +1,2 @@
|
||||
|
||||
export type FnEqual<T> = (a: T, b: T) => boolean
|
||||
export type FnUnequal<T> = (a: T, b: T) => boolean
|
||||
export type EqualOp<T> = {op?: 'equal', (a: T, b: T): boolean}
|
||||
export type UnequalOp<T> = {op?: 'unequal', (a: T, b: T): boolean}
|
||||
|
32
src/interfaces/type.ts
Normal file
32
src/interfaces/type.ts
Normal file
@ -0,0 +1,32 @@
|
||||
export interface AssociatedTypes<T> {
|
||||
undefined: {
|
||||
type: undefined
|
||||
zero: undefined
|
||||
one: undefined
|
||||
nan: undefined
|
||||
real: undefined
|
||||
}
|
||||
}
|
||||
|
||||
type AssociatedTypeNames = keyof AssociatedTypes<unknown>['undefined']
|
||||
export type Lookup<T, Name extends AssociatedTypeNames> = {
|
||||
[K in keyof AssociatedTypes<T>]:
|
||||
T extends AssociatedTypes<T>[K]['type'] ? AssociatedTypes<T>[K][Name] : never
|
||||
}[keyof AssociatedTypes<T>]
|
||||
|
||||
export type ZeroType<T> = Lookup<T, 'zero'>
|
||||
export type OneType<T> = Lookup<T, 'one'>
|
||||
export type WithConstants<T> = T | ZeroType<T> | OneType<T>
|
||||
export type NaNType<T> = Lookup<T, 'nan'>
|
||||
export type RealType<T> = Lookup<T, 'real'>
|
||||
|
||||
export type ZeroOp<T> = {op?: 'zero', (a: WithConstants<T>): ZeroType<T>}
|
||||
export type OneOp<T> = {op?: 'one', (a: WithConstants<T>): OneType<T>}
|
||||
export type NanOp<T> = {op?: 'nan', (a: T|NaNType<T>): NaNType<T>}
|
||||
export type ReOp<T> = {op?: 're', (a: T): RealType<T>}
|
||||
|
||||
type NamedFunction = {op?: string, (...params: any[]): any}
|
||||
export type Depends<FuncType extends NamedFunction> =
|
||||
{[K in FuncType['op']]: FuncType}
|
||||
|
||||
|
@ -1,26 +1,28 @@
|
||||
import { Config } from '../core/Config.js'
|
||||
import type { FnComplexBinary } from '../Complex/type.js'
|
||||
import { FnAdd, FnConj, FnSubtract, FnUnaryMinus, FnMultiply, FnAbsSquare, FnReciprocal, FnDivide, FnConservativeSqrt, FnSqrt } from '../interfaces/arithmetic.js'
|
||||
import type {configDependency} from '../core/Config.js'
|
||||
import type {ComplexOp} from '../Complex/type.js'
|
||||
import type {
|
||||
AddOp, ConjOp, SubtractOp, UnaryMinusOp, MultiplyOp,
|
||||
AbsquareOp, ReciprocalOp, DivideOp, ConservativeSqrtOp, SqrtOp
|
||||
} from '../interfaces/arithmetic.js'
|
||||
import type {Depends} from '../interfaces/type.js'
|
||||
|
||||
export const add: FnAdd<number> = (a, b) => a + b
|
||||
export const add: AddOp<number> = (a, b) => a + b
|
||||
export const addReal = add
|
||||
export const unaryMinus: FnUnaryMinus<number> = (a) => -a
|
||||
export const conj: FnConj<number> = (a) => a
|
||||
export const subtract: FnSubtract<number> = (a, b) => a - b
|
||||
export const multiply: FnMultiply<number> = (a, b) => a * b
|
||||
export const absquare: FnAbsSquare<number, number> = (a) => a * a
|
||||
export const reciprocal: FnReciprocal<number> = (a) => 1 / a
|
||||
export const divide: FnDivide<number> = (a, b) => a / b
|
||||
export const unaryMinus: UnaryMinusOp<number> = a => -a
|
||||
export const conj: ConjOp<number> = a => a
|
||||
export const subtract: SubtractOp<number> = (a, b) => a - b
|
||||
export const multiply: MultiplyOp<number> = (a, b) => a * b
|
||||
export const absquare: AbsquareOp<number> = a => a * a
|
||||
export const reciprocal: ReciprocalOp<number> = a => 1 / a
|
||||
export const divide: DivideOp<number> = (a, b) => a / b
|
||||
export const divideByReal = divide
|
||||
|
||||
export const conservativeSqrt: FnConservativeSqrt<number> = (a) => isNaN(a) ? NaN : Math.sqrt(a)
|
||||
const basicSqrt = a => isNaN(a) ? NaN : Math.sqrt(a)
|
||||
export const conservativeSqrt: ConservativeSqrtOp<number> = basicSqrt
|
||||
|
||||
export const sqrt =
|
||||
(dep: {
|
||||
config: Config,
|
||||
complex: FnComplexBinary<number>
|
||||
}): FnSqrt<number> => {
|
||||
if (dep.config.predictable || !dep.complex) return conservativeSqrt
|
||||
(dep: configDependency & Depends<ComplexOp<number>>): SqrtOp<number> => {
|
||||
if (dep.config.predictable || !dep.complex) return basicSqrt
|
||||
return a => {
|
||||
if (isNaN(a)) return NaN
|
||||
if (a >= 0) return Math.sqrt(a)
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type { FnIsReal, FnIsSquare } from "../interfaces/arithmetic"
|
||||
import type { IsRealOp, IsSquareOp } from '../interfaces/predicate.js'
|
||||
|
||||
export const isReal: FnIsReal<number> = (a) => true
|
||||
export const isSquare: FnIsSquare<number> = (a) => a >= 0
|
||||
export const isReal: IsRealOp<number> = (a) => true
|
||||
export const isSquare: IsSquareOp<number> = (a) => a >= 0
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { Config } from '../core/Config.js'
|
||||
import type { FnEqual, FnUnequal } from '../interfaces/relational.js'
|
||||
import {Config} from '../core/Config.js'
|
||||
import type {EqualOp} from '../interfaces/relational.js'
|
||||
|
||||
const DBL_EPSILON = Number.EPSILON || 2.2204460492503130808472633361816E-16
|
||||
|
||||
export const equal =
|
||||
(dep: {
|
||||
config: Config
|
||||
}): FnEqual<number> => (x, y) => {
|
||||
}): EqualOp<number> => (x, y) => {
|
||||
const eps = dep.config.epsilon
|
||||
if (eps === null || eps === undefined) return x === y
|
||||
if (x === y) return true
|
||||
@ -20,8 +20,3 @@ export const equal =
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
export const unequal = (dep: {
|
||||
equal: FnEqual<number>
|
||||
}): FnUnequal<number> =>
|
||||
(x, y) => !dep.equal(x, y)
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type { FnNaN, FnOne, FnZero, FnRe } from "../interfaces/arithmetic"
|
||||
import type { OneOp, ZeroOp, NanOp, ReOp } from '../interfaces/type.js'
|
||||
|
||||
export const number_type = {
|
||||
before: ['Complex'],
|
||||
@ -6,7 +6,21 @@ export const number_type = {
|
||||
from: { string: (s: string) => +s }
|
||||
}
|
||||
|
||||
export const zero: FnZero<number> = (a) => 0
|
||||
export const one: FnOne<number> = (a) => 1
|
||||
export const nan: FnNaN<number> = (a) => NaN
|
||||
export const re: FnRe<number, number> = (a) => a
|
||||
declare module "../interfaces/type" {
|
||||
interface AssociatedTypes<T> {
|
||||
numbers: {
|
||||
type: number
|
||||
zero: 0
|
||||
one: 1
|
||||
nan: typeof NaN
|
||||
real: number
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// I don't like the redundancy of repeating 'zero' and 'ZeroOp', any
|
||||
// way to eliminate that?
|
||||
export const zero: ZeroOp<number> = (a) => 0
|
||||
export const one: OneOp<number> = (a) => 1
|
||||
export const nan: NanOp<number> = (a) => NaN
|
||||
export const re: ReOp<number> = (a) => a
|
||||
|
Loading…
Reference in New Issue
Block a user