from matrix import Matrix
# 1 0
# 2 0
# 3 0
A = Matrix.from_list([[1, 0], [2, 0], [3, 0]])
# 0 0 0
# 0 0 0
# 0 0 0
B = Matrix(3, 3)
# 10 0 0
# 0 89 0
# 0 0 0
B[1, 1] = 10
B[2, 2] = 89
# 10 0
# 178 0
# 0 0
C = B * A
for i, j in C:
print(i, j, C[i, j]) # prints every pair of indices and element on that position
Last active
March 10, 2022 09:51
-
-
Save evtn/8683e58770f2901527275d46465e4cbe to your computer and use it in GitHub Desktop.
Simple matrix calculator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| from typing import Tuple, Callable, List, Dict, Union | |
| Number = Union[float, int] | |
| class MatrixIter: | |
| def __init__(self, matrix): | |
| self.matrix = matrix | |
| self.index = 0 | |
| def __iter__(self): | |
| return self | |
| def __next__(self) -> Tuple[int]: | |
| prev_index = self.index | |
| self.index += 1 | |
| if prev_index >= (self.matrix.rows * self.matrix.columns): | |
| raise StopIteration | |
| return ( | |
| prev_index % self.matrix.rows + 1, | |
| prev_index // self.matrix.rows + 1 | |
| ) | |
| class Matrix: | |
| def __init__(self, rows: int, columns: int): | |
| self.data: Dict[Tuple[int], Number] = {} | |
| self.rows: int = rows | |
| self.columns: int = columns | |
| @property | |
| def size(self) -> Tuple[int]: | |
| return (self.rows, self.columns) | |
| def cut(self, ij: Tuple[int]) -> "Matrix": | |
| self.bound_check(ij) | |
| new = Matrix(self.rows - 1, self.columns - 1) | |
| ci, cj = ij | |
| for i, j in self: | |
| ri = i - (i > ci) | |
| rj = j - (j > cj) | |
| if not (ci == i or cj == j): | |
| new[ri, rj] = self[i, j] | |
| return new | |
| def __eq__(self, other: "Matrix") -> bool: | |
| return (self.rows == other.rows) and (self.columns == other.columns) and (self.data == other.data) | |
| def bound_check(self, ij: Tuple[int]) -> None: | |
| if (ij[0] - 1) not in range(self.rows): | |
| raise IndexError("invalid row index: {} (Must be in 1...{} range)".format(ij[0], self.rows)) | |
| if (ij[1] - 1) not in range(self.columns): | |
| raise IndexError("invalid column index: {} (Must be in 1...{} range)".format(ij[1], self.columns)) | |
| def __getitem__(self, ij: Tuple[int]) -> Number: | |
| self.bound_check(ij) | |
| return self.data.get(ij, 0) | |
| def __setitem__(self, ij: Tuple[int], value: Number) -> None: | |
| self.bound_check(ij) | |
| if not value: | |
| self.data.pop(ij, 0) | |
| self.data[ij] = value | |
| def __iter__(self): | |
| return MatrixIter(self) | |
| def __str__(self) -> str: | |
| return "Matrix object ({}x{} matrix)".format(*self.size) | |
| def __matmul__(self, other: "Matrix") -> "Matrix": | |
| return self * other | |
| def __mul__(self, other: Union["Matrix", Number]) -> "Matrix": | |
| if type(other) in [int, float]: | |
| new = self.new() | |
| for i, j in self: | |
| new[i, j] = self[i, j] * other | |
| return new | |
| if self.columns != other.rows: | |
| raise ValueError("Can't multiply ({self.rows} x {self.columns}) matrix and ({other.rows} x {other.columns}) matrix".format(self=self, other=other)) | |
| new = Matrix(self.rows, other.columns) | |
| for i, j in new: | |
| new[i, j] = sum([self[i, x] * other[x, j] for x in range(1, self.columns + 1)]) | |
| return new | |
| def __add__(self, other: "Matrix") -> "Matrix": | |
| if self.size != other.size: | |
| raise ValueError("Can't add matrices with different sizes") | |
| new = self.new() | |
| for i, j in self: | |
| new[i, j] = self[i, j] + other[i, j] | |
| return new | |
| def __sub__(self, other: "Matrix") -> "Matrix": | |
| return self + (-other) | |
| def __neg__(self) -> "Matrix": | |
| return self * -1 | |
| def apply(self, func: Callable) -> "Matrix": | |
| new = self.new() | |
| for i, j in self: | |
| new[i, j] = func(self[i, j]) | |
| return new | |
| def new(self) -> "Matrix": | |
| return Matrix(self.rows, self.columns) | |
| def copy(self) -> "Matrix": | |
| data = self.data.copy() | |
| new = self.new() | |
| new.data = data | |
| return new | |
| def transpose(self) -> "Matrix": | |
| new = Matrix(self.columns, self.rows) | |
| for i, j in new: | |
| new[i, j] = self[j, i] | |
| return new | |
| def to_list(self) -> List[List[Number]]: | |
| result = [] | |
| for i in range(self.rows): | |
| result.append([]) | |
| for j in range(self.columns): | |
| result[i].append(self[i + 1, j + 1]) | |
| return result | |
| def to_flat_list(self) -> List[Number]: | |
| if 1 not in self.size: | |
| raise ValueError("Can flatten only vector-like matrices") | |
| l = self.to_list() | |
| if self.columns == 1: | |
| return [c[0] for c in l] | |
| return l[0] | |
| @property | |
| def determinant(self) -> Number: | |
| if self.m != self.n: | |
| raise ValueError("Can't calculate determinant for non-square matrix") | |
| if not any(sum(x[1:]) for x in self.data[1:]): | |
| return 0 | |
| if self.m == 2: | |
| return self[1][1] * self[2][2] - self[1][2] * self[2][1] | |
| return sum([((-1) ** (s + 1)) * self[1][s] * self.minor_matrix(cj=s).determinant for s in self.columns]) | |
| @staticmethod | |
| def from_list(data: List[List[Number]]) -> "Matrix": | |
| rows = len(data) | |
| columns_lengths = set([len(x) for x in data]) | |
| if not columns_lengths: | |
| raise ValueError("Your matrix is empty") | |
| if len(columns_lengths) > 1: | |
| raise ValueError("Columns of your list have different sizes") | |
| columns = len(data[0]) | |
| new = Matrix(rows, columns) | |
| for i, row in enumerate(data): | |
| for j, value in enumerate(row): | |
| new[i + 1, j + 1] = value | |
| return new | |
| @staticmethod | |
| def scalar(size, num=1) -> "Matrix": | |
| new = Matrix(size, size) | |
| for i in range(1, size + 1): | |
| new[i, i] = num | |
| return new |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment