Skip to contents

In base R, arithmetic and other binary operations between a matrix or array and a vector don't let the user control how the latter should be recycled: it's always recycled along the first dimension of the matrix or array. This has led users to use various tricks when they need recycling along the second dimension (a.k.a. "horizontal recycling"), like the popular "double-transposition" trick: t(t(m) / colSums(m)). However this is not only inelegant, it's also inefficient.

as_tile() is meant to address that.

It also allows arithmetic and other binary operations between two arrays of distinct dimensions (rejected as "non-conformable" by arithmetic operations in base R), typically between a small one (the tile) and a bigger one, as long as their geometries are compatible.

Usage

as_tile(x, along=1L, dim=NULL)

Arguments

x

An array-like object or a vector.

along

Can only be used when x is a vector. Must be a single positive integer indicating the "orientation" of the tile to be created, that is, the dimension along which x will be recycled by arithmetic operations and other binary operations.

dim

NULL or the dimensions (supplied as an integer vector) of the tile to be created.

Value

A tile object (tile is an extension of array).

See also

Examples

## ---------------------------------------------------------------------
## 2D EXAMPLES
## ---------------------------------------------------------------------
m0 <- matrix(1:54, nrow=6)
x <- c(-1, 0, 100)

## Arithmetic operations in base R recycle 'x' along the first dimension
## of the matrix ("vertical recycling"):
m0 * x
#>      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
#> [1,]   -1   -7  -13  -19  -25  -31  -37  -43  -49
#> [2,]    0    0    0    0    0    0    0    0    0
#> [3,]  300  900 1500 2100 2700 3300 3900 4500 5100
#> [4,]   -4  -10  -16  -22  -28  -34  -40  -46  -52
#> [5,]    0    0    0    0    0    0    0    0    0
#> [6,]  600 1200 1800 2400 3000 3600 4200 4800 5400

## To recycle 'x' along the second dimension of the matrix ("horizontal
## recycling"), we turn it into an "horizontal" tile:
t <- as_tile(x, along=2)
t
#> An object of class "tile"
#>      [,1] [,2] [,3]
#> [1,]   -1    0  100

m0 * t
#>      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
#> [1,]   -1    0 1300  -19    0 3100  -37    0 4900
#> [2,]   -2    0 1400  -20    0 3200  -38    0 5000
#> [3,]   -3    0 1500  -21    0 3300  -39    0 5100
#> [4,]   -4    0 1600  -22    0 3400  -40    0 5200
#> [5,]   -5    0 1700  -23    0 3500  -41    0 5300
#> [6,]   -6    0 1800  -24    0 3600  -42    0 5400

## The above produces the same result as the double-transposition trick
## but is more efficient (and also makes code easier to read):
stopifnot(identical(m0 * t, t(t(m0) * x)))

## A less artificial example:
cs0 <- colSums(m0)
m <- m0 / as_tile(cs0, along=2)

stopifnot(all.equal(colSums(m), rep(1, ncol(m))))  # sanity check

## Using an arbitrary 2D tile:

t <- m0[1:2, 1:3]
t
#>      [,1] [,2] [,3]
#> [1,]    1    7   13
#> [2,]    2    8   14
## Unfortunately arithmetic operations in base R refuse to operate on
## arrays that don't have the same dimensions:
if (FALSE) { # \dontrun{
  m0 / t  # ERROR! (non-conformable arrays)
} # }

## Wrapping 't' in a tile object makes this work:
m0 / as_tile(t)
#>      [,1]     [,2]     [,3] [,4]     [,5]     [,6] [,7]     [,8]     [,9]
#> [1,]    1 1.000000 1.000000   19 3.571429 2.384615   37 6.142857 3.769231
#> [2,]    1 1.000000 1.000000   10 3.250000 2.285714   19 5.500000 3.571429
#> [3,]    3 1.285714 1.153846   21 3.857143 2.538462   39 6.428571 3.923077
#> [4,]    2 1.250000 1.142857   11 3.500000 2.428571   20 5.750000 3.714286
#> [5,]    5 1.571429 1.307692   23 4.142857 2.692308   41 6.714286 4.076923
#> [6,]    3 1.500000 1.285714   12 3.750000 2.571429   21 6.000000 3.857143

## ---------------------------------------------------------------------
## 3D EXAMPLES
## ---------------------------------------------------------------------
## Note that colSums() supports multidimensional arrays. In this case
## the user can use the 'dims' argument to control how the array should
## be sliced into "columns". See '?base::colSums' for the details.

a <- array(runif(300), dim=c(10, 5, 6))

