<jupyter_start><jupyter_text>Linear Algebra for CHE Laboratory 3: Matrix Operations  Objectives1. Be familiar with the fundamental matrix operations.2. Apply the operations to solve the intermediate equations.3. Apply matrix algebra in engineering solutions   Discussion<jupyter_code>import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline<jupyter_output><empty_output><jupyter_text>Transporsition One of the fundamental operations in matrix algebra is Transposition. The transport of a matrix is done by flipping tha values of its elements over its diagonals. With these, rows and columns from the original matrix will be switched. So for a matrix $A$ its transpose is denoted as $A^T$. $$A = \begin{bmatrix} 1 & 4 & 5\\7 & -9 & 11 \\ 1 & -3 & 5\end{bmatrix}$$ $$A^T = \begin{bmatrix} 1 & 7 & 1\\4 & -9 & -3 \\ 5 & 11 & 5\end{bmatrix}$$ This can now be achieved programmatically by using np.tramspose() or using the T method.<jupyter_code>A = np.array([
    [1,4,5],
    [7,-9,11],
    [1,-3,5]
])
A
AT1 = np.transpose(A)
AT1
AT2 = A.T
AT2
np.array_equiv(AT1, AT2)
B = np.array([
    [1,2,3,4,5],
    [1,3,4,1,4],
])
B.shape
np.transpose(B).shape
B.T.shape<jupyter_output><empty_output><jupyter_text>Try to create own matrix (you can try non-squares) to test transposition.<jupyter_code>Z=np.array([
    [2,4,6,8],
    [3,6,9,12]
])
Z.shape
np.transpose(Z).shape
Z.T.shape
ZT = Z.T
ZT<jupyter_output><empty_output><jupyter_text>Dot Product / Inner Product Using the same operation with matrices. In matrix dot product we are going to get the sum of products of the vectors by row-column pairs. So if we have two matrices and $Y$: $$X = \begin{bmatrix} X(0,0) & X(0,1) \\X(1,0) & X(1,1)\end{bmatrix}$$,$$Y = \begin{bmatrix} X(0,0) & X(0,1) \\X(1,0) & X(1,1)\end{bmatrix}$$ The dot product will then be computed as: $$X.Y = \begin{bmatrix} X(0,0) * Y(0,0) + X(0,1) * Y(1,0) & X(0,0) * Y(0,1) + X(0,1) * Y(1,1)\\ X(1,0) * Y(0,0) + X(1,1) * Y(1,0) & X(1,0) * Y(0,1) + X(1,1) * Y(1,1)\end{bmatrix}$$ So if we assign values to $X$ and $Y$: $$X = \begin{bmatrix} -10 & -8 & -6 & -4 & -2 & 2 & 4 & 6 & 8 & 10 \\ -12 & -9 & -6 & -3 & 0 & 3 & 6 & 9 & 12\end{bmatrix}$$, $$Y = \begin{bmatrix} 1 & 3 & 5 & 7 & 9 \\ 2 & 4 & 6 & 8 & 10\end{bmatrix}$$ $$X.Y = \begin{bmatrix} 1 * -1 + 2 * 2 &  1 * 0 + 2 * 2\\ 0 * -1 + 1 * 2 & 0 * 0 + 1 * 2\end{bmatrix}$$ $$ \begin{bmatrix} 3 & 4 \\2 & 2\end{bmatrix}$$ This could be achieved programmatically using np.dot(), np.matmul() or the @ operator.<jupyter_code>X = np.array([
    [-10,8],
    [-12,9]
])
Y = np.array([
    [1,3],
    [2,4]
])
np.array_equiv(X,Y)
np.dot(X,Y)
X.dot(Y)
X @ Y
np.matmul(X,Y)
D = np.array([
    [-2,0,3],
    [-3,1,4],
    [-4,2,4]
])
E = np.array ([
    [-4,2,4],
    [4,6,8],
    [9,6,4]
])
np.array_equiv(D,E)
np.dot(D,E)
D.dot(E)
D @ E
np.matmul(D,E)<jupyter_output><empty_output><jupyter_text>In matix dot products there are additional rules compared with vector dot producs. Rule 1: The inner dimensions of the matrices in question must be the same. Given a matrix $A$ with a shape of $(a,b)$ where $a$ and $b$ are any integers. If we want to do a dot product between $A$ and another matrix $B$, then matrix $B$ should have a shape of $(b,c)$ are any integers. So for given the following matrices: $$A = \begin{bmatrix} 4 & 2\\5 & -1\\ 0 & -5\end{bmatrix}$$, $$B = \begin{bmatrix} 5 & 8\\7 & -2\\ 1 & -4\end{bmatrix}$$, $$C = \begin{bmatrix} 7 & 4 & 8\\5 & -4 & 2\end{bmatrix}$$ So in this case $A$ has a shape of $(3,2), B$ has a shape of $(2,3)$. So the only matrix pairs that is eligible to perform dot product is matrices $A*C, or B*C.$<jupyter_code>A = np.array([
    [4,2],
    [5,-1],
    [0,-5]
])
B = np.array([
    [5,8],
    [7,-2],
    [1,-4]
])
C = np.array([
    [7,4,8],
    [5,-4,2]
]) 
print(A.shape),
print(B.shape),
print(C.shape)
A @ C
B @ C<jupyter_output><empty_output><jupyter_text>If you would notice the shape of thedot product changed and its shape is not the same as any of the matrices we used. The shape of a dot product is actually derived from the shape of the matrices used. So recall $A$ with a shape of $(a,b)$ and matrix $B$ with a shape of $(b,c), A*B$ should have a shape $(a,c)$.<jupyter_code>A @ B.T
X = np.array([
    [3,4,5,6]
])
Y = np. array([
    [2,0,4,-2]
])
print(X.shape)
print(Y.shape)
Y.T @ X
X @ Y.T<jupyter_output><empty_output><jupyter_text>You can see that when you try to multiply A and B, it returns ValueError pertaining to matrix shape mismatch. Rule 2: Dot Product has special properties Dot product are prevalent in matrix algebra, this implies that it has severa; unique properties and it should be considered when formulation solutions: 1. $A \cdot B \neq B \cdot A$ 2. $A \cdot (B \cdot C) = (A \cdot B) \cdot C$ 3. $A\cdot(B+C) = A\cdot B + A\cdot C$ 4. $(B+C)\cdot A = B\cdot A + C\cdot A$ 5. $A\cdot I = A$ 6. $A\cdot \emptyset = \emptyset$ I'll be doing just one  of the properties and I'll  leave the rest to test your skills!<jupyter_code>A = np.array([
    [3,2,1],
    [4,5,1],
    [1,1,1]
])
B = np.array([
    [4,1,6],
    [4,1,9],
    [1,1,1]
])
C = np.array([
    [1,1,0],
    [0,1,1],
    [1,0,1]
])
np.eye(3)
A.dot(np.eye(3))
np.array_equal(A@B, B@A)
E = A @ (B @ C)
E
F = (A @ B) @ C
F
np.array_equal(E,X)
np.array_equiv(E,F)
np.eye(3)
A @ E
z_mat = np.zeros(A.shape)
z_mat
a_dot_z = A.dot(np.zeros(A.shape))
a_dot_z
np.array_equal(a_dot_z,z_mat)
null_mat = np.empty(A.shape, dtype=float)
null = np.array(null_mat,dtype=float)
print(null)
np.allclose(a_dot_z,null)<jupyter_output>[[0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]]<jupyter_text>Derterminant A determinant is a scalar value derived from a square matrix. The determinant is a fundamental and important value used in matrix algebra. Although it will not be evident in this laboratory on how it can be used practically, but it will be reatly used in future lessons. The determinant of some matrix $A$ is denoted as $det(A)$ or |$A$|. So let say $A$ is represented as:$$A = \begin{bmatrix}a_{(0,0)}&a_{(0,1)}\\a_{(1,0)}&a_{(1,1)}\end{bmatrix}$$We can compute for the determinant as:$$|A| = a_{(0,0)}*a_{(1,1)} - a_{(1,0)}*a_{(0,1)}$$So if we have $A$ as:$$A = \begin{bmatrix}1&4\\0&3\end{bmatrix}, |A| = 3$$But you might wonder how about square matrices beyond the shape $(2,2)$? We can approach this problem by using several methods such as co-factor expansion and the minors method. This can be taught in the lecture of the laboratory but we can achieve the strenuous computation of high-dimensional matrices programmatically using Python. We can achieve this by using `np.linalg.det()`.<jupyter_code>A = np.array([
    [3,6],
    [2,5]
])
np.linalg.det(A)
B = np.array([
              [3, 7, 4],
              [1, -3 ,-3],
              [0, -4, 3]
])
np.linalg.det(B)
## Now other mathematics classes would require you to solve this by hand, 
## and that is great for practicing your memorization and coordination skills 
## but in this class we aim for simplicity and speed so we'll use programming
## but it's completely fine if you want to try to solve this one by hand.
B = np.array([
    [3,5,7,8],
    [0,4,2,4],
    [5,3,6,1],
    [3,1,4,7]
])
np.linalg.det(B)<jupyter_output><empty_output><jupyter_text>Inverse The inverse of a matrix is another fundamental operation in matrix algebra. Determining the inverse of a matrix let us determine if its solvability and its characteristic as a system of linear equation — we'll expand on this in the nect module. Another use of the inverse matrix is solving the problem of divisibility between matrices. Although element-wise division exists but dividing the entire concept of matrices does not exists. Inverse matrices provides a related operation that could have the same concept of "dividing" matrices.Now to determine the inverse of a matrix we need to perform several steps. So let's say we have a matrix $M$:$$M = \begin{bmatrix}1&7\\-3&5\end{bmatrix}$$First, we need to get the determinant of $M$.$$|M| = (1)(5)-(-3)(7) = 26$$Next, we need to reform the matrix into the inverse form:$$M^{-1} = \frac{1}{|M|} \begin{bmatrix} m_{(1,1)} & -m_{(0,1)} \\ -m_{(1,0)} & m_{(0,0)}\end{bmatrix}$$So that will be:$$M^{-1} = \frac{1}{26} \begin{bmatrix} 5 & -7 \\ 3 & 1\end{bmatrix} = \begin{bmatrix} \frac{5}{26} & \frac{-7}{26} \\ \frac{3}{26} & \frac{1}{26}\end{bmatrix}$$For higher-dimension matrices you might need to use co-factors, minors, adjugates, and other reduction techinques. To solve this programmatially we can use `np.linalg.inv()`.<jupyter_code>M = np.array([
    [3,9],
    [-5, 3]
])

