A função de Ackerman é uma das características mais famosas da Ciência da Computação. Está associado a pelo menos um resultado fundamental e pelo menos um simplesmente importante. O resultado fundamental, para colocá-lo de maneira clara e incompreensível, é o seguinte: existe uma função computável definida em todos os lugares que não é recursiva primitiva. Um resultado importante é que a floresta de conjuntos disjuntos (também conhecida como união de conjuntos disjuntos) é muito rápida .
Eu realmente gosto de estudar a função de Ackerman, como tudo relacionado a ela é muito bonito e elegante. Portanto, o resultado fundamental registrado acima é muito mais fácil de entender do que parece.
No texto abaixo, você aprenderá o que são funções recursivas primitivas e como descobrir que a função Akkerman não se aplica a elas. E, é claro, este texto o convencerá de que é um design incrivelmente bonito e um raciocínio incrivelmente bonito!
1. Por que pode ser interessante
A discussão da relação entre funções recursivas primitivas e a função Ackerman é um exemplo de solução de um problema padrão na teoria da computabilidade: um determinado modelo de cálculo, uma determinada função é fornecida e é necessário determinar se essa função é computável nesse modelo.
Outros exemplos semelhantes estão associados, por exemplo, à decidibilidade algorítmica , à equivalência de vários modelos computacionais (máquinas de Turing, funções parcialmente recursivas, algoritmos normais de Markov e assim por diante). E através deles já estamos conectados a uma área de definição completamente prática para a integridade de Turing das linguagens de programação, transformações equivalentes dos textos dos programas e outras coisas interessantes.
A função de Ackerman parece ter sido criada especialmente para ser um exemplo elegante de solução de tais problemas. Você verá isso em breve.
2. função Ackerman
, « ». , , , .
a0,a1,...,an,... . :
a0(x)=x+1
ai+1(x)=ai[x+2](x)
f[n](x)=f(f(...(f(x))...)) — n, n . , : , x+2 x — x.
, — , .
:
def Foo(number, argument):
if number == 0:
return argument + 1
result = argument
for i in range(argument + 2):
result = Foo(number - 1, result)
return result
ai(x) Foo(i, x)
.
. -, : ai(x)>x i x. , , a0(x)=x+1>x, a0 .
-, : ai+1(x)>ai(x) i x. , — , . :
ai+1(x)=ai[x+2](x)≥ai[2](x)=ai(ai(x))>ai(x)
,
ai+1(x)≥ai(ai(x))
3. - ()
« ». — . : , , , .
- ? «». - :
- , : Null(x1,x2,...,xk)=0
- : S(x)=x+1
- -: Pik(x1,x2,...,xk)=xi
. « »:
- . f — k , g1,g2,...,gk — n , n F: n , k g1,...,gk, f. !
F(x1,...,xn)=f(g1(x1,...,xn),...,gk(x1,...,xn))
F(x1,...,xk,0)=f(x1,...,xk)
F(x1,...,xk,y+1)=g(x1,...,xk,y,F(x1,...,xk,y))
, . : , . : , , . , .. , .
, — , , .
.
, . , . , :
Sum(x,0)=P11(x)
Sum(x,y+1)=S(P33(x,y,Sum(x,y)))
— , . , . Sum(x,0)=x, , .. x . P11. , : x,y,Sum(x,y). , P33, .
:
Mult(x,0)=Null(x)
Mult(x,y+1)=Sum(P13(x,y,Mult(x,y)),P33(x,y,Mult(x,y)))
- . , ! , :
Fib0=0
Fib1=1
Fibn+2=Fibn+Fibn+1
, ; , !
, . , F, . , G, , :
F(n)=Fibn
G(n)=Fibn+1
F 0, 1, 1, 2, 3, 5; G, , 1, 1, 2, 3, 5, 8. :
G(n+1)=G(n)+F(n)
F(n+1)=G(n)
:
F(0)=Null()
G(0)=S(Null())
F(y+1)=P12(G(y),F(y))
G(y+1)=Sum(F(y),G(y))
:
def G(x):
if x == 0:
return 1
return G(x - 1) + F(x - 1)
def F(x):
if x == 0:
return 0
return G(x - 1)
, , , , n- - !
4. ,
, - « » . : - k f n, :
f(x1,...,xk)<an(max(x1,...,xk))
— . , , .
, :
Null(x1,...,xk)=0<max(x1,...,xk)+1=a0(max(x1,...,xk))
S(x)=x+1=a0(x)<a1(x)
Pik(x1,...,xk)=xi≤max(x1,...,xk)<a0(max(x1,...,xk))
, , a0 (: , , ). — a0, a1. - , , , .
. : , , , , .
F f,g1,...,gk, aM. , F . :
F(x1,...,xn)=f(g1(x1,...,xn),...,gk(x1,...,xn))<
<aM(max(g1(x1,...,xn),...,gk(x1,...,xn)))<
<aM[max(aM(max(x1,...,xn)),...,aM(max(x1,...,xn)))]
<aM(aM(max(x1,...,xn)))≤aM+1(max(x1,...,xn))
f, gi, k , . aM , aM+1.
F f g, aM.
, , . : f:
F(x1,...,xk,0)=f(x1,...,xk)<aM(max(x1,...,xk))
, , :
F(x1,...,xk,1)=g(x1,...,xk,0,F(x1,...,xk,0))<
<aM(max(x1,...,xk,0,aM(max(x1,...,xk)))<
<aM(aM(max(x1,...,xk))=aM[2](max(x1,...,xk))
F, g. aM: ,
aM(max(x1,...,xk))>max(x1,...,xk,0)
, ,
F(x1,...,xk,y)<aM[y+1](max(x1,...,xk))
E as propriedades da sequência introduzida de funções garantem que
aM[y+1 1](mumax(x1 1,...,xk))<umaM+1 1(mumax(x1 1,...,xk,y))
Finalmente:
F(x1 1,...,xk,y)<umaM+1 1(mumax(x1 1,...,xk,y))
E é aqui que a nossa prova termina. O engraçado é que, cada aplicação de composição ou recursão primitiva aumenta em um o número da função necessária pelas condições da instrução.
5. Função Ackerman e PRF, parte dois
Portanto, sabemos que, para qualquer função recursiva primitiva, existe uma função umaMque crescerá mais rápido. Agora você pode definir a seguinte função:
UMA(n)=uman(n)
De fato, introduzindo a sequência de funções de um argumento, introduzimos a função de dois argumentos: o primeiro deles define o número da função na sequência, o segundo - o próprio argumento. Igualando o número e o argumento, obtemos a função de um argumento.
: A -.
, , -. 4 M, A(x)<aM(x) x. , :
A(M+1)=aM+1(M+1)>aM(M+1)
, -. - , ! .
6. ?
, , - , . , . nn. Além disso, qualquer função da forma
nn...nn
com um número predeterminado de expoentes, é recursivo primitivo. Eu não vou ser preguiçoso e provar isso. Para começar, eu construirei uma funçãony:
PoW(n,0 0)=S(Nvocêeueu())
PoW(n,y+1 1)=Mvocêeut(P1 13(n,y,PoW(n,y)),P33(n,y,PoW(n,y)))
Agora eu uso para definir uma função nn:
SPoW(n)=PoW(P1 11 1(n),P1 11 1(n))
Como você pode ver, isso é feito por simples substituição. Agora não há dificuldade em definir uma funçãonnn:
SSPoW(n)=PoW(P1 11 1(n),SPoW(n))
Por analogia, podemos construir uma função na qual n elevado ao poder ncinco vezes, dez vezes, cem vezes, um milhão de vezes. A função de Ackerman cresce mais rapidamente do que qualquer uma dessas funções. É assim que cresce rápido!