-
-
Save robert-nix/8fd923d196a5b9d83ce0a188b3d148d2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as matrix from './matrix'; | |
import * as vec from './vec'; | |
test.each([ | |
[ | |
matrix.as<3, 2>([ | |
[1,2,3], | |
[4,5,6] | |
] as const), | |
matrix.as<2, 3>([ | |
[1, 4], | |
[2, 5], | |
[3, 6] | |
] as const) | |
], | |
[ | |
matrix.as<3, 1>([ | |
[1,2,3] | |
] as const), | |
matrix.as<1, 3>([ | |
[1], | |
[2], | |
[3] | |
] as const) | |
] | |
] as const)("matrix.transpose(%p) => %p", (a, b) => { | |
expect(matrix.transpose(a)).toEqual(b) | |
}) | |
test.each([ | |
[ [1,2,3], [3,2,1], 10] | |
])("vec.dot(%p, %p) => %p", (a, b, o) => { | |
expect(vec.dot(a, b)).toEqual(o) | |
}); | |
test.each([ | |
[ | |
matrix.as<2,3>([ | |
[1, 2], | |
[1, 4], | |
[6, 5] | |
] as const), | |
0, | |
[1, 1, 6] | |
] | |
])("matrix.col(%p, %p) => %p", (a, b, o) => { | |
expect([...matrix.col(a, b)]).toEqual(o) | |
}) | |
test.each([ | |
[ | |
matrix.as<2,3>([ | |
[1, 2], | |
[1, 4], | |
[6, 5] | |
] as const), | |
0, | |
[1, 2] | |
] | |
])("matrix.row(%p, %p) => %p", (a, b, o) => { | |
expect([...matrix.row(a, b)]).toEqual(o) | |
}) | |
test.each([ | |
[ | |
matrix.as<2, 1>([ | |
[6, 9] | |
] as const), | |
matrix.as<2, 2>([ | |
[0, 1], | |
[1, 0] | |
] as const), | |
matrix.as<2, 1>([ | |
[9, 6] | |
] as const) | |
], | |
[ | |
matrix.as<2,2>([ | |
[1, 0], | |
[0, 1] | |
]as const), | |
matrix.as<2, 2>([ | |
[2, 4], | |
[10, 9] | |
] as const), | |
matrix.as<2,2>([ | |
[2, 4], | |
[10, 9] | |
] as const) | |
] | |
])("matrix.mul(%p, %p) => %p", (a, b, o) => { | |
expect(matrix.mul(a, b)).toEqual(o) | |
}) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as vec from './vec'; | |
import { Vector } from './vec'; | |
// Matrix is a J-length vector of I-length vectors. | |
// The inner vectors are the rows, so the number of columns is I and the number of rows is J. | |
export interface Matrix<I extends number = number, J extends number = number, T = number> extends Vector<J, Vector<I, T>> { | |
} | |
export const as: | |
<I extends number = number, J extends number = number, T = number>(v: (readonly((readonly T[]) & { length: I })[]) & { length: J }) => Matrix<I, J, T> | |
= | |
v => v as any | |
; | |
export const add: | |
<I extends number, J extends number>(m1: Matrix<I, J>, m2: Matrix<I, J>) => Matrix<I,J> | |
= | |
<I extends number, J extends number>(m1: Matrix<I, J>, m2: Matrix<I, J>) => | |
vec.map(m1, (row, i) => vec.add(row, m2[i])) | |
; | |
export const row: | |
<I extends number, J extends number, T>(v: Matrix<I, J, T>, r: number) => Iterable<T> | |
= | |
function*(v, i) { | |
const a = v[i]; | |
if (!a) return; | |
for (let i = 0; i < a.length; i++) yield a[i]; | |
} | |
; | |
export const col: | |
<I extends number, J extends number, T>(v: Matrix<I, J, T>, i: number) => Iterable<T> | |
= | |
function*(v, i) { | |
const [, jsize] = size(v); | |
for (let j = 0; j < jsize; j++) yield v[j][i]; | |
} | |
; | |
// Since I1 = #cols, J1 = #rows, the result is a J1 rows x I2 cols matrix | |
export const mul: | |
<I1 extends number, J1 extends number, | |
I2 extends number, J2 extends number>(m1: Matrix<I1, J1>, m2: Matrix<I2, J2>) => | |
Matrix<I2, J1> | |
= | |
<I1 extends number, J1 extends number, I2 extends number, J2 extends number>( | |
m1: Matrix<I1, J1>, | |
m2: Matrix<I2, J2>) => { | |
const [i1, j1] = size(m1); | |
const [i2, j2] = size(m2); | |
return vec.map(vec.New<J1>(j1), (_, i) => | |
vec.map(vec.New<I2>(i2), (_, j) => vec.dot(row(m1, i), col(m2, j)))); | |
} | |
; | |
export const size: | |
<I extends number, J extends number>(m: Matrix<I, J, any>) => | |
J extends 0? [undefined, J]: [I, J] | |
= | |
m => [m[0]?.length, m.length] as any | |
; | |
export const transpose: | |
<I extends number, J extends number>(m: Matrix<I, J>) => Matrix<J, I> | |
= | |
<I extends number, J extends number>(m: Matrix<I, J>) => { | |
const [i, j] = size(m) | |
const rows = vec.New<I>(i); | |
return vec.map(rows, (_, rj) => vec.map(vec.New<J>(j), (__, vi) => m[vi][rj])) | |
} | |
; | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface ReadonlyArrayOfLength<T, I extends number> extends ReadonlyArray<T> { | |
length: I | |
} | |
export interface Vector<I extends number = number, T = number> extends ReadonlyArrayOfLength<T, I> { | |
length: I | |
} | |
type mapFn<I extends number, T> = <U>(callbackFn: (value: T, index: number, array: Vector<I, T>) => U, thisArg?: any) => | |
Vector<I, U>; | |
export const map: | |
<I extends number, T, U>( | |
vec: Vector<I, T>, | |
callbackFn: (value: T, index: number, array: Vector<I, T>) => U) => | |
Vector<I, U> | |
= | |
(vec, c) => (vec.map as mapFn<any, any>)(c) | |
; | |
export const imap: | |
<T, U>( | |
v: Iterable<T>, | |
f: (v: T, i: number) => U) => Iterable<U> | |
= | |
function*(v, f) { | |
let i = 0; | |
for (const l of v) { | |
yield f(l, i) | |
i++ | |
} | |
} | |
; | |
export const as: | |
<T, L extends number>(v: (readonly T[]) & { length: L }) => Vector<L, T> | |
= | |
v => v as any | |
; | |
export const New: | |
<N extends number>(n: number) => Vector<N, undefined> | |
= | |
n => [...Array(n)] as any as Vector<any, undefined> | |
; | |
export const add: | |
<I extends number>(v1: Vector<I>, v2: Vector<I>) => Vector<I> | |
= | |
(v1, v2) => map(v1, (v, i) => v + v2[i]) | |
; | |
export const mul: | |
<I extends number>(v1: number, v2: Vector<I>) => Vector<I> | |
= | |
(v1, v2) => map(v2, (v, i) => v * v1) | |
; | |
export const dot: | |
(v1: Iterable<number>, v2: Iterable<number>) => | |
number | |
= | |
(v1, v2) => | |
sum(imap(zip(v1, v2, 0 as const), ([a = 0 as const, b = 0 as const]) => a * b)) | |
; | |
export const sum: | |
(v1: Iterable<number>) => number | |
= | |
v => [...v].reduce((a, c) => a+c, 0) | |
; | |
export const zip: | |
<T1, T2, T3 >(v1: Iterable<T1>, v2: Iterable<T2>, fb: T3) => Iterable<[T1 | T3, T2 | T3]> | |
= | |
function*(v1, v2, fb) { | |
const [a, b] = [v1[Symbol.iterator](), v2[Symbol.iterator]()]; | |
for (let i = 0; ; i++) { | |
const [ar, br] = [a.next(), b.next()]; | |
const left = ar.done? fb: ar.value; | |
const right = br.done? fb: br.value; | |
if (ar.done&& br.done) break; | |
yield [left, right] | |
} | |
} | |
; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment