LLSSS-NG: gchromodynamic's remarkable LLSSS fork

For scripts to aid with computation or simulation in cellular automata.
Post Reply
User avatar
LuveelVoom
Posts: 782
Joined: April 27th, 2022, 7:59 pm

LLSSS-NG: gchromodynamic's remarkable LLSSS fork

Post by LuveelVoom »

Introduction

LLSSS-ng is a version of LLSSS by gchromodynamics (specifically, a C++ port) that uses significantly less memory and is much faster, at the cost of stripping out most of LLSSS’s extra features (most notably, the ability to do floating-row searches; L2S3ng can only do fixed-width orthogonal and diagonal searches). This is the program I used to find this 3c/7 in TTs in one night: https://conwaylife.com/forums/viewtopic ... 22#p234622

Here's the github: https://github.com/SuffixAutomata/llsss-ng

It also adds two major features:
-The ability to pause a search, producing a save file, which can be resumed later
-The ability to partition searches, which allows doing searches which would otherwise require far more memory, at the cost of an absurd amount of disk (I highly recommend using an external drive!)

This guide will not cover custom geometry and really complex features because I do not understand them. For those, refer to the github or pester gchromodynamics.

Installing

I’m bad at computer, so refer to the github:
Build instructions for linux: https://github.com/SuffixAutomata/llsss-ng
If you have a mac, there’s a downloadable binary at https://github.com/SuffixAutomata/llsss-ng/releases.
If you have a windows machine, uhh good luck there’s probably some way to do it idk

Using (no partitioning)

The command format is ./rlife llsss [options] <geometry> <start>.

Geometry follows one of the standard f2b LLSSS geometries (cP-f2b, KcP-f2b, cPd-f2b, or KcPd-f2b). Non f2b geometries aren’t supported at the moment. You can also use --left-edge even, --left-edge odd, or --left-edge gse/gso (for glide-symmetric searches) in the options section to do standard symmetries.

Start is the starting grid. You should typically do @bg(W) to do a search at a given width. There are more complex options, but I don’t know how to do them and won’t go into it here.

No, I do not know how diagonal widths correspond to other programs, each program seems to use a different system for diagonal width and I cannot for the life of me figure it out. Do a test run and kill it quickly and look at the bounding box.

For options, there are a lot of things to use. I’ll go over the most important ones; you can see the others with ./rlife llsss --help.

--filters bcaf: Break at zero. If you don’t include this, your search will not terminate when it finds a spaceship. Unless you specifically want a zillion tagalongs, I would include this.
--left-edge: I went over it above.
--rule: Determines the rule to do the search in (for example, --rule B3/S23-a5 searches in Travelling Ts)
--threads: If you do not set this option, L2S3ng will only use one thread. Example format: --threads 20
--halts: Halts the search when a specified condition is met. The most useful condition is w_pos:X, which halts the search at a certain W position (This is some weird LLSSS terminology that I do not understand but you probably do.)
--max-memory: Memory cap; if the program goes above this it saves and then stops.
--search-name: Determines the name of the save folder in the saves directory. Speaking of saving:

L2S3ng has the ability to save and load searches. If you ctrl-C the search (once, but I’m fairly sure you can do it multiple times, but I haven’t tested so be careful), it will detect the interrupt and exit once the current row is complete, saving a file in the save directory. These files are several gigabytes in size, by the way. You can also set it to save at other times using the --save command; the most important option is --save every:N, which saves a backup every N rows.

You can start the search again with the command ./rlife llsss --load saves/(save name). When you load, you can change --halts, --threads, --max-memory, and a few other things, but you cannot change the search parameters (width, rule, etc).

Partitioning

This is an extremely powerful feature that allows L2S3ng to split a run into multiple branches when memory use gets too high and continue each one individually. Partitioning is extremely storage intensive. Please use an external drive.

You can partition manually; I don’t really understand how, so refer to the github on that. L2S3ng comes with a partition manager python script, however, which automatically partitions searches when memory gets too high and goes back to earlier partitions when a partition is exhausted. Here’s how to use it:

Stick the following in front of your regular command: scripts/rlife_manager.py start saves/(search name) ./rlife --max-memory X --disk-reserve Y --parts Z (the rest of the options).

(search name) is the name of your search. This should be an entirely empty folder inside the directory you are using (by default, saves).
max-memory is the maximum amount of RAM L2S3ng is allowed to use before partitioning.
disk-reserve is how much space on disk the run is able to use; if it fills up this space, then the search pauses.
parts is how many pieces the search is split into at each partition. The recommended number is 4, and I don’t see much of a reason to change that.

