std::vector<double> tb_lt_invert_Cpp_impl(double t, const std::vector<double>& lambda1, const std::vector<double>& lambda2, const std::vector<double>& lambda3, const int Ap1, const int Bp1, const int Cp1, const int direction, const int nblocks, const double tol, int& Lmax, ParallelizationScheme& scheme) { // auto start = std::chrono::steady_clock::now(); const double double_PI = 3.141592653589793238463, AA = 20.0; const int matsize = Ap1*Bp1*Cp1; std::vector<mytype::ComplexVector> ig; std::vector<double> res(matsize), yvec(matsize); for (int i=0; i<matsize; ++i) { yvec[i] = lambda1[i] + lambda2[i] + lambda3[i]; } ///////////////////////////////////////////////////////////// // The following code computes the inverse Laplace transform // Algorithm from Abate and Whitt using a Riemann sum // Levin tranform is used to accelerate the convergence ///////////////////////////////////////////////////////////// ig.resize(Lmax); scheme.for_each( boost::make_counting_iterator(0), boost::make_counting_iterator(Lmax), [&](int w) { mytype::ComplexNumber s(AA/(2*t),double_PI*(w+1)/t); ig[w].resize(matsize); tb_lt_Cpp(s,lambda1,lambda2,lambda3,Ap1,Bp1,Cp1,direction,yvec,ig[w]); }); mytype::ComplexNumber s(AA/(2*t),0.0); mytype::ComplexVector psum0(matsize); tb_lt_Cpp(s,lambda1,lambda2,lambda3,Ap1,Bp1,Cp1,direction,yvec,psum0); std::for_each(boost::make_counting_iterator(0), boost::make_counting_iterator(matsize), [&](int i) { Levin levin(tol); // A struct for Levin transform double term = 1e16, sdiff = 1e16; int k = 1; double psum = real(psum0[i])/(2*t); double sk,sk1; while ((std::abs(sdiff) > 1e-16)||(std::abs(term)>1e-3)) { double sgn = (k%2 == 0) ? 1.0 : -1.0; term = sgn*real(ig[k-1][i])/t; psum += term; double omega = k*term; sk = levin.next(psum,omega,1.0); if (k>1) sdiff = sk - sk1; k++; sk1 = sk; if (k > Lmax) { ig.resize(Lmax+nblocks); scheme.for_each( boost::make_counting_iterator(0), boost::make_counting_iterator(nblocks), [&](int w) { mytype::ComplexNumber s(AA/(2*t),double_PI*(w+Lmax+1)/t); ig[w+Lmax].resize(matsize); tb_lt_Cpp(s,lambda1,lambda2,lambda3,Ap1,Bp1,Cp1,direction,yvec,ig[w+Lmax]); }); Lmax += nblocks; } } res[i] = sk1*exp(AA/2); }); // Rcpp::Rcout << "Lmax: " << Lmax; // auto end = std::chrono::steady_clock::now(); // // using TimingUnits = std::chrono::microseconds; // Rcpp::Rcout << "Time: " << std::chrono::duration_cast<TimingUnits>(end - start).count() << std::endl; return(std::move(res)); }
/** * Maximum entropy estimate by autocorrelation method. Implements * Yule-Walker method. * * @param r * Vector of correlation coefficients. * @param n * Number of lags used by MEM algorithm. * @param nfft * Size of fft for display. * @param spect * REAL*4 array of length FFT_SIZE in which the spectrum is returned. * @param errmsg * ERROR_MESSAGE CHARACTER*130 variable containing error message if an * an error occurs, ' ' otherwise. * @param errmsg_s * Length of \p errmsg * @param aux * REAL*4 scratch array of length FFT_SIZE. * * @author David Harris * * @date December 28, 1984 Last Modified * */ void mem(float *r, int n, int nfft, float *spect, char *errmsg, int errmsg_s, float *aux) { int i; float scale; float *a, *reflct; float *A; float *const Aux = &aux[0] - 1; float *const R = &r[0] - 1; float *const Spect = &spect[0] - 1; UNUSED(errmsg_s); if((a = (float *)malloc(n*sizeof(float))) == NULL){ strcpy(errmsg, "error allocating memory--mem\n"); return; } if((reflct = (float *)malloc(n*sizeof(float))) == NULL){ strcpy(errmsg, "error allocating memory--mem\n"); free(a); return; } A = a-1; /* if( n > 100 ){ fstrncpy( errmsg, errmsg_s-1, "MEM *** Maximum order (100) exceeded ***" , 40 ); return; } */ /* Zero arrays * */ zero( spect, nfft ); zero( aux, nfft ); /* Invoke Levinson's recursion to compute prediction filter * */ levin( r, a, reflct, n ); /* Compute transfer function of prediction filter * */ for( i = 1; i <= n; i++ ) Spect[i] = A[i]; fft( spect, aux, nfft, -1 ); /* Spectral estimate is reciprocal of filter's power spectrum * * Scale factor is equal to prediction error * */ scale = 0.; for( i = 1; i <= n; i++ ) scale = scale + R[i]*A[i]; for( i = 1; i <= nfft; i++ ) Spect[i] = scale/(powi(Spect[i],2) + powi(Aux[i],2)); /* Bye * */ free(a); free(reflct); return; } /* end of function */