knitr::opts_chunk$set(echo = TRUE)
directory = "C:/Users/Michael/Dropbox/priv/CUNY/MSDS/201909-Fall/DATA605_Larry/20190901_Week01/"
knitr::opts_knit$set(root.dir = directory)
### Make the output wide enough
options(scipen = 999, digits=6, width=150)
### Load some libraries
library(tidyr)
library(dplyr)##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
##
## Attaching package: 'kableExtra'
## The following object is masked from 'package:dplyr':
##
## group_rows
You can think of vectors representing many dimensions of related information.
For instance, Netflix might store all the ratings a user gives to movies in a vector.
This is clearly a vector of very large dimensions (in the millions) and very sparse as the user might have rated only a few movies.
Similarly, Amazon might store the items purchased by a user in a vector, with each slot or dimension representing a unique product and the value of the slot, the number of such items the user bought.
One task that is frequently done in these settings is to find similarities between users.
And, we can use dot-product between vectors to do just that.
As you know, the dot-product is proportional to the length of two vectors and to the angle between them.
In fact, the dot-product between two vectors, normalized by their lengths is called as the cosine distance and is frequently used in recommendation engines.
## [1] -0.5
\[ u \cdot v = -0.5 \]
Please note that the mathematical notion of the length of a vector is not the same as a computer science definition.
## [1] 0.707107
## [1] 5
\[ \left \| u \right \|= 0.707107 \]
\[ \left \| v \right \|= 5 \]
## [,1]
## [1,] -4.5
## [2,] 9.5
\[ 3u-2v=3 \begin{bmatrix}0.5 \\0.5 \\\end{bmatrix} - 2 \begin{bmatrix}3 \\-4 \\\end{bmatrix} = \begin{bmatrix}-4.5 \\9.5 \\\end{bmatrix} \]
rad2deg <-function(rad) rad/pi * 180
deg2rad <-function(deg) pi*deg / 180
cos_theta = dotproduct_uv / (len_u * len_v)
cos_theta## [1] -0.141421
## [1] 1.71269
## [1] 98.1301
\[ cos \left( \theta _{uv} \right)=\frac{u\cdot v}{\left \| u \right \|\left \| v \right \|} = \frac{ -0.5}{0.707107*5} = -0.141421 \]
\[ cos^{-1}\left( -0.141421 \right ) = 1.712693 \: (in\: radians) = 98.130102 ^{\circ } \: (in\: degrees) \]
Please write a function in R that will take two variables (matrix A & constraint vector b) and solve using elimination. Your function should produce the right answer for the system of equations for any 3-variable, 3-equation system. You donโt have to worry about degenerate cases and can safely assume that the function will only be tested with a system of equations that has a solution. Please note that you do have to worry about zero pivots, though. Please note that you should not use the built-in function solve to solve this system or use matrix inverses. The approach that you should employ is to construct an Upper Triangular Matrix and then back-substitute to get the solution. Alternatively, you can augment the matrix A with vector b and jointly apply the Gauss Jordan elimination procedure.
\[ \begin{bmatrix}1&1&3 \\2&-1&5 \\-1&-2&4 \\\end{bmatrix} \begin{bmatrix}x1 \\x2 \\x3 \\\end{bmatrix} = \begin{bmatrix}1 \\2 \\6 \\\end{bmatrix} \]
MYGaussJordan <- function(A, b){
# A: coefficient matrix of coefficients
# b: right-hand side
rowCount <- nrow(A)
colCount <- ncol(A)
epsilon=1e-7 # checking for zero pivot
determinant <- 1 # keep track of the determinant that has been divided out
pivotList <- rep(0, rowCount) # e.g., (0 0 0)
b <- as.matrix(b) # ensure that b is a matrix (rather than a vector)
Combined <- cbind(A, b) # append the columns of b onto A
i <- 1
j <- 1
while (i <= rowCount && j <= colCount){
while (j <= colCount){
# select column j
thisColumn <- Combined[,j]
# replace the values at or above the diagonal with zeroes
thisColumn[1:rowCount < i] <- 0
# find the maximum pivot in thisColumn at or below current row
whichRow <- which.max(abs(thisColumn)) # which.max gets the index
# of the maximum item in the vector
pivot <- thisColumn[whichRow] # select the element in the column for pivoting
determinant <- determinant*pivot # because the matrix determinant will be
# divided by the pivot
pivotList[i] <- pivot
# check for zero pivot!
if (abs(pivot) <= epsilon) { # check for zero pivot!
j <- j + 1 # skip to the next column,
# because there is a zero here!
next # flow goes back to while (j <= colCount)
}
if (whichRow > i) {
Combined[c(whichRow,i),] <- Combined[c(i,whichRow),] # switch rows
determinant <- -determinant # switching rows negates the determinant
}
Combined[i,] <- Combined[i,] / pivot # multiply row by pivot
for (k in 1:rowCount){
if (k == i) next # skip the diagonal
if (abs(Combined[k, j]) < epsilon) next # there is a zero here, so skip to next k
Combined[k,] <- Combined[k,] - Combined[k, j] * Combined[i,]
}
j <- j + 1
break # quit the inner loop because pivot completed
}
i <- i + 1
}
# move rows filled with zeros to the bottom
whichZeros <- which(apply(Combined[,1:colCount], 1, function(x) max(abs(x)) <= epsilon))
if (length(whichZeros) > 0){
# move rows of all zeros (inconsistent system) to the bottom
Combined <- rbind(Combined[-whichZeros,],
Combined[whichZeros,])
}
# return the combined matrix
Combined
}## [,1] [,2] [,3] [,4]
## [1,] 1 0 0 -1.545455
## [2,] 0 1 0 -0.318182
## [3,] 0 0 1 0.954545
\[ Result_{MYGJ} = \begin{bmatrix}1&0&0&-1.54545454545454 \\0&1&0&-0.318181818181819 \\0&0&1&0.954545454545454 \\\end{bmatrix} \]
## [1] -1.545455 -0.318182 0.954545
## [,1]
## [1,] -1.545455
## [2,] -0.318182
## [3,] 0.954545
\[ x_{MYGJ} = \begin{bmatrix}-1.54545454545454 \\-0.318181818181819 \\0.954545454545454 \\\end{bmatrix} \]
## [,1]
## [1,] 1
## [2,] 2
## [3,] 6
### Check that Ax-b is close to zero (it may differ by a tiny epsilon due to numerical precision)
A %*% xMYGJmat - b## [,1]
## [1,] -0.000000000000000888178
## [2,] 0.000000000000000444089
## [3,] 0.000000000000000000000
\[ \begin{bmatrix}1&1&3 \\2&-1&5 \\-1&-2&4 \\\end{bmatrix} \begin{bmatrix}-1.54545454545454 \\-0.318181818181819 \\0.954545454545454 \\\end{bmatrix} = \begin{bmatrix}0.999999999999999 \\2 \\6 \\\end{bmatrix} \approx \begin{bmatrix}1 \\2 \\6 \\\end{bmatrix} \]
# A is 3x3 coefficient matrix,
# B are the contraints
# function solves for vector x such that Ax=b
library(matlib)##
## Attaching package: 'matlib'
## The following objects are masked from 'package:pracma':
##
## angle, inv
##
## Initial matrix:
## [,1] [,2] [,3] [,4]
## [1,] 1 1 3 1
## [2,] 2 -1 5 2
## [3,] -1 -2 4 6
##
## row: 1
##
## exchange rows 1 and 2
## [,1] [,2] [,3] [,4]
## [1,] 2 -1 5 2
## [2,] 1 1 3 1
## [3,] -1 -2 4 6
##
## multiply row 1 by 0.5
## [,1] [,2] [,3] [,4]
## [1,] 1 -0.5 2.5 1
## [2,] 1 1.0 3.0 1
## [3,] -1 -2.0 4.0 6
##
## subtract row 1 from row 2
## [,1] [,2] [,3] [,4]
## [1,] 1 -0.5 2.5 1
## [2,] 0 1.5 0.5 0
## [3,] -1 -2.0 4.0 6
##
## multiply row 1 by 1 and add to row 3
## [,1] [,2] [,3] [,4]
## [1,] 1 -0.5 2.5 1
## [2,] 0 1.5 0.5 0
## [3,] 0 -2.5 6.5 7
##
## row: 2
##
## exchange rows 2 and 3
## [,1] [,2] [,3] [,4]
## [1,] 1 -0.5 2.5 1
## [2,] 0 -2.5 6.5 7
## [3,] 0 1.5 0.5 0
##
## multiply row 2 by -0.4
## [,1] [,2] [,3] [,4]
## [1,] 1 -0.5 2.5 1.0
## [2,] 0 1.0 -2.6 -2.8
## [3,] 0 1.5 0.5 0.0
##
## multiply row 2 by 0.5 and add to row 1
## [,1] [,2] [,3] [,4]
## [1,] 1 0.0 1.2 -0.4
## [2,] 0 1.0 -2.6 -2.8
## [3,] 0 1.5 0.5 0.0
##
## multiply row 2 by 1.5 and subtract from row 3
## [,1] [,2] [,3] [,4]
## [1,] 1 0 1.2 -0.4
## [2,] 0 1 -2.6 -2.8
## [3,] 0 0 4.4 4.2
##
## row: 3
##
## multiply row 3 by 0.227273
## [,1] [,2] [,3] [,4]
## [1,] 1 0 1.2 -0.400000
## [2,] 0 1 -2.6 -2.800000
## [3,] 0 0 1.0 0.954545
##
## multiply row 3 by 1.2 and subtract from row 1
## [,1] [,2] [,3] [,4]
## [1,] 1 0 0.0 -1.545455
## [2,] 0 1 -2.6 -2.800000
## [3,] 0 0 1.0 0.954545
##
## multiply row 3 by 2.6 and add to row 2
## [,1] [,2] [,3] [,4]
## [1,] 1 0 0 -1.545455
## [2,] 0 1 0 -0.318182
## [3,] 0 0 1 0.954545
## [,1] [,2] [,3] [,4]
## [1,] 1 0 0 -1.545455
## [2,] 0 1 0 -0.318182
## [3,] 0 0 1 0.954545
\[ Result_{GJ} = \begin{bmatrix}1&0&0&-1.54545455 \\0&1&0&-0.31818182 \\0&0&1&0.95454545 \\\end{bmatrix} \]
## [,1]
## [1,] -1.545455
## [2,] -0.318182
## [3,] 0.954545
\[ x_{GJ} = \begin{bmatrix}-1.54545455 \\-0.31818182 \\0.95454545 \\\end{bmatrix} \]
## [,1]
## [1,] 1
## [2,] 2
## [3,] 6
### Check that Ax-b is close to zero (it may differ by a tiny epsilon due to numerical precision)
A %*% xGJmat - b## [,1]
## [1,] -0.00000002
## [2,] -0.00000003
## [3,] -0.00000001
\[ \begin{bmatrix}1&1&3 \\2&-1&5 \\-1&-2&4 \\\end{bmatrix} \begin{bmatrix}-1.54545455 \\-0.31818182 \\0.95454545 \\\end{bmatrix} = \begin{bmatrix}0.99999998 \\1.99999997 \\5.99999999 \\\end{bmatrix} \approx \begin{bmatrix}1 \\2 \\6 \\\end{bmatrix} \]
# A is 3x3 coefficient matrix,
# B are the contraints
# function solves for vector x such that Ax=b
library(pracma)
RowReducedEchelonForm <- function(A, b) {
x = rref(cbind(A,b))
return(x)
}## [,1] [,2] [,3] [,4]
## [1,] 1 0 0 -1.545455
## [2,] 0 1 0 -0.318182
## [3,] 0 0 1 0.954545
\[ Result_{RREF} = \begin{bmatrix}1&0&0&-1.54545454545454 \\0&1&0&-0.318181818181819 \\0&0&1&0.954545454545454 \\\end{bmatrix} \]
## [1] -1.545455 -0.318182 0.954545
## [,1]
## [1,] -1.545455
## [2,] -0.318182
## [3,] 0.954545
\[ x_{RREF} = \begin{bmatrix}-1.54545454545454 \\-0.318181818181819 \\0.954545454545454 \\\end{bmatrix} \]
## [,1]
## [1,] 1
## [2,] 2
## [3,] 6
### Check that Ax-b is close to zero (it may differ by a tiny epsilon due to numerical precision)
A %*% xRREFmat - b## [,1]
## [1,] -0.000000000000000888178
## [2,] 0.000000000000000444089
## [3,] 0.000000000000000000000
\[ \begin{bmatrix}1&1&3 \\2&-1&5 \\-1&-2&4 \\\end{bmatrix} \begin{bmatrix}-1.54545454545454 \\-0.318181818181819 \\0.954545454545454 \\\end{bmatrix} = \begin{bmatrix}0.999999999999999 \\2 \\6 \\\end{bmatrix} \approx \begin{bmatrix}1 \\2 \\6 \\\end{bmatrix} \]