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
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')
|
|
}
|
|
}
|
|
}
|