43 std::optional<Vector<Scalar, Dims>>
Solve()
const override {
44 if (!this->cost().isValid())
return std::nullopt;
46 const auto &gradient = this->Gradient();
47 const Scalar gradient_norm2 = gradient.squaredNorm();
48 if (!std::isfinite(gradient_norm2))
return std::nullopt;
49 if (gradient_norm2 <= std::numeric_limits<Scalar>::epsilon()) {
50 pending_step_ =
false;
51 return Vector<Scalar, Dims>::Zero(gradient.size());
54 const auto gauss_newton =
55 tinyopt::SolveLinearSystem(this->
Hessian(), -gradient, this->options_.linear_solver,
56 this->options_.svd_relative_threshold);
57 const auto hessian_gradient = (this->
Hessian() * gradient).eval();
58 const Scalar curvature = gradient.dot(hessian_gradient);
59 Vector<Scalar, Dims> cauchy;
60 if (curvature > std::numeric_limits<Scalar>::epsilon())
61 cauchy = -(gradient_norm2 / curvature) * gradient;
63 cauchy = -(radius_ / std::sqrt(gradient_norm2)) * gradient;
65 Vector<Scalar, Dims> step;
66 bool on_boundary =
false;
67 if (gauss_newton && gauss_newton->norm() <= radius_) {
69 }
else if (cauchy.norm() >= radius_ || !gauss_newton) {
70 const Scalar cauchy_norm = cauchy.norm();
71 step = (radius_ / cauchy_norm) * cauchy;
74 const Vector<Scalar, Dims> difference = *gauss_newton - cauchy;
75 const Scalar a = difference.squaredNorm();
76 const Scalar b = Scalar(2) * cauchy.dot(difference);
77 const Scalar c = cauchy.squaredNorm() - radius_ * radius_;
78 const Scalar discriminant = std::max<Scalar>(0, b * b - Scalar(4) * a * c);
80 std::clamp((-b + std::sqrt(discriminant)) / (Scalar(2) * a), Scalar(0), Scalar(1));
81 step = cauchy + tau * difference;
85 const auto hessian_step = (this->
Hessian() * step).eval();
86 pending_prediction_ = -Scalar(2) * gradient.dot(step) - step.dot(hessian_step);
87 pending_cost_ = this->cost().cost;
88 pending_boundary_ = on_boundary;
89 pending_step_ = pending_prediction_ > 0 && std::isfinite(pending_prediction_);