There are some useful additional options (some more are documented on the github):
--delete-immediately: Automatically deletes exhausted save files. I strongly recommend using this. It reduces disk space used significantly.
--bfs: Runs the search breadth-first instead of depth-first. I haven’t tested this and there probably aren’t many situations where it’s useful.

Partitioning is slow, so you should ideally not do it very often. Pausing the search while it is in the middle of creating a partition loses progress on the partition creation, I lost 30 minutes of progress this way.
You can pause a partitioned search the same way you pause a normal search and then resume it with scripts/rlife_manager.py resume saves/(search name).

Good luck!
:mrgreen:
Last edited by LuveelVoom on September 29th, 2026, 8:35 pm, edited 1 time in total.
User avatar
LuveelVoom
Posts: 782
Joined: April 27th, 2022, 7:59 pm

Re: LLSSS-NG: gchromodynamic's remarkable LLSSS fork

Post by LuveelVoom »

There's apparently a way to continue from a partial using this script "inspired" by qfind:
https://github.com/SuffixAutomata/llsss ... t-rows.lua
This is gchromodynamic's description of the process:
Screenshot 2026-09-28 at 9.55.27 PM.png
Screenshot 2026-09-28 at 9.55.27 PM.png (113.49 KiB) Viewed 205 times
Yeah, I don't know either.
User avatar
May13
Posts: 1102
Joined: March 11th, 2021, 8:33 am

Re: LLSSS-NG: gchromodynamic's remarkable LLSSS fork

Post by May13 »

For some reason, the --max-memory option doesn't work for me (I'm using Cygwin). Here is an example where I set an extremely low memory limit (1KB), but the search continues anyway:

Code: Select all

