Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add assignment operator to DimNameProxy #339

Merged
merged 6 commits into from
Aug 14, 2015

Conversation

fplazaonate
Copy link
Contributor

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericMatrix test_mat(const NumericMatrix& mat)
{
  const int num_rows = mat.rows();
  const int num_cols = mat.cols();
  NumericMatrix res_mat(num_rows, num_cols);
  rownames(res_mat)=rownames(mat);
  colnames(res_mat)=colnames(mat);

  return res_mat;
}




/*** R
mat=matrix(1:150,nrow=10,ncol=15,byrow=T)
rownames(mat)=sapply(1:10,as.character)
colnames(mat)=sapply(1:15,as.character)

mat_res=test_mat(mat)

rownames(mat_res)
colnames(mat_res)
*/

Before:

> mat=matrix(1:150,nrow=10,ncol=15,byrow=T)

> rownames(mat)=sapply(1:10,as.character)

> colnames(mat)=sapply(1:15,as.character)

> mat_res=test_mat(mat)

> rownames(mat_res)
NULL

> colnames(mat_res)
NULL

After:

> mat=matrix(1:150,nrow=10,ncol=15,byrow=T)

> rownames(mat)=sapply(1:10,as.character)

> colnames(mat)=sapply(1:15,as.character)

> mat_res=test_mat(mat)

> rownames(mat_res)
 [1] "1"  "2"  "3"  "4"  "5"  "6"  "7"  "8"  "9"  "10"

> colnames(mat_res)
 [1] "1"  "2"  "3"  "4"  "5"  "6"  "7"  "8"  "9"  "10" "11" "12" "13" "14" "15"

After:

@eddelbuettel
Copy link
Member

This looks pretty straightforward -- in favour. Any seconds?

stop(s.str());
}
SEXP dimnames = Rf_getAttrib(data_, R_DimNamesSymbol);
SEXP dims = Rf_getAttrib(data_, R_DimSymbol);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like you already retrieved this above with SEXP dim = Rf_getAttrib(data_, R_DimSymbol) -- is this line superfluous?

EDIT: I see now the interface is mostly copied from the other operator=; I guess that's a similar oversight in the previous implementation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And while you're there, now that stop does the printf thing, the whole std::stringstream can be replaced.

@kevinushey
Copy link
Contributor

I agree this is a good change; it would probably be best to refactor the code into its own function (which both operator= methods can call) rather than duplicating code, however.

@fplazaonate
Copy link
Contributor Author

I made the change you asked.
Tell me if it suits you.

@eddelbuettel
Copy link
Member

Looks good to me.

@fplazaonate
Copy link
Contributor Author

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
void test_mat()
{
  const int num_rows = 2;
  const int num_cols = 2;
  NumericMatrix m1(num_rows, num_cols);
  NumericMatrix m2(num_rows, num_cols);
  rownames(m1)=CharacterVector::create("a", "b");
  rownames(m1)=rownames(m2);
}




/*** R
test_mat()
*/

Result

`test_mat()
Error in eval(expr, envir, enclos) : 
  dimension extent is '2' while length of names is '0'

I think this code should not produce an error as it works in R. What do you think?

@kevinushey
Copy link
Contributor

I agree that the code shouldn't produce an error; in fact, it looks like in current Rcpp we just get the wrong result:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericMatrix test_mat()
{
   const int num_rows = 2;
   const int num_cols = 2;
   NumericMatrix m1(num_rows, num_cols);
   NumericMatrix m2(num_rows, num_cols);
   rownames(m1)=CharacterVector::create("a", "b");
   rownames(m1)=rownames(m2);
   return m1;
}

/*** R
test_mat()
*/

gives

> Rcpp::sourceCpp('~/test.cpp')

> test_mat()
  [,1] [,2]
a    0    0
b    0    0

It looks to me like the second rownames assignment should have cleared the rownames of m1; if you are willing would you be able to tackle that as well?

Thanks for working on this!


inline DimNameProxy& assign(SEXP other) {
SEXP dims = Rf_getAttrib(data_, R_DimSymbol);
if (INTEGER(dims)[dim_] != Rf_length(other)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does the trick

if (Rf_length(other) != 0 && INTEGER(dims)[dim_] != Rf_length(other))

but it looks a bit dirty.

@fplazaonate
Copy link
Contributor Author

The last commit fixes the following cases:

#include <Rcpp.h>
using namespace Rcpp;


// [[Rcpp::export]]
NumericMatrix test_mat2()
{

  const int num_rows = 2;
  const int num_cols = 2;
  NumericMatrix m1(num_rows, num_cols);
  rownames(m1)=CharacterVector::create('a','b');
  rownames(m1)=CharacterVector::create();
  return m1;
}


// [[Rcpp::export]]
NumericMatrix  test_mat()
{
  const int num_rows = 2;
  const int num_cols = 2;
  NumericMatrix m1(num_rows, num_cols);
  NumericMatrix m2(num_rows, num_cols);
  rownames(m1)=CharacterVector::create("a", "b");
  rownames(m1)=rownames(m2);
  return m1;
}




/*** R
test_mat()
test_mat2()
*/
> test_mat()
     [,1] [,2]
[1,]    0    0
[2,]    0    0

> test_mat2()
     [,1] [,2]
[1,]    0    0
[2,]    0    0

It is ok to do so in R

> m1=matrix(nrow = 2,ncol = 2)
> rownames(m1)=c(1,2)
> rownames(m1)
[1] "1" "2"
> m2=matrix(nrow = 2,ncol = 2)
> rownames(m1)=rownames(m2)
> rownames(m1)
NULL
> rownames(m1)=c(1,2)
> rownames(m1)=c()
> rownames(m1)
NULL

} else {
SET_VECTOR_ELT(dimnames, dim_, other);
SEXP dims = Rf_getAttrib(data_, R_DimSymbol);
if (INTEGER(dims)[dim_] != Rf_length(other)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should check that dims is non-null here, e.g. if (dims != R_NilValue && ...)

@kevinushey
Copy link
Contributor

Thanks! I have one more nitpick re: a null check and then I think it's ready for merge.

@fplazaonate
Copy link
Contributor Author

I am not sure it can happen because a DimNameProxy object is currently created only from a Matrix.

@kevinushey
Copy link
Contributor

Good point -- okay, then I think this is good to go. @eddelbuettel, any other comments?

@eddelbuettel
Copy link
Member

Yup, let's fold this in.

eddelbuettel added a commit that referenced this pull request Aug 14, 2015
Add assignment operator to DimNameProxy
@eddelbuettel eddelbuettel merged commit e0ea6ed into RcppCore:master Aug 14, 2015
@fplazaonate fplazaonate deleted the DimNameProxy-patch1 branch August 17, 2015 07:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants