Matrix class
import sys
import tkinter
import time
 
# Warning: Here be dragons!
# May crash your computer, eat your pizza and/or turn you into a frog.
 
# Enabled only for linux/windows machines.
TKTHREAD_ENABLED = sys.platform in ('win32', 'linux')
 
if TKTHREAD_ENABLED:
    import threading
 
    class _TkThread(threading.Thread):
        the_lock = threading.RLock()
        the_queue = []
 
        def __init__(self, *args, **kwargs):
            threading.Thread.__init__(self, *args, **kwargs)
            self.setDaemon(True)
 
        def run(self):
            root = tkinter.Tk()
            root.withdraw()
            while True:
                with self.the_lock:
                    func = self.the_queue.pop() if self.the_queue else None
                if func is not None:
                    func(root)
                root.update()
                time.sleep(.1)
    _TkThread().start()
 
#
 
class Matrix:
    """
    Represents a rectangular matrix with n rows and m columns.
    """
 
    def __init__(self, n,m):
        """
        Create an n-by-m matrix of zeros.
        """
        assert n > 0 and m > 0
        self.rows = [[0]*m for i in range(n)]
 
    def dim(self):
        return len(self.rows), len(self.rows[0])
 
    def __repr__(self):
        return "<Matrix {}>".format(self.rows)
 
    def __eq__(self, other):
        return isinstance(other, Matrix) and self.rows == other.rows
 
    # cell/sub-matrix access/assignment
    ####################################
    def __getitem__(self, ij):
        i,j = ij
        if isinstance(i, int) and isinstance(j, int):
            return self.rows[i][j]
        elif isinstance(i, slice) and isinstance(j, slice):
            M = Matrix(1,1) # to be overwritten
            M.rows = [row[j] for row in self.rows[i]]
            return M
        else:
            return NotImplemented
 
    def __setitem__(self, ij, val):
        i,j = ij
        if isinstance(i,int) and isinstance(j,int):
            assert isinstance(val, (int, float, complex))
            self.rows[i][j] = val
        elif isinstance(i,slice) and isinstance(j,slice):
            assert isinstance(val, Matrix)
            n,m = val.dim()
            s_rows = self.rows[i]
            assert len(s_rows) == n and len(s_rows[0][j]) == m
            for s_row, v_row in zip(s_rows,val.rows):
                s_row[j] = v_row
        else:
            return NotImplemented
 
    # arithmetic operations
    ########################
    def __add__(self, other):
        if not isinstance(other, Matrix):
            return NotImplemented
        assert self.dim() == other.dim()
        n,m = self.dim()
        M = Matrix(n,m)
        for i in range(n):
            for j in range(m):
                M[i,j] = self[i,j] + other[i,j]
        return M
 
    def __sub__(self, other):
        if not isinstance(other, Matrix):
            return NotImplemented
        assert self.dim() == other.dim()
        n,m = self.dim()
        M = Matrix(n,m)
        for i in range(n):
            for j in range(m):
                M[i,j] = self[i,j] - other[i,j]
        return M
 
    def __neg__(self):
        n,m = self.dim()
        return Matrix(n,m) - self
 
    def __mul__(self, other):
        if isinstance(other, Matrix):
            return self.multiply_by_matrix(other)
        elif isinstance(other, (int, float, complex)):
            return self.multiply_by_scalar(other)
        else:
            return NotImplemented
 
    __rmul__ = __mul__
 
    def multiply_by_scalar(self, val):
        n,m = self.dim()
        M = Matrix(n,m)
        for i in range(n):
            for j in range(m):
                M[i,j] = self[i,j] * val
        return M
 
    def multiply_by_matrix_naive(self, other):
        assert isinstance(other, Matrix)
        n,m = self.dim()
        n2,m2 = other.dim()
        assert m == n2
        M = Matrix(n,m2)
        for i in range(n):
            for j in range(m2):
                M[i,j] = sum(self[i,k] * other[k,j] for k in range(m))
        return M
 
    def multiply_by_matrix_Strassen(self, other):
        n,m = self.dim()
        n2,m2 = other.dim()
        assert n == m == n2 == m2 # we deal with square matrices only
 
        if n==1:
            result = Matrix(1,1)
            result[0,0] = self[0,0]*other[0,0]
            return result
        else:
            assert n % 2 == 0
            k = n//2
 
            A11 = self[:k,:k]
            A12 = self[:k,k:]
            A21 = self[k:,:k]
            A22 = self[k:,k:]
            B11 = other[:k,:k]
            B12 = other[:k,k:]
            B21 = other[k:,:k]
            B22 = other[k:,k:]
 
            M1 = (A11+A22)*(B11+B22)
            M2 = (A21+A22)*B11
            M3 = A11*(B12-B22)
            M4 = A22*(B21-B11)
            M5 = (A11+A12)*B22
            M6 = (A21-A11)*(B11+B12)
            M7 = (A12-A22)*(B21+B22)
 
            C11 = M1+M4-M5+M7
            C12 = M3+M5
            C21 = M2+M4
            C22 = M1-M2+M3+M6
 
            result = Matrix(n, n)
            result[:k,:k] = C11
            result[:k,k:] = C12
            result[k:,:k] = C21
            result[k:,k:] = C22
            return result
 
    multiply_by_matrix = multiply_by_matrix_Strassen
 
    # Input/output
    ###############
    def save(self, filename):
        f = open(filename, 'w')
        n,m = self.dim()
        print(n,m, file=f)
        for row in self.rows:
            #print(" ".join(str(x) for x in row), file=f)
            print(*row, file=f)
        f.close()
 
    @staticmethod
    def load(filename):
        f = open(filename)
        line = f.readline()
        n,m = [int(x) for x in line.split()]
        result = Matrix(n,m)
        for i in range(n):
            line = f.readline()
            row = [int(x) for x in line.split()]
            assert len(row) == m
            result.rows[i] = row
        return result
 
    def display(self, title=None, zoom=None):
        height, width = self.dim()
        pixels = " ".join('{' + ' '.join('#'+'{:02x}'.format(int(pixel))*3
                                       for pixel in row) + '}'
                          for row in self.rows)
 
        def tk_worker(root):
            # should not use touch 'self' directly. (That's what she said)
            pi = tkinter.PhotoImage(width=width,height=height)
            pi.put(pixels)
            if zoom is not None:
                assert zoom > 0
                if zoom > 1:
                    pi = pi.zoom(zoom)
                elif zoom < 1:
                    pi = pi.subsample(zoom)
            tl = tkinter.Toplevel(master=root)
            tl.title('Matrix' if title is None else title)
            lb = tkinter.Label(master=tl, image=pi)
            lb.pi = pi
            lb.pack()
            return tl
 
        if TKTHREAD_ENABLED:
            with _TkThread.the_lock:
                _TkThread.the_queue.append(tk_worker)
        else:
            root = tkinter.Tk()
            root.withdraw()
            tl = tk_worker(root)
            tl.protocol("WM_DELETE_WINDOW", root.destroy)
            root.mainloop()
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License