This is a further development of @ais523's answer, reducing it to only two sets of brackets, and also using a more compact cell placement based on Golomb ruler theory. ais523 has made a compiler for this construction, as well as this TIO session showing a sample resulting BF program running with debug tracing of the TWM counters.
Like the original, this starts with a program in The Waterfall Model, with some restrictions that don't lose generality:
- All counters have the same self-reset value $R$; that is, the TWM trigger map $f$ has the property that $f(x,x)=R$ for all $x$.
- There is a single halting counter $h$.
- The number $c$ of counters is $(p-1)/2$ for some prime number $p$.
Golomb ruler
We combine the Erdős–Turán construction with the permutation function of a Welch–Costas array in order to get a Golomb ruler with the necessary properties.
(I'm sure this combined construction cannot be a new idea but we just found and fit together these two pieces from Wikipedia.)
Let $r$ be a primitive root of $p=2c+1$. Define the function
$$g(k)=4ck - ((r^k-1)\bmod(2c+1)), k=0,\ldots,2c-1.$$
- $g$ is a Golomb ruler of order $2c$. That is, the difference $g(i)-g(j)$ is unique for every pair of distinct numbers $i,j \in \{0,\ldots,2c-1\}$.
- $g(k)\bmod(2c)$ takes on every value $0,\ldots,2c-1$ exactly once.
Tape structure
For each TWM counter $x\in \{0,\ldots,c-1\}$, we assign two BF tape cell positions, a fallback cell $u(x)$ and a value cell $v(x)$:
$$u(x)=g(k_1)<v(x)=g(k_2)\mbox{ with }u(x)\equiv v(x)\equiv x\pmod c$$
By the second property of $g$ there are exactly two distinct $k_1,k_2$ values to choose from.
A fallback cell's content will most of the time be kept at $0$, except when its counter has just been visited, when it will be at $2R$, twice the counter self-reset value. A value cell will be kept at twice the value of the corresponding TWM counter.
All other cells that can be reached by the BF program execution (a finite number) will be kept at odd values, so that they always test as nonzero. After initialization this is automatic because all cell adjustments are by even amounts.
If desired, all cell positions can be shifted rightwards by a constant in order to avoid moving to the left of the initial BF tape position.
BF program structure
Let $H = v(h)-u(h)$ be the distance between the halting counter's value and fallback cells, and let $N$ be a number large enough that $cN+1 \geq v((x+1)\bmod c) - u(x)$ for all counters $x$. Then the basic BF program structure is
initialization [
>
$\times (H+cN+1)$ [
<
$\times c$ ]
adjustments <
$\times H$ ]
Initialization
The initialization phase sets all cells reachable by the program to their initial values, in a state as if the last counter had just been visited and the just active cell was its fallback cell $u(c-1)$:
- Value cells are initialized to twice the initial content of the corresponding TWM counter, except that counter $0$ is pre-decremented.
- Fallback cells are set to $0$, except cell $u(c-1)$, which is set to $2R$.
- All other cells reachable by the program (a finite number) are set to $1$.
Then the tape pointer is moved to position $u(c-1)-H$ (an always non-zero cell) before we reach the program's first [
.
Beginning of outer loop
At the beginning of an iteration of the outer loop, the tape pointer will be at either $u(x)-H$ or $v(x)-H$ for a counter $x$.
Let $y=((x+1)\bmod c)$ be the next counter to visit.
The movement >
$\times (H+cN+1)$ places the tape pointer on a position that is $\equiv y\pmod c$ and not to the left of $v(y)$.
The inner loop [
<
$\times c$ ]
now searches leftwards in steps of $c$ for a zero cell. If counter $y$ is zero, then it will stop at the (zero) value cell $v(y)$; otherwise it will find the fallback cell $u(y)$.
Whichever cell is found becomes the new active cell.
Adjustments
The adjustment phase adjusts various cells on the tape based on their position relative to the active cell. This section contains only +-><
commands and so these adjustments happen unconditionally. However, because all counter-related cells are in a Golomb ruler pattern, any adjustments that are not proper for the current active cell will miss all the important cells and adjust some irrelevant cell instead (while keeping it odd).
Separate code must thus be included in the program for each possible required pair of active and adjusted cell, except for an active cell's self-adjustment, which, because adjustment is based solely on relative position, must be shared between all of them.
The required adjustments are:
- Adjust the previous counter's fallback cell $u(x)$ by $-2R$.
- Adjust the current counter's fallback cell $u(y)$ by $2R$, except if the current active cell is $v(h)$ and so we should halt.
- Adjust the next counter's value cell $v((y+1)\bmod c)$ by $-2$ (decrementing the counter).
- When the active cell is a value cell $v(y)$ (so the counter $y$ has reached zero), adjust all value cells $v(z)$ by $2f(y,z)$ from the TWM trigger map. $v(y)$ itself becomes adjusted by $2R$.
The first and second adjustments above are made necessary by the fact that all active cells must adjust themselves by the same value, which is $2R$ for value cells, and thus also for fallback cells. This requires preparing and cleaning up the fallback cells to ensure they get back to $0$ in both the value and fallback branches.
End of outer loop
The movement <
$\times H$ represents that at the end of the adjustment phase, the tape pointer is moved $H$ places to the left of the active cell.
For all active cells other than the halting counter's value cell $v(h)$, this is an irrelevant cell, and so odd and non-zero, and the outer loop continues for another iteration.
For $v(h)$, the pointer is instead placed on its corresponding fallback cell $u(h)$, for which we have made an exception above to keep it zero, and so the program exits through the final ]
and halts.