Here I'll park various web demos, as they are constructed.
Over the years (sigh) I've written a large number of audio/video interactive programs,
often after suggestions by Steina and Woody Vasulka, to enable various installations.
However, these were written using Quicktime, and even QuickDraw, 32-bit frameworks which
have been "deprecated" for many years. Apple OSX operating systems used to be
quite admirable in supporting executables from days of yore, but no more. From around
OSX 10.13 onward, it has become increasingly difficult to use 32-bit applications, and
access the built-in webcam as before.
So what to do? If one is going to port code, where's the stable platform to port to?
Apple has even "deprecated" OpenGL, which was considered a standard, in favor of a proprietary
and probably ephemeral in-house graphics framework. So Apple is out, where do we go?
The answer seems to be, into the browser. WebGL allows use of the GPU in a browser, using OpenGL commands,
and is probably not going away soon. An additional advantage is that being in a browser gives one
independence from any particular operating system (though each of the major browsers have in fact
its own peculiarities). Further, modern browsers implement WebAssembly, a binary code format that allows
cross-compilation from, for example, C, into browser code which can run at near-native speed.
At the moment, Chrome-based browsers have trouble with these demos running under http,
Firefox and Safari work fine. If you access them via https://robshaw.net:4433/rob-demos.html
everything should work, even Chrome. For some reason, demos run in Chrome can initially stutter, and
run at reduced speed. Reloading the page a couple of times seems to clear this problem up.
This is a first demo using WebAssembly. The original code is written in C, and the screen
is accessed via SDL. Using the Emscripten package, it is possible to compile the code
either to a native executable, or to a .wasm file, which gets loaded and run by the browser.
The code runs in the browser typically around 80% native speed.
Video Cube Demo
A minimal WebGL demo which uses the HTML5 call getUserMedia() to grab a video stream from the webcam,
and apply it to the surfaces of a cube using minimal shaders. Assembled from old code fragments,
sorry, credits have been lost.
Logistic Map Bifurcation Plot
Here are plotted iterates of the logistic map x = rx(1-x) as a function of the parameter r.
The parameter r varies along the horizontal axis from values (3.5, 4.0) and each iterate is plotted
as a dot along the vertical axis, with values between (0, 1). The successive bifurcations as r is increased
are apparent, you can pan across the diagram with the arrow keys, and zoom in/out with shift up/down arrow keys.
This is now a familiar and canonical figure, prominantly featured, for example, in
a wikipedia article, or
two, or in
a Wolfram Mathworld article.
I believe this diagram was first constructed in Santa Cruz, back in the day, perhaps by Jim Crutchfield.
In the intervening 40 years (ak!), readily-available CPU speeds have increased by a factor of something
like 10,000, so it's now possible to compute this figure in real time. This WebAssembly demo can easily
compute and display 500,000 iterates, at 60 frames a second. The limiting ratio of the r values of
successive period-doubling bifurcations is called the Feigenbaum constant, after the late Mitchell Feigenbaum.
Simple Speed Test, Logistic Map
This is a raw speed test, the default is to crank away at the logistic map, 100,000,000 iterations per
display frame. My 2.9 GHz 2012 Macbook Pro runs at about 340 million iterations per second (mits) natively.
In a browser, it runs typically at about 95% of this speed. Firefox currently seems a percent or so faster than the
other browsers. This high speed is typical of computational tasks which can be accomplished in the registers,
more complicated tasks typically run in the browser at around 80% of native speed. This is because memory
accesses have to be checked, to make sure they are not trying to access something out of bounds. WebAssembly,
like all browser code, is "sandboxed", we don't want some downloaded .html file doing something untoward to our
local machine. For comparison, my $100 Lenovo smartphone runs the logistic map at about half the speed of
a browser on the laptop.
The Three Body Problem
Here is a simulation showing that it might be a bad idea to take up residence on a planet that is in
a close orbit around a binary star. This is the "restricted three body problem", we have three coplanar
objects, two of which are large (the stars), and are not perturbed by the third small body (the planet).
The simulation starts off with an ensemble of 5000 "planets" which are initially very close in position
and momentum. But, for these initial conditions, the system is chaotic, and the 5000 planets quickly
proceed along different histories. Most of them end up crashing into one star or the other, and being incinerated.
The remaining "survivors", around 900, are ejected from the binary system, at greater than the escape velocity,
into the frigid reaches of outer space. It was possibly this example that led Poincaré to first appreciate
what we now call low-dimensional chaos. You can experiment with different initial conditions wrt the phase
of the binary star orbits by hitting the 'n' key, 's' and 'S' speeds up or slows down the simulation.
Elastic Hard Disk Experiments
Here we have 3000 disks, initially confined to the right side of a chamber. After a transient, the
partition is removed. A histogram shows the density of disks as a function of the x position.
Note the "slosh". Question, how do we define a "slosh"?
Here is a simulation,
this time the histogram records the number of disks, as a function of the average speed.
The red curve is the equilibrium Maxwell-Boltzmann distribution. The "slosh" can be seen as a deviation
from the equilibrium distribution.
The ideal gas doesn't slosh. Now what is plotted
is the x position of the green balls. Note the rapid spreading.
But if we do a simulation with interacting balls, the spreading of the green balls
is slow, even with the dynamics. The system reaches equilibrium in momentum space rapidly, but slowly
in configuration space, due to stearic hindering. I believe there is an old paper by Joel Lebowitz
that mentions this effect, but I've lost the reference. All this could be quantified with p log p measures.
There are various keyboard commands that might be of interest, 'n' restarts a simulation, 's' and 'S' changes
the speed, 'h' cycles through various histograms. Again, there is some problem with Chrome, you may have to
reload the page a few times to get the simulation to run at full speed.
Random Waves and Shaders
Here's some more compulsive computation, of possible interest.
Many years ago, Bill Burke introduced me to random wave patterns, generated
by simply superposing monochromatic plane waves, traveling in random directions.
The resulting patterns he called "refrigerator mold", and they show up in a lot of places,
including studies of laser speckle, quantum chaos, and even in cosmology as will be suggested below.
Sadly, he died in a traffic accident, and I was unable to show him my real-time simulations.
The first problem, for the computers of that time, was that to make a picture, you needed to
compute sines and/or cosines at each pixel, e.g. cos(kx-wt) for each traveling wave. That's
a lot of cranking, which put real-time simulations out of reach 30 years ago. However, I noticed
that, on a lattice, you can expand cos(kx-wt) with a trig identity, and get rid of the cosines.
Effectively, to find the phase at an interior point, you integrate the harmonic oscillator equation
in from the boundaries. Each pixel is only four multiplies per wave, instead of a cosine.
That gave a speedup of something like four.
Further, the PPC processors that Apple was using had something called "AltiVec", a vector unit which
provided another factor of nearly four. This allowed some pretty nice real-time stuff, which
Bill never saw.
So this sat on the disk, gathering dust. But lately I thought I might resurrect the simulation.
Computers have sped up more than an order of magnitude in the intervening time, and the Intel processors
include an SSE vector unit, which is an easy port from AltiVec code.
The result looked great, so I says to myself, says I, let's port this to WebAssembly, where
people could see it in any browser. Well, after an embarrassing length of time, I found out that
the SSE instructions haven't been ported to WebAssembly, only emulated (there is work on this though).
The slow, nonvectorized CPU version can be run
here.
By clicking, or using a touch screen, you can cycle through a bunch of presets, with color maps,
selected on an esthetic basis. There's a lower resolution version for phones,
here.
Well, what about shaders, to speed things up? The problem with the trick described above is that
you have to compute the pixels in serial order, to propagate the phase from one pixel to the next.
I didn't see a way that the many independent shaders could do that. So, what the heck, let's just try having
the shaders do the sines and cosines, that way each pixel can be independently computed.
The results were shocking to me. My 2012 2.9 GHz laptop, with vanilla built-in Intel GPU, can crank out
more than 8 billion cosines per second, operating a factor of something like 60 faster than the SSE code.
So it became worth it to do the WebAssembly port of the shader code. It was a total pain in the ass,
with gotchas galore, and an absence of informative error messages.
But it now runs.
It's set up with a symmetric initial condition of 100 waves, with a little dispersion added so that the pattern
over time becomes random, as will be discussed below. You can zoom in with up arrow, restart with 'n', speed up and slow down
with 's' and 'S'. Color maps will be added "later". The clever trick has been completely obsoleted,
hopefully not me along with it...
Another surprise was that the WebAssembly running in the Chrome browser is actually a bit faster than
native code. The shaders are compiled on the fly every time you run the code, and apparently,
the Chrome shader compiler is better than the GLSL compiler built into OSX 12.
I looked around the literature a little,
found this competition,
which uses Matlab (boo!) and starts with a sampled unit circle in k space, then uses a FFT to generate the pattern (that's cheating!).
A direct comparison can't be made at this time, but I expect the GPU simulation to be about 10 times faster.
Here's another accessible reference on this subject.
Notice how this simulation naturally generates "walls" and "voids". A quantum-mechanical eigenfunction
of a higher energy state is expected to look like this, a funny-shaped boundary classically
will generate a chaotic billiard path. We just have the Helmholtz equation on a funny-shaped drum.
This work is partially motivated by a desire to understand "quantum chaos". I might be late to the party,
but the party is far from over!
Further, these patterns are qualitatively reminiscent of galaxy distributions,
collected along thin slices projected out into space.
Note the walls and voids. Coincidence??
(Cue the Twilight Zone music). Maybe not.
There is a cosmological theory that the anisotropies observed in galaxy distributions are due to
baryon acoustic oscillations,
sound density waves traveling, presumably in random directions, in the early universe plasma. When things cooled off enough
that atoms could combine, photons could freely travel, and the pattern became frozen. A particular wavelength was favored,
the
baryon acoustic peak, hence the similarity in the patterns.
To reveal a trick, a pure superposition of monochromatic waves traveling at constant velocity would
generate a basically static pattern that locally simply cycles every two pi. This is visually uninteresting, and perhaps unphysical.
To get the squirmy effect seen, a small dispersion is added to the energy; the superposed waves have the
same wavelength, but travel at different speeds. This effectively moves the pattern through an ensemble
of possible pictures, generated by random phases of the superposed waves. Any single snapshot is a correct member of the ensemble.
Scott-Gray Reaction-Diffusion Equations
The above simulations were written in C, and ported to WebAssembly using Emscripten. However, when I tried
to port trickier shaders, which implement reaction-diffusion systems, I started to run into problems. Apparently
browsers have WebGL limitations on their shaders, and I couldn't get around them. So rather than write in C, I was forced
to call shaders from javascript, using WebGL. This is OK, as I'm going to be using the camera, and will have to use
the HTML5 call getUserMedia(), and javascript anyway, as in the video cube demo above. For CPU-intensive tasks, one can still
make WebAssembly calls into C code from javascript.
There are a bunch of WebGL examples of reaction-diffusion on the web, the nicest example I found was
work by Robin Houston.
This is a piece of art code, minimal, though with error messages, and attractively free of licensing. Other good collections
can be found
here and
here.
My version uses a color map, for esthetic effect. The 'n' key will reset the initial condition, and
the 'N' key will give a blank initial condition. You can then use the mouse to perturb the system. More bells and whistles
will be added "later".
Array of Locally Coupled Limit Cycles
Here is a simulation consisting of a 512 x 512 array of limit cycles, each one diffusively coupled
to the four nearest neighbors. As in the Scott-Gray example above, this is written in straight WebGL, the source
can be directly examined via the browser. The limit cycle used is the Schnakenberg system, which has the advantage
that the limit cycle calculation supplied to the updater requires only two multiplies, and a few adds. The cycle
is a model for a periodic chemical reaction of the Belusov-Zhabotinsky type.
Try perturbing the system by dragging the mouse around, you'll find that a strong enough perturbation will disrupt
the global phase coherence, and nucleate pairs of Winfree-type phase singularities. The 'n' or 'N' key will reset
the initial conditions, the 'a' key toggles between a direct display of one of the chemical species, and a display
of the "amplitude" of the limit cycle.
Research Interests
Curriculum Vitae
Other Stuff