I am attaching a Golly script that can hopefully display an incremental synthesis of any 15 bit still life in less than 15 gliders. Save display_synth.txt and min_paths.txt in the same directory. I can't upload files with extension ".py" so rename display_synth.txt to display_synth.py. Select a still life or oscillator in Golly and run the script (making no selection is equivalent to selecting the entire universe). An incremental synthesis of the object will hopefully be displayed in a new layer.

It should always work for still lifes of 15 bits or less. In general, there is nothing stopping the script working for oscillators but min_paths.txt only knows about objects that are on an optimal route from an empty universe to some 15 bit still life. For example, I think it knows how to build blinkers, traffic lights, toads and beacons but not much else.

Also attached is a list of all 15-bit or fewer still lifes sorted by glider cost. The glider costs may differ from glider costs according to Bob or Mark for the following reasons:

1. I have added my 3 glider tail adder for all still lifes up to 15 bits.

2. My code has found a better route that was missed by humans.

3. The best synthesis of an object according to Bob's collection uses *WSS which my analyser does not understand.

4. A synthesis in Bob's database was not accepted by my code for some other reason.

Note that the steps in the displayed syntheses may have the inputs and outputs in different phases and orientations. There is enough information contained in min_paths.txt to address this but I was too lazy too work out the details.

chris_c wrote:I am attaching a Golly script that can hopefully display an incremental synthesis of any 15 bit still life in less than 15 gliders...

Wow. Worked perfectly when I tried several random spot checks.

How exactly do you handle cases where what would otherwise be the cheapest possible synthesis of a component still life can't be used because another component has to be constructed first, and it's in the way? Looks like that's all buried in min_paths.txt, since there's not a whole lot of complicated logic in the script. I haven't investigated any farther than that yet.

dvgrn wrote:Wow. Worked perfectly when I tried several random spot checks.

How exactly do you handle cases where what would otherwise be the cheapest possible synthesis of a component still life can't be used because another component has to be constructed first, and it's in the way? Looks like that's all buried in min_paths.txt, since there's not a whole lot of complicated logic in the script. I haven't investigated any farther than that yet.

Yes, as you noted, the code to display the synthesis is not at all clever. The file min_paths.txt contains lines of the form <start apgcode>;<end apgcode>;<data for glider synthesis>. For every object that the script knows how to synthesise there should be precisely one line in min_paths.txt that has the matching <end apgcode>. The script just finds the correct line and then steps backwards until (hopefully) we are at an empty universe.

The analysis code (which I haven't yet posted) knows nothing about "components". You need to pass in separate instantiations of every single version of a particular component. e.g. rle for "add tail to tub", "add tail to up boat", "add tail to down boat", "add tail to up barge", etc, etc, etc... I wrote some horribly slow python code that does this reasonably automatically.

The analyser script will analyse each without realising that there is any relation between them. It just checks each for correctness and puts them into a big list of known reactions. Finally I have some code that takes the big list of known reactions and whittles it down to the minimum version I posted above.

It's all a bit ad-hoc but already an improvement over doing these things manually.

I put updated versions of display_synth.py and min_paths.txt up on github. The new display script is posted below. It is the same as the old version except that it downloads min_paths.txt from the web if it doesn't find it in the current directory.

# Obtains a canonical representation of any oscillator/spaceship that (in# some phase) fits within a 40-by-40 bounding box. This representation is# alphanumeric and lowercase, and so much more compact than RLE. Compare:## Common name: pentadecathlon# Canonical representation: 4r4z4r4# Equivalent RLE: 2bo4bo$2ob4ob2o$2bo4bo!## It is a generalisation of a notation created by Allan Weschler in 1992.def canonise(duration):

Compared to the previous version of min_paths.txt there are improvements to 174 still lifes and 277 gliders saved in total. The majority of this is because I added many of the cheap-looking converters from Extrementhusiast's component collection.

Once I had done that I couldn't resist finding some synthesis improvements via Catagolue to make some nice new records. Specifically I found new syntheses for 10.15, 10.22, 12.51, 12.98 and 13.233:

Now according to summary.txt all 10-bit still lifes can be made in 6 gliders, all 12-bit in 9 gliders and all 13-bit in 11 gliders.

I also cross checked the glider costs given on Mark Niemiec's website. The following still lifes are listed with a smaller cost than predicted by me: 13.45, 13.49, 13.110, 13.231, 14.177, 14.358, 14.576, 15.28, 15.126, 15.594, 15.682, 15.884, 15.1062, 15.1200, 15.1244, 15.1253, 15.1336. But (if I didn't make any mistakes) the smaller cost is not justified by the syntheses in the corresponding files. Typically this is because of miscounting the number of gliders or misidentification of an SL.

