-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmatrix.ts
139 lines (105 loc) · 3.3 KB
/
matrix.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// A Matrix class that can be added, subtracted, and multiplied.
export type MatrixLike = ArrayLike<ArrayLike<number>>
export class Matrix {
static from(matrixLike: MatrixLike) {
const rows = matrixLike.length
if (rows <= 0) {
throw new Error(
"The matrix-like object has a zero or negative dimension.",
)
}
const cols = matrixLike[0]!.length
if (cols <= 0) {
throw new Error(
"The matrix-like object has a zero or negative dimension.",
)
}
const output = new Matrix(rows, cols)
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
output.data[row]![col] = matrixLike[row]![col]!
}
}
return output
}
data: number[][]
constructor(readonly rows = 1, readonly columns = 1) {
this.data = Array<void>(rows)
.fill()
.map(() => Array<number>().fill(columns))
}
copy() {
const output = new Matrix(this.rows, this.columns)
for (let row = 0; row < this.rows; row++) {
for (let col = 0; col < this.columns; col++) {
output.data[row]![col] = this.data[row]![col]!
}
}
return output
}
multiply(other: number | Matrix) {
if (typeof other == "number") {
const output = new Matrix(this.rows, this.columns)
for (let row = 0; row < this.rows; row++) {
for (let col = 0; col < this.columns; col++) {
output.data[row]![col] = this.data[row]![col]! * other
}
}
return output
}
if (this.columns !== other.rows) {
throw new Error(
"When multiplying matrices, the number of columns in the first matrix must be the same as the numbers of rows in the second matrix.",
)
}
const rows = this.rows
const cols = other.columns
const depth = this.columns // == other.rows
const output = new Matrix(rows, cols)
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
let sum = 0
for (let index = 0; index < depth; index++) {
sum += this.data[row]![index]! * other.data[index]![col]!
}
output.data[row]![col] = sum
}
}
return output
}
randomize(min = 0, max = 20) {
const pc = max - min + 1
for (let row = 0; row < this.rows; row++) {
for (let col = 0; col < this.columns; col++) {
this.data[row]![col] = Math.floor(pc * Math.random() + 1)
}
}
return this
}
divide(other: number) {
if (typeof other == "number") {
const output = new Matrix(this.rows, this.columns)
for (let row = 0; row < this.rows; row++) {
for (let col = 0; col < this.columns; col++) {
output.data[row]![col] = this.data[row]![col]! / other
}
}
return output
}
throw new Error("The other item is not a valid divisor.")
}
ascii() {
const toText = (item: unknown) => String(item)
const texts = this.data.map((row) => row.map(toText))
const maxSize = (size: number, now: string) =>
size < now.length ? now.length : size
const size = texts
.map((row) => row.reduce(maxSize, 0))
.reduce((a, b) => Math.max(a, b))
const onEach = (text: string) => text.padEnd(size)
return `[${texts
.map((row) => ` [${row.map(onEach).join(" ")}]`)
.join("\n")
.slice(1)}]`
}
}