Dear R developers, I am writing some C code that loads multiple images into a list of R matrices. The whole R object is created within the C code. To simplify coding, elements of the list are first created as vectors and then converted to corresponding matrices using setAttrib(x, R_DimSymbol, s). Generally the code works fine except for one detail. Applying setAttrib sets ALL elements (matrices) in the list to the same size, namely to the one last applied, doesn't matter if other matrices are larger or smaller. The command is applied to an element, not to the whole list in the following way, see below. Is there any way to change the dims of an element without altering other elements in this example? Furthermore, if I skip the last command and return a list of vectors instead of a list of matrices - all vectors have different lengths corresponding to the respective image sizes. // creating the list to hold matrices SEXP result = allocVector(VECSXP, nFiles); // creating a vector for the list element i SET_VECTOR_ELT(result, i, allocVector(INTSXP, size[0] * size[1])); // getting a pointer to the element to simlify coding SEXP element = VECTOR_ELT(result, i); // writing some values to the element // converting element into a matrix setAttrib(element, R_DimSymbol, imgSize); Thanks in advance for help Oleg Dr Oleg Sklyar European Bioinformatics Institute Wellcome Trust Genome Campus Hinxton, Cambridge, CB10 1SD England phone/fax +44(0)1223 49 4478/4468 e-mail osklyar@ebi.ac.uk
.Call - applying setAttrib(x, R_DimSymbol, s) to a matrix being an element of a list
6 messages · Simon Urbanek, Brian Ripley, Oleg Sklyar
Oleg, you gave us only a fragment of your code, so I can only guess what the problem is:
On Mar 16, 2005, at 12:40 PM, Oleg Sklyar wrote:
// converting element into a matrix setAttrib(element, R_DimSymbol, imgSize);
What is imgSize? The behavior you describe seems as if you re-using the imgSize SEXP in all elements. AFAIR in your case setAttrib doesn't copy the value, so you need to do so yourself (or alloc new dim array for each element). Cheers, Simon
Dear Simon,
> you gave us only a fragment of your code, so I can only guess what
the problem is:
> What is imgSize? The behavior you describe seems as if you re-using
the imgSize SEXP in all elements.
> AFAIR in your case setAttrib doesn't copy the value, so you need to
do so yourself (or alloc new dim array
> for each element).
Sorry, it is always a tradeoff - either to explain or put a relatively
large code, which also uses non-standard libraries making the code
difficult to read. imgSize values are reset in between: see the full
code below. The SEXP pointer imgSize stays in tact, that's true, but its
values are changed (the problem is, they are always the last in the
row). I.e. if I have 3 images 40x20, 200x100 and 150x75 I will get three
matrices of 150x75, but if I omit setAtrib and return vectors I get
vectors of different length.
Oleg
SEXP load2DImages(SEXP fileNames) {
int nFiles = LENGTH(fileNames);
std::cout << "Loading " << nFiles << " files..." << std::endl;
// SEXP result = allocList(nFiles);
SEXP result = allocVector(VECSXP, nFiles);
PROTECT(result);
SEXP imgSize = allocVector(INTSXP, 2);
PROTECT(imgSize);
TRGB2DImage::Pointer image;
TRGB2DReader::Pointer reader = TRGB2DReader::New();
TRGB2DImage::SizeType size;
TRGB2DImage::IndexType pixIndex;
for (int i = 0; i < nFiles; i++) {
try {
char *filename = CHAR(asChar(VECTOR_ELT(fileNames, i)));
std::cout << std::endl << "Loading image file " << filename
<< "... ";
reader->SetFileName(filename);
reader->Update();
image = reader->GetOutput();
} catch(...) {
std::cout << "failed!";
continue;
}
std::cout << std::endl;
size = image->GetLargestPossibleRegion().GetSize();
INTEGER(imgSize)[0] = size[1];
INTEGER(imgSize)[1] = size[0];
std::cout << size[0] << " x " << size[1] << std::endl;
SET_VECTOR_ELT(result, i, allocVector(INTSXP, size[0] * size[1]));
SEXP element = VECTOR_ELT(result, i);
for (int ix = 0; ix < size[0]; ix++) {
pixIndex[0] = ix;
for (int iy = 0; iy < size[1]; iy++) {
pixIndex[1] = iy;
INTEGER(element)[size[1] * ix + iy] =
getIntRGBColour(image->GetPixel(pixIndex));
}
}
setAttrib(element, R_DimSymbol, imgSize);
}
UNPROTECT(2);
if (nFiles == 1)
return VECTOR_ELT(result, 0);
else
return result;
}
Dr Oleg Sklyar
European Bioinformatics Institute
Wellcome Trust Genome Campus
Hinxton, Cambridge, CB10 1SD
England
phone/fax +44(0)1223 49 4478/4468
e-mail osklyar@ebi.ac.uk
Simon Urbanek wrote:
Oleg, you gave us only a fragment of your code, so I can only guess what the problem is: On Mar 16, 2005, at 12:40 PM, Oleg Sklyar wrote:
// converting element into a matrix setAttrib(element, R_DimSymbol, imgSize);
What is imgSize? The behavior you describe seems as if you re-using the imgSize SEXP in all elements. AFAIR in your case setAttrib doesn't copy the value, so you need to do so yourself (or alloc new dim array for each element). Cheers, Simon
On Thu, 17 Mar 2005, Oleg Sklyar wrote:
Dear Simon,
you gave us only a fragment of your code, so I can only guess what the
problem is:
What is imgSize? The behavior you describe seems as if you re-using the
imgSize SEXP in all elements.
AFAIR in your case setAttrib doesn't copy the value, so you need to do so
yourself (or alloc new dim array
for each element).
Sorry, it is always a tradeoff - either to explain or put a relatively large code, which also uses non-standard libraries making the code difficult to read. imgSize values are reset in between: see the full code below. The SEXP pointer imgSize stays in tact, that's true, but its values are changed (the problem is, they are always the last in the row). I.e. if I have 3 images 40x20, 200x100 and 150x75 I will get three matrices of 150x75, but if I omit setAtrib and return vectors I get vectors of different length.
So, as Simon says, you need to create separate objects for the dimensions of each matrix, not share the object. It is the object pointed to by imgSize you have attached as the dimensions, not the values. BTW, setAttrib(element, R_DimSymbol, imgSize) just calls dimgets(element, imgSize), so I would have used the latter directly. I believe you do not have three matrices of 150x75, rather a vector of length 40*20 with an inconsistent dim attribute of c(150, 75), etc.
Oleg
SEXP load2DImages(SEXP fileNames) {
int nFiles = LENGTH(fileNames);
std::cout << "Loading " << nFiles << " files..." << std::endl;
// SEXP result = allocList(nFiles);
SEXP result = allocVector(VECSXP, nFiles);
PROTECT(result);
SEXP imgSize = allocVector(INTSXP, 2);
PROTECT(imgSize);
TRGB2DImage::Pointer image;
TRGB2DReader::Pointer reader = TRGB2DReader::New();
TRGB2DImage::SizeType size; TRGB2DImage::IndexType pixIndex;
for (int i = 0; i < nFiles; i++) {
try {
char *filename = CHAR(asChar(VECTOR_ELT(fileNames, i)));
std::cout << std::endl << "Loading image file " << filename <<
"... ";
reader->SetFileName(filename);
reader->Update();
image = reader->GetOutput();
} catch(...) {
std::cout << "failed!";
continue;
}
std::cout << std::endl;
size = image->GetLargestPossibleRegion().GetSize();
INTEGER(imgSize)[0] = size[1];
INTEGER(imgSize)[1] = size[0];
std::cout << size[0] << " x " << size[1] << std::endl;
SET_VECTOR_ELT(result, i, allocVector(INTSXP, size[0] * size[1]));
SEXP element = VECTOR_ELT(result, i);
for (int ix = 0; ix < size[0]; ix++) {
pixIndex[0] = ix;
for (int iy = 0; iy < size[1]; iy++) {
pixIndex[1] = iy;
INTEGER(element)[size[1] * ix + iy] =
getIntRGBColour(image->GetPixel(pixIndex));
}
}
setAttrib(element, R_DimSymbol, imgSize);
}
UNPROTECT(2);
if (nFiles == 1)
return VECTOR_ELT(result, 0);
else
return result;
}
Dr Oleg Sklyar
European Bioinformatics Institute
Wellcome Trust Genome Campus
Hinxton, Cambridge, CB10 1SD
England
phone/fax +44(0)1223 49 4478/4468
e-mail osklyar@ebi.ac.uk
Simon Urbanek wrote:
Oleg, you gave us only a fragment of your code, so I can only guess what the problem is: On Mar 16, 2005, at 12:40 PM, Oleg Sklyar wrote:
// converting element into a matrix setAttrib(element, R_DimSymbol, imgSize);
What is imgSize? The behavior you describe seems as if you re-using the imgSize SEXP in all elements. AFAIR in your case setAttrib doesn't copy the value, so you need to do so yourself (or alloc new dim array for each element). Cheers, Simon
______________________________________________ R-devel@stat.math.ethz.ch mailing list https://stat.ethz.ch/mailman/listinfo/r-devel
Brian D. Ripley, ripley@stats.ox.ac.uk Professor of Applied Statistics, http://www.stats.ox.ac.uk/~ripley/ University of Oxford, Tel: +44 1865 272861 (self) 1 South Parks Road, +44 1865 272866 (PA) Oxford OX1 3TG, UK Fax: +44 1865 272595
Oleg,
On Mar 16, 2005, at 8:34 PM, Oleg Sklyar wrote:
Sorry, it is always a tradeoff - either to explain or put a relatively large code,
Just posting all R related commands is sufficient ;) - in your case that would be the single imgSize alloc and the assignments- but the full code is fine, too.
which also uses non-standard libraries making the code difficult to read. imgSize values are reset in between: see the full code below. The SEXP pointer imgSize stays in tact,
That's the problem. As I said previously - you need to duplicate it or alloc new ones. setAttrib of non-NAMED values doesn't copy the value, so you're passing the same pointer to all your matrices, so they all share the same dimension object. This means that whenever you change integers the pointer is pointing at, you change it for all matrices you used it in, which is probably not what you intended.
that's true, but its values are changed (the problem is, they are always the last in the row). I.e. if I have 3 images 40x20, 200x100 and 150x75 I will get three matrices of 150x75, but if I omit setAtrib and return vectors I get vectors of different length.
The length of the vector has nothing to do with the dimensions - technically. In C you can say "this is a vector of 10 integers and has dimension 100x200" - although such matrix is invalid, in C you're free to do so. It's up to your code to make sure the dimension and the vector length match. In your case, they don't and your code is to blame ;). Cheers, Simon
Thanks a lot for your comments. In fact I had an idea that maybe it is a pointer that is transferred after Simon's yesterday's commnent. So generally I should always allocVector for imgSize before passing it and just let the garbage collector to clean them afterwards if I understand right. Best regards Oleg Dr Oleg Sklyar European Bioinformatics Institute Wellcome Trust Genome Campus Hinxton, Cambridge, CB10 1SD England phone/fax +44(0)1223 49 4478/4468 e-mail osklyar@ebi.ac.uk
Prof Brian Ripley wrote:
On Thu, 17 Mar 2005, Oleg Sklyar wrote:
Dear Simon,
you gave us only a fragment of your code, so I can only guess what the
problem is:
What is imgSize? The behavior you describe seems as if you re-using the
imgSize SEXP in all elements.
AFAIR in your case setAttrib doesn't copy the value, so you need to do so
yourself (or alloc new dim array
for each element).
Sorry, it is always a tradeoff - either to explain or put a relatively large code, which also uses non-standard libraries making the code difficult to read. imgSize values are reset in between: see the full code below. The SEXP pointer imgSize stays in tact, that's true, but its values are changed (the problem is, they are always the last in the row). I.e. if I have 3 images 40x20, 200x100 and 150x75 I will get three matrices of 150x75, but if I omit setAtrib and return vectors I get vectors of different length.
So, as Simon says, you need to create separate objects for the dimensions of each matrix, not share the object. It is the object pointed to by imgSize you have attached as the dimensions, not the values. BTW, setAttrib(element, R_DimSymbol, imgSize) just calls dimgets(element, imgSize), so I would have used the latter directly. I believe you do not have three matrices of 150x75, rather a vector of length 40*20 with an inconsistent dim attribute of c(150, 75), etc.
Oleg
SEXP load2DImages(SEXP fileNames) {
int nFiles = LENGTH(fileNames);
std::cout << "Loading " << nFiles << " files..." << std::endl;
// SEXP result = allocList(nFiles);
SEXP result = allocVector(VECSXP, nFiles);
PROTECT(result);
SEXP imgSize = allocVector(INTSXP, 2);
PROTECT(imgSize);
TRGB2DImage::Pointer image;
TRGB2DReader::Pointer reader = TRGB2DReader::New();
TRGB2DImage::SizeType size; TRGB2DImage::IndexType pixIndex;
for (int i = 0; i < nFiles; i++) {
try {
char *filename = CHAR(asChar(VECTOR_ELT(fileNames, i)));
std::cout << std::endl << "Loading image file " << filename
<< "... ";
reader->SetFileName(filename);
reader->Update();
image = reader->GetOutput();
} catch(...) {
std::cout << "failed!";
continue;
}
std::cout << std::endl;
size = image->GetLargestPossibleRegion().GetSize();
INTEGER(imgSize)[0] = size[1];
INTEGER(imgSize)[1] = size[0];
std::cout << size[0] << " x " << size[1] << std::endl;
SET_VECTOR_ELT(result, i, allocVector(INTSXP, size[0] * size[1]));
SEXP element = VECTOR_ELT(result, i);
for (int ix = 0; ix < size[0]; ix++) {
pixIndex[0] = ix;
for (int iy = 0; iy < size[1]; iy++) {
pixIndex[1] = iy;
INTEGER(element)[size[1] * ix + iy] =
getIntRGBColour(image->GetPixel(pixIndex));
}
}
setAttrib(element, R_DimSymbol, imgSize);
}
UNPROTECT(2);
if (nFiles == 1)
return VECTOR_ELT(result, 0);
else
return result;
}
Dr Oleg Sklyar
European Bioinformatics Institute
Wellcome Trust Genome Campus
Hinxton, Cambridge, CB10 1SD
England
phone/fax +44(0)1223 49 4478/4468
e-mail osklyar@ebi.ac.uk
Simon Urbanek wrote:
Oleg, you gave us only a fragment of your code, so I can only guess what the problem is: On Mar 16, 2005, at 12:40 PM, Oleg Sklyar wrote:
// converting element into a matrix setAttrib(element, R_DimSymbol, imgSize);
What is imgSize? The behavior you describe seems as if you re-using the imgSize SEXP in all elements. AFAIR in your case setAttrib doesn't copy the value, so you need to do so yourself (or alloc new dim array for each element). Cheers, Simon
______________________________________________ R-devel@stat.math.ethz.ch mailing list https://stat.ethz.ch/mailman/listinfo/r-devel