chris_c wrote:The analysis code (which I haven't yet posted) knows nothing about "components". You need to pass in separate instantiations of every single version of a particular component. e.g. rle for "add tail to tub", "add tail to up boat", "add tail to down boat", "add tail to up barge", etc, etc, etc... I wrote some horribly slow python code that does this reasonably automatically.

By "this" you mean auto-creating recipe RLE for "add tail to X" for every object that might be able to have a tail added to it?

Mark Niemiec's expert system seems to be able to run reports saying that ninety-x percent of N-bit still lifes "can be synthesized using standard techniques from smaller still-lifes". Does your "horribly slow" code get in the way of doing the same kind of thing in practice for larger N, and/or are there other roadblocks as well?

dvgrn wrote:By "this" you mean auto-creating recipe RLE for "add tail to X" for every object that might be able to have a tail added to it?

Mark Niemiec's expert system seems to be able to run reports saying that ninety-x percent of N-bit still lifes "can be synthesized using standard techniques from smaller still-lifes". Does your "horribly slow" code get in the way of doing the same kind of thing in practice for larger N, and/or are there other roadblocks as well?

Yeah that's what I meant. The code for that part is at the bottom. Draw a converter using state 1 for the gliders and states 3 or 5 for the initial still life e.g. the 3G tail adder:

Then run the script. It works out which cells must always be off (state 2), which cells from the initial still life must stay on (state 3) and which cells in the initial still life can be switched off (state 5). Then it asks for a filename prefix and the maximum population of the output still life.

When I run it on this example for populations 15, 16, 17 and 18 I get:

The fact that the number of Output files per unit time is going down probably indicates that algorithmic improvements are possible. Also keeping track of live and dead cells using bitwise operations in C should be at least 100 times faster than using python sets.

But practically there is no immediate problem with moving on to 16 bit still lifes except for general trepidation...

# Define a cell as "interesting" if it is on or if it has at least 3# live neighbors. This function returns True if the set of interesting# cells is connected. So bi-blocks are semi-strict but tubs with# offset (4,0) and blocks with offset (3,3) are not.def is_semi_strict(cells):

#cells next to the priority cell if priority is not None: x, y = priority for dx in [-1,0,1]: for dy in [-1,0,1]: P = (x+dx, y+dy) if P not in on_cells and P not in off_cells: return P

#cells near any live cell for x, y in on_cells: for dx in [-1,0,1]: for dy in [-1,0,1]: P = (x+dx, y+dy) if P not in on_cells and P not in off_cells: return P

#cells that are distance 2 or sqrt(5) from a live cell for x, y in on_cells: for dx in [-2,-1,0,1,2]: for dy in [-2,-1,0,1,2]: if 4 <= dx*dx + dy*dy <= 5: P = (x+dx, y+dy) if P not in on_cells and P not in off_cells: return P

for i in range(0, len(pat)-2, 3): if pat[i+2] != 5: touched_cells.add((pat[i], pat[i+1]))

near_cells = set()

for x, y in touched_cells: for dx in range(-2, 3): for dy in range(-2, 3): if abs(dx) + abs(dy) < 4: near_cells.add((x+dx, y+dy)) else: # for (2,2) offsets use a more complicated (but # still conservative) rule that allows on cells # at a (2,2) offset from a glider trail count = 0 for ddx in range(-1, 2): for ddy in range(-1, 2): if g.getcell(x+dx//2+ddx, y+dy//2+ddy): count += 1 if count > 1: near_cells.add((x+dx, y+dy))

dvgrn wrote:By "this" you mean auto-creating recipe RLE for "add tail to X" for every object that might be able to have a tail added to it?

Mark Niemiec's expert system seems to be able to run reports saying that ninety-x percent of N-bit still lifes "can be synthesized using standard techniques from smaller still-lifes". Does your "horribly slow" code get in the way of doing the same kind of thing in practice for larger N, and/or are there other roadblocks as well?

chris_c wrote:Yeah that's what I meant. The code for that part is at the bottom. Draw a converter using state 1 for the gliders and states 3 or 5 for the initial still life e.g. the 3G tail adder:Then run the script. It works out which cells must always be off (state 2), which cells from the initial still life must stay on (state 3) and which cells in the initial still life can be switched off (state 5). Then it asks for a filename prefix and the maximum population of the output still life.

My method takes a specific list of patterns (e.g. 15-bit still-lifes) and list of converts (of which I have about a thousand currently). It then takes each pattern, and attempts to run each converter on it, until it finds one that works, at which point it outputs a possible solution in the form "target\tconverter\tsource\n". This is sufficient for existent proofs, but not to regenerate the synthesis - no orientation is provided for the converter, and some converters may be applied in more than one place. However, it would be easy to merely re-run the algorithm on that one pattern and one converter to rapidly recreate the solution. It also doesn't output the glider count, nor attempt to optimize the glider count (although this would easy to do by keeping the converters sorted in ascending order by number of gliders, and trying them in that order).

Each converter is in multi-colored CA with 5 different states. The default state is used for most of the universe, and represents cells that are the same in both source and destination, and may be either alive or dead, and may change during the course of the converter (e.g. in the tail-adder, all the cell at the corner of the tub, which could also be alive when adding a tail to a boat). One state is for cells that must be alive and must never change (e.g. the tub itself). One state is used for tool cells (e.g. incoming gliders or spaceships). One state is for births (e.g. the tail). One cell is for deaths (e.g. in snake-to-python, one of the original end cells). One state is for cells that must always be dead (e.g. the middle of the tub, and several cells around the tub). This state is particularly important, as it is also used for the 3 lanes adjacent to the incoming gliders, plus 1-3 cells around any births caused by the converter. This is especially important for finding non-viable recipes - if any birth ever happens in any such cell, the recipe cannot work, so it can be immediately abandoned without needing to run it any further. There is one state that represents living cells that must end up alive, but are permitted to die temporarily.

Finally, I have recently added one extra state for "example" cells. These cells are treated like the default for the purpose of the expert system, but are treated as "alive but may temporarily die" for running the recipe by humans. This allows a recipe to be verified and observed by supplying one real-life example conversion, without affecting how the converter is actually implemented. (e.g. in "snake to python", the rear end of the snake is like this, because such a converter can convert snakes of any length, and in some cases, can also lengthen barber poles as well).

Each converter is applied to a pattern, in all 8 possible rotations and reflections, and in each possible position. Because each converter is heavily constrained by "must be dead" cells, most converters will be immediately discarded without even running the pattern at all. If a converter does match a situation successfully, it is run to see if it does actually produce the desired result. In most cases, an incorrect converter will produce a forbidden birth or death, and then be immediately discarded. In some rare cases, a methuselah will result that does not violate the input constraints, but that also does not produce the desired result. Such cases are run for an arbitrary period (I currently use 300 generations), and if they do not produce a success or failure in that time, they are discarded. This limit can, of course, be increased, if any new converters are added that run for longer. It would also be easy to attach an annotation to each converter that specifies exactly how long it runs - by just running it against its example and counting the time until success.

The program does not actually generate reports. It just outputs successful conversions (as mentioned above), or if it can't find one, an unsuccessful conversion is indicated by merely outputting the original input pattern. A post-processing filter separates the output into two additional files - a list of successes, and a list of failures. The lengths of these three files are examined by hand to generate statistics.

The biggest problems I have is that, at present, the recipe repertoire necessarily only contains converters that increase the population, or in situations where the population doesn't change, produces more complex structures from simpler ones (where complexity is a subjective, but unambiguous criterion). This provides a partial order for all patterns, which is useful for inductive proofs of synthesizability. It lets one say, for example, that, given that all still-lifes up to 14 bits have known syntheses, that all successful matches from the 15-bit still-lifes will either produce successful syntheses, or in a few rare cases, partial syntheses based on other as-yet-unsynthesized 15-bit still-lifes.

There are a fair number of other useful converters that violate the above constraints. Unfortunately, this makes it difficult to prove syntheses by induction, unless some other kind of partial order can be established. For example, a converter that shortens a snake - being able to synthesize a "frob w/long snake" from a "frob w/even longer snake" is hardly useful, unless one can demonstrate a synthesis for the larger object.

A second, lesser problems occurs with syntheses of oscillators and pseudo-oscillators, especially those involving pulsators with larger periods. Recipes contain "must be dead" cells where the pattern cannot intrude without interfering with the conversion reaction, but those cells usually need to only remain dead during certain times (e.g. when an incoming glider passes by). With oscillators, it's possible for an oscillator to intrude on such cells at other times without harming the integrity of the conversion. One could remove the "must be dead" cells from such recipes, but that would make them less difficult to filter out, slowing down the search process for all patterns.

mniemiec wrote:My method takes a specific list of patterns (e.g. 15-bit still-lifes) and list of converts (of which I have about a thousand currently).

Woah. I think I have around 60 so far. I'm definitely worried about the number of holes that will be present if/when I extend to 16-bit still lifes.

mniemiec wrote:The biggest problems I have is that, at present, the recipe repertoire necessarily only contains converters that increase the population, or in situations where the population doesn't change, produces more complex structures from simpler ones (where complexity is a subjective, but unambiguous criterion). This provides a partial order for all patterns, which is useful for inductive proofs of synthesizability.

I don't see why you need a partial ordering like that. The following Python-flavoured pseudo-code takes a set of known objects and expands it to all objects that can be reached via objects of "complexity" less than or equal to LIMIT. When you encounter a new target I suppose you should make a note of the ancestor in order to make the list into an easily inspectable proof.

I have pushed a new version of min_paths and summary to github. It adds the above component and also some others that I haven't seen before. The first was noticed by A for Awesome the other two are by me.

chris_c wrote:I don't see why you need a partial ordering like that. The following Python-flavoured pseudo-code takes a set of known objects and expands it to all objects that can be reached via objects of "complexity" less than or equal to LIMIT. When you encounter a new target I suppose you should make a note of the ancestor in order to make the list into an easily inspectable proof.

If you have a list of known objects (i.e. ones for whom syntheses are known), you have a partial ordering - i.e. "patterns known on day 0, patterns known on day 1 (i.e. day 0 + one known converter), patterns known on day 2 (i.e. day 1 + one converter)", etc. By always starting with something simpler, it is possible to use an induction proof of completeness. If you use the method, "Let's take all known patterns and see what we can make from them to expand the set", this will always work. If you use the method, "Let's take all the patterns we need and see what we can make them from" as I do, that's not the case.

I made my analyzer synthesis using ROLLBACK glider at 40 steps back.When analysing its database found and fixed a bug in the synthesis of 15.373. The second from left glider interacts with the second from the right. If two left gliders roll back on 4 step each, these gliders fly by without interaction:

P.S. The homepage still shows that one week ago all 14-bit still-lifes could be synthesised in less than 1 glider per bit, but we have done the much more significant achievement of 15-bit still-lifes, so I feel that someone should update that.

The challenge is to reduce one of the numbers on the right hand side of the table.

Perhaps the easiest option is to do all 14-bit still-lifes in 12 gliders.

...

Thi table is incorrect for SL4 and SL6. I have never seen the tube (4.2) from 2G, as well as the snake (6.1) and carrier (6.4) of 3G. In the rest of the table is correct. The best idea is to show that SL16 can be synthesized less than 16G. Of course, the task is heavy, but I hope it will be automated. In the first step it is necessary to reduce the cost of expensive SL16 M. Niemiec’s database.

BobShemyakin wrote:The best idea is to show that SL16 can be synthesized less than 16G. Of course, the task is heavy, but I hope it will be automated.

I did quite a bit of work on making syntheses for all 16-bit still lifes. Adding many of the converters from Extrementhusiast's list and then making more expensive versions that have smaller reaction envelopes to get a few of the harder cases. There are still around 200 still lifes without a synthesis so probably I am still missing some useful converters. Good news is that at least 2800 out of 3286 still lifes are buildable in less than 16 gliders. I will post more details within a few days.

chris_c wrote:...I did quite a bit of work on making syntheses for all 16-bit still lifes. Adding many of the converters from Extrementhusiast's list and then making more expensive versions that have smaller reaction envelopes to get a few of the harder cases. There are still around 200 still lifes without a synthesis so probably I am still missing some useful converters. Good news is that at least 2800 out of 3286 still lifes are buildable in less than 16 gliders. I will post more details within a few days.

Offer my collection of converters. Partially assembled on the Forum but there are converters found me.2G:

I have pushed an update to my github repo that contains explicit syntheses for 3100 out of 3286 16-bit still lifes. So far 2843 have cost less than 16 gliders and 96 have cost equal to 16 gliders.

In summary.txt you should now find a list of all 16-bit or fewer still lifes ordered by cost. A cost of 999 represents still lifes with syntheses that are unknown to my system.

Also I have added files such as stillNN.txt that list still lifes of population NN bits in cost order and a file still_list.txt that contains the costs of all still lifes in Niemiec order.

The script display_synth.py has been updated and now shows all steps of the synthesis in the same orientation. The script is given lower down in this post. Remember to delete any previously downloaded version of min_paths.txt and the script will automatically download the latest version instead.

First of all let me write a bit about the still lifes that do not have syntheses. Define two still lifes as equivalent if there are known methods of obtaining one still life from the other in both directions. Then there are 142 equivalence classes of still lifes with unknown synthesis that contain a 16-bit still life and have no known 16-bit ancestor outside the equivalence class.

(EDIT: In the previous sentence the second occurrence of "16-bit" was missing originally).

These are shown below. I know that mniemiec's site will contain syntheses for many of them but I am posting them here in the hope that people can deduce some important converters that I am missing:

# Obtains a canonical representation of any oscillator/spaceship that (in# some phase) fits within a 40-by-40 bounding box. This representation is# alphanumeric and lowercase, and so much more compact than RLE. Compare:## Common name: pentadecathlon# Canonical representation: 4r4z4r4# Equivalent RLE: 2bo4bo$2ob4ob2o$2bo4bo!## It is a generalisation of a notation created by Allan Weschler in 1992.def canonise(duration):

Several converters, either duplicated, mislabeled, or obsoleted (although I may have failed to recognize necessary extra gliders in one or two cases), have been dealt with accordingly, things have been placed more neatly and readably, and this component have been taken off the lists entirely: