When I write programs, I have a much greater propensity for phrasing conditions, constraints, and conditionals as mathematical expressions, as opposed to combinations of ifs, loops, or boolean logic. Of course, this is directly attributable, in my opinion, to the fact that I started out as a mathematician, and that all my earliest formative experiences with computation were delivered in an environment of pure mathematics.

I tend to conceptualize constructing an expression to generate a sequence as just as natural, and sometimes more efficacious, approach as is writing a loop. The most basic example of one of these is using the equation a = 1 - a to toggle the variable a between 1 and 0. Basically, it's analogous to the inversion operation. All logic functions have an algebraic function equivalent when phrased int terms of 1s and 0s. For instance, AND can be expressed as a∙b for two inputs a and b.

However, there's much more to this than just converting logical expressions into mathematical formulae. Another way of looking at that 1-a operation is to consider it as a descriptor for a function which produces a cyclical output: f(0) = 1; f(1) = 0. Naturally, we can extend this to functions which have longer cycles to generate. Take for instance the function:

I tend to conceptualize constructing an expression to generate a sequence as just as natural, and sometimes more efficacious, approach as is writing a loop. The most basic example of one of these is using the equation a = 1 - a to toggle the variable a between 1 and 0. Basically, it's analogous to the inversion operation. All logic functions have an algebraic function equivalent when phrased int terms of 1s and 0s. For instance, AND can be expressed as a∙b for two inputs a and b.

However, there's much more to this than just converting logical expressions into mathematical formulae. Another way of looking at that 1-a operation is to consider it as a descriptor for a function which produces a cyclical output: f(0) = 1; f(1) = 0. Naturally, we can extend this to functions which have longer cycles to generate. Take for instance the function:

This may seem like a fairly random one to pick, but it's been chosen very carefully. If you select x =1, you will find that f(1) = 4, precisely. Then, f(4) = 5, and f(5) = 1. Starting at any of these points, you cycle exactly through the three numbers {1,4,5} in that order. f(x) generates the sequence 1, 4, 5.

The natural questions are: How did I get that weird polynomial, and can we do that for every series? It turns out those questions are, unsurprisingly, related. Let's start by defining what we want a little more abstractly.

If we have a sequence S = {s1,s2,s3...sn}, we want to write an expression f such that f(s1) = s2; f(s2) = s3, and so on, until we get to f(sn) = s1. One way to construct such a function is to set up a series of terms which evaluate to 0 at all values but one, and combine them into a grouped expression. For the set 1, 4, 5, let's look at a first term (f1) that is zero unless x is 1. We can write out an expression like this easily by taking a product:

f1(x) = (x - 4)∙(x - 5)

When x is either 4 or 5, this expression collapses to zero. However, it's still not set up properly for the function component we described above, because we want f1(1) = 4, but right now, it returns 12. We can fix this, too, by correcting the result of the expression so that the selection part is one when x is the desired value, and zero otherwise, by dividing the above by the value at x = 1.

The natural questions are: How did I get that weird polynomial, and can we do that for every series? It turns out those questions are, unsurprisingly, related. Let's start by defining what we want a little more abstractly.

If we have a sequence S = {s1,s2,s3...sn}, we want to write an expression f such that f(s1) = s2; f(s2) = s3, and so on, until we get to f(sn) = s1. One way to construct such a function is to set up a series of terms which evaluate to 0 at all values but one, and combine them into a grouped expression. For the set 1, 4, 5, let's look at a first term (f1) that is zero unless x is 1. We can write out an expression like this easily by taking a product:

f1(x) = (x - 4)∙(x - 5)

When x is either 4 or 5, this expression collapses to zero. However, it's still not set up properly for the function component we described above, because we want f1(1) = 4, but right now, it returns 12. We can fix this, too, by correcting the result of the expression so that the selection part is one when x is the desired value, and zero otherwise, by dividing the above by the value at x = 1.

From there, all we need do is multiply this segment by the desired value, and we've found f1(x) as we described it above:

It is then fairly simple to see that we have a recipe for building fi: we begin with the product of all (x-j) for j ≠ i; divide this product by the value of itself evaluated at i, and then multiply that by the desired result.

Then, to get the composite function which represents the entire set, we can stitch together these functions by addition, since any term will be zero unless its desired selection is the input. Naturally, this imposes a requirement that each value in the sequence appear only once, otherwise collisions would occur. For a given series S, we can write the entire function as:

he Which is where I got that weird quadratic earlier, by writing out and simplifying one of these. This answers the first of the two questions I posed above, where the expression came from. The second question requires a little more looking. As mentioned, we know at the outset that we can only produce one result from each input, so each value can appear only once per series without producing ambiguities. Aside from that requirement, we can produce any sequence of unique values with a singular expression.

One of the things to notice is that the the order of the function is determined by the number of elements in the sequence, n, as n - 1, because each element's selection function includes a term for each other element. Sometimes I've found that the complete function may result in some terms canceling completely, also. One way to think about this is to consider the related case of roots of a polynomial- to have a given number of roots, the function must peak and trough enough times to cross back and forth over the horizontal that number of times. In a similar way, the function must intersect all levels in the series.

One of the interesting things is that this in no way prohibits us from mapping multiple inputs onto a single output- it's only a matter of selecting the value to multiply by the selection function. Consequently, the sort of networks we can describe are not limited to simple sequences, but also any directed network which can be expressed by a suite of connections among nodes which are allowed any number of inputs but only one output, such as the below:

One of the things to notice is that the the order of the function is determined by the number of elements in the sequence, n, as n - 1, because each element's selection function includes a term for each other element. Sometimes I've found that the complete function may result in some terms canceling completely, also. One way to think about this is to consider the related case of roots of a polynomial- to have a given number of roots, the function must peak and trough enough times to cross back and forth over the horizontal that number of times. In a similar way, the function must intersect all levels in the series.

One of the interesting things is that this in no way prohibits us from mapping multiple inputs onto a single output- it's only a matter of selecting the value to multiply by the selection function. Consequently, the sort of networks we can describe are not limited to simple sequences, but also any directed network which can be expressed by a suite of connections among nodes which are allowed any number of inputs but only one output, such as the below:

Seeing this kind of graph naturally leads us to wonder what all sorts we could create in this manner. Could we turn any undirected graph into such by setting its edges as directed segments? We can answer this question very simply by noticing that each node has exactly one outgoing edge, and so the total number of edges will be n, thus graphs with more than n many edges are not possible.

We could also alter the construction a little, so that we allow termini, say by not including a term for that node thereby inducing the function to return zero for that node, or making it lead to itself. In that case, we can describe any tree with this carefully constructed polynomial. Of course, we could also leave the function as it is and construct for any graph with n many edges (since each node will have its own edge).

Although not immediately useful, I find it a fascinating relationship between these three related concepts- sequences, graphs, and functions, that they all share a common gestalt which can be expressed as a common mapping among them. I think there might be more to it, I'll have to tinker with it a little more.

We could also alter the construction a little, so that we allow termini, say by not including a term for that node thereby inducing the function to return zero for that node, or making it lead to itself. In that case, we can describe any tree with this carefully constructed polynomial. Of course, we could also leave the function as it is and construct for any graph with n many edges (since each node will have its own edge).

Although not immediately useful, I find it a fascinating relationship between these three related concepts- sequences, graphs, and functions, that they all share a common gestalt which can be expressed as a common mapping among them. I think there might be more to it, I'll have to tinker with it a little more.