void zn_array_mulmid_fft_precomp1_execute (ulong* res, const ulong* op2, ulong x, const zn_array_mulmid_fft_precomp1_t precomp) { const pmfvec_struct* vec1 = precomp->vec1; size_t n1 = precomp->n1; size_t n2 = precomp->n2; ulong m1 = precomp->m1; ulong m2 = precomp->m2; pmfvec_t vec2; pmfvec_init (vec2, vec1->lgK, vec1->skip, vec1->lgM, vec1->mod); // split and compute FFT of second input (with requested scaling factor) fft_split (vec2, op2, n2, 0, x, 0); pmfvec_fft (vec2, m1, m2, 0); // pointwise multiply against precomputed transposed IFFT of first input pmfvec_mul (vec2, vec1, vec2, m1, 0); // transposed FFT ulong m3 = m1 - m2 + 1; pmfvec_tpfft (vec2, m1, m3, 0); // reverse output and combine pmfvec_reverse (vec2, m3); fft_combine (res, n1 - n2 + 1, vec2, m3, 1); pmfvec_reverse (vec2, m3); pmfvec_clear (vec2); }
int main(int argc, char **argv) { // init args, format : fft -f file_name num_entries // fft samples cycles [phase] <- sin, phase in // increments of pi // fft -c samples cycles [phase] <- cos // fft -s samples cycles [phase] <- sqr Cnum *input; if (argc > 2) { int samples = 0; if (argv[1][0] == '-') { if (!argv[1][1]) goto usage; if (argv[1][1] == 'f') { if (argc == 4) { sscanf(argv[3], "%d", &samples); input = (Cnum *) malloc(sizeof(Cnum)*samples); input = read_file_in(argv[2]); } else goto usage; } else { double cycles = 0; sscanf(argv[2], "%d", &samples); sscanf(argv[3], "%lf", &cycles); double phase = 0; input = (Cnum *) malloc(sizeof(Cnum)*samples); if (argc == 5) sscanf(argv[4], "%lf", &phase); if (argv[1][1] == 'c') cos_wave(samples, cycles, phase*M_PI, input); if (argv[1][1] == 's') sqr_wave(samples, cycles, phase*M_PI, input); else goto usage; } } else { if (argc != 3 && argc != 4) goto usage; double cycles = 0; sscanf(argv[1], "%d", &samples); sscanf(argv[2], "%lf", &cycles); input = (Cnum *) malloc(sizeof(Cnum)*samples); double phase = 0; if (argc == 4) sscanf(argv[3], "%lf", &phase); sin_wave(samples, cycles, phase*M_PI, input); } Cnum *output = (Cnum *) malloc(sizeof(Cnum)*samples); /*Cnum *dout = (Cnum *) malloc(sizeof(Cnum)*samples);*/ Cnum *even = (Cnum *) malloc(sizeof(Cnum)*samples/2); Cnum *odd = (Cnum *) malloc(sizeof(Cnum)*samples/2); for (int i = 0; i < samples/2; i++) { even[i] = input[2*i]; odd[i] = input[2*i+1]; } // output = fft(samples, input); output = fft_combine(samples, fft(samples/2, even), fft(samples/2, odd)); Cnum *x; printf("Test example for two nodes:\n"); for (int i = 0; i < samples; i++) { /*double y = magn(&output[i])/samples;*/ x = &output[i]; printf("%f + %f i\n", x->real, x->imag); } printf("\n"); Cnum *even_even = (Cnum *) malloc(sizeof(Cnum)*samples/4); Cnum *even_odd = (Cnum *) malloc(sizeof(Cnum)*samples/4); for (int i = 0; i < samples/4; i++) { even_even[i] = even[2*i]; even_odd[i] = even[2*i+1]; } Cnum *odd_even = (Cnum *) malloc(sizeof(Cnum)*samples/4); Cnum *odd_odd = (Cnum *) malloc(sizeof(Cnum)*samples/4); for (int i = 0; i < samples/4; i++) { odd_even[i] = odd[2*i]; odd_odd[i] = odd[2*i+1]; } printf("Test example for four nodes:\n"); output = fft_combine(samples, fft_combine(samples/2, fft(samples/4, even_even), fft(samples/4, even_odd)), fft_combine(samples/2, fft(samples/4, odd_even), fft(samples/4, odd_odd))); for (int i = 0; i < samples; i++) { /*double y = magn(&output[i])/samples;*/ x = &output[i]; printf("%f + %f i\n", x->real, x->imag); } return 0; } usage: free (input); puts ("Usage : fft -[cs] samples cycles [phase]"); puts (" fft -f file_name samples"); exit (1); }
void zn_array_mul_fft (ulong* res, const ulong* op1, size_t n1, const ulong* op2, size_t n2, ulong x, const zn_mod_t mod) { ZNP_ASSERT (mod->m & 1); ZNP_ASSERT (n2 >= 1); ZNP_ASSERT (n1 >= n2); unsigned lgK, lgM; // number of pmf_t coefficients for each input poly ulong m1, m2; // figure out how big the transform needs to be mul_fft_params (&lgK, &lgM, &m1, &m2, n1, n2); // number of pmf_t coefficients for output poly ulong m3 = m1 + m2 - 1; ulong M = 1UL << lgM; ulong K = 1UL << lgK; ptrdiff_t skip = M + 1; pmfvec_t vec1, vec2; int sqr = (op1 == op2 && n1 == n2); if (!sqr) { // multiplying two distinct inputs // split inputs into pmf_t's and perform FFTs pmfvec_init (vec1, lgK, skip, lgM, mod); fft_split (vec1, op1, n1, 0, 1, 0); pmfvec_fft (vec1, m3, m1, 0); // note: we apply the fudge factor here, because the second input is // shorter than both the first input and the output :-) pmfvec_init (vec2, lgK, skip, lgM, mod); fft_split (vec2, op2, n2, 0, x, 0); pmfvec_fft (vec2, m3, m2, 0); // pointwise multiplication pmfvec_mul (vec1, vec1, vec2, m3, 1); pmfvec_clear (vec2); } else { // squaring a single input // split input into pmf_t's and perform FFTs pmfvec_init (vec1, lgK, skip, lgM, mod); fft_split (vec1, op1, n1, 0, 1, 0); pmfvec_fft (vec1, m3, m1, 0); // pointwise multiplication pmfvec_mul (vec1, vec1, vec1, m3, 1); } // inverse FFT, and write output pmfvec_ifft (vec1, m3, 0, m3, 0); size_t n3 = n1 + n2 - 1; fft_combine (res, n3, vec1, m3, 0); pmfvec_clear (vec1); // if we're squaring, then we haven't applied the fudge factor yet, // so do it now if (sqr) zn_array_scalar_mul_or_copy (res, res, n3, x, mod); }
void zn_array_invert_extend_fft (ulong* res, const ulong* approx, const ulong* op, size_t n1, size_t n2, const zn_mod_t mod) { ZNP_ASSERT (n2 >= 1); ZNP_ASSERT (n1 >= n2); ZNP_ASSERT (mod->m & 1); // The algorithm here is the same as in zn_array_invert_extend(), except // that we work with the FFTs directly. This allows us to save one FFT, // since we use the FFT of g in both the middle product step and the // product step. // Determine FFT parameters for computing h = middle product of // f[1, n1 + n2) and g[0, n1). (These parameters will also work for the // subsequent product g * h.) unsigned lgK, lgM; ulong m1, m2, m3, p; mulmid_fft_params (&lgK, &lgM, &m3, &m1, &p, n1 + n2 - 1, n1); m2 = m3 - m1 + 1; // We now have // m1 = ceil(n1 / (M/2)) // = (n1 + p - 1) / (M/2). // Therefore // m3 = ceil((n1 + n2 - 1 + p) / (M/2)) // = ceil(n2 / (M/2)) + (n1 + p - 1) / (M/2) // and // m2 = ceil(n2 / (M/2)) + 1. ulong M = 1UL << lgM; ulong K = 1UL << lgK; ptrdiff_t skip = M + 1; pmfvec_t vec1, vec2; pmfvec_init (vec1, lgK, skip, lgM, mod); pmfvec_init (vec2, lgK, skip, lgM, mod); // Find scaling factor that needs to be applied to both of the products // below; takes into account the fudge from the pointwise multiplies, and // the division by 2^lgK coming from the FFTs. ulong x = pmfvec_mul_fudge (lgM, 0, mod); x = zn_mod_mul (x, zn_mod_pow2 (-lgK, mod), mod); // Split g[0, n1) into m1 coefficients, apply scaling factor, and compute // m3 fourier coefficients, written to vec2. fft_split (vec2, approx, n1, 0, x, 0); pmfvec_fft (vec2, m3, m1, 0); // Split f[1, n1 + n2) into m3 coefficients (in reversed order, with // appropriate zero-padding), and compute transposed IFFT of length m3, // written to vec1. pmfvec_reverse (vec1, m3); fft_split (vec1, op + 1, n1 + n2 - 1, p, 1, 0); pmfvec_reverse (vec1, m3); pmfvec_tpifft (vec1, m3, 0, m3, 0); // Pointwise multiply the above FFT and transposed IFFT, into vec1. pmfvec_mul (vec1, vec1, vec2, m3, 0); // Transposed FFT vec1, obtaining m2 coefficients, then reverse and combine. pmfvec_tpfft (vec1, m3, m2, 0); pmfvec_reverse (vec1, m2); fft_combine (res, n2, vec1, m2, 1); pmfvec_reverse (vec1, m2); // At this stage we have obtained the polynomial h in res[0, n2). // Now we must compute h * g. // Split h[0, n2) into m2 - 1 coefficients, and compute m3 - 1 fourier // coefficients in vec1. For the splitting step, we set the bias to M, // which effectively negates everything, so we're really computing the FFT // of -h. fft_split (vec1, res, n2, 0, 1, M); pmfvec_fft (vec1, m3 - 1, m2 - 1, 0); // Pointwise multiply that FFT with the first FFT of g into vec2. pmfvec_mul (vec2, vec2, vec1, m3 - 1, 1); pmfvec_clear (vec1); // IFFT and combine, to obtain the product -h * g. We only need the low n2 // terms of the product (we throw away the high n1 - 1 terms). pmfvec_ifft (vec2, m3 - 1, 0, m3 - 1, 0); fft_combine (res, n2, vec2, m3 - 1, 0); pmfvec_clear (vec2); }