[Rd] Speeding up transpose
Hervé Pagès
hpages at fhcrc.org
Sat Aug 28 02:01:34 CEST 2010
Hi Radford,
On 08/25/2010 07:50 PM, Radford Neal wrote:
> I've looked at how to speed up the transpose function in R
> (ie, t(X)).
>
> The existing code does the work with loops like the following:
>
> for (i = 0; i< len; i++)
> REAL(r)[i] = REAL(a)[(i / ncol) + (i % ncol) * nrow];
>
> It seems a bit optimistic to expect a compiler to produce good code
> from this. I've re-written these loops as follows:
>
> for (i = 0, j = 0; i<len; i += 1, j += nrow) {
> if (j>=len) j -= (len-1);
> REAL(r)[i] = REAL(a)[j];
> }
You can even avoid the j>=len test within the loop by using 2 nested
loops:
dest = REAL(r);
src = REAL(a);
// walk the dest col by col (i.e. linearly)
// walk the src row by row (i.e. not linearly)
for (i = 0; i < nrow; i++, src++)
for (j = 0; j < len; j += nrow, dest++)
*dest = src[j];
1 test, 3 additions (src[j] being equiv to *(src + j)), 1 assignment
in the inner loop. I wonder if it's possible to get rid of one of the
additions.
This gives me another 10% gain in speed (on my 64-bit Ubuntu laptop),
not that much, but still...
BTW isn't that surprising that using div() is actually slower than using
of / and %, at least on Linux? Since div() is kind of the atomic version
of it, I would have expected it to be slightly faster :-/
Cheers,
H.
>
> The resulting improvement is sometimes dramatic. Here's a test
> program:
>
> M<- matrix(seq(0,1,12000),200,60)
>
> print(system.time({for (i in 1:10000) S<- t(M)}))
> print(system.time({for (i in 1:10000) R<- t(S)}))
>
> v<- seq(0,2,12000)
>
> print(system.time({for (i in 1:100000) u<- t(v)}))
> print(system.time({for (i in 1:100000) w<- t(u)}))
>
> Here are the times on an Intel Linux system:
>
> R version 2.11.1: Modified version:
>
> user system elapsed user system elapsed
> 1.190 0.040 1.232 0.610 0.010 0.619
> user system elapsed user system elapsed
> 1.200 0.020 1.226 0.610 0.000 0.616
> user system elapsed user system elapsed
> 0.800 0.010 0.813 0.750 0.000 0.752
> user system elapsed user system elapsed
> 0.910 0.010 0.921 0.860 0.000 0.864
>
> Here are the times on a SPARC Solaris system:
>
> R version 2.11.1: Modified version:
>
> user system elapsed user system elapsed
> 18.643 0.041 18.685 2.994 0.039 3.033
> user system elapsed user system elapsed
> 18.574 0.041 18.616 3.123 0.039 3.163
> user system elapsed user system elapsed
> 3.803 0.271 4.075 3.868 0.296 4.163
> user system elapsed user system elapsed
> 4.184 0.273 4.457 4.238 0.302 4.540
>
> So with the modification, transpose for a 60x200 or 200x60 matrix is
> about a factor of two faster on the Intel system, and a factor of six
> faster on the SPARC system. There is little or no gain from the
> modification when transposing a row or column vector, however. (I
> think it must be that on these machines multiplies and divides do not
> take constant time, but are faster when, for instance, dividing by 1.)
>
> I've appended below the new version of the modified part of the
> do_transpose function in src/main/array.c.
>
> Radford Neal
>
> ----------------------------------------------------------------------
>
> PROTECT(r = allocVector(TYPEOF(a), len));
> switch (TYPEOF(a)) {
> case LGLSXP:
> case INTSXP:
> for (i = 0, j = 0; i<len; i += 1, j += nrow) {
> if (j>=len) j -= (len-1);
> INTEGER(r)[i] = INTEGER(a)[j];
> }
> case REALSXP:
> for (i = 0, j = 0; i<len; i += 1, j += nrow) {
> if (j>=len) j -= (len-1);
> REAL(r)[i] = REAL(a)[j];
> }
> break;
> case CPLXSXP:
> for (i = 0, j = 0; i<len; i += 1, j += nrow) {
> if (j>=len) j -= (len-1);
> COMPLEX(r)[i] = COMPLEX(a)[j];
> }
> break;
> case STRSXP:
> for (i = 0, j = 0; i<len; i += 1, j += nrow) {
> if (j>=len) j -= (len-1);
> SET_STRING_ELT(r, i, STRING_ELT(a,j));
> }
> break;
> case VECSXP:
> for (i = 0, j = 0; i<len; i += 1, j += nrow) {
> if (j>=len) j -= (len-1);
> SET_VECTOR_ELT(r, i, VECTOR_ELT(a,j));
> }
> break;
> case RAWSXP:
> for (i = 0, j = 0; i<len; i += 1, j += nrow) {
> if (j>=len) j -= (len-1);
> RAW(r)[i] = RAW(a)[j];
> }
> break;
> default:
> UNPROTECT(1);
> goto not_matrix;
> }
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
--
Hervé Pagès
Program in Computational Biology
Division of Public Health Sciences
Fred Hutchinson Cancer Research Center
1100 Fairview Ave. N, M2-B876
P.O. Box 19024
Seattle, WA 98109-1024
E-mail: hpages at fhcrc.org
Phone: (206) 667-5791
Fax: (206) 667-1319
More information about the R-devel
mailing list