Declare implementations and dependencies via standard interfaces for operations #8
@ -1,47 +1,45 @@
|
||||
import {Complex, ComplexOp} from './type.js'
|
||||
import {Complex} from './type.js'
|
||||
import type {
|
||||
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
|
||||
Dependencies, OpType, OpReturns, RealType, ZeroType
|
||||
} from '../interfaces/type.js'
|
||||
import type {IsSquareOp, IsRealOp} from '../interfaces/predicate.js'
|
||||
|
||||
declare module "../interfaces/type" {
|
||||
interface Operations<T> {
|
||||
// TODO: Make Dispatcher collapse operations that start with the same
|
||||
// prefix up to a possible `_`
|
||||
add_real: {params: [T, RealType<T>], returns: T}
|
||||
divide_real: {params: [T, RealType<T>], returns: T}
|
||||
}
|
||||
}
|
||||
|
||||
export const add =
|
||||
<T>(dep: Depends<AddOp<T>> & Depends<ComplexOp<T>>): AddOp<Complex<T>> =>
|
||||
<T>(dep: Dependencies<'add' | 'complex', T>): OpType<'add', Complex<T>> =>
|
||||
(w, z) => dep.complex(dep.add(w.re, z.re), dep.add(w.im, z.im))
|
||||
|
||||
export const addReal =
|
||||
<T>(dep: Depends<AddRealOp<T>> & Depends<ComplexOp<T>>):
|
||||
AddRealOp<Complex<T>> =>
|
||||
(z, r) => dep.complex(dep.addReal(z.re, r), z.im)
|
||||
export const add_real =
|
||||
<T>(dep: Dependencies<'add_real' | 'complex', T>):
|
||||
OpType<'add_real', Complex<T>> =>
|
||||
(z, r) => dep.complex(dep.add_real(z.re, r), z.im)
|
||||
|
||||
export const unaryMinus =
|
||||
<T>(dep: Depends<UnaryMinusOp<T>> & Depends<ComplexOp<T>>):
|
||||
UnaryMinusOp<Complex<T>> =>
|
||||
<T>(dep: Dependencies<'unaryMinus' | 'complex', T>):
|
||||
OpType<'unaryMinus', Complex<T>> =>
|
||||
z => dep.complex(dep.unaryMinus(z.re), dep.unaryMinus(z.im))
|
||||
|
||||
export const conj =
|
||||
<T>(dep: Depends<UnaryMinusOp<T>>
|
||||
& Depends<ConjOp<T>>
|
||||
& Depends<ComplexOp<T>>):
|
||||
ConjOp<Complex<T>> =>
|
||||
<T>(dep: Dependencies<'unaryMinus' | 'conj' | 'complex', T>):
|
||||
OpType<'conj', Complex<T>> =>
|
||||
z => dep.complex(dep.conj(z.re), dep.unaryMinus(z.im))
|
||||
|
||||
export const subtract =
|
||||
<T>(dep: Depends<SubtractOp<T>> & Depends<ComplexOp<T>>):
|
||||
SubtractOp<Complex<T>> =>
|
||||
<T>(dep: Dependencies<'subtract' | 'complex', T>):
|
||||
OpType<'subtract', Complex<T>> =>
|
||||
(w, z) => dep.complex(dep.subtract(w.re, z.re), dep.subtract(w.im, z.im))
|
||||
|
||||
export const multiply =
|
||||
<T>(dep: Depends<AddOp<T>>
|
||||
& Depends<SubtractOp<T>>
|
||||
& Depends<MultiplyOp<T>>
|
||||
& Depends<ConjOp<T>>
|
||||
& Depends<ComplexOp<T>>):
|
||||
MultiplyOp<Complex<T>> =>
|
||||
<T>(dep: Dependencies<
|
||||
'add' | 'subtract' | 'multiply' | 'conj' | 'complex', T>):
|
||||
OpType<'multiply', Complex<T>> =>
|
||||
(w, z) => {
|
||||
const mult = dep.multiply
|
||||
const realpart = dep.subtract(
|
||||
@ -52,69 +50,48 @@ export const multiply =
|
||||
}
|
||||
|
||||
export const absquare =
|
||||
<T>(dep: Depends<AddOp<RealType<T>>> & Depends<AbsquareOp<T>>):
|
||||
AbsquareOp<Complex<T>> =>
|
||||
<T>(dep: Dependencies<'absquare', T>
|
||||
& Dependencies<'add', OpReturns<'absquare', T>>):
|
||||
OpType<'absquare', Complex<T>> =>
|
||||
z => dep.add(dep.absquare(z.re), dep.absquare(z.im))
|
||||
|
||||
export const divideByReal =
|
||||
<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))
|
||||
<T>(dep: Dependencies<'divide_real' | 'complex', T>):
|
||||
OpType<'divide_real', Complex<T>> =>
|
||||
(z, r) => dep.complex(dep.divide_real(z.re, r), dep.divide_real(z.im, r))
|
||||
|
||||
export const reciprocal =
|
||||
<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))
|
||||
<T>(dep: Dependencies<'conj' | 'absquare' | 'divide_real', Complex<T>>):
|
||||
OpType<'reciprocal', Complex<T>> =>
|
||||
z => dep.divide_real(dep.conj(z), dep.absquare(z))
|
||||
|
||||
export const divide =
|
||||
<T>(dep: Depends<MultiplyOp<Complex<T>>>
|
||||
& Depends<ReciprocalOp<Complex<T>>>):
|
||||
DivideOp<Complex<T>> =>
|
||||
<T>(dep: Dependencies<'multiply' | 'reciprocal', Complex<T>>):
|
||||
OpType<'divide', 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: 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: 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>> =>
|
||||
<T>(dep:
|
||||
Dependencies<
|
||||
'conservativeSqrt' | 'add' | 'unaryMinus' | 'equal', RealType<T>>
|
||||
& Dependencies<'zero' | 'add_real', T>
|
||||
& Dependencies<'complex', T | ZeroType<T>>
|
||||
& Dependencies<'absquare' | 're' | 'divide_real', Complex<T>>
|
||||
& {add_complex_real: OpType<'add_real', Complex<T>>}):
|
||||
OpType<'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 negr = dep.unaryMinus(r)
|
||||
if (dep.equal(myabs, negr)) {
|
||||
// pure imaginary square root; z.im already sero
|
||||
return dep.complex(
|
||||
dep.zero(z.re), dep.add_real(z.im, dep.conservativeSqrt(negr)))
|
||||
}
|
||||
const num = dep.add_complex_real(z, myabs)
|
||||
const denomsq = dep.add(dep.add(myabs, myabs), dep.add(r, r))
|
||||
const denom = dep.conservativeSqrt(denomsq)
|
||||
return dep.divideByReal(num, denom)
|
||||
return dep.divide_real(num, denom)
|
||||
}
|
||||
|
||||
export const conservativeSqrt = sqrt
|
||||
|
@ -1,12 +1,9 @@
|
||||
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'
|
||||
import type {Dependencies, OpType} from '../interfaces/type.js'
|
||||
|
||||
export const isReal =
|
||||
<T>(dep: Depends<AddOp<T>> & Depends<EqualOp<T>> & Depends<IsRealOp<T>>):
|
||||
IsRealOp<Complex<T>> =>
|
||||
<T>(dep: Dependencies<'add' | 'equal' | 'isReal', T>):
|
||||
OpType<'isReal', Complex<T>> =>
|
||||
z => dep.isReal(z.re) && dep.equal(z.re, dep.add(z.re, z.im))
|
||||
|
||||
export const isSquare: IsSquareOp<Complex<any>> = z => true // FIXME: not correct for Complex<bigint> once we get there
|
||||
export const isSquare: OpType<'isSquare', Complex<any>> = z => true // FIXME: not correct for Complex<bigint> once we get there
|
||||
|
@ -1,7 +1,6 @@
|
||||
import {Complex} from './type.js'
|
||||
import {Depends} from '../interfaces/type.js'
|
||||
import {EqualOp} from '../interfaces/relational.js'
|
||||
import {Dependencies, OpType} from '../interfaces/type.js'
|
||||
|
||||
export const equal =
|
||||
<T>(dep: Depends<EqualOp<T>>): EqualOp<Complex<T>> =>
|
||||
<T>(dep: Dependencies<'equal', T>): OpType<'equal', Complex<T>> =>
|
||||
(w, z) => dep.equal(w.re, z.re) && dep.equal(w.im, z.im)
|
||||
|
@ -2,7 +2,7 @@ import {
|
||||
joinTypes, typeOfDependency, Dependency,
|
||||
} from '../core/Dispatcher.js'
|
||||
import type {
|
||||
OneOp, ZeroOp, NanOp, ReOp, ZeroType, OneType, NaNType, Depends
|
||||
ZeroType, OneType, NaNType, Dependencies, OpType, OpReturns
|
||||
} from '../interfaces/type.js'
|
||||
|
||||
export type Complex<T> = { re: T; im: T; }
|
||||
@ -32,31 +32,34 @@ declare module "../interfaces/type" {
|
||||
real: RealType<R>
|
||||
} : never
|
||||
}
|
||||
|
||||
interface Operations<T> {
|
||||
complex: {params: [T] | [T,T], returns: Complex<T>}
|
||||
}
|
||||
}
|
||||
|
||||
export type ComplexOp<T> = {op?: 'complex', (a: T, b?: T): Complex<T>}
|
||||
|
||||
export const complex =
|
||||
<T>(dep: Depends<ZeroOp<T>>): ComplexOp<T | ZeroType<T>> =>
|
||||
<T>(dep: Dependencies<'zero', T>): OpType<'complex', T | ZeroType<T>> =>
|
||||
(a, b) => ({re: a, im: b || dep.zero(a)})
|
||||
|
||||
export const zero =
|
||||
<T>(dep: Depends<ZeroOp<T>> & Depends<ComplexOp<ZeroType<T>>>):
|
||||
ZeroOp<Complex<T>> =>
|
||||
<T>(dep: Dependencies<'zero', T>
|
||||
& Dependencies<'complex', OpReturns<'zero', T>>):
|
||||
OpType<'zero', Complex<T>> =>
|
||||
z => dep.complex(dep.zero(z.re), dep.zero(z.im))
|
||||
|
||||
export const one =
|
||||
<T>(dep: Depends<OneOp<T>>
|
||||
& Depends<ZeroOp<T>>
|
||||
& Depends<ComplexOp<ZeroType<T>|OneType<T>>>):
|
||||
OneOp<Complex<T>> =>
|
||||
<T>(dep: Dependencies<'one' | 'zero', T>
|
||||
& Dependencies<'complex', OpReturns<'one' | 'zero', T>>):
|
||||
OpType<'one', Complex<T>> =>
|
||||
z => dep.complex(dep.one(z.re), dep.zero(z.im))
|
||||
|
||||
export const nan =
|
||||
<T>(dep: Depends<NanOp<T>> & Depends<ComplexOp<NaNType<T>>>):
|
||||
NanOp<Complex<T>> =>
|
||||
<T>(dep: Dependencies<'nan', T>
|
||||
& Dependencies<'complex', OpReturns<'nan', T>>):
|
||||
OpType<'nan', Complex<T>> =>
|
||||
z => dep.complex(dep.nan(z.re), dep.nan(z.im))
|
||||
|
||||
export const re =
|
||||
<T>(dep: Depends<ReOp<T>>): ReOp<Complex<T>> =>
|
||||
<T>(dep: Dependencies<'re', T>): OpType<'re', Complex<T>> =>
|
||||
z => dep.re(z.re)
|
||||
|
@ -1,6 +1,5 @@
|
||||
import type {Depends} from '../interfaces/type.js'
|
||||
import type {MultiplyOp, SquareOp} from '../interfaces/arithmetic.js'
|
||||
import type {Dependencies, OpType} from '../interfaces/type.js'
|
||||
|
||||
export const square =
|
||||
<T>(dep: Depends<MultiplyOp<T>>): SquareOp<T> =>
|
||||
<T>(dep: Dependencies<'multiply', T>): OpType<'square', T> =>
|
||||
z => dep.multiply(z, z)
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {Depends} from '../interfaces/type.js'
|
||||
import type {EqualOp, UnequalOp} from '../interfaces/relational.js'
|
||||
import {Dependencies, OpType} from '../interfaces/type.js'
|
||||
|
||||
export const unequal = <T>(dep: Depends<EqualOp<T>>): UnequalOp<T> =>
|
||||
export const unequal =
|
||||
<T>(dep: Dependencies<'equal', T>): OpType<'unequal', T> =>
|
||||
(x, y) => !dep.equal(x, y)
|
||||
|
@ -1,25 +1,25 @@
|
||||
import type {Complex} from '../Complex/type.js'
|
||||
import type {RealType, WithConstants, NaNType} from './type.js'
|
||||
|
||||
// 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 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>
|
||||
type UnaryOperator<T> = {params: [T], returns: T}
|
||||
type BinaryOperator<T> = {params: [T, T], returns: T}
|
||||
declare module "./type" {
|
||||
interface Operations<T> {
|
||||
add: BinaryOperator<T>
|
||||
unaryMinus: UnaryOperator<T>
|
||||
conj: UnaryOperator<T>
|
||||
subtract: BinaryOperator<T>
|
||||
multiply: BinaryOperator<T>
|
||||
square: UnaryOperator<T>
|
||||
absquare: {params: [T], returns: RealType<T>}
|
||||
reciprocal: UnaryOperator<T>
|
||||
divide: BinaryOperator<T>
|
||||
conservativeSqrt: UnaryOperator<T>
|
||||
sqrt: {
|
||||
params: [T],
|
||||
returns: T extends Complex<infer R>
|
||||
? Complex<R | ZeroType<R>>
|
||||
: T | Complex<T>
|
||||
}
|
||||
}
|
||||
}
|
||||
export type SquareOp<T> = {op?: 'square', (z: T): T}
|
||||
|
||||
|
@ -1,2 +1,9 @@
|
||||
export type IsRealOp<T> = {op?: 'isReal', (a: T): boolean}
|
||||
export type IsSquareOp<T> = {op?: 'isSquare', (a: T): boolean}
|
||||
// Warning: a module must have something besides just a "declare module"
|
||||
// section; otherwise it is ignored.
|
||||
export type UnaryPredicate<T> = {params: [T], returns: boolean}
|
||||
declare module "./type" {
|
||||
interface Operations<T> {
|
||||
isReal: UnaryPredicate<T>
|
||||
isSquare: UnaryPredicate<T>
|
||||
}
|
||||
}
|
||||
|
@ -1,2 +1,9 @@
|
||||
export type EqualOp<T> = {op?: 'equal', (a: T, b: T): boolean}
|
||||
export type UnequalOp<T> = {op?: 'unequal', (a: T, b: T): boolean}
|
||||
// Warning: a module must have something besides just a "declare module"
|
||||
// section; otherwise it is ignored.
|
||||
export type BinaryPredicate<T> = {params: [T, T], returns: boolean}
|
||||
declare module "./type" {
|
||||
interface Operations<T> {
|
||||
equal: BinaryPredicate<T>
|
||||
unequal: BinaryPredicate<T>
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,15 @@
|
||||
// Every typocomath type has some associated types; they need
|
||||
// to be published as in the following interface. The key is the
|
||||
// name of the type, and within the subinterface for that key,
|
||||
// the type of the 'type' property is the actual TypeScript type
|
||||
// we are associating the other properties to. Note the interface
|
||||
// is generic with one parameter, corresponding to the fact that
|
||||
// typocomath currently only allows types with a single generic parameter.
|
||||
// This way, AssociatedTypes<SubType> can give the associated types
|
||||
// for a generic type instantiated with SubType. That's not necessary for
|
||||
// the 'undefined' type (or if you look in the `numbers` subdirectory,
|
||||
// the 'number' type either) or any concrete type, but that's OK, the
|
||||
// generic parameter doesn't hurt in those cases.
|
||||
export interface AssociatedTypes<T> {
|
||||
undefined: {
|
||||
type: undefined
|
||||
@ -9,24 +21,46 @@ export interface AssociatedTypes<T> {
|
||||
}
|
||||
|
||||
type AssociatedTypeNames = keyof AssociatedTypes<unknown>['undefined']
|
||||
export type Lookup<T, Name extends AssociatedTypeNames> = {
|
||||
type ALookup<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 ZeroType<T> = ALookup<T, 'zero'>
|
||||
export type OneType<T> = ALookup<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 NaNType<T> = ALookup<T, 'nan'>
|
||||
export type RealType<T> = ALookup<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>}
|
||||
// The global signature patterns for all operations need to be published in the
|
||||
// following interface. Each key is the name of an operation (but note that
|
||||
// the Dispatcher will automatically merge operations that have the same
|
||||
// name when the first underscore `_` and everything thereafter is stripped).
|
||||
// The type of each key should be an interface with two properties: 'params'
|
||||
// whose type is the type of the parameter list for the operation, and
|
||||
// 'returns' whose type is the return type of the operation on those
|
||||
// parameters. These types are generic in a parameter type T which should
|
||||
// be interpreted as the type that the operation is supposed to "primarily"
|
||||
// operate on, although note that some of the parameters and/or return types
|
||||
// may depend on T rather than be exactly T.
|
||||
// So note that the example 're' below provides essentially the same
|
||||
// information that e.g.
|
||||
// `type ReOp<T> = (t: T) => RealType<T>`
|
||||
// would, but in a way that is much easier to manipulate in TypeScript,
|
||||
// and it records the name of the operation as 're' also by virtue of the
|
||||
// key 're' in the interface.
|
||||
export interface Operations<T> {
|
||||
zero: {params: [WithConstants<T>], returns: ZeroType<T>}
|
||||
one: {params: [WithConstants<T>], returns: OneType<T>}
|
||||
nan: {params: [T | NaNType<T>], returns: NaNType<T>}
|
||||
re: {params: [T], returns: RealType<T>}
|
||||
}
|
||||
|
||||
type NamedFunction = {op?: string, (...params: any[]): any}
|
||||
export type Depends<FuncType extends NamedFunction> =
|
||||
{[K in FuncType['op']]: FuncType}
|
||||
type OpKey = keyof Operations<unknown>
|
||||
|
||||
export type OpReturns<Name extends OpKey, T> = Operations<T>[Name]['returns']
|
||||
export type OpType<Name extends OpKey, T> =
|
||||
(...args: Operations<T>[Name]['params']) => OpReturns<Name, T>
|
||||
export type Dependencies<Name extends OpKey, T> = {[K in Name]: OpType<K, T>}
|
||||
|
||||
|
||||
|
@ -1,27 +1,21 @@
|
||||
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'
|
||||
import type {Dependencies, OpType} from '../interfaces/type.js'
|
||||
|
||||
export const add: AddOp<number> = (a, b) => a + b
|
||||
export const addReal = add
|
||||
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 add: OpType<'add', number> = (a, b) => a + b
|
||||
export const unaryMinus: OpType<'unaryMinus', number> = a => -a
|
||||
export const conj: OpType<'conj', number> = a => a
|
||||
export const subtract: OpType<'subtract', number> = (a, b) => a - b
|
||||
export const multiply: OpType<'multiply', number> = (a, b) => a * b
|
||||
export const absquare: OpType<'absquare', number> = a => a * a
|
||||
export const reciprocal: OpType<'reciprocal', number> = a => 1 / a
|
||||
export const divide: OpType<'divide', number> = (a, b) => a / b
|
||||
|
||||
const basicSqrt = a => isNaN(a) ? NaN : Math.sqrt(a)
|
||||
export const conservativeSqrt: ConservativeSqrtOp<number> = basicSqrt
|
||||
export const conservativeSqrt: OpType<'conservativeSqrt', number> = basicSqrt
|
||||
|
||||
export const sqrt =
|
||||
(dep: configDependency & Depends<ComplexOp<number>>): SqrtOp<number> => {
|
||||
(dep: configDependency & Dependencies<'complex', number>):
|
||||
OpType<'sqrt', number> => {
|
||||
if (dep.config.predictable || !dep.complex) return basicSqrt
|
||||
return a => {
|
||||
if (isNaN(a)) return NaN
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type { IsRealOp, IsSquareOp } from '../interfaces/predicate.js'
|
||||
import type {OpType} from '../interfaces/type.js'
|
||||
|
||||
export const isReal: IsRealOp<number> = (a) => true
|
||||
export const isSquare: IsSquareOp<number> = (a) => a >= 0
|
||||
export const isReal: OpType<'isReal', number> = (a) => true
|
||||
export const isSquare: OpType<'isSquare', number> = (a) => a >= 0
|
||||
|
@ -1,12 +1,11 @@
|
||||
import {Config} from '../core/Config.js'
|
||||
import type {EqualOp} from '../interfaces/relational.js'
|
||||
import {configDependency} from '../core/Config.js'
|
||||
import {OpType} from '../interfaces/type.js'
|
||||
|
||||
const DBL_EPSILON = Number.EPSILON || 2.2204460492503130808472633361816E-16
|
||||
|
||||
export const equal =
|
||||
(dep: {
|
||||
config: Config
|
||||
}): EqualOp<number> => (x, y) => {
|
||||
(dep: configDependency): OpType<'equal', number> =>
|
||||
(x, y) => {
|
||||
const eps = dep.config.epsilon
|
||||
if (eps === null || eps === undefined) return x === y
|
||||
if (x === y) return true
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type { OneOp, ZeroOp, NanOp, ReOp } from '../interfaces/type.js'
|
||||
import type { OpType } from '../interfaces/type.js'
|
||||
|
||||
export const number_type = {
|
||||
before: ['Complex'],
|
||||
@ -18,9 +18,8 @@ declare module "../interfaces/type" {
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
// I don't like the redundancy of repeating 'zero'; any way to eliminate that?
|
||||
export const zero: OpType<'zero', number> = (a) => 0
|
||||
export const one: OpType<'one', number> = (a) => 1
|
||||
export const nan: OpType<'nan', number> = (a) => NaN
|
||||
export const re: OpType<'re', number> = (a) => a
|
||||
|
Loading…
Reference in New Issue
Block a user