From 9ca536bc7209fb1b422a2d5615fa745178f2918c Mon Sep 17 00:00:00 2001 From: "Eric W. Wallace" Date: Sat, 16 Aug 2014 23:28:23 -0400 Subject: [PATCH] initial commit, should satisfy all objectives --- README.md | 12 +++++++ cachematrix.R | 99 ++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 106 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7a8c502a4be..a6feeb62535 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ +# Week 3, Programming Assignment 2 + +## Assignment Details + ### Introduction This second programming assignment will require you to write an R @@ -103,3 +107,11 @@ In order to complete this assignment, you must do the following: ### Grading This assignment will be graded via peer assessment. + +## My Comments + +My solution here is a pretty tight match with the instructor's sample code, nothing more complicated or exciting than that. + +However, I've added a testCacheSolve() method to put the code through the paces to confirm it's working as expected. + +*—Eric Wallace, 16 August 2014* \ No newline at end of file diff --git a/cachematrix.R b/cachematrix.R index a50be65aa44..1a164b16d16 100644 --- a/cachematrix.R +++ b/cachematrix.R @@ -1,15 +1,104 @@ -## Put comments here that give an overall description of what your -## functions do +## Since matrix inversion can be a lengthy computation, these functions are speedier +## if you end up needing to calculate the same inverstion again, because they cache +## the result from the earlier calculation. The code is merely tweaked from the +## instructor's example of a similar caching closure. -## Write a short comment describing this function + +## Given a matrix, makeCacheMatrix() creates a speical matrix object which also +## stores its inverse after the first time you call cacheSolve() on it. (Thanks +## to the magic of lexical scoping this function acts as a closure.) The function +## returns a list object with with getters & setters for the matrix and its inverse. makeCacheMatrix <- function(x = matrix()) { + inv <- NULL + + set <- function(y) { + x <<- y # remember the matrix + inv <<- NULL # erase any previously remembered inverse + } + get <- function() x + setinverse <- function(solve) inv <<- solve + getinverse <- function() inv + + # return a list with getter and setter methods + list(set = set, get = get, + setinverse = setinverse, + getinverse = getinverse) } -## Write a short comment describing this function +## Given an invertible matrix 'x' in the form of a makeCacheMatrix() object, +## cacheSolve() will return its inverse. If it has been called before for this +## same matrix, then it will return very quickly because it retrieves the cached +## value instead of calculating it again. cacheSolve <- function(x, ...) { - ## Return a matrix that is the inverse of 'x' + # check if x has a cached inverse + inv <- x$getinv() + if(!is.null(inv)) { + # yup, we got a cached one, so simply return it + message("(Fetching cached data)") + return(inv) + } + # nope, we haven't solved this yet, so solve it now + data <- x$get() + inv <- solve(data, ...) + # ...and cache the result in x + x$setinverse(inv) + inv } + + +## testCacheSolve() tests the makeCacheMatrix() and cacheSolve() functions by +## using a sample matrix of random numbers, solving it for the inverse while +## timing the calculation, then solving yet again and timing to confirm that the +## cached value was returned more quickly. + +testCacheSolve <- function(n=2000) { + print("Testing the cached matrix inverse functions...") + + # seed random off current time + t <- as.numeric(Sys.time()) + set.seed((t - floor(t)) * 1e8) + + # generate matrix of randoms + vec <- runif(n*n,1,10) # random uniform distribution, low chance of degenerate + mtx <- matrix(vec,nrow=n,ncol=n) + + # make it cacheable + mcached <- makeCacheMatrix(mtx) + + # solve for inverse while timing + time1 <- system.time( answer1 <- cacheSolve(mcached) ) + print(paste("Initial call:", round(time1[[3]],4), "seconds.")) + + # solve again while timing + time2 <- system.time( answer2 <- cacheSolve(mcached) ) + print(paste("Second call:", round(time2[[3]],4), "seconds.")) + + # test if answer really is the inverse (matrix * inverse = identity) + confirm <- identical( round(mtx %*% answer1, 1), diag(n) ) + if (confirm) { + message("SUCCESS: Response is the inverse matrix.") + } else { + message("FAIL: Response doesn't fit the inverse!") + } + + # ensure same answer given both times + if (identical(answer1, answer2)) { + message("SUCCESS: Same answer given each time.") + } else { + message("FAIL: Answers were not equal!") + } + + # calculate and display time difference + difference <- time1 - time2 + if (difference[3] > 0) { + message("SUCCESS: Cached response was ", round(difference[3],4), " seconds faster.") + } else { + message("FAIL: Cached reponse was not faster!") + } + + invisible(NULL) +} \ No newline at end of file