Laver cálculos de tabela e um algoritmo que não é conhecido por terminar no ZFC

12

As tabelas Laver fornecem exemplos de programas que não foram mostrados para terminar no sistema axiomático padrão da matemática ZFC, mas que terminam quando alguém assume axiomas cardinais muito grandes.

Introdução

As tabelas Laver clássicos são as álgebras finitas únicos com subjacente conjunto e uma operação que satisfaz a identidade e onde para e onde .An{1,...,2n}*x * (y * z)=(x * y) * (x * z)x*1=x+1x<2n2n*1=1

Mais informações sobre as tabelas clássicas do Laver podem ser encontradas no livro Tranças e auto-distributividade, de Patrick Dehornoy.

Desafio

Qual é o código mais curto (em bytes) que calcula 1*32nas tabelas clássicas do Laver e termina exatamente quando encontra um ncom ? Em outras palavras, o programa termina se e somente se encontrar um com mas, caso contrário, ele será executado para sempre.1*32<2nn1*32<2n

Motivação

Um cardeal de classificação em hierarquia (também chamado de cardeal I3) é um nível extremamente grande de infinito e se alguém assume a existência de um cardeal de classificação em hierarquia, então é possível provar mais teoremas do que se não o fizer. supor a existência de um cardeal de classificação em classificação. Se existe um cardeal de classificação em classificação, então existe uma tabela clássica de Laver em que . No entanto, não há provas conhecidas disso no ZFC. Além disso, sabe-se que o menor onde é maior que (que é um número extremamente grande, uma vez que a função Ackermann é uma função de rápido crescimento). Portanto, qualquer programa desse tipo durará um período extremamente longo.An1*32<2n1*32<2nn1*32<2nAck(9,Ack(8,Ack(8,254)))Ack

Quero ver o quão curto um programa pode ser escrito para que não saibamos se o programa termina usando o sistema axiomático ZFC padrão, mas onde sabemos que o programa termina eventualmente em um sistema axiomático muito mais forte, o ZFC + I3. Essa pergunta foi inspirada no post recente de Scott Aaronson, em que Aaronson e Adam Yedidia construíram uma máquina de Turing com menos de 8000 estados, de modo que o ZFC não pode provar que a máquina de Turing não termina, mas sabe-se que não termina quando alguém assume grandes hipóteses cardinais.

Como são calculadas as tabelas clássicas do Laver

Ao calcular tabelas do Laver, geralmente é conveniente usar o fato de que na álgebra , temos tudo para dentro .An2n * x=xxAn

O código a seguir calcula a tabela clássica do Laver An

# table (n, x, y) retorna x * y em A n
tabela: = função (n, x, y)
se x = 2 ^ n, em seguida, retorne y;
elif y = 1 então retorne x + 1;
caso contrário, retorne tabela (n, tabela (n, x, y-1), x + 1); fi; fim;

Por exemplo, a entrada table(4,1,2)retornará 12.

O código para table(n,x,y)é bastante ineficiente e só pode computar na tabela Laver em um período de tempo razoável. Felizmente, existem algoritmos muito mais rápidos para calcular as tabelas Laver clássicas do que os dados acima.A4

Joseph Van Name
fonte
2
Bem-vindo ao PPCG! Ótimo post!
NoOneIsHere
1
De acordo com a Wikipedia, Ack (9, Ack (8, Ack (8.254))) é um limite inferior em n para o qual o período excede 16. Para isso, podemos verificar 1 * 16 em vez de 1 * 32. Vou alterar meu programa de acordo.
John Tromp
1
Comecei a escrever uma máquina de Turing para fazer isso e acho que percebi um erro de fator de dois em dois. Dougherty não provou que esse Ack(9,Ack(8,Ack(8,254)))é um limite inferior para a primeira tabela na qual a primeira linha possui o período 32, ou seja, onde 1*16 < 2^n?
Peter Taylor
1
Se você tem uma máquina de dois estados com 20 símbolos para a Ackermann, por favor, me dê um link, porque provavelmente posso roubar algumas idéias dela. Tenho 44 estados para calcular table(n,x,y)e acho que serão necessários entre 25 e 30 estados para configurar as constantes e o loop externo. A única representação direta da TM que posso encontrar no esolangs.org é esolangs.org/wiki/ScripTur e não é realmente assim.
Peter Taylor
1
cheddarmonk.org/papers/laver.pdf é o que eu espero que seja feito esta semana, porque vou viajar.
31816 Peter Taylor

Respostas:

4

Cálculo binário Lambda, 215 bits (27 bytes)

