Hur kan MLK göra så snabba matrismultiplikationer?

Permalänk
Hedersmedlem
Skrivet av Yoshman:

Verkar som FFT inte skalar med kärnor, även med 100 000 samples används bara en kärna både på Ubuntu 22.04 och MacOS (det är då testat mer 3 olika ramverk, FFTW, Arm ComputeLibrary samt Apple Accelerate).

För långa fft-längder skalar det rätt bra, men man måste aktivt be om multitrådning och säga hur många trådar man vill använda.

Åtta kärnor:

#include <fftw3.h> #include <chrono> #include <iostream> const int fftSize = 1024*100; fftwf_complex* fftInput; fftwf_complex* fftOutput; fftwf_plan fftPlan; int main(int argc, char *argv[]) { fftwf_init_threads(); fftwf_plan_with_nthreads(8); fftwf_import_wisdom_from_filename("wisdom.dat"); fftInput = fftwf_alloc_complex(fftSize); fftOutput = fftwf_alloc_complex(fftSize); fftPlan = fftwf_plan_dft_1d(fftSize, fftInput, fftOutput, FFTW_FORWARD, FFTW_MEASURE | FFTW_PRESERVE_INPUT); fftwf_export_wisdom_to_filename("wisdom.dat"); for(int i = 0; i < fftSize; ++i) { fftInput[i][0] = rand()%1000000; fftInput[i][1] = rand()%1000000; } std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now(); const int N = 1000; for(int q = 0; q < N; ++q) fftwf_execute(fftPlan); std::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now(); std::cout << "Time: " << std::chrono::duration_cast<std::chrono::duration<double>>(t2 - t1).count()/N*1000 << " ms" << std::endl; fftwf_destroy_plan(fftPlan); fftwf_free(fftInput); fftwf_free(fftOutput); fftwf_cleanup_threads(); }

0,09 ms (i7 8700k).

Permalänk
Hedersmedlem
Skrivet av heretic16:

Nu har jag testat FFT2 med FFTPack 5.1. Det fungerar.
Det blir dock inte samma MATLAB-resultat vid tidsplan -> frekvensplan.
Men det blir samma resultat vid tidsplan -> frekvensplan -> tidsplan.

Har du testat att rita upp resultatet? De skulle ju kunna ha olika syn på fft-skift till exempel (och skalning, men du normaliserade väl ändå).

Permalänk
Hedersmedlem
Skrivet av heretic16:

Jag gillar dock inte MLK's FFT implementering. Men den så måste man antingen välja complex.h, att inkludera, eller så måste man ha +2 längre data array för att andra elementet måste ha en noll-imaginär tal, vilket är rätt värdelöst. Då början och slutet på en FFT-array i frekvensplanet är alltid ett reellt tal.

Nu har jag inte mkl framför mig, men fftw har ju fftwf_plan_dft_r2c_1d för reell-till-komplex-transformation. MKL är ju kompatibelt, så det borde fungera där också.

Permalänk
Skrivet av Elgot:

Har du testat att rita upp resultatet? De skulle ju kunna ha olika syn på fft-skift till exempel (och skalning, men du normaliserade väl ändå).

Jag behöver tydligen inte normalisera när jag kör FFTPack 5.1, men kör jag FFTPack 5.0 (Det första optimerade) https://github.com/marton78/pffft/blob/master/fftpack.c så måste jag normalisera efter invers FFT.

Vi kan ta ett arbetsexempel.

#define row 3 #define column 3 int main() { clock_t start, end; float cpu_time_used; start = clock(); /* Create X */ float X[row * column] = { -0.6485, 0.2851, 1.3475, -0.6743, -0.1499, -1.5549, 1.4951, 0.4504, -0.4982 }; /* Do FFT2 */ fft2(X, row, column); /* Print */ print(X, row, column); end = clock(); cpu_time_used = ((float)(end - start)) / CLOCKS_PER_SEC; printf("\nTotal speed was %f\n", cpu_time_used); return EXIT_SUCCESS; }

Utskriften blir

0.0058111 0.0258111 -0.1242458 0.1611111 -0.2950723 0.3444953 0.3681955 -0.2190056 0.0864390

Kör jag

ifft2(X, row, column);

direkt efter

fft2(X, row, column);

så får jag samma matris X tillbaka.

