Skip to content

Commit b49beaa

Browse files
authored
Merge pull request #2666 from ERGO-Code/hipo-64
HiPO factorisation uses 64-bit integers
2 parents 8435cc4 + 5dc4550 commit b49beaa

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+863
-629
lines changed

cmake/sources.cmake

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ set(hipo_headers
205205
set(factor_highs_sources
206206
ipm/hipo/factorhighs/Analyse.cpp
207207
ipm/hipo/factorhighs/CallAndTimeBlas.cpp
208+
ipm/hipo/factorhighs/CliqueStack.cpp
208209
ipm/hipo/factorhighs/DataCollector.cpp
209210
ipm/hipo/factorhighs/DenseFactHybrid.cpp
210211
ipm/hipo/factorhighs/DenseFactKernel.cpp
@@ -218,12 +219,12 @@ set(factor_highs_sources
218219
ipm/hipo/factorhighs/Numeric.cpp
219220
ipm/hipo/factorhighs/SolveHandler.cpp
220221
ipm/hipo/factorhighs/Swaps.cpp
221-
ipm/hipo/factorhighs/SymScaling.cpp
222222
ipm/hipo/factorhighs/Symbolic.cpp)
223223

224224
set(factor_highs_headers
225225
ipm/hipo/factorhighs/Analyse.h
226226
ipm/hipo/factorhighs/CallAndTimeBlas.h
227+
ipm/hipo/factorhighs/CliqueStack.h
227228
ipm/hipo/factorhighs/DataCollector.h
228229
ipm/hipo/factorhighs/DenseFact.h
229230
ipm/hipo/factorhighs/DgemmParallel.h
@@ -238,17 +239,18 @@ set(factor_highs_headers
238239
ipm/hipo/factorhighs/ReturnValues.h
239240
ipm/hipo/factorhighs/SolveHandler.h
240241
ipm/hipo/factorhighs/Swaps.h
241-
ipm/hipo/factorhighs/SymScaling.h
242242
ipm/hipo/factorhighs/Symbolic.h
243243
ipm/hipo/factorhighs/Timing.h)
244244

245245
set(hipo_util_sources
246+
ipm/hipo/auxiliary/AutoDetect.cpp
246247
ipm/hipo/auxiliary/Auxiliary.cpp
247248
ipm/hipo/auxiliary/KrylovMethods.cpp
248249
ipm/hipo/auxiliary/Log.cpp
249250
ipm/hipo/auxiliary/VectorOperations.cpp)
250251

251252
set(hipo_util_headers
253+
ipm/hipo/auxiliary/AutoDetect.h
252254
ipm/hipo/auxiliary/Auxiliary.h
253255
ipm/hipo/auxiliary/IntConfig.h
254256
ipm/hipo/auxiliary/KrylovMethods.h

docs/src/installation.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ On Windows, do not forget to specify configuration type
5151
cmake --build build --config Release
5252
```
5353

54+
If you compile HiGHS with 64-bit integers (HIGHSINT64=ON), then Metis must also be compiled with 64-bit integers.
55+
5456
### HiPO
5557

5658
To install HiPO, on Linux and MacOS, run

highs/io/HighsIO.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <cstdarg>
1515
#include <cstdio>
1616

17+
#include "ipm/hipo/auxiliary/AutoDetect.h"
1718
#include "lp_data/HighsLp.h"
1819
#include "lp_data/HighsOptions.h"
1920

@@ -28,11 +29,20 @@ void highsLogHeader(const HighsLogOptions& log_options,
2829
githash_text.c_str(), kHighsCopyrightStatement.c_str());
2930

3031
#ifdef HIPO
32+
std::string blas_model =
33+
hipo::getIntegerModelString(hipo::getBlasIntegerModel());
34+
3135
#ifdef BLAS_LIBRARIES
32-
highsLogUser(log_options, HighsLogType::kInfo, "Using blas: %s\n",
33-
BLAS_LIBRARIES);
36+
highsLogUser(log_options, HighsLogType::kInfo, "Using BLAS: %s - %s\n",
37+
BLAS_LIBRARIES, blas_model.c_str());
38+
#else
39+
#ifdef HIPO_USES_OPENBLAS
40+
highsLogUser(log_options, HighsLogType::kInfo, "Using BLAS: OpenBLAS - %s\n",
41+
blas_model.c_str());
3442
#else
35-
highsLogUser(log_options, HighsLogType::kInfo, "Using blas: unknown\n");
43+
highsLogUser(log_options, HighsLogType::kInfo, "Using BLAS: unknown - %s\n",
44+
blas_model.c_str());
45+
#endif
3646
#endif
3747
#endif
3848
}

highs/ipm/IpxWrapper.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1521,9 +1521,9 @@ HighsStatus reportHipoStatus(const HighsOptions& options,
15211521
else if (status == hipo::kStatusError) {
15221522
highsLogUser(options.log_options, HighsLogType::kError,
15231523
"Hipo: Internal error\n");
1524-
} else if (status == hipo::kStatusOoM) {
1524+
} else if (status == hipo::kStatusOverflow) {
15251525
highsLogUser(options.log_options, HighsLogType::kError,
1526-
"Hipo: Out of memory\n");
1526+
"Hipo: Integer overflow\n");
15271527
} else if (status == hipo::kStatusErrorAnalyse) {
15281528
highsLogUser(options.log_options, HighsLogType::kError,
15291529
"Hipo: Error in analyse phase\n");
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
#include "AutoDetect.h"
2+
3+
#include <stdint.h>
4+
5+
// declare Metis with 32-bit integers for the test
6+
#define IDXTYPEWIDTH 32
7+
#include "metis.h"
8+
9+
// Weird tricks to detect the integer type width used by BLAS and Metis.
10+
// These are technically undefined behaviour, because they rely on using a
11+
// function declaration that involves a certain integer type, while the actual
12+
// implementation may use a different one. Their behaviour may depend on the
13+
// endianness of the CPU (?).
14+
15+
namespace hipo {
16+
17+
extern "C" {
18+
int64_t cblas_isamax(const int64_t N, const float* X, const int64_t incX);
19+
}
20+
IntegerModel getBlasIntegerModel() {
21+
// Test if BLAS uses 32-bit integers (LP64) or 64-bit integers (ILP64) at
22+
// runtime. Inspired by libblastrampoline's autodetection.c
23+
24+
// Even though isamax is declared to use 64-bit integers, it may actually
25+
// use 32-bit integers. If a negative number is passed as first argument,
26+
// isamax returns 0. If the correct value of 3 is passed, it returns 2
27+
// instead.
28+
29+
static IntegerModel blas_model = IntegerModel::not_set;
30+
31+
if (blas_model == IntegerModel::not_set) {
32+
// This is a very negative 64-bit number, but it is just 3 if only the lower
33+
// 32 bits are used.
34+
const int64_t n = 0xffffffff00000003;
35+
36+
const float X[3] = {1.0f, 2.0f, 3.0f};
37+
38+
const int64_t incx = 1;
39+
int64_t max_idx = cblas_isamax(n, X, incx);
40+
41+
// Ignore potential upper 32 bits of the result
42+
max_idx = max_idx & 0xffffffff;
43+
44+
if (max_idx == 0) {
45+
// isamax read negative n and returned 0, so it's using ilp64
46+
blas_model = IntegerModel::ilp64;
47+
48+
} else if (max_idx == 2) {
49+
// isamax read correct n and returned 2, so it's using lp64
50+
blas_model = IntegerModel::lp64;
51+
52+
} else {
53+
// something went wrong
54+
blas_model = IntegerModel::unknown;
55+
}
56+
}
57+
58+
return blas_model;
59+
}
60+
61+
std::string getIntegerModelString(IntegerModel i) {
62+
switch (i) {
63+
case IntegerModel::not_set:
64+
return "Not set";
65+
66+
case IntegerModel::unknown:
67+
return "Unknown";
68+
69+
case IntegerModel::lp64:
70+
return "LP64";
71+
72+
case IntegerModel::ilp64:
73+
return "ILP64";
74+
}
75+
}
76+
77+
IntegerModel getMetisIntegerModel() {
78+
static IntegerModel metis_model = IntegerModel::not_set;
79+
80+
if (metis_model == IntegerModel::not_set) {
81+
idx_t options[METIS_NOPTIONS];
82+
for (int i = 0; i < METIS_NOPTIONS; ++i) options[i] = -1;
83+
84+
// if 32 bits are used, this sets iptype to 2, otherwise it sets objtype to
85+
// a wrong value
86+
options[METIS_OPTION_IPTYPE] = 2;
87+
88+
idx_t n = 3;
89+
idx_t ptr[4] = {0, 2, 4, 6};
90+
idx_t rows[6] = {1, 2, 0, 2, 0, 1};
91+
idx_t perm[3], iperm[3];
92+
93+
idx_t status = METIS_NodeND(&n, ptr, rows, NULL, options, perm, iperm);
94+
95+
if (status == METIS_OK) {
96+
if (perm[0] != 0 || perm[1] != 1 || perm[2] != 2)
97+
metis_model = IntegerModel::unknown;
98+
else
99+
metis_model = IntegerModel::lp64;
100+
} else if (status == METIS_ERROR_INPUT) {
101+
metis_model = IntegerModel::ilp64;
102+
} else {
103+
metis_model = IntegerModel::unknown;
104+
}
105+
}
106+
107+
return metis_model;
108+
}
109+
} // namespace hipo
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#ifndef HIPO_AUTO_DETECT_H
2+
#define HIPO_AUTO_DETECT_H
3+
4+
#include <string>
5+
6+
namespace hipo {
7+
// Detect BLAS integer model
8+
enum class IntegerModel { not_set, unknown, lp64, ilp64 };
9+
IntegerModel getBlasIntegerModel();
10+
11+
// Detect Metis integer type
12+
IntegerModel getMetisIntegerModel();
13+
14+
std::string getIntegerModelString(IntegerModel i);
15+
16+
} // namespace hipo
17+
18+
#endif

highs/ipm/hipo/auxiliary/Auxiliary.cpp

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,6 @@
44

55
namespace hipo {
66

7-
void counts2Ptr(std::vector<Int>& ptr, std::vector<Int>& w) {
8-
// Given the column counts in the vector w (of size n),
9-
// compute the column pointers in the vector ptr (of size n+1),
10-
// and copy the first n pointers back into w.
11-
12-
Int temp_nz{};
13-
Int n = w.size();
14-
for (Int j = 0; j < n; ++j) {
15-
ptr[j] = temp_nz;
16-
temp_nz += w[j];
17-
w[j] = ptr[j];
18-
}
19-
ptr[n] = temp_nz;
20-
}
21-
227
void inversePerm(const std::vector<Int>& perm, std::vector<Int>& iperm) {
238
// Given the permutation perm, produce the inverse permutation iperm.
249
// perm[i] : i-th entry to use in the new order.
@@ -208,8 +193,8 @@ void processEdge(Int j, Int i, const std::vector<Int>& first,
208193
prevleaf[i] = j;
209194
}
210195

211-
double getDiagStart(Int n, Int k, Int nb, Int n_blocks, std::vector<Int>& start,
212-
bool triang) {
196+
Int64 getDiagStart(Int n, Int k, Int nb, Int n_blocks,
197+
std::vector<Int64>& start, bool triang) {
213198
// start position of diagonal blocks for blocked dense formats
214199
start.assign(n_blocks, 0);
215200
for (Int i = 1; i < n_blocks; ++i) {
@@ -218,8 +203,8 @@ double getDiagStart(Int n, Int k, Int nb, Int n_blocks, std::vector<Int>& start,
218203
}
219204

220205
Int jb = std::min(nb, k - (n_blocks - 1) * nb);
221-
double result = (double)start.back() + (double)(n - (n_blocks - 1) * nb) * jb;
222-
if (triang) result -= (double)jb * (jb - 1) / 2;
206+
Int64 result = start.back() + (Int64)(n - (n_blocks - 1) * nb) * jb;
207+
if (triang) result -= jb * (jb - 1) / 2;
223208
return result;
224209
}
225210

highs/ipm/hipo/auxiliary/Auxiliary.h

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
namespace hipo {
1313

14-
void counts2Ptr(std::vector<Int>& ptr, std::vector<Int>& w);
1514
void inversePerm(const std::vector<Int>& perm, std::vector<Int>& iperm);
1615
void subtreeSize(const std::vector<Int>& parent, std::vector<Int>& sizes);
1716
void transpose(const std::vector<Int>& ptr, const std::vector<Int>& rows,
@@ -27,8 +26,24 @@ void dfsPostorder(Int node, Int& start, std::vector<Int>& head,
2726
void processEdge(Int j, Int i, const std::vector<Int>& first,
2827
std::vector<Int>& maxfirst, std::vector<Int>& delta,
2928
std::vector<Int>& prevleaf, std::vector<Int>& ancestor);
30-
double getDiagStart(Int n, Int k, Int nb, Int n_blocks, std::vector<Int>& start,
31-
bool triang = false);
29+
Int64 getDiagStart(Int n, Int k, Int nb, Int n_blocks,
30+
std::vector<Int64>& start, bool triang = false);
31+
32+
template <typename T>
33+
void counts2Ptr(std::vector<T>& ptr, std::vector<T>& w) {
34+
// Given the column counts in the vector w (of size n),
35+
// compute the column pointers in the vector ptr (of size n+1),
36+
// and copy the first n pointers back into w.
37+
38+
T temp_nz{};
39+
T n = w.size();
40+
for (T j = 0; j < n; ++j) {
41+
ptr[j] = temp_nz;
42+
temp_nz += w[j];
43+
w[j] = ptr[j];
44+
}
45+
ptr[n] = temp_nz;
46+
}
3247

3348
template <typename T>
3449
void permuteVector(std::vector<T>& v, const std::vector<Int>& perm) {
Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,28 @@
11
#ifndef HIPO_INT_CONFIG_H
22
#define HIPO_INT_CONFIG_H
33

4-
#include "util/HighsInt.h"
54
#include "lp_data/HConst.h"
5+
#include "util/HighsInt.h"
66

77
namespace hipo {
88

9+
// Generic integer type from HiGHS
910
typedef HighsInt Int;
1011

11-
}
12+
// Integer type for factorisation
13+
typedef int64_t Int64;
14+
15+
// The matrix (AS or NE) is formed using Int, so it must have fewer than
16+
// kHighsIInf nonzero entries. Metis works with the same type as Int, so it must
17+
// be compiled accordingly.
18+
//
19+
// The factorisation uses a combination of Int and Int64. Int64 is used only
20+
// where needed, i.e. when dealing with nonzeros of the factor or when checking
21+
// overflows.
22+
// BLAS is 32-bit, so the vectors used by BLAS must be addressable with 32-bit
23+
// integers.
24+
//
25+
26+
} // namespace hipo
1227

1328
#endif

0 commit comments

Comments
 (0)