Isenção de responsabilidade: Eu sei que esse tópico é mais antigo, mas se alguém estiver procurando por "convolução rápida precisa, alta faixa dinâmica" ou semelhante, este é um dos primeiros de apenas alguns resultados decentes. Quero compartilhar minhas idéias que obtive sobre esse tópico, para que possa ajudar alguém no futuro. Peço desculpas se posso usar os termos errados na minha resposta, mas tudo o que encontrei neste tópico é bastante vago e leva a confusão, mesmo neste tópico. Espero que o leitor entenda de qualquer maneira.
A convolução direta é mais precisa para usinar a precisão de cada ponto, ou seja, o erro relativo é geralmente aproximado ou próximo de 1.e-16 para precisão dupla para cada ponto do resultado. Cada ponto tem 16 dígitos corretos. Os erros de arredondamento podem ser significativos para convoluções atipicamente grandes e, estritamente falando, deve-se ter cuidado com o cancelamento e usar algo como a soma de Kahan e tipos de dados de precisão alta o suficiente, mas na prática o erro é quase sempre ideal.
O erro de uma convolução da FFT além dos erros de arredondamento é um erro "relativo global", o que significa que o erro em cada ponto depende da precisão da máquina e do valor de pico do resultado. Por exemplo, se o valor de pico do resultado for 2.e9
, o erro absoluto em cada ponto será2⋅109⋅10−16=2⋅10−7. Portanto, se um valor no resultado for muito pequeno, digamos10- 9, o erro relativo nesse ponto pode ser enorme. A convolução da FFT é basicamente inútil se você precisar de pequenos erros relativos no final do seu resultado, por exemplo, se houver uma deterioração exponencial dos seus dados e se precisar de valores precisos no final. Curiosamente, se a convolução da FFT não se limita a esse erro, ela apresenta erros de arredondamento muito menores em comparação à convolução direta, pois você obviamente faz menos adições / multiplicações. Na verdade, é por isso que as pessoas costumam afirmar que a convolução da FFT é mais precisa, e elas estão quase certas em algum sentido, para que possam ser bastante inflexíveis.
Infelizmente, não há uma correção universal fácil para obter convoluções rápidas e precisas, mas, dependendo do seu problema, pode haver uma ... Encontrei duas:
Se você possui núcleos lisos que podem ser bem aproximados por um polinômio na cauda, o método Multipolo rápido da caixa preta com interpolação Chebyshev pode ser interessante para você. Se o seu kernel é "bom", isso funciona perfeitamente: você obtém complexidade computacional linear (!) E precisão da precisão da máquina. Se isso se encaixa no seu problema, você deve usá-lo. No entanto, não é fácil de implementar.
Para alguns kernels específicos (acho que funções convexas, geralmente a partir de densidades de probabilidade), você pode usar um "deslocamento exponencial" para obter um erro ideal em alguma parte da cauda do resultado. Existe uma tese de doutorado e um github com uma implementação em python usando isso sistematicamente, e o autor o chama de convolução FFT precisa . Na maioria dos casos, isso não é super útil, pois ele regride de volta à convolução direta ou você pode usar a convolução da FFT de qualquer maneira. Embora o código faça isso automaticamente, o que é legal, é claro.
--------------------EDITAR:--------------------
Eu olhei um pouco para o algoritmo Karatsuba (eu realmente fiz uma pequena implementação) e, para mim, parece que ele geralmente tem um comportamento de erro semelhante ao da convolução da FFT, ou seja, você recebe um erro em relação ao valor de pico do resultado. Devido à natureza de divisão e conquista do algoritmo, alguns valores na cauda do resultado realmente apresentam um erro melhor, mas não vejo uma maneira sistemática fácil de dizer quais ou, de qualquer forma, como usar essa observação. Que pena, no começo eu pensei que o Karatsuba poderia ser algo útil entre a convolução direta e a FFT. Mas não vejo casos de uso comuns em que o Karatsuba deve ser preferido em relação aos dois algoritmos comuns de convolução.
E para acrescentar à mudança exponencial que mencionei acima: há muitos casos em que você pode usá-la para melhorar o resultado de uma convolução, mas, novamente, não é uma correção universal. Na verdade, eu uso isso junto com a convolução da FFT para obter bons resultados (no caso geral de todas as entradas: no pior mesmo erro que a convolução normal da FFT, no melhor erro relativo em cada ponto da precisão da máquina). Mas, novamente, isso realmente funciona muito bem para kernels e dados específicos, mas para mim é o kernel e os dados ou um pouco exponencial em decadência.
convolve()
apenas chamafftconvolve()
agora, se o tamanho da entrada for grande. Especifiquemethod='direct'
se você deseja direto.