Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
c170119
Created empty class for L-BFGS Hessian model (conditional on LAPACK) …
cvanaret Apr 3, 2025
86acb44
Added function notify_accepted_iterate() in HessianModel and subclass…
cvanaret Apr 4, 2025
8406616
Added CMake flag WITH_LAPACK to control whether LAPACK is enabled or not
cvanaret Apr 4, 2025
b03b6be
Added class DenseMatrix that will be used LBFGSHessian
cvanaret Apr 4, 2025
bc5778d
Some progress on L-BFGS
cvanaret Apr 23, 2025
95494ca
Initialize the HessianModel with the dimensions of the Model + progre…
cvanaret Apr 23, 2025
76f389f
Progress in L-BFGS + added functional tests for LAPACK's rank-k update
cvanaret Apr 23, 2025
1fc0981
Moved HessianModel to ConstraintRelaxationStrategy: one for each phas…
cvanaret Apr 23, 2025
087a1ee
Introduced class AssembledLagrangianGradient (wrapper around Lagrangi…
cvanaret Apr 10, 2025
7324a3b
Removed OptimalityProblem (replaced by virtual OptimizationProblem)
cvanaret Apr 23, 2025
818a6e8
Minor changes
cvanaret Apr 23, 2025
926fda5
Removed unused #includes
cvanaret Apr 23, 2025
57fd7f4
Minor changes in LBFGS
cvanaret Apr 23, 2025
b04a5a7
Enabled LAPACK in Julia CI scripts
cvanaret Apr 25, 2025
e2be893
L-BFGS: allocate memory for all the matrices!
cvanaret Apr 25, 2025
959bb38
Explicitlt link LAPACK to GTest target
cvanaret Apr 26, 2025
56ceb7f
L-BFGS: computed the initial identity multiple. Added a DenseColumn c…
cvanaret Apr 28, 2025
f30cee1
Complete computation of L-BFGS Hessian representation + added symobli…
cvanaret Apr 30, 2025
ffb0f22
L-BFGS: correct computation of initial_identity_multiple, now used to…
cvanaret May 1, 2025
74570c3
Made changes to DenseMatrix and DenseColumn so that a column can be o…
cvanaret May 3, 2025
a523de8
Draft of functional L-BFGS with Hessian-vector products
cvanaret May 6, 2025
444358c
L-BFGS seems to be working on small instances (QP Cornell, hs015, hs0…
cvanaret May 6, 2025
4364277
Added an option for the placement of the statistics column "QN |memory|"
cvanaret May 7, 2025
0c88b34
Cleaned up HessianModelFactory
cvanaret May 7, 2025
32e2dee
Added optional fixed objective multiplier in LBFGSHessian. Variable c…
cvanaret May 7, 2025
9f67488
When fixed objective multiplier in LBFGSHessian, compute Lag gradient…
cvanaret May 8, 2025
1b88a37
Improved the name of the strategy combination
cvanaret May 14, 2025
21f8947
Minor changes
cvanaret May 14, 2025
346f1d4
Fixed errors after merge + wrote dot() function taking a double* as s…
cvanaret Jul 31, 2025
8fb70a2
BQPD: call problem.number_hessian_nonzeros() only if the problem has …
cvanaret Aug 5, 2025
ad48445
Fixes after rebasing
cvanaret Sep 24, 2025
80baffd
Compiles but is broken, since we now need the inequality handling str…
cvanaret Sep 24, 2025
ccd23e7
Minor changes
cvanaret Oct 1, 2025
ca2466d
Added option quasi_newton_memory_size
cvanaret Oct 23, 2025
9ecad4d
Removed empty HessianModel::initialize()
cvanaret Oct 26, 2025
2426396
Initialize the statistics of HessianModel
cvanaret Nov 13, 2025
0ec4404
Minor changes
cvanaret Nov 13, 2025
1f0a3d5
Fix after rebasing
cvanaret Nov 17, 2025
62e8af0
Set statistics column |BFGS| (size of L-BFGS limited memory) at each …
cvanaret Nov 17, 2025
97a2d66
Removed unused member
cvanaret Nov 17, 2025
e960a8b
Fix after rebasing
cvanaret Nov 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/julia/build_tarballs_release.jl
Original file line number Diff line number Diff line change
Expand Up @@ -167,4 +167,4 @@ build_tarballs(
julia_compat = "1.6",
preferred_gcc_version = v"10.2.0",
clang_use_lld=false,
)
)
2 changes: 1 addition & 1 deletion .github/julia/build_tarballs_yggdrasil.jl
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,4 @@ build_tarballs(
julia_compat = "1.9",
preferred_gcc_version = v"10.2.0",
clang_use_lld=false,
)
)
20 changes: 19 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ find_library(HSL hsl)
find_library(MA57 ma57)
find_library(MA27 ma27)
find_library(BQPD bqpd)
if(HSL OR MA57 OR MA27 OR BQPD)
option(WITH_LAPACK "Enable LAPACK" OFF)
find_package(LAPACK)
if(HSL OR MA57 OR MA27 OR BQPD OR (WITH_LAPACK AND LAPACK_FOUND))
message(STATUS "Fortran compiler required")
enable_language(Fortran)
include(FortranCInterface)
Expand Down Expand Up @@ -89,6 +91,7 @@ file(GLOB TESTS_UNO_SOURCE_FILES
unotest/unit_tests/ConcatenationTests.cpp
unotest/unit_tests/COOSparseStorageTests.cpp
unotest/unit_tests/CSCSparseStorageTests.cpp
unotest/unit_tests/DenseMatrixTests.cpp
unotest/unit_tests/RangeTests.cpp
unotest/unit_tests/ScalarMultipleTests.cpp
unotest/unit_tests/SparseVectorTests.cpp
Expand All @@ -101,6 +104,7 @@ file(GLOB TESTS_UNO_SOURCE_FILES
# external dependencies #
#########################
set(LIBRARIES "")
set(TEST_LIBRARIES "")

# function that links an existing library to Uno
function(link_to_uno library_name library_path)
Expand Down Expand Up @@ -144,6 +148,20 @@ if(HSL OR MA27)
list(APPEND LIBRARIES ${BLAS_LIBRARIES})
endif()

# LAPACK
if(WITH_LAPACK)
find_package(LAPACK)
if(NOT LAPACK_FOUND)
message(WARNING "Optional library LAPACK was not found.")
else()
link_to_uno(LAPACK ${LAPACK_LIBRARIES})
set(TEST_LIBRARIES ${TEST_LIBRARIES} ${LAPACK_LIBRARIES})
# enable the use of quasi-Newton methods
list(APPEND UNO_SOURCE_FILES uno/ingredients/hessian_models/quasi_newton/LBFGSHessian.cpp)
list(APPEND TESTS_UNO_SOURCE_FILES unotest/functional_tests/LAPACKTests.cpp)
endif()
endif()

# METIS
find_library(METIS metis)
if(METIS)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ namespace uno {
optimality_problem(model),
// relax the linear constraints in the l1 relaxed problem only if we are using a trust-region constraint
feasibility_problem(model, 0., this->constraint_violation_coefficient, use_trust_region),
optimality_hessian_model(HessianModelFactory::create(model, options)),
feasibility_hessian_model(HessianModelFactory::create(model, options)),
optimality_hessian_model(HessianModelFactory::create(model, 1., options)),
feasibility_hessian_model(HessianModelFactory::create(model, 0., options)),
optimality_inertia_correction_strategy(InertiaCorrectionStrategyFactory::create(options)),
feasibility_inertia_correction_strategy(InertiaCorrectionStrategyFactory::create(options)),
optimality_inequality_handling_method(InequalityHandlingMethodFactory::create(options)),
Expand Down Expand Up @@ -59,6 +59,8 @@ namespace uno {
this->optimality_inequality_handling_method->initialize_statistics(statistics);
this->feasibility_inertia_correction_strategy->initialize_statistics(statistics);
this->feasibility_inequality_handling_method->initialize_statistics(statistics);
this->optimality_hessian_model->initialize_statistics(statistics);
this->feasibility_hessian_model->initialize_statistics(statistics);
statistics.add_column("Phase", Statistics::int_width - 1, 3, Statistics::column_order.at("Phase"));
statistics.set("Phase", "OPT");

Expand Down Expand Up @@ -201,10 +203,16 @@ namespace uno {
if (this->current_phase == Phase::OPTIMALITY) {
accept_iterate = this->optimality_inequality_handling_method->is_iterate_acceptable(statistics,
*this->optimality_globalization_strategy, current_iterate, trial_iterate, direction, step_length, user_callbacks);
if (accept_iterate) {
this->optimality_hessian_model->notify_accepted_iterate(statistics, current_iterate, trial_iterate);
}
}
else {
accept_iterate = this->feasibility_inequality_handling_method->is_iterate_acceptable(statistics,
this->feasibility_globalization_strategy, current_iterate, trial_iterate, direction, step_length, user_callbacks);
if (accept_iterate) {
this->feasibility_hessian_model->notify_accepted_iterate(statistics, current_iterate, trial_iterate);
}
}
trial_iterate.status = this->check_termination(model, trial_iterate);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace uno {
ConstraintRelaxationStrategy(options),
problem(model),
inequality_handling_method(InequalityHandlingMethodFactory::create(options)),
hessian_model(HessianModelFactory::create(model, options)),
hessian_model(HessianModelFactory::create(model, 1., options)),
inertia_correction_strategy(InertiaCorrectionStrategyFactory::create(options)),
globalization_strategy(options) {
}
Expand All @@ -32,6 +32,7 @@ namespace uno {
// statistics
this->inertia_correction_strategy->initialize_statistics(statistics);
this->inequality_handling_method->initialize_statistics(statistics);
this->hessian_model->initialize_statistics(statistics);

// initial iterate
this->inequality_handling_method->generate_initial_iterate(initial_iterate);
Expand Down Expand Up @@ -69,6 +70,9 @@ namespace uno {
UserCallbacks& user_callbacks) {
const bool accept_iterate = this->inequality_handling_method->is_iterate_acceptable(statistics, this->globalization_strategy,
current_iterate, trial_iterate, direction, step_length, user_callbacks);
if (accept_iterate) {
this->hessian_model->notify_accepted_iterate(statistics, current_iterate, trial_iterate);
}
trial_iterate.status = this->check_termination(model, trial_iterate);
warmstart_information.no_changes();
return accept_iterate;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,4 @@ namespace uno {
std::string WaechterFilterMethod::get_name() const {
return "Waechter-filter";
}
} // namespace
} // namespace
6 changes: 6 additions & 0 deletions uno/ingredients/hessian_models/ExactHessian.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ namespace uno {
return false;
}

void ExactHessian::initialize_statistics(Statistics& /*statistics*/) const {
}

void ExactHessian::notify_accepted_iterate(Statistics& /*statistics*/, Iterate& /*current_iterate*/, Iterate& /*trial_iterate*/) {
}

void ExactHessian::evaluate_hessian(Statistics& /*statistics*/, const Vector<double>& primal_variables,
double objective_multiplier, const Vector<double>& constraint_multipliers, double* hessian_values) {
this->model.evaluate_lagrangian_hessian(primal_variables, objective_multiplier, constraint_multipliers, hessian_values);
Expand Down
3 changes: 3 additions & 0 deletions uno/ingredients/hessian_models/ExactHessian.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ namespace uno {
class ExactHessian : public HessianModel {
public:
explicit ExactHessian(const Model& model);
~ExactHessian() override = default;

[[nodiscard]] bool has_hessian_operator() const override;
[[nodiscard]] bool has_hessian_matrix() const override;
Expand All @@ -21,6 +22,8 @@ namespace uno {
void compute_sparsity(uno_int* row_indices, uno_int* column_indices, uno_int solver_indexing) const override;
[[nodiscard]] bool is_positive_definite() const override;

void initialize_statistics(Statistics& statistics) const override;
void notify_accepted_iterate(Statistics& statistics, Iterate& current_iterate, Iterate& trial_iterate) override;
void evaluate_hessian(Statistics& statistics, const Vector<double>& primal_variables, double objective_multiplier,
const Vector<double>& constraint_multipliers, double* hessian_values) override;
void compute_hessian_vector_product(const double* x, const double* vector, double objective_multiplier,
Expand Down
5 changes: 5 additions & 0 deletions uno/ingredients/hessian_models/HessianModel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@

namespace uno {
// forward declarations
class Iterate;
class Model;
class Options;
class Statistics;
template <typename ElementType>
class Vector;
Expand All @@ -31,6 +34,8 @@ namespace uno {
virtual void compute_sparsity(uno_int* row_indices, uno_int* column_indices, uno_int solver_indexing) const = 0;
[[nodiscard]] virtual bool is_positive_definite() const = 0;

virtual void initialize_statistics(Statistics& statistics) const = 0;
virtual void notify_accepted_iterate(Statistics& statistics, Iterate& current_iterate, Iterate& trial_iterate) = 0;
virtual void evaluate_hessian(Statistics& statistics, const Vector<double>& primal_variables,
double objective_multiplier, const Vector<double>& constraint_multipliers, double* hessian_values) = 0;
virtual void compute_hessian_vector_product(const double* x, const double* vector,
Expand Down
11 changes: 10 additions & 1 deletion uno/ingredients/hessian_models/HessianModelFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@
#include "ExactHessian.hpp"
#include "IdentityHessian.hpp"
#include "ZeroHessian.hpp"
#ifdef HAS_LAPACK
#include "quasi_newton/LBFGSHessian.hpp"
#endif
#include "model/Model.hpp"
#include "options/Options.hpp"
#include "tools/Logger.hpp"

namespace uno {
std::unique_ptr<HessianModel> HessianModelFactory::create(const Model& model, const Options& options) {
std::unique_ptr<HessianModel> HessianModelFactory::create(const Model& model, [[maybe_unused]] double objective_multiplier,
const Options& options) {
const std::string& hessian_model = options.get_string("hessian_model");
if (hessian_model == "exact") {
// if no Hessian (matrix or operator) is available, pick a zero Hessian
Expand All @@ -28,6 +32,11 @@ namespace uno {
else if (hessian_model == "identity") {
return std::make_unique<IdentityHessian>(model.number_variables);
}
#ifdef HAS_LAPACK
else if (hessian_model == "L-BFGS") {
return std::make_unique<LBFGSHessian>(model, objective_multiplier, options);
}
#endif
else if (hessian_model == "zero") {
return std::make_unique<ZeroHessian>(model.number_variables);
}
Expand Down
2 changes: 1 addition & 1 deletion uno/ingredients/hessian_models/HessianModelFactory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace uno {

class HessianModelFactory {
public:
static std::unique_ptr<HessianModel> create(const Model& model, const Options& options);
static std::unique_ptr<HessianModel> create(const Model& model, double objective_multiplier, const Options& options);
};
} // namespace

Expand Down
6 changes: 6 additions & 0 deletions uno/ingredients/hessian_models/IdentityHessian.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ namespace uno {
return true;
}

void IdentityHessian::initialize_statistics(Statistics& /*statistics*/) const {
}

void IdentityHessian::notify_accepted_iterate(Statistics& /*statistics*/, Iterate& /*current_iterate*/, Iterate& /*trial_iterate*/) {
}

void IdentityHessian::evaluate_hessian(Statistics& /*statistics*/, const Vector<double>& /*primal_variables*/,
double /*objective_multiplier*/, const Vector<double>& /*constraint_multipliers*/, double* hessian_values) {
DEBUG << "Setting identity Hessian\n";
Expand Down
2 changes: 2 additions & 0 deletions uno/ingredients/hessian_models/IdentityHessian.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ namespace uno {
void compute_sparsity(uno_int* row_indices, uno_int* column_indices, uno_int solver_indexing) const override;
[[nodiscard]] bool is_positive_definite() const override;

void initialize_statistics(Statistics& statistics) const override;
void notify_accepted_iterate(Statistics& statistics, Iterate& current_iterate, Iterate& trial_iterate) override;
void evaluate_hessian(Statistics& statistics, const Vector<double>& primal_variables,
double objective_multiplier, const Vector<double>& constraint_multipliers, double* hessian_values) override;
void compute_hessian_vector_product(const double* x, const double* vector, double objective_multiplier,
Expand Down
7 changes: 6 additions & 1 deletion uno/ingredients/hessian_models/ZeroHessian.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,14 @@ namespace uno {
return false;
}

void ZeroHessian::initialize_statistics(Statistics& /*statistics*/) const {
}

void ZeroHessian::notify_accepted_iterate(Statistics& /*statistics*/, Iterate& /*current_iterate*/, Iterate& /*trial_iterate*/) {
}

void ZeroHessian::evaluate_hessian(Statistics& /*statistics*/, const Vector<double>& /*primal_variables*/,
double /*objective_multiplier*/, const Vector<double>& /*constraint_multipliers*/, double* /*hessian_values*/) {
// do nothing
}

void ZeroHessian::compute_hessian_vector_product(const double* /*x*/, const double* /*vector*/,
Expand Down
3 changes: 3 additions & 0 deletions uno/ingredients/hessian_models/ZeroHessian.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace uno {
class ZeroHessian : public HessianModel {
public:
explicit ZeroHessian(size_t number_variables);
~ZeroHessian() override = default;

[[nodiscard]] bool has_hessian_operator() const override;
[[nodiscard]] bool has_hessian_matrix() const override;
Expand All @@ -18,6 +19,8 @@ namespace uno {
void compute_sparsity(uno_int* row_indices, uno_int* column_indices, uno_int solver_indexing) const override;
[[nodiscard]] bool is_positive_definite() const override;

void initialize_statistics(Statistics& statistics) const override;
void notify_accepted_iterate(Statistics& statistics, Iterate& current_iterate, Iterate& trial_iterate) override;
void evaluate_hessian(Statistics& statistics, const Vector<double>& primal_variables, double objective_multiplier,
const Vector<double>& constraint_multipliers, double* hessian_values) override;
void compute_hessian_vector_product(const double* x, const double* vector, double objective_multiplier,
Expand Down
Loading
Loading