Men om det inte spelar någon roll, så låter jag det vara.
Det viktigaste är att jag kan återskapa datat.

Permalänk
Hedersmedlem
Skrivet av heretic16:

Jag behöver tydligen inte normalisera när jag kör FFTPack 5.1, men kör jag FFTPack 5.0 (Det första optimerade) https://github.com/marton78/pffft/blob/master/fftpack.c så måste jag normalisera efter invers FFT.

Vi kan ta ett arbetsexempel.

#define row 3 #define column 3 int main() { clock_t start, end; float cpu_time_used; start = clock(); /* Create X */ float X[row * column] = { -0.6485, 0.2851, 1.3475, -0.6743, -0.1499, -1.5549, 1.4951, 0.4504, -0.4982 }; /* Do FFT2 */ fft2(X, row, column); /* Print */ print(X, row, column); end = clock(); cpu_time_used = ((float)(end - start)) / CLOCKS_PER_SEC; printf("\nTotal speed was %f\n", cpu_time_used); return EXIT_SUCCESS; }

Utskriften blir

0.0058111 0.0258111 -0.1242458 0.1611111 -0.2950723 0.3444953 0.3681955 -0.2190056 0.0864390

Kör jag

ifft2(X, row, column);

direkt efter

fft2(X, row, column);

så får jag samma matris X tillbaka.

Men om det inte spelar någon roll, så låter jag det vara.
Det viktigaste är att jag kan återskapa datat.

Hur ser fft2 ut? Jag får fortfarande inte den där fftpack att stämma med koden du visade förut (rffti och rfftf vill inte ha så många parametrar).

Jag testade mkl också nu (102400 slumpmässiga komplexa sampel):

i7-8700k: 1 tråd 8 trådar mkl 0.36 ms 0.14 ms mkl-fftw 0,36 ms 0.15 ms fftw 0,28 ms 0.094 ms i7-12850HX: 1 tråd 8 trådar mkl-fftw 0,19 ms 0.11 ms fftw 0,17 ms 0.09 ms

FFTW verkar faktiskt vara snabbare i detta fall.

Permalänk
Skrivet av Elgot:

Hur ser fft2 ut? Jag får fortfarande inte den där fftpack att stämma med koden du visade förut (rffti och rfftf vill inte ha så många parametrar).

Jag testade mkl också nu (102400 slumpmässiga komplexa sampel):

i7-8700k: 1 tråd 8 trådar mkl 0.36 ms 0.14 ms mkl-fftw 0,36 ms 0.15 ms fftw 0,28 ms 0.094 ms i7-12850HX: 1 tråd 8 trådar mkl-fftw 0,19 ms 0.11 ms fftw 0,17 ms 0.09 ms

FFTW verkar faktiskt vara snabbare i detta fall.

Jag laddar upp exemplet här: https://easyupload.io/bg2zbv

Du laddar ned FFTPack_5_1.zip och packar upp den. Då finns det två intressanta filer: fft2.c och ifft2.c

Kör med detta exempel

void print(float A[], size_t row, size_t column) { size_t i, j; for (i = 0; i < row; i++) { for (j = 0; j < column; j++) { printf("%0.7f\t", *(A++)); } printf("\n"); } printf("\n"); } #define row 3 #define column 3 int main() { /* Create X */ float X[row * column] = { -0.6485, 0.2851, 1.3475, -0.6743, -0.1499, -1.5549, 1.4951, 0.4504, -0.4982 }; /* Do inverse FFT2 */ fft2(X, row, column); ifft2(X, row, column); /* Print */ print(X, row, column); return 0; }

Permalänk

Jag har löst detta problem nu. Jag bara använde cfft2f/b och multiplicerade varje tal med n*n. Då fick jag samma resultat som Matlab. Om det är värt det, är tveksamt. Det är ju bara en skalning.

Hur som helst så kanske det är värt att testa MLK för FFT, nu när FFTpack 5.1 är något långsamare än FFTPack 5.1.

Hur ser deras komplexa rutin ut? Kräver den C99?

Permalänk
Hedersmedlem
Skrivet av heretic16:

Jag har löst detta problem nu. Jag bara använde cfft2f/b och multiplicerade varje tal med n*n. Då fick jag samma resultat som Matlab. Om det är värt det, är tveksamt. Det är ju bara en skalning.

