Re: amling search program principles discussion / brain dump
Posted: October 9th, 2026, 2:27 pm
I think the filter and final partials stuff is looking pretty good. As I said above, simple use should be more or less unaffected but weird uses of filters or DL stuff will probably need to know some details.
The final partials stuff makes "--pre-partials none" slightly less weird. I still struggle to imagine wanting to have no idea what the search was doing until it finishes, but it works at least. If anyone is out there and does (want to) run LLSSS this way maybe drop me a line and let me know you exist?
I added LLSSS_LOG_LEVEL which can be used to restrict logs to that level and up. The order right now is DEBUG, INFO, WARNING, ERROR and the default is DEBUG (get everything). I've also banished a modest amount of spammier stuff to DEBUG.
Combining all this, search output can be pretty quiet now:
I did not exactly audit carefully all log lines, rather I just zapped whatever noisy stuff came up in my brief testing of this. If you choose to run at INFO and notice any particularly spammy lines maybe chime in here and we might choose to exile them to DEBUG as well.
The DL consequences of some of this reworking are material. For, uh, "simple" uses of DL it should shake out as "replace ^e with ^^ in lambdas", but it's certainly possible to have written DL that can't be fixed by just that. The details are complicated.
Previously when you did something like...
...what was happening was it was all compiled and interpreted in one shot by one DL interpreter. The "^e" constructs a lambda that cb_step's internals would later call with an object (bound to $e) that has methods like "log" on it. In this version the choice of "e" is arbitrary as the lambda's argument isn't named to its callers. This single DL interpreter's library of calls includes both "cb_step" and "log".
Now this has to be:
What is happening is "^^" is just quoting the inside (as a DL AST). When cb_step() is called with it, it does a second tier compile with a second DL interpreter and this compile provides a $e (or rather indicates it will provide one when it evaluates the results from the compile). The name "e" is part of cb_step's contract with the ASTs it is passed and it matters. Here the outer DL interpreter's library of calls includes "cb_step" and the inner's library includes "log".
Similarly there are difference in accessing $cfg, although it is provided either way. Before it was provided on the sole interpreter and the lambda could capture it from context. Now it is provided separately on each interpreter, and they both have registered the APIs for using it.
Finally, the APIs for halt have been reworked. I have replaced the convoluted dance of returning a halt indication with halt() being able to abort the DL evaluation and just stop everything immediately. E.g. this previously would fail to type check as old halt() return type and () don't match, but now, as a slight oversimplification, halt doesn't return so it's fine.
Most of this rework was done to make fixing the filter DL integration much less painful. Similar to step.gate() (formerly known as "gate_step()"), there is filter.gate() which will cause the filters to only run when the gate code evaluates to true. These gate() calls both (step and filter) again take an AST and provide a $e that has the sorts of methods you might expect.
Compare ungated filter running every expansion round:
Versus gated filter running only once at the end of each W row:
I've pushed (just now) all this to codeberg master as of 62cf0a520031. Please let me know here if it breaks on you.
The final partials stuff makes "--pre-partials none" slightly less weird. I still struggle to imagine wanting to have no idea what the search was doing until it finishes, but it works at least. If anyone is out there and does (want to) run LLSSS this way maybe drop me a line and let me know you exist?
I added LLSSS_LOG_LEVEL which can be used to restrict logs to that level and up. The order right now is DEBUG, INFO, WARNING, ERROR and the default is DEBUG (get everything). I've also banished a modest amount of spammier stuff to DEBUG.
Combining all this, search output can be pretty quiet now:
Code: Select all
$ rlife llsss-recentering-wao c2-f2b '@bg' 18 --llsss-env LLSSS_LOG_LEVEL=INFO --pre-partials none
20261009 10:51:49 [INFO] Start file magic grid generated:
20261009 10:51:49 [INFO] | | ZZZ |
20261009 10:51:49 [INFO] | ... | ... |
20261009 10:51:49 [INFO] | ... | ... |
20261009 10:51:49 [INFO] | ... | |
20261009 10:51:49 [INFO] WAO error window #0 (included):
20261009 10:51:49 [INFO] | | ZZZZZ |
20261009 10:51:49 [INFO] | ..... | ..... |
20261009 10:51:49 [INFO] | ..... | ..... |
20261009 10:51:49 [INFO] | ..xWW | |
20261009 10:51:49 [INFO] Start: precompile
20261009 10:51:49 [INFO] Finish: precompile -> took 23.941956ms (327.227ms user, 7µs sys)
20261009 10:51:49 [INFO] Start: search proper
20261009 10:51:49 [INFO] Cols sizes: 4 / 5
20261009 10:51:49 [INFO] Completed w_pos 4: 256 B, 12.989996ms
20261009 10:51:49 [INFO] Cols sizes: 8 / 14
20261009 10:51:49 [INFO] Completed w_pos 5: 416 B [+47.62%], 13.11836ms [+0.98%]
20261009 10:51:49 [INFO] Cols sizes: 14 / 24
20261009 10:51:49 [INFO] Completed w_pos 6: 1.15 KB [+95.48%], 14.313295ms [+8.71%]
...
20261009 10:51:51 [INFO] Completed w_pos 25: 12.33 KB [-17.99%], 41.396617ms [-21.39%]
20261009 10:51:51 [INFO] Cols sizes: 419 / 706
20261009 10:51:51 [INFO] Completed w_pos 26: 12.19 KB [-1.15%], 38.759995ms [-6.58%]
20261009 10:51:51 [INFO] Cols sizes: 415 / 627
20261009 10:51:51 [INFO] Completed w_pos 27: 10.17 KB [-18.03%], 37.87855ms [-2.30%]
20261009 10:51:51 [INFO] Cols sizes: 337 / 476
20261009 10:51:51 [INFO] Last thinnest partial RLE:
x = 49, y = 14, rule = LifeHistory
F.21B.F.21B.F$F.21B.F.21B.F$F.8BA3BA8B.F.7B3AB3A7B.F$F.7B3AB3A7B.F.6B
A2BABA2BA6B.F$F.6B2ABABAB2A6B.F.5BA3BABA3BA5B.F$F.5B2A7B2A5B.F.5BA9BA
5B.F$F.6BA7BA6B.F.7BA5BA7B.F$F.5B2A7B2A5B.F.4BABA7BABA4B.F$F.3B2ABABA
BABABAB2A3B.F.3B2AB2AB3AB2AB2A3B.F$F.3BA5BABA5BA3B.F.3BAB3ABABAB3ABA
3B.F$F.5BABABABABABA5B.F.2B2A5BABA5B2A2B.F$F.2B2ABABABABABABAB2A2B.F.
5BABABABABABA5B.F$F.5B2ABA3BAB2A5B.F.2B4A9B4A2B.F$F.2BA4BAB2AB2A4BA2B
.F.3B2ABAB2A3B2ABABA2B.F!
20261009 10:51:51 [INFO] Cols sizes hash: 0xA2A35BEF89A6CF63
20261009 10:51:51 [INFO] LlsssStepExpandRecentering: max pre-reify estimated mem: 196.36 KB
20261009 10:51:51 [INFO] Finish: search proper -> took 1.792972403s (22.111414s user, 651.021ms sys)
20261009 10:51:51 [INFO] Final results: 0 normal
20261009 10:51:51 [INFO] Done
$
Code: Select all
$ rlife llsss c2-f2b '@bg(22)' --filters bcaf --llsss-env LLSSS_LOG_LEVEL=INFO --pre-partials none
20261009 10:53:09 [INFO] Start file magic grid generated:
20261009 10:53:09 [INFO] | ...................... | ...................... |
20261009 10:53:09 [INFO] | ...................... | ...................... |
20261009 10:53:09 [INFO] Start: precompile
20261009 10:53:09 [INFO] Finish: precompile -> took 28.186804ms (341.657ms user, 3.441ms sys)
20261009 10:53:09 [INFO] Start: search proper
20261009 10:53:09 [INFO] Cols sizes: 1 / 1 \ 1 / 1 \ 1 / 1 \ 1 / 1 \ 1 / 1 \ 1 / 1 \ 1 / 1 \ 1 / 1 \ 1 / 1 \ 1 / 1 \ 1 / 1 \ 1 / 1 \ 1 / 1 \ 1 / 1 \ 1 / 1 \ 1 / 1 \ 1 / 1 \ 1 / 1 \ 1 / 1 \ 1 / 1 \ 1
20261009 10:53:09 [INFO] Completed w_pos 4: 2.17 KB, 34.960836ms
20261009 10:53:09 [INFO] Cols sizes: 1 / 2 \ 2 / 4 \ 4 / 7 \ 4 / 7 \ 4 / 7 \ 4 / 7 \ 4 / 7 \ 4 / 7 \ 4 / 7 \ 4 / 7 \ 4 / 7 \ 4 / 7 \ 4 / 7 \ 4 / 7 \ 4 / 7 \ 4 / 7 \ 4 / 7 \ 4 / 7 \ 4 / 4 \ 2 / 2 \ 1
20261009 10:53:09 [INFO] Completed w_pos 5: 3.40 KB [+44.04%], 47.736577ms [+30.90%]
20261009 10:53:09 [INFO] Cols sizes: 1 / 2 \ 2 / 5 \ 5 / 10 \ 7 / 12 \ 7 / 12 \ 7 / 12 \ 7 / 12 \ 7 / 12 \ 7 / 12 \ 7 / 12 \ 7 / 12 \ 7 / 12 \ 7 / 12 \ 7 / 12 \ 7 / 12 \ 7 / 12 \ 7 / 12 \ 7 / 10 \ 5 / 5 \ 2 / 2 \ 1
20261009 10:53:09 [INFO] Completed w_pos 6: 9.29 KB [+92.86%], 46.306472ms [-3.04%]
...
20261009 10:53:11 [INFO] Completed w_pos 25: 14.92 KB [-29.46%], 57.40335ms [-18.35%]
20261009 10:53:11 [INFO] Cols sizes: 1 / 12 \ 12 / 16 \ 16 / 24 \ 20 / 41 \ 24 / 31 \ 26 / 33 \ 25 / 35 \ 25 / 41 \ 31 / 51 \ 37 / 65 \ 34 / 65 \ 37 / 51 \ 31 / 41 \ 25 / 35 \ 25 / 33 \ 26 / 31 \ 24 / 41 \ 20 / 24 \ 16 / 16 \ 12 / 12 \ 1
20261009 10:53:11 [INFO] Completed w_pos 26: 13.23 KB [-11.99%], 53.821654ms [-6.44%]
20261009 10:53:11 [INFO] Cols sizes: 1 / 11 \ 11 / 15 \ 15 / 25 \ 19 / 25 \ 17 / 21 \ 15 / 19 \ 17 / 32 \ 21 / 44 \ 32 / 52 \ 37 / 63 \ 38 / 63 \ 37 / 52 \ 32 / 44 \ 21 / 32 \ 17 / 19 \ 15 / 21 \ 17 / 25 \ 19 / 25 \ 15 / 15 \ 11 / 11 \ 1
20261009 10:53:11 [INFO] Completed w_pos 27: 6.36 KB [-70.18%], 59.198252ms [+9.51%]
20261009 10:53:11 [INFO] Cols sizes: 1 / 4 \ 4 / 6 \ 6 / 8 \ 6 / 9 \ 6 / 9 \ 6 / 10 \ 7 / 13 \ 11 / 19 \ 18 / 28 \ 22 / 29 \ 22 / 29 \ 22 / 28 \ 18 / 19 \ 11 / 13 \ 7 / 10 \ 6 / 9 \ 6 / 9 \ 6 / 8 \ 6 / 6 \ 4 / 4 \ 1
20261009 10:53:11 [INFO] Last firstest partial RLE:
x = 51, y = 14, rule = LifeHistory
F.22B.F.22B.F$F.22B.F.22B.F$F.9BA3BA8B.F.8B3AB3A7B.F$F.8B3AB3A7B.F.7B
A2BABA2BA6B.F$F.7B2ABABAB2A6B.F.6BA3BABA3BA5B.F$F.6B2A7B2A5B.F.6BA9BA
5B.F$F.7BA7BA6B.F.8BA5BA7B.F$F.6B2A7B2A5B.F.5BABA7BABA4B.F$F.4B2ABABA
BABABAB2A3B.F.4B2AB2AB3AB2AB2A3B.F$F.4BA5BABA5BA3B.F.4BAB3ABABAB3ABA
3B.F$F.6BABABABABABA5B.F.3B2A5BABA5B2A2B.F$F.3B2ABABABABABABAB2A2B.F.
6BABABABABABA5B.F$F.6B2ABA3BAB2A5B.F.3B4A9B4A2B.F$F.3BA4BAB2AB2A4BA2B
.F.4B2ABAB2A3B2ABABA2B.F!
20261009 10:53:11 [INFO] Cols sizes hash: 0xBD35983F2FF3EA17
20261009 10:53:11 [INFO] Finish: search proper -> took 2.404107598s (24.427787s user, 1.452524s sys)
20261009 10:53:11 [INFO] Final results: 0 normal
20261009 10:53:11 [INFO] Done
$
The DL consequences of some of this reworking are material. For, uh, "simple" uses of DL it should shake out as "replace ^e with ^^ in lambdas", but it's certainly possible to have written DL that can't be fixed by just that. The details are complicated.
Previously when you did something like...
Code: Select all
$ rlife ... --extras 'cb_step(^e $e.log("DEBUG", "yay"))
Now this has to be:
Code: Select all
$ rlife ... --extras 'cb_step(^^ $e.log("DEBUG", "yay"))
Similarly there are difference in accessing $cfg, although it is provided either way. Before it was provided on the sole interpreter and the lambda could capture it from context. Now it is provided separately on each interpreter, and they both have registered the APIs for using it.
Finally, the APIs for halt have been reworked. I have replaced the convoluted dance of returning a halt indication with halt() being able to abort the DL evaluation and just stop everything immediately. E.g. this previously would fail to type check as old halt() return type and () don't match, but now, as a slight oversimplification, halt doesn't return so it's fine.
Code: Select all
$ rlife llsss c2-f2b '@bg(10)' --extras 'cb_step(^^ $e.w_pos == 10 ? $e.halt("BYE") : ())' | grep 'Completed\|BYE'
20261009 11:11:23 [INFO] Completed w_pos 4: 784 B, 24.147277ms
20261009 11:11:23 [INFO] Completed w_pos 5: 1.05 KB [+31.76%], 23.282858ms [-3.65%]
20261009 11:11:23 [INFO] Completed w_pos 6: 2.07 KB [+65.00%], 27.400144ms [+16.25%]
20261009 11:11:23 [INFO] Completed w_pos 7: 3.85 KB [+60.16%], 24.607157ms [-10.74%]
20261009 11:11:23 [INFO] Completed w_pos 8: 5.20 KB [+29.71%], 28.248522ms [+13.78%]
20261009 11:11:23 [WARNING] Halting (reason: BYE)...
Compare ungated filter running every expansion round:
Code: Select all
$ rlife llsss p3 '@bg(10)' --constraint statorless --filters 'bcaf' | grep 'LlsssFilterAgarCycleAvoiding.*u_pos 0'
20261009 11:07:57 [DEBUG] Filtered [LlsssFilterAgarCycleAvoiding]: w_pos 2[2] u_pos 0 [bcol]: 1 -> 1 [-]
20261009 11:07:57 [DEBUG] Filtered [LlsssFilterAgarCycleAvoiding]: w_pos 2[2] u_pos 0 [col]: 7 -> 7 [-]
20261009 11:07:57 [DEBUG] Filtered [LlsssFilterAgarCycleAvoiding]: w_pos 3[0] u_pos 0 [bcol]: 1 -> 1 [-]
20261009 11:07:57 [DEBUG] Filtered [LlsssFilterAgarCycleAvoiding]: w_pos 3[0] u_pos 0 [col]: 12 -> 12 [-]
20261009 11:07:57 [DEBUG] Filtered [LlsssFilterAgarCycleAvoiding]: w_pos 3[1] u_pos 0 [bcol]: 1 -> 1 [-]
20261009 11:07:57 [DEBUG] Filtered [LlsssFilterAgarCycleAvoiding]: w_pos 3[1] u_pos 0 [col]: 18 -> 18 [-]
20261009 11:07:57 [DEBUG] Filtered [LlsssFilterAgarCycleAvoiding]: w_pos 3[2] u_pos 0 [bcol]: 1 -> 1 [-]
20261009 11:07:57 [DEBUG] Filtered [LlsssFilterAgarCycleAvoiding]: w_pos 3[2] u_pos 0 [col]: 16 -> 16 [-]
20261009 11:07:57 [DEBUG] Filtered [LlsssFilterAgarCycleAvoiding]: w_pos 4[0] u_pos 0 [bcol]: 1 -> 1 [-]
20261009 11:07:57 [DEBUG] Filtered [LlsssFilterAgarCycleAvoiding]: w_pos 4[0] u_pos 0 [col]: 27 -> 27 [-]
20261009 11:07:57 [DEBUG] Filtered [LlsssFilterAgarCycleAvoiding]: w_pos 4[1] u_pos 0 [bcol]: 1 -> 1 [-]
20261009 11:07:57 [DEBUG] Filtered [LlsssFilterAgarCycleAvoiding]: w_pos 4[1] u_pos 0 [col]: 42 -> 42 [-]
20261009 11:07:57 [DEBUG] Filtered [LlsssFilterAgarCycleAvoiding]: w_pos 4[2] u_pos 0 [bcol]: 1 -> 1 [-]
20261009 11:07:57 [DEBUG] Filtered [LlsssFilterAgarCycleAvoiding]: w_pos 4[2] u_pos 0 [col]: 43 -> 43 [-]
...
Code: Select all
$ rlife llsss p3 '@bg(10)' --constraint statorless --filters 'bcaf.gate(^^ $e.subtile_pos == 2)' | grep 'LlsssFilterAgarCycleAvoiding.*u_pos 0'
20261009 11:19:52 [DEBUG] Filtered [LlsssFilterAgarCycleAvoiding]: w_pos 2[2] u_pos 0 [bcol]: 1 -> 1 [-]
20261009 11:19:52 [DEBUG] Filtered [LlsssFilterAgarCycleAvoiding]: w_pos 2[2] u_pos 0 [col]: 7 -> 7 [-]
20261009 11:19:53 [DEBUG] Filtered [LlsssFilterAgarCycleAvoiding]: w_pos 3[2] u_pos 0 [bcol]: 1 -> 1 [-]
20261009 11:19:53 [DEBUG] Filtered [LlsssFilterAgarCycleAvoiding]: w_pos 3[2] u_pos 0 [col]: 16 -> 16 [-]
20261009 11:19:53 [DEBUG] Filtered [LlsssFilterAgarCycleAvoiding]: w_pos 4[2] u_pos 0 [bcol]: 1 -> 1 [-]
20261009 11:19:53 [DEBUG] Filtered [LlsssFilterAgarCycleAvoiding]: w_pos 4[2] u_pos 0 [col]: 43 -> 43 [-]
20261009 11:19:53 [DEBUG] Filtered [LlsssFilterAgarCycleAvoiding]: w_pos 5[2] u_pos 0 [bcol]: 1 -> 1 [-]
20261009 11:19:53 [DEBUG] Filtered [LlsssFilterAgarCycleAvoiding]: w_pos 5[2] u_pos 0 [col]: 76 -> 76 [-]
...