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

@fplaza
Copy link
Contributor

@fplaza fplaza commented Aug 14, 2015

#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

@eddelbuettel eddelbuettel commented Aug 14, 2015

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);

This comment has been minimized.

@kevinushey

kevinushey Aug 14, 2015
Contributor

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.

This comment has been minimized.

@romainfrancois

romainfrancois Aug 14, 2015
Contributor

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

@@ -56,6 +56,31 @@ namespace internal{
return *this;
}

inline DimNameProxy& operator=(const DimNameProxy& other) {
SEXP dim = Rf_getAttrib(data_, R_DimSymbol);

This comment has been minimized.

@kevinushey

kevinushey Aug 14, 2015
Contributor

This should probably have a NULL check (same with older implementation)

@kevinushey
Copy link
Contributor

@kevinushey kevinushey commented Aug 14, 2015

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.

fplaza added 3 commits Aug 14, 2015
@fplaza
Copy link
Contributor Author

@fplaza fplaza commented Aug 14, 2015

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

@eddelbuettel
Copy link
Member

@eddelbuettel eddelbuettel commented Aug 14, 2015

Looks good to me.

@fplaza
Copy link
Contributor Author

@fplaza fplaza commented Aug 14, 2015

#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

@kevinushey kevinushey commented Aug 14, 2015

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)) {

This comment has been minimized.

@fplaza

fplaza Aug 14, 2015
Author Contributor

This does the trick

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

but it looks a bit dirty.

fplaza added 2 commits Aug 14, 2015
@fplaza
Copy link
Contributor Author

@fplaza fplaza commented Aug 14, 2015

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)) {

This comment has been minimized.

@kevinushey

kevinushey Aug 14, 2015
Contributor

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

@kevinushey
Copy link
Contributor

@kevinushey kevinushey commented Aug 14, 2015

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

@fplaza
Copy link
Contributor Author

@fplaza fplaza commented Aug 14, 2015

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

@kevinushey
Copy link
Contributor

@kevinushey kevinushey commented Aug 14, 2015

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

@eddelbuettel
Copy link
Member

@eddelbuettel eddelbuettel commented Aug 14, 2015

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
1 check passed
1 check passed
continuous-integration/travis-ci/pr The Travis CI build passed
Details
@fplaza fplaza deleted the fplaza:DimNameProxy-patch1 branch Aug 17, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

4 participants
You can’t perform that action at this time.