## Using 'dims=2' indicates that the columns are the 2D slices obtained
## by slicing the array along its 3rd dimension. With this slicing, each
## column is a 10 x 5 matrix.
cs2 <- colSums(a, dims=2)
cs2  # vector of length 6 (one value per 2D slice)
#> [1] 25.67506 23.10812 28.01204 24.69427 25.85462 24.16648

t <- as_tile(cs2, along=3)
a / t
#> , , 1
#> 
#>              [,1]         [,2]        [,3]        [,4]        [,5]
#>  [1,] 0.004905041 0.0313820275 0.013504781 0.034340070 0.031273211
#>  [2,] 0.008819007 0.0030672134 0.023402695 0.028673615 0.034067962
#>  [3,] 0.018539037 0.0188968499 0.036230123 0.009703260 0.020476150
#>  [4,] 0.024183572 0.0061101572 0.035186878 0.032761256 0.037393265
#>  [5,] 0.032485544 0.0328140273 0.003701757 0.021304701 0.011897596
#>  [6,] 0.025992551 0.0205676668 0.025613195 0.005299261 0.015897284
#>  [7,] 0.012352795 0.0005404554 0.021111480 0.011601741 0.019647763
#>  [8,] 0.025103104 0.0309366446 0.003090926 0.025802346 0.009830089
#>  [9,] 0.035149483 0.0381608824 0.022512773 0.007216479 0.000637245
#> [10,] 0.003971493 0.0382604699 0.008932281 0.022494866 0.014156928
#> 
#> , , 2
#> 
#>              [,1]        [,2]        [,3]        [,4]         [,5]
#>  [1,] 0.023408212 0.032013481 0.030976016 0.008872240 0.0017316806
#>  [2,] 0.024658085 0.036715993 0.012625268 0.003163934 0.0382629819
#>  [3,] 0.010510984 0.010414673 0.003472925 0.030776679 0.0088235694
#>  [4,] 0.009080977 0.022375306 0.006696857 0.022659372 0.0083567068
#>  [5,] 0.020014801 0.042445576 0.040491944 0.014215597 0.0358868522
#>  [6,] 0.009445305 0.015871686 0.023190731 0.039719416 0.0005240762
#>  [7,] 0.027874263 0.017434323 0.033030399 0.007488815 0.0371117158
#>  [8,] 0.012258396 0.019354319 0.022418431 0.010978887 0.0051842433
#>  [9,] 0.013212255 0.005340906 0.027456543 0.027242309 0.0367408961
#> [10,] 0.034816406 0.026625446 0.001295415 0.014497050 0.0322370546
#> 
#> , , 3
#> 
#>              [,1]       [,2]        [,3]        [,4]        [,5]
#>  [1,] 0.001948557 0.02856611 0.011266349 0.010631152 0.028324850
#>  [2,] 0.026138822 0.02758221 0.033262982 0.004908784 0.015541477
#>  [3,] 0.032675188 0.01170009 0.030916963 0.004226368 0.034859926
#>  [4,] 0.021075356 0.03440793 0.008024639 0.004072719 0.019072370
#>  [5,] 0.019220120 0.02982018 0.022671785 0.004484221 0.020914476
#>  [6,] 0.006163747 0.03304549 0.029655188 0.005361134 0.003804231
#>  [7,] 0.026391863 0.03542315 0.028097012 0.021148515 0.031938430
#>  [8,] 0.008511148 0.03180742 0.026509085 0.032851818 0.028484426
#>  [9,] 0.009836137 0.01932545 0.002237154 0.007912922 0.019250926
#> [10,] 0.017782804 0.01107234 0.032161136 0.022025014 0.022889834
#> 
#> , , 4
#> 
#>              [,1]        [,2]        [,3]         [,4]        [,5]
#>  [1,] 0.005586718 0.022945555 0.012158407 0.0067547344 0.017493634
#>  [2,] 0.011761964 0.007327147 0.027619932 0.0022988334 0.027918303
#>  [3,] 0.002529781 0.036250662 0.010508280 0.0349325524 0.013548310
#>  [4,] 0.006043344 0.038171599 0.005111655 0.0205060362 0.035833769
#>  [5,] 0.004125217 0.001665289 0.022182446 0.0343519157 0.039221271
#>  [6,] 0.038906949 0.033747213 0.038420071 0.0011768958 0.007884861
#>  [7,] 0.011035337 0.014176877 0.002164358 0.0402784480 0.036875389
#>  [8,] 0.015000204 0.031158541 0.012522312 0.0288194156 0.009289926
#>  [9,] 0.031394000 0.020684723 0.007403017 0.0003554224 0.010057287
#> [10,] 0.038474964 0.037374334 0.015329147 0.0353502877 0.035272666
#> 
#> , , 5
#> 
#>              [,1]        [,2]         [,3]        [,4]       [,5]
#>  [1,] 0.026177998 0.008248017 0.0008341776 0.010643768 0.03763645
#>  [2,] 0.033850226 0.006680275 0.0256754885 0.014674892 0.01370559
#>  [3,] 0.022480395 0.008466281 0.0385737968 0.038205423 0.03048280
#>  [4,] 0.028457592 0.026971177 0.0386170017 0.002105223 0.02303327
#>  [5,] 0.023587985 0.017854163 0.0294484226 0.006122665 0.02668107
#>  [6,] 0.022971921 0.017822885 0.0117014790 0.005083239 0.02228533
#>  [7,] 0.011198484 0.030615857 0.0324622404 0.034273374 0.03094888
#>  [8,] 0.017246720 0.001433584 0.0160490507 0.013622107 0.01679579
#>  [9,] 0.009529030 0.037539444 0.0060242378 0.002891859 0.02435357
#> [10,] 0.003982721 0.021416922 0.0114698328 0.028069420 0.03099787
#> 
#> , , 6
#> 
#>              [,1]        [,2]         [,3]        [,4]        [,5]
#>  [1,] 0.020988167 0.003358426 0.0187098136 0.038191692 0.026030911
#>  [2,] 0.012139254 0.027485065 0.0241590253 0.029499412 0.014044658
#>  [3,] 0.015681482 0.020468527 0.0167251797 0.038019307 0.007021392
#>  [4,] 0.033874197 0.018380591 0.0002364385 0.001956707 0.013529513
#>  [5,] 0.020244401 0.033606924 0.0053315623 0.021603269 0.012742241
#>  [6,] 0.040669675 0.035812935 0.0061836003 0.024161318 0.008351151
#>  [7,] 0.036576751 0.007860447 0.0165381814 0.014215748 0.039023867
#>  [8,] 0.022030294 0.021839530 0.0160825688 0.010802439 0.002915852
#>  [9,] 0.007730449 0.016434692 0.0257347023 0.031703360 0.027747372
#> [10,] 0.027079695 0.029374078 0.0122446292 0.041230229 0.003628278
#> 

