16double f_alpha(
double alphabar,
double lambda = 1.)
18 return 1-exp( -lambda*alphabar);
20double finv_alpha(
double alpha,
double lambda = 1.)
22 return - log( 1. -
alpha)/lambda;
24double df_alpha(
double alphabar,
double lambda = 1)
26 return lambda*exp( -alphabar*lambda);
28double ddf_alpha(
double alphabar,
double lambda = 1)
30 return -lambda*lambda*exp( -alphabar*lambda);
39std::pair<std::vector<thrust::complex<double>>,std::vector<thrust::complex<double>>>
40 weights_and_nodes_talbot(
unsigned N,
const std::vector<double>& params)
42 thrust::complex<double> I( 0,1);
43 double h =
M_PI/(double)N;
45 std::vector<thrust::complex<double>> zk(N/2);
46 std::vector<thrust::complex<double>> wk(N/2);
47 double mu = params[0];
48 double sigma = params[1];
49 double nu = params[2];
50 double alphabar = params[3];
51 double alpha = f_alpha( alphabar);
53 for(
unsigned k=0; k<
n; k++)
55 double x = 2.0*h*k + h;
56 zk[k] = -(double)N*(-sigma +
mu*
x/tan(
alpha*
x) + nu*I*
x);
59 return std::make_pair( zk, wk);
62std::pair<std::vector<thrust::complex<double>>,std::vector<thrust::complex<double>>>
63 jacobian_talbot(
unsigned N,
const std::vector<double>& params)
65 thrust::complex<double> I( 0,1);
66 double h =
M_PI/(double)N;
68 std::vector<thrust::complex<double>> dzk(4*
n);
69 std::vector<thrust::complex<double>> dwk(4*
n);
70 double mu = params[0];
71 double alphabar = params[3];
72 double alpha = f_alpha( alphabar);
73 double dalpha = df_alpha( alphabar);
74 for(
unsigned k=0; k<
n; k++)
76 double Nc = (double)N;
77 double x = 2.0*h*k + h;
79 dzk[1*
n+k] = -Nc*(-1. );
80 dzk[2*
n+k] = -Nc*(I*
x);
90 return std::make_pair( dzk, dwk);
93std::vector<double> weights_and_nodes2params(
const
94std::pair<std::vector<thrust::complex<double>>,std::vector<thrust::complex<double>>>& zkwk)
96 const auto& zk = zkwk.first;
97 const auto& wk = zkwk.second;
98 std::vector<double> params( 4*zk.size());
99 unsigned n = zk.size();
100 for(
unsigned i=0; i<
n; i++)
102 params[0*
n+i] = zk[i].real();
103 params[1*
n+i] = zk[i].imag();
105 for(
unsigned i=0; i<
n; i++)
107 params[2*
n+i] = wk[i].real();
108 params[3*
n+i] = wk[i].imag();
115std::pair<std::vector<thrust::complex<double>>,std::vector<thrust::complex<double>>>
116 weights_and_nodes_identity(
unsigned N,
const std::vector<double>& params )
118 if( N != params.size()/2)
121 std::vector<thrust::complex<double>> zk(
n);
122 std::vector<thrust::complex<double>> wk(
n);
123 for(
unsigned i=0; i<
n; i++)
124 zk[i] = thrust::complex<double>(params[0*
n+i], params[1*
n+i]);
125 for(
unsigned i=0; i<
n; i++)
126 wk[i] = thrust::complex<double>(params[2*
n+i], params[3*
n+i]);
127 return std::make_pair( zk, wk);
129std::pair<std::vector<thrust::complex<double>>,std::vector<thrust::complex<double>>>
130 jacobian_identity(
unsigned N,
const std::vector<double>&)
133 std::vector<thrust::complex<double>> dzk(4*
n*
n, {0.});
134 std::vector<thrust::complex<double>> dwk(4*
n*
n, {0.});
135 for(
unsigned k=0; k<
n; k++)
137 dzk[(0*
n+k)*
n + k] = thrust::complex<double>(1,0);
138 dzk[(1*
n+k)*
n + k] = thrust::complex<double>(0,1);
139 dwk[(2*
n+k)*
n + k] = thrust::complex<double>(1,0);
140 dwk[(3*
n+k)*
n + k] = thrust::complex<double>(0,1);
142 return std::make_pair( dzk, dwk);
164struct LeastSquaresCauchyError
177 template<
class Generator,
class UnaryFunction>
178 LeastSquaresCauchyError(
unsigned N, Generator generate, UnaryFunction func,
const
179 std::vector<double>& rrs,
const std::vector<double>& lls,
unsigned order = 2):
180 m_N(N), m_func( func), m_generate(generate),
181 m_rrs(rrs), m_lls(lls), m_exact( lls.size()*rrs.size()),
182 m_func_rrs( N/2*rrs.size()), m_order(order)
186 for(
unsigned i=0; i<m_nl; i++)
187 for(
unsigned j=0; j<m_nr; j++)
188 m_exact[i*m_nr+j] = (func( thrust::complex<double>(m_lls[i]*m_rrs[j]))).real();
190 void result(
const std::vector<double>& params, std::vector<double>& result)
194 auto pair = m_generate( m_N, params);
195 const auto& zk = pair.first;
196 const auto& wk = pair.second;
197 unsigned n = zk.size();
199 for(
unsigned k=0; k<
n; k++)
200 for(
unsigned j=0; j<m_nr; j++)
201 m_func_rrs[k*m_nr + j] = wk[k]*m_func( m_rrs[j]*zk[k]);
202 for(
int k=
n-1; k>=0; k--)
203 for(
unsigned i=0; i<m_nl; i++)
204 for(
unsigned j=0; j<m_nr; j++)
205 result[i*m_nr+j]+= 2*(m_func_rrs[k*m_nr+j]/(zk[k]-m_lls[i])).real();
207 void error(
const std::vector<double>& params, std::vector<double>& err)
209 result( params, err);
212 void set_order (
unsigned order){
216 void operator()(
const std::vector<double>& params, std::vector<double>& res)
220 result( params, res);
232 unsigned m_N, m_nl, m_nr;
233 std::function<thrust::complex<double>(thrust::complex<double>)> m_func;
234 std::function<std::pair<std::vector<thrust::complex<double>>, std::vector<thrust::complex<double>>>(unsigned,
const std::vector<double>&)> m_generate;
235 std::vector<double> m_rrs, m_lls, m_exact;
236 std::vector<thrust::complex<double>> m_func_rrs;
237 unsigned m_order = 2;
241struct LeastSquaresCauchyJacobian
247 template<
class Generator,
class GeneratorJac,
class UnaryFunction,
class UnaryFunctionD>
248 LeastSquaresCauchyJacobian(
unsigned N, Generator generate, GeneratorJac generateJac,
249 UnaryFunction func, UnaryFunctionD dxfunc,
const std::vector<double>& rrs,
const std::vector<double>& lls,
unsigned order = 2):
250 m_N(N), m_func( func), m_dxfunc(dxfunc),
251 m_generate(generate), m_generateJac( generateJac),
252 m_rrs(rrs), m_lls(lls), m_exact( lls.size()*rrs.size()),
254 m_func_rrs(N/2*rrs.size()), m_order ( order)
258 for(
unsigned i=0; i<m_nl; i++)
259 for(
unsigned j=0; j<m_nr; j++)
260 m_exact[i*m_nr+j] = (func( thrust::complex<double>(m_lls[i]*m_rrs[j]))).real();
263 void set_order(
unsigned order) { m_order = order;}
264 void operator()(
const std::vector<double>& params, std::vector<std::vector<double>>& jac)
268 auto pair = m_generate( m_N, params);
269 const auto& zk = pair.first;
270 const auto& wk = pair.second;
271 auto Jacpair = m_generateJac( m_N, params);
272 const auto& dzk = Jacpair.first;
273 const auto& dwk = Jacpair.second;
274 unsigned n = zk.size();
279 for(
unsigned k=0; k<
n; k++)
280 for(
unsigned j=0; j<m_nr; j++)
281 m_func_rrs[k*m_nr+j] = wk[k]*m_func( m_rrs[j]*zk[k]);
282 for(
int k=
n-1; k>=0; k--)
283 for(
unsigned i=0; i<m_nl; i++)
284 for(
unsigned j=0; j<m_nr; j++)
285 m_result[i*m_nr+j]+= 2*(m_func_rrs[k*m_nr+j]/(zk[k] -m_lls[i] )).real();
290 std::vector<thrust::complex<double>> tmp( m_func_rrs.size());
292 for(
unsigned p=0; p<params.size(); p++)
294 for(
unsigned k=0; k<
n; k++)
295 for(
unsigned j=0; j<m_nr; j++)
296 tmp[k*m_nr+j] = wk[k]*m_rrs[j]*dzk[p*
n+k]*m_dxfunc(m_rrs[j]*zk[k]);
297 for(
int k=
n-1; k>=0; k--)
298 for(
unsigned i=0; i<m_nl; i++)
299 for(
unsigned j=0; j<m_nr; j++)
300 jac[p][i*m_nr+j]+= 2.*((m_func_rrs[k*m_nr+j]*(
301 dwk[p*
n+k]/wk[k]-dzk[p*
n+k]/(zk[k]-m_lls[i])) +
302 tmp[k*m_nr+j])/(zk[k] - m_lls[i])).real();
310 unsigned m_N, m_nl, m_nr;
311 std::function<thrust::complex<double>(thrust::complex<double>)> m_func, m_dxfunc;
312 std::function<std::pair<std::vector<thrust::complex<double>>, std::vector<thrust::complex<double>>>(unsigned,
const std::vector<double>&)> m_generate, m_generateJac;
313 std::vector<double> m_rrs, m_lls, m_exact, m_result;
314 std::vector<thrust::complex<double>> m_func_rrs;
315 unsigned m_order = 2;
318std::vector<double> generate_range(
double min,
double max,
unsigned per_order = 20,
bool with_zero =
false)
320 unsigned orders = unsigned (log10(max) - log10(min));
323 std::vector<double> range(orders*per_order);
324 unsigned N = range.size();
325 double h = (log10(max) - log10(min))/
double(N-1);
326 for(
unsigned i=0; i<N; i++)
327 range[i] = pow( 10.0, log10(min) + i*h);
329 range.insert( range.begin(), 0);
335template<
class ContainerType,
class UnaryFunc>
336void result_talbot(
unsigned N,
double rrs,
double lls,
337 const std::vector<ContainerType>& ps,
339 ContainerType& result)
342 double mu,
double sigma,
double nu,
double alphabar,
double& result)
344 thrust::complex<double> I( 0,1);
345 double h =
M_PI/(double)N;
348 double alpha = 1.-exp(-alphabar);
349 for(
int k=
n-1; k>=0; k--)
351 double x = 2*h*k + h;
352 double tanx = tan(
alpha*
x);
353 double sinx = sin(
alpha*
x);
354 thrust::complex<double> zk( -(
double)N*(-sigma +
mu*
x/tanx), -nu*
x*N);
355 thrust::complex<double> wk(-nu, (
mu/tanx -
mu*
x*
alpha/sinx/sinx));
356 result+= 2*(wk*func(rrs*zk)/(zk-lls)).real();
358 }, ps[0], ps[1], ps[2], ps[3], result);
361template<
class ContainerType,
class UnaryFunc>
362void error_talbot(
unsigned N,
const std::vector<double>& rrs,
const std::vector<double>& lls,
363 const std::vector<ContainerType>& ps,
365 ContainerType& error)
368 ContainerType tmp( error);
369 for(
unsigned i=0; i<lls.size();i++)
370 for(
unsigned j=0; j<rrs.size();j++)
372 result_talbot( N, rrs[j], lls[i], ps, f, tmp);
373 dg::blas1::plus( tmp, -f(thrust::complex<double>(lls[i]*rrs[j])).real());
381struct CauchyOptimizer
389 void set_verbose(
bool verbose) { m_verbose = verbose;}
412 template<
class UnaryFunc,
class UnaryFuncD>
413 const std::pair<std::vector<thrust::complex<double>>, std::vector<thrust::complex<double>>>& update_zkwk(
415 UnaryFunc func, UnaryFuncD dxfunc,
double lmin,
double lmax,
416 double dmin,
double dmax,
bool with_zero,
double eps = 1e-4)
420 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
423 double error_tolerance_factor = 10;
429 unsigned max_nodes = 36;
430 const unsigned order = 2;
433 auto rrs = dg::mat::generate_range( dmin, dmax, 20);
434 auto lls = dg::mat::generate_range( lmin, lmax, 20, with_zero );
435 std::vector<double> results( lls.size()*rrs.size());
437 unsigned n = m_zkwk.first.size();
438 dg::mat::LeastSquaresCauchyError
439 Icauchy( 2*
n, dg::mat::weights_and_nodes_identity, func, rrs, lls, order);
440 Icauchy.error( m_paramsI, results);
442 if( current_eps > 100*eps || current_eps < eps/error_tolerance_factor)
445 while( current_eps > eps &&
n < max_nodes )
448 dg::mat::LeastSquaresCauchyError
449 cauchy( 2*
n, dg::mat::weights_and_nodes_talbot, func, rrs, lls, order);
450 dg::mat::LeastSquaresCauchyJacobian
451 jac( 2*
n, dg::mat::weights_and_nodes_talbot, dg::mat::jacobian_talbot, func, dxfunc, rrs, lls, order);
457 DG_RANK0 std::cout <<
"# Current n "<<
n<<
"\n";
458 DG_RANK0 std::cout <<
"# Num steps in Levenberg Marquardt "<<steps<<
"\n";
459 cauchy.error( m_params, results);
461 DG_RANK0 std::cout <<
"# Talbot error "<<cauchy_error<<
" ";
462 DG_RANK0 std::cout <<
"# with params "<<m_params[0]<<
" "<<m_params[1]<<
" "<<m_params[2]<<
" "<<m_params[3]<<
"\n";
464 DG_RANK0 std::cout <<
"# Abs max error "<< abs_max<<
"\n";
468 dg::mat::LeastSquaresCauchyError
469 Icauchy( 2*
n, dg::mat::weights_and_nodes_identity, func, rrs, lls, order);
470 dg::mat::LeastSquaresCauchyJacobian
471 Ijac( 2*
n, dg::mat::weights_and_nodes_identity, dg::mat::jacobian_identity, func, dxfunc, rrs, lls, order);
473 auto zkwk = dg::mat::weights_and_nodes_talbot( 2*
n, m_params);
474 m_paramsI = dg::mat::weights_and_nodes2params( zkwk);
476 Icauchy.error( m_paramsI, results);
481 DG_RANK0 std::cout <<
"# Num steps in Levenberg Marquardt Id "<<stepsI<<
"\n";
482 DG_RANK0 std::cout <<
"# Cauchy I error "<<cauchy_error<<
"\n";
483 DG_RANK0 std::cout <<
"# Abs max I error "<<current_eps<<
"\n";
485 m_zkwk = dg::mat::weights_and_nodes_identity( 2*
n, m_paramsI);
492 throw dg::Error(
dg::Message(
_ping_)<<
"Error! Maximum number of nodes (36) reached! Tolerance "<<eps<<
" cannot be reached! Current eps "<<current_eps);
494 m_called_previously =
true;
497 unsigned num_nodes()
const {
return m_zkwk.first.size();}
500 m_called_previously =
false;
502 m_params = {0.5017,0.6122,0.2645,dg::mat::finv_alpha(0.6407)};
503 m_zkwk = dg::mat::weights_and_nodes_talbot( 2*2, m_params);
504 m_paramsI = dg::mat::weights_and_nodes2params( m_zkwk);
507 bool m_called_previously =
false;
508 std::vector<double> m_params, m_paramsI;
509 std::pair<std::vector<thrust::complex<double>>, std::vector<thrust::complex<double>>> m_zkwk;
510 bool m_verbose =
false;