Nej, det är som sagt bara skalning. Man vill förmodligen ändå skala om på något sätt om man skall presentera resultatet på något sätt.

Skrivet av heretic16:

Hur som helst så kanske det är värt att testa MLK för FFT, nu när FFTpack 5.1 är något långsamare än FFTPack 5.1.

Hur ser deras komplexa rutin ut? Kräver den C99?

Du borde kunna använda min kodsnutt ovan. FFTW borde också fungera, men om du vill använda mkl istället är det bara att länka till de biblioteken istället för fftw. Man behöver inte ändra koden.

Permalänk
Skrivet av Elgot:

Nej, det är som sagt bara skalning. Man vill förmodligen ändå skala om på något sätt om man skall presentera resultatet på något sätt.
Du borde kunna använda min kodsnutt ovan. FFTW borde också fungera, men om du vill använda mkl istället är det bara att länka till de biblioteken istället för fftw. Man behöver inte ändra koden.

Jag kollade upp FFT för MKL och den kräver C99 för FFT complex. Jag försöker alltid att vara halvt besvärlig igenom att strikt hålla mig till ANSI C. Detta har med att ANSI C är liksom oändlig och kod som är skrivet i ANSI C blir för evig.

Permalänk
Hedersmedlem
Skrivet av heretic16:

Jag kollade upp FFT för MKL och den kräver C99 för FFT complex. Jag försöker alltid att vara halvt besvärlig igenom att strikt hålla mig till ANSI C. Detta har med att ANSI C är liksom oändlig och kod som är skrivet i ANSI C blir för evig.

Håll dig till FFTW då; den påstås vara skriven i ansi-c.

Permalänk
Skrivet av Elgot:

Håll dig till FFTW då; den påstås vara skriven i ansi-c.

Men FFTW innehåller så mycket filer. Jag gillar när det är bara några .c filer som man kan bara klistra in. Då slipper man allt görm med att länka hit och dit.

Permalänk
Hedersmedlem
Skrivet av heretic16:

Men FFTW innehåller så mycket filer. Jag gillar när det är bara några .c filer som man kan bara klistra in. Då slipper man allt görm med att länka hit och dit.

Det där fftpack-paketet du länkade till förut var väl också massor av filer?

Annars finns ju fftw fördigbyggt för många system och annars är det ju bara (om du kör cmake) att packa upp koden och inkludera mappen i projektet.

Permalänk
Skrivet av Elgot:

Det där fftpack-paketet du länkade till förut var väl också massor av filer?

Annars finns ju fftw fördigbyggt för många system och annars är det ju bara (om du kör cmake) att packa upp koden och inkludera mappen i projektet.

FFTPack är bara en mapp med massa .f filer som man exporterar till .c via f2c. Inge mer.

Jag är nyfiken på vilken mapp du pratar om då i FFTW3.

Permalänk
Hedersmedlem
Skrivet av heretic16:

Jag är nyfiken på vilken mapp du pratar om då i FFTW3.

Källkoden finns här.

Permalänk

Jag misstänker att FFTW3 använder sig av hårdvaran?

Nu verkar jag ha problem igen med cfft2f hos FFTPack 5.1.
Jag trodde jag kunde multiplicera alla element med antalet celler i matrisen t.ex. m*n. Men det verkar inte gälla för alla scenarion.

Är det någon som vet hur FFTPack är normaliserad? Enligt manualen så är den normaliserad. Men jag har ett behov utav att få den mer lik matlabs.

Permalänk
Hedersmedlem
Skrivet av heretic16:

Jag misstänker att FFTW3 använder sig av hårdvaran?

Ja, den identifierar lämplig hårdvara (sse, avx, neon och liknande) under körning och använder den om den finns. Man måste dock säga att man vill ha sådant stöd när man bygger FFTW.

Skrivet av heretic16:

Är det någon som vet hur FFTPack är normaliserad? Enligt manualen så är den normaliserad. Men jag har ett behov utav att få den mer lik matlabs.

Parsevals teorem borde gälla:

Permalänk
Skrivet av Elgot:

Ja, den identifierar lämplig hårdvara (sse, avx, neon och liknande) under körning och använder den om den finns. Man måste dock säga att man vill ha sådant stöd när man bygger FFTW.

Parsevals teorem borde gälla:
https://ccrma.stanford.edu/~jos/st/img1415_2x.png

