Saturday 14 September 2013

Dynamo - Max using Reduce

Wow, following Zach Kron’s very kind article over at Buildz, I guess I’d better get posting. Here’s a quick study using Reduce, one of the List Processing nodes I talked about last time. I’ve had a couple of comments suggesting that Reduce is a bit hard to understand, which implies I didn’t explain it very well. So here goes for a more detailed explanation. Or perhaps I should just stop while I’m behind.

There are lots of ways to find the maximum element in a list. This one uses Reduce.

image

Reduce takes a function, an initial value, and a list. In this case, my function is a custom node called Max, which returns the higher of two input numbers.

So I feed my list into Reduce, and set the initial value (the a input on the Reduce node) to the First value in the list. This way, I know that my final output will be a value from the list. (You might think you could just use zero as an initial value, but what would happen if all the items in the list were negative numbers?)

So Reduce takes the initial number (I tend to think of this as ‘the number it has in its hand’), and feeds it to Max alongside the first item from the list. Obviously, they’re both the same number, so Max outputs that number. Then Reduce takes that number and feeds it to Max alongside the second item in the list. And so on. At each stage, if the number from the list is higher than the number that Reduce has in its hand already, then Max gives that higher number to Reduce. And after Reduce has walked through all the items in the list, the number it has in its hand is the highest number in the list.

Does that make sense?

Here’s the definition of Max:

image

It’d be trivial to change this into a Min node that returned the smaller of the two numbers. Then you could plug that into Reduce to extract the Minimum value from a list.

So, Reduce steps through each item in a list and ‘has a value in its hand’. Your function needs to take those two values as inputs, and give an output value back to Reduce. The eventual output from Reduce is the output from the function when it’s invoked with the last item in the list and the value that Reduce has in its hand at that point.

Clear as mud.

Tuesday 3 September 2013

Dynamo - List Processing

Many Dynamo layouts need to process lists. Lacing is one option, and recursion is another, but sometimes the built-in list-processing nodes Map, Reduce and Combine are just what you need.

Map applies a function to each element of a list and generates a list of the results. The function needs to have one unconnected input, and is called once for each element in the list: The element is fed into the unconnected input, and the function’s output is appended to Map’s output-list.

This is an example that doubles each element of a list:

image

You’d probably use Lacing for this in a real-world layout, but Map will work with custom nodes, whereas Lacing only works with Lacing-enabled built-in nodes at the moment. I’ll often create a custom node to ‘wrap’ a bunch of nodes, just to surface the single input that Map needs.

Combine is like Map, but takes two or more input lists. The number of unconnected inputs on the function needs to match the number of lists in the Combine. Just like Map, the output from Combine is a list of the outputs of the individual function calls.

And here’s an example using Combine to generate a series of Square numbers:

image

The same comment about Lacing applies…

In contrast to Map and Combine, Reduce just produces a single value, not a list. It’s inputs are a list, a function, and an initial value. The function needs to take one list element and the initial value, and output a single value. That value is then fed into the function along with the next element in the list. And the output from the Reduce node is the output from the last function-call.

As an example, here is Factorial implemented with Reduce:

image

Note that there’s nothing to stop you using a list as your ‘single input value’, so you can use Reduce to implement lots of other list-processing functions. And of course your function can inspect and edit the contents of the ‘single input value’ at each stage. Reduce is really very versatile.

Another example, generating a Fibonacci series using Reduce:

image

Which uses this Fibonacci custom node:

image

It’s a bit inelegant in places, but it does the job.

For the code-geeks, it does look as though the Reduce node in Dynamo is actually implemented as Fold in the underlying F#, so the name might change in future Dynamo releases.