x <- array(1:20, c(4, 5))
y <- array(1:5 * 100, c(1, 5))
z <- array(20:1, c(4, 5))
broadcaster(x) <- TRUE
broadcaster(y) <- TRUE
broadcaster(z) <- TRUE
x + y / z
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] 6.000000 17.50000 34.00000 63.00000 142.0000
#> [2,] 7.263158 19.33333 37.27273 71.14286 184.6667
#> [3,] 8.555556 21.28571 41.00000 81.66667 269.0000
#> [4,] 9.882353 23.38462 45.33333 96.00000 520.0000
#> broadcasterFunctions Overview
1 Introduction
The ‘broadcast’ package provides 6 main functionalities:
- Broadcasted Infix Operators
- broadcasted dimensional binding of arrays
- casting functions, that cast subset-groups of an array to a new dimension, cast nested lists to dimensional lists, and vice-versa.
- broadcasted generic pair-wise functions
- array typecasting with dimensions and names preserved
- simple linear algebra functions for statistics
This guide gives a brief overview of the functions provided by the ‘broadcast’ - package.
2 Broadcasted Infix Operators
Base comes with relational (==, !=, etc.), arithmetic (+, -, *, /, etc.), logical (&, |) and bit-wise (&, |) operators. ‘broadcast’ provides 2 ways to use these operators with broadcasting.
The first (and simple) way is to use the broadcaster() class, which comes with it’s own method dispatch for the above mentioned operators. This approach supports operator precedence, and for the average user, this is sufficient.
For example:
The second way is to use the large set ofbc. - functions. These offer much greater control and more operators than the previous method, and has less risk of running into conflicting methods. But it does not support operator precedence.
For example:
x <- array(1:20, c(4, 5))
y <- array(1:5 * 100, c(1, 5))
print(x)
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] 1 5 9 13 17
#> [2,] 2 6 10 14 18
#> [3,] 3 7 11 15 19
#> [4,] 4 8 12 16 20
print(y)
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] 100 200 300 400 500
bc.i(x, y, "gcd") # calculate greatest common divisor between x and y
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] 1 5 3 1 1
#> [2,] 2 2 10 2 2
#> [3,] 1 1 1 5 1
#> [4,] 4 8 12 16 20
2.1 Derived operators
There is no overload for xor(), as xor() is defined using the existing base relational and logical (or bit-wise, for type of raw) operators.
There is also no overload for the %d==%, %d!=%, etc. operators, as they too are defined using the existing base relational and logical operators.
2.2 Overloaded operators vs bc.* functions
Overloading the operators is primarily useful for ensuring mathematically correct operator precedence, and to reduce the amount of typing.
However, the many bc.* functions provide much greater control than the simple operators can provide.
For example:
The & and | operators provide logical AND and OR, respectively for all atomic types except type raw; for type raw, the & and | operators provide BIT-WISE AND and OR, respectively.
But what if you want to use logical AND/OR for raw arrays, or bit-wise AND/OR for integer arrays?
When using the overloaded operators, using logical AND/OR for type raw necessitates converting the vector/array to type logical, thus making a copy.
With the bc.*() functions, this is not necessary.
Want to use logical AND/OR? Use bc.b(), it supports several types including raw.
Want to use bit-wise AND/OR? Use bc.bit(), it supports not only raw, but integer as well.
The bc. functions also provides far more operations than the simple symbols can provide.
Like calculating the greatest common divisors between integers, string edit distance, and more.
3 Binding arrays
‘broadcast’ provides the bind_array() function. This binds arrays (including matrices) along any arbitrary dimension. It allows for dimensional broadcasting, and returns an array.
3.1 Why another array binding function
There is already a famous, battle-tested function for binding arrays, namely the abind() function from the fantastic package of the same name. So why does ‘broadcast’ provide another array binding function?
Well, as great as abind::abind() is, there are some issues with it, and the bind_array() function from ’broadcast` attempts (and in my humble opinion succeeds) to provide a better alternative:
- bind_array() is faster and more memory efficient.
abind()does not support broadcasting. bind_array() does support broadcasting.abind()does not support recursive arrays (i.e. arrays of typelist). When binding recursive arrays,abind()will attempt to unlist it, even when it does not make sense, ruining the structure of the array. bind_array() fully supports recursive arrays, as well as arrays of all atomic types.abind()has somewhat confusing mechanisms for giving dimension names to the output. bind_array() has more streamlined naming arguments.
bind_array() uses a similar API to that of abind::abind(), and provides similar features like binding arrays before the first dimension (using along = 0) or after the last dimension.
4 Casting
‘broadcast’ provides several “casting” functions. These can facility complex forms of broadcasting that would normally not be possible.
But these “casting” functions also have their own merit, beside empowering complex broadcasting.
The following casting functions are currently available:
acast(): casts group-based subset of an array into a new dimension.
Useful for, for example, computing grouped broadcasted operations.cast_hier2dim(): casts a nested/hierarchical list into a dimensional list (i.e. recursive array).
Useful because one cannot broadcast through nesting, but one can broadcast along dimensions.cast_dim2hier(): casts a dimensional list into a nested/hierarchical list; the opposite of cast_hier2dim.
cast_shallow2atomic(): casts a (dimensional) shallow (i.e. non-nested) list into an atomic vector or array.
Useful because atomic vectors/arrays have access to many vectorized (broadcasted) operations that may not be available for vectors/arrays of type list.cast_dim2flat(): casts a dimensional list into a flattened list, but with names that indicate their original dimensional positions.
Mostly useful for printing or summarizing dimensional lists.dropnests(): drop redundant nesting in lists; mostly used for facilitating the above casting functions.
5 General Broadcasted methods
‘broadcast’ provides the bcapply() method, which is a broadcasted apply-like function.
‘broadcast’ also provides the bc_ifelse() and bc_strrep()methods, which are broadcasted versions of ifelse() and strrep(), respectively.
6 Type-casting
‘broadcast’ offers type-casting functions. Unlike base R’s type-casting functions (as.logical(), as.integer(), etc.), the type-casting functions from ‘broadcast’ preserve names and dimensions. See typecast.
7 Simple linear algebra functions for statistics
‘broadcast’ provides a small set of simple linear algebra functions for usage in statistics. See linear_algebra_stats.
8 Supported Structures
The functions in the ‘broadcast’ package only support S3 structures. S4 structures, Reference Classes, and so on are not supported.
9 Writing Methods for Custom Classes
Almost all functions provided by ‘broadcast’ are S3 or S4 generics.
Users and package authors can write methods for these generics to support custom classes (like custom handling of class-related attributes).