tinyopt
700
Tinyopt, a lightweight, header only optimization library
Toggle main menu visibility
Loading...
Searching...
No Matches
cg.h
1
// Copyright 2026 Julien Michot.
2
// SPDX-License-Identifier: Apache-2.0
3
4
#pragma once
5
6
#include <algorithm>
7
#include <limits>
8
9
#include <tinyopt/solvers/gd.h>
10
11
namespace
tinyopt::solvers {
12
13
template
<
typename
Gradient_t = VecX>
14
class
SolverCG :
public
SolverGD<Gradient_t> {
15
public
:
16
using
Base = SolverGD<Gradient_t>;
17
using
Scalar =
typename
Base::Scalar;
18
using
Grad_t =
typename
Base::Grad_t;
19
static
constexpr
Index Dims = Base::Dims;
20
static
constexpr
bool
IsNLLS =
false
;
21
static
constexpr
bool
FirstOrder =
true
;
22
23
explicit
SolverCG(
const
Options
&options = {}) : Base(options), step_size_(options.cg.step_size) {
24
// `Grad_t::Zero()` is invalid for dynamic sizes, so zero-initialize here instead
25
ResetDirection();
26
direction_.setZero();
27
}
28
29
void
reset() {
30
Base::reset
();
31
ResetDirection();
32
step_size_ = this->options_.cg.step_size;
33
}
34
35
template
<
typename
X_t,
typename
AccFunc>
36
bool
Build(
const
X_t &x,
const
AccFunc &acc,
bool
resize_and_clear =
true
) {
37
if
(!
Base::Build
(x, acc, resize_and_clear))
return
false
;
38
ResizeWorkspace();
39
40
Scalar beta = 0;
41
if
(has_previous_) {
42
const
Scalar denominator = previous_gradient_.squaredNorm();
43
if
(denominator > std::numeric_limits<Scalar>::epsilon()) {
44
beta = std::max<Scalar>(0, this->grad_.dot(this->grad_ - previous_gradient_) / denominator);
45
}
46
}
47
48
direction_ = -this->grad_ + beta * previous_direction_;
49
if
(this->grad_.dot(direction_) >= 0) direction_ = -this->grad_;
50
previous_gradient_ = this->grad_;
51
previous_direction_ = direction_;
52
has_previous_ =
true
;
53
return
true
;
54
}
55
56
std::optional<Vector<Scalar, Dims>>
Solve
()
const override
{
57
if
(!this->cost().isValid())
return
std::nullopt;
58
return
(step_size_ * direction_).eval();
59
}
60
61
void
BadStep(Scalar
/*quality*/
= 0)
override
{
62
step_size_ *= this->options_.cg.step_reduction;
63
ResetDirection();
64
}
65
66
private
:
67
void
ResizeWorkspace() {
68
if
(previous_gradient_.size() == this->grad_.size())
return
;
69
previous_gradient_.resize(this->grad_.size());
70
previous_direction_.resize(this->grad_.size());
71
previous_gradient_.setZero();
72
previous_direction_.setZero();
73
has_previous_ =
false
;
74
}
75
76
void
ResetDirection() {
77
previous_gradient_.setZero();
78
previous_direction_.setZero();
79
has_previous_ =
false
;
80
}
81
82
Grad_t previous_gradient_;
83
Grad_t previous_direction_;
84
Grad_t direction_;
85
Scalar step_size_;
86
bool
has_previous_ =
false
;
87
};
88
89
}
// namespace tinyopt::solvers
tinyopt::solvers::SolverCG::Solve
std::optional< Vector< Scalar, Dims > > Solve() const override
Solve the linear system dx = -H^-1 * grad, returns nullopt on failure.
Definition
cg.h:56
tinyopt::solvers::SolverGD< Gradient_t >::Build
bool Build(const X_t &x, const AccFunc &acc, bool resize_and_clear=true)
Definition
gd.h:116
tinyopt::solvers::SolverGD< Gradient_t >::reset
void reset()
Definition
gd.h:34
tinyopt::Options
Definition
options.h:18
include
tinyopt
solvers
cg.h
Generated by
1.18.0