Last year we released Version 13.0 of the Wolfram Language. Here are the updates in listability since then, including the latest features in 13.1.
Beyond Listability: Introducing Threaded
From the very beginning of Mathematica and the
Wolfram Language we’ve had the concept of listability: if you add two lists, for example, their corresponding elements will be added:
It’s a very convenient mechanism, that typically does exactly what you’d want. And for 35 years we haven’t really considered extending it. But if we look at code that gets written, it often happens that there are parts that basically implement something very much like listability, but slightly more general. And in
Version 13.1 we have a new symbolic construct,
Threaded, that effectively allows you to easily generalize listability.
Consider:
This uses ordinary listability, effectively computing:
But what if you want instead to “go down a level” and thread {x,y} into the lowest parts of the first list? Well, now you can use
Threaded to do that:
On its own,
Threaded is just a symbolic wrapper:
But as soon as it appears in a function—like
Plus—that has attribute
Listable, it specifies that the listability should be applied after what’s specified inside
Threaded is “threaded” at the lowest level.
Here’s another example. Create a list:
How should we then multiply each element by {1,–1}? We could do this with:
But now we’ve got
Threaded, and so instead we can just say:
You can give
Threaded as an argument to any listable function, not just
Plus and
Times:
You can use
Threaded and ordinary listability together:
You can have several
Threadeds together as well:
Threaded, by the way, gets its name from the function
Thread, which explicitly does “threading”, as in:
By default,
Threaded will always thread into the lowest level of a list:
Here’s a “real-life” example of using
Threaded like this. The data in a 3D color image consists of a rank-3 array of triples of RGB values:
This multiplies every RGB triple by {0,1,2}:
Most of the time you either want to use ordinary listability that operates at the top level of a list, or you want to use the default form of
Threaded, that operates at the lowest level of a list. But
Threaded has a more general form, in which you can explicitly say what level you want it to operate at.
Here’s the default case:
Here’s level 1, which is just like ordinary listability:
And here’s threading into level 2:
Threaded provides a very convenient way to do all sorts of array-combining operations. There’s additional complexity when the object being “threaded in” itself has multiple levels. The default in this case is to align the lowest level in the thing being threaded in with the lowest level of the thing into which it’s being threaded:
Here now is “ordinary listability” behavior:
For the arrays we’re looking at here, the default behavior is equivalent to:
Sometimes it’s clearer to write this out in a form like
which says that the first level of the array inside the
Threaded is to be aligned with the second level of the outside array. In general, the default case is equivalent to –1 → –1, specifying that the bottom level of the array inside the
Threaded should be aligned with the bottom level of the array outside.