You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

59 lines
1.9 KiB

type TupleOf<T, N extends number> = N extends N ? number extends N ? T[] : _TupleOf<T, N, []> : never
type _TupleOf<T, N extends number, R extends unknown[]> = R['length'] extends N ? R : _TupleOf<T, N, [T, ...R]>
export class Vector<N extends number> {
public readonly values: TupleOf<number, N>
constructor(
public readonly length: N
) {
this.values = Array(length).fill(0) as TupleOf<number, N>
}
}
export class Matrix<R extends number, C extends number> {
public readonly values: TupleOf<TupleOf<number, C>, R>
constructor(
public readonly rows: R,
public readonly cols: C,
) {
this.values = Array(rows).fill(0).map(() => Array(cols).fill(0) as TupleOf<number, C>) as TupleOf<TupleOf<number, C>, R>
}
isSquare() {
return Number(this.rows) === Number(this.cols)
}
set(row: number, col: number, value: number) {
this.validateCoordinates(row, col)
this.values[row-1 as R][col-1 as C] = value
}
get(row: number, col: number): number {
this.validateCoordinates(row, col)
return this.values[row-1 as R][col-1 as C] as number
}
getDeterminant() {
if ( !this.isSquare() ) {
throw new RangeError('Cannot find determinant of non-square matrix.')
}
const determinant = (m: number[][]): number =>
m.length == 1 ? m[0][0] :
m.length == 2 ? m[0][0]*m[1][1]-m[0][1]*m[1][0] :
m[0].reduce((r,e,i) =>
r+(-1)**(i+2)*e*determinant(m.slice(1).map(c =>
c.filter((_,j) => i != j))),0)
return determinant(this.values)
}
protected validateCoordinates(row: number, col: number) {
if ( row < 1 || row > Number(this.rows) || col < 1 || col > Number(this.cols) ) {
throw new RangeError('Invalid matrix coordinates')
}
}
}