np.array(M @ np.linalg.inv(M), dtype=int)
P = np.array([
              [4, 7, -2],
              [6, 4, -3],
              [1, 4, 8]
])
Q = np.linalg.inv(P)
Q
P @ Q
## And now let's test your skills in solving a matrix with high dimensions:
N = np.array([
    [14,8,27,4,0,35,15],
    [2,44,10,1,12,14,22],
    [15,19,2,10,8,0,5],
    [11,16,5,2,5,4,14],
    [18,-3,4,9,0,7,11],
    [-5,10,-2,0,-4,6,-13],
    [-2,-3,10,12,15,22,-12],
])
N_inv = np.linalg.inv(N)
np.array(N @ N_inv,dtype=int)<jupyter_output><empty_output><jupyter_text>To validate the wether if the matric that you have solved is really the inverse, we follow this dot product property for a matrix $M$:$$M\cdot M^{-1} = I$$<jupyter_code>squad = np.array([
    [1.5, 1.5, 1.0],
    [2.7, 1.2, 0.4],
    [2.3, 0.5, 1.0]
])
weights = np.array([
    [0.2, 0.7, 0.7]
])
p_grade = squad @ weights.T
p_grade<jupyter_output><empty_output><jupyter_text>Activity  Task 1 Prove and implement the remaining 6 matrix multiplication properties. You may create your own matrices in which their shapes should not be lower than (3,3) . In your methodology, create individual flowcharts for each property and discuss the property you would then present your proofs or validity of your implementation in the results section by comparing your result to present functions from NumPy.<jupyter_code>np.array([])
import numpy as np 
arr = np.array([1,2,3,4,5,6,7,8,9,10,11,12])
print(arr)
print(type(arr))
print(arr.ndim)
print(arr[0])
print(arr[1:5])
for x in arr:
  print(x)
x = np.where(arr == 4)
print(x)<jupyter_output>(array([3]),)
{'fraction_non_alphanumeric': 0.1682611697406056, 'fraction_numerical': 0.05039944767728573, 'mean_word_length': 3.6944444444444446, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 5, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '11', 'dir': 'jupyter-structured-clean-dedup', 'id': '366953', 'license': 'Apache-2.0', 'n_tokens_mistral': 4093, 'n_tokens_neox': 3850, 'n_words': 1289, 'path': 'Assignment4.ipynb', 'repo_name': 'Kristel04/LinearAlgebra1T-2021-2022', 'size': '10139'}