$ ./rlife llsss --rule 'B3/S23' --filters bcaf --threads 4 --right-edge odd --max-memory 1KB 3c7-f2b '@bg(13)'rlife: geom=3c7-f2b lattice=orthogonal p=7 k=3 subtiles=1 rule=B3/S23 width=13 left_edge=bg right_edge=odd bcaf=yes halt_on_ends=yes search_name=save
soft memory cap: 1024iB peak RSS
indexed relation walks: 4 workers
Row 14, 180 nodes, mem 87KiB, sec 0.000000, cols: [1/1\1/1\1/1\1/1\1/1\1/1\1/1\1/1\1/1\1/1\1/1\1]
Row 15, 222 nodes, mem 88KiB, sec 0.002231, cols: [1/2\2/4\4/7\4/7\4/7\4/7\4/7\4/7\4/7\4/7\4/6\3]
Row 16, 380 nodes, mem 88KiB, sec 0.001605, cols: [1/4\4/16\16/49\16/49\16/49\16/49\16/49\16/49\16/49\16/49\16/36\9]
Row 17, 992 nodes, mem 89KiB, sec 0.001630, cols: [1/8\8/64\64/343\64/343\64/343\64/343\64/343\64/343\64/343\64/343\64/216\27]
Row 18, 3394 nodes, mem 91KiB, sec 0.001904, cols: [1/16\16/256\256/2401\256/2401\256/2401\256/2401\256/2401\256/2401\256/2401\256/2401\256/1296\81]
Row 19, 6900 nodes, mem 95KiB, sec 0.003154, cols: [1/16\16/320\320/3430\448/4116\448/4116\448/4116\448/4116\448/4116\448/4116\448/3430\320/1728\108]
Row 20, 12784 nodes, mem 102KiB, sec 0.004812, cols: [1/16\16/400\400/4900\784/7056\784/7056\784/7056\784/7056\784/7056\784/7056\784/4900\400/2304\144]
Row 21, 22854 nodes, mem 114KiB, sec 0.007320, cols: [1/16\16/500\500/7000\1372/12096\1372/12096\1372/12096\1372/12096\1372/12096\1372/12096\1372/7000\500/3072\192]
Row 22, 47615 nodes, mem 139KiB, sec 0.011699, cols: [1/20\20/750\750/11700\3136/25776\3430/28368\3430/28368\3430/28368\3430/28368\3430/25920\3185/13500\875/4928\304]
Row 23, 88408 nodes, mem 185KiB, sec 0.015415, cols: [1/22\22/880\880/15490\4718/41364\6433/50952\6734/52908\6734/52908\6734/50928\6468/41916\4935/21100\1275/6296\420]
Row 24, 160266 nodes, mem 265KiB, sec 0.019449, cols: [1/23\23/990\990/19425\6546/63495\11990/90014\12986/96559\12986/96259\12986/89851\12046/64467\6939/30367\1755/7735\573]
Row 25, 316150 nodes, mem 428KiB, sec 0.029635, cols: [1/32\32/1424\1424/29512\10274/116982\25810/189193\29067/209755\29841/216010\29213/191250\26268/121956\11490/55495\3117/12796\969]
Row 26, 600578 nodes, mem 734KiB, sec 0.052874, cols: [1/49\49/2003\2003/42146\15231/198960\48708/374157\57564/434221\59984/448351\58696/387843\50988/220594\19176/92372\5421/20358\1548]
Row 27, 1053904 nodes, mem 1233KiB, sec 0.091590, cols: [1/77\77/2641\2641/56521\20672/298445\76242/632207\103394/771876\108856/763967\106130/677503\89715/374732\30059/140565\8362/30068\2403]
Row 28, 1787301 nodes, mem 2041KiB, sec 0.137995, cols: [1/125\125/3504\3504/75550\28073/432072\114145/1010669\181341/1292416\192613/1210141\182680/1079221\152674/621150\47413/210806\12984/43586\3628]
Row 29, 2594583 nodes, mem 2989KiB, sec 0.209826, cols: [1/160\160/4473\4473/96906\36765/557417\149969/1325207\257389/1717158\275262/1478339\238903/1319391\210980/847811\68037/282960\18795/58749\4943]
Row 30, 3483571 nodes, mem 4036KiB, sec 0.281239, cols: [1/183\183/5600\5600/118547\45871/677791\187642/1621641\335622/2157436\368662/1837346\310926/1584366\264861/1056923\93631/365756\26113/76624\6539]
Row 31, 4054500 nodes, mem 4739KiB, sec 0.365790, cols: [1/201\201/6677\6677/138653\55101/781352\220194/1785747\389840/2235431\411921/1740317\333044/1552930\288623/1131573\115948/423496\33596/93325\8030]
Row 32, 4488771 nodes, mem 5273KiB, sec 0.393105, cols: [1/276\276/8346\8346/164920\65404/887428\249904/1969114\442202/2348149\447529/1688171\334888/1488778\294306/1185098\133437/478771\41433/112903\9947]
Row 33, 4717658 nodes, mem 5586KiB, sec 0.414142, cols: [1/353\353/10124\10124/193415\76341/972462\270711/2081686\470289/2422439\457174/1733940\316521/1430670\276551/1198857\146205/526773\48063/131338\11735]
Row 34, 4747036 nodes, mem 5667KiB, sec 0.422788, cols: [1/436\436/11707\11707/216478\85817/1021427\280944/2068545\472078/2284722\433050/1639096\287252/1346778\262026/1188619\153423/549909\53308/146031\13538]
Row 35, 4197877 nodes, mem 5062KiB, sec 0.415331, cols: [1/521\521/12968\12968/232071\92000/1010225\271213/1811253\406134/1728034\345599/1292104\223673/1006173\212434/1019129\147015/525228\55200/151040\15077]
Row 36, 4293435 nodes, mem 5133KiB, sec 0.368133, cols: [1/646\646/15239\15239/263362\104789/1081391\289120/1852364\411599/1663677\338145/1294068\228914/1065524\229547/1123629\168570/597284\63742/173144\17090]
Row 37, 4606723 nodes, mem 5459KiB, sec 0.374733, cols: [1/821\821/18330\18330/295085\118941/1168535\313011/2037355\445341/1911039\367668/1508911\249321/1302146\256819/1276804\185552/639268\72310/192870\19191]
Row 38, 5146256 nodes, mem 6030KiB, sec 0.402571, cols: [1/1047\1047/22265\22265/336798\137426/1295107\349660/2320113\484410/2225639\408984/1803133\302947/1733531\315526/1529849\216504/733852\83333/218665\21591]
Row 39, 6125822 nodes, mem 7034KiB, sec 0.454237, cols: [1/1322\1322/26772\26772/401367\165509/1548795\414143/2990692\591079/2967003\523105/2571312\412932/2558832\402130/1952242\255074/869947\99368/261082\25189]
Row 40, 7725894 nodes, mem 8823KiB, sec 0.562095, cols: [1/1702\1702/33911\33911/488729\201107/1921818\506381/3863609\722475/4053271\678386/3716689\566509/3623696\525264/2445701\314635/1053901\118812/312079\30119]
Row 41, 10427179 nodes, mem 11MiB, sec 0.742262, cols: [1/2253\2253/43427\43427/608944\255815/2473724\665617/5225707\992259/5501662\976701/5173619\850177/5253668\753334/3197847\415839/1359589\151735/390036\36566]
Row 42, 14485796 nodes, mem 15MiB, sec 0.996114, cols: [1/2930\2930/57358\57358/773262\335714/3132889\877024/6785759\1378781/7512821\1420926/7552727\1304951/7633022\1095914/4287000\566460/1781671\200069/498217\44743]
Row 43, 18449379 nodes, mem 20MiB, sec 1.352216, cols: [1/3696\3696/74032\74032/942815\419379/3740972\1079071/8003247\1701599/9318696\1798611/9740394\1658928/9413659\1361787/5279277\709356/2195887\249983/618942\55633]
Row 44, 24537801 nodes, mem 26MiB, sec 1.705901, cols: [1/4782\4782/94418\94418/1169945\535524/4648771\1370953/10106940\2299898/12153445\2495974/12626678\2321464/12150185\1822506/6835133\899832/2728798\314003/759466\66370]
Row 45, 32013737 nodes, mem 34MiB, sec 2.186777, cols: [1/6034\6034/119868\119868/1467947\680272/5877001\1746654/12804118\2941342/15583943\3306576/16910460\3127075/15562152\2370525/8873399\1148136/3432567\391578/937508\82068]
Row 46, 38149499 nodes, mem 41MiB, sec 2.701019, cols: [1/7435\7435/148620\148620/1753892\806261/6951323\2065713/14606650\3387785/17374424\3823676/19206266\3624068/17169220\2721840/10109598\1344248/4002515\469412/1134947\100711]
Row 47, 48058403 nodes, mem 52MiB, sec 3.222106, cols: [1/9244\9244/181275\181275/2090236\955032/8133953\2460997/16481089\4165413/20155218\4907886/22554395\4751329/20071549\3482051/12308785\1683124/4929555\589350/1410697\126394]
Row 48, 59248234 nodes, mem 65MiB, sec 3.859878, cols: [1/11049\11049/217043\217043/2508393\1152138/9656916\2953035/18963420\4964954/23477425\6022115/27060895\5910154/23387710\4301038/15086938\2091203/6050956\719772/1721801\156313]
Interrupt requested. Will exit after completing the current row.
interrupt requested; saving completed row 49 and exiting
checkpoint saved: saves/save_49
Because of this, I cannot do partitioned searches.
Spaceship databases:
new-gliders.db (30683 gliders, square grid)
hex-gliders.db (668 gliders, hexagonal grid)
My scripts: new-glider.py v0.2, nbsearch2a.py, collector.py v0.3

