/** \file error_estimator.hpp \brief define the function used to estimate the error boundaries of a fit \author Junhua Gu */ #ifndef ERROR_EST #define ERROR_EST #include #include #include #include #include #include #include namespace opt_utilities { template typename element_type_trait::element_type estimate_error_hessian(fitter& fit,const Tstr& pname,const Ts& dchi) { size_t porder=fit.get_param_order(pname); holder > h; try { h.reset(fit.get_param_modifier().clone()); } catch(const param_modifier_undefined&) { h.reset(0); } fit.clear_param_modifier(); Tp p=fit.get_all_params(); Ts a=hessian(fit.get_statistic(),p,porder,porder)/2; if(h.get()) { fit.set_param_modifier(*(h.get())); } fit.fit(); return std::sqrt(dchi/a); } /** \brief calculate the error boundary of a fit, according to the given delta statistic. \param fit the fitter that has a sucessful fit result \param pname the name of the parameter, the error of which will be estimated \param lower input as the initial value of the lower boundary, and output as the final result of the lower boundary \param upper input as the initial value of the upper boundary, and output as the final result of the upper boundary \param dchi the delta statistic corresponding to a certain confidence level \param precision determine how precise the error bounds should be determined */ template void estimate_error_directly(fitter& fit,const Tstr& pname,typename element_type_trait::element_type& lower,typename element_type_trait::element_type& upper,const Ts& dchi,const Ts& precision) { typedef typename element_type_trait::element_type Tpe; std::vector pnames; std::vector pvalues; //Make sure we start from an optimal parameter set fit.fit(); //stores origin parameter values for(int i=0;i* pfp=dynamic_cast*>(&fit.get_param_modifier()); if(pfp==0) { assert(0); } *pfp+=freeze_param(pname); } catch(const param_modifier_undefined&) { fit.set_param_modifier(freeze_param(pname)); } //get current statistic value Tpe current_value= fit.get_param_value(pname); //initial lower boundary should be a worse parameter, //so do the upper boundary if(lower>=current_value||upper<=current_value) { std::cerr<<"Error, initial lower and upper limits should be smaller and larger than the best fit value, respectively"<current_chi+dchi) { break; } upper+=step; } //perform the bi-search Ts target_chi=current_chi+dchi; while(upper-upper1>std::abs(precision)) { fit.set_param_value(pname,upper1); fit.fit(); Ts s1=fit.get_statistic_value(); fit.set_param_value(pname,upper); fit.fit(); Ts s=fit.get_statistic_value(); fit.set_param_value(pname,(upper+upper1)/2); fit.fit(); Ts s01=fit.get_statistic_value(); std::cerr<=0) { upper=(upper+upper1)/2; } else if((s1-target_chi)*(s01-target_chi)>0&&(s-target_chi)*(s01-target_chi)<=0) { upper1=(upper+upper1)/2; } else { std::cerr<<"strange statistic structure"<current_chi+dchi) { break; } lower-=step; } fit.set_param_value(pname,current_value); fit.fit(); while(lower1-lower>std::abs(precision)) { fit.set_param_value(pname,lower1); fit.fit(); Ts s1=fit.get_statistic_value(); fit.set_param_value(pname,lower); fit.fit(); Ts s=fit.get_statistic_value(); fit.set_param_value(pname,(lower+lower1)/2); fit.fit(); Ts s01=fit.get_statistic_value(); std::cerr<=0) { lower=(lower+lower1)/2; } else if((s1-target_chi)*(s01-target_chi)>0&&(s-target_chi)*(s01-target_chi)<=0) { lower1=(lower+lower1)/2; } else { std::cerr<<"strange statistic structure"<& >(fit.get_param_modifier())-=freeze_param(pname); //restore the origin param values for(int i=0;i void estimate_error(fitter& fit,const Tstr& pname,typename element_type_trait::element_type& lower,typename element_type_trait::element_type& upper,const Ts& dchi,const Ts& precision) { typename element_type_trait::element_type e=estimate_error_hessian(fit,pname,dchi); lower=fit.get_param_value(pname)-e*2; upper=fit.get_param_value(pname)+e*2; estimate_error_directly(fit,pname,lower,upper,dchi,precision); } } #endif //EOF