1背景

注:本文档参考第2版beachmatAPI,它仍然受到支持,但不再处于积极的开发中。bob电竞体育官网鼓励编写新代码的开发人员使用版本3,它更加简化。

通常,直接支持矩阵表示需要在中定义适当的方法beachmat在编译时。这是最广泛使用的矩阵类的情况,但对其他社区贡献的矩阵表示有一定的限制。幸运的是,R提供了一种机制来链接来自不同包的共享库。这意味着定义R矩阵表示的包开发人员也可以定义c+bob电竞体育官网+方法,以支持在beachmat端依赖代码。通过这样做,我们可以通过避免通过R进行块处理来提高访问这些新类的效率。

该方法的功能演示可在扩展测试包。这篇短文将解释扩展,我们建议同时检查源代码:

系统。文件(“扩展”,包=“beachmat”)
## [1] "/tmp/RtmpvcXcVI/Rinst3cc67a28eaa669/beachmat/extensions"

2外部输入联动

2.1在R中设置

假设我们已经定义了一个新的类似矩阵的S4类(这里,AaronMatrix).通知beachmatAPI,直接输入支持可用,我们需要:

  • 类的方法定义方法supportCppAccess ()通用(从beachmat)。这应该会返回真正的如果直接支持是可用的(显然)。
  • 类的方法定义方法类型()通用的DelayedArray包中。这应该返回矩阵的类型,即整数、逻辑、数字或字符。

可能只对给定矩阵表示的特定数据类型提供直接支持。例子是扩展仅直接支持整数和字符AaronMatrix对象1因为我懒得把它们都加起来。只会回来真正的对于这样的类型。

2.2在c++中设置

我们将使用整数矩阵进行演示,不过通过替换将其推广到所有类型很简单_integer,例如,_character2对c++模板的一些理解将极大地简化不同类型的相同方法的定义。.首先,我们定义acreate ()函数,该函数接受饱和度指数对象,并返回无效指针。这应该指向一些c++类,该类可以包含用于有效访问的中间数据结构。

void * ptr = AaronMatrix_integer_input_create(in /* SEXP */);

我们定义一个克隆()函数执行上述指针的深度复制。

void* ptr_copy = AaronMatrix_integer_input_clone(ptr /* void* */);

我们定义一个destroy ()函数释放指向的内存ptr

AaronMatrix_integer_input_destroy(ptr /* void* */);

我们定义一个get_dim ()函数记录由所指向的对象中的行数和列数ptr.注意nrow而且ncol

AaronMatrix_integer_input_dim(ptr, /* void* */ nrow, /* size_t* */ ncol /* size_t* */);

所有功能都采用系统的命名方案,包括:

  • 矩阵表示法的名称,即AaronMatrix
  • 数据类型,即整数
  • 不管它是输入输出类。
  • 函数的目的,例如:摧毁

2.3定义getter方法

2.3.1适用于所有类型

类所描述的getter函数通常遵循相同的结构输入API.我们期待得到函数获取矩阵的指定项:

AaronMatrix_integer_intput_get(ptr, /* void* */ r, /* size_t */ c, /* size_t */ val /* int* */);

请注意,瓦尔是一个指针到矩阵类型。例如,瓦尔应该是Rcpp:字符串*对于字符矩阵,a双*对于数值矩阵,和int *对于逻辑矩阵。

bob电竞体育官网开发人员可以假设r而且c是有效的,即,在[0, nrow)而且[0, ncol)分别。这些检查由beachmat并且不必在开发人员定义的函数中重复3.显然,矩阵的维数指向ptr不应该改变!

2.3.2对于非数值类型

在这里,我们将使用字符矩阵4字符矩阵往往需要特别注意,因为字符数组需要强制转换为Rcpp:字符串中返回的对象举个例子。我们期待getCol函数获取矩阵的一列:

AaronMatrix_character_input_getCol(ptr, /* void* */ c, /* size_t */ in, /* Rcpp::StringVector::iterator* */ first, /* size_t */ last /* size_t */);

……另一个getRow函数获取矩阵中的一行:

AaronMatrix_character_input_getRow(ptr, /* void* */ r, /* size_t */ in*, /* Rcpp::StringVector::iterator* */ first, /* size_t */ last /* size_t */);

