/** * The main program. * * \param argc The number of arguments * \param argv An array containing the arguments as C-strings * * \return Exit code * * \author Jens Keiner */ int main (int argc, char **argv) { int T; int N; int M; int M2; int t; /* Index variable for testcases */ nfsft_plan plan; /* NFSFT plan */ nfsft_plan plan2; /* NFSFT plan */ solver_plan_complex iplan; /* NFSFT plan */ int j; /* */ int k; /* */ int m; /* */ int use_nfsft; /* */ int use_nfft; /* */ int use_fpt; /* */ int cutoff; /**< The current NFFT cut-off parameter */ double threshold; /**< The current NFSFT threshold parameter */ double re; double im; double a; double *scratch; double xs; double *ys; double *temp; double _Complex *temp2; int qlength; double *qweights; fftw_plan fplan; fpt_set set; int npt; int npt_exp; double *alpha, *beta, *gamma; /* Read the number of testcases. */ fscanf(stdin,"testcases=%d\n",&T); fprintf(stderr,"%d\n",T); /* Process each testcase. */ for (t = 0; t < T; t++) { /* Check if the fast transform shall be used. */ fscanf(stdin,"nfsft=%d\n",&use_nfsft); fprintf(stderr,"%d\n",use_nfsft); if (use_nfsft != NO) { /* Check if the NFFT shall be used. */ fscanf(stdin,"nfft=%d\n",&use_nfft); fprintf(stderr,"%d\n",use_nfsft); if (use_nfft != NO) { /* Read the cut-off parameter. */ fscanf(stdin,"cutoff=%d\n",&cutoff); fprintf(stderr,"%d\n",cutoff); } else { /* TODO remove this */ /* Initialize unused variable with dummy value. */ cutoff = 1; } /* Check if the fast polynomial transform shall be used. */ fscanf(stdin,"fpt=%d\n",&use_fpt); fprintf(stderr,"%d\n",use_fpt); if (use_fpt != NO) { /* Read the NFSFT threshold parameter. */ fscanf(stdin,"threshold=%lf\n",&threshold); fprintf(stderr,"%lf\n",threshold); } else { /* TODO remove this */ /* Initialize unused variable with dummy value. */ threshold = 1000.0; } } else { /* TODO remove this */ /* Set dummy values. */ use_nfft = NO; use_fpt = NO; cutoff = 3; threshold = 1000.0; } /* Read the bandwidth. */ fscanf(stdin,"bandwidth=%d\n",&N); fprintf(stderr,"%d\n",N); /* Do precomputation. */ nfsft_precompute(N,threshold, ((use_nfsft==NO)?(NFSFT_NO_FAST_ALGORITHM):(0U/*NFSFT_NO_DIRECT_ALGORITHM*/)), 0U); /* Read the number of nodes. */ fscanf(stdin,"nodes=%d\n",&M); fprintf(stderr,"%d\n",M); /* */ if ((N+1)*(N+1) > M) { X(next_power_of_2_exp)(N, &npt, &npt_exp); fprintf(stderr, "npt = %d, npt_exp = %d\n", npt, npt_exp); fprintf(stderr,"Optimal interpolation!\n"); scratch = (double*) nfft_malloc(4*sizeof(double)); ys = (double*) nfft_malloc((N+1)*sizeof(double)); temp = (double*) nfft_malloc((2*N+1)*sizeof(double)); temp2 = (double _Complex*) nfft_malloc((N+1)*sizeof(double _Complex)); a = 0.0; for (j = 0; j <= N; j++) { xs = 2.0 + (2.0*j)/(N+1); ys[j] = (2.0-((j == 0)?(1.0):(0.0)))*4.0*nfft_bspline(4,xs,scratch); //fprintf(stdout,"%3d: g(%le) = %le\n",j,xs,ys[j]); a += ys[j]; } //fprintf(stdout,"a = %le\n",a); for (j = 0; j <= N; j++) { ys[j] *= 1.0/a; } qlength = 2*N+1; qweights = (double*) nfft_malloc(qlength*sizeof(double)); fplan = fftw_plan_r2r_1d(N+1, qweights, qweights, FFTW_REDFT00, 0U); for (j = 0; j < N+1; j++) { qweights[j] = -2.0/(4*j*j-1); } fftw_execute(fplan); qweights[0] *= 0.5; for (j = 0; j < N+1; j++) { qweights[j] *= 1.0/(2.0*N+1.0); qweights[2*N+1-1-j] = qweights[j]; } fplan = fftw_plan_r2r_1d(2*N+1, temp, temp, FFTW_REDFT00, 0U); for (j = 0; j <= N; j++) { temp[j] = ((j==0 || j == 2*N)?(1.0):(0.5))*ys[j]; } for (j = N+1; j < 2*N+1; j++) { temp[j] = 0.0; } fftw_execute(fplan); for (j = 0; j < 2*N+1; j++) { temp[j] *= qweights[j]; } fftw_execute(fplan); for (j = 0; j < 2*N+1; j++) { temp[j] *= ((j==0 || j == 2*N)?(1.0):(0.5)); if (j <= N) { temp2[j] = temp[j]; } } set = fpt_init(1, npt_exp, 0U); alpha = (double*) nfft_malloc((N+2)*sizeof(double)); beta = (double*) nfft_malloc((N+2)*sizeof(double)); gamma = (double*) nfft_malloc((N+2)*sizeof(double)); alpha_al_row(alpha, N, 0); beta_al_row(beta, N, 0); gamma_al_row(gamma, N, 0); fpt_precompute(set, 0, alpha, beta, gamma, 0, 1000.0); fpt_transposed(set,0, temp2, temp2, N, 0U); fpt_finalize(set); nfft_free(alpha); nfft_free(beta); nfft_free(gamma); fftw_destroy_plan(fplan); nfft_free(scratch); nfft_free(qweights); nfft_free(ys); nfft_free(temp); } /* Init transform plans. */ nfsft_init_guru(&plan, N, M, ((use_nfft!=0)?(0U):(NFSFT_USE_NDFT)) | ((use_fpt!=0)?(0U):(NFSFT_USE_DPT)) | NFSFT_MALLOC_F | NFSFT_MALLOC_X | NFSFT_MALLOC_F_HAT | NFSFT_NORMALIZED | NFSFT_ZERO_F_HAT, PRE_PHI_HUT | PRE_PSI | FFTW_INIT | FFT_OUT_OF_PLACE, cutoff); if ((N+1)*(N+1) > M) { solver_init_advanced_complex(&iplan, (nfft_mv_plan_complex*)(&plan), CGNE | PRECOMPUTE_DAMP); } else { solver_init_advanced_complex(&iplan, (nfft_mv_plan_complex*)(&plan), CGNR | PRECOMPUTE_WEIGHT | PRECOMPUTE_DAMP); } /* Read the nodes and function values. */ for (j = 0; j < M; j++) { fscanf(stdin,"%le %le %le %le\n",&plan.x[2*j+1],&plan.x[2*j],&re,&im); plan.x[2*j+1] = plan.x[2*j+1]/(2.0*PI); plan.x[2*j] = plan.x[2*j]/(2.0*PI); if (plan.x[2*j] >= 0.5) { plan.x[2*j] = plan.x[2*j] - 1; } iplan.y[j] = re + _Complex_I * im; fprintf(stderr,"%le %le %le %le\n",plan.x[2*j+1],plan.x[2*j], creal(iplan.y[j]),cimag(iplan.y[j])); } /* Read the number of nodes. */ fscanf(stdin,"nodes_eval=%d\n",&M2); fprintf(stderr,"%d\n",M2); /* Init transform plans. */ nfsft_init_guru(&plan2, N, M2, ((use_nfft!=0)?(0U):(NFSFT_USE_NDFT)) | ((use_fpt!=0)?(0U):(NFSFT_USE_DPT)) | NFSFT_MALLOC_F | NFSFT_MALLOC_X | NFSFT_MALLOC_F_HAT | NFSFT_NORMALIZED | NFSFT_ZERO_F_HAT, PRE_PHI_HUT | PRE_PSI | FFTW_INIT | FFT_OUT_OF_PLACE, cutoff); /* Read the nodes and function values. */ for (j = 0; j < M2; j++) { fscanf(stdin,"%le %le\n",&plan2.x[2*j+1],&plan2.x[2*j]); plan2.x[2*j+1] = plan2.x[2*j+1]/(2.0*PI); plan2.x[2*j] = plan2.x[2*j]/(2.0*PI); if (plan2.x[2*j] >= 0.5) { plan2.x[2*j] = plan2.x[2*j] - 1; } fprintf(stderr,"%le %le\n",plan2.x[2*j+1],plan2.x[2*j]); } nfsft_precompute_x(&plan); nfsft_precompute_x(&plan2); /* Frequency weights. */ if ((N+1)*(N+1) > M) { /* Compute Voronoi weights. */ //nfft_voronoi_weights_S2(iplan.w, plan.x, M); /* Print out Voronoi weights. */ /*a = 0.0; for (j = 0; j < plan.M_total; j++) { fprintf(stderr,"%le\n",iplan.w[j]); a += iplan.w[j]; } fprintf(stderr,"sum = %le\n",a);*/ for (j = 0; j < plan.N_total; j++) { iplan.w_hat[j] = 0.0; } for (k = 0; k <= N; k++) { for (j = -k; j <= k; j++) { iplan.w_hat[NFSFT_INDEX(k,j,&plan)] = 1.0/(pow(k+1.0,2.0)); /*temp2[j]*/; } } } else { for (j = 0; j < plan.N_total; j++) { iplan.w_hat[j] = 0.0; } for (k = 0; k <= N; k++) { for (j = -k; j <= k; j++) { iplan.w_hat[NFSFT_INDEX(k,j,&plan)] = 1/(pow(k+1.0,2.5)); } } /* Compute Voronoi weights. */ nfft_voronoi_weights_S2(iplan.w, plan.x, M); /* Print out Voronoi weights. */ a = 0.0; for (j = 0; j < plan.M_total; j++) { fprintf(stderr,"%le\n",iplan.w[j]); a += iplan.w[j]; } fprintf(stderr,"sum = %le\n",a); } fprintf(stderr, "N_total = %d\n", plan.N_total); fprintf(stderr, "M_total = %d\n", plan.M_total); /* init some guess */ for (k = 0; k < plan.N_total; k++) { iplan.f_hat_iter[k] = 0.0; } /* inverse trafo */ solver_before_loop_complex(&iplan); /*for (k = 0; k < plan.M_total; k++) { printf("%le %le\n",creal(iplan.r_iter[k]),cimag(iplan.r_iter[k])); }*/ for (m = 0; m < 29; m++) { fprintf(stderr,"Residual ||r||=%e,\n",sqrt(iplan.dot_r_iter)); solver_loop_one_step_complex(&iplan); } /*NFFT_SWAP_complex(iplan.f_hat_iter, plan.f_hat); nfsft_trafo(&plan); NFFT_SWAP_complex(iplan.f_hat_iter, plan.f_hat); a = 0.0; b = 0.0; for (k = 0; k < plan.M_total; k++) { printf("%le %le %le\n",cabs(iplan.y[k]),cabs(plan.f[k]), cabs(iplan.y[k]-plan.f[k])); a += cabs(iplan.y[k]-plan.f[k])*cabs(iplan.y[k]-plan.f[k]); b += cabs(iplan.y[k])*cabs(iplan.y[k]); } fprintf(stderr,"relative error in 2-norm: %le\n",a/b);*/ NFFT_SWAP_complex(iplan.f_hat_iter, plan2.f_hat); nfsft_trafo(&plan2); NFFT_SWAP_complex(iplan.f_hat_iter, plan2.f_hat); for (k = 0; k < plan2.M_total; k++) { fprintf(stdout,"%le\n",cabs(plan2.f[k])); } solver_finalize_complex(&iplan); nfsft_finalize(&plan); nfsft_finalize(&plan2); /* Delete precomputed data. */ nfsft_forget(); if ((N+1)*(N+1) > M) { nfft_free(temp2); } } /* Process each testcase. */ /* Return exit code for successful run. */ return EXIT_SUCCESS; }
int main(void) { /* This example shows the use of the fast polynomial transform to evaluate a * finite expansion in Legendre polynomials, * * f(x) = a_0 P_0(x) + a_1 P_1(x) + ... + a_N P_N(x) (1) * * at the Chebyshev nodes x_j = cos(j*pi/N), j=0,1,...,N. */ const int N = 8; /* An fpt_set is a data structure that contains precomputed data for a number * of different polynomial transforms. Here, we need only one transform. the * second parameter (t) is the exponent of the maximum transform size desired * (2^t), i.e., t = 3 means that N in (1) can be at most N = 8. */ fpt_set set = fpt_init(1,lrint(ceil(log2((double)N))),0U); /* Three-term recurrence coefficients for Legendre polynomials */ double *alpha = malloc((N+2)*sizeof(double)), *beta = malloc((N+2)*sizeof(double)), *gamma = malloc((N+2)*sizeof(double)); /* alpha[0] and beta[0] are not referenced. */ alpha[0] = beta[0] = 0.0; /* gamma[0] contains the value of P_0(x) (which is a constant). */ gamma[0] = 1.0; /* Actual three-term recurrence coefficients for Legendre polynomials */ { int k; for (k = 0; k <= N; k++) { alpha[k+1] = ((double)(2*k+1))/((double)(k+1)); beta[k+1] = 0.0; gamma[k+1] = -((double)(k))/((double)(k+1)); } } printf( "Computing a fast polynomial transform (FPT) and a fast discrete cosine \n" "transform (DCT) to evaluate\n\n" " f_j = a_0 P_0(x_j) + a_1 P_1(x_j) + ... + a_N P_N(x_j), j=0,1,...,N,\n\n" "with N=%d, x_j = cos(j*pi/N), j=0,1,...N, the Chebyshev nodes, a_k,\n" "k=0,1,...,N, random Fourier coefficients in [-1,1]x[-1,1]*I, and P_k,\n" "k=0,1,...,N, the Legendre polynomials.",N ); /* Random seed, makes things reproducible. */ nfft_srand48(314); /* The function fpt_repcompute actually does the precomputation for a single * transform. It needs arrays alpha, beta, and gamma, containing the three- * term recurrence coefficients, here of the Legendre polynomials. The format * is explained above. The sixth parameter (k_start) is where the index in the * linear combination (1) starts, here k_start=0. The seventh parameter * (kappa) is the threshold which has an influence on the accuracy of the fast * polynomial transform. Usually, kappa = 1000 is a good choice. */ fpt_precompute(set,0,alpha,beta,gamma,0,1000.0); { /* Arrays for Fourier coefficients and function values. */ double _Complex *a = malloc((N+1)*sizeof(double _Complex)); double _Complex *b = malloc((N+1)*sizeof(double _Complex)); double *f = malloc((N+1)*sizeof(double _Complex)); /* Plan for discrete cosine transform */ const int NP1 = N + 1; fftw_r2r_kind kind = FFTW_REDFT00; fftw_plan p = fftw_plan_many_r2r(1, &NP1, 1, (double*)b, NULL, 2, 1, (double*)f, NULL, 1, 1, &kind, 0U); /* random Fourier coefficients */ { int k; printf("\n2) Random Fourier coefficients a_k, k=0,1,...,N:\n"); for (k = 0; k <= N; k++) { a[k] = 2.0*X(drand48)() - 1.0; /* for debugging: use k+1 */ printf(" a_%-2d = %+5.3lE\n",k,creal(a[k])); } } /* fast polynomial transform */ fpt_trafo(set,0,a,b,N,0U); /* Renormalize coefficients b_j, j=1,2,...,N-1 owing to how FFTW defines a * DCT-I; see * http://www.fftw.org/fftw3_doc/1d-Real_002deven-DFTs-_0028DCTs_0029.html * for details */ { int j; for (j = 1; j < N; j++) b[j] *= 0.5; } /* discrete cosine transform */ fftw_execute(p); { int j; printf("\n3) Function values f_j, j=1,1,...,M:\n"); for (j = 0; j <= N; j++) printf(" f_%-2d = %+5.3lE\n",j,f[j]); } /* cleanup */ free(a); free(b); free(f); /* cleanup */ fftw_destroy_plan(p); } /* cleanup */ fpt_finalize(set); free(alpha); free(beta); free(gamma); return EXIT_SUCCESS; }