class Matrix:
def __init__(self, rows, cols, default_value=0):
self.rows = rows
self.cols = cols
self.matrix = [[default_value] * cols for _ in range(rows)]
def __getitem__(self, key):
row, col = key
self._validate_indices(row, col)
return self.matrix[row][col]
def __setitem__(self, key, value):
row, col = key
self._validate_indices(row, col)
self.matrix[row][col] = value
def _validate_indices(self, row, col):
if not (0 <= row < self.rows and 0 <= col < self.cols):
raise IndexError("Matrix index out of range")
def add(self, other):
if (self.rows, self.cols) != (other.rows, other.cols):
raise ValueError("Matrix dimensions must match")
result = Matrix(self.rows, self.cols)
for i in range(self.rows):
for j in range(self.cols):
result[i, j] = self[i, j] + other[i, j]
return result
def multiply(self, other):
if self.cols != other.rows:
raise ValueError("Matrix dimensions incompatible for multiplication")
result = Matrix(self.rows, other.cols)
for i in range(self.rows):
for j in range(other.cols):
sum_val = 0
for k in range(self.cols):
sum_val += self[i, k] * other[k, j]
result[i, j] = sum_val
return result
class SparseMatrix:
def __init__(self, rows, cols):
self.rows = rows
self.cols = cols
self.elements = {}
def __getitem__(self, key):
return self.elements.get(key, 0)
def __setitem__(self, key, value):
if value != 0:
self.elements[key] = value
elif key in self.elements:
del self.elements[key]
def multiply(self, other):
result = SparseMatrix(self.rows, other.cols)
for (i, k), val1 in self.elements.items():
for j in range(other.cols):
if (k, j) in other.elements:
key = (i, j)
result[key] = result[key] + val1 * other[k, j]
return result
import numpy as np
class NumPyMatrix:
def __init__(self, data):
self.data = np.array(data)
def add(self, other):
return NumPyMatrix(self.data + other.data)
def multiply(self, other):
return NumPyMatrix(np.dot(self.data, other.data))
def transpose(self):
return NumPyMatrix(self.data.T)
* k is number of non-zero elements
** For m×n and n×p matrices
*** k is number of non-zero elements in first matrix
**** View only, actual transpose is O(mn)
def handle_empty_matrix(self):
return self.rows == 0 or self.cols == 0
def is_single_element(self):
return self.rows == 1 and self.cols == 1
def validate_dimensions(self, other):
if (self.rows, self.cols) != (other.rows, other.cols):
raise ValueError("Matrix dimensions must match")
def block_multiply(self, other, block_size=32):
result = Matrix(self.rows, other.cols)
for i in range(0, self.rows, block_size):
for j in range(0, other.cols, block_size):
for k in range(0, self.cols, block_size):
for bi in range(min(block_size, self.rows - i)):
for bj in range(min(block_size, other.cols - j)):
sum_val = result[i + bi, j + bj]
for bk in range(min(block_size, self.cols - k)):
sum_val += self[i + bi, k + bk] * other[k + bk, j + bj]
result[i + bi, j + bj] = sum_val
return result
def strassen_multiply(self, other):
if self.rows <= 64:
return self.multiply(other)
n = self.rows
mid = n // 2
a11 = self.submatrix(0, mid, 0, mid)
a12 = self.submatrix(0, mid, mid, n)
a21 = self.submatrix(mid, n, 0, mid)
a22 = self.submatrix(mid, n, mid, n)
b11 = other.submatrix(0, mid, 0, mid)
b12 = other.submatrix(0, mid, mid, n)
b21 = other.submatrix(mid, n, 0, mid)
b22 = other.submatrix(mid, n, mid, n)
p1 = (a11 + a22).strassen_multiply(b11 + b22)
p2 = (a21 + a22).strassen_multiply(b11)
p3 = a11.strassen_multiply(b12 - b22)
p4 = a22.strassen_multiply(b21 - b11)
p5 = (a11 + a12).strassen_multiply(b22)
p6 = (a21 - a11).strassen_multiply(b11 + b12)
p7 = (a12 - a22).strassen_multiply(b21 + b22)
c11 = p1 + p4 - p5 + p7
c12 = p3 + p5
c21 = p2 + p4
c22 = p1 - p2 + p3 + p6
return Matrix.combine(c11, c12, c21, c22)
class CompactMatrix:
def __init__(self, rows, cols):
self.rows = rows
self.cols = cols
self.data = bytearray(rows * cols * 8)
def __getitem__(self, key):
i, j = key
return struct.unpack('d', self.data[8*(i*self.cols + j):8*(i*self.cols + j+1)])[0]
def __setitem__(self, key, value):
i, j = key
self.data[8*(i*self.cols + j):8*(i*self.cols + j+1)] = struct.pack('d', value)
class MatrixPool:
def __init__(self, max_size):
self.pool = {}
def get_matrix(self, rows, cols):
key = (rows, cols)
if key in self.pool and self.pool[key]:
return self.pool[key].pop()
return Matrix(rows, cols)
def return_matrix(self, matrix):
key = (matrix.rows, matrix.cols)
if key not in self.pool:
self.pool[key] = []
self.pool[key].append(matrix)
def cache_friendly_multiply(self, other):
result = Matrix(self.rows, other.cols)
other_t = other.transpose()
for i in range(self.rows):
for j in range(other.cols):
sum_val = 0
for k in range(self.cols):
sum_val += self[i, k] * other_t[j, k]
result[i, j] = sum_val
return result
from multiprocessing import Pool
def parallel_multiply(self, other, num_processes=4):
pool = Pool(processes=num_processes)
result = Matrix(self.rows, other.cols)
def multiply_row(i):
return [sum(self[i, k] * other[k, j]
for k in range(self.cols))
for j in range(other.cols)]
results = pool.map(multiply_row, range(self.rows))
for i, row in enumerate(results):
for j, val in enumerate(row):
result[i, j] = val
pool.close()
return result
def copy_wrong(self):
return self.matrix[:]
def copy_correct(self):
result = Matrix(self.rows, self.cols)
for i in range(self.rows):
for j in range(self.cols):
result[i, j] = self[i, j]
return result
def multiply_wrong(self, other):
result = Matrix(self.rows, other.cols)
for i in range(self.rows):
for j in range(other.cols):
result[i, j] = sum(self[i, k] * other[k, j]
for k in range(self.cols))
def multiply_correct(self, other):
if self.cols != other.rows:
raise ValueError("Matrix dimensions incompatible for multiplication")
def add_wrong(self, other):
return [[self[i, j] + other[i, j]
for j in range(self.cols)]
for i in range(self.rows)]
def add_correct(self, other):
result = Matrix(self.rows, self.cols)
for i in range(self.rows):
for j in range(self.cols):
result[i, j] = self[i, j] + other[i, j]
return result