它们采用驼峰格式,以简化函数名的解析。我们进一步期望getCols函数获取多个列:

AaronMatrix_character_input_getCols(ptr, /* void* */ c, /* size_t */ indexes, /* Rcpp::IntegerVector::iterator* */ n, /* size_t */ in, /* Rcpp::StringVector::iterator* */ first, /* size_t */ last /* size_t */);

…和一个getRows函数获取多行:

AaronMatrix_character_input_getRows(ptr, /* void* */ r, /* size_t */ indexes, /* Rcpp::IntegerVector::iterator* */ n, /* size_t */ in, /* Rcpp::StringVector::iterator* */ first, /* size_t */ last /* size_t */);

在所有情况下,第一个而且最后的都是有效的,也就是说,第一<=最后两者都在[0, nrow)[0, ncol)(分别用于列和行访问)。指数在指数也可以假设是有效的,即在矩阵维内且严格递增。

我们强调不同的迭代器参数是指向迭代器的指针而不是迭代器本身。这是为了避免c++类在通过R使用C风格的链接时出现潜在的问题R_GetCCallable ()框架。

2.3.3数值类型

对于整数、逻辑或数字矩阵,我们需要考虑类型转换。这可以通过定义以下函数来实现(以整数矩阵为例):

  • AaronMatrix_integer_input_getCol_integer,用于以整数形式获取单个列的值。
  • AaronMatrix_integer_input_getCol_numeric,用于将单列的值作为双精度值获取。
  • AaronMatrix_integer_input_getRow_integer,用于获取作为整数的单行值。
  • AaronMatrix_integer_input_getRow_numeric,用于将单行的值作为双精度值获取。
  • AaronMatrix_integer_input_getCols_integer,用于以整数形式获取多列的值。
  • AaronMatrix_integer_input_getCols_numeric,用于将多列的值作为双精度值获取。
  • AaronMatrix_integer_input_getRows_integer,用于以整数形式获取多行值。
  • AaronMatrix_integer_input_getRows_numeric,用于将多行值作为双精度值获取。

以单列getter为例:

AaronMatrix_integer_input_getCol_integer(ptr, /* void* */ c, /* size_t */ in, /* Rcpp::IntegerVector::iterator* */ first, /* size_t */ last /* size_t */);AaronMatrix_integer_input_getCol_numeric(ptr, /* void* */ c, /* size_t */ in, /* Rcpp::NumericVector::iterator* */ first, /* size_t */ last /* size_t */);

函数名现在有一个额外的后缀来表示目标类型。我们在这里显式地定义转换,因为跨库链接框架不支持的模板或重载

3.输出外部链接

3.1在R中设置

通知beachmat如果API支持直接输出,我们需要在包的命名空间中定义标志。

beachmat_AaronMatrix_integer_output <- TRUE beachmat_AaronMatrix_character_output <- TRUE

这表明支持可用于AaronMatrix整数和字符输出。缺失或在这种情况下,标志表示没有可用的支持beachmat默认情况下将写入普通矩阵。

3.2在c++中设置

同样,我们将使用整数矩阵进行演示。所需的函数大多类似于输入情况。对于创建,我们期望有行数nr和列数控

void * ptr = AaronMatrix_integer_output_create(nr /* size_t */, nc /* size_t */);

我们定义一个克隆()函数执行深度拷贝:

void* ptr_copy = AaronMatrix_integer_output_clone(ptr /* void* */);

我们还定义了destroy ()释放内存的函数:

AaronMatrix_integer_output_destroy(ptr /* void* */);

在所有情况下,我们使用_output_表示我们处理的是一个输出矩阵类。

3.3定义setter方法

3.3.1适用于所有类型

类中所描述的setter函数遵循相同的结构从API.我们期待函数获取矩阵的指定项:

AaronMatrix_integer_intput_set(ptr, /* void* */ r, /* size_t */ c, /* size_t */ val /* int* */);

请再次注意瓦尔是一个指针到矩阵类型。

3.3.2对于非数值类型

在这里,我们将使用字符矩阵5字符矩阵往往需要特别注意,因为字符数组需要强制转换为Rcpp:字符串中返回的对象举个例子。我们期待setCol函数获取矩阵的一列:

