#include #include #include #include "pcg-cpp/include/pcg_random.hpp" #include "randutils/randutils.hpp" template using Vector = Eigen::Matrix; template using Matrix = Eigen::Matrix; template class Model { private: Matrix A; Vector b; public: template Model(Real σ, unsigned N, unsigned M, Generator& r) : A(M, N), b(M) { std::normal_distribution aDistribution(0, 1 / sqrt(N)); for (unsigned i = 0; i < M; i++) { for (unsigned j =0; j < N; j++) { A(i, j) = aDistribution(r); } } std::normal_distribution bDistribution(0, σ); for (unsigned i = 0; i < M; i++) { b(i) = bDistribution(r); } } unsigned N() const { return A.cols(); } unsigned M() const { return A.rows(); } Vector V(const Vector& x) const { return A * x + b; } Matrix dV(const Vector& x) const { return A; } // const Real ddV(const Vector& x) { // return Matrix::Zero(; // } Real H(const Vector& x) const { return V(x).squaredNorm(); } Vector dH(const Vector& x) const { return dV(x).transpose() * V(x); } Matrix ddH(const Vector& x) const { return dV(x).transpose() * dV(x); } Vector ∇H(const Vector& x) const { return dH(x) - dH(x).dot(x) * x / x.squaredNorm(); } Matrix HessH(const Vector& x) const { Matrix hess = ddH(x) - x.dot(dH(x)) * Matrix::Identity(N(), N()); return hess - (hess * x) * x.transpose() / x.squaredNorm(); } Vector HessSpectrum(const Vector& x) const { Eigen::EigenSolver> eigenS(HessH(x)); return eigenS.eigenvalues().real(); } }; template Vector normalize(const Eigen::MatrixBase& z) { return z * sqrt((double)z.size() / (typename Derived::Scalar)(z.transpose() * z)); } template Vector findMinimum(const Model& M, const Vector& x0, Real ε) { Vector x = x0; Real λ = 100; Real H = M.H(x); Vector dH = M.dH(x); Matrix ddH = M.ddH(x); Vector g = dH - x.dot(dH) * x / x.squaredNorm(); Matrix m = ddH - (dH * x.transpose() + x.dot(dH) * Matrix::Identity(M.N(), M.N()) + (ddH * x) * x.transpose()) / x.squaredNorm() + 2.0 * x * x.transpose(); while (g.norm() / x.size() > ε && λ < 1e8) { Vector dz = (m + λ * (Matrix)abs(m.diagonal().array()).matrix().asDiagonal()).partialPivLu().solve(g); dz -= x.dot(dz) * x / x.squaredNorm(); Vector zNew = normalize(x - dz); Real HNew = M.H(zNew); Vector dHNew = M.dH(zNew); Matrix ddHNew = M.ddH(zNew); if (HNew * 1.0001 <= H) { x = zNew; H = HNew; dH = dHNew; ddH = ddHNew; g = dH - x.dot(dH) * x / (Real)x.size(); m = ddH - (dH * x.transpose() + x.dot(dH) * Matrix::Identity(x.size(), x.size()) + (ddH * x) * x.transpose()) / (Real)x.size() + 2.0 * x * x.transpose(); λ /= 2; } else { λ *= 1.5; } } return x; } using Rng = randutils::random_generator; using Real = double; int main(int argc, char* argv[]) { unsigned N = 10; Real α = 1; Real σ = 1; int opt; while ((opt = getopt(argc, argv, "N:a:s:")) != -1) { switch (opt) { case 'N': N = (unsigned)atof(optarg); break; case 'a': α = atof(optarg); break; case 's': σ = atof(optarg); break; default: exit(1); } } unsigned M = (unsigned)(α * N); Rng r; Model leastSquares(σ, N, M, r.engine()); Vector x = Vector::Zero(N); x(0) = sqrt(N); std::cout << leastSquares.H(x) / N << std::endl; Vector xMin = findMinimum(leastSquares, x, 1e-12); std::cout << leastSquares.H(xMin) / N << std::endl; std::cout << leastSquares.HessSpectrum(xMin)(1) / N << std::endl; return 0; }