Matrix包的类布局表明
Matrix是R最著名的稀疏矩阵包,内里界说了许多类,错综巨大,这里作一个简朴的理顺,对付领略R package的建造、R面向工具的编程要领也会有很大辅佐。
这里只是做阐明,并不必然要安装Matrix包,只要把它的源代码下载下来就完了。
解压出来有几个目次:data目次是随包带的数据;inst的内容会直接丢到安装后的包目次;man是辅佐文档;tests是测试剧本;这里都不消管。主要看看R目次及src目次,前者放着R剧本,后者是C源代码。
所有类的界说根基都在R/AllClass.R里,始祖类Matrix的界说如下:
## Mother class of all Matrix objects
setClass(“Matrix”,
representation(Dim = “integer”, Dimnames = “list”, “VIRTUAL”),
prototype = prototype(Dim = integer(2), Dimnames = list(NULL,NULL)),
validity = function(object) {
Dim <- [email protected]
if (length(Dim) != 2)
return(“Dim slot must be of length 2”)
if (any(Dim < 0))
return(“Dim slot must contain non-negative values”)
Dn <- [email protected]
if (!is.list(Dn) || length(Dn) != 2)
return(“‘Dimnames’ slot must be list of length 2”)
lDn <- sapply(Dn, length)
if (lDn[1] > 0 && lDn[1] != Dim[1])
return(“length(Dimnames[[1]])’ must match Dim[1]”)
if (lDn[2] > 0 && lDn[2] != Dim[2])
return(“length(Dimnames[[2]])’ must match Dim[2]”)
## ‘else’ ok :
TRUE
})
类的界说是用setClass函数指定的,第一个参数是类名;参数representation指定该类有哪些slot,相当于成员变量,要害词”VIRTUAL”说明这是一个虚类;参数prototype指定slot的默认值;参数validity在类工具生成时用于验证数据的正当性。接下来就是blablablabla的一大堆的类担任体系了,这里只举几个例子说明:
## Virtual class of numeric matrices
setClass(“dMatrix”,
representation(x = “numeric”, “VIRTUAL”), contains = “Matrix”,
validity = function(object)
.Call(dMatrix_validate, object))
这里是一个处理惩罚double型的矩阵类,contains参数说明它是从”Matrix”类担任的;representation部门参数及validity参数也被重载了;依旧是虚类。再看看一个用得更为遍及的实类dgCMatrix的界说:
## numeric, sparse, sorted compressed sparse column-oriented general matrices
setClass(“dgCMatrix”,
contains = c(“CsparseMatrix”, “dsparseMatrix”, “generalMatrix”),
validity = function(object) .Call(xCMatrix_validate, object)
)
它担任自”CsparseMatrix”, “dsparseMatrix”, “generalMatrix”几个类,名字dgC也是由这三个类的首字母凑成的,dsparseMatrix担任自上面提到的dMatrix,是个double型的稀疏矩阵类;CsparseMatrix是一个以compressed布局形式暗示的稀疏矩阵类;generalMatrix暗示这是一个凡是构型的矩阵类,与之对应的有symmetricMatrix(对称矩阵)、triangularMatrix(上/下三角矩阵)等。
再看看R/AllGeneric.R文件,内里利用setGeneric函数把许多R内置的函数指定为泛型函数(generic function),这里的浸染相当于是把普通函数转变为虚函数,然后就可以利用面临工具编程的“多态”特性了。好比声明
setGeneric(“colSums”,
def = function(x, na.rm = FALSE, dims = 1, …) standardGeneric(“colSums”),
useAsDefault = function(x, na.rm = FALSE, dims = 1, …)
之后,colSums这个函数就不再是只能对凡是矩阵各列求和的成果了,它已经酿成一个虚函数,假如我在差异的矩阵类A或B中对它作了重载,则colSums(a)和colSum(a)获得的功效是纷歧样的(a和b别离是A和B的实例)。好比,在R/colSums.R中,我们可以看到如下界说:
## the last two arguments to dgCMatrix_colSums are `trans’ and `means’
setMethod(“colSums”, signature(x = “dgCMatrix”),
function(x, na.rm = FALSE, dims = 1, sparseResult = FALSE)
.Call(dgCMatrix_colSums, x, na.rm, sparseResult, FALSE, FALSE))
参数signature指明这个界说所合用的类名,假如把dgCMatrix类的工具通报给colSums,则紧接着的function界说的语句将会被执行。setMethod实现了对泛型函数与类工具的绑定分配成果。那假如我要对加减乘除这类操纵符也举办重载那该怎么办呢?谜底是操作R面向工具编程的Group观念,它包括一些荟萃,包罗Arith(运算符荟萃:+-*/)、Compare(较量符荟萃:<>等等)、Logic、Math等等。从文件R/Ops.R里可以看到运算符是如何重载的,实际上与一般函数重载雷同。需要留意的是矩阵乘%*%并不是Group界说的范畴,需要别的界说,可以参看R/products.R里的实现。
上面代码里呈现了.Call这个外部挪用接口,挪用由C编写生成的so库。实际上这个包里大量地利用了C写的扩展,关于如何写.Call范例的挪用接口,可参看我上一篇文章。Matrix包里用.Call挪用的函数多半界说在src/*.h中,实此刻src/*.c中,有乐趣的还可以对源代码加以研究。安装时这些源代码会被编译毗连成一个so文件Matrix.so,在NAMESPACE文件里用useDynLib(Matrix, .registration=TRUE)声明自动载入之后,就可以利用了。
最后附录一个Matrix包的担录用名三维布局图,dim1指代数据范例(double, logical, none),dim2指代矩阵构型(凡是、对称、三角、对角),dim3指代数据存储方法。