Compare commits
6 Commits
main
...
approach2.
Author | SHA1 | Date |
---|---|---|
Glen Whitney | f860fca03d | |
Glen Whitney | 7db6f38a30 | |
Glen Whitney | 8c06c8f36e | |
Glen Whitney | fbec410c42 | |
Glen Whitney | d55776655f | |
Glen Whitney | 1eb73be2fa |
|
@ -1,8 +1,10 @@
|
|||
import {ForType} from '../core/Dispatcher.js'
|
||||
import {ComplexImpTypes} from './type.js'
|
||||
import * as Complex from './native.js'
|
||||
|
||||
export {Complex}
|
||||
|
||||
declare module "../core/Dispatcher" {
|
||||
interface ImplementationTypes extends ForType<'Complex', typeof Complex> {}
|
||||
interface ImpTypes<T>
|
||||
extends ForType<'Complex', ComplexImpTypes<T>> {}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
import {Complex, UnderlyingReal, complex_binary} from './type.js'
|
||||
import {Dependency, ImpType} from '../core/Dispatcher.js'
|
||||
|
||||
type ComplexUnary<T> =
|
||||
T extends Complex<infer R> ? (a: Complex<R>) => Complex<R> : never
|
||||
type ComplexBinary<T> =
|
||||
T extends Complex<infer R>
|
||||
? (a: Complex<R>, b: Complex<R>) => Complex<R>
|
||||
: never
|
||||
type ComplexReal<T> = T extends Complex<infer R>
|
||||
? (a: Complex<R>, b: UnderlyingReal<R>) => Complex<R>
|
||||
: never
|
||||
declare module "./type" {
|
||||
interface ComplexImpTypes<T> {
|
||||
add: ComplexBinary<T>
|
||||
add_real: ComplexReal<T>
|
||||
unaryMinus: ComplexUnary<T>
|
||||
conj: ComplexUnary<T>
|
||||
subtract: ComplexBinary<T>
|
||||
multiply: ComplexBinary<T>
|
||||
absquare: T extends Complex<infer R> ? (a: T) => UnderlyingReal<R> : never
|
||||
reciprocal: ComplexUnary<T>
|
||||
divide: ComplexBinary<T>
|
||||
divide_real: ComplexReal<T>
|
||||
// square root that remains the same type
|
||||
conservativeSqrt: ComplexUnary<T>
|
||||
// Same as conservativeSqrt for complex numbers:
|
||||
sqrt: ComplexUnary<T>
|
||||
}
|
||||
}
|
||||
|
||||
export const add =
|
||||
<T>(dep: Dependency<'add', [T,T]>):
|
||||
ImpType<'add', [Complex<T>, Complex<T>]> =>
|
||||
(w, z) => complex_binary(dep.add(w.re, z.re), dep.add(w.im, z.im))
|
||||
|
||||
export const add_real =
|
||||
<T>(dep: Dependency<'add_real', [T, UnderlyingReal<T>]>):
|
||||
ImpType<'add_real', [Complex<T>, UnderlyingReal<T>]> =>
|
||||
(z, r) => complex_binary(dep.add_real(z.re, r), z.im)
|
||||
|
||||
export const unaryMinus =
|
||||
<T>(dep: Dependency<'unaryMinus', [T]>):
|
||||
ImpType<'unaryMinus', [Complex<T>]> =>
|
||||
z => complex_binary(dep.unaryMinus(z.re), dep.unaryMinus(z.im))
|
||||
|
||||
export const conj =
|
||||
<T>(dep: Dependency<'unaryMinus'|'conj', [T]>):
|
||||
ImpType<'conj', [Complex<T>]> =>
|
||||
z => complex_binary(dep.conj(z.re), dep.unaryMinus(z.im))
|
||||
|
||||
export const subtract =
|
||||
<T>(dep: Dependency<'subtract', [T,T]>):
|
||||
ImpType<'subtract', [Complex<T>, Complex<T>]> =>
|
||||
(w, z) => complex_binary(dep.subtract(w.re, z.re), dep.subtract(w.im, z.im))
|
||||
|
||||
export const multiply =
|
||||
<T>(dep: Dependency<'add', [T,T]>
|
||||
& Dependency<'subtract', [T,T]>
|
||||
& Dependency<'multiply', [T,T]>
|
||||
& Dependency<'conj', [T]>):
|
||||
ImpType<'multiply', [Complex<T>, 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 complex_binary(realpart, imagpart)
|
||||
}
|
||||
|
||||
export const absquare =
|
||||
<T>(dep: Dependency<'absquare', [T]>
|
||||
& Dependency<'add', [UnderlyingReal<T>, UnderlyingReal<T>]>):
|
||||
ImpType<'absquare', [Complex<T>]> =>
|
||||
z => dep.add(dep.absquare(z.re), dep.absquare(z.im))
|
||||
|
||||
export const divide_real =
|
||||
<T>(dep: Dependency<'divide_real', [T, UnderlyingReal<T>]>):
|
||||
ImpType<'divide_real', [Complex<T>, UnderlyingReal<T>]> =>
|
||||
(z, r) => complex_binary(
|
||||
dep.divide_real(z.re, r), dep.divide_real(z.im, r))
|
||||
|
||||
export const reciprocal =
|
||||
<T>(dep: Dependency<'conj', [Complex<T>]>
|
||||
& Dependency<'absquare', [Complex<T>]>
|
||||
& Dependency<'divide_real', [Complex<T>, UnderlyingReal<T>]>):
|
||||
ImpType<'reciprocal', [Complex<T>]> =>
|
||||
z => dep.divide_real(dep.conj(z), dep.absquare(z))
|
||||
|
||||
export const divide =
|
||||
<T>(dep: Dependency<'multiply', [Complex<T>, Complex<T>]>
|
||||
& Dependency<'reciprocal', [Complex<T>]>):
|
||||
ImpType<'divide', [Complex<T>, Complex<T>]> =>
|
||||
(w, z) => dep.multiply(w, dep.reciprocal(z))
|
||||
|
||||
export const sqrt =
|
||||
<T>(dep: Dependency<'absquare' | 're', [Complex<T>]>
|
||||
& Dependency<'conservativeSqrt' | 'unaryMinus', [UnderlyingReal<T>]>
|
||||
& Dependency<'divide_real', [Complex<T>, UnderlyingReal<T>]>
|
||||
& Dependency<'add_real', [T, UnderlyingReal<T>]>
|
||||
& {add_complex_real:
|
||||
ImpType<'add_real', [Complex<T>, UnderlyingReal<T>]>}
|
||||
& Dependency<'equal' | 'add', [UnderlyingReal<T>, UnderlyingReal<T>]>
|
||||
& Dependency<'complex', [T, T]>
|
||||
& Dependency<'zero', [T]>
|
||||
): ImpType<'sqrt', [Complex<T>]> =>
|
||||
z => {
|
||||
const myabs = dep.conservativeSqrt(dep.absquare(z))
|
||||
const r = dep.re(z)
|
||||
const negr = dep.unaryMinus(r)
|
||||
if (dep.equal(myabs, negr)) {
|
||||
// pure imaginary square root; z.im already zero
|
||||
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.divide_real(num, denom)
|
||||
}
|
||||
|
||||
|
||||
export const conservativeSqrt = sqrt
|
|
@ -1 +1,4 @@
|
|||
export * from './type.js'
|
||||
export * from './arithmetic.js'
|
||||
export * from './predicate.js'
|
||||
export * from './relational.js'
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
import {Complex} from './type.js'
|
||||
import {Dependency, ImpType} from '../core/Dispatcher.js'
|
||||
|
||||
type ComplexPredicate<T> = T extends Complex<any> ? (a: T) => boolean : never
|
||||
|
||||
declare module "./type" {
|
||||
interface ComplexImpTypes<T> {
|
||||
isReal: ComplexPredicate<T>
|
||||
isSquare: ComplexPredicate<T>
|
||||
}
|
||||
}
|
||||
|
||||
export const isReal =
|
||||
<T>(dep: Dependency<'equal', [T,T]>
|
||||
& Dependency<'add', [T,T]>
|
||||
& Dependency<'isReal', [T]>
|
||||
): ImpType<'isReal', [Complex<T>]> =>
|
||||
z => dep.isReal(z.re) && dep.equal(z.re, dep.add(z.re, z.im))
|
||||
|
||||
export const isSquare: ImpType<'isSquare', [Complex<any>]> =
|
||||
z => true // FIXME: not correct for Complex<bigint> once we get there
|
|
@ -0,0 +1,16 @@
|
|||
import {Complex} from './type.js'
|
||||
import {ImpType, Dependency} from '../core/Dispatcher.js'
|
||||
|
||||
type ComplexRelation<T> =
|
||||
T extends Complex<any> ? (a: T, b: T) => boolean : never
|
||||
|
||||
declare module "./type" {
|
||||
interface ComplexImpTypes<T> {
|
||||
equal: ComplexRelation<T>
|
||||
}
|
||||
}
|
||||
|
||||
export const equal =
|
||||
<T>(dep: Dependency<'equal', [T,T]>):
|
||||
ImpType<'equal', [Complex<T>, Complex<T>]> =>
|
||||
(w, z) => dep.equal(w.re, z.re) && dep.equal(w.im, z.im)
|
|
@ -1,7 +1,12 @@
|
|||
import {joinTypes, typeOfDependency, Dependency} from '../core/Dispatcher.js'
|
||||
import {
|
||||
joinTypes, typeOfDependency, Dependency, ImpType, ImpReturns
|
||||
} from '../core/Dispatcher.js'
|
||||
|
||||
export type Complex<T> = {re: T; im: T;}
|
||||
|
||||
export type UnderlyingReal<T> =
|
||||
T extends Complex<infer U> ? UnderlyingReal<U> : T
|
||||
|
||||
export const Complex_type = {
|
||||
test: <T>(dep: {testT: (z: unknown) => z is T}) =>
|
||||
(z: unknown): z is Complex<T> =>
|
||||
|
@ -17,6 +22,37 @@ export const Complex_type = {
|
|||
}
|
||||
}
|
||||
|
||||
export const complex_unary = <T>(dep: Dependency<'zero', [T]>) =>
|
||||
(t: T) => ({re: t, im: dep.zero(t)})
|
||||
export const complex_binary = <T>(t: T, u: T) => ({re: t, im: u})
|
||||
export interface ComplexImpTypes<T> {
|
||||
complex: (a: T, b?: T) => Complex<T>
|
||||
zero: T extends Complex<infer R>
|
||||
? (a: Complex<R>) => Complex<R | ImpReturns<'zero', [R]>> : never
|
||||
one: T extends Complex<infer R>
|
||||
? (a: Complex<R>) => Complex<R | ImpReturns<'one' | 'zero', [R]>> : never
|
||||
nan: T extends Complex<infer R>
|
||||
? (a: Complex<R>) => Complex<R | ImpReturns<'NaN', [R]>> : never
|
||||
re: T extends Complex<infer R>
|
||||
? (a: Complex<R>) => UnderlyingReal<R> : never
|
||||
}
|
||||
|
||||
export const complex_unary =
|
||||
<T>(dep: Dependency<'zero', [T]>): ImpType<'complex', [T]> =>
|
||||
t => ({re: t, im: dep.zero(t)})
|
||||
export const complex_binary = <T>(t: T, u: T): ImpReturns<'complex', [T,T]> =>
|
||||
({re: t, im: u})
|
||||
|
||||
export const zero =
|
||||
<T>(dep: Dependency<'zero', [T]>): ImpType<'zero', [Complex<T>]> =>
|
||||
z => complex_binary(dep.zero(z.re), dep.zero(z.im))
|
||||
|
||||
export const one =
|
||||
<T>(dep: Dependency<'zero' | 'one', [T]>): ImpType<'one', [Complex<T>]> =>
|
||||
z => // Must provide parameter T, else TS narrows to return type of dep.one
|
||||
complex_binary<T>(dep.one(z.re), dep.zero(z.im))
|
||||
|
||||
export const nan =
|
||||
<T>(dep: Dependency<'nan', [T]>): ImpType<'nan', [Complex<T>]> =>
|
||||
z => complex_binary(dep.nan(z.re), dep.nan(z.im))
|
||||
|
||||
export const re =
|
||||
<T>(dep: Dependency<'re', [T]>): ImpType<'re', [Complex<T>]> =>
|
||||
z => dep.re(z.re)
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
export * from './numbers/all.js'
|
||||
export * from './Complex/all.js'
|
||||
export * from './generic/all.js'
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
export type Config = {
|
||||
epsilon: number
|
||||
predictable: boolean
|
||||
}
|
||||
|
||||
|
|
|
@ -9,15 +9,59 @@
|
|||
|
||||
type TypeName = string
|
||||
type Parameter = TypeName
|
||||
type Signature = Parameter[]
|
||||
type InputSignature = Parameter[]
|
||||
type DependenciesType = Record<string, Function>
|
||||
|
||||
export interface ImplementationTypes {}
|
||||
export type typeOfDependency = {typeOf: (x: unknown) => TypeName}
|
||||
|
||||
// Helper for collecting implementations
|
||||
// (Really just suffixes the type name onto the keys of exports)
|
||||
export type ForType<T extends string, Exports> = keyof Exports extends string
|
||||
? {[K in keyof Exports as `${K}_${T}`]: Exports[K]}
|
||||
// All of the implementations must publish descriptions of their
|
||||
// types into the following interface, using the format
|
||||
// described just below:
|
||||
export interface ImpTypes<T> {}
|
||||
|
||||
/*****
|
||||
To describe one implementation for a hypothetical operation `foo`, there
|
||||
should be a property of the interface whose name starts with `foo` and whose
|
||||
next character, if any, is an underscore. The type of this property
|
||||
must be the type of that implementation when T matches the
|
||||
first parameter of the implementation.
|
||||
Thus to describe an implementation that takes a number and a string and
|
||||
returns a boolean, for example, you could write
|
||||
```
|
||||
declare module "Dispatcher" {
|
||||
interface ImpTypes<T> {
|
||||
foo_example: (a: number, b: string) => boolean
|
||||
}
|
||||
}
|
||||
```
|
||||
If there is another, generic implementation that takes one argument
|
||||
of any type and returns a Vector of that type, you can say
|
||||
```
|
||||
...
|
||||
foo_generic: (a: T) => Vector<T>
|
||||
...
|
||||
```
|
||||
In practice, each subdirectory corresponding to a type, like Complex,
|
||||
defines an interface, like `ComplexImpTypes<T>` for the implementations
|
||||
in that subdirectory, which can mostly be defined without suffixes because
|
||||
there's typically just a single implementation within that domain.
|
||||
Then the module responsible for collating all of the implementations for
|
||||
that type inserts all of the properties of that interface into `ReturnTypes`
|
||||
suitably suffixed to avoid collisions.
|
||||
|
||||
Note that if the type is not generic, it will not bother with the generic
|
||||
parameter in its subdirectory ImpTypes interface.
|
||||
|
||||
And note again, that for generic types, the type parameter of ImpTypes
|
||||
_must_ match the type of the **first** argument of the operation. Hence,
|
||||
choose argument order so that you can infer all the other parameter types
|
||||
and the return type from the type of the first argument.
|
||||
*****/
|
||||
|
||||
// Helper for collecting return types
|
||||
// (Really just adds the literal string Suffix onto the keys of interface IFace)
|
||||
export type ForType<Suffix extends string, IFace> = keyof IFace extends string
|
||||
? {[K in keyof IFace as `${K}_${Suffix}`]: IFace[K]}
|
||||
: never
|
||||
|
||||
//dummy implementation for now
|
||||
|
@ -26,27 +70,34 @@ export function joinTypes(a: TypeName, b: TypeName) {
|
|||
return 'any'
|
||||
}
|
||||
|
||||
/**
|
||||
* Build up to Dependency type lookup
|
||||
*/
|
||||
type DependenciesType = Record<string, Function>
|
||||
// Used to filter keys that match a given operation name
|
||||
type BeginsWith<Name extends string> = Name | `${Name}_${string}`
|
||||
|
||||
type FinalShape<FuncType> =
|
||||
FuncType extends (arg: DependenciesType) => Function
|
||||
? ReturnType<FuncType> : FuncType
|
||||
|
||||
type BeginsWith<Name extends string> = `${Name}${string}`
|
||||
|
||||
type DependencyTypes<Ob, Name extends string, Params extends unknown[]> =
|
||||
{[K in keyof Ob]: K extends BeginsWith<Name>
|
||||
? FinalShape<Ob[K]> extends (...args: Params) => any
|
||||
? FinalShape<Ob[K]>
|
||||
: never
|
||||
export type RawDependency<Name extends string, Params extends unknown[]> =
|
||||
{[K in keyof ImpTypes<Params[0]>]: K extends BeginsWith<Name>
|
||||
? ImpTypes<Params[0]>[K] extends (...args: Params) => any
|
||||
? ImpTypes<Params[0]>[K]
|
||||
: never
|
||||
: never}
|
||||
|
||||
// The type of an implementation (with dependencies satisfied,
|
||||
// based on its name and the parameters it takes
|
||||
export type ImpType<Name extends string, Params extends unknown[]> =
|
||||
RawDependency<Name, Params>[keyof ImpTypes<Params[0]>]
|
||||
|
||||
// The type of a dependency on an implementation based on its name
|
||||
// and the parameters it takes (just a simple object with one property
|
||||
// named the same as the operation, of value type equal to the type of
|
||||
// that implementation. These can be `&`ed together in case of multiple
|
||||
// dependencies:
|
||||
export type Dependency<Name extends string, Params extends unknown[]> =
|
||||
{[N in Name]:
|
||||
DependencyTypes<ImplementationTypes, N, Params>[keyof ImplementationTypes]}
|
||||
{[N in Name]: ImpType<N, Params>}
|
||||
|
||||
// Look up the return type of an implementation based on its name
|
||||
// and the parameters it takes
|
||||
export type ImpReturns<Name extends string, Params extends unknown[]> =
|
||||
ReturnType<ImpType<Name, Params>>
|
||||
|
||||
|
||||
// Now types used in the Dispatcher class itself
|
||||
|
||||
|
@ -64,9 +115,9 @@ type SpecificationsGroup = Record<string, SpecObject>
|
|||
export class Dispatcher {
|
||||
installSpecification(
|
||||
name: string,
|
||||
signature: Signature,
|
||||
signature: InputSignature,
|
||||
returns: TypeName,
|
||||
dependencies: Record<string, Signature>,
|
||||
dependencies: Record<string, InputSignature>,
|
||||
behavior: Function // possible todo: constrain this type based
|
||||
// on the signature, return type, and dependencies. Not sure if
|
||||
// that's really possible, though.
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
import { ForType } from '../core/Dispatcher.js'
|
||||
import { GenericImpTypes } from './type.js'
|
||||
import * as generic from './native.js'
|
||||
|
||||
export { generic }
|
||||
|
||||
declare module "../core/Dispatcher" {
|
||||
interface ImpTypes<T>
|
||||
extends ForType<'generic', GenericImpTypes<T>> { }
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
import {Dependency, ImpType, ImpReturns} from '../core/Dispatcher.js'
|
||||
|
||||
declare module "./type" {
|
||||
interface GenericImpTypes<T> {
|
||||
square: (a: T) => ImpReturns<'multiply', [T, T]>
|
||||
}
|
||||
}
|
||||
|
||||
export const square =
|
||||
<T>(dep: Dependency<'multiply', [T, T]>):
|
||||
ImpType<'square', [T]> =>
|
||||
t => dep.multiply(t, t)
|
|
@ -0,0 +1,2 @@
|
|||
export * from './arithmetic.js'
|
||||
export * from './relational.js'
|
|
@ -0,0 +1,11 @@
|
|||
import {Dependency, ImpType} from '../core/Dispatcher.js'
|
||||
|
||||
declare module "./type" {
|
||||
interface GenericImpTypes<T> {
|
||||
unequal: (a: T, b:T) => boolean
|
||||
}
|
||||
}
|
||||
|
||||
export const unequal =
|
||||
<T>(dep: Dependency<'equal', [T,T]>): ImpType<'unequal', [T, T]> =>
|
||||
(a, b) => !dep.equal(a, b)
|
|
@ -0,0 +1,3 @@
|
|||
export interface GenericImpTypes<T> {
|
||||
|
||||
}
|
16
src/index.ts
16
src/index.ts
|
@ -2,3 +2,19 @@ import {Dispatcher} from './core/Dispatcher.js'
|
|||
import * as Specifications from './all.js'
|
||||
|
||||
export default new Dispatcher(Specifications)
|
||||
|
||||
import {Complex} from './Complex/type.js'
|
||||
import {absquare as absquare_complex} from './Complex/arithmetic.js'
|
||||
|
||||
const mockRealAdd = (a: number, b: number) => a+b
|
||||
const mockComplexAbsquare = (z: Complex<number>) => z.re*z.re + z.im*z.im
|
||||
|
||||
const quatAbsquare = absquare_complex({
|
||||
add: mockRealAdd,
|
||||
absquare: mockComplexAbsquare
|
||||
})
|
||||
|
||||
const myabs = quatAbsquare({re: {re: 0, im: 1}, im: {re:2, im: 3}})
|
||||
const typeTest: typeof myabs = 7 // check myabs is just a number
|
||||
|
||||
console.log('Result is', myabs)
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import {ForType} from '../core/Dispatcher.js'
|
||||
import {NumbersImpTypes} from './type.js'
|
||||
import * as numbers from './native.js'
|
||||
|
||||
export {numbers}
|
||||
|
||||
declare module "../core/Dispatcher" {
|
||||
interface ImplementationTypes extends ForType<'numbers', typeof numbers> {}
|
||||
interface ImpTypes<T>
|
||||
extends ForType<'numbers', NumbersImpTypes> {}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,48 @@
|
|||
import {configDependency} from '../core/Config.js'
|
||||
import {Dependency} from '../core/Dispatcher.js'
|
||||
import {
|
||||
Dependency, ImpType
|
||||
} from '../core/Dispatcher.js'
|
||||
import type {Complex, UnderlyingReal} from '../Complex/type.js'
|
||||
|
||||
type UnaryNumber = (a: number) => number
|
||||
type BinaryNumber = (a: number, b:number) => number
|
||||
|
||||
declare module "./type" {
|
||||
interface NumbersImpTypes {
|
||||
add: BinaryNumber
|
||||
unaryMinus: UnaryNumber
|
||||
conj: UnaryNumber
|
||||
subtract: BinaryNumber
|
||||
multiply: BinaryNumber
|
||||
absquare: UnaryNumber
|
||||
reciprocal: UnaryNumber
|
||||
divide: BinaryNumber
|
||||
conservativeSqrt: UnaryNumber
|
||||
// Best we can do for sqrt at compile time, since actual return
|
||||
// type depends on config. Not sure how this will play out
|
||||
// when we make a number-only bundle, but at least the import type
|
||||
// above for Complex<> does not lead to any emitted JavaScript.
|
||||
sqrt: (a: number) => number | Complex<number>
|
||||
}
|
||||
}
|
||||
|
||||
export const add: ImpType<'add', [number, number]> = (a, b) => a + b
|
||||
export const unaryMinus: ImpType<'unaryMinus', [number]> = a => -a
|
||||
export const conj: ImpType<'conj', [number]> = a => a
|
||||
export const subtract: ImpType<'subtract', [number, number]> = (a, b) => a - b
|
||||
export const multiply: ImpType<'multiply', [number, number]> = (a, b) => a * b
|
||||
export const absquare: ImpType<'absquare', [number]> = a => a*a
|
||||
export const reciprocal: ImpType<'reciprocal', [number]> = a => 1/a
|
||||
export const divide: ImpType<'divide', [number, number]> = (a, b) => a / b
|
||||
|
||||
export const conservativeSqrt: ImpType<'conservativeSqrt', [number]> =
|
||||
a => isNaN(a) ? NaN : Math.sqrt(a)
|
||||
|
||||
export const add = (a: number, b: number) => a + b
|
||||
export const unaryMinus = (a: number) => -a
|
||||
export const subtract = (a: number, b: number) => a - b
|
||||
export const multiply = (a: number, b: number) => a * b
|
||||
export const divide = (a: number, b: number) => a / b
|
||||
export const sqrt =
|
||||
(dep: configDependency
|
||||
& Dependency<'complex', [number, number]>) => {
|
||||
if (dep.config.predictable || !dep.complex) {
|
||||
return (a: number) => isNaN(a) ? NaN : Math.sqrt(a)
|
||||
}
|
||||
return (a: number) => {
|
||||
& Dependency<'complex', [number, number]>): ImpType<'sqrt', [number]> => {
|
||||
if (dep.config.predictable || !dep.complex) return conservativeSqrt
|
||||
return a => {
|
||||
if (isNaN(a)) return NaN
|
||||
if (a >= 0) return Math.sqrt(a)
|
||||
return dep.complex(0, Math.sqrt(unaryMinus(a)))
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
export * from './type.js'
|
||||
export * from './arithmetic.js'
|
||||
export * from './predicate.js'
|
||||
export * from './relational.js'
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
import {ImpType} from '../core/Dispatcher.js'
|
||||
|
||||
type NumberPredicate = (a: number) => boolean
|
||||
declare module "./type" {
|
||||
interface NumbersImpTypes {
|
||||
isReal: NumberPredicate
|
||||
isSquare: NumberPredicate
|
||||
}
|
||||
}
|
||||
|
||||
export const isReal: ImpType<'isReal', [number]> = a => true
|
||||
export const isSquare: ImpType<'isSquare', [number]> = a => a >= 0
|
|
@ -0,0 +1,29 @@
|
|||
import {configDependency} from '../core/Config.js'
|
||||
import {ImpType, Dependency} from '../core/Dispatcher.js'
|
||||
|
||||
const DBL_EPSILON = Number.EPSILON || 2.2204460492503130808472633361816E-16
|
||||
|
||||
type NumberRelation = (a: number, b: number) => boolean
|
||||
|
||||
declare module "./type" {
|
||||
interface NumbersImpTypes {
|
||||
equal: NumberRelation
|
||||
}
|
||||
}
|
||||
|
||||
export const equal =
|
||||
(dep: configDependency): ImpType<'equal', [number, number]> =>
|
||||
(x, y) => {
|
||||
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
|
||||
}
|
|
@ -1,7 +1,21 @@
|
|||
import {ImpType} from '../core/Dispatcher.js'
|
||||
import type {UnderlyingReal} from '../Complex/type.js'
|
||||
|
||||
export const number_type = {
|
||||
before: ['Complex'],
|
||||
test: (n: unknown): n is number => typeof n === 'number',
|
||||
from: {string: s => +s}
|
||||
}
|
||||
|
||||
export const zero = (a: number) => 0
|
||||
|
||||
export interface NumbersImpTypes {
|
||||
zero: (a: number) => 0
|
||||
one: (a: number) => 1
|
||||
nan: (a: number) => typeof NaN
|
||||
re: (a: number) => number
|
||||
}
|
||||
|
||||
export const zero: ImpType<'zero', [number]> = a => 0
|
||||
export const one: ImpType<'one', [number]> = a => 1
|
||||
export const nan: ImpType<'nan', [number]> = a => NaN
|
||||
export const re: ImpType<'re', [number]> = a => a
|
||||
|
|
Loading…
Reference in New Issue