Slovník | Vyhledávání | Mapa webu
 
Základy informatiky pro biologyAnalýza dat v R Propojení C a R Datové struktury v C

Logo Matematická biologie

Datové struktury v C

Propojení C pomocí funkce .Call() vyžaduje použití speciálních datových typů. Základním typem, ve kterém jsou na úrovni C uložené všechny objekty R je SEXP (S-expresion), proto všechny funkce musí vracet a příjímat argumenty jako SEXP. SEXP je obecný typ. Pro konkrétní datové typy které známe z R existuje mnoho specifických SXP typů. Nejběžnějšími jsou:

  • REALSXP: numerický vektor
  • INTSXP: vektor celých čísel
  • LGLSXP: logický vektor
  • STRSXP: znakový vektor
  • VECSXP: seznam
  • CLOSXP: funkce

Existuji samozřejmě i SXP typy pro méně použivané typy objektů:

  • CPLXSXP: komplexní vektory
  • LISTSXP: "párový" seznam (z jazyka LISP)
  • DOTSXP: '...'
  • NILSXP: NULL

Balík pryr obsahuje funkci sexp_type(), která vrací SEXP podtyp pro objekt R.

Načteme balík:

> library(pryr)

Příklady:

> sexp_type(4)
[1] "REALSXP"
> sexp_type("a")
[1] "STRSXP"
> sexp_type(TRUE)
[1] "LGLSXP"
> sexp_type(list(a=1))
[1] "VECSXP"

V souboru Rinternals.h jsou take definované funkce pro převod SEXP vektorů délky jedna na skalár základního typu C (R nezná skalár, pouze vektor o délce jedna):

  • asLogical(): převádí LGLSXP na int
  • asInteger(): převádí INTSXP na int
  • asReal(): převádí REALSXP na double
  • CHAR(asChar()): převádí STRSXP na const char*

Nebo v opačném směru

  • ScalarLogical(): převádí int na LGLSXP
  • ScalarInteger(): převádí int na INTSXP
  • ScalarReal(): převádí double na REALSXP
  • mkString(): převádí const char* na STRSXP

Pro přístup k prvkům numerických, celočíselných nebo logických vektorů slouží funkce REAL(), INTEGER(), LOGICAL(). Pro demonstraci jejich použití vytvoříme funkci add_one(), která přičte ke každému prvku celočíselného vektoru jedničku. Všimněte si také, že v C se vektory indexují od nuly, ne od jedničky!

> add_one <- cfunction(c(x = "numeric"), "
+   int n = length(x);
+   SEXP out = PROTECT(allocVector(REALSXP, n));
+   
+   for (int i = 0; i < n; i++) {
+     REAL(out)[i] = REAL(x)[i] + 1;
+   }
+   UNPROTECT(1);
+
+   return out;
+ ")

> add_one(as.numeric(1:10))

 [1]  2  3  4  5  6  7  8  9 10 11

Vytváření a ochrana vektorů:

Nejjednodušším způsobem vytváření nových vektorů je použití funcke allocVector(). Funkce má 2 argumenty: SEXP podtyp a délku vektoru. Např. následující funkce vytváří a vrací  numerický vektor délky 4:

> library(inline)
> dummy <- cfunction(body = '
+   SEXP vektor = PROTECT(allocVector(REALSXP, 4));
+   UNPROTECT(1);
+   return vektor;

+ ')

> dummy()
[1] 2.108492e-265 5.773281e-252 1.003520e-253 1.003494e-253

Všimněte si, že vektor není prázdný, ale obsahuje konkrétní hodnoty a při opakovaném vyvolání funkce dummy() se hodnoty liší. Jde o hodnotu buněk paměti, které byly pro vektor alokované. Protože R obsahuje tzv. garbage collector, který odstraňuje nepoužívané objekty, je nutné vytvořené objekty v C speciálně chránit pomoci funkce PROTECT(). Na konci výpočtu MUSÍME všechny chráněné objekty uvolnit pomoci funkce UNPROTECT(), jinak by došlo k zaplnění paměti pro R.

 
vytvořil Institut biostatistiky a analýz Lékařské fakulty Masarykovy univerzity