@pawells/math-extended 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +319 -0
- package/build/angles.d.ts +31 -0
- package/build/angles.d.ts.map +1 -0
- package/build/angles.js +85 -0
- package/build/angles.js.map +1 -0
- package/build/angles.spec.d.ts +2 -0
- package/build/angles.spec.d.ts.map +1 -0
- package/build/angles.spec.js +147 -0
- package/build/angles.spec.js.map +1 -0
- package/build/clamp.d.ts +17 -0
- package/build/clamp.d.ts.map +1 -0
- package/build/clamp.js +19 -0
- package/build/clamp.js.map +1 -0
- package/build/clamp.spec.d.ts +2 -0
- package/build/clamp.spec.d.ts.map +1 -0
- package/build/clamp.spec.js +19 -0
- package/build/clamp.spec.js.map +1 -0
- package/build/documentation-validation.spec.d.ts +11 -0
- package/build/documentation-validation.spec.d.ts.map +1 -0
- package/build/documentation-validation.spec.js +401 -0
- package/build/documentation-validation.spec.js.map +1 -0
- package/build/index.d.ts +8 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +8 -0
- package/build/index.js.map +1 -0
- package/build/interpolation.d.ts +175 -0
- package/build/interpolation.d.ts.map +1 -0
- package/build/interpolation.js +369 -0
- package/build/interpolation.js.map +1 -0
- package/build/interpolation.spec.d.ts +2 -0
- package/build/interpolation.spec.d.ts.map +1 -0
- package/build/interpolation.spec.js +480 -0
- package/build/interpolation.spec.js.map +1 -0
- package/build/matrices/arithmetic.d.ts +411 -0
- package/build/matrices/arithmetic.d.ts.map +1 -0
- package/build/matrices/arithmetic.js +954 -0
- package/build/matrices/arithmetic.js.map +1 -0
- package/build/matrices/arithmetic.spec.d.ts +2 -0
- package/build/matrices/arithmetic.spec.d.ts.map +1 -0
- package/build/matrices/arithmetic.spec.js +915 -0
- package/build/matrices/arithmetic.spec.js.map +1 -0
- package/build/matrices/asserts.d.ts +306 -0
- package/build/matrices/asserts.d.ts.map +1 -0
- package/build/matrices/asserts.js +396 -0
- package/build/matrices/asserts.js.map +1 -0
- package/build/matrices/asserts.spec.d.ts +2 -0
- package/build/matrices/asserts.spec.d.ts.map +1 -0
- package/build/matrices/asserts.spec.js +565 -0
- package/build/matrices/asserts.spec.js.map +1 -0
- package/build/matrices/core.d.ts +168 -0
- package/build/matrices/core.d.ts.map +1 -0
- package/build/matrices/core.js +457 -0
- package/build/matrices/core.js.map +1 -0
- package/build/matrices/core.spec.d.ts +2 -0
- package/build/matrices/core.spec.d.ts.map +1 -0
- package/build/matrices/core.spec.js +634 -0
- package/build/matrices/core.spec.js.map +1 -0
- package/build/matrices/decompositions.d.ts +326 -0
- package/build/matrices/decompositions.d.ts.map +1 -0
- package/build/matrices/decompositions.js +816 -0
- package/build/matrices/decompositions.js.map +1 -0
- package/build/matrices/decompositions.spec.d.ts +2 -0
- package/build/matrices/decompositions.spec.d.ts.map +1 -0
- package/build/matrices/decompositions.spec.js +195 -0
- package/build/matrices/decompositions.spec.js.map +1 -0
- package/build/matrices/index.d.ts +9 -0
- package/build/matrices/index.d.ts.map +1 -0
- package/build/matrices/index.js +9 -0
- package/build/matrices/index.js.map +1 -0
- package/build/matrices/linear-algebra.d.ts +64 -0
- package/build/matrices/linear-algebra.d.ts.map +1 -0
- package/build/matrices/linear-algebra.js +253 -0
- package/build/matrices/linear-algebra.js.map +1 -0
- package/build/matrices/linear-algebra.spec.d.ts +2 -0
- package/build/matrices/linear-algebra.spec.d.ts.map +1 -0
- package/build/matrices/linear-algebra.spec.js +355 -0
- package/build/matrices/linear-algebra.spec.js.map +1 -0
- package/build/matrices/normalization.d.ts +62 -0
- package/build/matrices/normalization.d.ts.map +1 -0
- package/build/matrices/normalization.js +167 -0
- package/build/matrices/normalization.js.map +1 -0
- package/build/matrices/normalization.spec.d.ts +2 -0
- package/build/matrices/normalization.spec.d.ts.map +1 -0
- package/build/matrices/normalization.spec.js +335 -0
- package/build/matrices/normalization.spec.js.map +1 -0
- package/build/matrices/transformations.d.ts +484 -0
- package/build/matrices/transformations.d.ts.map +1 -0
- package/build/matrices/transformations.js +592 -0
- package/build/matrices/transformations.js.map +1 -0
- package/build/matrices/transformations.spec.d.ts +2 -0
- package/build/matrices/transformations.spec.d.ts.map +1 -0
- package/build/matrices/transformations.spec.js +755 -0
- package/build/matrices/transformations.spec.js.map +1 -0
- package/build/matrices/types.d.ts +134 -0
- package/build/matrices/types.d.ts.map +1 -0
- package/build/matrices/types.js +6 -0
- package/build/matrices/types.js.map +1 -0
- package/build/quaternions/asserts.d.ts +77 -0
- package/build/quaternions/asserts.d.ts.map +1 -0
- package/build/quaternions/asserts.js +175 -0
- package/build/quaternions/asserts.js.map +1 -0
- package/build/quaternions/asserts.spec.d.ts +2 -0
- package/build/quaternions/asserts.spec.d.ts.map +1 -0
- package/build/quaternions/asserts.spec.js +320 -0
- package/build/quaternions/asserts.spec.js.map +1 -0
- package/build/quaternions/conversions.d.ts +73 -0
- package/build/quaternions/conversions.d.ts.map +1 -0
- package/build/quaternions/conversions.js +179 -0
- package/build/quaternions/conversions.js.map +1 -0
- package/build/quaternions/conversions.spec.d.ts +2 -0
- package/build/quaternions/conversions.spec.d.ts.map +1 -0
- package/build/quaternions/conversions.spec.js +344 -0
- package/build/quaternions/conversions.spec.js.map +1 -0
- package/build/quaternions/core.d.ts +203 -0
- package/build/quaternions/core.d.ts.map +1 -0
- package/build/quaternions/core.js +374 -0
- package/build/quaternions/core.js.map +1 -0
- package/build/quaternions/core.spec.d.ts +2 -0
- package/build/quaternions/core.spec.d.ts.map +1 -0
- package/build/quaternions/core.spec.js +294 -0
- package/build/quaternions/core.spec.js.map +1 -0
- package/build/quaternions/index.d.ts +7 -0
- package/build/quaternions/index.d.ts.map +1 -0
- package/build/quaternions/index.js +7 -0
- package/build/quaternions/index.js.map +1 -0
- package/build/quaternions/interpolation.d.ts +54 -0
- package/build/quaternions/interpolation.d.ts.map +1 -0
- package/build/quaternions/interpolation.js +201 -0
- package/build/quaternions/interpolation.js.map +1 -0
- package/build/quaternions/interpolation.spec.d.ts +2 -0
- package/build/quaternions/interpolation.spec.d.ts.map +1 -0
- package/build/quaternions/interpolation.spec.js +64 -0
- package/build/quaternions/interpolation.spec.js.map +1 -0
- package/build/quaternions/predefined.d.ts +36 -0
- package/build/quaternions/predefined.d.ts.map +1 -0
- package/build/quaternions/predefined.js +42 -0
- package/build/quaternions/predefined.js.map +1 -0
- package/build/quaternions/predefined.spec.d.ts +2 -0
- package/build/quaternions/predefined.spec.d.ts.map +1 -0
- package/build/quaternions/predefined.spec.js +35 -0
- package/build/quaternions/predefined.spec.js.map +1 -0
- package/build/quaternions/types.d.ts +55 -0
- package/build/quaternions/types.d.ts.map +1 -0
- package/build/quaternions/types.js +7 -0
- package/build/quaternions/types.js.map +1 -0
- package/build/random.d.ts +66 -0
- package/build/random.d.ts.map +1 -0
- package/build/random.js +115 -0
- package/build/random.js.map +1 -0
- package/build/random.spec.d.ts +2 -0
- package/build/random.spec.d.ts.map +1 -0
- package/build/random.spec.js +267 -0
- package/build/random.spec.js.map +1 -0
- package/build/vectors/asserts.d.ts +182 -0
- package/build/vectors/asserts.d.ts.map +1 -0
- package/build/vectors/asserts.js +285 -0
- package/build/vectors/asserts.js.map +1 -0
- package/build/vectors/asserts.spec.d.ts +2 -0
- package/build/vectors/asserts.spec.d.ts.map +1 -0
- package/build/vectors/asserts.spec.js +260 -0
- package/build/vectors/asserts.spec.js.map +1 -0
- package/build/vectors/core.d.ts +507 -0
- package/build/vectors/core.d.ts.map +1 -0
- package/build/vectors/core.js +825 -0
- package/build/vectors/core.js.map +1 -0
- package/build/vectors/core.spec.d.ts +2 -0
- package/build/vectors/core.spec.d.ts.map +1 -0
- package/build/vectors/core.spec.js +343 -0
- package/build/vectors/core.spec.js.map +1 -0
- package/build/vectors/index.d.ts +6 -0
- package/build/vectors/index.d.ts.map +1 -0
- package/build/vectors/index.js +6 -0
- package/build/vectors/index.js.map +1 -0
- package/build/vectors/interpolation.d.ts +404 -0
- package/build/vectors/interpolation.d.ts.map +1 -0
- package/build/vectors/interpolation.js +585 -0
- package/build/vectors/interpolation.js.map +1 -0
- package/build/vectors/interpolation.spec.d.ts +2 -0
- package/build/vectors/interpolation.spec.d.ts.map +1 -0
- package/build/vectors/interpolation.spec.js +378 -0
- package/build/vectors/interpolation.spec.js.map +1 -0
- package/build/vectors/predefined.d.ts +191 -0
- package/build/vectors/predefined.d.ts.map +1 -0
- package/build/vectors/predefined.js +191 -0
- package/build/vectors/predefined.js.map +1 -0
- package/build/vectors/predefined.spec.d.ts +2 -0
- package/build/vectors/predefined.spec.d.ts.map +1 -0
- package/build/vectors/predefined.spec.js +333 -0
- package/build/vectors/predefined.spec.js.map +1 -0
- package/build/vectors/types.d.ts +62 -0
- package/build/vectors/types.d.ts.map +1 -0
- package/build/vectors/types.js +6 -0
- package/build/vectors/types.js.map +1 -0
- package/package.json +75 -0
|
@@ -0,0 +1,954 @@
|
|
|
1
|
+
import { AssertNumber } from '@pawells/typescript-common';
|
|
2
|
+
import { AssertMatrices, AssertMatrix, AssertMatrix1, AssertMatrix2, AssertMatrix3, AssertMatrix4, AssertMatrixRow, AssertMatrixValue } from './asserts.js';
|
|
3
|
+
import { MatrixCreate, MatrixIsSquare, MatrixSize } from './core.js';
|
|
4
|
+
import { VectorIsValid } from '../vectors/core.js';
|
|
5
|
+
import { AssertVector } from '../vectors/asserts.js';
|
|
6
|
+
/**
|
|
7
|
+
* Performs element-wise addition of two matrices.
|
|
8
|
+
*
|
|
9
|
+
* This function implements matrix addition using the standard mathematical definition:
|
|
10
|
+
* `C[i,j] = A[i,j] + B[i,j]` for all valid indices i,j
|
|
11
|
+
*
|
|
12
|
+
* The operation requires both matrices to have identical dimensions and produces
|
|
13
|
+
* a new matrix without modifying the input matrices. Matrix addition is both
|
|
14
|
+
* commutative (A + B = B + A) and associative ((A + B) + C = A + (B + C)).
|
|
15
|
+
*
|
|
16
|
+
* **Properties:**
|
|
17
|
+
* - Commutative: A + B = B + A
|
|
18
|
+
* - Associative: (A + B) + C = A + (B + C)
|
|
19
|
+
* - Identity element: A + 0 = A (where 0 is the zero matrix)
|
|
20
|
+
* - Inverse element: A + (-A) = 0
|
|
21
|
+
*
|
|
22
|
+
* **Time Complexity:** O(m×n) where m and n are the matrix dimensions
|
|
23
|
+
* **Space Complexity:** O(m×n) for the result matrix
|
|
24
|
+
*
|
|
25
|
+
* @template T - The matrix type extending IMatrix interface
|
|
26
|
+
* @param a - First matrix (addend) - must have same dimensions as b
|
|
27
|
+
* @param b - Second matrix (addend) - must have same dimensions as a
|
|
28
|
+
* @returns {TMatrixResult<T>} A new matrix where each element is the sum of corresponding elements
|
|
29
|
+
* @throws {Error} If matrices have different dimensions or contain invalid values
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* // Adding 2×2 matrices
|
|
34
|
+
* MatrixAdd([[1, 2], [3, 4]], [[5, 6], [7, 8]]) // Returns [[6, 8], [10, 12]]
|
|
35
|
+
*
|
|
36
|
+
* // Adding 1×3 row vectors
|
|
37
|
+
* MatrixAdd([[1, 2, 3]], [[4, 5, 6]]) // Returns [[5, 7, 9]]
|
|
38
|
+
*
|
|
39
|
+
* // Type-safe matrix addition with specific matrix types
|
|
40
|
+
* const matrixA: IMatrix2 = [[1, 2], [3, 4]];
|
|
41
|
+
* const matrixB: IMatrix2 = [[5, 6], [7, 8]];
|
|
42
|
+
* const result: IMatrix2 = MatrixAdd(matrixA, matrixB);
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export function MatrixAdd(a, b) {
|
|
46
|
+
// Validate matrices have compatible dimensions for addition
|
|
47
|
+
AssertMatrices(a, b);
|
|
48
|
+
// Initialize result matrix with same dimensions as inputs
|
|
49
|
+
const [arows, acols] = MatrixSize(a);
|
|
50
|
+
const result = MatrixCreate(arows, acols);
|
|
51
|
+
// Perform element-wise addition: C[i,j] = A[i,j] + B[i,j]
|
|
52
|
+
for (let row = 0; row < arows; row++) {
|
|
53
|
+
// Get row references for both input matrices
|
|
54
|
+
const aRow = a[row];
|
|
55
|
+
AssertMatrixRow(aRow);
|
|
56
|
+
const bRow = b[row];
|
|
57
|
+
AssertMatrixRow(bRow);
|
|
58
|
+
// Get reference to result row for efficient access
|
|
59
|
+
const resultRow = result[row];
|
|
60
|
+
AssertMatrixRow(resultRow);
|
|
61
|
+
// Add corresponding elements column by column
|
|
62
|
+
for (let col = 0; col < acols; col++) {
|
|
63
|
+
// Validate and extract values from both matrices
|
|
64
|
+
const aVal = aRow[col];
|
|
65
|
+
AssertMatrixValue(aVal, { rowIndex: row, columnIndex: col });
|
|
66
|
+
const bVal = bRow[col];
|
|
67
|
+
AssertMatrixValue(bVal, { rowIndex: row, columnIndex: col });
|
|
68
|
+
// Store sum in result matrix
|
|
69
|
+
resultRow[col] = aVal + bVal;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Performs element-wise subtraction of two matrices (a - b).
|
|
76
|
+
*
|
|
77
|
+
* This function implements matrix subtraction using the standard mathematical definition:
|
|
78
|
+
* `C[i,j] = A[i,j] - B[i,j]` for all valid indices i,j
|
|
79
|
+
*
|
|
80
|
+
* The operation requires both matrices to have identical dimensions and produces
|
|
81
|
+
* a new matrix without modifying the input matrices. Note that matrix subtraction
|
|
82
|
+
* is **not commutative**: A - B ≠ B - A in general.
|
|
83
|
+
*
|
|
84
|
+
* **Properties:**
|
|
85
|
+
* - Non-commutative: A - B ≠ B - A (in general)
|
|
86
|
+
* - Non-associative: (A - B) - C ≠ A - (B - C) (in general)
|
|
87
|
+
* - Relationship to addition: A - B = A + (-B)
|
|
88
|
+
* - Self-subtraction: A - A = 0 (zero matrix)
|
|
89
|
+
*
|
|
90
|
+
* **Time Complexity:** O(m×n) where m and n are the matrix dimensions
|
|
91
|
+
* **Space Complexity:** O(m×n) for the result matrix
|
|
92
|
+
*
|
|
93
|
+
* @template T - The matrix type extending IMatrix interface
|
|
94
|
+
* @param a - First matrix (minuend) - the matrix being subtracted from
|
|
95
|
+
* @param b - Second matrix (subtrahend) - the matrix being subtracted
|
|
96
|
+
* @returns {TMatrixResult<T>} A new matrix where each element is the difference of corresponding elements
|
|
97
|
+
* @throws {Error} If matrices have different dimensions or contain invalid values
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* // Subtracting 2×2 matrices
|
|
102
|
+
* MatrixSubtract([[10, 8], [6, 4]], [[3, 2], [1, 1]]) // Returns [[7, 6], [5, 3]]
|
|
103
|
+
*
|
|
104
|
+
* // Order matters: A - B ≠ B - A
|
|
105
|
+
* MatrixSubtract([[1, 2]], [[3, 4]]) // Returns [[-2, -2]]
|
|
106
|
+
* MatrixSubtract([[3, 4]], [[1, 2]]) // Returns [[2, 2]]
|
|
107
|
+
*
|
|
108
|
+
* // Self-subtraction produces zero matrix
|
|
109
|
+
* MatrixSubtract([[5, 6]], [[5, 6]]) // Returns [[0, 0]]
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
export function MatrixSubtract(a, b) {
|
|
113
|
+
// Validate matrices have compatible dimensions for subtraction
|
|
114
|
+
AssertMatrices(a, b);
|
|
115
|
+
// Initialize result matrix with same dimensions as inputs
|
|
116
|
+
const [arows, acols] = MatrixSize(a);
|
|
117
|
+
const result = MatrixCreate(arows, acols);
|
|
118
|
+
// Perform element-wise subtraction: C[i,j] = A[i,j] - B[i,j]
|
|
119
|
+
for (let row = 0; row < arows; row++) {
|
|
120
|
+
// Get row references for both input matrices
|
|
121
|
+
const aRow = a[row];
|
|
122
|
+
AssertMatrixRow(aRow);
|
|
123
|
+
const bRow = b[row];
|
|
124
|
+
AssertMatrixRow(bRow);
|
|
125
|
+
// Get reference to result row for efficient access
|
|
126
|
+
const resultRow = result[row];
|
|
127
|
+
AssertMatrixRow(resultRow);
|
|
128
|
+
// Subtract corresponding elements column by column
|
|
129
|
+
for (let col = 0; col < acols; col++) {
|
|
130
|
+
const aVal = aRow[col];
|
|
131
|
+
AssertMatrixValue(aVal, { rowIndex: row, columnIndex: col });
|
|
132
|
+
const bVal = bRow[col];
|
|
133
|
+
AssertMatrixValue(bVal, { rowIndex: row, columnIndex: col });
|
|
134
|
+
// Store difference in result matrix
|
|
135
|
+
resultRow[col] = aVal - bVal;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return result;
|
|
139
|
+
}
|
|
140
|
+
export function MatrixMultiply(a, b) {
|
|
141
|
+
AssertMatrix(a);
|
|
142
|
+
// Route to appropriate multiplication algorithm based on operand type
|
|
143
|
+
if (typeof b === 'number')
|
|
144
|
+
return matrixMultiplyScalar(a, b);
|
|
145
|
+
if (VectorIsValid(b))
|
|
146
|
+
return matrixMultiplyVector(a, b);
|
|
147
|
+
return matrixMultiplyMatrix(a, b);
|
|
148
|
+
}
|
|
149
|
+
function matrixMultiplyScalar(matrix, scalar) {
|
|
150
|
+
AssertMatrix(matrix);
|
|
151
|
+
AssertNumber(scalar, { finite: true }, { message: 'Scalar multiplier must be a valid number' });
|
|
152
|
+
const [rows, cols] = MatrixSize(matrix);
|
|
153
|
+
const result = MatrixCreate(rows, cols);
|
|
154
|
+
// Apply scalar multiplication to each matrix element
|
|
155
|
+
for (let row = 0; row < rows; row++) {
|
|
156
|
+
const matrixRow = matrix[row];
|
|
157
|
+
AssertMatrixRow(matrixRow);
|
|
158
|
+
const resultRow = result[row];
|
|
159
|
+
AssertMatrixRow(resultRow);
|
|
160
|
+
// Multiply each element in the row by the scalar
|
|
161
|
+
for (let col = 0; col < cols; col++) {
|
|
162
|
+
const val = matrixRow[col];
|
|
163
|
+
AssertMatrixValue(val, { rowIndex: row, columnIndex: col });
|
|
164
|
+
resultRow[col] = val * scalar;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return result;
|
|
168
|
+
}
|
|
169
|
+
function matrixMultiplyVector(matrix, vector) {
|
|
170
|
+
// Validate inputs
|
|
171
|
+
AssertMatrix(matrix);
|
|
172
|
+
AssertVector(vector);
|
|
173
|
+
// Get matrix dimensions
|
|
174
|
+
const [matrixRows, matrixCols] = MatrixSize(matrix);
|
|
175
|
+
// Verify dimensional compatibility: matrix columns must equal vector length
|
|
176
|
+
if (matrixCols !== vector.length) {
|
|
177
|
+
throw new Error(`Matrix-vector multiplication requires matrix columns (${matrixCols}) to equal vector length (${vector.length})`);
|
|
178
|
+
}
|
|
179
|
+
// Initialize result vector with same length as matrix rows
|
|
180
|
+
const result = new Array(matrixRows);
|
|
181
|
+
// Compute each element of the result vector
|
|
182
|
+
for (let row = 0; row < matrixRows; row++) {
|
|
183
|
+
// Get matrix row reference
|
|
184
|
+
const matrixRow = matrix[row];
|
|
185
|
+
AssertMatrixRow(matrixRow);
|
|
186
|
+
// Compute dot product of matrix row with vector
|
|
187
|
+
let dotProduct = 0;
|
|
188
|
+
for (let col = 0; col < matrixCols; col++) {
|
|
189
|
+
// Validate matrix element
|
|
190
|
+
const matrixElement = matrixRow[col];
|
|
191
|
+
AssertMatrixValue(matrixElement, { rowIndex: row, columnIndex: col });
|
|
192
|
+
// Validate vector element
|
|
193
|
+
const vectorElement = vector[col];
|
|
194
|
+
AssertNumber(vectorElement);
|
|
195
|
+
// Add to dot product
|
|
196
|
+
dotProduct += matrixElement * vectorElement;
|
|
197
|
+
}
|
|
198
|
+
// Store result
|
|
199
|
+
result[row] = dotProduct;
|
|
200
|
+
}
|
|
201
|
+
return result;
|
|
202
|
+
}
|
|
203
|
+
function matrixMultiplyMatrix(a, b) {
|
|
204
|
+
// Validate matrices are compatible for multiplication (a.columns === b.rows)
|
|
205
|
+
AssertMatrices(a, b, { transposition: true });
|
|
206
|
+
const [arows, acols] = MatrixSize(a);
|
|
207
|
+
const aSquare = MatrixIsSquare(a);
|
|
208
|
+
const [brows, bcols] = MatrixSize(b);
|
|
209
|
+
const bSquare = MatrixIsSquare(b);
|
|
210
|
+
// Use optimized algorithms for specific square matrix sizes
|
|
211
|
+
if (aSquare && bSquare && arows === brows && acols === bcols) {
|
|
212
|
+
const aSizeSquare = arows;
|
|
213
|
+
if (aSizeSquare === 1) {
|
|
214
|
+
AssertMatrix1(a);
|
|
215
|
+
AssertMatrix1(b);
|
|
216
|
+
return matrixMultiplyMatrix1(a, b);
|
|
217
|
+
}
|
|
218
|
+
else if (aSizeSquare === 2) {
|
|
219
|
+
AssertMatrix2(a);
|
|
220
|
+
AssertMatrix2(b);
|
|
221
|
+
return matrixMultiplyMatrix2(a, b);
|
|
222
|
+
}
|
|
223
|
+
else if (aSizeSquare === 3) {
|
|
224
|
+
AssertMatrix3(a);
|
|
225
|
+
AssertMatrix3(b);
|
|
226
|
+
return matrixMultiplyMatrix3(a, b);
|
|
227
|
+
}
|
|
228
|
+
else if (aSizeSquare === 4) {
|
|
229
|
+
AssertMatrix4(a);
|
|
230
|
+
AssertMatrix4(b);
|
|
231
|
+
return matrixMultiplyMatrix4(a, b);
|
|
232
|
+
}
|
|
233
|
+
else if (aSizeSquare >= 32) {
|
|
234
|
+
// Use Strassen algorithm for large square matrices (≥32×32)
|
|
235
|
+
// Provides better asymptotic performance O(n^2.807) vs O(n³)
|
|
236
|
+
return matrixMultiplyStrassen(a, b);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// Standard O(n³) algorithm for general case: C[i,j] = Σ(A[i,k] × B[k,j])
|
|
240
|
+
const result = MatrixCreate(arows, bcols);
|
|
241
|
+
// Iterate through each position in the result matrix
|
|
242
|
+
for (let row = 0; row < arows; row++) {
|
|
243
|
+
const aRow = a[row];
|
|
244
|
+
AssertMatrixRow(aRow);
|
|
245
|
+
const resultRow = result[row];
|
|
246
|
+
AssertMatrixRow(resultRow);
|
|
247
|
+
for (let col = 0; col < bcols; col++) {
|
|
248
|
+
let sum = 0;
|
|
249
|
+
// Compute dot product of matrix A row with matrix B column
|
|
250
|
+
for (let k = 0; k < acols; k++) {
|
|
251
|
+
const aVal = aRow[k];
|
|
252
|
+
AssertMatrixValue(aVal, { rowIndex: row, columnIndex: k });
|
|
253
|
+
const bRow = b[k];
|
|
254
|
+
AssertMatrixRow(bRow);
|
|
255
|
+
const bVal = bRow[col];
|
|
256
|
+
AssertMatrixValue(bVal, { rowIndex: k, columnIndex: col });
|
|
257
|
+
// Skip multiplication if either operand is zero (performance optimization)
|
|
258
|
+
if (aVal === 0 || bVal === 0)
|
|
259
|
+
continue;
|
|
260
|
+
sum += aVal * bVal;
|
|
261
|
+
}
|
|
262
|
+
resultRow[col] = sum;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return result;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Optimized multiplication for 1×1 matrices.
|
|
269
|
+
*
|
|
270
|
+
* For 1×1 matrices, multiplication reduces to simple scalar multiplication of the
|
|
271
|
+
* two single elements. This optimization completely avoids the overhead of nested
|
|
272
|
+
* loops and provides the fastest possible execution for this trivial case.
|
|
273
|
+
*
|
|
274
|
+
* **Mathematical formula:** `[[a]] × [[b]] = [[a×b]]`
|
|
275
|
+
*
|
|
276
|
+
* This function is primarily used as a base case in recursive algorithms and for
|
|
277
|
+
* completeness in the optimization hierarchy. While seemingly trivial, it provides
|
|
278
|
+
* measurable performance benefits in recursive divide-and-conquer algorithms like
|
|
279
|
+
* Strassen multiplication.
|
|
280
|
+
*
|
|
281
|
+
* **Time Complexity:** O(1) - constant time operation
|
|
282
|
+
* **Space Complexity:** O(1) - single element allocation
|
|
283
|
+
*
|
|
284
|
+
* @param a - First 1×1 matrix [[a]]
|
|
285
|
+
* @param b - Second 1×1 matrix [[b]]
|
|
286
|
+
* @returns {IMatrix1} The product as a 1×1 matrix [[a×b]]
|
|
287
|
+
*
|
|
288
|
+
* @example
|
|
289
|
+
* ```typescript
|
|
290
|
+
* // Simple scalar values in matrix form
|
|
291
|
+
* matrixMultiplyMatrix1([[5]], [[3]]) // Returns [[15]]
|
|
292
|
+
*
|
|
293
|
+
* // Decimal multiplication
|
|
294
|
+
* matrixMultiplyMatrix1([[2.5]], [[4]]) // Returns [[10]]
|
|
295
|
+
*
|
|
296
|
+
* // Negative values
|
|
297
|
+
* matrixMultiplyMatrix1([[-3]], [[7]]) // Returns [[-21]]
|
|
298
|
+
*
|
|
299
|
+
* // Zero multiplication
|
|
300
|
+
* matrixMultiplyMatrix1([[0]], [[999]]) // Returns [[0]]
|
|
301
|
+
* ```
|
|
302
|
+
*/
|
|
303
|
+
function matrixMultiplyMatrix1(a, b) {
|
|
304
|
+
return [[a[0][0] * b[0][0]]];
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Optimized multiplication for 2×2 matrices.
|
|
308
|
+
*
|
|
309
|
+
* This function implements hardcoded 2×2 matrix multiplication using direct
|
|
310
|
+
* element calculations, completely avoiding loop overhead. This optimization
|
|
311
|
+
* is particularly valuable since 2×2 matrices are commonly used in 2D graphics,
|
|
312
|
+
* rotation transformations, and as building blocks in recursive algorithms.
|
|
313
|
+
*
|
|
314
|
+
* Mathematical expansion of C = A × B:
|
|
315
|
+
* C[0,0] = A[0,0]×B[0,0] + A[0,1]×B[1,0]
|
|
316
|
+
* C[0,1] = A[0,0]×B[0,1] + A[0,1]×B[1,1]
|
|
317
|
+
* C[1,0] = A[1,0]×B[0,0] + A[1,1]×B[1,0]
|
|
318
|
+
* C[1,1] = A[1,0]×B[0,1] + A[1,1]×B[1,1]
|
|
319
|
+
*
|
|
320
|
+
* Applications:
|
|
321
|
+
* - 2D rotation and scaling transformations
|
|
322
|
+
* - Linear system solutions (2x2 case)
|
|
323
|
+
* - Recursive matrix algorithms (Strassen base case)
|
|
324
|
+
* - Computer graphics operations
|
|
325
|
+
*
|
|
326
|
+
* Time Complexity: O(1) - exactly 8 multiplications and 4 additions
|
|
327
|
+
* Space Complexity: O(1) - fixed 2×2 result allocation
|
|
328
|
+
*
|
|
329
|
+
* @param a - First 2×2 matrix
|
|
330
|
+
* @param b - Second 2×2 matrix
|
|
331
|
+
* @returns {IMatrix2} The product as a 2×2 matrix
|
|
332
|
+
* @example
|
|
333
|
+
* ```typescript
|
|
334
|
+
* // Standard 2x2 multiplication
|
|
335
|
+
* matrixMultiplyMatrix2([[1, 2], [3, 4]], [[5, 6], [7, 8]])
|
|
336
|
+
* // Returns [[19, 22], [43, 50]]
|
|
337
|
+
* // Calculation:
|
|
338
|
+
* // [1*5+2*7, 1*6+2*8] = [19, 22]
|
|
339
|
+
* // [3*5+4*7, 3*6+4*8] = [43, 50]
|
|
340
|
+
*
|
|
341
|
+
* // 2D rotation by 90 degrees (rotation matrix)
|
|
342
|
+
* matrixMultiplyMatrix2([[0, -1], [1, 0]], [[1, 0], [0, 1]])
|
|
343
|
+
* // Returns [[0, -1], [1, 0]]
|
|
344
|
+
*
|
|
345
|
+
* // Scaling transformation
|
|
346
|
+
* matrixMultiplyMatrix2([[2, 0], [0, 3]], [[1, 2], [3, 4]])
|
|
347
|
+
* // Returns [[2, 4], [9, 12]]
|
|
348
|
+
* ```
|
|
349
|
+
*/
|
|
350
|
+
function matrixMultiplyMatrix2(a, b) {
|
|
351
|
+
return [
|
|
352
|
+
[
|
|
353
|
+
(a[0][0] * b[0][0]) + (a[0][1] * b[1][0]), // C[0,0]
|
|
354
|
+
(a[0][0] * b[0][1]) + (a[0][1] * b[1][1]), // C[0,1]
|
|
355
|
+
],
|
|
356
|
+
[
|
|
357
|
+
(a[1][0] * b[0][0]) + (a[1][1] * b[1][0]), // C[1,0]
|
|
358
|
+
(a[1][0] * b[0][1]) + (a[1][1] * b[1][1]), // C[1,1]
|
|
359
|
+
],
|
|
360
|
+
];
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Optimized multiplication for 3×3 matrices.
|
|
364
|
+
*
|
|
365
|
+
* This function implements hardcoded 3×3 matrix multiplication using direct
|
|
366
|
+
* element calculations. 3×3 matrices are extensively used in 3D computer graphics
|
|
367
|
+
* for representing rotations, scaling, shearing, and other linear transformations
|
|
368
|
+
* in homogeneous coordinate systems.
|
|
369
|
+
*
|
|
370
|
+
* Mathematical expansion: Each element C[i,j] = Σ(A[i,k] × B[k,j]) for k=0,1,2
|
|
371
|
+
*
|
|
372
|
+
* Applications:
|
|
373
|
+
* - 3D rotation matrices (Euler angles, axis-angle representations)
|
|
374
|
+
* - 3D scaling and shearing transformations
|
|
375
|
+
* - Camera transformations in computer graphics
|
|
376
|
+
* - Crystallography and materials science calculations
|
|
377
|
+
* - Robotic arm kinematics (rotation components)
|
|
378
|
+
*
|
|
379
|
+
* Performance Benefits:
|
|
380
|
+
* - Eliminates loop overhead with direct calculations
|
|
381
|
+
* - 27 hardcoded multiplications and 18 additions
|
|
382
|
+
* - Optimal cache usage with predictable memory access
|
|
383
|
+
* - Compiler can optimize register allocation
|
|
384
|
+
*
|
|
385
|
+
* Time Complexity: O(1) - exactly 27 multiplications and 18 additions
|
|
386
|
+
* Space Complexity: O(1) - fixed 3×3 result allocation
|
|
387
|
+
*
|
|
388
|
+
* @param a - First 3×3 matrix
|
|
389
|
+
* @param b - Second 3×3 matrix
|
|
390
|
+
* @returns {IMatrix3} The product as a 3×3 matrix
|
|
391
|
+
* @example
|
|
392
|
+
* ```typescript
|
|
393
|
+
* // 3D rotation matrix multiplication (combining rotations)
|
|
394
|
+
* const rotX = [[1, 0, 0], [0, 0.707, -0.707], [0, 0.707, 0.707]]; // X rotation
|
|
395
|
+
* const rotY = [[0.707, 0, 0.707], [0, 1, 0], [-0.707, 0, 0.707]]; // Y rotation
|
|
396
|
+
* matrixMultiplyMatrix3(rotX, rotY) // Combined X-Y rotation
|
|
397
|
+
*
|
|
398
|
+
* // Identity matrix test
|
|
399
|
+
* matrixMultiplyMatrix3([[1, 2, 3], [4, 5, 6], [7, 8, 9]], [[1, 0, 0], [0, 1, 0], [0, 0, 1]])
|
|
400
|
+
* // Returns [[1, 2, 3], [4, 5, 6], [7, 8, 9]] (unchanged)
|
|
401
|
+
*
|
|
402
|
+
* // Scaling transformation
|
|
403
|
+
* matrixMultiplyMatrix3([[2, 0, 0], [0, 3, 0], [0, 0, 4]], [[1, 1, 1], [1, 1, 1], [1, 1, 1]])
|
|
404
|
+
* // Returns [[2, 2, 2], [3, 3, 3], [4, 4, 4]]
|
|
405
|
+
* ```
|
|
406
|
+
*/
|
|
407
|
+
function matrixMultiplyMatrix3(a, b) {
|
|
408
|
+
return [
|
|
409
|
+
[
|
|
410
|
+
// Row 0: [a00*b00 + a01*b10 + a02*b20, a00*b01 + a01*b11 + a02*b21, a00*b02 + a01*b12 + a02*b22]
|
|
411
|
+
(a[0][0] * b[0][0]) + (a[0][1] * b[1][0]) + (a[0][2] * b[2][0]),
|
|
412
|
+
(a[0][0] * b[0][1]) + (a[0][1] * b[1][1]) + (a[0][2] * b[2][1]),
|
|
413
|
+
(a[0][0] * b[0][2]) + (a[0][1] * b[1][2]) + (a[0][2] * b[2][2]),
|
|
414
|
+
],
|
|
415
|
+
[
|
|
416
|
+
// Row 1: [a10*b00 + a11*b10 + a12*b20, a10*b01 + a11*b11 + a12*b21, a10*b02 + a11*b12 + a12*b22]
|
|
417
|
+
(a[1][0] * b[0][0]) + (a[1][1] * b[1][0]) + (a[1][2] * b[2][0]),
|
|
418
|
+
(a[1][0] * b[0][1]) + (a[1][1] * b[1][1]) + (a[1][2] * b[2][1]),
|
|
419
|
+
(a[1][0] * b[0][2]) + (a[1][1] * b[1][2]) + (a[1][2] * b[2][2]),
|
|
420
|
+
],
|
|
421
|
+
[
|
|
422
|
+
// Row 2: [a20*b00 + a21*b10 + a22*b20, a20*b01 + a21*b11 + a22*b21, a20*b02 + a21*b12 + a22*b22]
|
|
423
|
+
(a[2][0] * b[0][0]) + (a[2][1] * b[1][0]) + (a[2][2] * b[2][0]),
|
|
424
|
+
(a[2][0] * b[0][1]) + (a[2][1] * b[1][1]) + (a[2][2] * b[2][1]),
|
|
425
|
+
(a[2][0] * b[0][2]) + (a[2][1] * b[1][2]) + (a[2][2] * b[2][2]),
|
|
426
|
+
],
|
|
427
|
+
];
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Optimized multiplication for 4×4 matrices.
|
|
431
|
+
*
|
|
432
|
+
* This function implements hardcoded 4×4 matrix multiplication using direct
|
|
433
|
+
* element calculations. 4×4 matrices are the cornerstone of 3D computer graphics,
|
|
434
|
+
* enabling homogeneous coordinate transformations that can represent translation,
|
|
435
|
+
* rotation, scaling, and perspective projection in a unified mathematical framework.
|
|
436
|
+
*
|
|
437
|
+
* Mathematical expansion: Each element C[i,j] = Σ(A[i,k] × B[k,j]) for k=0,1,2,3
|
|
438
|
+
*
|
|
439
|
+
* Applications:
|
|
440
|
+
* - 3D graphics transformation pipelines (model-view-projection matrices)
|
|
441
|
+
* - Homogeneous coordinate transformations (translation + rotation + scaling)
|
|
442
|
+
* - Perspective and orthographic projection matrices
|
|
443
|
+
* - Camera transformations and view matrices
|
|
444
|
+
* - Skeletal animation bone transformations
|
|
445
|
+
* - Virtual reality and augmented reality systems
|
|
446
|
+
*
|
|
447
|
+
* Homogeneous Coordinates Structure:
|
|
448
|
+
* [Rotation/Scale | Translation]
|
|
449
|
+
* [ 0 | 1 ]
|
|
450
|
+
*
|
|
451
|
+
* Performance Benefits:
|
|
452
|
+
* - Eliminates loop overhead with 64 direct calculations
|
|
453
|
+
* - Optimal for graphics transformation chains
|
|
454
|
+
* - Predictable memory access patterns
|
|
455
|
+
* - Compiler-optimizable register allocation
|
|
456
|
+
*
|
|
457
|
+
* Time Complexity: O(1) - exactly 64 multiplications and 48 additions
|
|
458
|
+
* Space Complexity: O(1) - fixed 4×4 result allocation
|
|
459
|
+
*
|
|
460
|
+
* @param a - First 4×4 matrix (typically a transformation matrix)
|
|
461
|
+
* @param b - Second 4×4 matrix (typically another transformation matrix)
|
|
462
|
+
* @returns {IMatrix4} The product as a 4×4 matrix (combined transformation)
|
|
463
|
+
* @example
|
|
464
|
+
* ```typescript
|
|
465
|
+
* // Combine translation and rotation matrices (common in 3D graphics)
|
|
466
|
+
* const translation = [[1,0,0,5], [0,1,0,3], [0,0,1,0], [0,0,0,1]]; // Translate by (5,3,0)
|
|
467
|
+
* const rotation = [[0,-1,0,0], [1,0,0,0], [0,0,1,0], [0,0,0,1]]; // 90° Z rotation
|
|
468
|
+
* matrixMultiplyMatrix4(translation, rotation); // Combined transform
|
|
469
|
+
*
|
|
470
|
+
* // Identity matrix test (should return unchanged matrix)
|
|
471
|
+
* const testMatrix = [[1,2,3,4], [5,6,7,8], [9,10,11,12], [13,14,15,16]];
|
|
472
|
+
* const identity = [[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]];
|
|
473
|
+
* matrixMultiplyMatrix4(testMatrix, identity) // Returns testMatrix unchanged
|
|
474
|
+
*
|
|
475
|
+
* // Perspective projection matrix combination
|
|
476
|
+
* const projection = [[2,0,0,0], [0,2,0,0], [0,0,-1,-1], [0,0,-2,0]];
|
|
477
|
+
* const view = [[1,0,0,0], [0,1,0,0], [0,0,1,-10], [0,0,0,1]];
|
|
478
|
+
* matrixMultiplyMatrix4(projection, view); // Combined projection-view matrix
|
|
479
|
+
* ```
|
|
480
|
+
*/
|
|
481
|
+
function matrixMultiplyMatrix4(a, b) {
|
|
482
|
+
return [
|
|
483
|
+
[
|
|
484
|
+
// Row 0: Transform of basis vector [1,0,0,0]
|
|
485
|
+
(a[0][0] * b[0][0]) + (a[0][1] * b[1][0]) + (a[0][2] * b[2][0]) + (a[0][3] * b[3][0]),
|
|
486
|
+
(a[0][0] * b[0][1]) + (a[0][1] * b[1][1]) + (a[0][2] * b[2][1]) + (a[0][3] * b[3][1]),
|
|
487
|
+
(a[0][0] * b[0][2]) + (a[0][1] * b[1][2]) + (a[0][2] * b[2][2]) + (a[0][3] * b[3][2]),
|
|
488
|
+
(a[0][0] * b[0][3]) + (a[0][1] * b[1][3]) + (a[0][2] * b[2][3]) + (a[0][3] * b[3][3]),
|
|
489
|
+
],
|
|
490
|
+
[
|
|
491
|
+
// Row 1: Transform of basis vector [0,1,0,0]
|
|
492
|
+
(a[1][0] * b[0][0]) + (a[1][1] * b[1][0]) + (a[1][2] * b[2][0]) + (a[1][3] * b[3][0]),
|
|
493
|
+
(a[1][0] * b[0][1]) + (a[1][1] * b[1][1]) + (a[1][2] * b[2][1]) + (a[1][3] * b[3][1]),
|
|
494
|
+
(a[1][0] * b[0][2]) + (a[1][1] * b[1][2]) + (a[1][2] * b[2][2]) + (a[1][3] * b[3][2]),
|
|
495
|
+
(a[1][0] * b[0][3]) + (a[1][1] * b[1][3]) + (a[1][2] * b[2][3]) + (a[1][3] * b[3][3]),
|
|
496
|
+
],
|
|
497
|
+
[
|
|
498
|
+
// Row 2: Transform of basis vector [0,0,1,0]
|
|
499
|
+
(a[2][0] * b[0][0]) + (a[2][1] * b[1][0]) + (a[2][2] * b[2][0]) + (a[2][3] * b[3][0]),
|
|
500
|
+
(a[2][0] * b[0][1]) + (a[2][1] * b[1][1]) + (a[2][2] * b[2][1]) + (a[2][3] * b[3][1]),
|
|
501
|
+
(a[2][0] * b[0][2]) + (a[2][1] * b[1][2]) + (a[2][2] * b[2][2]) + (a[2][3] * b[3][2]),
|
|
502
|
+
(a[2][0] * b[0][3]) + (a[2][1] * b[1][3]) + (a[2][2] * b[2][3]) + (a[2][3] * b[3][3]),
|
|
503
|
+
],
|
|
504
|
+
[
|
|
505
|
+
// Row 3: Transform of basis vector [0,0,0,1] (usually homogeneous coordinates)
|
|
506
|
+
(a[3][0] * b[0][0]) + (a[3][1] * b[1][0]) + (a[3][2] * b[2][0]) + (a[3][3] * b[3][0]),
|
|
507
|
+
(a[3][0] * b[0][1]) + (a[3][1] * b[1][1]) + (a[3][2] * b[2][1]) + (a[3][3] * b[3][1]),
|
|
508
|
+
(a[3][0] * b[0][2]) + (a[3][1] * b[1][2]) + (a[3][2] * b[2][2]) + (a[3][3] * b[3][2]),
|
|
509
|
+
(a[3][0] * b[0][3]) + (a[3][1] * b[1][3]) + (a[3][2] * b[2][3]) + (a[3][3] * b[3][3]),
|
|
510
|
+
],
|
|
511
|
+
];
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Performs matrix multiplication using Strassen's algorithm for improved performance on large matrices.
|
|
515
|
+
*
|
|
516
|
+
* Strassen's algorithm is a divide-and-conquer approach that reduces the computational
|
|
517
|
+
* complexity of matrix multiplication from O(n³) to approximately O(n^2.807) by using
|
|
518
|
+
* clever algebraic manipulations. Instead of computing 8 submatrix products as in the
|
|
519
|
+
* naive block approach, Strassen's method computes only 7 products through strategic
|
|
520
|
+
* addition and subtraction operations.
|
|
521
|
+
*
|
|
522
|
+
* **Algorithm Overview:**
|
|
523
|
+
* 1. Recursively partition each n×n matrix into four (n/2)×(n/2) submatrices
|
|
524
|
+
* 2. Compute 7 specific intermediate products (M1-M7) using Strassen's formulas
|
|
525
|
+
* 3. Combine these products using addition/subtraction to form result quadrants
|
|
526
|
+
* 4. Recursively apply until reaching base case (n ≤ 32) where standard multiplication is used
|
|
527
|
+
*
|
|
528
|
+
* **Strassen's Seven Products:**
|
|
529
|
+
* - M1 = (A11 + A22)(B11 + B22)
|
|
530
|
+
* - M2 = (A21 + A22)B11
|
|
531
|
+
* - M3 = A11(B12 - B22)
|
|
532
|
+
* - M4 = A22(B21 - B11)
|
|
533
|
+
* - M5 = (A11 + A12)B22
|
|
534
|
+
* - M6 = (A21 - A11)(B11 + B12)
|
|
535
|
+
* - M7 = (A12 - A22)(B21 + B22)
|
|
536
|
+
*
|
|
537
|
+
* **Result Reconstruction:**
|
|
538
|
+
* - C11 = M1 + M4 - M5 + M7
|
|
539
|
+
* - C12 = M3 + M5
|
|
540
|
+
* - C21 = M2 + M4
|
|
541
|
+
* - C22 = M1 + M3 - M2 + M6
|
|
542
|
+
*
|
|
543
|
+
* **Performance Characteristics:**
|
|
544
|
+
* - Asymptotic complexity: O(n^2.807) vs O(n³) for standard algorithm
|
|
545
|
+
* - Crossover point: typically beneficial for matrices ≥ 32×32
|
|
546
|
+
* - Memory overhead: recursive calls and temporary matrices
|
|
547
|
+
* - Numerical stability: slightly less stable due to more floating-point operations
|
|
548
|
+
*
|
|
549
|
+
* **Automatic Optimizations:**
|
|
550
|
+
* - Base case optimization: switches to standard algorithm for small matrices
|
|
551
|
+
* - Padding handling: automatically pads odd-sized matrices with zeros
|
|
552
|
+
* - Memory management: efficient temporary matrix allocation and cleanup
|
|
553
|
+
*
|
|
554
|
+
* **Time Complexity:** O(n^2.807) average case, O(n³) worst case (small matrices)
|
|
555
|
+
* **Space Complexity:** O(n²) for recursive call stack and temporary matrices
|
|
556
|
+
*
|
|
557
|
+
* @param a - First square matrix (must be same size as b)
|
|
558
|
+
* @param b - Second square matrix (must be same size as a)
|
|
559
|
+
* @returns {IMatrix} The product matrix with same dimensions as inputs
|
|
560
|
+
* @throws {Error} If matrices are not square or have incompatible dimensions
|
|
561
|
+
*
|
|
562
|
+
* @example
|
|
563
|
+
* ```typescript
|
|
564
|
+
* // Large matrix multiplication (automatically used for 32×32 and larger)
|
|
565
|
+
* const size = 256;
|
|
566
|
+
* const largeA = MatrixCreate(size, size); // Create 256×256 matrix
|
|
567
|
+
* const largeB = MatrixCreate(size, size); // Create 256×256 matrix
|
|
568
|
+
* // ... fill matrices with data ...
|
|
569
|
+
* const result = matrixMultiplyStrassen(largeA, largeB); // Uses Strassen algorithm
|
|
570
|
+
*
|
|
571
|
+
* // Performance comparison for large matrices:
|
|
572
|
+
* // Standard O(n³): ~16.8M operations for 256×256
|
|
573
|
+
* // Strassen O(n^2.807): ~11.2M operations for 256×256 (33% reduction)
|
|
574
|
+
*
|
|
575
|
+
* // Odd-sized matrices are automatically handled with padding
|
|
576
|
+
* const oddMatrix = MatrixCreate(127, 127); // Will be padded to 128×128 internally
|
|
577
|
+
* const result2 = matrixMultiplyStrassen(oddMatrix, oddMatrix);
|
|
578
|
+
*
|
|
579
|
+
* // Base case automatically falls back to standard algorithm
|
|
580
|
+
* const small = MatrixCreate(16, 16); // Uses standard algorithm (< 32×32)
|
|
581
|
+
* const result3 = matrixMultiplyStrassen(small, small);
|
|
582
|
+
* ```
|
|
583
|
+
*/
|
|
584
|
+
function matrixMultiplyStrassen(a, b) {
|
|
585
|
+
AssertMatrix(a, { square: true });
|
|
586
|
+
AssertMatrix(b, { square: true });
|
|
587
|
+
const [arows, _acols] = MatrixSize(a);
|
|
588
|
+
const [brows, _bcols] = MatrixSize(b);
|
|
589
|
+
if (arows !== brows) {
|
|
590
|
+
throw new Error(`Matrix dimensions incompatible for multiplication: ${arows}×${arows} and ${brows}×${brows}`);
|
|
591
|
+
}
|
|
592
|
+
const n = arows;
|
|
593
|
+
// Base case: use standard multiplication for small matrices to avoid overhead
|
|
594
|
+
if (n < 32) {
|
|
595
|
+
return matrixMultiplyMatrix(a, b);
|
|
596
|
+
}
|
|
597
|
+
// Ensure matrix size is even for clean partitioning into quadrants
|
|
598
|
+
if (n % 2 !== 0) {
|
|
599
|
+
// Pad matrices to next even size with zeros
|
|
600
|
+
const paddedSize = n + 1;
|
|
601
|
+
const aPadded = MatrixPad(a, paddedSize, paddedSize);
|
|
602
|
+
const bPadded = MatrixPad(b, paddedSize, paddedSize);
|
|
603
|
+
const resultPadded = matrixMultiplyStrassen(aPadded, bPadded);
|
|
604
|
+
// Extract original size result (remove padding)
|
|
605
|
+
return MatrixSubmatrix(resultPadded, 0, 0, n, n);
|
|
606
|
+
}
|
|
607
|
+
const halfSize = n / 2;
|
|
608
|
+
// Partition matrices into 2×2 blocks: A=[A11 A12; A21 A22], B=[B11 B12; B21 B22]
|
|
609
|
+
const a11 = MatrixSubmatrix(a, 0, 0, halfSize, halfSize);
|
|
610
|
+
const a12 = MatrixSubmatrix(a, halfSize, 0, halfSize, halfSize);
|
|
611
|
+
const a21 = MatrixSubmatrix(a, 0, halfSize, halfSize, halfSize);
|
|
612
|
+
const a22 = MatrixSubmatrix(a, halfSize, halfSize, halfSize, halfSize);
|
|
613
|
+
const b11 = MatrixSubmatrix(b, 0, 0, halfSize, halfSize);
|
|
614
|
+
const b12 = MatrixSubmatrix(b, halfSize, 0, halfSize, halfSize);
|
|
615
|
+
const b21 = MatrixSubmatrix(b, 0, halfSize, halfSize, halfSize);
|
|
616
|
+
const b22 = MatrixSubmatrix(b, halfSize, halfSize, halfSize, halfSize);
|
|
617
|
+
// Calculate the 7 Strassen products (reduces 8 multiplications to 7)
|
|
618
|
+
// These specific combinations enable efficient result reconstruction
|
|
619
|
+
const m1 = matrixMultiplyStrassen(MatrixAdd(a11, a22), MatrixAdd(b11, b22)); // (A11+A22)(B11+B22)
|
|
620
|
+
const m2 = matrixMultiplyStrassen(MatrixAdd(a21, a22), b11); // (A21+A22)B11
|
|
621
|
+
const m3 = matrixMultiplyStrassen(a11, MatrixSubtract(b12, b22)); // A11(B12-B22)
|
|
622
|
+
const m4 = matrixMultiplyStrassen(a22, MatrixSubtract(b21, b11)); // A22(B21-B11)
|
|
623
|
+
const m5 = matrixMultiplyStrassen(MatrixAdd(a11, a12), b22); // (A11+A12)B22
|
|
624
|
+
const m6 = matrixMultiplyStrassen(MatrixSubtract(a21, a11), MatrixAdd(b11, b12)); // (A21-A11)(B11+B12)
|
|
625
|
+
const m7 = matrixMultiplyStrassen(MatrixSubtract(a12, a22), MatrixAdd(b21, b22)); // (A12-A22)(B21+B22)
|
|
626
|
+
// Reconstruct result quadrants using Strassen's combination formulas
|
|
627
|
+
const c11 = MatrixAdd(MatrixSubtract(MatrixAdd(m1, m4), m5), m7); // M1 + M4 - M5 + M7
|
|
628
|
+
const c12 = MatrixAdd(m3, m5); // M3 + M5
|
|
629
|
+
const c21 = MatrixAdd(m2, m4); // M2 + M4
|
|
630
|
+
const c22 = MatrixAdd(MatrixSubtract(MatrixAdd(m1, m3), m2), m6); // M1 + M3 - M2 + M6
|
|
631
|
+
// Combine quadrants into final result matrix
|
|
632
|
+
return MatrixCombine(c11, c12, c21, c22);
|
|
633
|
+
}
|
|
634
|
+
/**
|
|
635
|
+
* Extracts a rectangular submatrix from a larger matrix.
|
|
636
|
+
*
|
|
637
|
+
* This function creates a new matrix containing a specified rectangular region from
|
|
638
|
+
* the source matrix. It performs a deep copy of the selected elements, ensuring the
|
|
639
|
+
* original matrix remains unmodified. This operation is fundamental for matrix
|
|
640
|
+
* partitioning algorithms, block operations, and data analysis workflows.
|
|
641
|
+
*
|
|
642
|
+
* Coordinate System:
|
|
643
|
+
* - startRow, startCol: Top-left corner of the extraction region (0-based, inclusive)
|
|
644
|
+
* - width, height: Dimensions of the region to extract
|
|
645
|
+
* - Extraction bounds: [startRow, startRow+height) × [startCol, startCol+width)
|
|
646
|
+
*
|
|
647
|
+
* NOTE: parameter order is (startCol, startRow) — reversed from typical convention
|
|
648
|
+
*
|
|
649
|
+
* Applications:
|
|
650
|
+
* - Block matrix algorithms (Strassen, block LU decomposition)
|
|
651
|
+
* - Image processing (extracting regions of interest)
|
|
652
|
+
* - Data analysis (extracting subsets of datasets)
|
|
653
|
+
* - Sparse matrix operations (extracting dense blocks)
|
|
654
|
+
* - Machine learning (feature selection, data windowing)
|
|
655
|
+
*
|
|
656
|
+
* Bounds Checking:
|
|
657
|
+
* - Validates that extraction region fits within source matrix
|
|
658
|
+
* - Ensures all parameters are non-negative integers
|
|
659
|
+
* - Checks for valid matrix structure and element values
|
|
660
|
+
*
|
|
661
|
+
* Memory Efficiency:
|
|
662
|
+
* - Creates new matrix with minimal required size
|
|
663
|
+
* - Performs element-by-element copying with validation
|
|
664
|
+
* - No unnecessary memory allocation or copying
|
|
665
|
+
*
|
|
666
|
+
* Time Complexity: O(width × height) - linear in extracted region size
|
|
667
|
+
* Space Complexity: O(width × height) - size of extracted submatrix
|
|
668
|
+
*
|
|
669
|
+
* @param matrix - Source matrix to extract from
|
|
670
|
+
* @param startCol - Starting column index (0-based, inclusive) — note reversed order
|
|
671
|
+
* @param startRow - Starting row index (0-based, inclusive) — note reversed order
|
|
672
|
+
* @param width - Number of columns to extract (must be positive)
|
|
673
|
+
* @param height - Number of rows to extract (must be positive)
|
|
674
|
+
* @returns {IMatrix} The extracted submatrix with dimensions height×width
|
|
675
|
+
* @throws {Error} If extraction bounds exceed matrix dimensions or contain invalid values
|
|
676
|
+
* @example
|
|
677
|
+
* ```typescript
|
|
678
|
+
* const matrix = [
|
|
679
|
+
* [1, 2, 3, 4],
|
|
680
|
+
* [5, 6, 7, 8],
|
|
681
|
+
* [9, 10, 11, 12]
|
|
682
|
+
* ]; // 3×4 matrix
|
|
683
|
+
*
|
|
684
|
+
* // Extract 2×2 submatrix from top-left corner
|
|
685
|
+
* MatrixSubmatrix(matrix, 0, 0, 2, 2) // Returns [[1, 2], [5, 6]]
|
|
686
|
+
*
|
|
687
|
+
* // Extract 2×2 submatrix from center-right region
|
|
688
|
+
* MatrixSubmatrix(matrix, 2, 1, 2, 2) // Returns [[7, 8], [11, 12]]
|
|
689
|
+
*
|
|
690
|
+
* // Extract single column (column vector)
|
|
691
|
+
* MatrixSubmatrix(matrix, 1, 0, 1, 3) // Returns [[2], [6], [10]]
|
|
692
|
+
*
|
|
693
|
+
* // Extract single row (row vector)
|
|
694
|
+
* MatrixSubmatrix(matrix, 0, 1, 4, 1) // Returns [[5, 6, 7, 8]]
|
|
695
|
+
*
|
|
696
|
+
* // Block matrix partitioning for algorithms
|
|
697
|
+
* const large = MatrixCreate(8, 8); // 8×8 matrix
|
|
698
|
+
* const topLeft = MatrixSubmatrix(large, 0, 0, 4, 4); // Top-left 4×4 block
|
|
699
|
+
* const topRight = MatrixSubmatrix(large, 4, 0, 4, 4); // Top-right 4×4 block
|
|
700
|
+
* const bottomLeft = MatrixSubmatrix(large, 0, 4, 4, 4); // Bottom-left 4×4 block
|
|
701
|
+
* const bottomRight = MatrixSubmatrix(large, 4, 4, 4, 4); // Bottom-right 4×4 block
|
|
702
|
+
* ```
|
|
703
|
+
*/
|
|
704
|
+
export function MatrixSubmatrix(matrix, startCol, startRow, width, height) {
|
|
705
|
+
AssertMatrix(matrix);
|
|
706
|
+
const result = MatrixCreate(height, width);
|
|
707
|
+
// Copy elements from specified source region to result matrix
|
|
708
|
+
for (let row = 0; row < height; row++) {
|
|
709
|
+
const sourceRow = matrix[startRow + row];
|
|
710
|
+
AssertMatrixRow(sourceRow);
|
|
711
|
+
const resultRow = result[row];
|
|
712
|
+
AssertMatrixRow(resultRow);
|
|
713
|
+
for (let col = 0; col < width; col++) {
|
|
714
|
+
const val = sourceRow[startCol + col];
|
|
715
|
+
AssertMatrixValue(val, { rowIndex: startRow + row, columnIndex: startCol + col });
|
|
716
|
+
resultRow[col] = val;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
return result;
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* Pads a matrix with zeros to reach the specified dimensions.
|
|
723
|
+
*
|
|
724
|
+
* This function extends a matrix by adding rows and/or columns filled with zeros,
|
|
725
|
+
* preserving the original matrix content in the top-left corner. This operation
|
|
726
|
+
* is essential for algorithms that require matrices of specific sizes or when
|
|
727
|
+
* preparing matrices for operations that need dimension alignment.
|
|
728
|
+
*
|
|
729
|
+
* Padding Strategy:
|
|
730
|
+
* - Original content remains in top-left corner at [0,0]
|
|
731
|
+
* - Additional rows/columns are filled with zeros
|
|
732
|
+
* - New dimensions must be greater than or equal to current dimensions
|
|
733
|
+
* - Supports both symmetric and asymmetric padding
|
|
734
|
+
*
|
|
735
|
+
* Common Use Cases:
|
|
736
|
+
* - Algorithm requirements (power-of-2 sizes for FFT-based algorithms)
|
|
737
|
+
* - Block matrix operations (ensuring uniform block sizes)
|
|
738
|
+
* - Strassen algorithm (handling odd-sized matrices)
|
|
739
|
+
* - Image processing (border padding for convolution operations)
|
|
740
|
+
* - Signal processing (zero-padding for frequency domain analysis)
|
|
741
|
+
* - Machine learning (batch size alignment, tensor operations)
|
|
742
|
+
*
|
|
743
|
+
* Padding Preservation Property:
|
|
744
|
+
* If A is the original matrix and A' is the padded matrix, then:
|
|
745
|
+
* A'[i,j] = A[i,j] for all valid i,j in A
|
|
746
|
+
* A'[i,j] = 0 for all other positions
|
|
747
|
+
*
|
|
748
|
+
* Memory Efficiency:
|
|
749
|
+
* - Creates new matrix only of the target size
|
|
750
|
+
* - Copies only existing elements (no redundant operations)
|
|
751
|
+
* - Zero-fills remaining positions efficiently
|
|
752
|
+
*
|
|
753
|
+
* Time Complexity: O(newRows × newCols) - must initialize entire new matrix
|
|
754
|
+
* Space Complexity: O(newRows × newCols) - size of padded result
|
|
755
|
+
*
|
|
756
|
+
* @param matrix - Source matrix to pad
|
|
757
|
+
* @param newRows - Target number of rows (must be ≥ current rows)
|
|
758
|
+
* @param newCols - Target number of columns (must be ≥ current columns)
|
|
759
|
+
* @returns {IMatrix} The padded matrix with dimensions newRows×newCols
|
|
760
|
+
* @throws {Error} If new dimensions are smaller than current dimensions
|
|
761
|
+
* @example
|
|
762
|
+
* ```typescript
|
|
763
|
+
* const matrix = [[1, 2], [3, 4]]; // 2×2 matrix
|
|
764
|
+
*
|
|
765
|
+
* // Pad to 4×4 matrix (symmetric padding)
|
|
766
|
+
* MatrixPad(matrix, 4, 4)
|
|
767
|
+
* // Returns:
|
|
768
|
+
* // [[1, 2, 0, 0],
|
|
769
|
+
* // [3, 4, 0, 0],
|
|
770
|
+
* // [0, 0, 0, 0],
|
|
771
|
+
* // [0, 0, 0, 0]]
|
|
772
|
+
*
|
|
773
|
+
* // Pad to 3×4 matrix (asymmetric padding)
|
|
774
|
+
* MatrixPad(matrix, 3, 4)
|
|
775
|
+
* // Returns:
|
|
776
|
+
* // [[1, 2, 0, 0],
|
|
777
|
+
* // [3, 4, 0, 0],
|
|
778
|
+
* // [0, 0, 0, 0]]
|
|
779
|
+
*
|
|
780
|
+
* // Prepare for power-of-2 algorithm (e.g., FFT-based convolution)
|
|
781
|
+
* const data = [[1, 2, 3], [4, 5, 6]]; // 2×3 matrix
|
|
782
|
+
* const powerOf2 = MatrixPad(data, 4, 4); // Pad to 4×4 for FFT
|
|
783
|
+
*
|
|
784
|
+
* // Batch size alignment in machine learning
|
|
785
|
+
* const features = MatrixCreate(7, 10); // 7 samples, 10 features
|
|
786
|
+
* const aligned = MatrixPad(features, 8, 10); // Align to batch size 8
|
|
787
|
+
*
|
|
788
|
+
* // Image border padding for convolution
|
|
789
|
+
* const image = MatrixCreate(28, 28); // 28×28 image
|
|
790
|
+
* const padded = MatrixPad(image, 32, 32); // Add border for valid convolution
|
|
791
|
+
* ```
|
|
792
|
+
*/
|
|
793
|
+
export function MatrixPad(matrix, newRows, newCols) {
|
|
794
|
+
AssertMatrix(matrix);
|
|
795
|
+
const [currentRows, currentCols] = MatrixSize(matrix);
|
|
796
|
+
const result = MatrixCreate(newRows, newCols);
|
|
797
|
+
// Copy existing values to top-left corner, zero-fill remaining positions
|
|
798
|
+
for (let row = 0; row < Math.min(currentRows, newRows); row++) {
|
|
799
|
+
const sourceRow = matrix[row];
|
|
800
|
+
AssertMatrixRow(sourceRow);
|
|
801
|
+
const resultRow = result[row];
|
|
802
|
+
AssertMatrixRow(resultRow);
|
|
803
|
+
for (let col = 0; col < Math.min(currentCols, newCols); col++) {
|
|
804
|
+
const val = sourceRow[col];
|
|
805
|
+
AssertMatrixValue(val, { rowIndex: row, columnIndex: col });
|
|
806
|
+
resultRow[col] = val;
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
return result;
|
|
810
|
+
}
|
|
811
|
+
/**
|
|
812
|
+
* Combines four square submatrices into a single matrix (2×2 block structure).
|
|
813
|
+
*
|
|
814
|
+
* This function reconstructs a larger matrix from four quadrant submatrices using
|
|
815
|
+
* a 2×2 block structure. It serves as the inverse operation of matrix partitioning
|
|
816
|
+
* and is essential for divide-and-conquer algorithms like Strassen multiplication,
|
|
817
|
+
* block matrix operations, and hierarchical matrix constructions.
|
|
818
|
+
*
|
|
819
|
+
* **Block Matrix Structure:**
|
|
820
|
+
* ```
|
|
821
|
+
* Result = [C11 C12] where each Cij is an n×n submatrix
|
|
822
|
+
* [C21 C22]
|
|
823
|
+
* ```
|
|
824
|
+
*
|
|
825
|
+
* The resulting matrix has dimensions 2n×2n when each input quadrant is n×n.
|
|
826
|
+
*
|
|
827
|
+
* **Quadrant Placement:**
|
|
828
|
+
* - c11 (top-left): positioned at [0:n, 0:n]
|
|
829
|
+
* - c12 (top-right): positioned at [0:n, n:2n]
|
|
830
|
+
* - c21 (bottom-left): positioned at [n:2n, 0:n]
|
|
831
|
+
* - c22 (bottom-right): positioned at [n:2n, n:2n]
|
|
832
|
+
*
|
|
833
|
+
* **Applications:**
|
|
834
|
+
* - Strassen algorithm result reconstruction
|
|
835
|
+
* - Block matrix operations and algebra
|
|
836
|
+
* - Hierarchical matrix assembly (multigrid methods)
|
|
837
|
+
* - Sparse matrix construction from dense blocks
|
|
838
|
+
* - Parallel matrix computation result merging
|
|
839
|
+
* - Image processing (combining processed image quadrants)
|
|
840
|
+
* - Scientific computing (domain decomposition methods)
|
|
841
|
+
*
|
|
842
|
+
* **Validation Requirements:**
|
|
843
|
+
* - All four input matrices must be square
|
|
844
|
+
* - All four input matrices must have identical dimensions
|
|
845
|
+
* - All elements must be valid numbers
|
|
846
|
+
* - No null or undefined matrices allowed
|
|
847
|
+
*
|
|
848
|
+
* **Memory Layout:**
|
|
849
|
+
* The function performs efficient copying by iterating through each quadrant
|
|
850
|
+
* sequentially, minimizing cache misses and ensuring optimal memory access patterns.
|
|
851
|
+
*
|
|
852
|
+
* **Time Complexity:** O(n²) where n is the dimension of each input quadrant
|
|
853
|
+
* **Space Complexity:** O(4n²) for the combined result matrix
|
|
854
|
+
*
|
|
855
|
+
* @param c11 - Top-left quadrant (upper-left block)
|
|
856
|
+
* @param c12 - Top-right quadrant (upper-right block)
|
|
857
|
+
* @param c21 - Bottom-left quadrant (lower-left block)
|
|
858
|
+
* @param c22 - Bottom-right quadrant (lower-right block)
|
|
859
|
+
* @returns {IMatrix} The combined matrix with dimensions 2n×2n (where each input is n×n)
|
|
860
|
+
* @throws {Error} If quadrants have mismatched dimensions or invalid values
|
|
861
|
+
*
|
|
862
|
+
* @example
|
|
863
|
+
* ```typescript
|
|
864
|
+
* // Basic 2×2 quadrant combination
|
|
865
|
+
* const topLeft = [[1, 2], [3, 4]];
|
|
866
|
+
* const topRight = [[5, 6], [7, 8]];
|
|
867
|
+
* const bottomLeft = [[9, 10], [11, 12]];
|
|
868
|
+
* const bottomRight = [[13, 14], [15, 16]];
|
|
869
|
+
*
|
|
870
|
+
* MatrixCombine(topLeft, topRight, bottomLeft, bottomRight)
|
|
871
|
+
* // Returns:
|
|
872
|
+
* // [[1, 2, 5, 6],
|
|
873
|
+
* // [3, 4, 7, 8],
|
|
874
|
+
* // [9, 10, 13, 14],
|
|
875
|
+
* // [11,12, 15, 16]]
|
|
876
|
+
*
|
|
877
|
+
* // Strassen algorithm result reconstruction
|
|
878
|
+
* const m1 = computeStrassenProduct1(); // Computed Strassen intermediate results
|
|
879
|
+
* const m2 = computeStrassenProduct2();
|
|
880
|
+
* const m3 = computeStrassenProduct3();
|
|
881
|
+
* const m4 = computeStrassenProduct4();
|
|
882
|
+
* const finalResult = MatrixCombine(m1, m2, m3, m4); // Assemble final result
|
|
883
|
+
*
|
|
884
|
+
* // Image processing: combining processed quadrants
|
|
885
|
+
* const processedTopLeft = processImageQuadrant(imageTopLeft);
|
|
886
|
+
* const processedTopRight = processImageQuadrant(imageTopRight);
|
|
887
|
+
* const processedBottomLeft = processImageQuadrant(imageBottomLeft);
|
|
888
|
+
* const processedBottomRight = processImageQuadrant(imageBottomRight);
|
|
889
|
+
* const reconstructedImage = MatrixCombine(
|
|
890
|
+
* processedTopLeft, processedTopRight,
|
|
891
|
+
* processedBottomLeft, processedBottomRight
|
|
892
|
+
* );
|
|
893
|
+
* ```
|
|
894
|
+
*/
|
|
895
|
+
export function MatrixCombine(c11, c12, c21, c22) {
|
|
896
|
+
AssertMatrix(c11);
|
|
897
|
+
AssertMatrix(c12);
|
|
898
|
+
AssertMatrix(c21);
|
|
899
|
+
AssertMatrix(c22);
|
|
900
|
+
const [qrows, _qcols] = MatrixSize(c11);
|
|
901
|
+
const halfSize = qrows;
|
|
902
|
+
const fullSize = halfSize * 2;
|
|
903
|
+
const result = MatrixCreate(fullSize, fullSize);
|
|
904
|
+
// Copy c11 to top-left quadrant [0:n, 0:n]
|
|
905
|
+
for (let row = 0; row < halfSize; row++) {
|
|
906
|
+
const sourceRow = c11[row];
|
|
907
|
+
AssertMatrixRow(sourceRow);
|
|
908
|
+
const resultRow = result[row];
|
|
909
|
+
AssertMatrixRow(resultRow);
|
|
910
|
+
for (let col = 0; col < halfSize; col++) {
|
|
911
|
+
const val = sourceRow[col];
|
|
912
|
+
AssertMatrixValue(val, { rowIndex: row, columnIndex: col });
|
|
913
|
+
resultRow[col] = val;
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
// Copy c12 to top-right quadrant [0:n, n:2n]
|
|
917
|
+
for (let row = 0; row < halfSize; row++) {
|
|
918
|
+
const sourceRow = c12[row];
|
|
919
|
+
AssertMatrixRow(sourceRow);
|
|
920
|
+
const resultRow = result[row];
|
|
921
|
+
AssertMatrixRow(resultRow);
|
|
922
|
+
for (let col = 0; col < halfSize; col++) {
|
|
923
|
+
const val = sourceRow[col];
|
|
924
|
+
AssertMatrixValue(val, { rowIndex: row, columnIndex: col });
|
|
925
|
+
resultRow[col + halfSize] = val;
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
// Copy c21 to bottom-left quadrant [n:2n, 0:n]
|
|
929
|
+
for (let row = 0; row < halfSize; row++) {
|
|
930
|
+
const sourceRow = c21[row];
|
|
931
|
+
AssertMatrixRow(sourceRow);
|
|
932
|
+
const resultRow = result[row + halfSize];
|
|
933
|
+
AssertMatrixRow(resultRow);
|
|
934
|
+
for (let col = 0; col < halfSize; col++) {
|
|
935
|
+
const val = sourceRow[col];
|
|
936
|
+
AssertMatrixValue(val, { rowIndex: row, columnIndex: col });
|
|
937
|
+
resultRow[col] = val;
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
// Copy c22 to bottom-right quadrant [n:2n, n:2n]
|
|
941
|
+
for (let row = 0; row < halfSize; row++) {
|
|
942
|
+
const sourceRow = c22[row];
|
|
943
|
+
AssertMatrixRow(sourceRow);
|
|
944
|
+
const resultRow = result[row + halfSize];
|
|
945
|
+
AssertMatrixRow(resultRow);
|
|
946
|
+
for (let col = 0; col < halfSize; col++) {
|
|
947
|
+
const val = sourceRow[col];
|
|
948
|
+
AssertMatrixValue(val, { rowIndex: row, columnIndex: col });
|
|
949
|
+
resultRow[col + halfSize] = val;
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
return result;
|
|
953
|
+
}
|
|
954
|
+
//# sourceMappingURL=arithmetic.js.map
|