A Mathematical View on Broadcasting

The Broadcasting mechanism in NumPy is usually introduced by explaining the relevant rules.

Another perspective is to look at the topic from a mathematical viewpoint.

The initial example is the addition of a function and a constant.

$$f:= \sin{} + C$$

The authors argue that this is not proper mathematical notation and resolve it by defining a broadcast function for the constant.

$$\overline{C}:= C \thinspace \text{ for all } x$$

The result is the addition of two functions, the sine function and a constant function.

$$f:= \sin{} + \overline{C}$$

Which could also be written as

$$f:= \sin(x) + \overline{C}(x)$$

It is not quite clear to me what the intention of the authors was to leave out the function parameters. I assume they were omitted to make it clear that what being talked about is the mathematical objects rather than specific numerical outputs.

The question whether a 1×1 matrix should be considered a scalar is a similar topic with regard to notation.

A perspective that tries to bring together rigour and practicality:

A 1×1 matrix is not a scalar–it is an element of a matrix algebra. However, there is sometimes a meaningful way of treating a 1×1 matrix as though it were a scalar, hence in many contexts it is useful to treat such matrices as being "functionally equivalent" to scalars. It might be a little sloppy to do so, but a little bit of sloppiness is forgivable if it introduces no confusion or ambiguity, and if it aids brevity or clarity of exposition.

With the objection:

We can cast any real \(x\) to the constant function on \(\mathbb{R}\) whose value is always \(x\), but are reals and constant functions "functionally equivalent"? Well... no, a function can be evaluated at a point, while a real has no such feature.

And the remark:

Okay I guess the added words "in the right context", in the right context, would evade my objection. Namely, if we interpret it to mean that scalars and 1-by-1 matrices, when used in certain specific ways, can be treated as functionally equivalent, then I agree. =)

Handling of a 1x1 array in NumPy:

>>> from numpy import array, reshape
>>> a = reshape(array(1), (1,1))
>>> type(a)
<class 'numpy.ndarray'>
>>> a.shape
(1, 1)
>>> type(a[0,0])
<class 'numpy.int64'>
>>> type(a.item())
<class 'int'>

Similar for a zero-dimensional array:

>>> a = array(1)
>>> type(a)
<class 'numpy.ndarray'>
>>> a.shape
>>> type(a[()])
<class 'numpy.int64'>
>>> type(a.item())
<class 'int'>

Interesting Stuff

Me writing about Tech stuff