import {Type} from '#core/Type.js' import {onType} from '#core/helpers.js' const isComplex = z => z && typeof z === 'object' && 're' in z && 'im' in z const specializesTo = CType => CType.complex function complexSpecialize(ComponentType) { const compTest = ComponentType.test const specTest = z => isComplex(z) && compTest(z.re) && compTest(z.im) const typeName = `Complex(${ComponentType})` if (ComponentType.concrete) { const fromSpec = [ ComponentType, math => r => ({re: r, im: ComponentType.zero})] for (const [matchType, fctry] of ComponentType.from.patterns) { fromSpec.push(this.specialize(matchType.type), math => { const compConv = fctry(math) return z => ({re: compConv(z.re), im: compConv(z.im)}) }) } const typeOptions = {from: onType(...fromSpec), typeName} if ('zero' in ComponentType) { typeOptions.zero = {re: ComponentType.zero, im: ComponentType.zero} if ('one' in ComponentType) { typeOptions.one = {re: ComponentType.one, im: ComponentType.zero} } } if ('nan' in ComponentType) { typeOptions.nan = {re: ComponentType.nan, im: ComponentType.nan} } const complexCompType = new Type(specTest, typeOptions) complexCompType.Component = ComponentType complexCompType.complex = true return complexCompType } // wrapping a generic type in Complex const cplx = this const innerSpecialize = (...args) => { const innerType = ComponentType.specialize(...args) return cplx.specialize(innerType) } const innerSpecializesTo = CType => specializesTo(CType) && ComponentType.specializesTo(CType.Component) const innerRefine = (z, typer) => { const reType = ComponentType.refine(z.re, typer) const imType = ComponentType.refine(z.im, typer) if (reType === imType) return cplx.specialize(reType) throw new TypeError( 'mixed-type Complex numbers disallowed ' + `(real: ${reType}, imaginary: ${imType})`) } return new Type(specTest, { specialize: innerSpecialize, specializesTo: innerSpecializesTo, refine: innerRefine, typeName, }) } export const Complex = new Type(isComplex, { specialize: complexSpecialize, specializesTo, refine: function(z, typer) { const reType = typer(z.re) const imType = typer(z.im) if (reType === imType) return this.specialize(reType) throw new TypeError( 'mixed-type Complex numbers disallowed ' + `(real: ${reType}, imaginary: ${imType})`) } })