AaronMatrix_character_output_setCol(ptr, /* void* */ c, /* size_t */ in, /* Rcpp::StringVector::iterator* */ first, /* size_t */ last /* size_t */);

……另一个setRow函数获取矩阵中的一行:

AaronMatrix_character_output_setRow(ptr, /* void* */ r, /* size_t */ in*, /* Rcpp::StringVector::iterator* */ first, /* size_t */ last /* size_t */);

它们采用驼峰格式,以简化函数名的解析。我们进一步期望setColIndexed函数设置列的特定元素:

AaronMatrix_character_output_setColIndexed(ptr, /* void */ c, /* size_t */ n, /* size_t */ idx, /* Rcpp::IntegerVector::iterator */ in /* Rcpp::StringVector::iterator */)

idx的数组n零索引的行索引和瓦尔指向一个值数组。该函数应将每个值赋给列对应的行c输出矩阵的。

同样,我们期望asetRowIndexed函数设置一行中的特定元素:

AaronMatrix_character_output_setRowIndexed(ptr, /* void */ r, /* size_t */ n, /* size_t */ idx, /* Rcpp::IntegerVector::iterator */ in /* Rcpp::StringVector::iterator */)

idx现在包含列索引。

3.3.3数值类型

对于整数、逻辑或数字矩阵,我们需要考虑类型转换。这可以通过定义以下函数来实现(以整数矩阵为例):

  • AaronMatrix_integer_output_setCol_integer,用于从整数中设置单个列的值。
  • AaronMatrix_integer_output_setCol_numeric,用于从双精度值设置单列的值。
  • AaronMatrix_integer_output_setRow_integer,用于从整数中设置单行的值。
  • AaronMatrix_integer_output_setRow_numeric,用于从双精度值设置单行值。
  • AaronMatrix_integer_output_setColIndexed_integer,用于从整数中索引单个列的值。
  • AaronMatrix_integer_output_setColIndexed_numeric,用于从双精度值到单列值的索引设置。
  • AaronMatrix_integer_output_setRowIndexed_integer,用于从整数中索引单行值的设置。
  • AaronMatrix_integer_output_setRowIndexed_numeric,用于从双精度值到单行值的索引设置

以单列setter为例:

AaronMatrix_integer_output_setCol_integer(ptr, /* void* */ c, /* size_t */ in, /* Rcpp::IntegerVector::iterator* */ first, /* size_t */ last /* size_t */);AaronMatrix_integer_output_setCol_numeric(ptr, /* void* */ c, /* size_t */ in, /* Rcpp::NumericVector::iterator* */ first, /* size_t */ last /* size_t */);

3.4定义getter方法

应该支持所有单元素和单行/列getter:

  • AaronMatrix_character_output_get
  • AaronMatrix_character_output_getRow
  • AaronMatrix_character_output_getCol

对于数字类型,也应该支持可转换getter:

  • AaronMatrix_character_output_get
  • AaronMatrix_character_output_getRow_integer
  • AaronMatrix_character_output_getRow_numeric
  • AaronMatrix_character_output_getCol_integer
  • AaronMatrix_character_output_getCol_numeric

4确保可发现性

我们使用R_RegisterCCallable ()函数来注册上面的函数(参见在这里为了一个解释)。这样可以确保通过beachmat当一个AaronMatrix实例。注意,函数必须用c风格的链接定义,以便此过程能够正常工作,因此使用外来的“C”扩展测试包。

不用说,名称空间应该包含适当的useDynLib命令。这意味着共享库将与包一起加载,允许beachmat以访问内部的已注册例程。然而,supportCppAccess方法和输出标志不需要导出,因为它们将直接从包的命名空间中恢复。

5测试

我们建议使用beachtest包来测试通过外部链接到自定义矩阵表示的正确输入和输出。当使用testthat框架,这可以添加到设置。R

Testpkg <- system。devtools::install(testpkg, quick=TRUE) library(beachtest)

使用类似的函数来编写测试脚本是很简单的check_read_all而且check_write_all快速验证链接是否正确工作。bob电竞体育官网开发人员再次被提及扩展测试包的工作示例。