So in looking at @lspector's slides for the "Expressive GP" tutorial, I found myself asking a lot of questions about these tag things since there are several slides devoted to them.
I went and looked through all of @thelmuth's "clustering" results (essentially anything where he saved CSV files with entire populations across the whole run). There are 900 log files (runs) in that set, 249 of which were successful. 16 of those 249 have the string "tag" somewhere in the simplified successful program at the end. 11 have both "tag_" and "tagged_", so 11 of 249 (less than 5%) both declare a tag and use a tag in the simplified, successful program.
Maybe. It could be less. I've got a few questions about how these things are actually implemented that I'm hoping @thelmuth and/or @lspector can help clarify:
- When an instruction (or block of instructions) is tagged, is it popped from the
exec stack? This appears to be under the control of a
global-pop-when-tagging variable, which appears to default to
true, which which appears to still be true in these runs.
- It is not executed when it's popped, right? So I think it quietly vanishes when it's tagged, only to appear again later if a tag is searched for. Is that true?
- Tagging is done _when the
tag instruction is executed, and not sooner, right? So if I have a
tagged instruction first, it won't find anything, right? If so my simple grepping above may be over counting, as there might be programs there that have both a
tag_ and a
tagged_, but in the wrong order so the tagging actually has no effect.
So there could be less than 11 because of the ordering thing. There could also be less than 11 because some of the
tag_ instructions might be trying to tag items on empty stacks, and thus turn into NOOPs.
A quick skim (some of these are quite long, even after simplification) identifies a few that use tags to re-arrange the order of things. This solution to Syllables:
(\e "ThF &umb1r oV syllable=1isa" integer_fromchar
string_last \y \o in1 char_swap \i string_replacechar
tag_exec_950 (\u \i string_replacechar \i string_replacechar
\i char_yankdup string_replacechar string_occurrencesofchar
string_replacechar "The number of syllables is " \o \e
for example, appears to be using tags to essentially move the tagged block from where it is to the end of the program, where it is called once. So not really any kind of modularity so much as a way to fix a bit of bad positioning.
I think this solution to string-length-backwards:
(string_length tagged_225 print_integer
is also using tags to move an instruction (the
print_newline) from the end of that block to the second spot, but only after the loop as been executed once, thereby avoiding a spurious newline the first time through the loop.
And I may have identified one instance where tagging is being used in a tag-y sort of way to create a module. If I'm understanding all the pieces correctly, I think this solution to negative-to-zero actually uses tags to create some sort of module:
(boolean_stackdepth integer_min boolean_stackdepth
exec_dup (vector_integer_pushall in1) tagged_279)
This starts by tagging an
exec block, then it sets some things up and calls that block. That block ends in a tagged call, so it is effectively an infinite loop, relying on the step limit to stop it eventually. I think the block takes the next value from the integer stack (which contains all the values in the input vector as part of the setup), mins it with 0, and then either (a) replaces all instances of 0 with 0 if the vector value was ≥0 or (b) replaces all instances of the value with 0 if the vector value was ≤0. So it works, which is cool, and it is actually a tagged block that is being called with something akin to a
GOTO (less cool? more cool?).
In general, though, it really doesn't look like tagging is happening much, and I'd bet good money that @thelmuth could have run all these experiments without the tagging instructions and seen little to no impact on the results.
I've included all 11 of the simplified solutions that my quick
grep identified in this file: tagged_programs.txt (8.6 KB)