Por que isto pode ser útil? Para encontrar os coeficientes do polinômio P, se o polinômio é de ordem N, então, por amostragem em pontos N+1, podemos determinar seus coeficientes.
Por exemplo, se o polinômio x⁵ + 3x³ +4x-2, que é de ordem 5, for amostrado em 6 pontos, podemos então calcular o polinômio inteiro.
Intuitivamente, um polinômio de ordem 5 tem 6 coeficientes: o coeficiente de 1, x, x², x³, x⁴, x⁵. Dados 6 valores e 6 desconhecidos, podemos descobrir os valores.
(Se você conhece álgebra linear, você pode tratar as diferentes potências de x como vetores linearmente independentes, fazer uma matriz para representar a informação, inverter a matriz, e voila)
Polinômios de amostragem para determinar os coeficientes (Opcional)
Aqui olhamos com um pouco mais de profundidade para a lógica por trás da amostragem de um polinômio para deduzir seus coeficientes. Sinta-se livre para pular para a próxima seção.
O que vamos mostrar é que, se dois polinômios de grau N concordam em pontos N+1, então eles devem ser os mesmos. Ou seja, N+1 pontos especificam um polinômio de ordem N.
Considerar um polinômio de ordem 2. Isto é da forma P(z) = az² +bz + c. Pelo teorema fundamental da álgebra – sem vergonha, plug aqui, eu passei vários meses juntando uma prova disto, e depois escrevendo, aqui – este polinômio pode ser fatorizado. Isso significa que podemos escrevê-lo como A(z-r)(z-w)
Nota que em z = r, e em z = w, o polinômio avalia para 0. Dizemos que w e r são raízes do polinômio.
Agora mostramos que P(z) não pode ter mais do que duas raízes. Suponha que tivesse três raízes, a que chamamos w, r, s. Depois factorizamos o polinómio. P(z) = A(z-r)(z-w). Depois P(s) = A(s-r)(s-w). Isto não é igual a 0, pois a multiplicação de números não zero dá um número não zero. Isto é uma contradição porque nossa suposição original era que s era uma raiz do polinômio P.
Este argumento pode ser aplicado a um polinômio de ordem N de forma essencialmente idêntica.
Agora, suponha que dois polinômios P e Q de ordem N concordam em pontos N+1. Então, se eles forem diferentes, P-Q é um polinômio de ordem N que é 0 em pontos N+1. Pelo anterior, isto é impossível, pois um polinômio de ordem N tem no máximo N raízes. Assim, nossa suposição deve ter sido errada, e se P e Q concordam em pontos N+1 eles são o mesmo polinômio.
Vendo é acreditar: Exemplo trabalhado
Vejamos um número realmente enorme que chamamos p. Na base 10, p tem 24 dígitos (n=24), e nos dividiremos em 4 peças (r=4). n/r = 24/4 = 6
p = 292.103.243.859.143.157.364.152.
E deixe o polinômio representando-o ser chamado P,
P(x) = 292.103 x³ + 243.859 x² +143.157 x+ 364.152
com P(10⁶) = p.
>Como o grau deste polinômio é 3, podemos trabalhar todos os coeficientes a partir da amostragem em 4 lugares. Vamos sentir o que acontece quando o sampleamos em alguns pontos.
P(0) = 364.152
P(1) = 1.043.271
P(-1) = 172.751
P(2) = 3.962.726
Uma coisa impressionante é que todos estes têm 6 ou 7 dígitos. Isso é comparado com os 24 dígitos originalmente encontrados em p.
Multipliquemos p por q. Let q = 124.153.913.241.143.634.899.130, e
Q(x) = 124.153 x³ + 913.241 x²+143.634 x + 899.130
Calcular t=pq pode ser horrível. Mas em vez de o fazer directamente, tentamos calcular a representação polinomial de t, que rotulamos T. Como P é um polinómio de ordem r-1=3, e Q é um polinómio de ordem r-1 = 3, T é um polinómio de ordem 2r-2 = 6.
T(10⁶) = t = pq
T(10⁶) = P(10⁶)Q(10⁶)
O truque é que vamos trabalhar os coeficientes de T, em vez de multiplicarmos directamente p e q juntos. Então, calcular T(1⁰⁶) é fácil, porque para multiplicar por 1⁰⁶ basta colar 6 zeros na parte de trás. Somar todas as partes também é fácil porque a adição é uma ação de baixo custo para os computadores.
Para calcular os coeficientes de T, precisamos amostrar a 2r-1 = 7 pontos, porque é um polinômio de ordem 6. Nós provavelmente queremos escolher inteiros pequenos, por isso escolhemos
T(0)=P(0)=P(0)= 364.152*899.130
T(1)=P(1)Q(1)= 1.043.271*2.080.158
T(2)=P(2)Q(2)= 3.962.726*5.832,586
T(-1)=P(-1)Q(-1)= 172751*1544584
T(-2)=P(-2)Q(-2)= -1.283.550*3.271,602
T(3)=P(-3)Q(-3)= -5,757,369*5,335,266
Nota o tamanho de P(-3), Q(-3), P(2), Q(2) etc… Estes são todos números com aproximadamente n/r = 24/4 = 6 dígitos. Alguns são de 6 dígitos, outros de 7. Como n fica maior, esta aproximação fica cada vez mais razoável.
Até agora reduzimos o problema aos seguintes passos, ou algoritmo:
(1) Primeiro calcule P(0), Q(0), P(1), Q(1), etc (ação de baixo custo)
(2) Para obter nossos 2r-1= 7 valores de T(x), devemos agora multiplicar 2r-1 números de tamanho aproximado de n/r de comprimento de dígitos. Nomeadamente, devemos calcular P(0)Q(0), P(1)Q(1), P(-1)Q(-1), etc. (Ação de custo alto)
(3) Reconstruir T(x) a partir dos nossos pontos de dados. (Ação de baixo custo: mas será considerada mais tarde).
(4) Com a nossa T(x) reconstruída, avalie T(10⁶) neste caso
Isto leva a uma boa análise do tempo de execução desta abordagem.
Tempo de execução
Do acima, descobrimos que, ignorando temporariamente as ações de baixo custo (1) e (3), o custo de multiplicar dois n dígitos com o algoritmo do Toom obedecerá:
Foi o que vimos no exemplo trabalhado. Multiplicar cada P(0)Q(0), P(1)Q(1), etc. custa T(n/r) porque estamos a multiplicar dois números de comprimento aproximadamente n/r. Temos que fazer isso 2r-1 vezes, pois queremos amostrar T(x) – sendo um polinômio de ordem 2r-2 – em 2r-1 lugares.
Quão rápido é isso? Nós podemos resolver este tipo de equação explicitamente.
>
>
>
>
>
>
> >
>
>
Tudo o que resta agora é algum álgebra confusa
>
>
>
Como houve alguns outros custos do processo de multiplicação da matriz (“remontagem”), e pela adição, não podemos realmente dizer que nossa solução é o tempo de execução exato, então concluímos que encontramos o big-O do tempo de execução
>
>
>
>
> >
>>
Optimização r
>
Este tempo de execução ainda depende de r. Fixar r, e estamos feitos. Mas a nossa curiosidade ainda não está satisfeita!
As n se tornam grandes, queremos encontrar um valor aproximadamente óptimo para a nossa escolha de r. Ou seja, queremos escolher um valor de r que muda para diferentes valores de n.
O fundamental aqui é que, com r variável, precisamos de prestar alguma atenção ao custo de remontagem – a matriz que realiza esta operação tem um custo de O(r²). Quando r foi fixo, não tivemos que olhar para isso, pois como n cresceu grande com r fixo, foram os termos envolvendo n que determinaram o crescimento em quanto cálculo foi necessário. Como a nossa escolha óptima de r vai ficar maior à medida que n fica maior, não podemos mais ignorar isto.
Esta distinção é crucial. Inicialmente a nossa análise escolheu um valor de r, talvez 3, talvez 3 bilhões, e depois olhou para o tamanho do big-O à medida que n crescia arbitrariamente grande. Agora, olhamos para o comportamento enquanto n cresce arbitrariamente grande e r cresce com n a algum ritmo que determinamos. Esta mudança de perspectiva olha para O(r²) como uma variável, enquanto que quando r foi mantido fixo, O(r²) era uma constante, embora não soubéssemos.
>
Então, atualizamos nossa análise de antes:
onde o O(r²) representa o custo da matriz de remontagem. Queremos agora escolher um valor de r para cada valor de n, o que minimiza aproximadamente esta expressão. Para minimizar, primeiro tentamos diferenciar com respeito a r. Isto dá a expressão de aspecto um pouco hediondo
Normalmente, para encontrar o ponto mínimo, definimos a derivada igual a 0. Mas esta expressão não tem um mínimo agradável. Em vez disso, encontramos uma solução ‘suficientemente boa’. Usamos r = r^(sqrt(logN)) como nosso valor de adivinhação. Graficamente, isto é muito próximo do mínimo. (No diagrama abaixo, o fator 1/1000 está lá para tornar o gráfico visível em uma escala razoável)
O gráfico abaixo mostra nossa função para T(N), escalada por uma constante, em vermelho. A linha verde está em x = 2^sqrt(logN) que foi o nosso valor estimado. ‘x’ toma o lugar de ‘r’, e em cada uma das três figuras, um valor diferente de N é usado.
>
>
>
>
>
>
>
> >
>
>
>gráficos feitos com Desmos.com
Esta é bastante convincente para mim que a nossa escolha foi uma boa escolha. Com esta escolha de r, podemos plugá-lo e ver como o nosso algoritmo final big-O:
>
>
>
>
>
onde simplesmente plugamos nosso valor para r, e usamos uma aproximação para log(2r-1)/log(r) que é muito precisa para grandes valores de r.
How Much of An Improvement?
Talvez eu não tenha visto este algoritmo quando eu era um rapazinho fazendo multiplicação era razoável. No gráfico abaixo, eu dou o coeficiente da nossa função big-O para ser 10 (para fins de demonstração) e o divido por x² (como a abordagem original da multiplicação era O(n²). Se a linha vermelha tende a 0, isso mostraria que nosso novo tempo de execução assimptóticamente faz melhor que O(n²).
E de fato, enquanto a forma da função mostra que nossa abordagem é eventualmente mais rápida, e eventualmente é muito mais rápida, temos que esperar até termos quase 400 números longos de dígitos para que isso seja o caso! Mesmo que o coeficiente fosse apenas 5, os números teriam de ter cerca de 50 dígitos para ver uma melhoria da velocidade.
>
>
>
>
>
Para o meu eu de 10 anos, multiplicar números de 400 dígitos seria um pouco exagerado! Manter um registo das várias chamadas recursivas da minha função também seria um pouco assustador. Mas para um computador fazendo uma tarefa em IA ou em física, este é um problema comum!
Quão profundo é este resultado?
O que eu adoro nesta técnica é que ela não é ciência de foguetes. Não é a matemática mais espantosa que há para ser descoberta. Em retrospectiva, talvez pareça óbvio!
Yet, este é o brilho e a beleza da matemática. Li que Kolmogorov conjecturou em um seminário que a multiplicação era fundamentalmente O(n²). Kolmogorov basicamente inventou muita teoria e análise de probabilidade moderna. Ele foi um dos grandes matemáticos do século XX. No entanto, quando se tratava deste campo não relacionado, revelou-se que havia todo um corpus de conhecimento à espera de ser descoberto, sentado mesmo debaixo do seu nariz e do de todos os outros!
De facto, os algoritmos Divide and Conquer vêm à mente bastante rapidamente hoje em dia, pois são tão vulgarmente utilizados. Mas eles são um produto da revolução informática, na medida em que é apenas com um vasto poder computacional que as mentes humanas têm focado especificamente na velocidade da computação como uma área da matemática digna de estudo por direito próprio.
É por isso que os matemáticos não estão apenas dispostos a aceitar a Hipótese de Riemann é verdadeira só porque parece que pode ser verdade, ou que P não é igual a NP só porque isso parece mais provável. O maravilhoso mundo da matemática sempre mantém uma capacidade de confundir nossas expectativas.
Na verdade, você pode encontrar maneiras ainda mais rápidas de se multiplicar. As melhores abordagens atuais usam transformadas rápidas de fourier. Mas vou guardar isso para outro dia 🙂
Deixe-me conhecer os seus pensamentos abaixo. Estou recentemente no Twitter como ethan_the_mathmo, você pode me seguir aqui.
Conheci este problema em um livro maravilhoso que estou usando chamado ‘The Nature of Computation’ pelos físicos Moore e Mertens, onde um dos problemas guia você através da análise do algoritmo do Toom.