Jadu.
Det fungerar bra vid 1D, men vid 2D så fungerar det inte alls.

Jag har en liten idé!
FFTpack som jag använde först, den där optimerade från Pretty Fast FFT på GitHub. Den kan bara göra 1D FFT och den gav exakt samma resultat som Matlab gjorde. Dessutom var den riktigt optimerad, trots bara en .c och .h fil. Orsaken har med att skaparen har själv tagit bort lite onödiga saker så som massa gotos osv.

Men orsaken varför jag gick över till FFTPack 5.1 har med att den har 2D beräkningar för komplexa tal, trots ANSI C.

Matlab's FFT2 fungerar så att den tar FFT på alla kolumner, sedan tar den transponatet av resultatet och sedan tar FFT på alla rader. Så här alltså.

fft(fft(X)')'

Pretty Fast FFT https://github.com/marton78/pffft/blob/master/fftpack.h
Denna har cffti, cfftf, cfftb och med dessa så kanske jag kan göra en FFT 1D på en 2D matris.
Men då är frågan hur jag skapar min komplexa array?

Citat:

******************************************************************

subroutine cfftf(n,c,wsave)

******************************************************************

subroutine cfftf computes the forward complex discrete fourier
transform (the fourier analysis). equivalently , cfftf computes
the fourier coefficients of a complex periodic sequence.
the transform is defined below at output parameter c.

the transform is not normalized. to obtain a normalized transform
the output must be divided by n. otherwise a call of cfftf
followed by a call of cfftb will multiply the sequence by n.

the array wsave which is used by subroutine cfftf must be
initialized by calling subroutine cffti(n,wsave).

input parameters

n the length of the complex sequence c. the method is
more efficient when n is the product of small primes. n

c a complex array of length n which contains the sequence

wsave a real work array which must be dimensioned at least 4n+15
in the program that calls cfftf. the wsave array must be
initialized by calling subroutine cffti(n,wsave) and a
different wsave array must be used for each different
value of n. this initialization does not have to be
repeated so long as n remains unchanged thus subsequent
transforms can be obtained faster than the first.
the same wsave array can be used by cfftf and cfftb.

output parameters

c for j=1,...,n

c(j)=the sum from k=1,...,n of

c(k)*exp(-i*(j-1)*(k-1)*2*pi/n)

where i=sqrt(-1)

wsave contains initialization calculations which must not be
destroyed between calls of subroutine cfftf or cfftb

Hur ska arrayen c vara? Jag vet att den ska vara komplex, men om den ska vara n lång, så måste den väll vara 2*n lång om den ska vara komplex?

Jag har svårt att tolka hur arrayen c ska skapas. Det är av datatypen float. Så jag misstänker att antingen ska arrayen vara 2*n, eller så så blir det bara halva frekvensen?

Permalänk
Hedersmedlem
Skrivet av heretic16:

Pretty Fast FFT https://github.com/marton78/pffft/blob/master/fftpack.h
Denna har cffti, cfftf, cfftb och med dessa så kanske jag kan göra en FFT 1D på en 2D matris.
Men då är frågan hur jag skapar min komplexa array?
Hur ska arrayen c vara? Jag vet att den ska vara komplex, men om den ska vara n lång, så måste den väll vara 2*n lång om den ska vara komplex?

Jag har svårt att tolka hur arrayen c ska skapas. Det är av datatypen float. Så jag misstänker att antingen ska arrayen vara 2*n, eller så så blir det bara halva frekvensen?

De har några exempel (till exempel här) och det verkar som att det skall vara varannan reell och varannan imaginär.

Permalänk
Skrivet av Elgot:

De har några exempel (till exempel här) och det verkar som att det skall vara varannan reell och varannan imaginär.

Tackar. Jag ska testa detta.
Jag hoppas att det ska gå bättre att göra 2D FFT av 1D FFT. Jag gillar inte att det är icke-samma resultat från FFTPack 5.1, trots att man kan återskapa signalen med invers FFT.

Återkommer.

Permalänk

Nu har jag testat ytterligare.

Jag testade göra FFT 2D av två stycken rffti -> rfftf -> cffti -> cfftf
r står för tids-data och c står för komplex data.

Med den där optimerade fftpack.h och fftpack.c från Pretty Fast FFT så tog det 3.15 sekunder att göra FFT 2D på en 5000*5000 matris.
Med FFTpack 5.1 så tog det 5.3 sekunder att göra FFT 2D på en 5000*5000 matris.

Dessutom gav fftpack.h och fftpack.c filen från Pretty Fast FFT 100% exakt samma resultat som Matlab.
Notera att detta är utan någon optimeringsflagga eller liknande. Bara ren ANSI C kod som är plattformsoberoende.

Det var trixigt att få till rffti -> rfftf -> cffti -> cfftf då det inte finns någon manual eller ens folk som verkar använda det, trots att FFTpack är snabbt om man väljer den från Pretty Fast FFT.

Permalänk
Hedersmedlem
Skrivet av heretic16:

Med FFTpack 5.1 så tog det 5.3 sekunder att göra FFT 2D på en 5000*5000 matris.

Dessutom gav fftpack.h och fftpack.c filen från Pretty Fast FFT 100% exakt samma resultat som Matlab.
Notera att detta är utan någon optimeringsflagga eller liknande. Bara ren ANSI C kod som är plattformsoberoende.

Det var trixigt att få till rffti -> rfftf -> cffti -> cfftf då det inte finns någon manual eller ens folk som verkar använda det, trots att FFTpack är snabbt om man väljer den från Pretty Fast FFT.

FFTW verkar väl ändå vara närmare 10 gånger snabbare (och plattformsoberoende ansi-c), och folk i allmänhet bryr sig kanske inte så mycket om hur många filer som ingår? PFFFT verkar ju också förespråka att man bygger det som ett bibliotek.

Permalänk
Skrivet av Elgot:

FFTW verkar väl ändå vara närmare 10 gånger snabbare (och plattformsoberoende ansi-c), och folk i allmänhet bryr sig kanske inte så mycket om hur många filer som ingår? PFFFT verkar ju också förespråka att man bygger det som ett bibliotek.

Jo, fast FFTW använder säkert trådar. fftpack.h och fftpack.c kommer från PFFFT och det är en modifierad FFTpack version. Troligtvis så har dom själv manuellt tagit bort massa saker för att det ska gå snabbare.

FFTW är säkert jättebra, men det verkar vara mycket filer. fftpack.c/h från PFFFT är bara två filer och är riktigt snabbt. Så jag känner mig nöjd.

Tror jag inte kan få det snabbare. FFTW3 sägs inte vara den snabbaste heller. Tror mycket handlar om vilken hårdvara och kompilator man använder. Jag kör MSVC.

Permalänk
Hedersmedlem
Skrivet av heretic16:

Jo, fast FFTW använder säkert trådar.

Det kan den göra om man ber den, men det förklarar inte skillnaden (i just det här fallet verkar det inte göra så stor skillnad heller). Pffft har ju också stöd för simd, så det borde inte vara det heller.

Skrivet av heretic16:

FFTW är säkert jättebra, men det verkar vara mycket filer. fftpack.c/h från PFFFT är bara två filer och är riktigt snabbt. Så jag känner mig nöjd.

Tror jag inte kan få det snabbare. FFTW3 sägs inte vara den snabbaste heller. Tror mycket handlar om vilken hårdvara och kompilator man använder. Jag kör MSVC.

Fler filer är det förstås, men är det verkligen så mycket att bry sig om? Om man länkar till mkl (eller om fftw redan finns i systemet) behöver man heller inte mer än h-filen.
Jag har testat gcc (i windows och linux) och msvc på hyfsat modern x86_64, och det verkar inte vara så stor skillnad.

Permalänk
Skrivet av Elgot:

Det kan den göra om man ber den, men det förklarar inte skillnaden (i just det här fallet verkar det inte göra så stor skillnad heller). Pffft har ju också stöd för simd, så det borde inte vara det heller.

Fler filer är det förstås, men är det verkligen så mycket att bry sig om? Om man länkar till mkl (eller om fftw redan finns i systemet) behöver man heller inte mer än h-filen.
Jag har testat gcc (i windows och linux) och msvc på hyfsat modern x86_64, och det verkar inte vara så stor skillnad.

Testa och kör dessa exempel: https://easyupload.io/b7kr10

Kolla vad du får för tid vid 5000*5000 matris.
Det tog 3.15 sekunder för mig.

Permalänk
Hedersmedlem
Skrivet av heretic16:

Testa och kör dessa exempel: https://easyupload.io/b7kr10

Kolla vad du får för tid vid 5000*5000 matris.
Det tog 3.15 sekunder för mig.

Kom alla filer med (finns det en main till exempel)?

Hur lång tid tar det för dig i matlab?
En slumpad 5000x5000-matris tar 0,4 sekunder i octave på den dator jag sitter vid just nu och mitt program är något snabbare (0,35 s, och 0,25 s med fyra trådar).

Edit:
På en dator där octave tar 0,13 sekunder tar din fft2 1,7 sekunder.

Permalänk
Skrivet av Elgot:

Kom alla filer med (finns det en main till exempel)?

Hur lång tid tar det för dig i matlab?
En slumpad 5000x5000-matris tar 0,4 sekunder i octave på den dator jag sitter vid just nu och mitt program är något snabbare (0,35 s, och 0,25 s med fyra trådar).

Edit:
På en dator där octave tar 0,13 sekunder tar din fft2 1,7 sekunder.

Det går självklart snabbare I Octave

>> tic; fft2(randn(5000,5000)); toc Elapsed time is 0.671597 seconds. >>

Så 1.7 sekunder är inte illa, med tanke på att det är bara en enkel C fil Jag har försökt optimera detta så bra som möjligt.

Så:
Din dator FFT2 med min kod: 1.7 sekunder
Min dator FFT2 med min kod: 3.15 sekunder
Din dator FFT2 med octave: 0.13 sekunder
Min dator FFT2 med min kod: 0.67 sekunder

Detta betyder att din dator är ungefär 2 gånger snabbare än min.

Permalänk
Hedersmedlem
Skrivet av heretic16:

Det går självklart snabbare I Octave

>> tic; fft2(randn(5000,5000)); toc Elapsed time is 0.671597 seconds. >>

Nu räknar du också med dubbel precision.
>> m=single(randn(5000,5000)); tic; fft2(m); toc
borde vara ytterligare lite snabbare.

Skrivet av heretic16:

Så 1.7 sekunder är inte illa, med tanke på att det är bara en enkel C fil Jag har försökt optimera detta så bra som möjligt.

Antalet filer är ju dock inget man normalt bryr sig om. Lägg dem i en egen mapp, bygg och länka. Eller använd en färdigbyggd version.
Man skulle säkert kunna refaktorera fftw till enstaka filer också, men det vanliga är väl snarare att gå åt andra hållet för ökad översiktlighet.

Permalänk
Skrivet av Elgot:

Nu räknar du också med dubbel precision.
>> m=single(randn(5000,5000)); tic; fft2(m); toc
borde vara ytterligare lite snabbare.

Antalet filer är ju dock inget man normalt bryr sig om. Lägg dem i en egen mapp, bygg och länka. Eller använd en färdigbyggd version.
Man skulle säkert kunna refaktorera fftw till enstaka filer också, men det vanliga är väl snarare att gå åt andra hållet för ökad översiktlighet.

Ja, det gick mycket snabbare.

>> m=single(randn(5000,5000)); tic; fft2(m); toc Elapsed time is 0.191178 seconds.

Problemet är att jag vet inte vilka filer jag ska ha. FFTW är inte pedagogiskt skrivet direkt.
Sedan så kräver FFTW3 att man ska vara licensierad mot MIT om det ska användas i kommersiella produkter.

Permalänk
Medlem
Skrivet av heretic16:

Sedan så kräver FFTW3 att man ska vara licensierad mot MIT om det ska användas i kommersiella produkter.

Går det inte att köpa en MIT licens på t.ex. Amazon?

Permalänk
Hedersmedlem
Skrivet av heretic16:

Problemet är att jag vet inte vilka filer jag ska ha. FFTW är inte pedagogiskt skrivet direkt.

Man behöver inte veta så mycket. Du behöver inkludera fftw3f.h och sedan länka till fftw3f.lib (windows) eller libfftw3f (linux) eller mkl. Om biblioten inte finns i systemet kan man bygga dem genom att köra cmake.

Skrivet av heretic16:

Sedan så kräver FFTW3 att man ska vara licensierad mot MIT om det ska användas i kommersiella produkter.

Ja, licenser kan ju däremot vara ett problem men man borde komma runt det om man använder mkl.