feat(polynomialRoot): Initial implementation (linear only)
This commit is contained in:
parent
31add66f4c
commit
de52c041e5
@ -9,9 +9,11 @@ export {conjugate} from './conjugate.mjs'
|
|||||||
export {equalTT} from './equalTT.mjs'
|
export {equalTT} from './equalTT.mjs'
|
||||||
export {gcd} from './gcd.mjs'
|
export {gcd} from './gcd.mjs'
|
||||||
export {invert} from './invert.mjs'
|
export {invert} from './invert.mjs'
|
||||||
|
export {isReal} from './isReal.mjs'
|
||||||
export {isZero} from './isZero.mjs'
|
export {isZero} from './isZero.mjs'
|
||||||
export {multiply} from './multiply.mjs'
|
export {multiply} from './multiply.mjs'
|
||||||
export {negate} from './negate.mjs'
|
export {negate} from './negate.mjs'
|
||||||
|
export {polynomialRoot} from './polynomialRoot.mjs'
|
||||||
export {quaternion} from './quaternion.mjs'
|
export {quaternion} from './quaternion.mjs'
|
||||||
export {quotient} from './quotient.mjs'
|
export {quotient} from './quotient.mjs'
|
||||||
export {roundquotient} from './roundquotient.mjs'
|
export {roundquotient} from './roundquotient.mjs'
|
||||||
|
@ -87,6 +87,7 @@ function substituteInSignature(signature, parameter, type) {
|
|||||||
return sig.replaceAll(pattern, type)
|
return sig.replaceAll(pattern, type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const UniversalType = 'ground' // name for a type that matches anything
|
||||||
let lastWhatToDo = null // used in an infinite descent check
|
let lastWhatToDo = null // used in an infinite descent check
|
||||||
|
|
||||||
export default class PocomathInstance {
|
export default class PocomathInstance {
|
||||||
@ -128,12 +129,13 @@ export default class PocomathInstance {
|
|||||||
// its onMismatch function, below:
|
// its onMismatch function, below:
|
||||||
this._metaTyped = typed.create()
|
this._metaTyped = typed.create()
|
||||||
this._metaTyped.clear()
|
this._metaTyped.clear()
|
||||||
|
this._metaTyped.addTypes([{name: UniversalType, test: () => true}])
|
||||||
|
|
||||||
// And these are the meta bindings: (I think we don't need separate
|
// And these are the meta bindings: (I think we don't need separate
|
||||||
// invalidation for them as they are only accessed through a main call.)
|
// invalidation for them as they are only accessed through a main call.)
|
||||||
this._meta = {} // The resulting typed-functions
|
this._meta = {} // The resulting typed-functions
|
||||||
this._metaTFimps = {} // and their implementations
|
this._metaTFimps = {} // and their implementations
|
||||||
const me = this
|
const me = this
|
||||||
const myTyped = this._typed
|
|
||||||
this._typed.onMismatch = (name, args, sigs) => {
|
this._typed.onMismatch = (name, args, sigs) => {
|
||||||
if (me._invalid.has(name)) {
|
if (me._invalid.has(name)) {
|
||||||
// rebuild implementation and try again
|
// rebuild implementation and try again
|
||||||
@ -523,6 +525,10 @@ export default class PocomathInstance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Need to metafy ground types
|
||||||
|
if (type === base) {
|
||||||
|
this._metafy(type)
|
||||||
|
}
|
||||||
// update the typeOf function
|
// update the typeOf function
|
||||||
const imp = {}
|
const imp = {}
|
||||||
imp[type] = {uses: new Set(), does: () => Returns('string', () => type)}
|
imp[type] = {uses: new Set(), does: () => Returns('string', () => type)}
|
||||||
@ -640,7 +646,7 @@ export default class PocomathInstance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// install the "base type" in the meta universe:
|
// install the "base type" in the meta universe:
|
||||||
let beforeType = 'any'
|
let beforeType = UniversalType
|
||||||
for (const other of spec.before || []) {
|
for (const other of spec.before || []) {
|
||||||
if (other in this.templates) {
|
if (other in this.templates) {
|
||||||
beforeType = other
|
beforeType = other
|
||||||
@ -648,6 +654,13 @@ export default class PocomathInstance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this._metaTyped.addTypes([{name: base, test: spec.base}], beforeType)
|
this._metaTyped.addTypes([{name: base, test: spec.base}], beforeType)
|
||||||
|
// Add conversions to the base type:
|
||||||
|
if (spec.from && spec.from[theTemplateParam]) {
|
||||||
|
for (const ground of this._metafiedTypes) {
|
||||||
|
this._metaTyped.addConversion(
|
||||||
|
{from: ground, to: base, convert: spec.from[theTemplateParam]})
|
||||||
|
}
|
||||||
|
}
|
||||||
this._instantiationsOf[base] = new Set()
|
this._instantiationsOf[base] = new Set()
|
||||||
|
|
||||||
// update the typeOf function
|
// update the typeOf function
|
||||||
@ -881,7 +894,7 @@ export default class PocomathInstance {
|
|||||||
basesig, theTemplateParam, '')
|
basesig, theTemplateParam, '')
|
||||||
if (testsig === basesig) {
|
if (testsig === basesig) {
|
||||||
// that is not also top-level
|
// that is not also top-level
|
||||||
for (const templateType of typeListOfSignature(basesig)) {
|
for (let templateType of typeListOfSignature(basesig)) {
|
||||||
if (templateType.slice(0,3) === '...') {
|
if (templateType.slice(0,3) === '...') {
|
||||||
templateType = templateType.slice(3)
|
templateType = templateType.slice(3)
|
||||||
}
|
}
|
||||||
@ -908,7 +921,7 @@ export default class PocomathInstance {
|
|||||||
let baseSignature = rawSignature.replaceAll(templateCall, '')
|
let baseSignature = rawSignature.replaceAll(templateCall, '')
|
||||||
/* Any remaining template params are top-level */
|
/* Any remaining template params are top-level */
|
||||||
const signature = substituteInSignature(
|
const signature = substituteInSignature(
|
||||||
baseSignature, theTemplateParam, 'any')
|
baseSignature, theTemplateParam, UniversalType)
|
||||||
const hasTopLevel = (signature !== baseSignature)
|
const hasTopLevel = (signature !== baseSignature)
|
||||||
if (!ubType && hasTopLevel) {
|
if (!ubType && hasTopLevel) {
|
||||||
for (const othersig in imps) {
|
for (const othersig in imps) {
|
||||||
@ -939,7 +952,6 @@ export default class PocomathInstance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const instType of instantiationSet) {
|
for (const instType of instantiationSet) {
|
||||||
this._instantiateTemplateImplementation(name, rawSignature, instType)
|
this._instantiateTemplateImplementation(name, rawSignature, instType)
|
||||||
}
|
}
|
||||||
@ -1018,9 +1030,10 @@ export default class PocomathInstance {
|
|||||||
usedConversions = true
|
usedConversions = true
|
||||||
instantiateFor = self.joinTypes(argTypes, usedConversions)
|
instantiateFor = self.joinTypes(argTypes, usedConversions)
|
||||||
if (instantiateFor === 'any') {
|
if (instantiateFor === 'any') {
|
||||||
|
let argDisplay = args.map(toString).join(', ')
|
||||||
throw TypeError(
|
throw TypeError(
|
||||||
`In call to ${name}, no type unifies arguments `
|
`In call to ${name}, no type unifies arguments `
|
||||||
+ args.toString() + '; of types ' + argTypes.toString()
|
+ argDisplay + '; of types ' + argTypes.toString()
|
||||||
+ '; note each consecutive pair must unify to a '
|
+ '; note each consecutive pair must unify to a '
|
||||||
+ 'supertype of at least one of them')
|
+ 'supertype of at least one of them')
|
||||||
}
|
}
|
||||||
@ -1042,7 +1055,9 @@ export default class PocomathInstance {
|
|||||||
for (j = 0; j < parTypes.length; ++j) {
|
for (j = 0; j < parTypes.length; ++j) {
|
||||||
if (wantTypes[j] !== parTypes[j] && parTypes[j].includes('<')) {
|
if (wantTypes[j] !== parTypes[j] && parTypes[j].includes('<')) {
|
||||||
// actually used the param and is a template
|
// actually used the param and is a template
|
||||||
self._ensureTemplateTypes(parTypes[j], instantiateFor)
|
const strippedType = parTypes[j].substr(
|
||||||
|
parTypes[j].lastIndexOf('.') + 1)
|
||||||
|
self._ensureTemplateTypes(strippedType, instantiateFor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1117,11 +1132,13 @@ export default class PocomathInstance {
|
|||||||
if (Object.keys(tf_imps).length > 0) {
|
if (Object.keys(tf_imps).length > 0) {
|
||||||
tf = this._typed(name, tf_imps)
|
tf = this._typed(name, tf_imps)
|
||||||
tf.fromInstance = this
|
tf.fromInstance = this
|
||||||
|
tf.isMeta = false
|
||||||
}
|
}
|
||||||
let metaTF
|
let metaTF
|
||||||
if (Object.keys(meta_imps).length > 0) {
|
if (Object.keys(meta_imps).length > 0) {
|
||||||
metaTF = this._metaTyped(name, meta_imps)
|
metaTF = this._metaTyped(name, meta_imps)
|
||||||
metaTF.fromInstance = this
|
metaTF.fromInstance = this
|
||||||
|
metaTF.isMeta = true
|
||||||
}
|
}
|
||||||
this._meta[name] = metaTF
|
this._meta[name] = metaTF
|
||||||
|
|
||||||
@ -1325,6 +1342,14 @@ export default class PocomathInstance {
|
|||||||
if (destination && needsig) {
|
if (destination && needsig) {
|
||||||
destination = this.resolve(func, needsig)
|
destination = this.resolve(func, needsig)
|
||||||
}
|
}
|
||||||
|
if (!destination) {
|
||||||
|
// Unresolved reference. This is allowed so that
|
||||||
|
// you can bundle up just some portions of the library,
|
||||||
|
// but let's warn.
|
||||||
|
console.log(
|
||||||
|
'WARNING: No definition found for dependency',
|
||||||
|
dep, 'needed by a function with signature', signature)
|
||||||
|
}
|
||||||
refs[dep] = destination
|
refs[dep] = destination
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1364,76 +1389,85 @@ export default class PocomathInstance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_correctPartialSelfRefs(name, imps) {
|
_correctPartialSelfRefs(name, imps) {
|
||||||
for (const aSignature in imps) {
|
let sawDeferral = true
|
||||||
if (!(imps[aSignature].deferred)) continue
|
while (sawDeferral) {
|
||||||
const deferral = imps[aSignature]
|
// We might generate some new partial self references in resolving
|
||||||
const part_self_references = deferral.psr
|
// the previously existing ones, so looping through the signatures
|
||||||
const corrected_self_references = []
|
// once is not enough; we have to keep looping until there are no
|
||||||
const remaining_self_references = []
|
// more deferrals
|
||||||
const refs = deferral.builtRefs
|
sawDeferral = false
|
||||||
for (const neededSig of part_self_references) {
|
for (const aSignature in imps) {
|
||||||
// Have to find a match for neededSig among the other signatures
|
if (!(imps[aSignature].deferred)) continue
|
||||||
// of this function. That's a job for typed-function, but we will
|
sawDeferral = true
|
||||||
// try here:
|
const deferral = imps[aSignature]
|
||||||
if (neededSig in imps) { // the easy case
|
const part_self_references = deferral.psr
|
||||||
corrected_self_references.push(neededSig)
|
const corrected_self_references = []
|
||||||
remaining_self_references.push(neededSig)
|
const remaining_self_references = []
|
||||||
continue
|
const refs = deferral.builtRefs
|
||||||
}
|
for (const neededSig of part_self_references) {
|
||||||
// No exact match, try to get one that matches with
|
// Have to find a match for neededSig among the other signatures
|
||||||
// subtypes since the whole conversion thing in typed-function
|
// of this function. That's a job for typed-function, but we will
|
||||||
// is too complicated to reproduce
|
// try here:
|
||||||
let foundSig = this._findSubtypeImpl(name, imps, neededSig)
|
if (neededSig in imps) { // the easy case
|
||||||
if (foundSig) {
|
corrected_self_references.push(neededSig)
|
||||||
corrected_self_references.push(foundSig)
|
remaining_self_references.push(neededSig)
|
||||||
remaining_self_references.push(neededSig)
|
continue
|
||||||
} else {
|
}
|
||||||
// Maybe it's a template instance we don't yet have
|
// No exact match, try to get one that matches with
|
||||||
foundSig = this._findSubtypeImpl(
|
// subtypes since the whole conversion thing in typed-function
|
||||||
name, this._imps[name], neededSig)
|
// is too complicated to reproduce
|
||||||
|
let foundSig = this._findSubtypeImpl(name, imps, neededSig)
|
||||||
if (foundSig) {
|
if (foundSig) {
|
||||||
const match = this._pocoFindSignature(name, neededSig)
|
corrected_self_references.push(foundSig)
|
||||||
const neededTemplate = match.fn._pocoSignature
|
remaining_self_references.push(neededSig)
|
||||||
const neededInstance = whichSigInstance(
|
|
||||||
neededSig, neededTemplate)
|
|
||||||
const neededImplementation =
|
|
||||||
this._instantiateTemplateImplementation(
|
|
||||||
name, neededTemplate, neededInstance)
|
|
||||||
if (!neededImplementation) {
|
|
||||||
refs[`self(${neededSig})`] = match.implementation
|
|
||||||
} else {
|
|
||||||
if (typeof neededImplementation === 'function') {
|
|
||||||
refs[`self(${neededSig})`] = neededImplementation
|
|
||||||
} else {
|
|
||||||
corrected_self_references.push(neededSig)
|
|
||||||
remaining_self_references.push(neededSig)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error(
|
// Maybe it's a template instance we don't yet have
|
||||||
'Implement inexact self-reference in typed-function for '
|
foundSig = this._findSubtypeImpl(
|
||||||
+ `${name}(${neededSig})`)
|
name, this._imps[name], neededSig)
|
||||||
|
if (foundSig) {
|
||||||
|
const match = this._pocoFindSignature(name, neededSig)
|
||||||
|
const neededTemplate = match.fn._pocoSignature
|
||||||
|
const neededInstance = whichSigInstance(
|
||||||
|
neededSig, neededTemplate)
|
||||||
|
const neededImplementation =
|
||||||
|
this._instantiateTemplateImplementation(
|
||||||
|
name, neededTemplate, neededInstance)
|
||||||
|
if (!neededImplementation) {
|
||||||
|
refs[`self(${neededSig})`] = match.implementation
|
||||||
|
} else {
|
||||||
|
if (typeof neededImplementation === 'function') {
|
||||||
|
refs[`self(${neededSig})`] = neededImplementation
|
||||||
|
} else {
|
||||||
|
corrected_self_references.push(neededSig)
|
||||||
|
remaining_self_references.push(neededSig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
'Implement inexact self-reference in typed-function for '
|
||||||
|
+ `${name}(${neededSig})`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
const does = deferral.sigDoes
|
||||||
const does = deferral.sigDoes
|
if (remaining_self_references.length > 0) {
|
||||||
if (remaining_self_references.length > 0) {
|
imps[aSignature] = this._typed.referTo(
|
||||||
imps[aSignature] = this._typed.referTo(
|
...corrected_self_references, (...impls) => {
|
||||||
...corrected_self_references, (...impls) => {
|
for (let i = 0; i < remaining_self_references.length; ++i) {
|
||||||
for (let i = 0; i < remaining_self_references.length; ++i) {
|
refs[`self(${remaining_self_references[i]})`] = impls[i]
|
||||||
refs[`self(${remaining_self_references[i]})`] = impls[i]
|
}
|
||||||
|
const implementation = does(refs)
|
||||||
|
// What will we do with the return type info in here?
|
||||||
|
return implementation
|
||||||
}
|
}
|
||||||
const implementation = does(refs)
|
)
|
||||||
// What will we do with the return type info in here?
|
} else {
|
||||||
return implementation
|
imps[aSignature] = does(refs)
|
||||||
}
|
}
|
||||||
)
|
imps[aSignature]._pocoSignature = deferral._pocoSignature
|
||||||
} else {
|
imps[aSignature]._pocoInstance = deferral._pocoInstance
|
||||||
imps[aSignature] = does(refs)
|
imps[aSignature].fromInstance = deferral.fromInstance
|
||||||
}
|
}
|
||||||
imps[aSignature]._pocoSignature = deferral._pocoSignature
|
|
||||||
imps[aSignature]._pocoInstance = deferral._pocoInstance
|
|
||||||
imps[aSignature].fromInstance = deferral.fromInstance
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1550,7 +1584,7 @@ export default class PocomathInstance {
|
|||||||
const otherTypeList = typeListOfSignature(otherSig)
|
const otherTypeList = typeListOfSignature(otherSig)
|
||||||
if (typeList.length !== otherTypeList.length) continue
|
if (typeList.length !== otherTypeList.length) continue
|
||||||
let allMatch = true
|
let allMatch = true
|
||||||
let paramBound = 'any'
|
let paramBound = UniversalType
|
||||||
for (let k = 0; k < typeList.length; ++k) {
|
for (let k = 0; k < typeList.length; ++k) {
|
||||||
let myType = typeList[k]
|
let myType = typeList[k]
|
||||||
let otherType = otherTypeList[k]
|
let otherType = otherTypeList[k]
|
||||||
@ -1577,6 +1611,7 @@ export default class PocomathInstance {
|
|||||||
theTemplateParam, paramBound)
|
theTemplateParam, paramBound)
|
||||||
}
|
}
|
||||||
if (otherType === 'any') continue
|
if (otherType === 'any') continue
|
||||||
|
if (otherType === UniversalType) continue
|
||||||
if (myType === otherType) continue
|
if (myType === otherType) continue
|
||||||
if (otherType in this.Templates) {
|
if (otherType in this.Templates) {
|
||||||
const [myBase] = splitTemplate(myType)
|
const [myBase] = splitTemplate(myType)
|
||||||
@ -1608,6 +1643,7 @@ export default class PocomathInstance {
|
|||||||
typedFunction = this[name]
|
typedFunction = this[name]
|
||||||
}
|
}
|
||||||
const haveTF = this._typed.isTypedFunction(typedFunction)
|
const haveTF = this._typed.isTypedFunction(typedFunction)
|
||||||
|
&& !(typedFunction.isMeta)
|
||||||
if (haveTF) {
|
if (haveTF) {
|
||||||
// First try a direct match
|
// First try a direct match
|
||||||
let result
|
let result
|
||||||
|
@ -6,5 +6,5 @@ export {Tuple} from './Types/Tuple.mjs'
|
|||||||
* are convertible to the same type.
|
* are convertible to the same type.
|
||||||
*/
|
*/
|
||||||
export const tuple = {
|
export const tuple = {
|
||||||
'...T': ({T}) => Returns(`Tuple<${T}>`, args => ({elts: args}))
|
'...T': ({T}) => Returns(`Tuple<${T}>`, args => ({elts: args}))
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,11 @@ describe('complex', () => {
|
|||||||
assert.ok(!(math.equal(math.complex(45n, 3n), 45n)))
|
assert.ok(!(math.equal(math.complex(45n, 3n), 45n)))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('tests for reality', () => {
|
||||||
|
assert.ok(math.isReal(math.complex(3, 0)))
|
||||||
|
assert.ok(!(math.isReal(math.complex(3, 2))))
|
||||||
|
})
|
||||||
|
|
||||||
it('computes gcd', () => {
|
it('computes gcd', () => {
|
||||||
assert.deepStrictEqual(
|
assert.deepStrictEqual(
|
||||||
math.gcd(math.complex(53n, 56n), math.complex(47n, -13n)),
|
math.gcd(math.complex(53n, 56n), math.complex(47n, -13n)),
|
||||||
|
Loading…
Reference in New Issue
Block a user