#include "HCheckConfig.h"
#include "catch.hpp"
#include "lp_data/HighsOptions.h"
#include "model/HighsHessian.h"
#include "model/HighsHessianUtils.h"
const bool dev_run = false;
TEST_CASE("HighsHessian", "[highs_hessian]") {
HighsOptions options;
if (!dev_run) options.output_flag = false;
HighsHessian square_hessian;
square_hessian.dim_ = 5;
square_hessian.format_ = HessianFormat::kSquare;
square_hessian.start_ = {0, 4, 7, 9, 12, 15};
square_hessian.index_ = {0, 1, 3, 4, 0, 1, 4, 2, 3, 0, 2, 3, 0, 1, 4};
square_hessian.value_ = {5, 1, -1, 2, 1, 4, 1, 3, -1, -1, -1, 4, 2, 1, 5};
HighsHessian triangular_hessian;
triangular_hessian.dim_ = 5;
triangular_hessian.format_ = HessianFormat::kTriangular;
triangular_hessian.start_ = {0, 4, 6, 8, 9, 10};
triangular_hessian.index_ = {0, 1, 3, 4, 1, 4, 2, 3, 3, 4};
triangular_hessian.value_ = {5, 1, -1, 2, 4, 1, 3, -1, 4, 5};
HighsHessian triangular_hessian0 = triangular_hessian;
REQUIRE(assessHessian(square_hessian, options) == HighsStatus::kOk);
REQUIRE(okHessianDiagonal(options, square_hessian, ObjSense::kMinimize));
REQUIRE(!okHessianDiagonal(options, square_hessian, ObjSense::kMaximize));
if (dev_run) {
printf("\nReturned square Hessian\n");
square_hessian.print();
}
REQUIRE(assessHessian(triangular_hessian, options) == HighsStatus::kOk);
REQUIRE(okHessianDiagonal(options, square_hessian, ObjSense::kMinimize));
REQUIRE(!okHessianDiagonal(options, square_hessian, ObjSense::kMaximize));
if (dev_run) {
printf("\nReturned triangular Hessian\n");
triangular_hessian.print();
}
REQUIRE((triangular_hessian == triangular_hessian0));
REQUIRE(extractTriangularHessian(options, square_hessian) ==
HighsStatus::kOk);
if (dev_run) {
printf("\nReturned triangularised square Hessian\n");
square_hessian.print();
}
REQUIRE(extractTriangularHessian(options, triangular_hessian) ==
HighsStatus::kOk);
if (dev_run) {
printf("\nReturned triangularised triangular Hessian\n");
triangular_hessian.print();
}
HighsHessian negative_diagonal_hessian = triangular_hessian;
negative_diagonal_hessian.value_[0] = -negative_diagonal_hessian.value_[0];
negative_diagonal_hessian.value_[4] = -negative_diagonal_hessian.value_[4];
negative_diagonal_hessian.value_[6] = -negative_diagonal_hessian.value_[6];
negative_diagonal_hessian.value_[8] = -negative_diagonal_hessian.value_[8];
negative_diagonal_hessian.value_[9] = -negative_diagonal_hessian.value_[9];
REQUIRE(assessHessian(negative_diagonal_hessian, options) ==
HighsStatus::kOk);
REQUIRE(!okHessianDiagonal(options, negative_diagonal_hessian,
ObjSense::kMinimize));
REQUIRE(okHessianDiagonal(options, negative_diagonal_hessian,
ObjSense::kMaximize));
HighsHessian hessian0;
hessian0.dim_ = 5;
hessian0.format_ = HessianFormat::kSquare;
hessian0.start_ = {0, 1, 3, 4, 7, 10};
hessian0.index_ = {0, 0, 1, 2, 0, 2, 3, 0, 1, 4};
hessian0.value_ = {5, 2, 4, 3, -2, -2, 4, 4, 2, 5};
REQUIRE(assessHessian(hessian0, options) == HighsStatus::kOk);
if (dev_run) {
printf("\nReturned\n");
hessian0.print();
}
REQUIRE((hessian0 == triangular_hessian0));
HighsHessian hessian1;
hessian1.format_ = HessianFormat::kSquare;
hessian1.dim_ = 5;
hessian1.start_ = {0, 3, 5, 7, 10, 14};
hessian1.index_ = {0, 3, 4, 0, 1, 2, 4, 0, 2, 3, 0, 1, 2, 4};
hessian1.value_ = {5, -5, 1, 2, 4, 3, 1, 3, -2, 4, 3, 2, -1, 5};
REQUIRE(assessHessian(hessian1, options) == HighsStatus::kOk);
if (dev_run) {
printf("\nReturned\n");
hessian1.print();
}
REQUIRE((hessian1 == triangular_hessian0));
HighsHessian indefinite;
indefinite.dim_ = 3;
indefinite.format_ = HessianFormat::kTriangular;
indefinite.start_ = {0, 2, 2, 3};
indefinite.index_ = {0, 2, 2};
indefinite.value_ = {2, 1, 4};
HighsInt indefinite_num_nz0 = indefinite.numNz();
REQUIRE(assessHessian(indefinite, options) == HighsStatus::kOk);
REQUIRE(indefinite.numNz() == indefinite_num_nz0 + 1);
for (HighsInt iCol = 0; iCol < indefinite.dim_; iCol++) {
const HighsInt iEl = indefinite.start_[iCol];
REQUIRE(indefinite.index_[iEl] == iCol);
}
for (HighsInt iCol = 0; iCol < indefinite.dim_; iCol++) {
const HighsInt iEl = indefinite.start_[iCol];
indefinite.value_[iEl] = -indefinite.value_[iEl];
}
if (dev_run) {
printf("\nIndefinite\n");
indefinite.print();
}
REQUIRE(assessHessian(indefinite, options) == HighsStatus::kOk);
REQUIRE(!okHessianDiagonal(options, indefinite, ObjSense::kMinimize));
REQUIRE(okHessianDiagonal(options, indefinite, ObjSense::kMaximize));
}