1 #ifndef NPSTAT_GRADIENTDESCENTFORNEYMANOSDE1D_HH_
2 #define NPSTAT_GRADIENTDESCENTFORNEYMANOSDE1D_HH_
31 template<
class ConvergenceCalculator>
32 inline NeymanOSDE1DResult gradientDescentForNeymanOSDE1D(
33 const NeymanOSDE1D& nosde,
34 const double* initialCoeffs,
const unsigned nCoeffs,
35 const double* shrinkages,
const unsigned nShrinkages,
36 const ConvergenceCalculator& conv,
const unsigned maxIterations)
39 const double armijoC = 0.5;
40 const double armijoTau = 0.5;
41 const unsigned maxLineIterations = 100;
43 std::vector<double> coeffs(initialCoeffs, initialCoeffs+nCoeffs);
44 std::vector<double> lineSearchCoeffs(nCoeffs);
45 std::vector<double> polyStats(nShrinkages);
46 std::vector<double> prevGradient(nCoeffs);
47 std::vector<double> currentGradient(nCoeffs);
48 std::vector<double> hessianEigenvalues(nCoeffs);
49 std::vector<double> step(nCoeffs);
50 std::vector<double> unitStep(nCoeffs);
51 std::vector<double> scales(nCoeffs);
52 Matrix<double> hessian(nCoeffs, nCoeffs);
53 SimpleScalarProduct<double> sp;
55 double prevChisq = nosde.chiSquare(&coeffs[0], nCoeffs,
56 shrinkages, nShrinkages,
57 &polyStats[0], &prevGradient[0],
59 bool converged =
false;
61 for (; iter<maxIterations && !converged; ++iter)
68 const double gradientNorm = std::sqrt(sp(&prevGradient[0], &prevGradient[0], nCoeffs));
69 assert(gradientNorm > 0.0);
70 for (
unsigned i=0; i<nCoeffs; ++i)
71 unitStep[i] = -prevGradient[i]*scales[i]/gradientNorm;
72 const double unitStepLen = std::sqrt(sp(&unitStep[0], &unitStep[0], nCoeffs));
73 assert(unitStepLen > 0.0);
74 for (
unsigned i=0; i<nCoeffs; ++i)
75 unitStep[i] = -prevGradient[i]/gradientNorm;
80 const double m = -gradientNorm;
81 double alpha = unitStepLen/armijoTau;
82 bool lineIterConverged =
false;
84 double lineChisq = 0.0;
85 for (; lit<maxLineIterations && !lineIterConverged; ++lit)
88 for (
unsigned i=0; i<nCoeffs; ++i)
90 step[i] = unitStep[i]*alpha;
91 lineSearchCoeffs[i] = coeffs[i] + step[i];
93 lineChisq = nosde.chiSquare(
94 &lineSearchCoeffs[0], nCoeffs, shrinkages, nShrinkages,
95 &polyStats[0], ¤tGradient[0],
nullptr);
96 lineIterConverged = lineChisq <= prevChisq + alpha*armijoC*m;
98 assert(lineIterConverged);
102 for (
unsigned i=0; i<nCoeffs; ++i)
103 coeffs[i] = lineSearchCoeffs[i];
104 const double currentChisq = nosde.chiSquare(&coeffs[0], nCoeffs,
105 shrinkages, nShrinkages,
106 &polyStats[0], ¤tGradient[0],
108 converged = conv.converged(iter, prevChisq, prevGradient, step,
109 currentChisq, currentGradient, hessian);
111 prevChisq = currentChisq;
112 std::swap(prevGradient, currentGradient);
115 return NeymanOSDE1DResult(coeffs, polyStats, prevChisq,
116 maxAbsValue(&prevGradient[0], prevGradient.size()),
117 NOSDE_GRADIENT_DESCENT, iter, converged,
false);
Class for representing results of the Neyman OSDE optimization algorithms.
OSDE based on minimizing the expected ISE of the empirical comparison density.
A simple code to calculate scalar products with unit weight function.
Maximum absolute value in an array.
Definition: AbsArrayProjector.hh:14
void scalesFromHessian(const Matrix< double > &hessian, double negativeScaleLimit, double *scales, unsigned nScales)
Make a guess about local function scales from the function Hessian.