top of page

Writing Linear Algebra Routine I: Power of a Python List


If you want to talk to machines and you want them to talk back to you, you won’t go far without knowing at-least something about Linear Algebra. The famous Matrix Triology is one good analogy/allegory of this. Although there are some efficient and powerful routines present however, one soon realizes that importing, extending and re-use of the code becomes a challenge with the use of these libraries. In this post I am demonstrating the power of a simple Python list and/or 1st order nested list. For example list = [[x,y,z],[a,b,c],[1,2,3]] is an example of a 1st order nested list. You can call any list that could be indexed as List[m][n] as a 1st order nested list. I am writing the code from scratch, which means that my code is not built on any library (not even the most basic math.py in this case).

An m×n matrix consists of m rows and n columns. Python lists can behave very much like matrices if one could properly index them. For example a value Aij refers to the value in ith row and jth column. For example: given that

. if i=2 and j=1, then Aij = 3.

Similarly, in Python one can index a nested list (list within a list) as List[m][n] or List[m] if the dimension of the matrix is 1X0. (In following code I have used a notation of List[n][m] rather than List[m][n] to denote the ijth value receptively!)

I have used only the functionality of lists to develop this basic linear algebra library. I am working on higher functions such as Inverse and Transpose, SVD etc. and some optimization algorithms to effectively optimize our lists. They will be available, shortly. Please, do note that I have tested the code for some routine values, however, due to some time constraints I could not rigorously test the code so feel free to report bugs and/or suggest changes. Following are the implemented functions:

dim(k) – Takes list/1st order list to return the dimension of VECTOR/MATRIX. Returns Dimension as a 1X2 tuple. IsConsistent(k) – Takes in a VECTOR/MATRIX in the form of a list/1st order list and returns ‘True’ if it is consistent. (Please Note: All of the functions implemented in this library; assume that the arguments passed have consistent dimensions ) IsOfEqualDim(x,y) – Checks if the dimension of these arguments are equal hence is it possible to perform Addition, subtraction etc between them. Function takes two simple or 1st degree nested list or int or float. Returns True or False. IsMultipliable(e,f) – Takes in list/1st Order list and returns True if the 2 passed arguments are capable of matrix multiplication. ADD(a,b) – takes 2 arguments and performs addition operation. Because of commutative and associative nature of addition, an argument can be passed in any order. Please note that either or both of the arguments can be int or floats. Hence it making this function adaptive for scalar addition. SUBT(a,b) – takes 2 arguments and performs subtraction operation. Because of commutative and associative nature of subtraction, an argument can be passed in any order (This will maintain the integrity of integer sign). Note that either or both of the arguments can be int or floats.Hence, it making this function adaptive for scalar subtraction. MULT(e,f) – Multiplies two VECTORS/MATRICES together or with a Scalar. The order in which u pass the argument MATTERS HERE because, multiplication is not commutative. However if either of the arguments is a scalar than order doesn’t matter. Takes in VECTOR/MATRIX/FLOAT/INT. However, they should be IsMultipliable(x,y)and IsConsistent(x) !
############################################################
def dim(k):
    ''' Takes list/1st order list to return the dimension of VECTOR/MATRIX. Returns Dimension as a 1X2 tuple.'''
    try:
        n = 0
        if type(k[0]) in [int,float]:
            return (1,0)
        else:
            return len(k), len(k[0])
    except:
        return 'dim(arg) takes a list or a 1st degree nested list(e.g list that could be indexed as list[m][n])'
        
###############################################################

        
###############################################################

def IsConsistent(k):
    
    '''All of teh functions implemented in this library; assume that the arguments passed have consistent dimensions. This function takes in a VECTOR/MATRIX in the form of a 1st order list or simple list and returns true if it is consistent'''
    
    n = 0
    t = []
    for i in k[:-1]:
        if (type(k[n]) in [float,int]):
            t.append(2)
        if (type(k[n]) != type(k[n+1])):
            t.append(1)
        n = n + 1
        
    if 1 in t:
        return False
    
    elif 2 in t:
        return True
        
    m = 0
    for i in k[:-1]:
        try:
            if type(k[m]) != type(k[m+1]):
                t.append(1)
            if len(k[m]) != len(k[m+1]):
                t.append(1)
            m = m + 1
        except:
            return 'Please, check if the matrix : ' + str(k) + ' is a nested list.'
            break
    if 1 in t:
        return False
    else:
        return True

