diff --git a/README.md b/README.md index 503fa6b..4131211 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,12 @@ print(my_matrix.inverse) [-2, 1] [1.5, -0.5] +#special use by '**' power operator: +print(my_matrix ** -1) +#result: +[-2, 1] +[1.5, -0.5] + my_matrix2 = Mx.Matrix("1,2,3;4,5,6;7,8,9") print(my_matrix2) @@ -183,4 +189,4 @@ print(i) [1, 0, 0] [0, 1, 0] [0, 0, 1] -``` +``` \ No newline at end of file diff --git a/setup.py b/setup.py index 8fe7fa6..3de6cd7 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setup( name="xmatrix", - version="1.1.2", + version="1.1.3", author="Xanonymous", author_email="trusaidlin@gmail.com", description="Help you calculate matrix.", diff --git a/xmatrix/matrix.py b/xmatrix/matrix.py index b811abb..1b9b59b 100644 --- a/xmatrix/matrix.py +++ b/xmatrix/matrix.py @@ -5,6 +5,8 @@ More style details on:https://www.python.org/dev/peps/pep-0008 """ +from math import isclose + class Matrix: """Define the Matrix class""" @@ -59,12 +61,7 @@ def __sub__(self, other): def __mul__(self, other): if isinstance(other, int): # method accept single integer to be calculated. - new = list() - for i, x in enumerate(self.__storage): - new_tmp = list() - for _, y in enumerate(x): - new_tmp.append(y) - new.append(new_tmp) + new = self.__make_copy(self.__storage) return Matrix(self.__rate(new, other)) # If the matrices cannot be multiplied, throw an error. resource = other.raw @@ -77,7 +74,7 @@ def __mul__(self, other): return # if the second matrix is an identity_matrix, the answer will be the same as first matrix. if self.is_unit_matrix(resource): - new = self.__storage[:].copy() + new = self.__make_copy(self.__storage) return Matrix(new) new = list() for i, x in enumerate(self.__storage): @@ -94,9 +91,10 @@ def __rmul__(self, other): return self.__mul__(other) def __pow__(self, power: int, modulo=None): + # if self is an identity matrix or power assign 1, than return self. if self.is_unit_matrix(self.__storage) or power == 1: - new = self.__storage[:].copy() - return Matrix(new) + return Matrix(self.__make_copy(self.__storage)) + # if power == 0, than return identity matrix. if not power: n = len(self.__storage) tmp_n = n @@ -110,14 +108,22 @@ def __pow__(self, power: int, modulo=None): tmp.insert(0, tmp_tmp) tmp_n -= 1 return Matrix(tmp) + # if the matrix is not a square or invalid, return error. if not len(self.__storage) == len(self.__storage[0]): self.__error_handler("Unable to calculate power, not square.") return - tmp = Matrix(self.__storage[:].copy()) + # if the power < 0, recursive the positive power by self inverse. + tmp = Matrix(self.__make_copy(self.__storage)) + if power < 0: + tmp = tmp.inverse + if tmp is not None: + return tmp ** (power * -1) + return self.__error_handler("Unable to calculate power, determinant is zero.") + # calculate the positive power value of this matrix. for x in range(power - 1): self.__storage = self.__mul__(tmp).raw - new = self.__storage[:].copy() - self.__storage = tmp.raw[:].copy() + new = self.__make_copy(self.__storage) + self.__storage = self.__make_copy(tmp.raw) return Matrix(new) def __eq__(self, other): @@ -125,32 +131,20 @@ def __eq__(self, other): @property def inverse(self): - def make_new(old): - new_thing = list() - for _, xx in enumerate(old): - new_tmp = list() - for _, yy in enumerate(xx): - new_tmp.append(yy) - new_thing.append(new_tmp) - return new_thing - determinant = self.__determinant(self.__storage) if not determinant: self.__error_handler("The determinant is zero, can't be inverse.") return + new = self.__make_copy(self.__storage) if len(self.__storage) == 1: - new = make_new(self.__storage[:].copy()) new[0][0] = new[0][0] ** -1 return Matrix(new) if len(self.__storage) == 2: - new = make_new(self.__storage[:].copy()) new[0][0], new[1][1] = new[1][1], new[0][0] new[0][1] *= -1 new[1][0] *= -1 - new = self.__rate(new, 1 / determinant) - return Matrix(new) + return Matrix(self.__rate(new, 1 / determinant)) ans = list() - new = make_new(self.__storage[:].copy()) for i, x in enumerate(self.__storage): ans_tmp = list() for j, y in enumerate(x): @@ -158,13 +152,11 @@ def make_new(old): ans_tmp.append(h * self.__determinant(self.__get_ans_range(i, j, new))) ans.append(ans_tmp) ans = self.__transpose(ans) - new = self.__rate(ans, 1 / determinant) - return Matrix(new) + return Matrix(self.__rate(ans, 1 / determinant)) @property def transpose(self): - new = self.__storage[:].copy() - return Matrix(self.__transpose(new)) + return Matrix(self.__transpose(self.__make_copy(self.__storage))) def __determinant(self, r) -> int or float: if not self.__valid(r): @@ -198,19 +190,22 @@ def raw(self) -> list: # get the real value of the object return self.__storage - @staticmethod - def __pretty(r) -> str: - # Detect if the value can be an integer. + def __pretty(self, r) -> str: + # Detect if the value can be more short. for i, x in enumerate(r): for j, y in enumerate(x): - if abs(r[i][j] - int(r[i][j])) < 10 ** -3: + # try to turn the data to integer. + if abs(r[i][j] - int(r[i][j])) < 10 ** -4: r[i][j] = int(r[i][j]) + # the max floating point length in python is 16 so we use 15 to calculate. + if isinstance(r[i][j], float): + r[i][j] = self.__get_near_number(r[i][j], 15) # format the value then return return '\n'.join(map(str, r)) + '\n' @staticmethod def __error_handler(msg): - print(msg) + return print(msg) @staticmethod def __transpose(resource: list) -> list: @@ -252,6 +247,22 @@ def __magnification_iteration(r: list, rate) -> list: r[i][0] *= rate return r + @staticmethod + def __make_copy(old: list) -> list: + new = list() + for _, x in enumerate(old): + new_tmp = list() + for _, y in enumerate(x): + new_tmp.append(y) + new.append(new_tmp) + return new + + # find the max nearly round number of the float value. + def __get_near_number(self, data: float, pos: int) -> int or float: + if not isclose(data, round(data, pos), rel_tol=1e-4): + return round(data, pos + 1) + return self.__get_near_number(data, pos - 1) + class UnitMatrix(Matrix): def __init__(self, n):