Merge pull request 'feat(quaternion): Add convenience quaternion creator function' (#48) from quaternion into main
Reviewed-on: #48
This commit is contained in:
commit
28ccbf8d48
6
src/bigint/absquare.mjs
Normal file
6
src/bigint/absquare.mjs
Normal file
@ -0,0 +1,6 @@
|
||||
export * from './Types/bigint.mjs'
|
||||
|
||||
/* Absolute value squared */
|
||||
export const absquare = {
|
||||
bigint: ({'square(bigint)': sqb}) => b => sqb(b)
|
||||
}
|
@ -3,6 +3,7 @@ import {identity} from '../generic/identity.mjs'
|
||||
|
||||
export * from './Types/bigint.mjs'
|
||||
|
||||
export {absquare} from './absquare.mjs'
|
||||
export {add} from './add.mjs'
|
||||
export {compare} from './compare.mjs'
|
||||
export const conjugate = {bigint: () => identity}
|
||||
|
@ -2,7 +2,9 @@ export * from './Types/Complex.mjs'
|
||||
|
||||
export const abs = {
|
||||
'Complex<T>': ({
|
||||
'sqrt(T)': sqt,
|
||||
sqrt, // Calculation of the type needed in the square root (the
|
||||
// underlying numeric type of T, whatever T is, is beyond Pocomath's
|
||||
// (current) template abilities, so punt and just do full resolution
|
||||
'absquare(Complex<T>)': absq
|
||||
}) => z => sqt(absq(z))
|
||||
}) => z => sqrt(absq(z))
|
||||
}
|
||||
|
@ -2,7 +2,8 @@ export * from './Types/Complex.mjs'
|
||||
|
||||
export const absquare = {
|
||||
'Complex<T>': ({
|
||||
'add(T,T)': plus,
|
||||
'square(T)': sqr
|
||||
}) => z => plus(sqr(z.re), sqr(z.im))
|
||||
add, // Calculation of exact type needed in add (underlying numeric of T)
|
||||
// is (currently) too involved for Pocomath
|
||||
'self(T)': absq
|
||||
}) => z => add(absq(z.re), absq(z.im))
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ export {invert} from './invert.mjs'
|
||||
export {isZero} from './isZero.mjs'
|
||||
export {multiply} from './multiply.mjs'
|
||||
export {negate} from './negate.mjs'
|
||||
export {quaternion} from './quaternion.mjs'
|
||||
export {quotient} from './quotient.mjs'
|
||||
export {roundquotient} from './roundquotient.mjs'
|
||||
export {sqrt} from './sqrt.mjs'
|
||||
|
5
src/complex/quaternion.mjs
Normal file
5
src/complex/quaternion.mjs
Normal file
@ -0,0 +1,5 @@
|
||||
export * from './Types/Complex.mjs'
|
||||
|
||||
export const quaternion = {
|
||||
'T,T,T,T': ({complex}) => (r,i,j,k) => complex(complex(r,j), complex(i,k))
|
||||
}
|
@ -64,6 +64,7 @@ export default class PocomathInstance {
|
||||
*/
|
||||
this._priorTypes = {}
|
||||
this._seenTypes = new Set() // all types that have occurred in a signature
|
||||
this._maxDepthSeen = 1 // deepest template nesting we've actually encountered
|
||||
this._invalid = new Set() // methods that are currently invalid
|
||||
this._config = {predictable: false, epsilon: 1e-12}
|
||||
const self = this
|
||||
@ -336,6 +337,7 @@ export default class PocomathInstance {
|
||||
let nextSuper = type
|
||||
while (nextSuper) {
|
||||
if (this._priorTypes[nextSuper].has(from)) break
|
||||
if (from === nextSuper) break
|
||||
this._typed.addConversion(
|
||||
{from, to: nextSuper, convert: spec.from[from]})
|
||||
this._invalidateDependents(':' + nextSuper)
|
||||
@ -360,12 +362,16 @@ export default class PocomathInstance {
|
||||
}
|
||||
let nextSuper = to
|
||||
while (nextSuper) {
|
||||
if (type === nextSuper) break
|
||||
try { // may already be a conversion, and no way to ask
|
||||
this._typed.addConversion({
|
||||
from: type,
|
||||
to: nextSuper,
|
||||
convert: this.Types[to].from[fromtype]
|
||||
})
|
||||
this._invalidateDependents(':' + nextSuper)
|
||||
} catch {
|
||||
}
|
||||
this._priorTypes[nextSuper].add(type)
|
||||
nextSuper = this.Types[nextSuper].refines
|
||||
}
|
||||
@ -609,6 +615,14 @@ export default class PocomathInstance {
|
||||
substituteInSig(rawSignature, theTemplateParam, instType)
|
||||
/* Don't override an explicit implementation: */
|
||||
if (signature in imps) continue
|
||||
/* Don't go too deep */
|
||||
let maxdepth = 0
|
||||
for (const argType in typeListOfSignature(signature)) {
|
||||
const depth = argType.split('<').length
|
||||
if (depth > maxdepth) maxdepth = depth
|
||||
}
|
||||
if (maxdepth > this._maxDepthSeen + 1) continue
|
||||
/* All right, go ahead and instantiate */
|
||||
const uses = new Set()
|
||||
for (const dep of behavior.uses) {
|
||||
if (this._templateParam(dep)) continue
|
||||
@ -718,6 +732,10 @@ export default class PocomathInstance {
|
||||
+ 'supertype of at least one of them')
|
||||
}
|
||||
}
|
||||
const depth = instantiateFor.split('<').length
|
||||
if (depth > self._maxDepthSeen) {
|
||||
self._maxDepthSeen = depth
|
||||
}
|
||||
/* Generate the list of actual wanted types */
|
||||
const wantTypes = parTypes.map(type => substituteInSig(
|
||||
type, theTemplateParam, instantiateFor))
|
||||
@ -790,6 +808,28 @@ export default class PocomathInstance {
|
||||
tf_imps, signature, {uses: outerUses, does: patch})
|
||||
}
|
||||
this._correctPartialSelfRefs(name, tf_imps)
|
||||
// Make sure we have all of the needed (template) types; and if they
|
||||
// can't be added (because they have been instantiated too deep),
|
||||
// ditch the signature:
|
||||
const badSigs = new Set()
|
||||
for (const sig in tf_imps) {
|
||||
for (const type of typeListOfSignature(sig)) {
|
||||
if (type.includes('<')) {
|
||||
// it's a template type, turn it into a template and an arg
|
||||
let base = type.split('<',1)[0]
|
||||
const arg = type.slice(base.length+1, -1)
|
||||
if (base.slice(0,3) === '...') {
|
||||
base = base.slice(3)
|
||||
}
|
||||
if (this.instantiateTemplate(base, arg) === undefined) {
|
||||
badSigs.add(sig)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const badSig of badSigs) {
|
||||
delete tf_imps[badSig]
|
||||
}
|
||||
const tf = this._typed(name, tf_imps)
|
||||
Object.defineProperty(this, name, {configurable: true, value: tf})
|
||||
return tf
|
||||
@ -928,8 +968,8 @@ export default class PocomathInstance {
|
||||
* in the instance.
|
||||
*/
|
||||
_ensureTemplateTypes(template, type) {
|
||||
let [base, arg] = template.split('<', 2)
|
||||
arg = arg.slice(0,-1)
|
||||
const base = template.split('<', 1)[0]
|
||||
const arg = template.slice(base.length + 1, -1)
|
||||
if (!arg) {
|
||||
throw new Error(
|
||||
'Implementation error in _ensureTemplateTypes', template, type)
|
||||
@ -951,9 +991,15 @@ export default class PocomathInstance {
|
||||
|
||||
/* Maybe add the instantiation of template type base with argument tyoe
|
||||
* instantiator to the Types of this instance, if it hasn't happened already.
|
||||
* Returns the name of the type if added, false otherwise.
|
||||
* Returns the name of the type if added, false if it was already there,
|
||||
* and undefined if the type is declined (because of being nested too deep).
|
||||
*/
|
||||
instantiateTemplate(base, instantiator) {
|
||||
const depth = instantiator.split('<').length
|
||||
if (depth > this._maxDepthSeen ) {
|
||||
// don't bother with types much deeper thant we have seen
|
||||
return undefined
|
||||
}
|
||||
const wantsType = `${base}<${instantiator}>`
|
||||
if (wantsType in this.Types) return false
|
||||
// OK, need to generate the type from the template
|
||||
|
6
src/number/absquare.mjs
Normal file
6
src/number/absquare.mjs
Normal file
@ -0,0 +1,6 @@
|
||||
export * from './Types/number.mjs'
|
||||
|
||||
/* Absolute value squared */
|
||||
export const absquare = {
|
||||
number: ({'square(number)': sqn}) => n => sqn(n)
|
||||
}
|
@ -4,6 +4,7 @@ import {identity} from '../generic/identity.mjs'
|
||||
export * from './Types/number.mjs'
|
||||
|
||||
export {abs} from './abs.mjs'
|
||||
export {absquare} from './absquare.mjs'
|
||||
export {add} from './add.mjs'
|
||||
export {compare} from './compare.mjs'
|
||||
export const conjugate = {number: () => identity}
|
||||
|
@ -68,4 +68,23 @@ describe('complex', () => {
|
||||
assert.strictEqual(math.floor(gi), gi) // literally a no-op
|
||||
})
|
||||
|
||||
it('performs rudimentary quaternion calculations', () => {
|
||||
const q0 = math.quaternion(1, 0, 1, 0)
|
||||
const q1 = math.quaternion(1, 0.5, 0.5, 0.75)
|
||||
assert.deepStrictEqual(
|
||||
q1,
|
||||
math.complex(math.complex(1, 0.5), math.complex(0.5, 0.75)))
|
||||
assert.deepStrictEqual(
|
||||
math.add(q0,q1),
|
||||
math.quaternion(2, 0.5, 1.5, 0.75))
|
||||
assert.deepStrictEqual(
|
||||
math.multiply(q0, q1),
|
||||
math.quaternion(0.5, 1.25, 1.5, 0.25))
|
||||
assert.deepStrictEqual(
|
||||
math.multiply(q0, math.quaternion(2, 1, 0.1, 0.1)),
|
||||
math.quaternion(1.9, 1.1, 2.1, -0.9))
|
||||
assert.strictEqual(math.abs(q0), Math.sqrt(2))
|
||||
assert.strictEqual(math.abs(q1), Math.sqrt(33)/4)
|
||||
})
|
||||
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user