逻辑缓存r中矩阵的逆矩阵

时间:2017-09-07 17:44:02

标签: r

这实际上不是问题,而是我无法理解下面代码的逻辑,请你帮助我理解这段代码的逻辑

makecachematrix<- function(x = matrix){
    inv <- NULL
    set <- function(y){
        x <<- y
        inv <<- NULL
    }
    get <- function(){
        x
    }
    setinv <- function(inverse){
        inv <<- inverse
    }
    getinv <- function(){
        inv
    }
    list(set = set, get = get, setinv = setinv, getinv = getinv)
}

cachesolve <- function(x,...){
    inv <- x$getinv()
    if(!is.null(inv)){
       message("getting cached data")
       return(inv)
     }
    mat.data <- x$get()
    inv <- solve(mat.data, ...)
    x$setinv(inv)
    return(inv)
}

test <- function(mat){
     temp <- makecachematrix(mat)
     st <- Sys.time()
     cachesolve(temp)
     et <- Sys.time()
     TimeTaken <- st - et
     return(TimeTaken)

     st <- Sys.time()
     cachesolve(temp)
     et <- Sys.time()
     TimeTaken <- st - et
     return(TimeTaken)

}

set.seed(101)
r <- rnorm(1000000)
mat1 <- matrix(r, 1000, 1000)
test(mat1)

从这段代码我可以理解它是缓存矩阵的逆矩阵以便重用它但我无法理解这个脚本的基本逻辑。

很抱歉,如果这是一个愚蠢的问题,因为我是R的初学者,所以请帮帮我 提前谢谢。

1 个答案:

答案 0 :(得分:2)

让我们首先说明应该如何:定义引用类。阅读?setRefClass,了解如何做到这一点。

关于这是如何工作的:范围规则。定义函数时,它会记住创建的环境。

mat <- makecachematrix(matrix(1:4, 2))
ls(envir = environment(mat$set))
#[1] "get"    "getinv" "inv"    "set"    "setinv" "x"

环境可以具有父环境,并且这些父环境中的所有变量都可用。这就是为什么这个功能可以工作的原因:

a <- 10
myfun <- function(x) x + a
myfun(5)
# [1] 15

因此,即使$set函数仅将y作为参数,它也会知道&#34;关于makecachematrix函数环境中定义的所有变量。当x <<- y用于分配时,它首先在相同的环境级别查找x。如果它没有找到它,它会向上移动一个级别并重复该过程。找到x后,它会在该级别指定它。 (附注:如果不存在x,则将在全局环境中创建一个。)

makecachematrix正在做的是创建一个函数列表,所有函数都具有相同的父环境。因此,当一个函数改变该父环境中的变量时,该变量也将针对其他函数进行更改。

是的,这可能会变得复杂。这就是为什么这种类型的东西应该使用引用类系统。这是基本版本:

cache_matrix <- setRefClass("cache_matrix",
  fields = list(
    data     = "matrix",
    inverse  = "matrix"
  ),
  methods = list(
    get_inverse = function() {
      if (identical(length(.self$inverse), 0L)) {
        inverse <<- solve(.self$data)
      }
      cache_matrix(data = .self$inverse, inverse = .self$data)
    }
  )
)

在幕后,它的工作方式与makecachematrix几乎相同:使用方法创建对象,共享环境。但是,使用提供的系统比利用范围规则制作自己的系统更好。

以下是如何使用引用类。

mat <- cache_matrix(data = matrix(1:4, 2))
mat
# Reference class object of class "cache_matrix"
# Field "data":
#      [,1] [,2]
# [1,]    1    3
# [2,]    2    4
# Field "inverse":
# <0 x 0 matrix>

mat$data
#       [,1] [,2]
# [1,]    1    3
# [2,]    2    4

mat$get_inverse()
# Reference class object of class "cache_matrix"
# Field "data":
#      [,1] [,2]
# [1,]   -2  1.5
# [2,]    1 -0.5
# Field "inverse":
#      [,1] [,2]
# [1,]    1    3
# [2,]    2    4

mat
# Reference class object of class "cache_matrix"
# Field "data":
#      [,1] [,2]
# [1,]    1    3
# [2,]    2    4
# Field "inverse":
#      [,1] [,2]
# [1,]   -2  1.5
# [2,]    1 -0.5

mat$get_inverse()
# Reference class object of class "cache_matrix"
# Field "data":
#      [,1] [,2]
# [1,]   -2  1.5
# [2,]    1 -0.5
# Field "inverse":
#      [,1] [,2]
# [1,]    1    3
# [2,]    2    4

使用类加入:使用一些额外的代码,您可以将对象视为普通矩阵。

setMethod(
  "solve",
  "cache_matrix",
  function(a, b, ...) {
    a$get_inverse()
  }
)

solve(mat)
# Reference class object of class "cache_matrix"
# Field "data":
#      [,1] [,2]
# [1,]   -2  1.5
# [2,]    1 -0.5
# Field "inverse":
#      [,1] [,2]
# [1,]    1    3
# [2,]    2    4

setMethod(
  "Arith",
  "cache_matrix",
  function(e1, e2) {
    result <- callGeneric(e1$data, e2)
    cache_matrix(data = result)
  }
)

mat + 1
# Reference class object of class "cache_matrix"
# Field "data":
#      [,1] [,2]
# [1,]    2    4
# [2,]    3    5
# Field "inverse":
# <0 x 0 matrix>

setMethod(
  "Arith",
  "numeric",
  function(e1, e2) {
    if (inherits(e2, "cache_matrix")) e2 <- e2$data
    result <- callGeneric(e1, e2)
    cache_matrix(data = result)
  }
)

5 + mat
# Reference class object of class "cache_matrix"
# Field "data":
#       [,1] [,2]
# [1,]    6    8
# [2,]    7    9
# Field "inverse":
# <0 x 0 matrix>