In a blog post yesterday, I mentioned that the golden angle is an irrational portion of a circle, and so a sequence of rotations by the golden angle will not repeat itself. We can say more: rotations by an irrational portion of a circle are ergodic. Roughly speaking, this means that not only does the sequence not repeat itself, the sequence “mixes well” in a technical sense.
Ergodic functions have the property that “the time average equals the space average.” We’ll unpack what that means and illustrate it by simulation.
Suppose we pick a starting point x on the circle then repeatedly rotate it by a golden angle. Take an integrable function f on the circle and form the average of its values at the sequence of rotations. This is the time average. The space average is the integral of f over the circle, divided by the circumference of the circle. The ergodic theorem says that the time average equals the space average, except possibly for a setting of starting values of measure zero.
More generally, let X be a measure space (like the unit circle) with measure μ let T be an ergodic transformation (like rotating by a golden angle), Then for almost all starting values x we have the following:
Let’s do a simulation to see this in practice by running the following Python script.
from scipy import pi, cos from scipy.constants import golden from scipy.integrate import quad golden_angle = 2*pi*golden**-2 def T(x): return (x + golden_angle) % (2*pi) def time_average(x, f, T, n): s = 0 for k in range(n): s += f(x) x = T(x) return s/n def space_average(f): integral = quad(f, 0, 2*pi) return integral / (2*pi) f = lambda x: cos(x)**2 N = 1000000 print( time_average(0, f, T, N) ) print( space_average(f) )
In this case we get 0.49999996 for the time average, and 0.5 for the space average. They’re not the same, but we only used a finite value of n; we didn’t take a limit. We should expect the two values to be close because n is large, but we shouldn’t expect them to be equal.
Update: The code and results were updated to fix a bug pointed out in the comments below. I had written
... % 2*pi when I should have written
... % (2*pi). I assumed the modulo operator was lower precedence than multiplication, but it’s not. It was a coincidence that the buggy code was fairly accurate.
A friend of mine, a programmer with decades of experience, recently made a similar error. He’s a Clojure fan but was writing in C or some similar language. He rightfully pointed out that this kind of error simply cannot happen in Clojure. Lisps, including Clojure, don’t have operator precedence because they don’t have operators. They only have functions, and the order in which functions are called is made explicit with parentheses. The Python code
x % 2*pi corresponds to
(* (mod x 2) pi) in Clojure, and the Python code
x % (2*pi) corresponds to
(mod x (* 2 pi)).
Related: Origin of the word “ergodic”