\io. let
  zero = \f\x. x;
  one = \x. x;
  two = \f\x. f (f x);
  sixteen = (\x. x x x) two;
  pred = \n\f\x. n (\g\h. h (g f)) (\h. x) (\x. x);
  laver = \mx.
    let laver = \b\a. a (\_. mx (b (laver (pred a))) zero) b
    in laver;
  sweet = sixteen;
  dblp1 = \n\f\x. n f (n f (f x)); -- map n to 2*n+1
  go2 = \mx. laver mx sweet mx (\_. mx) (go2 (dblp1 mx));
in go2 one

compila para (usando o software em https://github.com/tromp/AIT )

000101000110100000010101010100011010000000010110000101111110011110010111
110111100000010101111100000011001110111100011000100000101100100010110101
00000011100111010100011001011101100000010111101100101111011001110100010

Esta solução se deve principalmente a https://github.com/int-e

John Tromp
fonte
2
Não sei como você obteve sua pontuação, mas, por padrão, os envios devem ser pontuados de acordo com o número de bytes no código. Conto 375 bytes para este envio. Você também deve incluir o nome do idioma e, opcionalmente, um link para um intérprete para o idioma.
Alex A.
Você provavelmente deve incluir o código exato de 234 bits de comprimento na sua postagem.
CalculatorFeline
2
A codificação pode ser encontrada na Wikipedia . Há também um link para este intérprete (não testado). Porém, eles devem ser verificados e a codificação binária também deve estar no post.
PurkkaKoodari
1
Para idiomas compilados, pontuamos o código escrito pelo usuário - não o número de bytes no binário gerado.
Alex A.
5
@AlexA. Isso não é necessário ... qualquer forma de código que possa ser entendida por um compilador ou intérprete está correta.
feersum
4

CJam ( 36 32 bytes)

1{2*31TW$,(+a{0X$j@(@jj}2j)W$=}g

Na prática, esse erro ocorre rapidamente porque transborda a pilha de chamadas, mas em uma máquina teórica ilimitada está correta, e entendo que essa é a suposição desta pergunta.

O código para table(n,x,y)é bastante ineficiente e só pode calcular na tabela Laver A 4 em um período de tempo razoável.

não está realmente correto se armazenarmos em cache os valores computados para evitar recalculá-los. Essa é a abordagem que jadotei , usando o operador (memoisation) . Ele testa A 6 em milissegundos e transborda o teste A 7 da pilha - e eu realmente desoptimizei table no interesse do golfe.

Dissecação

Se assumirmos que isso né entendido a partir do contexto, em vez de

f(x,y) =
    x==2^n ? y :
    y==1 ? x+1 :
    f(f(x,y-1),x+1)

podemos remover o primeiro caso especial, dando

f(x,y) =
    y==1 ? x+1 :
    f(f(x,y-1),x+1)

e ainda funciona porque

f(2^n, 1) = 2^n + 1 = 1

e para qualquer outro y,

f(2^n, y) = f(f(2^n, y-1), 1) = f(2^n, y-1) + 1

então, por indução, obtemos f(2^n, y) = y.

Para CJam, é mais conveniente reverter a ordem dos parâmetros. E, em vez de usar o intervalo 1 .. 2^n, estou usando o intervalo 0 .. 2^n - 1decrementando cada valor; portanto, a função recursiva que estou implementando é

g(y,x) =
    y==0 ? x+1
         : g(x+1, g(y-1, x))

1           e# Initial value of 2^n
{           e# do-while loop
  2*        e#   Double 2^n (i.e. increment n)
  31T       e#   table(n,1,32) is g(31,0) so push 31 0
  W$,(+a    e#   Set up a lookup table for g(0,x) = x+1 % 2^n
  {         e#   Memoisation function body: stack is 2^n ... y x
    0X$j    e#     Compute g(0,x) = x+1 % 2^n
            e#     Stack is 2^n ... y x (x+1%2^n)
    @(      e#     Bring y to top, decrement (guaranteed not to underflow)
            e#     Stack is 2^n ... x (x+1%2^n) (y-1%2^n)
    @jj     e#     Rotate and apply memoised function twice: g(x+1,g(y-1,x))
  }
  2j        e#   Memoise two-parameter function
            e#   Stack: 2^n g(31,0)
  )W$=      e#   Test whether g(31,0)+1 is 2^n
}g          e# Loop while true
Peter Taylor
fonte
1

Pitão, 33 bytes

.N?qT^2NY?tY:N:NTtYhThT<:T1 32^2T

Experimente online! (Obviamente, a parte de teste não está incluída aqui.)

Freira Furada
fonte
Que laço? Além disso, o que significa fino código?
Freira vazando