Antihydra: Difference between revisions

From BusyBeaverWiki
Jump to navigation Jump to search
(Adding sources section, adding a source for its Collatz rule, and documenting access dates of Discord messages based on edit history)
(Combined introduction with link to bbch)
 
(44 intermediate revisions by 9 users not shown)
Line 1: Line 1:
{{machine|1RB1RA_0LC1LE_1LD1LC_1LA0LB_1LF1RE_---0RA}}
{{machine|1RB1RA_0LC1LE_1LD1LC_1LA0LB_1LF1RE_---0RA}}{{unsolved|Does Antihydra run forever?}}
[[File:Antihydra-depiction.png|right|thumb|Artistic depiction of Antihydra by Jadeix]]
{{TM|1RB1RA_0LC1LE_1LD1LC_1LA0LB_1LF1RE_---0RA|undecided}}, called '''Antihydra''', is a [[BB(6)]] [[Cryptid]]. Its pseudo-random behaviour was first reported [https://discord.com/channels/960643023006490684/1026577255754903572/1256223215206924318 on Discord] by mxdys on 28 June 2024, and Racheline discovered the high-level rules soon after. It was named after the 2-state, 5-symbol [[Turing machine]] called [[Hydra]] for sharing many similarities to it.<ref>[https://discord.com/channels/960643023006490684/960643023530762341/1257053002859286701 Discord conversation where the machine was named]</ref>
Antihydra is the 6-state 2-symbol machine {{TM|1RB1RA_0LC1LE_1LD1LC_1LA0LB_1LF1RE_---0RA}}.


This machine was the first identified [[BB(6)]] Collatz-like [[Cryptid]], and is closely related to [[Hydra]].
Antihydra is known to not generate Sturmian words<ref>DUBICKAS A. ON INTEGER SEQUENCES GENERATED BY LINEAR MAPS. ''Glasgow Mathematical Journal''. 2009;51(2):243-252. doi:[https://doi.org/10.1017/S0017089508004655 10.1017/S0017089508004655]</ref> (Corollary 4).
 
<table style="margin: auto; text-align: center;"><tr><td style="width: 200px;">[[File:Antihydra-depiction.png|200px]]<br>Artistic depiction of Antihydra by Jadeix</td><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td><td>
It simulates the Collatz-like iteration
{|class="wikitable" style="margin-left: auto; margin-right: auto;"
 
! !!0!!1
<math display="block">\begin{array}{l}
|-
  A(2a,   & b) & \to & A(3a,   & b+2) \\
!A
  A(2a+1, & b) & \to & A(3a+1, & b-1) & \text{if} & b>0 \\
|1RB
  A(2a+1, & 0) & \to & \text{HALT}
|1RA
|-
!B
|0LC
|1LE
|-
!C
|1LD
|1LC
|-
!D
|1LA
|0LB
|-
!E
|1LF
|1RE
|-
!F
| ---
|0RA
|}
The transition table of Antihydra.
</td><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td><td style="width: 220px;">[[File:Antihydra award.jpg|220px]]<br>A community trophy - to be awarded to the first person or group who solves the Antihydra problem
</td></tr></table></div>
== Analysis ==
Let <math>A(a,b):=0^\infty\;1^a\;0\;1^b\;\textrm{E>}\;0^\infty</math>. Then,<ref name="bl">S. Ligocki, "[https://www.sligocki.com/2024/07/06/bb-6-2-is-hard.html BB(6) is Hard (Antihydra)]" (2024). Accessed 22 July 2024.</ref>
<math display="block">\begin{array}{|lll|}\hline
A(a,2b)& \xrightarrow{2a+3b^2+12b+11}& A(a+2,3b+2),\\
A(0,2b+1)&\xrightarrow{3b^2+9b-1}& 0^\infty\;\textrm{<F}\;110\;1^{3b}\;0^\infty,\\
A(a+1,2b+1)&\xrightarrow{3b^2+12b+5}& A(a,3b+3).\\\hline
\end{array}</math>
\end{array}</math>
<br>
<div class="toccolours mw-collapsible mw-collapsed">'''Proof'''<div class="mw-collapsible-content">
starting from <math>A(8, 0)</math>, using configurations of the form <math>A(a+4, b) = 0^\infty \; 1^b \; 0 \; 1^a \; E> \; 0^\infty</math>.<ref>S. Ligocki, "[https://www.sligocki.com/2024/07/06/bb-6-2-is-hard.html BB(6) is Hard (Antihydra)]" (2024). Accessed 22 July 2024.</ref>
Consider the partial configuration <math>P(m,n):=0\;1^m\;\textrm{E>}\;0\;1^n\;0^\infty</math>. The configuration after two steps is <math>0\;1^{m-1}\;0\;\textrm{A>}\;1^{n+1}\;0^\infty</math>. We note the following shift rule:
 
<math display="block">\begin{array}{|c|}\hline\textrm{A>}\;1^s\xrightarrow{s}1^s\;\textrm{A>}\\\hline\end{array}</math>
It was discovered by mxdys on 28 Jun 2024 and shared on Discord.<ref>[https://discord.com/channels/960643023006490684/1026577255754903572/1256223215206924318 Discord message], accessed 30 June 2024.</ref>
As a result, we get <math>0\;1^{m-1}\;0\;1^{n+1}\;\textrm{A>}\;0^\infty</math> after <math>n+1</math> steps. Advancing two steps produces <math>0\;1^{m-1}\;0\;1^{n+2}\;\textrm{<C}\;0^\infty</math>. A second shift rule is useful here:
 
<math display="block">\begin{array}{|c|}\hline1^s\;\textrm{<C}\xrightarrow{s}\textrm{<C}\;1^s\\\hline\end{array}</math>
Racheline found that compared to the [[Hydra]] iteration, this one starts at (8, 0) rather than (3, 0), and the roles of odd and even a are exchanged (in terms of which increases b by two, and which decrements b or halts).
This allows us to reach <math>0\;1^{m-1}\;0\;\textrm{<C}\;1^{n+2}\;0^\infty</math> in <math>n+2</math> steps. Moving five more steps gets us to <math>0\;1^{m-2}\;\textrm{E>}\;0\;1^{n+3}\;0^\infty</math>, which is the same configuration as <math>P(m-2,n+3)</math>. Accounting for the head movement creates the condition that <math>m\ge 4</math>. In summary:
Obstacles to proving the long-run behavior are equally serious.
<math display="block">\begin{array}{|c|}\hline P(m,n)\xrightarrow{2n+12}P(m-2,n+3)\text{ if }m\ge 4.\\\hline\end{array}</math>
Like the [[Hydra]] iteration, this one is biased toward increasing the value of b (assuming equal chances of adding +2 or -1).
With <math>A(a,b)</math> we have <math>P(b,0)</math>. As a result, we can apply this rule <math display="inline>\big\lfloor\frac{1}{2}b\big\rfloor-1</math> times (assuming <math>b\ge 4</math>), which creates two possible scenarios:
 
#If <math>b\equiv0\ (\operatorname{mod}2)</math>, then in <math>\sum_{i=0}^{(b/2)-2}(2\times 3i+12)=\textstyle\frac{3}{4}b^2+\frac{3}{2}b-6</math> steps we arrive at <math display="inline">P\Big(2,\frac{3}{2}b-3\Big)</math>. The matching complete configuration is <math>0^\infty\;1^a\;011\;\textrm{E>}\;0\;1^{(3b)/2-3}\;0^\infty</math>. After <math>3b+4</math> steps this is <math>0^\infty\;1^a\;\textrm{<C}\;00\;1^{(3b)/2}\;0^\infty</math>, which then leads to <math>0^\infty\;\textrm{<C}\;1^a\;00\;1^{(3b)/2}\;0^\infty</math> in <math>a</math> steps. After five more steps, we reach <math>0^\infty\;1\;\textrm{E>}\;1^{a+2}\;00\;1^{(3b)/2}\;0^\infty</math>, from which another shift rule must be applied:<math display="block">\begin{array}{|c|}\hline\textrm{E>}\;1^s\xrightarrow{s}1^s\;\textrm{E>}\\\hline\end{array}</math>Doing so allows us to get the configuration <math>0^\infty\;1^{a+3}\;\textrm{E>}\;00\;1^{(3b)/2}\;0^\infty</math> in <math>a+2</math> steps. In six steps we have <math>0^\infty\;1^{a+2}\;011\;\textrm{E>}\;1^{(3b)/2}\;0^\infty</math>, so we use the shift rule again, ending at <math>0^\infty\;1^{a+2}\;0\;1^{(3b)/2+2}\;\textrm{E>}\;0^\infty</math>, equal to <math display="inline">A\Big(a+2,\frac{3}{2}b+2\Big)</math>, <math display="inline">\frac{3}{2}b</math> steps later. This gives a total of <math display="inline">2a+\frac{3}{4}b^2+6b+11</math> steps.
There is no halt in the first 11.8 million iterations, by which point b has reached 5890334 (which means that it also does not halt in the first 17690334 iterations).<ref>[https://discord.com/channels/960643023006490684/1026577255754903572/1256403772998029372 Discord message], accessed 2 July 2024.</ref>
#If <math>b\equiv1\ (\operatorname{mod}2)</math>, then in <math display="inline">\frac{3}{4}b^2-\frac{27}{4}</math> steps we arrive at <math display="inline">P\Big(3,\frac{3b-9}{2}\Big)</math>. The matching complete configuration is <math>0^\infty\;1^a\;0111\;\textrm{E>}\;0\;1^{(3b-9)/2}\;0^\infty</math>. After <math>3b+2</math> steps this becomes <math>0^\infty\;1^a\;\textrm{<F}\;110\;1^{(3b-3)/2}\;0^\infty</math>. If <math>a=0</math> then we have reached the undefined <code>F0</code> transition with a total of <math display="inline">\frac{3}{4}b^2+3b-\frac{19}{4}</math> steps. Otherwise, continuing for six steps gives us <math>0^\infty\;1^{a-1}\;0111\;\textrm{E>}\;1^{(3b-3)/2}\;0^\infty</math>. We conclude with the configuration <math>0^\infty\;1^{a-1}\;0\;1^{(3b+3)/2}\;\textrm{E>}\;0^\infty</math>, equal to <math display="inline">A\Big(a-1,\frac{3b+3}{2}\Big)</math>, in <math display="inline">\frac{3b-3}{2}</math> steps. This gives a total of <math display="inline">\frac{3}{4}b^2+\frac{9}{2}b-\frac{1}{4}</math> steps.
 
The information above can be summarized as
== Simulator ==
<math display="block">A(a,b)\rightarrow\begin{cases}A\Big(a+2,\frac{3}{2}b+2\Big)&\text{if }b\ge 2,b\equiv0\pmod{2};\\0^\infty\;\textrm{<F}\;110\;1^{(3b-3)/2}\;0^\infty&\text{if }b\ge3,b\equiv1\pmod{2},\text{ and }a=0;\\A\Big(a-1,\frac{3b+3}{2}\Big)&\text{if }b\ge3,b\equiv1\pmod{2},\text{ and }a>0.\end{cases}</math>
 
Substituting <math>b\leftarrow 2b</math> for the first case and <math>b\leftarrow 2b+1</math> for the other two yields the final result.
Two simulators are available. A fast simulator written in Rust for the odd/even sequence used by Antihydra is available [http://nethack4.org/esolangs/fasthydra.zip here].
</div></div>
In effect, the halting problem for Antihydra is about whether repeatedly applying the function <math display="inline">f(n)=\Big\lfloor\frac{3n}{2}\Big\rfloor+2</math> will at some point produce more odd values of <math>n</math> than twice the number of even values.


Alternatively, here is a GMP implementation of the program with some performance diagnostics added:<syntaxhighlight lang="c">
These rules can be modified to use the function <math display="inline">H(n)=\Big\lfloor\frac{3n}{2}\Big\rfloor</math>, or the [[Hydra function]], which strengthens Antihydra's similarities to Hydra.
/* Tested on GMP 6.3.0, Ubuntu 24.04. */
== Trajectory ==
11 steps are required to enter the configuration <math>A(0, 4)</math> before the rules are repeatedly applied. So far, Antihydra has been simulated to <math>2^{31}</math> rule steps, at which point <math>b=1073720884</math>. Here are the first few:
<math display="block">\begin{array}{|c|}\hline A(0,4)\xrightarrow{47}A(2,8)\xrightarrow{111}A(4,14)\xrightarrow{250}A(6,23)\xrightarrow{500}A(5,36)\xrightarrow{1209}A(7,56)\xrightarrow{2713}A(9,86)\rightarrow\cdots\\\hline\end{array}</math>
The trajectory of <math>b</math> values resembles a random walk in which the walker can only move in step sizes +2 or -1 with equal probability, starting at position 0. If <math>P(n)</math> is the probability that the walker will reach position -1 from position <math>n</math>, then it can be seen that <math display="inline">P(n)=\frac{1}{2}P(n-1)+\frac{1}{2}P(n+2)</math>. Solutions to this recurrence relation come in the form <math display="inline"> P(n)=c_0{\left(\frac{\sqrt{5}-1}{2}\right)}^n+c_1+c_2{\left(-\frac{1+\sqrt{5}}{2}\right)}^n</math>, which after applying the appropriate boundary conditions reduces to <math display="inline">P(n)={\left(\frac{\sqrt{5}-1}{2}\right)}^{n+1}</math>. This means that if the walker were to get to position 1073720884 then the probability of it ever reaching position -1 is <math display="inline">{\left(\frac{\sqrt{5}-1}{2}\right)}^{1073720885}\approx 4.841\times 10^{-224394395}</math>. This combined with the fact that the expected position of the walker after <math>k</math> steps is <math display="inline">\frac{1}{2}k</math> strongly suggests Antihydra [[probviously]] runs indefinitely.


#include <stdio.h>
== Code ==
#include <stdint.h>
The following Python program implements the abstracted behavior of the Antihydra. Proving whether it halts or not would also solve the Antihydra problem:<syntaxhighlight lang="python" line="1">
#include <inttypes.h>
# Current value of the iterated Hydra function starting with initial value 8 (the values do not overflow)
#include <time.h>
h = 8
# (Collatz-like) condition counter that keeps track of how many odd and even numbers have been encountered
c = 0
# If c equals -1 there have been (strictly) more than twice as many odd as even numbers and the program halts
while c != -1:
    # If h is even, add 2 to c so even numbers count twice
    if h % 2 == 0:
        c += 2
    else:
        c -= 1
    # Add the current hydra value divided by two (integer division, rounding down) to itself (Hydra function)
    # Note that integer division by 2 is equivalent to one bit shift to the right (h >> 1)
    h += h//2
</syntaxhighlight>


#include <gmp.h>
The variable values of this iteration have been put into the On-Line Encyclopedia of Integer Sequences (OEIS):


static uint64_t get_milis(void) {
* Hydra function values with Antihydra's starting value 8: https://oeis.org/A386792
    struct timespec ts;
* Antihydra's condition values: https://oeis.org/A385902
    timespec_get(&ts, TIME_UTC);
    return (uint64_t)(ts.tv_sec * 1000 + ts.tv_nsec/1000000);
}


int main(int argc, char **argv) {
Fast [[Hydra]]/Antihydra simulation code by Greg Kuperberg (who said it could be made faster using FLINT):<syntaxhighlight lang="python2" line="1">
    char *as, *bs;
# Python script to demonstrate almost linear time hydra simulation
    mpz_t a, aq, ar, b;
# using fast multiplication.
    uint64_t i, time, newtime;
# by Greg Kuperberg


    /* CLI and init. */
import time
    if (argc > 1) {
from gmpy2 import mpz,bit_mask
        as = argv[1];
    } else {
        as = "8";
    }
    if (argc > 2) {
        bs = argv[2];
    } else {
        bs = "0";
    }
    mpz_init_set_str(a, as, 10);
    mpz_init_set_str(b, bs, 10);
    mpz_init(aq);
    mpz_init(ar);
    i = 0;
    time = get_milis();


    /* Run. */
# Straight computation of t steps of hydra
    while (1) {
def simple(n,t):
        /* aq = a / 2
    for s in range(t): n += n>>1
        * ar = a % 2 */
    return n
        mpz_fdiv_qr_ui(aq, ar, a, 2);
        if (
            /* odd */
            mpz_cmp_ui(ar, 0)
        ) {
            if (!mpz_cmp_ui(b, 0)) break;
            /* a = aq * 3 + 1 */
            mpz_mul_ui(a, aq, 3);
            mpz_add_ui(a, a, 1);
            /* b -= 1 */
            mpz_sub_ui(b, b, 1);
        } else {
            /* a = aq * 3 */
            mpz_mul_ui(a, aq, 3);
            /* b += 2 */
            mpz_add_ui(b, b, 2);
        }
        i++;
        if (i % 100000 == 0) {
            newtime = get_milis();
            gmp_printf("%" PRIu64 " ms=%" PRIu64 " log10(a)=%ju log10(b)=%ju\n",
                      i/100000, newtime - time, mpz_sizeinbase(a, 10), mpz_sizeinbase(b, 10));
            time = newtime;
        }
    }


    /* Cleanup if we ever reach it. */
# Accelerated computation of 2**e steps of hydra
     mpz_clear(a);
def hydra(n,e):
     mpz_clear(aq);
     if e < 9: return simple(n,1<<e)
     mpz_clear(ar);
     t = 1<<(e-1)
     mpz_clear(b);
     (p3t,m) = (mpz(3)**t,bit_mask(t))
     return 0;
     n = p3t*(n>>t) + hydra(n&m,e-1)
}
     return p3t*(n>>t) + hydra(n&m,e-1)
‎</syntaxhighlight>


Compile and run with:<syntaxhighlight lang="bash">
def elapsed():
gcc -ggdb3 -O2 -pedantic-errors -std=c11 -Wall -Wextra -o 'antihydra.out' 'antihydra.c' -lgmp
    (last,elapsed.mark) = (elapsed.mark,time.process_time())
./antihydra.out
    return elapsed.mark-last
‎</syntaxhighlight>
elapsed.mark = 0


Tested on Tested on GMP 6.3.0, Ubuntu 24.04.
(n,e) = (mpz(3),25)


==Sources==
elapsed()
<references />
print('hydra:  steps=%d hash=%016x time=%.6fs'
    % (1<<e,hash(hydra(n,e)),elapsed()))


# Quadratic time algorithm for comparison
# print('simple: steps=%d hash=%016x time=%.6fs'
#    % (1<<e,hash(simple(n,1<<e)),elapsed()))
</syntaxhighlight>


[[Category:Individual machines]]
==References==
[[Category:Individual machines]][[Category:Cryptids]]

Latest revision as of 21:23, 10 August 2025

Unsolved problem:
Does Antihydra run forever?

1RB1RA_0LC1LE_1LD1LC_1LA0LB_1LF1RE_---0RA (bbch), called Antihydra, is a BB(6) Cryptid. Its pseudo-random behaviour was first reported on Discord by mxdys on 28 June 2024, and Racheline discovered the high-level rules soon after. It was named after the 2-state, 5-symbol Turing machine called Hydra for sharing many similarities to it.[1]

Antihydra is known to not generate Sturmian words[2] (Corollary 4).


Artistic depiction of Antihydra by Jadeix
      
0 1
A 1RB 1RA
B 0LC 1LE
C 1LD 1LC
D 1LA 0LB
E 1LF 1RE
F --- 0RA

The transition table of Antihydra.

      
A community trophy - to be awarded to the first person or group who solves the Antihydra problem

Analysis

Let . Then,[3]

Proof

Consider the partial configuration . The configuration after two steps is . We note the following shift rule:

As a result, we get after steps. Advancing two steps produces . A second shift rule is useful here:
This allows us to reach in steps. Moving five more steps gets us to , which is the same configuration as . Accounting for the head movement creates the condition that . In summary:
With we have . As a result, we can apply this rule times (assuming ), which creates two possible scenarios:

  1. If , then in steps we arrive at . The matching complete configuration is . After steps this is , which then leads to in steps. After five more steps, we reach , from which another shift rule must be applied:
    Doing so allows us to get the configuration in steps. In six steps we have , so we use the shift rule again, ending at , equal to , steps later. This gives a total of steps.
  2. If , then in steps we arrive at . The matching complete configuration is . After steps this becomes . If then we have reached the undefined F0 transition with a total of steps. Otherwise, continuing for six steps gives us . We conclude with the configuration , equal to , in steps. This gives a total of steps.

The information above can be summarized as

Substituting for the first case and for the other two yields the final result.

In effect, the halting problem for Antihydra is about whether repeatedly applying the function will at some point produce more odd values of than twice the number of even values.

These rules can be modified to use the function , or the Hydra function, which strengthens Antihydra's similarities to Hydra.

Trajectory

11 steps are required to enter the configuration before the rules are repeatedly applied. So far, Antihydra has been simulated to rule steps, at which point . Here are the first few:

The trajectory of values resembles a random walk in which the walker can only move in step sizes +2 or -1 with equal probability, starting at position 0. If is the probability that the walker will reach position -1 from position , then it can be seen that . Solutions to this recurrence relation come in the form , which after applying the appropriate boundary conditions reduces to . This means that if the walker were to get to position 1073720884 then the probability of it ever reaching position -1 is . This combined with the fact that the expected position of the walker after steps is strongly suggests Antihydra probviously runs indefinitely.

Code

The following Python program implements the abstracted behavior of the Antihydra. Proving whether it halts or not would also solve the Antihydra problem:

# Current value of the iterated Hydra function starting with initial value 8 (the values do not overflow)
h = 8
# (Collatz-like) condition counter that keeps track of how many odd and even numbers have been encountered
c = 0
# If c equals -1 there have been (strictly) more than twice as many odd as even numbers and the program halts
while c != -1:
    # If h is even, add 2 to c so even numbers count twice
    if h % 2 == 0:
        c += 2
    else:
        c -= 1
    # Add the current hydra value divided by two (integer division, rounding down) to itself (Hydra function)
    # Note that integer division by 2 is equivalent to one bit shift to the right (h >> 1)
    h += h//2

The variable values of this iteration have been put into the On-Line Encyclopedia of Integer Sequences (OEIS):

Fast Hydra/Antihydra simulation code by Greg Kuperberg (who said it could be made faster using FLINT):

# Python script to demonstrate almost linear time hydra simulation
# using fast multiplication. 
# by Greg Kuperberg

import time
from gmpy2 import mpz,bit_mask

# Straight computation of t steps of hydra
def simple(n,t):
    for s in range(t): n += n>>1
    return n

# Accelerated computation of 2**e steps of hydra
def hydra(n,e):
    if e < 9: return simple(n,1<<e)
    t = 1<<(e-1)
    (p3t,m) = (mpz(3)**t,bit_mask(t))
    n = p3t*(n>>t) + hydra(n&m,e-1)
    return p3t*(n>>t) + hydra(n&m,e-1)

def elapsed():
    (last,elapsed.mark) = (elapsed.mark,time.process_time())
    return elapsed.mark-last
elapsed.mark = 0

(n,e) = (mpz(3),25)

elapsed()
print('hydra:  steps=%d hash=%016x time=%.6fs'
    % (1<<e,hash(hydra(n,e)),elapsed()))

# Quadratic time algorithm for comparison
# print('simple: steps=%d hash=%016x time=%.6fs'
#     % (1<<e,hash(simple(n,1<<e)),elapsed()))

References

  1. Discord conversation where the machine was named
  2. DUBICKAS A. ON INTEGER SEQUENCES GENERATED BY LINEAR MAPS. Glasgow Mathematical Journal. 2009;51(2):243-252. doi:10.1017/S0017089508004655
  3. S. Ligocki, "BB(6) is Hard (Antihydra)" (2024). Accessed 22 July 2024.