# Installs !pip install --upgrade tf-nightly-2.0-preview # Imports import tensorflow as tf import sys import numpy as np import matplotlib.pyplot as plt import pandas as pd """ If you are running this notebook in Google colab, make sure to upload the helpers.py file to your session before running it, but if you are running this in Binder, then you don't have to worry about it. The helpers.py file will be in the notebook folder in GitHub. """ from helpers import vector_plot, plot_transform # let's create a ones 3x3 rank 2 tensor rank_2_tensor_A = tf.ones([3, 3], name='MatrixA') print("3x3 Rank 2 Tensor A: \n{}\n".format(rank_2_tensor_A)) # let's manually create a 3x3 rank two tensor and specify the data type as float rank_2_tensor_B = tf.constant([[1, 2, 3], [4, 5, 6], [7, 8, 9]], name='MatrixB', dtype=tf.float32) print("3x3 Rank 2 Tensor B: \n{}\n".format(rank_2_tensor_B)) # addition of the two tensors rank_2_tensor_C = tf.add(rank_2_tensor_A, rank_2_tensor_B, name='MatrixC') print("Rank 2 Tensor C with shape={} and elements: \n{}".format(rank_2_tensor_C.shape, rank_2_tensor_C)) # Let's see what happens if the shapes are not the same two_by_three = tf.ones([2, 3]) try: incompatible_tensor = tf.add(two_by_three, rank_2_tensor_B) except: print("""Incompatible shapes to add with two_by_three of shape {0} and 3x3 Rank 2 Tensor B of shape {1} """.format(two_by_three.shape, rank_2_tensor_B.shape)) # Create scalar a, c and Matrix B rank_0_tensor_a = tf.constant(2, name="scalar_a", dtype=tf.float32) rank_2_tensor_B = tf.constant([[1, 2, 3], [4, 5, 6], [7, 8, 9]], name='MatrixB', dtype=tf.float32) rank_0_tensor_c = tf.constant(3, name="scalar_c", dtype=tf.float32) # multiplying aB multiply_scalar = tf.multiply(rank_0_tensor_a, rank_2_tensor_B) # adding aB + c rank_2_tensor_D = tf.add(multiply_scalar, rank_0_tensor_c, name="MatrixD") print("""Original Rank 2 Tensor B: \n{0} \n\nScalar a: {1} Rank 2 Tensor for aB: \n{2} \n\nScalar c: {3} \nRank 2 Tensor D = aB + c: \n{4} """.format(rank_2_tensor_B, rank_0_tensor_a, multiply_scalar, rank_0_tensor_c, rank_2_tensor_D)) # Creating a Matrix E rank_2_tensor_E = tf.constant([[1, 2, 3], [4, 5, 6]]) # Transposing Matrix E transpose_E = tf.transpose(rank_2_tensor_E, name="transposeE") print("""Rank 2 Tensor E of shape: {0} and elements: \n{1}\n Transpose of Rank 2 Tensor E of shape: {2} and elements: \n{3}""".format(rank_2_tensor_E.shape, rank_2_tensor_E, transpose_E.shape, transpose_E)) # Creating a vector b rank_1_tensor_b = tf.constant([[4.], [5.], [6.]]) # Broadcasting a vector b to a matrix A such that it yields a matrix F = A + b rank_2_tensor_F = tf.add(rank_2_tensor_A, rank_1_tensor_b, name="broadcastF") print("""Rank 2 tensor A: \n{0}\n \nRank 1 Tensor b: \n{1} \nRank 2 tensor F = A + b:\n{2}""".format(rank_2_tensor_A, rank_1_tensor_b, rank_2_tensor_F)) # Matrix A and B with shapes (2, 3) and (3, 4) mmv_matrix_A = tf.ones([2, 3], name="matrix_A") mmv_matrix_B = tf.constant([[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]], name="matrix_B", dtype=tf.float32) # Matrix Multiplication: C = AB with C shape (2, 4) matrix_multiply_C = tf.matmul(mmv_matrix_A, mmv_matrix_B, name="matrix_multiply_C") print("""Matrix A: shape {0} \nelements: \n{1} \n\nMatrix B: shape {2} \nelements: \n{3} \nMatrix C: shape {4} \nelements: \n{5}""".format(mmv_matrix_A.shape, mmv_matrix_A, mmv_matrix_B.shape, mmv_matrix_B, matrix_multiply_C.shape, matrix_multiply_C)) """ Note that we use multiply to do element wise matrix multiplication and matmul to do matrix multiplication """ # Creating new Matrix A and B with shapes (3, 3) element_matrix_A = tf.ones([3, 3], name="element_matrix_A") element_matrix_B = tf.constant([[1, 2, 3], [4, 5, 6], [7, 8, 9]], name="element_matrix_B", dtype=tf.float32) # Element wise multiplication of Matrix A and B element_wise_C = tf.multiply(element_matrix_A, element_matrix_B, name="element_wise_C") print("""Matrix A: shape {0} \nelements: \n{1} \n\nMatrix A: shape {2} \nelements: \n{3}\n Matrix C: shape {4} \nelements: \n{5}""".format(element_matrix_A.shape, element_matrix_A, element_matrix_B.shape, element_matrix_B, element_wise_C.shape, element_wise_C)) # Creating Matrix A and B with shapes (3, 3) dot_matrix_A = tf.ones([3, 3], name="dot_matrix_A") dot_matrix_B = tf.constant([[1, 2, 3], [4, 5, 6], [7, 8, 9]], name="dot_matrix_B", dtype=tf.float32) # Dot product of A and B dot_product_C = tf.tensordot(dot_matrix_A, dot_matrix_B, axes=1, name="dot_product_C") print("""Matrix A: shape {0} \nelements: \n{1} \n\nMatrix B: shape {2} \nelements: \n{3}\n Matrix C: shape {4} \nelements: \n{5}""".format(dot_matrix_A.shape, dot_matrix_A, dot_matrix_B.shape, dot_matrix_B, dot_product_C.shape, dot_product_C)) # Common Matrices to check all the matrix Properties matrix_A = tf.constant([[1, 2], [3, 4]], name="matrix_a") matrix_B = tf.constant([[5, 6], [7, 8]], name="matrix_b") matrix_C = tf.constant([[9, 1], [2, 3]], name="matrix_c") # Distributive Property print("Matrix A: \n{} \n\nMatrix B: \n{} \n\nMatrix C: \n{}\n".format(matrix_A, matrix_B, matrix_C)) # AB + AC distributive_RHS = tf.add(tf.matmul(matrix_A, matrix_B), tf.matmul(matrix_A, matrix_C), name="RHS") # A(B+C) distributive_LHS = tf.matmul(matrix_A, (tf.add(matrix_B, matrix_C)), name="LHS") """ Following is another way a conditional statement can be implemented from tensorflow This might not seem very useful now but I want to introduce it here so you can figure out how it works for a simple example. """ # To compare each element in the matrix, you need to reduce it first and check if it's equal predictor = tf.reduce_all(tf.equal(distributive_RHS, distributive_LHS)) # condition to act on if predictor is True def true_print(): print("""Distributive property is valid RHS: AB + AC: \n{} \n\nLHS: A(B+C): \n{}""".format(distributive_RHS, distributive_LHS)) # condition to act on if predictor is False def false_print(): print("""You Broke the Distributive Property of Matrix RHS: AB + AC: \n{} \n\nis NOT Equal to LHS: A(B+C): \n{}""".format(distributive_RHS, distributive_LHS)) tf.cond(predictor, true_print, false_print) # Associative property print("Matrix A: \n{} \n\nMatrix B: \n{} \n\nMatrix C: \n{}\n".format(matrix_A, matrix_B, matrix_C)) # (AB)C associative_RHS = tf.matmul(tf.matmul(matrix_A, matrix_B), matrix_C) # A(BC) associative_LHS = tf.matmul(matrix_A, tf.matmul(matrix_B, matrix_C)) # To compare each element in the matrix, you need to reduce it first and check if it's equal predictor = tf.reduce_all(tf.equal(associative_RHS, associative_LHS)) # condition to act on if predictor is True def true_print(): print("""Associative property is valid RHS: (AB)C: \n{} \n\nLHS: A(BC): \n{}""".format(associative_RHS, associative_LHS)) # condition to act on if predictor is False def false_print(): print("""You Broke the Associative Property of Matrix RHS: (AB)C: \n{} \n\nLHS: A(BC): \n{}""".format(associative_RHS, associative_LHS)) tf.cond(predictor, true_print, false_print) # Matrix multiplication is not commutative print("Matrix A: \n{} \n\nMatrix B: \n{}\n".format(matrix_A, matrix_B)) # Matrix A times B commutative_RHS = tf.matmul(matrix_A, matrix_B) # Matrix B times A commutative_LHS = tf.matmul(matrix_B, matrix_A) predictor = tf.logical_not(tf.reduce_all(tf.equal(commutative_RHS, commutative_LHS))) def true_print(): print("""Matrix Multiplication is not commutative RHS: (AB): \n{} \n\nLHS: (BA): \n{}""".format(commutative_RHS, commutative_LHS)) def false_print(): print("""You made Matrix Multiplication commutative RHS: (AB): \n{} \n\nLHS: (BA): \n{}""".format(commutative_RHS, commutative_LHS)) tf.cond(predictor, true_print, false_print) # Transpose of a matrix print("Matrix A: \n{} \n\nMatrix B: \n{}\n".format(matrix_A, matrix_B)) # Tensorflow transpose function transpose_RHS = tf.transpose(tf.matmul(matrix_A, matrix_B)) # If you are doing matrix multiplication tf.matmul has a parameter to take the tranpose and then matrix multiply transpose_LHS = tf.matmul(matrix_B, matrix_A, transpose_a=True, transpose_b=True) predictor = tf.reduce_all(tf.equal(transpose_RHS, transpose_LHS)) def true_print(): print("""Transpose property is valid RHS: (AB):^T \n{} \n\nLHS: (B^T A^T): \n{}""".format(transpose_RHS, transpose_LHS)) def false_print(): print("""You Broke the Transpose Property of Matrix RHS: (AB):^T \n{} \n\nLHS: (B^T A^T): \n{}""".format(transpose_RHS, transpose_LHS)) tf.cond(predictor, true_print, false_print) # let's create a identity matrix I identity_matrix_I = tf.eye(3, 3, dtype=tf.float32, name='IdentityMatrixI') print("Identity matrix I: \n{}\n".format(identity_matrix_I)) # let's create a 3x1 vector x iim_vector_x = tf.constant([[4], [5], [6]], name='Vector_x', dtype=tf.float32) print("Vector x: \n{}\n".format(iim_vector_x)) # Ix will result in x iim_matrix_C = tf.matmul(identity_matrix_I, iim_vector_x, name='MatrixC') print("Matrix C from Ix: \n{}".format(iim_matrix_C)) iim_matrix_A = tf.constant([[2, 3], [2, 2]], name='MatrixA', dtype=tf.float32) try: # Tensorflow function to take the inverse inverse_matrix_A = tf.linalg.inv(iim_matrix_A) # Creating a identity matrix using tf.eye identity_matrix = tf.eye(2, 2, dtype=tf.float32, name="identity") iim_RHS = identity_matrix iim_LHS = tf.matmul(inverse_matrix_A, iim_matrix_A, name="LHS") predictor = tf.reduce_all(tf.equal(iim_RHS, iim_LHS)) def true_print(): print("""A^-1 times A equals the Identity Matrix Matrix A: \n{0} \n\nInverse of Matrix A: \n{1} \n\nRHS: I: \n{2} \n\nLHS: A^(-1) A: \n{3}""".format(iim_matrix_A, inverse_matrix_A, iim_RHS, iim_LHS)) def false_print(): print("Condition Failed") tf.cond(predictor, true_print, false_print) except: print("""A^-1 doesnt exist Matrix A: \n{} \n\nInverse of Matrix A: \n{} \n\nRHS: I: \n{} \nLHS: (A^(-1) A): \n{}""".format(iim_matrix_A, inverse_matrix_A, iim_RHS, iim_LHS)) # The above system of equation can be written in the matrix format as: sys_matrix_A = tf.constant([[2, 3], [4, 9]], dtype=tf.float32) sys_vector_B = tf.constant([[6], [15]], dtype=tf.float32) print("Matrix A: \n{} \n\nVector B: \n{}\n".format(sys_matrix_A, sys_vector_B)) # now to solve for x: x = A^(-1)b sys_x = tf.matmul(tf.linalg.inv(sys_matrix_A), sys_vector_B) print("Vector x is: \n{} \nWhere x = {} and y = {}".format(sys_x, sys_x[0], sys_x[1])) # Lets start by finding for some value of A and x, what the result of x is lds_matrix_A = tf.constant([[3, 1], [1, 2]], name='MatrixA', dtype=tf.float32) lds_vector_x = tf.constant([2, 3], name='vectorX', dtype=tf.float32) lds_b = tf.multiply(lds_matrix_A, lds_vector_x, name="b") # Now let's see if an inverse for Matrix A exists try: inverse_A = tf.linalg.inv(lds_matrix_A) print("Matrix A is successfully inverted: \n{}".format(inverse_A)) except: print("Inverse of Matrix A: \n{} \ndoesn't exist. ".format(lds_matrix_A)) # Let's find the value of x using x = A^(-1)b verify_x = tf.matmul(inverse_A, lds_b, name="verifyX") predictor = tf.equal(lds_vector_x[0], verify_x[0][0]) and tf.equal(lds_vector_x[1], verify_x[1][1]) def true_print(): print("""\nThe two x values match, we proved that if a matrix A is invertible Then x = A^T b, \nwhere x: {}, \n\nA^T: \n{}, \n\nb: \n{}""".format(lds_vector_x, inverse_A, lds_b)) def false_print(): print("""\nThe two x values don't match. Vector x: {} \n\nA^(-1)b: \n{}""".format(lds_vector_x, verify_x)) tf.cond(predictor, true_print, false_print) # Euclidean distance between square root(3^2 + 4^2) calculated by setting ord='euclidean' dist_euclidean = tf.norm([3., 4.], ord='euclidean') print("Euclidean Distance: {}".format(dist_euclidean)) # Size of the vector [3., 4.] vector_size = tf.multiply(tf.transpose([3., 4.]), [3., 4.]) print("Vector Size: {}".format(vector_size)) def SE(x,y,intc,beta): return (1./len(x))*(0.5)*sum(y - beta * x - intc)**2 def L1(intc,beta,lam): return lam*(tf.abs(intc) + tf.abs(beta)) def L2(intc,beta,lam): return lam*(intc**2 + beta**2) N = 100 x = np.random.randn(N) y = 2 * x + np.random.randn(N) beta_N = 100 beta = tf.linspace(-100., 100., beta_N) intc = 0.0 SE_array = np.array([SE(x,y,intc,i) for i in beta]) L1_array = np.array([L1(intc,i,lam=30) for i in beta]) L2_array = np.array([L2(intc,i,lam=1) for i in beta]) fig1 = plt.figure() ax1 = fig1.add_subplot(1,1,1) ax1.plot(beta, SE_array, label='Squared L2 Norm') ax1.plot(beta, L1_array, label='L1 norm') ax1.plot(beta, L2_array, label='L2 norm') plt.rc_context({'axes.edgecolor':'orange', 'xtick.color':'red', 'ytick.color':'red'}) plt.title('The graph of each of the norms', color='w') plt.legend() fig1.show() n_matrix_A = tf.constant([[2, -1, 5], [0, 2, 1], [3, 1, 1]], name="matrix_A", dtype=tf.float32) # Frobenius norm for matrix calculated by setting ord='fro' frobenius_norm = tf.norm(n_matrix_A, ord='fro', axis=(0, 1)) print("Frobenius norm: {}".format(frobenius_norm)) # for x(0, 2) and y(2, 2) cos theta = 45 degrees n_vector_x = tf.constant([[0], [2]], dtype=tf.float32, name="vectorX") n_vector_y = tf.constant([[2], [2]], dtype=tf.float32, name="vectorY") # Due to pi being in, we won't get an exact value so we are rounding our final value prod_RHS = tf.round(tf.multiply(tf.multiply(tf.norm(n_vector_x), tf.norm(n_vector_y)), tf.cos(np.pi/4))) prod_LHS = tf.tensordot(tf.transpose(n_vector_x), n_vector_y, axes=1, name="LHS") predictor = tf.equal(prod_RHS, prod_LHS) def true_print(): print("""Dot Product can be rewritten in terms of norms, where \n RHS: {} \nLHS: {}""".format(prod_RHS, prod_LHS)) def false_print(): print("""Dot Product can not be rewritten in terms of norms, where \n RHS: {} \nLHS: {}""".format(prod_RHS, prod_LHS)) tf.cond(predictor, true_print, false_print) origin=[0,0] plt.rc_context({'axes.edgecolor':'orange', 'xtick.color':'red', 'ytick.color':'red'}) plt.xlim(-2, 10) plt.ylim(-1, 10) plt.axvline(x=0, color='grey', zorder=0) plt.axhline(y=0, color='grey', zorder=0) plt.text(-1, 2, r'$\vec{x}$', size=18) plt.text(2, 1.5, r'$\vec{y}$', size=18) plt.quiver(*origin, n_vector_x, n_vector_y, color=['#FF9A13','#1190FF'], scale=8) plt.show() # create vector v and x sp_vector_v = tf.random.uniform([5], minval=0, maxval=10, dtype = tf.int32, seed = 0, name="vector_v") sp_vector_x = tf.random.uniform([5], minval=0, maxval=10, dtype = tf.int32, seed = 0, name="vector_x") print("Vector v: {} \nVector x: {}\n".format(sp_vector_v, sp_vector_x)) # RHS diagonal vector v dot diagonal vector x. The linalg.diag converts a vector to a diagonal matrix sp_RHS = tf.tensordot(tf.linalg.diag(sp_vector_v), tf.linalg.diag(sp_vector_x), axes=1) # LHS diag(v)x sp_LHS = tf.multiply(tf.linalg.diag(sp_vector_v), sp_vector_x) predictor = tf.reduce_all(tf.equal(sp_RHS, sp_LHS)) def true_print(): print("Diagonal of v times x: \n{} \n\nis equal to vector v dot vector x: \n{}".format(sp_RHS, sp_LHS)) def false_print(): print("Diagonal of v times x: \n{} \n\nis NOT equal to vector v dot vector x: \n{}".format(sp_RHS, sp_LHS)) tf.cond(predictor, true_print, false_print) try: # try creating a vector_v with zero elements and see what happens d_vector_v = tf.random.uniform([5], minval=1, maxval=10, dtype = tf.float32, seed = 0, name="vector_v") print("Vector v: {}".format(d_vector_v)) # linalg.diag converts a vector to a diagonal matrix diag_RHS = tf.linalg.diag(tf.transpose(1. / d_vector_v)) # we convert the vector to diagonal matrix and take it's inverse inv_LHS = tf.linalg.inv(tf.linalg.diag(d_vector_v)) predictor = tf.reduce_all(tf.equal(diag_RHS, inv_LHS)) def true_print(): print("The inverse of LHS: \n{} \n\nMatch the inverse of RHS: \n{}".format(diag_RHS, inv_LHS)) def false_print(): print("The inverse of LHS: \n{} \n\n Does not match the inverse of RHS: \n{}".format(diag_RHS, inv_LHS)) tf.cond(predictor, true_print, false_print) except: print("The inverse exists only if every diagonal is nonzero, your vector looks: \n{}".format(d_vector_v)) # create a symmetric matrix sp_matrix_A = tf.constant([[0, 1, 3], [1, 2, 4], [3, 4, 5]], name="matrix_a", dtype=tf.int32) # get the transpose of matrix A sp_transpose_a = tf.transpose(sp_matrix_A) predictor = tf.reduce_all(tf.equal(sp_matrix_A, sp_transpose_a)) def true_print(): print("Matrix A: \n{} \n\nMatches the the transpose of Matrix A: \n{}".format(sp_matrix_A, sp_transpose_a)) def false_print(): print("Matrix A: \n{} \n\nDoes Not match the the transpose of Matrix A: \n{}".format(sp_matrix_A, sp_transpose_a)) tf.cond(predictor, true_print, false_print) # Lets create two vectors ortho_vector_x = tf.constant([2, 2], dtype=tf.float32, name="vector_x") ortho_vector_y = tf.constant([2, -2], dtype=tf.float32, name="vector_y") print("Vector x: {} \nVector y: {}\n".format(ortho_vector_x, ortho_vector_y)) # lets verify if x transpose dot y is zero ortho_LHS = tf.tensordot(tf.transpose(ortho_vector_x), ortho_vector_y, axes=1) print("X transpose times y = {}\n".format(ortho_LHS)) # let's see what their norms are ortho_norm_x = tf.norm(ortho_vector_x) ortho_norm_y = tf.norm(ortho_vector_y) print("Norm x: {} \nNorm y: {}\n".format(ortho_norm_x, ortho_norm_y)) # If they have non zero norm, let's see what angle they are to each other if tf.logical_and(ortho_norm_x > 0, ortho_norm_y > 0): # from the equation cos theta = (x dot y)/(norm of x times norm y) cosine_angle = (tf.divide(tf.tensordot(ortho_vector_x, ortho_vector_y, axes=1), tf.multiply(ortho_norm_x, ortho_norm_y))) print("Angle between vector x and vector y is: {} degrees".format(tf.acos(cosine_angle) * 180 /np.pi)) origin=[0,0] plt.rc_context({'axes.edgecolor':'orange', 'xtick.color':'red', 'ytick.color':'red'}) plt.xlim(-1, 10) plt.ylim(-10, 10) plt.axvline(x=0, color='grey', zorder=0) plt.axhline(y=0, color='grey', zorder=0) plt.text(1, 4, r'$\vec{x}$', size=18) plt.text(1, -6, r'$\vec{y}$', size=18) plt.quiver(*origin, ortho_vector_x, ortho_vector_y, color=['#FF9A13','#1190FF'], scale=8) plt.show() # Lets use sine and cosine to create orthogonal matrix ortho_matrix_A = tf.Variable([[tf.cos(.5), -tf.sin(.5)], [tf.sin(.5), tf.cos(.5)]], name="matrixA") print("Matrix A: \n{}\n".format(ortho_matrix_A)) # extract columns from the matrix to verify if they are orthogonal col_0 = tf.reshape(ortho_matrix_A[:, 0], [2, 1]) col_1 = tf.reshape(ortho_matrix_A[:, 1], [2, 1]) row_0 = tf.reshape(ortho_matrix_A[0, :], [2, 1]) row_1 = tf.reshape(ortho_matrix_A[1, :], [2, 1]) # Verifying if the columns are orthogonal ortho_column = tf.tensordot(tf.transpose(col_0), col_1, axes=2) print("Columns are orthogonal: {}".format(ortho_column)) plt.rc_context({'axes.edgecolor':'orange', 'xtick.color':'red', 'ytick.color':'red'}) origin = [0, 0] plt.xlim(-2, 2) plt.ylim(-3, 4) plt.axvline(x=0, color='grey', zorder=0) plt.axhline(y=0, color='grey', zorder=0) plt.text(0, 2, r'$\vec{col_0}$', size=18) plt.text(0.5, -2, r'$\vec{col_1}$', size=18) plt.quiver(*origin, col_0, col_1, color=['#FF9A13','#FF9A13'], scale=3) # Verifying if the rows are orthogonal ortho_row = tf.tensordot(tf.transpose(row_0), row_1, axes=2) print("Rows are orthogonal: {}\n".format(ortho_row)) plt.text(-1, 2, r'$\vec{row_0}$', size=18) plt.text(1, 0.5, r'$\vec{row_1}$', size=18) plt.quiver(*origin, row_0, row_1, color=['r','r'], scale=3) plt.show() # inverse of matrix A ortho_inverse_A = tf.linalg.inv(ortho_matrix_A) # Transpose of matrix A ortho_transpose_A = tf.transpose(ortho_matrix_A) predictor = tf.reduce_all(tf.equal(ortho_inverse_A, ortho_transpose_A)) def true_print(): print("Inverse of Matrix A: \n{} \n\nEquals the transpose of Matrix A: \n{}".format(ortho_inverse_A, ortho_transpose_A)) def false_print(): print("Inverse of Matrix A: \n{} \n\nDoes not equal the transpose of Matrix A: \n{}".format(ortho_inverse_A, ortho_transpose_A)) tf.cond(predictor, true_print, false_print) # Let's see how we can compute the eigen vectors and values from a matrix e_matrix_A = tf.random.uniform([2, 2], minval=3, maxval=10, dtype=tf.float32, name="matrixA") print("Matrix A: \n{}\n".format(e_matrix_A)) # Calculating the eigen values and vectors using tf.linalg.eigh, if you only want the values you can use eigvalsh eigen_values_A, eigen_vectors_A = tf.linalg.eigh(e_matrix_A) print("Eigen Vectors: \n{} \n\nEigen Values: \n{}\n".format(eigen_vectors_A, eigen_values_A)) # Now lets plot our Matrix with the Eigen vector and see how it looks Av = tf.tensordot(e_matrix_A, eigen_vectors_A, axes=0) vector_plot([tf.reshape(Av, [-1]), tf.reshape(eigen_vectors_A, [-1])], 10, 10) # Lets us multiply our eigen vector by a random value s and plot the above graph again to see the rescaling sv = tf.multiply(5, eigen_vectors_A) vector_plot([tf.reshape(Av, [-1]), tf.reshape(sv, [-1])], 10, 10) # Creating a matrix A to find it's decomposition eig_matrix_A = tf.constant([[5, 1], [3, 3]], dtype=tf.float32) new_eigen_values_A, new_eigen_vectors_A = tf.linalg.eigh(eig_matrix_A) print("Eigen Values of Matrix A: {} \n\nEigen Vector of Matrix A: \n{}\n".format(new_eigen_values_A, new_eigen_vectors_A)) # calculate the diag(lamda) diag_lambda = tf.linalg.diag(new_eigen_values_A) print("Diagonal of Lambda: \n{}\n".format(diag_lambda)) # Find the eigendecomposition of matrix A decomp_A = tf.tensordot(tf.tensordot(eigen_vectors_A, diag_lambda, axes=1), tf.linalg.inv(new_eigen_vectors_A), axes=1) print("The decomposition Matrix A: \n{}".format(decomp_A)) # In section 2.6 we manually created a matrix to verify if it is symmetric, but what if we don't know the exact values and want to create a random symmetric matrix new_matrix_A = tf.Variable(tf.random.uniform([2,2], minval=1, maxval=10, dtype=tf.float32)) # to create an upper triangular matrix from a square one X_upper = tf.linalg.band_part(new_matrix_A, 0, -1) sym_matrix_A = tf.multiply(0.5, (X_upper + tf.transpose(X_upper))) print("Symmetric Matrix A: \n{}\n".format(sym_matrix_A)) # create orthogonal matrix Q from eigen vectors of A eigen_values_Q, eigen_vectors_Q = tf.linalg.eigh(sym_matrix_A) print("Matrix Q: \n{}\n".format(eigen_vectors_Q)) # putting eigen values in a diagonal matrix new_diag_lambda = tf.linalg.diag(eigen_values_Q) print("Matrix Lambda: \n{}\n".format(new_diag_lambda)) sym_RHS = tf.tensordot(tf.tensordot(eigen_vectors_Q, new_diag_lambda, axes=1), tf.transpose(eigen_vectors_Q), axes=1) predictor = tf.reduce_all(tf.equal(tf.round(sym_RHS), tf.round(sym_matrix_A))) def true_print(): print("It WORKS. \nRHS: \n{} \n\nLHS: \n{}".format(sym_RHS, sym_matrix_A)) def false_print(): print("Condition FAILED. \nRHS: \n{} \n\nLHS: \n{}".format(sym_RHS, sym_matrix_A)) tf.cond(predictor, true_print, false_print) # mxn matrix A svd_matrix_A = tf.constant([[2, 3], [4, 5], [6, 7]], dtype=tf.float32) print("Matrix A: \n{}\n".format(svd_matrix_A)) # Using tf.linalg.svd to calculate the singular value decomposition where d: Matrix D, u: Matrix U and v: Matrix V d, u, v = tf.linalg.svd(svd_matrix_A, full_matrices=True, compute_uv=True) print("Diagonal D: \n{} \n\nMatrix U: \n{} \n\nMatrix V^T: \n{}".format(d, u, v)) # Lets see if we can bring back the original matrix from the values we have # mxm orthogonal matrix U svd_matrix_U = tf.constant([[0.30449855, -0.86058956, 0.40824753], [0.54340035, -0.19506174, -0.81649673], [0.78230214, 0.47046405, 0.40824872]]) print("Orthogonal Matrix U: \n{}\n".format(svd_matrix_U)) # mxn diagonal matrix D svd_matrix_D = tf.constant([[11.782492, 0], [0, 0.41578525], [0, 0]], dtype=tf.float32) print("Diagonal Matrix D: \n{}\n".format(svd_matrix_D)) # nxn transpose of matrix V svd_matrix_V_trans = tf.constant([[0.63453555, 0.7728936], [0.7728936, -0.63453555]], dtype=tf.float32) print("Transpose Matrix V: \n{}\n".format(svd_matrix_V_trans)) # UDV(^T) svd_RHS = tf.tensordot(tf.tensordot(svd_matrix_U, svd_matrix_D, axes=1), svd_matrix_V_trans, axes=1) predictor = tf.reduce_all(tf.equal(tf.round(svd_RHS), svd_matrix_A)) def true_print(): print("It WORKS. \nRHS: \n{} \n\nLHS: \n{}".format(tf.round(svd_RHS), svd_matrix_A)) def false_print(): print("Condition FAILED. \nRHS: \n{} \n\nLHS: \n{}".format(tf.round(svd_RHS), svd_matrix_A)) tf.cond(predictor, true_print, false_print) # Let's define a unit square svd_square = tf.constant([[0, 0, 1, 1],[0, 1, 1, 0]], dtype=tf.float32) # a new 2x2 matrix svd_new_matrix = tf.constant([[1, 1.5], [0, 1]]) # SVD for the new matrix new_d, new_u, new_v = tf.linalg.svd(svd_new_matrix, full_matrices=True, compute_uv=True) # lets' change d into a diagonal matrix new_d_marix = tf.linalg.diag(new_d) # Rotation: V^T for a unit square plot_transform(svd_square, tf.tensordot(new_v, svd_square, axes=1), "$Square$", "$V^T \cdot Square$", "Rotation", axis=[-0.5, 3.5 , -1.5, 1.5]) plt.show() # Scaling and Projecting: DV^(T) plot_transform(tf.tensordot(new_v, svd_square, axes=1), tf.tensordot(new_d_marix, tf.tensordot(new_v, svd_square, axes=1), axes=1), "$V^T \cdot Square$", "$D \cdot V^T \cdot Square$", "Scaling and Projecting", axis=[-0.5, 3.5 , -1.5, 1.5]) plt.show() # Second Rotation: UDV^(T) trans_1 = tf.tensordot(tf.tensordot(new_d_marix, new_v, axes=1), svd_square, axes=1) trans_2 = tf.tensordot(tf.tensordot(tf.tensordot(new_u, new_d_marix, axes=1), new_v, axes=1), svd_square, axes=1) plot_transform(trans_1, trans_2,"$U \cdot D \cdot V^T \cdot Square$", "$D \cdot V^T \cdot Square$", "Second Rotation", color=['#1190FF', '#FF9A13'], axis=[-0.5, 3.5 , -1.5, 1.5]) plt.show() # Matrix A mpp_matrix_A = tf.random.uniform([3, 2], minval=1, maxval=10, dtype=tf.float32) print("Matrix A: \n{}\n".format(mpp_matrix_A)) # Singular Value decomposition of matrix A mpp_d, mpp_u, mpp_v = tf.linalg.svd(mpp_matrix_A, full_matrices=True, compute_uv=True) print("Matrix U: \n{} \n\nMatrix V: \n{}\n".format(mpp_u, mpp_v)) # pseudo inverse of matrix D d_plus = tf.concat([tf.transpose(tf.linalg.diag(tf.math.reciprocal(mpp_d))), tf.zeros([2, 1])], axis=1) print("D plus: \n{}\n".format(d_plus)) # moore-penrose pseudoinverse of matrix A matrix_A_star = tf.matmul(tf.matmul(mpp_v, d_plus, transpose_a=True), mpp_u, transpose_b=True) print("The Moore-Penrose pseudoinverse of Matrix A: \n{}".format(matrix_A_star)) mpp_vector_y = tf.constant([[2], [3], [4]], dtype=tf.float32) print("Vector y: \n{}\n".format(mpp_vector_y)) mpp_vector_x = tf.matmul(matrix_A_star, mpp_vector_y) print("Vector x: \n{}".format(mpp_vector_x)) # random 3x3 matrix A to_matrix_A = tf.random.uniform([3, 3], minval=0, maxval=10, dtype=tf.float32) # trace of matrix A using tf.linalg.trace trace_matrix_A = tf.linalg.trace(to_matrix_A) print("Trace of Matrix A: \n{} \nis: {}".format(to_matrix_A, trace_matrix_A)) # Frobenius Norm of A frobenius_A = tf.norm(to_matrix_A) # sqrt(Tr(A times A^T)) trace_rhs = tf.sqrt(tf.linalg.trace(tf.matmul(to_matrix_A, to_matrix_A, transpose_b=True))) predictor = tf.equal(tf.round(frobenius_A), tf.round(trace_rhs)) def true_print(): print("It WORKS. \nRHS: {} \nLHS: {}".format(frobenius_A, trace_rhs)) def false_print(): print("Condition FAILED. \nRHS: {} \nLHS: {}".format(frobenius_A, trace_rhs)) tf.cond(predictor, true_print, false_print) # Transpose of Matrix A trans_matrix_A = tf.transpose(to_matrix_A) #Trace of the transpose Matrix A trace_trans_A = tf.linalg.trace(trans_matrix_A) predictor = tf.equal(trace_matrix_A, trace_trans_A) def true_print(): print("It WORKS. \nRHS: {} \nLHS: {}".format(trace_matrix_A, trace_trans_A)) def false_print(): print("Condition FAILED. \nRHS: {} \nLHS: {}".format(trace_matrix_A, trace_trans_A)) tf.cond(predictor, true_print, false_print) # random 3x3 matrix B and matrix C to_matrix_B = tf.random.uniform([3, 3], minval=0, maxval=10, dtype=tf.float32) to_matrix_C = tf.random.uniform([3, 3], minval=0, maxval=10, dtype=tf.float32) # ABC abc = tf.tensordot((tf.tensordot(to_matrix_A, to_matrix_B, axes=1)), to_matrix_C, axes=1) # CAB cab = tf.tensordot((tf.tensordot(to_matrix_C, to_matrix_A, axes=1)), to_matrix_B, axes=1) # BCA bca = tf.tensordot((tf.tensordot(to_matrix_B, to_matrix_C, axes=1)), to_matrix_A, axes=1) # trace of matrix ABC, CAB and matrix BCA trace_matrix_abc = tf.linalg.trace(abc) trace_matrix_cab = tf.linalg.trace(cab) trace_matrix_bca = tf.linalg.trace(bca) predictor = tf.equal(tf.round(trace_matrix_abc), tf.round(trace_matrix_cab)) and tf.equal(tf.round(trace_matrix_cab), tf.round(trace_matrix_bca)) def true_print(): print("It WORKS. \nABC: {} \nCAB: {} \nBCA: {}".format(trace_matrix_abc, trace_matrix_cab, trace_matrix_bca)) def false_print(): print("Condition FAILED. \nABC: {} \nCAB: {} \nBCA: {}".format(trace_matrix_abc, trace_matrix_cab, trace_matrix_bca)) tf.cond(predictor, true_print, false_print) # mxn matrix A to_new_matrix_A = tf.random.uniform([3, 2], minval=0, maxval=10, dtype=tf.float32) print(" 3x2 Matrix A: \n{}\n".format(to_new_matrix_A)) # mxn matrix B to_new_matrix_B = tf.random.uniform([2, 3], minval=0, maxval=10, dtype=tf.float32) print(" 3x2 Matrix B: \n{}\n".format(to_new_matrix_B)) # trace of matrix AB and BA ab = tf.linalg.trace(tf.matmul(to_new_matrix_A, to_new_matrix_B)) ba = tf.linalg.trace(tf.matmul(to_new_matrix_B, to_new_matrix_A)) predictor = tf.equal(tf.round(ab), tf.round(ba)) def true_print(): print("It WORKS. \nAB: {} \nBA: {}".format(ab, ba)) def false_print(): print("Condition FAILED. \nAB: {} \nBA: {}".format(ab, ba)) tf.cond(predictor, true_print, false_print) # calculate det of a matrix det_matrix_A = tf.constant([[3,1], [0,3]], dtype=tf.float32) det_A = tf.linalg.det(det_matrix_A) print("Matrix A: \n{} \nDeterminant of Matrix A: {}".format(det_matrix_A, det_A)) vector_plot(det_matrix_A, 5, 5) # Let's find the eigen values of matrix A d_eigen_values = tf.linalg.eigvalsh(det_matrix_A) eigvalsh_product = tf.multiply(d_eigen_values[0], d_eigen_values[1]) # lets validate if the product of the eigen values is equal to the determinant predictor = tf.equal(eigvalsh_product, det_A) def true_print(): print("It WORKS. \nRHS: \n{} \n\nLHS: \n{}".format(eigvalsh_product, det_A)) def false_print(): print("Condition FAILED. \nRHS: \n{} \n\nLHS: \n{}".format(eigvalsh_product, det_A)) tf.cond(predictor, true_print, false_print) # If you see the following plot, you can see the vectors are expanded vector_plot(tf.multiply(tf.abs(det_A), det_matrix_A), 50, 50) # To start working with PCA, let's start by creating a 2D data set x_data = tf.multiply(5, tf.random.uniform([100], minval=0, maxval=100, dtype = tf.float32, seed = 0)) y_data = tf.multiply(2, x_data) + 1 + tf.random.uniform([100], minval=0, maxval=100, dtype = tf.float32, seed = 0) X = tf.stack([x_data, y_data], axis=1) plt.rc_context({'axes.edgecolor':'orange', 'xtick.color':'red', 'ytick.color':'red'}) plt.plot(X[:,0], X[:,1], '+', color='b') plt.grid() def normalize(data): # creates a copy of data X = tf.identity(data) # calculates the mean X -=tf.reduce_mean(data, axis=0) return X normalized_data = normalize(X) plt.plot(normalized_data[:,0], normalized_data[:,1], '+', color='b') plt.grid() # Finding the Eigne Values and Vectors for the data eigen_values, eigen_vectors = tf.linalg.eigh(tf.tensordot(tf.transpose(normalized_data), normalized_data, axes=1)) print("Eigen Vectors: \n{} \nEigen Values: \n{}".format(eigen_vectors, eigen_values)) X_new = tf.tensordot(tf.transpose(eigen_vectors), tf.transpose(normalized_data), axes=1) plt.plot(X_new[0, :], X_new[1, :], '+', color='b') plt.xlim(-500, 500) plt.ylim(-700, 700) plt.grid()