###############################################################

###############################################################

def IsOfEqualDim(x,y):
    ''' Check if the dimension of these arguments are equal hence is it possible to perform Addition, subtraction etc b'w them. Function takes two simple or 1st degree nested list or list/float'''
    
    if dim(x) == dim(y):
        return True
            
    elif dim(x) != dim(y):
           return False
 
################################################################

################################################################

def IsMultipliable(e,f):
    ''' Takes in list/1st Order list and returns true if the 2 passed arguments are multipliable '''
    
    if dim(e)[1] == dim(f)[0]:
        return True
    elif dim(e)[1] != dim(f)[0]:
        return False
        
###############################################################

################################################################

def ADD(a,b):
    
    ''' ADD(arg#1, arg#2) takes two arguments and performs addition operation. Because of commutitive and associative nature of addition, an argument can be passed in any order. Please note that either or both of teh arguments can be int or floats.Hence it making this function adaptive for normal addition'''
    
    try: # 'Hypothesis are nets, only the one who casts will catch' ~ Novalis
    
        #~SCALAR to VECTOR/MATRIX ADDITION PART~#

#First, check if BOTH of arguments are scalars? if so keep it short and return just simple addition.
        if type(a) in [float,int] and type(b) in [float,int]:
            return a + b

#If first argument (arg#1) is a scalar then proceed accordingly:
        if type(a) in [float,int]:
            t = [] #set the list to capture values of operation.
    #if arg#2 is a VECTOR (or simple list); proceed accodrdingly (iterating over outer loop only).
            if (type(b[0]) in [float,int]):
                n = 0
                for i in b:
                    t.append(a + b[n])
                    n = n + 1
                return t
            
    #Likewise, if arg#2 is a MATRIX(or 1st degree nested list); then make sure you loop over inner loop aswell(to iterate over columns aswell ):
            elif (type(b[0]) in [list]):
                n = 0
                for i in b:
                    m = 0
                    u = []
            # Going in inner loop to iterate over the coulmns,    
                    for i in b[0]:
                        u.append(a + b[n][m])
                        m = m + 1
                    t.append(u)
                    n = n + 1
                return t
    
#Similarly repeat the same process wrt the arg#2 to maintain robustness for the order of arguments and maintining associativity and commutivity.  

        if type(b) in [float,int]:
            t = []
            if (type(a[0]) in [float,int]):
                n = 0
                for i in a:
                    t.append(a[n] + b)
                    n = n + 1
                return t
    
            elif (type(a[0]) in [list]):
            #u = []
                n = 0
                for i in a:
                    m = 0
                    u = []
                    for i in a[0]:
                        u.append(a[n][m] + b)
                        m = m + 1
                    t.append(u)
                    n = n + 1
                return t   
                
        #~VECTOR/MATRIX to VECTOR/MATRIX ADDITION PART~#
        
        else:
            t = []
            if (type(a[0]) in [float,int]):
                n = 0
                for i in a:
                    t.append(a[n] + b[n])
                    n = n + 1
                return t
    
            elif (type(a[0]) in [list]):
                #u = []
                n = 0
                for i in a:
                    m = 0
                    u = []
                    for i in a[0]:
                        u.append(a[n][m] + b[n][m])
                        m = m + 1
                    t.append(u)
                    n = n + 1
                return t
                
    except: #Remember our friend Novalis up there??
        return 'Check if the arguments being passed are IsConsistent(arg) and/or IsOfEqualDim(arg,kwarg)'
        

################################################################

################################################################

def SUBT(a,b):
    
    ''' SUBT(arg#1, arg#2) takes two arguments and performs subtraction operation. Because of commutitive and associative nature of subtraction, an argument can be passed in any order. Please note that either or both of the arguments can be int or floats.Hence it making this function adaptive for normal subtraction'''
    
    try: # 'Hypothesis are nets, only the one who casts will catch' ~ Novalis
    
        #~SCALAR to VECTOR/MATRIX ADDITION PART~#

#First, check if BOTH of arguments are scalars? if so keep it short and return just simple operation.
        if type(a) in [float,int] and type(b) in [float,int]:
            return a - b

