// ch13_linear_fit.cpp // Companion code for Chapter 13: Optimization and Data Fitting. // Standalone C++11; standard library only; console output without plotting. // Compile: c++ -std=c++11 -O2 -Wall -Wextra -pedantic ch13_linear_fit.cpp -o ch13_linear_fit // Edit the example settings in main(); routines above main() can be reused. // Fixed seeds reproduce runs with the same standard-library implementation. // Random distributions need not give identical sequences across compilers/languages. #include #include #include #include #include #include #include #include #include #include #include #include #include using Vec = std::vector; using Mat = std::vector; using Function = std::function; using ScalarFunction = std::function; const double pi = std::acos(-1.0); void require(bool condition, const std::string& message) { if (!condition) throw std::invalid_argument(message); } void finite_vector(const Vec& x) { require(!x.empty(), "A nonempty vector is required."); for (double v : x) require(std::isfinite(v), "Data must be finite."); } void check_bounds(const Vec& lo, const Vec& hi) { finite_vector(lo); finite_vector(hi); require(lo.size() == hi.size(), "Bounds must have matching dimensions."); for (std::size_t j=0; jlo[j] && std::isfinite(hi[j]-lo[j]), "Require finite upper > lower."); } double objective_value(double value) { require(std::isfinite(value), "Objective must return a finite real scalar."); return value; } double clip(double x, double lo, double hi) { return std::max(lo,std::min(hi,x)); } Vec linspace(double a, double b, int n) { require(n>=2, "Grid needs at least two points."); Vec x(n); for (int i=0; i uniform{0.0,1.0}; std::normal_distribution normal{0.0,1.0}; explicit Random(unsigned int seed) : engine(seed) {} double u() { return uniform(engine); } double z() { return normal(engine); } int index(int n) { return std::uniform_int_distribution(0,n-1)(engine); } }; struct Result { Vec point; double value=0.0; long long evaluations=0; int iterations=0; std::string status; }; void print_result(const Result& r) { std::cout << std::setprecision(12); for (std::size_t j=0; j=3 && y.size()==n, "Require matching x,y and at least three observations."); LineFit r; r.known_sigma=!sigma.empty(); Vec w(n,1.0); if (r.known_sigma) { finite_vector(sigma); require(sigma.size()==n, "One uncertainty per observation is required."); for (std::size_t i=0;i0, "Uncertainties must be positive."); w[i]=1/(sigma[i]*sigma[i]); require(std::isfinite(w[i]) && w[i]>0, "Numerically unusable weights."); } } double W=0,xb=0,yb=0; for (std::size_t i=0;i0, "Weight sum overflow."); xb/=W; yb/=W; double Sxx=0,Sxy=0; for (std::size_t i=0;i0 && std::isfinite(Sxy+xb+yb), "No usable x spread or data scaling."); r.slope=Sxy/Sxx; r.intercept=yb-r.slope*xb; r.dof=static_cast(n)-2; r.residuals.resize(n); for (std::size_t i=0;i::quiet_NaN(); for (Vec& row:r.covariance) for (double& a:row) a*=r.sse/r.dof; } r.standard_errors={std::sqrt(r.covariance[0][0]),std::sqrt(r.covariance[1][1])}; r.residual_std=std::sqrt(r.sse/r.dof); return r; } int main() { try { const unsigned int seed = 1; Random rng(seed); // Alternative: comment out the previous line and seed from system entropy. // Random rng(std::random_device{}()); Vec x=linspace(0,10,15), y(x.size()),sigma_y(x.size(),.5); for (std::size_t i=0;i