| operator | action | functions like |
|---|---|---|
| + | add | bc.d |
| - | substract | bc.d |
| * | multiply | bc.d |
| / | divide | bc.d |
| ^ | raise to power | bc.d |
| %/% | floored integer divide | bc.i |
| %% | modulo | bc.i |
Technical Details
1 Introduction
This page gives some brief details on some of the more technical aspects of the broadcast package. This page will probably not be of much interest for most users; this page is presented nonetheless for the sake of completeness and transparency.
2 Overload method tables
The overloaded operators from the âbroadcastâ package attempts to mimic the base operators accurately, except that broadcasting is used (obviously).
The following tables overview the behaviour of the operators.
2.1 Regular Arithmetic operators
If both sides of the operators given here are numeric or logical, the following holds:
2.2 Complex Arithmetic operators
If at least one of the arguments of the operators given here are complex, the following holds:
| operator | action | functions like |
|---|---|---|
| + | add | bc.cplx |
| - | substract | bc.cplx |
| * | multiply | bc.cplx |
| / | divide | bc.cplx |
2.3 Logical Operators
If both sides of the operators given here are complex, numeric or logical, the following holds:
| operator | action | functions like |
|---|---|---|
| & | and | bc.b |
| | | or | bc.b |
2.4 Bit-wise operators
If both sides of the operators given here are type of raw, the following holds:
| operator | action | functions like |
|---|---|---|
| & | bit-wise and | bc.bit |
| | | bit-wise or | bc.bit |
2.5 Relational operators
For relational operators, âbroadcastâ first finds the âhighestâ (or most complex) atomic type of both sides, coerces both sides to said type, and then performs the broadcasted relational operation. Recursive types are not supported.
The types, from complex to simple, are: character, complex, numeric (also known as double), integer, logical, and raw.
3 Compatibility with Custom Methods
Consider a classed vector like the following:
x <- 1:10
class(x) <- "someclass"
print(class(x))
#> [1] "someclass"Setting a vector or array as a âbroadcasterâ using the broadcaster()<- function, will add the âbroadcasterâ class attribute;
but note that the âbroadcasterâ class will be placed last in the class attribute:
broadcaster(x) <- TRUE
print(class(x))
#> [1] "someclass" "broadcaster"Notice how the âbroadcasterâ class comes after the âsomeclassâ class.
Letâs make a quick ân dirty (and not at all smart) + method for âsomceclassâ, which will just print some text:
`+.someclass` <- function(e1, e2) {print("someclass method called")}What will happen? Will the + method for the broadcaster be called, or the + method for âsomeclassâ?
Well, since the âbroadcasterâ class is intentionally placed last, operator methods for the overriding classes will always âwinâ over the âbroadcasterâ class. In this case, if there are methods for the base operators (such as +, -, etc.) for the âsomeclassâ class, the method for âsomeclassâ will be called, rather than the broadcaster method:
y <- array(1:10, c(1, 10))
class(y) <- "someclass"
broadcaster(y) <- TRUE
x + y
#> [1] "someclass method called"
#> [1] "someclass method called"Notice how the + method for âsomeclassâ is called, rather than the + method for the broadcaster.
This ensures compatibility with custom classes.
After all, some classes may not be intended to be broadcasted, or they may not be compatible with the base âRâ way of arithmetic (which is what âbroadcastâ mimics), or they may need careful handling of attributes.
Authors of these custom classes can make their methods use broadcasting if a broadcaster vector/array is detected, if they so choose; only they know what is appropriate for their classes and what isnât.
4 Pre-processing dimensions for broadcasting
Before broadcasting occurs in the bc.* methods and the infix operators, the dimensions of the involved arrays are pre-processed internally to simplify the dimensions. Although this pre-processing increases the overload of the broadcasting methods a bit, it also improves the speed of iterating over the array elements.
The pre-processing of the dimensions consists of the following steps:
- Normalizing dimensions so that they get the same size.
- Nullifying dimensions if the dimensions are not necessary (for example if no actual broadcasting will occur).
- Dropping dimensional elements that are equal to
1in both arrays. - Merging dimensions that can be merged to reduce the number of dimensions without changing the order of the array elements and without overflowing the maximum dimension sizes (
2^31 - 1). For example, ifxhas dimensions{1, 10, 10, 1}andyhas dimensions{10, 1, 1, 10}, these dimensions can be merged to become{1, 100, 1}forxand{10, 1, 10}fory.
Pre-processing the dimensions does not affect the actual arrays involved in the operation itself, and neither is any copy made of the involved arrays. Moreover, the dimensions, dimension names, and other relevant attributes will still be correct in the resulting output.
After pre-processing, the âdimensional modeâ of the simplified arrays is determined. The following modes are available:
- Vector mode: This mode is used when no actual broadcasting occurs, and thus the arrays can be treated as dimensionless vectors.
- Outer mode: This mode is used when broadcasting the simplified dimensions constitute a simple outer operation.
- Sandwich mode: This mode is used when the broadcasted operation involves a array and a (directional) vector, where all dimensions of the array are greater than or equal to the dimensions of the vector. Note that a directional vector is an array where (after simplification) one dimension is greater than 1, and all other dimensions are equal to 1.
- General mode: This mode is used for general broadcasting, that cannot be simplified to any of the above cases.