Skip to content

Commit 6add9b7

Browse files
committed
Fixed errors after merge + wrote dot() function taking a double* as second parameter
1 parent 79ad3bd commit 6add9b7

File tree

7 files changed

+43
-155
lines changed

7 files changed

+43
-155
lines changed

uno/ingredients/hessian_models/HessianModelFactory.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@
1414
#include "options/Options.hpp"
1515

1616
namespace uno {
17-
std::unique_ptr<HessianModel> HessianModelFactory::create([[maybe_unused]] std::optional<double> fixed_objective_multiplier,
18-
const Options& options) {
17+
std::unique_ptr<HessianModel> HessianModelFactory::create(double objective_multiplier, const Options& options) {
1918
const std::string& hessian_model = options.get_string("hessian_model");
2019
if (hessian_model == "exact") {
2120
return std::make_unique<ExactHessian>();
@@ -25,7 +24,7 @@ namespace uno {
2524
}
2625
#ifdef HAS_LAPACK
2726
else if (hessian_model == "L-BFGS") {
28-
return std::make_unique<LBFGSHessian>(fixed_objective_multiplier, options);
27+
return std::make_unique<LBFGSHessian>(objective_multiplier, options);
2928
}
3029
#endif
3130
else if (hessian_model == "zero") {

uno/ingredients/hessian_models/HessianModelFactory.hpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
#define UNO_HESSIANMODELFACTORY_H
66

77
#include <memory>
8-
#include <optional>
98

109
namespace uno {
1110
// forward declarations
@@ -15,7 +14,7 @@ namespace uno {
1514

1615
class HessianModelFactory {
1716
public:
18-
static std::unique_ptr<HessianModel> create(std::optional<double> fixed_objective_multiplier, const Options& options);
17+
static std::unique_ptr<HessianModel> create(double fixed_objective_multiplier, const Options& options);
1918
};
2019
} // namespace
2120

uno/ingredients/hessian_models/quasi_newton/LBFGSHessian.cpp

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,16 @@
77
#include "linear_algebra/LAPACK.hpp"
88
#include "linear_algebra/SymmetricMatrix.hpp"
99
#include "optimization/Iterate.hpp"
10+
#include "optimization/OptimizationProblem.hpp"
1011
#include "symbolic/Expression.hpp"
1112
#include "symbolic/Range.hpp"
1213
#include "tools/Statistics.hpp"
1314

1415
namespace uno {
15-
LBFGSHessian::LBFGSHessian(std::optional<double> fixed_objective_multiplier, const Options& options):
16+
LBFGSHessian::LBFGSHessian(double objective_multiplier, const Options& options):
1617
HessianModel(),
17-
fixed_objective_multiplier(fixed_objective_multiplier),
18+
objective_multiplier(objective_multiplier),
1819
memory_size(options.get_unsigned_int("quasi_newton_memory_size")) {
19-
if (fixed_objective_multiplier.has_value()) {
20-
DEBUG << "L-BFGS Hessian model was declared with a fixed objective multiplier of " << *fixed_objective_multiplier << '\n';
21-
}
2220
}
2321

2422
bool LBFGSHessian::has_implicit_representation() const {
@@ -67,8 +65,11 @@ namespace uno {
6765

6866
// Hessian-vector product where the Hessian approximation is Bk = B0 - U U^T + V V^T and B0 = delta I
6967
// Bk v = (B0 - U U^T + V V^T) v = delta v - U U^T x + V V^T x
70-
void LBFGSHessian::compute_hessian_vector_product(const Model& model, const double* vector, double /*objective_multiplier*/,
68+
void LBFGSHessian::compute_hessian_vector_product(const Model& model, const double* vector, double objective_multiplier,
7169
const Vector<double>& /*constraint_multipliers*/, double* result) {
70+
assert(objective_multiplier == this->objective_multiplier &&
71+
"The L-BFGS Hessian model was initialized with a different objective multiplier");
72+
7273
if (this->hessian_recomputation_required) {
7374
this->recompute_hessian_representation();
7475
this->hessian_recomputation_required = false;
@@ -136,23 +137,21 @@ namespace uno {
136137
// fill the Y matrix: y = \nabla L(x_k, y_k, z_k) - \nabla L(x_{k-1}, y_k, z_k)
137138
void LBFGSHessian::update_Y_matrix(const Model& model, Iterate& current_iterate, Iterate& trial_iterate) {
138139
// evaluate Lagrangian gradients at the current and trial iterates, both with the trial multipliers
139-
// TODO objective multiplier is hardcoded for the moment
140-
if (this->fixed_objective_multiplier.has_value()) {
141-
current_iterate.evaluate_objective_gradient(model);
142-
current_iterate.evaluate_constraint_jacobian(model);
143-
trial_iterate.evaluate_objective_gradient(model);
144-
trial_iterate.evaluate_constraint_jacobian(model);
145-
// TODO preallocate
146-
Vector<double> current_lagrangian_gradient(this->dimension);
147-
Vector<double> trial_lagrangian_gradient(this->dimension);
148-
const double objective_multiplier = *this->fixed_objective_multiplier;
149-
model.evaluate_lagrangian_gradient(current_lagrangian_gradient, current_iterate, trial_iterate.multipliers, objective_multiplier);
150-
model.evaluate_lagrangian_gradient(trial_lagrangian_gradient, trial_iterate, trial_iterate.multipliers, objective_multiplier);
151-
this->Y_matrix.column(this->current_memory_slot) = trial_lagrangian_gradient - current_lagrangian_gradient;
152-
}
153-
else {
154-
throw std::runtime_error("LBFGSHessian::update_Y_matrix: the objective multiplier varies. This is not implemented yet");
155-
}
140+
current_iterate.evaluate_objective_gradient(model);
141+
current_iterate.evaluate_constraint_jacobian(model);
142+
trial_iterate.evaluate_objective_gradient(model);
143+
trial_iterate.evaluate_constraint_jacobian(model);
144+
// TODO preallocate
145+
LagrangianGradient<double> current_split_lagrangian_gradient(this->dimension);
146+
LagrangianGradient<double> trial_split_lagrangian_gradient(this->dimension);
147+
const OptimizationProblem problem{model};
148+
problem.evaluate_lagrangian_gradient(current_split_lagrangian_gradient, current_iterate, trial_iterate.multipliers);
149+
problem.evaluate_lagrangian_gradient(trial_split_lagrangian_gradient, trial_iterate, trial_iterate.multipliers);
150+
const auto current_lagrangian_gradient = this->objective_multiplier * current_split_lagrangian_gradient.objective_contribution
151+
+ current_split_lagrangian_gradient.constraints_contribution;
152+
const auto trial_lagrangian_gradient = this->objective_multiplier * trial_split_lagrangian_gradient.objective_contribution
153+
+ trial_split_lagrangian_gradient.constraints_contribution;
154+
this->Y_matrix.column(this->current_memory_slot) = trial_lagrangian_gradient - current_lagrangian_gradient;
156155
}
157156

158157
void LBFGSHessian::update_D_matrix() {

uno/ingredients/hessian_models/quasi_newton/LBFGSHessian.hpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
#ifndef UNO_LBFGSHESSIAN_H
55
#define UNO_LBFGSHESSIAN_H
66

7-
#include <optional>
87
#include <vector>
98
#include "../HessianModel.hpp"
109
#include "linear_algebra/DenseMatrix.hpp"
@@ -19,7 +18,7 @@ namespace uno {
1918
// J J^T = M = Sk^T B0 Sk + Lk Dk^(-1) Lk^T
2019
class LBFGSHessian: public HessianModel {
2120
public:
22-
LBFGSHessian(std::optional<double> fixed_objective_multiplier, const Options& options);
21+
LBFGSHessian(double objective_multiplier, const Options& options);
2322
~LBFGSHessian() override = default;
2423

2524
[[nodiscard]] bool has_implicit_representation() const override;
@@ -38,7 +37,7 @@ namespace uno {
3837

3938
protected:
4039
size_t dimension{};
41-
std::optional<double> fixed_objective_multiplier;
40+
const double objective_multiplier;
4241
const size_t memory_size; // user defined
4342
size_t number_entries_in_memory{0}; // 0 <= used_memory_size <= memory_size
4443
size_t current_memory_slot{0}; // 0 <= current_available_slot < memory_size

uno/model/Model.cpp

Lines changed: 2 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,16 @@
55
#include <utility>
66
#include "Model.hpp"
77
#include "linear_algebra/Vector.hpp"
8-
#include "optimization/Iterate.hpp"
9-
#include "optimization/LagrangianGradient.hpp"
10-
#include "optimization/Multipliers.hpp"
118

129
namespace uno {
10+
// abstract Problem class
1311
Model::Model(std::string name, size_t number_variables, size_t number_constraints, double objective_sign) :
1412
name(std::move(name)), number_variables(number_variables), number_constraints(number_constraints), objective_sign(objective_sign) {
1513
}
1614

1715
void Model::project_onto_variable_bounds(Vector<double>& x) const {
1816
for (size_t variable_index: Range(this->number_variables)) {
19-
x[variable_index] = std::max(std::min(x[variable_index], this->variable_upper_bound(variable_index)),
20-
this->variable_lower_bound(variable_index));
17+
x[variable_index] = std::max(std::min(x[variable_index], this->variable_upper_bound(variable_index)), this->variable_lower_bound(variable_index));
2118
}
2219
}
2320

@@ -31,54 +28,4 @@ namespace uno {
3128
const double upper_bound_violation = std::max(0., constraint_value - this->constraint_upper_bound(constraint_index));
3229
return std::max(lower_bound_violation, upper_bound_violation);
3330
}
34-
35-
void Model::evaluate_lagrangian_gradient(Vector<double>& lagrangian_gradient, const Iterate& iterate,
36-
const Multipliers& multipliers, double objective_multiplier) const {
37-
lagrangian_gradient.fill(0.);
38-
// compute and scale the objective contribution
39-
if (objective_multiplier != 0.) {
40-
this->evaluate_lagrangian_gradient_objective(lagrangian_gradient, iterate);
41-
lagrangian_gradient.scale(objective_multiplier);
42-
}
43-
// add the constraints contribution
44-
this->evaluate_lagrangian_gradient_constraints(lagrangian_gradient, iterate, multipliers);
45-
}
46-
47-
// Lagrangian gradient split in two parts: objective contribution and constraints' contribution
48-
void Model::evaluate_lagrangian_gradient(LagrangianGradient<double>& lagrangian_gradient, const Iterate& iterate,
49-
const Multipliers& multipliers) const {
50-
lagrangian_gradient.objective_contribution.fill(0.);
51-
lagrangian_gradient.constraints_contribution.fill(0.);
52-
this->evaluate_lagrangian_gradient_objective(lagrangian_gradient.objective_contribution, iterate);
53-
this->evaluate_lagrangian_gradient_constraints(lagrangian_gradient.constraints_contribution, iterate, multipliers);
54-
}
55-
56-
// protected member functions
57-
58-
// Lagrangian gradient split in two parts: objective contribution and constraints' contribution
59-
void Model::evaluate_lagrangian_gradient_objective(Vector<double>& objective_contribution, const Iterate& iterate) const {
60-
// objective gradient
61-
/*
62-
for (auto [variable_index, derivative]: iterate.evaluations.objective_gradient) {
63-
objective_contribution[variable_index] += derivative;
64-
}
65-
*/
66-
}
67-
68-
// Lagrangian gradient split in two parts: objective contribution and constraints' contribution
69-
void Model::evaluate_lagrangian_gradient_constraints(Vector<double>& constraints_contribution, const Iterate& iterate,
70-
const Multipliers& multipliers) const {
71-
// constraints
72-
for (size_t constraint_index: Range(this->number_constraints)) {
73-
if (multipliers.constraints[constraint_index] != 0.) {
74-
for (auto [variable_index, derivative]: iterate.evaluations.constraint_jacobian[constraint_index]) {
75-
constraints_contribution[variable_index] -= multipliers.constraints[constraint_index] * derivative;
76-
}
77-
}
78-
}
79-
// bound constraints
80-
for (size_t variable_index: Range(this->number_variables)) {
81-
constraints_contribution[variable_index] -= (multipliers.lower_bounds[variable_index] + multipliers.upper_bounds[variable_index]);
82-
}
83-
}
8431
} // namespace

uno/model/Model.hpp

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ namespace uno {
1515
template <typename ElementType>
1616
class Collection;
1717
template <typename ElementType>
18-
class LagrangianGradient;
19-
class Multipliers;
20-
template <typename ElementType>
2118
class RectangularMatrix;
2219
template <typename ElementType>
2320
class SparseVector;
@@ -88,16 +85,6 @@ namespace uno {
8885
[[nodiscard]] virtual double constraint_violation(double constraint_value, size_t constraint_index) const;
8986
template <typename Array>
9087
double constraint_violation(const Array& constraints, Norm residual_norm) const;
91-
92-
void evaluate_lagrangian_gradient(Vector<double>& lagrangian_gradient, const Iterate& iterate,
93-
const Multipliers& multipliers, double objective_multiplier) const;
94-
void evaluate_lagrangian_gradient(LagrangianGradient<double>& lagrangian_gradient, const Iterate& iterate,
95-
const Multipliers& multipliers) const;
96-
97-
protected:
98-
void evaluate_lagrangian_gradient_objective(Vector<double>& objective_contribution, const Iterate& iterate) const;
99-
void evaluate_lagrangian_gradient_constraints(Vector<double>& constraints_contribution, const Iterate& iterate,
100-
const Multipliers& multipliers) const;
10188
};
10289

10390
// compute ||c||
@@ -111,4 +98,4 @@ namespace uno {
11198
}
11299
} // namespace
113100

114-
#endif // UNO_MODEL_H
101+
#endif // UNO_MODEL_H

uno/optimization/LagrangianGradient.hpp

Lines changed: 13 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -8,57 +8,6 @@
88
#include "linear_algebra/Vector.hpp"
99

1010
namespace uno {
11-
// forward declaration
12-
template <typename ElementType>
13-
class LagrangianGradient;
14-
15-
// The LagrangianGradient class represents the dense Lagrangian gradient broken into:
16-
// - the objective contribution \nabla f(x_k)
17-
// - the constraint contribution -\nabla c(x_k) y_k - z_k
18-
// The two contributions can be assembled with a given objective multiplier \rho (see assemble(double)):
19-
// \rho \nabla f(x_k) - \nabla c(x_k) y_k - z_k
20-
// The resulting object, an AssembledLagrangianGradient, is a wrapper around the LagrangianGradient and \rho
21-
22-
template <typename ElementType>
23-
class AssembledLagrangianGradient {
24-
public:
25-
using value_type = ElementType;
26-
27-
AssembledLagrangianGradient(const LagrangianGradient<ElementType>& lagrangian_gradient, ElementType objective_multiplier);
28-
29-
[[nodiscard]] size_t size() const;
30-
[[nodiscard]] ElementType operator[](size_t variable_index) const;
31-
32-
protected:
33-
const LagrangianGradient<ElementType>& lagrangian_gradient;
34-
const ElementType objective_multiplier;
35-
};
36-
37-
template<typename ElementType>
38-
AssembledLagrangianGradient<ElementType>::AssembledLagrangianGradient(const LagrangianGradient<ElementType> &lagrangian_gradient,
39-
ElementType objective_multiplier): lagrangian_gradient(lagrangian_gradient), objective_multiplier(objective_multiplier) { }
40-
41-
template <typename ElementType>
42-
size_t AssembledLagrangianGradient<ElementType>::size() const {
43-
return this->lagrangian_gradient.size();
44-
}
45-
46-
// access i-th element
47-
template <typename ElementType>
48-
ElementType AssembledLagrangianGradient<ElementType>::operator[](size_t variable_index) const {
49-
return this->objective_multiplier * this->lagrangian_gradient.objective_contribution[variable_index] +
50-
this->lagrangian_gradient.constraints_contribution[variable_index];
51-
}
52-
53-
template <typename ElementType>
54-
std::ostream& operator<<(std::ostream& stream, const AssembledLagrangianGradient<ElementType>& gradient) {
55-
for (size_t variable_index: Range(gradient.size())) {
56-
stream << gradient[variable_index] << ' ';
57-
}
58-
stream << '\n';
59-
return stream;
60-
}
61-
6211
// Gradient of the Lagrangian
6312
// Keep the objective and constraint contributions separate. This helps:
6413
// - computing the KKT and FJ stationarity conditions
@@ -73,8 +22,8 @@ namespace uno {
7322

7423
explicit LagrangianGradient(size_t number_variables);
7524
[[nodiscard]] size_t size() const;
25+
[[nodiscard]] ElementType operator[](size_t variable_index) const;
7626
void resize(size_t number_variables);
77-
AssembledLagrangianGradient<ElementType> assemble(double objective_multiplier) const;
7827
};
7928

8029
template <typename ElementType>
@@ -88,16 +37,25 @@ namespace uno {
8837
return this->objective_contribution.size();
8938
}
9039

40+
// access i-th element
41+
template <typename ElementType>
42+
ElementType LagrangianGradient<ElementType>::operator[](size_t variable_index) const {
43+
return this->objective_contribution[variable_index] + this->constraints_contribution[variable_index];
44+
}
45+
9146
template <typename ElementType>
9247
void LagrangianGradient<ElementType>::resize(size_t number_variables) {
9348
this->objective_contribution.resize(number_variables);
9449
this->constraints_contribution.resize(number_variables);
9550
}
9651

9752
template <typename ElementType>
98-
AssembledLagrangianGradient<ElementType> LagrangianGradient<ElementType>::assemble(double objective_multiplier) const {
99-
// TODO use existing Expression
100-
return {*this, objective_multiplier};
53+
std::ostream& operator<<(std::ostream& stream, const LagrangianGradient<ElementType>& gradient) {
54+
for (size_t variable_index: Range(gradient.constraints_contribution.size())) {
55+
stream << gradient[variable_index] << ' ';
56+
}
57+
stream << '\n';
58+
return stream;
10159
}
10260
} // namespace
10361

0 commit comments

Comments
 (0)