-Dmitry Maitak
User avatar
LuveelVoom
Posts: 782
Joined: April 27th, 2022, 7:59 pm

Re: LLSSS-NG: gchromodynamic's remarkable LLSSS fork

Post by LuveelVoom »

May13 wrote: October 8th, 2026, 7:28 am For some reason, the --max-memory option doesn't work for me (I'm using Cygwin). Here is an example where I set an extremely low memory limit (1KB), but the search continues anyway:
I have brought this to gchromodynamic’s attention, thanks for the report

Edit: He says that the max memory option does not work on Cygwin but the program should be able to compile on native windows (???) Give it a shot, I guess
User avatar
May13
Posts: 1102
Joined: March 11th, 2021, 8:33 am

Re: LLSSS-NG: gchromodynamic's remarkable LLSSS fork

Post by May13 »

LuveelVoom wrote: October 8th, 2026, 10:54 am Edit: He says that the max memory option does not work on Cygwin but the program should be able to compile on native windows (???) Give it a shot, I guess
I haven't figured out how to compile the program on native Windows yet, but I tried running it using WSL 2 on my laptop with Windows 11, and the max-memory option works! Now the program shows the RSS value:

Code: Select all

Row 98, 3844675970 nodes, mem 4471MiB, 3490MiB RSS, sec 2083.753060, cols: [1/1133176\1133176/34287830\34287830/409129440\83882468/620318000\123253722/927083296\194746373/1193502282\253356267/1244293460\252206673/1133521657\222665534/935188406\180725835/695508666\131996960/452944102\89193169/279741852\55085874/153666928\20932789]
Spaceship databases:
new-gliders.db (30683 gliders, square grid)
hex-gliders.db (668 gliders, hexagonal grid)
My scripts: new-glider.py v0.2, nbsearch2a.py, collector.py v0.3

-Dmitry Maitak
Post Reply