Home About Projects Resources

Python Linear Algebra

Linear algebra is used for a wide range of applications. Often when one has a system of equations linear algebra comes in handy. Cramer's rule is a somewhat reasonable way of solving systems of equations. Let's briefly review Cramer's rule and how it can help us solve a systme of linear equations.

If you recall, Cramers' rule is given as the following. Consider a system of n unknowns represented in a matrix multiplication form.

\[Ax = b\]

where the $n \times n $ matrix A has a nonzero determinant, and the vector x = $[x_1, x_2,...,x_n]^T$ is a column vector of the variables. The system has a unique solution whose indeividual values for the unknowns are given by

\[x_i = \frac{det(A_i)}{det(A)} \quad i=1,...,n\]

where $A_i$ is the matrix formed by replacing the $i^{th}$ column of $A$ with vector $b$.

Review of Determinants

Finding the determinant is an important part of Cramer's Rule. Let's take a moment to review how it's done. We'll start off small with a 2x2 matrix.

IMPORTANT: Determinants can only be found for square matricies.

\[ det\begin{bmatrix} a & b\\ c & d\\ \end{bmatrix} = (ad) - (bc)\]

Pretty simple, right! Well let's add another dimension and work through how to find the determinant of a 3x3 matrix. There are a few more steps, but once you see how it's done you'll be on your way to becoming a determinant master! Below you can see how the determinant of a 3x3 is found.

\[ det\begin{bmatrix} a & b & c \\ d & e & f \\ h & i & j \\ \end{bmatrix} = a \cdot det \begin{bmatrix} e & f \\ h & i \\ \end{bmatrix} - b \cdot det \begin{bmatrix} d & f \\ g & i \\ \end{bmatrix} + c \cdot det \begin{bmatrix} d & e \\ g & h \\ \end{bmatrix}\]

There are a few details that I have left out just for simplicity sake. If you'd like to learn more about the details check out the wiki page about Determinants. This method for finding the determinant works for any size of matrix. The only downside is the larger the matrix the more calculations are involved.

Cramer's Rule

I breifly touched on the mathmatics behind Cramer's Rule at the being, but let's take a closer look at how it is accomplished. Consider the system below.

\[\begin{bmatrix} a_1 & b_1 & c_1\\ a_2 & b_2 & c_2\\ a_3 & b_3 & c_3\\ \end{bmatrix} \begin{bmatrix} x\\ y\\ z\\ \end{bmatrix} = \begin{bmatrix} d_1\\ d_2\\ d_3\\ \end{bmatrix}\]

The values of x,y, and z are as follows...

\[x = \frac{det\begin{bmatrix} \color{red}d_1 & b_1 & c_1\\ \color{red}d_2 & b_2 & c_2\\ \color{red}d_3 & b_3 & c_3\\ \end{bmatrix}}{det\begin{bmatrix} a_1 & b_1 & c_1\\ a_2 & b_2 & c_2\\ a_3 & b_3 & c_3\\ \end{bmatrix}}, \qquad y = \frac{det\begin{bmatrix} a_1 & \color{red}d_1 & c_1\\ a_2 & \color{red}d_2 & c_2\\ a_3 & \color{red}d_3 & c_3\\ \end{bmatrix}}{det\begin{bmatrix} a_1 & b_1 & c_1\\ a_2 & b_2 & c_2\\ a_3 & b_3 & c_3\\ \end{bmatrix}}, \qquad z = \frac{det\begin{bmatrix} a_1 & b_1 & \color{red}d_1\\ a_2 & b_2 & \color{red}d_2\\ a_3 & b_3 & \color{red}d_3\\ \end{bmatrix}}{det\begin{bmatrix} a_1 & b_1 & c_1\\ a_2 & b_2 & c_2\\ a_3 & b_3 & c_3\\ \end{bmatrix}} \]

Application

Now that we understand Cramer's Rule let's apply it! The first application will be the ubiquitous nodal analysis with three (3) unknowns and three (3) equations. We'll start off by doing the nodal analysis on the following circuit.

pano

Let's run through the nodal analysis and label our points of interest, currents, and current direction. Remember when doing nodal analysis you get to pick which direction your currents flow and what you'd like to label your points of interest. Just make sure to be consistent with how you solve for the voltages.

pano Now that we have labeled our circuit we can move onto finding the equations for the currents using Kirchhoff's Current Law (KCL). Remember that the sum of currents entering or leaving a node is equal to zero (0). This principle can be succinctly stated as:

\[\sum_{k=1}^{n} I_{k}= 0\]

where n is the total number of branches with currents flowing towards or away from the node. Let's sum up each current flowing through each node.

\[I_1 = I_3 + I_2 \qquad I_2 = I_5 + I_4 \qquad I_4 = I_6\]

Let's find the current in terms of voltage and resistance. Remember that: $ V = IR$. When you calcaulte the voltage drop through a resistor. Take the voltage at the back of the arrow and minus the voltage at the front of the arrow.

\[\frac{6-V_a}{2k} = \frac{V_a - V_b}{2k} + \frac{V_a - 0}{1k}\qquad \frac{V_a-V_b}{2k} = \frac{V_b - 0}{1k} + \frac{V_b - V_c}{1k} \qquad \frac{V_b-V_c}{1k} = \frac{V_c}{3k}\]

With the currents all

import numpy as np
import numpy as np
#cramer's rule for 2x2
def det_2x2(A):
    #split up the 
    a_1 = A[0][0]
    a_2 = A[1][0]
    b_1 = A[0][1]
    b_2 = A[1][1]
    #perform calculation
    detA = ((a_1)*(b_2)-(a_2)*(b_1))
    return detA

def det_3x3(B):
    #break up the 3x3 matrix
    B_0 = B[1:3:1, 1:3:1]
    B_1 = B[1:3:1, 0:3:2]
    B_2 = B[1:3:1, 0:2:1]
    #perform calculation
    detB = B[0][0]*det_2x2(B_0) - \
        B[0][1]*det_2x2(B_1) + B[0][2]*det_2x2(B_2)
    return detB

def cramer_2x2(A,b):
    #create temp values when replacing b into A
    tempA = A*1
    tempB = A*1
    tempA[0:,0,] = b[:,0]
    tempB[0:,1,] = b[:,0]
    
    #solve using cramer's rule
    x = det_2x2(tempA)/det_2x2(A)
    y = det_2x2(tempB)/det_2x2(A)
    return x,y

def cramer_3x3(A3,b3):
    #create temp values when replacing b into A
    tempAx = A3*1
    tempAy = A3*1
    tempAz = A3*1
    
    #replace specific columns with b3
    tempAx[0:,0] = b3[:,0]
    tempAy[0:,1] = b3[:,0]
    tempAz[0:,2] = b3[:,0]
    
    #solve using cramer's rule
    x = det_3x3(tempAx)/det_3x3(A3)
    y = det_3x3(tempAy)/det_3x3(A3)
    z = det_3x3(tempAz)/det_3x3(A3)
    return x,y,z

def main():
    #enter array for 2x2
    A = np.array([[1.,2.],
                  [3.,4.]])
    b = np.array ([[5.], [6.]])
    #enter array for 3x3
    C = np.array ([[4. , -1. , 0.],
                   [-2. , 7. , -4.],
                   [0. , -3. , 4.]])
    d = np.array ([[6.], [0.], [0.]])
    #find the determinant of A
    detA = det_2x2(A)
    x_A,y_A = cramer_2x2(A,b)
    #find the determinant of C
    detC = det_3x3(C)
    x_C, y_C, z_C = cramer_3x3(C, d)
    
    #print statements
    print('--------Matrix 2x2--------')
    print('numpy det A:       %.4f' %np.linalg.det(A))
    print('det_2x2 function:  %.4f' %detA)
    print('x = %.3f \t \t y = %.3f\n' %(x_A,y_A))
    
    print('--------Matrix 3x3---------')
    print('numpy det C:       %.4f' %np.linalg.det(C))
    print('det_3x3 function:  %.4f' %detC)
    print('x=%.4f  y=%.4f  z=%.6f' \
          %(x_C,y_C,z_C))
    
if __name__ == "__main__":
    main()