2025-04-22 01:48:51 +00:00
|
|
|
import {Complex} from './Complex.js'
|
|
|
|
import {Returns} from "#core/Type.js"
|
2025-04-24 13:09:15 -07:00
|
|
|
import {Any, match} from "#core/TypePatterns.js"
|
2025-04-24 20:13:35 -07:00
|
|
|
import {BooleanT} from '#boolean/BooleanT.js'
|
2025-04-24 13:09:15 -07:00
|
|
|
import {NumberT} from '#number/NumberT.js'
|
2025-04-22 01:48:51 +00:00
|
|
|
|
refactor: change onType to match and take only one pattern and result (#22)
Pursuant to #12. Besides changing the name of onType to match, and only allowing one pattern and result in `match()`,
this PR also arranges that in place of an onType with lots of alternating PATTERN, VALUE, PATTERN, VALUE arguments, one now exports an _array_ of `match(PATTERN, VALUE)` items.
Doesn't quite fully resolve #12, because there is still the question of whether `match(...)` can be left out for a behavior that literally matches anything (current behavior), or whether `match(Passthru, behavior)` should be required for such cases.
Reviewed-on: https://code.studioinfinity.org/StudioInfinity/nanomath/pulls/22
Co-authored-by: Glen Whitney <glen@studioinfinity.org>
Co-committed-by: Glen Whitney <glen@studioinfinity.org>
2025-04-22 05:01:21 +00:00
|
|
|
export const complex = [
|
|
|
|
match(Any, (math, T) => {
|
2025-04-22 01:48:51 +00:00
|
|
|
const z = math.zero(T)
|
|
|
|
if (math.hasnan(T)) {
|
|
|
|
const isnan = math.isnan.resolve([T])
|
|
|
|
const compnan = math.nan(Complex(T))
|
|
|
|
return Returns(Complex(T), r => {
|
|
|
|
if (isnan(r)) return compnan
|
|
|
|
return {re: r, im: z}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return Returns(Complex(T), r => ({re: r, im: z}))
|
refactor: change onType to match and take only one pattern and result (#22)
Pursuant to #12. Besides changing the name of onType to match, and only allowing one pattern and result in `match()`,
this PR also arranges that in place of an onType with lots of alternating PATTERN, VALUE, PATTERN, VALUE arguments, one now exports an _array_ of `match(PATTERN, VALUE)` items.
Doesn't quite fully resolve #12, because there is still the question of whether `match(...)` can be left out for a behavior that literally matches anything (current behavior), or whether `match(Passthru, behavior)` should be required for such cases.
Reviewed-on: https://code.studioinfinity.org/StudioInfinity/nanomath/pulls/22
Co-authored-by: Glen Whitney <glen@studioinfinity.org>
Co-committed-by: Glen Whitney <glen@studioinfinity.org>
2025-04-22 05:01:21 +00:00
|
|
|
}),
|
|
|
|
match([Any, Any], (math, [T, U]) => {
|
2025-04-22 01:48:51 +00:00
|
|
|
if (T !== U) {
|
|
|
|
throw new RangeError(
|
|
|
|
'mixed complex types disallowed '
|
|
|
|
+ `(real ${T}, imaginary ${U})`)
|
|
|
|
}
|
|
|
|
return Returns(Complex(T), (r, m) => ({re: r, im: m}))
|
|
|
|
})
|
refactor: change onType to match and take only one pattern and result (#22)
Pursuant to #12. Besides changing the name of onType to match, and only allowing one pattern and result in `match()`,
this PR also arranges that in place of an onType with lots of alternating PATTERN, VALUE, PATTERN, VALUE arguments, one now exports an _array_ of `match(PATTERN, VALUE)` items.
Doesn't quite fully resolve #12, because there is still the question of whether `match(...)` can be left out for a behavior that literally matches anything (current behavior), or whether `match(Passthru, behavior)` should be required for such cases.
Reviewed-on: https://code.studioinfinity.org/StudioInfinity/nanomath/pulls/22
Co-authored-by: Glen Whitney <glen@studioinfinity.org>
Co-committed-by: Glen Whitney <glen@studioinfinity.org>
2025-04-22 05:01:21 +00:00
|
|
|
]
|
2025-04-24 13:09:15 -07:00
|
|
|
|
|
|
|
export const arg = match(
|
|
|
|
Complex(NumberT), Returns(NumberT, z => Math.atan2(z.im, z.re)))
|
2025-04-24 20:13:35 -07:00
|
|
|
|
|
|
|
/* Returns true if w is z multiplied by a complex unit */
|
|
|
|
export const associate = match([Complex, Complex], (math, [W, Z]) => {
|
|
|
|
if (Z.Component.complex) {
|
|
|
|
throw new Error(
|
|
|
|
`The group of units of type ${Z} is not yet implemented`)
|
|
|
|
}
|
|
|
|
const eq = math.equal.resolve([W, Z])
|
|
|
|
const neg = math.negate.resolve(Z)
|
|
|
|
const eqN = math.equal.resolve([W, neg.returns])
|
|
|
|
const mult = math.multiply.resolve([Z, Z])
|
|
|
|
const eqM = math.equal.resolve([W, mult.returns])
|
|
|
|
const negM = math.negate.resolve(mult.returns)
|
|
|
|
const eqNM = math.equal.resolve([W, negM.returns])
|
|
|
|
const iZ = math.complex(math.zero(Z.Component), math.one(Z.Component))
|
|
|
|
return Returns(BooleanT, (w, z) => {
|
|
|
|
if (eq(w, z) || eqN(w, neg(z))) return true
|
|
|
|
const iz = mult(iZ, z)
|
|
|
|
return eqM(w, iz) || eqNM(w, negM(iz))
|
|
|
|
})
|
2025-04-24 20:52:43 -07:00
|
|
|
})
|
|
|
|
|
|
|
|
export const cis = match(NumberT, Returns(Complex(NumberT), t => ({
|
|
|
|
re: Math.cos(t), im: Math.sin(t)})))
|