stopifnot(all.equal(colSums(a / t, dims=2), rep(1, 6)))  # sanity check

## By default (i.e. when 'dims=1') the array is considered to be made
## of 5*6 columns of length 10.
cs1 <- colSums(a)
cs1  # 5 x 6 matrix
#>          [,1]     [,2]     [,3]     [,4]     [,5]     [,6]
#> [1,] 4.916816 4.281466 4.754868 4.071059 5.157559 5.727804
#> [2,] 5.667421 5.282326 7.360174 6.013102 4.577524 5.186640
#> [3,] 4.962653 4.659858 6.297171 3.788585 5.451594 3.430328
#> [4,] 5.114411 4.150550 3.294850 5.057992 4.025356 6.075055
#> [5,] 5.013762 4.733925 6.304976 5.763529 6.642584 3.746656

t <- as_tile(cs1, dim=c(1L, dim(cs1)))
a / t
#> , , 1
#> 
#>             [,1]       [,2]       [,3]       [,4]        [,5]
#>  [1,] 0.02561358 0.14216970 0.06986910 0.17239199 0.160147542
#>  [2,] 0.04605186 0.01389537 0.12107751 0.14394559 0.174459234
#>  [3,] 0.09680877 0.08560822 0.18744222 0.04871173 0.104856679
#>  [4,] 0.12628390 0.02768079 0.18204483 0.16446612 0.191487837
#>  [5,] 0.16963586 0.14865708 0.01915162 0.10695260 0.060926613
#>  [6,] 0.13573018 0.09317751 0.13251388 0.02660304 0.081408687
#>  [7,] 0.06450491 0.00244842 0.10922355 0.05824238 0.100614582
#>  [8,] 0.13108559 0.14015199 0.01599139 0.12953141 0.050339080
#>  [9,] 0.18354665 0.17287988 0.11647336 0.03622774 0.003263279
#> [10,] 0.02073869 0.17333104 0.04621256 0.11292740 0.072496467
#> 
#> , , 2
#> 
#>             [,1]       [,2]       [,3]       [,4]        [,5]
#>  [1,] 0.12633988 0.14004655 0.15360933 0.04939607 0.008453005
#>  [2,] 0.13308574 0.16061822 0.06260840 0.01761516 0.186776450
#>  [3,] 0.05673037 0.04556015 0.01722215 0.17134871 0.043071263
#>  [4,] 0.04901227 0.09788328 0.03320955 0.12615573 0.040792326
#>  [5,] 0.10802480 0.18568292 0.20079858 0.07914513 0.175177640
#>  [6,] 0.05097863 0.06943247 0.11500228 0.22113727 0.002558219
#>  [7,] 0.15044425 0.07626840 0.16379696 0.04169387 0.181156674
#>  [8,] 0.06616158 0.08466764 0.11117247 0.06112479 0.025306302
#>  [9,] 0.07130979 0.02336439 0.13615634 0.15167116 0.179346559
#> [10,] 0.18791270 0.11647599 0.00642393 0.08071211 0.157361563
#> 
#> , , 3
#> 
#>             [,1]       [,2]        [,3]       [,4]       [,5]
#>  [1,] 0.01147941 0.10871960 0.050116701 0.09038355 0.12584295
#>  [2,] 0.15398990 0.10497497 0.147965492 0.04173333 0.06904839
#>  [3,] 0.19249716 0.04452928 0.137529573 0.03593158 0.15487729
#>  [4,] 0.12415984 0.13095294 0.035696429 0.03462530 0.08473560
#>  [5,] 0.11323021 0.11349243 0.100852106 0.03812379 0.09291980
#>  [6,] 0.03631207 0.12576762 0.131916749 0.04557910 0.01690161
#>  [7,] 0.15548062 0.13481676 0.124985434 0.17979969 0.14189753
#>  [8,] 0.05014116 0.12105565 0.117921773 0.27929841 0.12655192
#>  [9,] 0.05794698 0.07355060 0.009951649 0.06727379 0.08552890
#> [10,] 0.10476265 0.04214013 0.143064093 0.18725148 0.10169601
#> 
#> , , 4
#> 
#>             [,1]        [,2]       [,3]        [,4]       [,5]
#>  [1,] 0.03388797 0.094231507 0.07924936 0.032978150 0.07495278
#>  [2,] 0.07134583 0.030090714 0.18002868 0.011223427 0.11961804
#>  [3,] 0.01534517 0.148872169 0.06849371 0.170548667 0.05804874
#>  [4,] 0.03665777 0.156760965 0.03331813 0.100115133 0.15353245
#>  [5,] 0.02502277 0.006838915 0.14458676 0.167713866 0.16804645
#>  [6,] 0.23600211 0.138591148 0.25042475 0.005745873 0.03378327
#>  [7,] 0.06693824 0.058220796 0.01410744 0.196648544 0.15799534
#>  [8,] 0.09098837 0.127960136 0.08162132 0.140702942 0.03980338
#>  [9,] 0.19043000 0.084946850 0.04825339 0.001735253 0.04309119
#> [10,] 0.23338177 0.153486801 0.09991647 0.172588145 0.15112836
#> 
#> , , 5
#> 
#>             [,1]        [,2]        [,3]       [,4]       [,5]
#>  [1,] 0.13122917 0.046586175 0.003956153 0.06836427 0.14649056
#>  [2,] 0.16968972 0.037731307 0.121768039 0.09425594 0.05334563
#>  [3,] 0.11269325 0.047818963 0.182939288 0.24539109 0.11864676
#>  [4,] 0.14265667 0.152337699 0.183144191 0.01352172 0.08965130
#>  [5,] 0.11824555 0.100843286 0.139661478 0.03932550 0.10384948
#>  [6,] 0.11515724 0.100666622 0.055495192 0.03264933 0.08674015
#>  [7,] 0.05613751 0.172923454 0.153954748 0.22013578 0.12046088
#>  [8,] 0.08645706 0.008097123 0.076113895 0.08749396 0.06537346
#>  [9,] 0.04776861 0.212029029 0.028570425 0.01857424 0.09479025
#> [10,] 0.01996521 0.120966342 0.054396591 0.18028817 0.12065154
#> 
#> , , 6
#> 
#>             [,1]       [,2]        [,3]        [,4]       [,5]
#>  [1,] 0.08855230 0.01564816 0.131809653 0.151926021 0.16790319
#>  [2,] 0.05121738 0.12806313 0.170199063 0.117348253 0.09059011
#>  [3,] 0.06616258 0.09537047 0.117828011 0.151240276 0.04528901
#>  [4,] 0.14292044 0.08564200 0.001665696 0.007783754 0.08726734
#>  [5,] 0.08541424 0.15658715 0.037560576 0.085937505 0.08218932
#>  [6,] 0.17159160 0.16686577 0.043563139 0.096113386 0.05386615
#>  [7,] 0.15432293 0.03662475 0.116510618 0.056550047 0.25170967
#>  [8,] 0.09294919 0.10175849 0.113300851 0.042971954 0.01880767
#>  [9,] 0.03261595 0.07657534 0.181299624 0.126115526 0.17897462
#> [10,] 0.11425339 0.13686475 0.086262769 0.164013279 0.02340292
#> 

## Sanity check:
stopifnot(all.equal(colSums(a / t), matrix(1, nrow=5, ncol=6)))