Quickly Detecting Cool Still Lifes
April 8, 2025 / code, cuda, gol
QuFince is a CUDA tool written by apg to conduct brute-force Game
of Life searches on the cartesian product of two sets of
configurations. That is, each configuration from set A is combined
with each configuration from set B, and run until stabilised. Not
every result is reported, only those where certain criteria are met.
Right now the options are either that the result has some interesting
periodInteresting period here typically means period not dividing
120, to rule out blinkers, pulsars, pentadecathlons and figure
eights, among other things.
(to hunt for glider syntheses of
oscillators), or that the result contains a specified pattern (to
hunt for synthesis components for specific still lifes).
One thing that can’t be done currently is have QuFince report any combination that results in an interesting still life, but without knowing which still life you want in advance. It’s not so obvious what “interesting still life” should mean exactly, but here are some randomly chosen examples of things that should qualify:
We can’t use a population threshold as our criterion for interestingness, because the typical result of one of these QuFince trials is a bunch of uninteresting junk. One option is to do proper object separation, like apgsearch, and then report any object that is sufficiently rare. But a QuFince search can conceivably test hundreds of billions of configurations, and full object separation is simply too slow.
Here I’ll present an alternative, a simple heuristic that works well enough. There are some constraints, but most important is that our mistakes only go in one direction. False negatives are disappointing, because we might be missing out on a cool result. But false positives are catastrophic because they cause a firehose of useless results, which defeats the purpose of using QuFince in the first place.
To evaluate how we’re doing, we’ll test the heuristic on the 10,000
most common still lifes. We’ll declare any still life with population
\geq 18 to be “interesting”, and any still life with population
\leq 10 to be a deal-breaker that must be rejected.These
thresholds are somewhat arbitrary.
Our goal is to correctly classify
as many of the remaining 10,000 as possible.
Chunky Regions
The first thing that comes to mind is that rare still lifes are often
dense, so we should devise a fast check for dense regions. If we fill
in the “holes” in the ash, a dense region will show up as a place
where we can fit a decently sized square. Or stated a different way,
if we inflate the ash a bit, and then deflate the result a bit more,
the only way anything can remain is if there was some thing decently
sized to begin with. Here, the zoi()
method blows up every cell in a
pattern into its 3 \times 3 neighbourhood.
= ~(~pattern.zoi()).zoi().zoi(); chunky_locations
This is quite efficient to evaluate when the state is represented by as a bitplane (as it is in QuFince and LifeAPI). It’s a good start and correctly identifies 7223/10000 still lifes, but it does have some unacceptable false positives:
Changing the precise kind of inflation/deflation helps. To test this
systematically, I defined a handful of “neighbourhoods” and tried all
combinations. Some of the neighbourhoods I tried are things like:I
also threw in some more exotic neighbourhoods, but none turned out to
help.
What worked by far the best was the following pair, so inflating by the radius-1 von Neumann neighbourhood on the left and deflating by the radius-2 Moore neighbourhood on the right.
= ~(~bx.vonneumann()).zoi().zoi(); chunky_locations
This correctly classifies 6017/10000, but with none of the painful false positives of the previous version.
The Line-of-five Rule
Let’s inspect some of the still lifes that don’t get picked up by this.
One thing that jumps out is that many of them contain a orthogonal line of length at least 5. This is also efficient to test for, doesn’t occur in any of our deal-breakers, and improves the detection rate to 7337/10000. However, there’s a downside: it does pick up the fourteener, a surprisingly common still life that happens to contain a line of five.
The fourteener is the 43rd most common still life, and one needs to go down to 75th and then 138th to see another line like that. The improvement is too good to give up, so I just filter these fourteeners out as a special case.
The new set of missed still lifes begins as follows, and it’s less easy to spot a common feature that could be tested for.
Here’s where I stopped. Any ideas?
I’ve been putting this into practice by searching for new glider
syntheses, crashing 6 randomly placed gliders together. You can see
some of the results as I go here. I work a lot more efficiently than
previous attempts (like the moog_stdin
and 5Glider_stdin
symmetries), because 1) I make sure the gliders actually collide
rather than positioning them completely randomly, and 2) I do the vast
majority of the work on the GPU kernel rather than piping an RLE
generator into apgsearch.
This has already turned up a handful of record-breaking syntheses after just a couple of hours, and I’m looking forward to a lot more. Here’s one chosen at random. If you have a powerful GPU and also want to do some searches, let me know!
Edit (11/05/25): Indeed this was extremely productive, producing many hundreds of new syntheses. Here are some of the clean ones involving 6 gliders, each of which feels pretty miraculous.
I’ve started to lose a sense of how spectacularly rare objects like these actually are, after spending so much time looking at the results of searches that have already thrown out billions of configurations.