The Devil’s Staircase

The Cantor function, mapping the unit interval to itself, is a relative to the Cantor set, which was described previously on this website. Being uniformly continuous, but not absolutely continuous, it is a classic mathematical counterexample. Although its derivative is zero almost everywhere, its range of outputs still encompasses the full unit interval. Wikipedia has a nice pictorial representation of the iterative process that defines it.


Cantor iteration, courtesy of Wikipedia


The concept starts from considering the Cantor set probabilistically. The Cantor function is in fact the cumulative distribution function for a random variable which is uniformly distributed on the Cantor set. But we can also define the Cantor function directly. Consider the Cantor set as the set of all ternary expansions whose entires are all either \( 0 \) or \(2\). As mentioned previously, there is then a bijection between the Cantor set and the full unit interval by ‘pretending’ the \(2\)s are \(1\)s and interpreting the numbers as binary expansions. Hence, for an input \(x\) which belongs to the Cantor set, we define \(c(x)\) as this correspondence. We then further define the Cantor function on inputs \(x\) that do not belong to the Cantor set as follows: since \(x\) does not belong to the Cantor set, it must contain a \(1\) in its ternary expansion. By truncating \(x\) immediately after the first \(1\) in its expansion, ‘pretending’ any previous \(2\)s are \(1\)s, and then interpreting the result as a binary expression as before, we obtain the appropriate output \(c(x)\).

I’ve recently written the code for a Cantor function UGen in SuperCollider for use in digital audio. The UGen uses an approximation to the Cantor function based on a recursive sequence of functions which converge pointwise to the Cantor function. The user can control the depth of the recursion for more or less precision. Here are a few very primitive demonstrations. To illustrate the recursion of the function sequence that converges to the Cantor function, I’ve taken a sine oscillator and modulated its frequency from \(200\) to \(600\) Hz using different convergents of the Cantor function. Here they are, for \( n = 0, 1, 2, \text{and } 3\):

\( n = 0\): (equivalent to one straight line between \(200\) and \(600\); i.e., no plateaus)

\(n = 1\): (comprises three straight lines, the middle one being completely flat; i.e., one plateau)

\(n = 2\): (three plateaus connected by straight lines)

\(n = 3\): (seven plateaus connected by straight lines)

(In general, there will be \( 2^n – 1\) plateaus.)

Of course, those examples aren’t especially interesting from a musical perspective. However, I found that the UGen was quite expressive when used at control rate to manipulate such parameters as envelopes and rhythms. Here is a recording  of an improvisation I generated in SuperCollider, using almost exclusively the Cantor UGen to shape the sounds. (The actual audio rate UGen is a pulse oscillator, and the end result is put through a reverberator.)

If others are interested in trying out the Cantor function UGen, I will post the code shortly!