File: TestHighsHessian.cpp

package info (click to toggle)
scipy 1.16.3-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 236,092 kB
  • sloc: cpp: 503,720; python: 345,302; ansic: 195,677; javascript: 89,566; fortran: 56,210; cs: 3,081; f90: 1,150; sh: 857; makefile: 792; pascal: 284; csh: 135; lisp: 134; xml: 56; perl: 51
file content (145 lines) | stat: -rw-r--r-- 5,703 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include "HCheckConfig.h"
#include "catch.hpp"
#include "lp_data/HighsOptions.h"
#include "model/HighsHessian.h"
#include "model/HighsHessianUtils.h"
// #include "<cstdio>"

const bool dev_run = false;

// No commas in test case name.
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;

  // Check that the positive diagonal entries are recognised as being
  // OK for default assessHessian (minimization) but not for
  // maximization.
  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();
  }

  // Check that the positive diagonal entries are recognised as being
  // OK for default assessHessian (minimization) but not for
  // maximization.
  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));

  // Extract the triangluar Hessian from the square Hessian
  REQUIRE(extractTriangularHessian(options, square_hessian) ==
          HighsStatus::kOk);
  if (dev_run) {
    printf("\nReturned triangularised square Hessian\n");
    square_hessian.print();
  }

  // Extract the triangluar Hessian from the triangular Hessian
  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));

  // Square Hessian with only triangular entries - doubled strictly triangular
  // entries.
  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));

  // Nonsymmetric Hessian - with entries resulting in cancellation
  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);
  // Check that there is one more entry due to the explicit zero
  REQUIRE(indefinite.numNz() == indefinite_num_nz0 + 1);
  // Check that all first indices are for the diagonal
  for (HighsInt iCol = 0; iCol < indefinite.dim_; iCol++) {
    const HighsInt iEl = indefinite.start_[iCol];
    REQUIRE(indefinite.index_[iEl] == iCol);
  }
  // Negate the diagonal entries
  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);
  // Can tell that the indefinite Hessian is not OK for minimization
  REQUIRE(!okHessianDiagonal(options, indefinite, ObjSense::kMinimize));
  // Cannot tell that the indefinite Hessian is not OK for
  // maximization since its diagonal entries are in [-4 0)
  REQUIRE(okHessianDiagonal(options, indefinite, ObjSense::kMaximize));
}