AKshayKulkarni
AKshayKulkarni

Reputation: 57

.nrow() method in C++ in Rcpp returning zeros

With Rcpp, I've defined a matrix M in C++. Using M.nrow(), we should be able to retrieve the number of rows. However, when I tried to return the number of rows as an IntegerVector, the answer is incorrect:

set.seed(1100)
M = matrix(sample(18), nrow = 6)
Rcpp::cppFunction('IntegerVector tccp5(IntegerMatrix M) { int x = M.nrow(); return x;}')
tccp5(M)
# [1] 0 0 0 0 0 0

The correct answer should be the number of rows, e.g.

# [1] 6

Can you please explain what is happening?

Upvotes: 3

Views: 610

Answers (2)

coatless
coatless

Reputation: 20746

While @gfgm's answer is spot on, I wanted to expand upon why declaring as an int and not IntegerVector leads to the right construction...

In particular, each return into R is seamlessly converted using wrap() to an SEXP, or an S expression that points to the structure. By supplying IntegerVector and returning an int, the wrap() must instantiate a new IntegerVector of length x as there is no SEXP underlying an int. On the other hand, when the defined return type is int, the wrap() feature of Rcpp is able to correctly coerce the int into an IntegerVector.


To emphasize the underlying "seamless" transition that happens, let's add the parameter verbose = TRUE to cppFunction() to view how the C++ code is: compiled, linked, and imported into R. (Note: I've truncated the output to the compilations.)

If we consider:

Rcpp::cppFunction('IntegerVector tccp5(IntegerMatrix M) { int x = M.nrow(); return x;}',
                  verbose = TRUE)

We get:

Generated code for function definition: 
--------------------------------------------------------

#include <Rcpp.h>

using namespace Rcpp;

// [[Rcpp::export]]
IntegerVector tccp5(IntegerMatrix M) { int x = M.nrow(); return x;}

Generated extern "C" functions 
--------------------------------------------------------


#include <Rcpp.h>
// tccp5
IntegerVector tccp5(IntegerMatrix M);
RcppExport SEXP sourceCpp_7_tccp5(SEXP MSEXP) {
BEGIN_RCPP
    Rcpp::RObject rcpp_result_gen;
    Rcpp::RNGScope rcpp_rngScope_gen;
    Rcpp::traits::input_parameter< IntegerMatrix >::type M(MSEXP);
    rcpp_result_gen = Rcpp::wrap(tccp5(M));
    return rcpp_result_gen;
END_RCPP
}

Compared to:

Rcpp::cppFunction('int tccp5(IntegerMatrix M) { int x = M.nrow(); return x;}', 
                  verbose = TRUE)

which gives:

Generated code for function definition: 
--------------------------------------------------------

#include <Rcpp.h>

using namespace Rcpp;

// [[Rcpp::export]]
int tccp5(IntegerMatrix M) { int x = M.nrow(); return x;}

Generated extern "C" functions 
--------------------------------------------------------


#include <Rcpp.h>
// tccp5
int tccp5(IntegerMatrix M);
RcppExport SEXP sourceCpp_9_tccp5(SEXP MSEXP) {
BEGIN_RCPP
    Rcpp::RObject rcpp_result_gen;
    Rcpp::RNGScope rcpp_rngScope_gen;
    Rcpp::traits::input_parameter< IntegerMatrix >::type M(MSEXP);
    rcpp_result_gen = Rcpp::wrap(tccp5(M));
    return rcpp_result_gen;
END_RCPP
}

Upvotes: 3

gfgm
gfgm

Reputation: 3647

The anomalous output arises because of the type declaration of the function.

library(Rcpp)
M <- matrix(sample(1:18), nrow=6)

cppFunction('int tccp6(IntegerMatrix M) { int x = M.nrow(); return x;}')
tccp6(M)
#> [1] 6

Created on 2018-03-22 by the reprex package (v0.2.0).

Upvotes: 1

Related Questions