#If first argument (arg#1) is a scalar then proceed accordingly:
        if type(a) in [float,int]:
            t = [] #set the list to capture values of operation.
    #if arg#2 is a VECTOR (or simple list); proceed accodrdingly (iterating over outer loop only).
            if (type(b[0]) in [float,int]):
                n = 0
                for i in b:
                    t.append(a - b[n])
                    n = n + 1
                return t
            
    #Likewise, if arg#2 is a MATRIX(or 1st degree nested list); then make sure you loop over inner loop aswell(to iterate over columns aswell ):
            elif (type(b[0]) in [list]):
                n = 0
                for i in b:
                    m = 0
                    u = []
            # Going in inner loop to iterate over the coulmns,    
                    for i in b[0]:
                        u.append(a - b[n][m])
                        m = m + 1
                    t.append(u)
                    n = n + 1
                return t
    
#Similarly repeat the same process wrt the arg#2 to maintain robustness for the order of arguments and maintining associativity and commutivity.  

        if type(b) in [float,int]:
            t = []
            if (type(a[0]) in [float,int]):
                n = 0
                for i in a:
                    t.append(a[n] - b)
                    n = n + 1
                return t
    
            elif (type(a[0]) in [list]):
            #u = []
                n = 0
                for i in a:
                    m = 0
                    u = []
                    for i in a[0]:
                        u.append(a[n][m] - b)
                        m = m + 1
                    t.append(u)
                    n = n + 1
                return t   
                
        #~VECTOR/MATRIX to VECTOR/MATRIX SUBTRACTION PART~#
        
        else:
            t = []
            if (type(a[0]) in [float,int]):
                n = 0
                for i in a:
                    t.append(a[n] - b[n])
                    n = n + 1
                return t
    
            elif (type(a[0]) in [list]):
                #u = []
                n = 0
                for i in a:
                    m = 0
                    u = []
                    for i in a[0]:
                        u.append(a[n][m] - b[n][m])
                        m = m + 1
                    t.append(u)
                    n = n + 1
                return t
                
    except: #Remember our friend Novalis up there??
        return 'Check if the arguments being passed are IsConsistent(arg) and/or IsOfEqualDim(arg,kwarg)'
        

################################################################

################################################################

def MULT(e,f):
    
    '''Multiplies two VECTORS/MATRICES togeather or with a Scalar. The order in which u pass the argument matters because, multiplication is not commutative. However if either of the arguments is a scalar than order doesn't matter. Takes in VECTOR/MATRIX/FLOAT/INT. However, they should be IsMultipliable(x,y).and IsConsistent'''
    
    '''Before moving any further check if the two arguments can be multiplied and save yourdelf some computational cost'''
    
    if (IsMultipliable(e,f) == False) and (dim(f) !=  (1,0)):
        return 'ERROR: IsMultipliable() and/or order of multiplication)'
        
        
    ##################################################
    #This Function shreds the first elements of the rows of arg#2 and prepares arg#2 for multiplication.
    def AccordinglyShred(b):
        lst=[]
        n=0
        for i in b[n]:
            u = []
            m = 0
            for i in b:
                u.append(b[m][n])
                m = m + 1
            lst.append(u)
            n = n + 1
        return lst
    
    ####################################################
    #This function takes in arg#2 as a vector and multiplies.
    def m(a,b):
        if type(b[0]) in [float,int]:
            t = []
            n = 0
            for i in a:
                m = 0
                h = 0
                for i in a[n]:
                    h += (a[n][m] * b[m])
                    m = m + 1
                n = n + 1
                t.append(h)#
            return t
    
        if type(a[0]) in [float,int]:
            t = []
            n = 0
            for i in b:
            #u = []
                m = 0
                h = 0
                for i in b[n]:
                    h += (b[n][m] * a[m])
                    m = m + 1
                n = n + 1
                t.append(h)#
            return t
    #######################################################
    
    if dim(f) ==  (1,0):
        return m(e,f)
        
            
    else:
        try:
            f = AccordinglyShred(f)
            g = []
            n = 0
            for i in f:
                g.append(m(e,f[n]))
                n = n + 1    
            g = zip(*g)    
            foo = []
            o = 0
            for i in g:
                g[o] = (list(g[o]))
                o += 1    
            return g
            
        except:
            return 'Check The dimensions of the Matrices (Hint: check if IsConsistent(), IsMultipliable() and/or order of multiplication)'

##############################################################

1 view0 comments

Comentarios


bottom of page