Skip to content

Commit 58160a7

Browse files
authored
Merge pull request ERGO-Code#2258 from ERGO-Code/risc-v
Unit tests on Risc-V
2 parents f170db6 + d3f4958 commit 58160a7

File tree

3 files changed

+344
-303
lines changed

3 files changed

+344
-303
lines changed

check/CMakeLists.txt

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -88,19 +88,33 @@ if ((NOT FAST_BUILD OR ALL_TESTS) AND NOT (BUILD_EXTRA_UNIT_ONLY))
8888
TestThrow.cpp
8989
TestTspSolver.cpp
9090
TestUserScale.cpp
91-
Avgas.cpp
9291
TestSpecialLps.cpp
9392
TestLpSolvers.cpp
94-
TestMipSolver.cpp)
93+
TestMipSolver.cpp
94+
Avgas.cpp)
9595

96-
if (BUILD_EXTRA_UNIT_TESTS)
97-
list(APPEND CMAKE_MODULE_PATH "${HIGHS_SOURCE_DIR}/check/highs-unit-tests")
98-
message(STATUS "${HIGHS_SOURCE_DIR}/check/highs-unit-tests")
99-
include(highs-unit-tests)
96+
set(OPT_LEVEL_CHANGED OFF)
10097

101-
set(TEST_SOURCES ${TEST_SOURCES} ${HIGHS_EXTRA_UNIT_TESTS})
102-
message(STATUS ${TEST_SOURCES})
98+
if(CMAKE_CXX_FLAGS_RELEASE MATCHES "-O[0-9s]" AND NOT CMAKE_CXX_FLAGS_RELEASE MATCHES "-O3")
99+
# message(MESSAGE "User has overridden the default optimization level for Release mode.")
100+
set(OPT_LEVEL_CHANGED ON)
101+
endif()
102+
103+
if (LINUX AND NOT OPT_LEVEL_CHANGED AND CMAKE_CXX_COMPILER_ID STREQUAL "g++" AND CMAKE_SIZEOF_VOID_P EQUAL 8)
104+
if (NOT ((${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm64")) AND
105+
NOT (${CMAKE_SYSTEM_PROCESSOR} MATCHES "riscv(32|64)"))
106+
set(TEST_SOURCES ${TEST_SOURCES} TestLpSolversIterations.cpp)
103107
endif()
108+
endif()
109+
110+
if (BUILD_EXTRA_UNIT_TESTS)
111+
list(APPEND CMAKE_MODULE_PATH "${HIGHS_SOURCE_DIR}/check/highs-unit-tests")
112+
message(STATUS "${HIGHS_SOURCE_DIR}/check/highs-unit-tests")
113+
include(highs-unit-tests)
114+
115+
set(TEST_SOURCES ${TEST_SOURCES} ${HIGHS_EXTRA_UNIT_TESTS})
116+
message(STATUS ${TEST_SOURCES})
117+
endif()
104118

105119
add_executable(unit_tests ${TEST_SOURCES})
106120

@@ -217,6 +231,20 @@ if ((NOT FAST_BUILD OR ALL_TESTS) AND NOT (BUILD_EXTRA_UNIT_ONLY))
217231
"standmps\;218\; 1.4060175000\;"
218232
)
219233

234+
set(successRiscVInstances
235+
"25fv47\;3103\; 5.5018458\;"
236+
"80bau3b\;3705\; 9.8722419\;"
237+
"etamacro\;531\;-7.5571523\;"
238+
"greenbea\;5156\;-7.2555248\;"
239+
"stair\;531\;-2.5126695\;" # last like mac arm
240+
"adlittle\;74\; 2.2549496\;"
241+
"afiro\;22\;-4.6475314\;"
242+
"shell\;623\; 1.2088253\;"
243+
"standata\;72\; 1.2576995\;"
244+
"standgub\;68\; 1.2576995\;"
245+
"standmps\;218\; 1.4060175\;"
246+
)
247+
220248
set(infeasibleInstances
221249
"bgetam\; infeasible"
222250
"box1\; infeasible"
@@ -411,7 +439,10 @@ if ((NOT FAST_BUILD OR ALL_TESTS) AND NOT (BUILD_EXTRA_UNIT_ONLY))
411439
"Model status : ${solutionstatus}")
412440

413441
if(${solutionstatus} STREQUAL "Optimal")
414-
if(${setting} STREQUAL "--presolve=off" AND (NOT CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM"))
442+
if(${setting} STREQUAL "--presolve=off" AND
443+
(NOT CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM") AND
444+
(NOT OPT_LEVEL_CHANGED) AND
445+
(CMAKE_SIZEOF_VOID_P EQUAL 8))
415446
set_tests_properties (${name}${setting} PROPERTIES
416447
PASS_REGULAR_EXPRESSION
417448
"Simplex iterations: ${iter}\nObjective value : ${optval}")
@@ -428,6 +459,10 @@ if ((NOT FAST_BUILD OR ALL_TESTS) AND NOT (BUILD_EXTRA_UNIT_ONLY))
428459
# add tests for success and fail instances
429460
if (APPLE AND (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm64"))
430461
add_instancetests(successMacArmInstances "Optimal")
462+
elseif(LINUX AND ${CMAKE_SYSTEM_PROCESSOR} MATCHES "riscv(32|64)")
463+
if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "riscv64")
464+
add_instancetests(successRiscVInstances "Optimal")
465+
endif()
431466
else()
432467
add_instancetests(successInstances "Optimal")
433468
endif()

check/TestLpSolvers.cpp

Lines changed: 0 additions & 294 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,6 @@
44

55
const bool dev_run = false;
66

7-
struct IterationCount {
8-
HighsInt simplex;
9-
HighsInt ipm;
10-
HighsInt crossover;
11-
};
127

138
void testDualObjective(const std::string model) {
149
HighsStatus return_status;
@@ -30,295 +25,6 @@ void testDualObjective(const std::string model) {
3025
REQUIRE(relative_primal_dual_gap < 1e-12);
3126
}
3227

33-
void testSolver(Highs& highs, const std::string solver,
34-
IterationCount& default_iteration_count,
35-
const HighsInt int_simplex_strategy = 0) {
36-
double default_time_limit;
37-
HighsInt default_simplex_iteration_limit;
38-
HighsInt default_ipm_iteration_limit;
39-
HighsModelStatus model_status;
40-
HighsStatus return_status;
41-
const bool perform_timeout_test = false; // true; //
42-
bool use_simplex = solver == "simplex";
43-
const HighsInfo& info = highs.getInfo();
44-
45-
if (!dev_run) highs.setOptionValue("output_flag", false);
46-
return_status = highs.setOptionValue("solver", solver);
47-
REQUIRE(return_status == HighsStatus::kOk);
48-
49-
if (use_simplex) {
50-
SimplexStrategy simplex_strategy =
51-
static_cast<SimplexStrategy>(int_simplex_strategy);
52-
if (simplex_strategy == SimplexStrategy::kSimplexStrategyDualTasks) return;
53-
if (dev_run)
54-
printf("Simplex strategy %" HIGHSINT_FORMAT "\n", int_simplex_strategy);
55-
return_status = highs.setOptionValue("simplex_strategy", simplex_strategy);
56-
REQUIRE(return_status == HighsStatus::kOk);
57-
}
58-
59-
return_status = highs.getOptionValue("time_limit", default_time_limit);
60-
REQUIRE(return_status == HighsStatus::kOk);
61-
62-
if (use_simplex) {
63-
return_status = highs.getOptionValue("simplex_iteration_limit",
64-
default_simplex_iteration_limit);
65-
REQUIRE(return_status == HighsStatus::kOk);
66-
// Clear the solver information - necessary if this is the second
67-
// or subsequent call to testSolver
68-
return_status = highs.clearSolver();
69-
REQUIRE(return_status == HighsStatus::kOk);
70-
} else {
71-
return_status = highs.getOptionValue("ipm_iteration_limit",
72-
default_ipm_iteration_limit);
73-
REQUIRE(return_status == HighsStatus::kOk);
74-
}
75-
76-
// Vanilla solve: get solution time to calibrate time limit test
77-
double run_time = highs.getRunTime();
78-
return_status = highs.run();
79-
REQUIRE(return_status == HighsStatus::kOk);
80-
const double single_solve_run_time = highs.getRunTime() - run_time;
81-
82-
if (use_simplex) {
83-
REQUIRE(info.simplex_iteration_count == default_iteration_count.simplex);
84-
} else {
85-
if (dev_run)
86-
printf("IPM: %" HIGHSINT_FORMAT "; Crossover: %" HIGHSINT_FORMAT "\n",
87-
info.ipm_iteration_count, info.crossover_iteration_count);
88-
REQUIRE(info.ipm_iteration_count == default_iteration_count.ipm);
89-
REQUIRE(info.crossover_iteration_count ==
90-
default_iteration_count.crossover);
91-
}
92-
// Following simplex or IPM+Crossover, nonbasic variables are on bounds
93-
// complementarity_violation
94-
REQUIRE(info.max_complementarity_violation == 0);
95-
REQUIRE(info.sum_complementarity_violations == 0);
96-
97-
// Only perform the time limit test if the solve time is large enough
98-
const double min_run_time_for_test = 0.001;
99-
if (perform_timeout_test && single_solve_run_time > min_run_time_for_test) {
100-
const HighsInt ideal_num_solve = 10;
101-
const double local_time_limit = ideal_num_solve * single_solve_run_time;
102-
103-
// Solve with time limit
104-
run_time = highs.getRunTime();
105-
if (dev_run) printf("Current run time is %g\n", run_time);
106-
107-
double use_time_limit = run_time + local_time_limit;
108-
return_status = highs.setOptionValue("time_limit", use_time_limit);
109-
REQUIRE(return_status == HighsStatus::kOk);
110-
111-
const HighsInt max_num_solve = 10 * ideal_num_solve;
112-
HighsInt num_solve;
113-
for (num_solve = 0; num_solve < max_num_solve; num_solve++) {
114-
if (use_simplex) return_status = highs.setBasis();
115-
return_status = highs.run();
116-
if (highs.getModelStatus() == HighsModelStatus::kTimeLimit) break;
117-
}
118-
REQUIRE(num_solve < max_num_solve);
119-
run_time = highs.getRunTime();
120-
if (dev_run)
121-
printf("Current run time is %g: time limit is %g (difference = %g)\n",
122-
run_time, use_time_limit, run_time - use_time_limit);
123-
124-
if (dev_run)
125-
printf("Required %" HIGHSINT_FORMAT " solves (ideally %" HIGHSINT_FORMAT
126-
" - max %" HIGHSINT_FORMAT ")\n",
127-
num_solve, ideal_num_solve, max_num_solve);
128-
} else {
129-
if (dev_run)
130-
printf(
131-
"Not performed the time limit test since solve time is %g <= %g = "
132-
"min_run_time_for_test\n",
133-
single_solve_run_time, min_run_time_for_test);
134-
}
135-
return_status = highs.setOptionValue("time_limit", default_time_limit);
136-
REQUIRE(return_status == HighsStatus::kOk);
137-
if (!use_simplex) {
138-
if (dev_run)
139-
printf("IPM: %" HIGHSINT_FORMAT "; Crossover: %" HIGHSINT_FORMAT "\n",
140-
info.ipm_iteration_count, info.crossover_iteration_count);
141-
}
142-
// Solve with iteration limit
143-
// First of all check that no iterations are performed if the
144-
// iteration limit is zero
145-
if (use_simplex) {
146-
return_status = highs.setOptionValue("simplex_iteration_limit", 0);
147-
REQUIRE(return_status == HighsStatus::kOk);
148-
149-
return_status = highs.setBasis();
150-
REQUIRE(return_status == HighsStatus::kOk);
151-
} else {
152-
return_status = highs.setOptionValue("ipm_iteration_limit", 0);
153-
REQUIRE(return_status == HighsStatus::kOk);
154-
}
155-
156-
return_status = highs.run();
157-
model_status = highs.getModelStatus();
158-
if (dev_run)
159-
printf("Returns status = %" HIGHSINT_FORMAT "; model status = %s\n",
160-
(HighsInt)return_status,
161-
highs.modelStatusToString(model_status).c_str());
162-
REQUIRE(return_status == HighsStatus::kWarning);
163-
REQUIRE(model_status == HighsModelStatus::kIterationLimit);
164-
165-
if (use_simplex) {
166-
REQUIRE(info.simplex_iteration_count == 0);
167-
} else {
168-
REQUIRE(info.ipm_iteration_count == 0);
169-
}
170-
171-
// Now check that simplex/IPM stops after 10/5 iterations
172-
const HighsInt further_simplex_iterations = 10;
173-
const HighsInt further_ipm_iterations = 5;
174-
if (use_simplex) {
175-
if (dev_run)
176-
printf("Setting simplex_iteration_limit = %" HIGHSINT_FORMAT "\n",
177-
further_simplex_iterations);
178-
return_status = highs.setOptionValue("simplex_iteration_limit",
179-
further_simplex_iterations);
180-
REQUIRE(return_status == HighsStatus::kOk);
181-
return_status = highs.clearSolver();
182-
REQUIRE(return_status == HighsStatus::kOk);
183-
} else {
184-
if (dev_run)
185-
printf("Setting ipm_iteration_limit = %" HIGHSINT_FORMAT "\n",
186-
further_ipm_iterations);
187-
return_status =
188-
highs.setOptionValue("ipm_iteration_limit", further_ipm_iterations);
189-
REQUIRE(return_status == HighsStatus::kOk);
190-
}
191-
192-
return_status = highs.run();
193-
REQUIRE(return_status == HighsStatus::kWarning);
194-
REQUIRE(highs.getModelStatus() == HighsModelStatus::kIterationLimit);
195-
196-
if (use_simplex) {
197-
REQUIRE(info.simplex_iteration_count == further_simplex_iterations);
198-
return_status = highs.setOptionValue("simplex_iteration_limit",
199-
default_simplex_iteration_limit);
200-
REQUIRE(return_status == HighsStatus::kOk);
201-
} else {
202-
REQUIRE(info.ipm_iteration_count == further_ipm_iterations);
203-
return_status = highs.setOptionValue("ipm_iteration_limit",
204-
default_ipm_iteration_limit);
205-
REQUIRE(return_status == HighsStatus::kOk);
206-
}
207-
}
208-
209-
void testSolversSetup(const std::string model,
210-
IterationCount& model_iteration_count,
211-
vector<HighsInt>& simplex_strategy_iteration_count) {
212-
if (model.compare("adlittle") == 0) {
213-
simplex_strategy_iteration_count[(
214-
int)SimplexStrategy::kSimplexStrategyChoose] = 87;
215-
simplex_strategy_iteration_count[(
216-
int)SimplexStrategy::kSimplexStrategyDualPlain] = 87;
217-
simplex_strategy_iteration_count[(
218-
int)SimplexStrategy::kSimplexStrategyDualTasks] = 72;
219-
simplex_strategy_iteration_count[(
220-
int)SimplexStrategy::kSimplexStrategyDualMulti] = 73;
221-
simplex_strategy_iteration_count[(
222-
int)SimplexStrategy::kSimplexStrategyPrimal] = 94;
223-
model_iteration_count.ipm = 13;
224-
model_iteration_count.crossover = 2;
225-
}
226-
}
227-
228-
void testSolvers(Highs& highs, IterationCount& model_iteration_count,
229-
const vector<HighsInt>& simplex_strategy_iteration_count) {
230-
bool have_omp = true;
231-
232-
/*
233-
HighsInt i = (HighsInt)SimplexStrategy::kSimplexStrategyPrimal;
234-
model_iteration_count.simplex = simplex_strategy_iteration_count[i];
235-
testSolver(highs, "simplex", model_iteration_count, i);
236-
*/
237-
238-
HighsInt from_i = (HighsInt)SimplexStrategy::kSimplexStrategyMin;
239-
HighsInt to_i =
240-
(HighsInt)SimplexStrategy::kSimplexStrategyDualMulti; // PRIMAL; // NUM;
241-
for (HighsInt i = from_i; i < to_i; i++) {
242-
if (!have_omp) {
243-
if (i == (HighsInt)SimplexStrategy::kSimplexStrategyDualTasks) continue;
244-
if (i == (HighsInt)SimplexStrategy::kSimplexStrategyDualMulti) continue;
245-
}
246-
model_iteration_count.simplex = simplex_strategy_iteration_count[i];
247-
testSolver(highs, "simplex", model_iteration_count, i);
248-
}
249-
testSolver(highs, "ipm", model_iteration_count);
250-
}
251-
252-
// No commas in test case name.
253-
TEST_CASE("LP-solver", "[highs_lp_solver]") {
254-
std::string model;
255-
std::string model_file;
256-
IterationCount model_iteration_count;
257-
vector<HighsInt> simplex_strategy_iteration_count;
258-
simplex_strategy_iteration_count.resize(
259-
(HighsInt)SimplexStrategy::kSimplexStrategyNum);
260-
261-
HighsLp lp;
262-
// HighsStatus run_status;
263-
HighsStatus return_status;
264-
HighsStatus read_status;
265-
266-
Highs highs;
267-
if (!dev_run) highs.setOptionValue("output_flag", false);
268-
269-
// Read mps
270-
model = "adlittle";
271-
model_file = std::string(HIGHS_DIR) + "/check/instances/" + model + ".mps";
272-
testSolversSetup(model, model_iteration_count,
273-
simplex_strategy_iteration_count);
274-
275-
read_status = highs.readModel(model_file);
276-
REQUIRE(read_status == HighsStatus::kOk);
277-
278-
return_status = highs.setBasis();
279-
REQUIRE(return_status == HighsStatus::kOk);
280-
281-
return_status = highs.run();
282-
REQUIRE(return_status == HighsStatus::kOk);
283-
284-
testSolvers(highs, model_iteration_count, simplex_strategy_iteration_count);
285-
286-
// Now check that we can change model within the same Highs instance
287-
// First reset all the options to their default values
288-
return_status = highs.resetOptions();
289-
REQUIRE(return_status == HighsStatus::kOk);
290-
291-
if (!dev_run) highs.setOptionValue("output_flag", false);
292-
293-
model_file = std::string(HIGHS_DIR) + "/check/instances/etamacro.mps";
294-
read_status = highs.readModel(model_file);
295-
REQUIRE(read_status == HighsStatus::kOk);
296-
297-
return_status = highs.setBasis();
298-
REQUIRE(return_status == HighsStatus::kOk);
299-
300-
return_status = highs.run();
301-
REQUIRE(return_status == HighsStatus::kOk);
302-
303-
const HighsInfo& info = highs.getInfo();
304-
REQUIRE(info.num_dual_infeasibilities == 0);
305-
306-
// REQUIRE(info.simplex_iteration_count == 472); // differs on macOS
307-
308-
HighsModelStatus model_status = highs.getModelStatus();
309-
REQUIRE(model_status == HighsModelStatus::kOptimal);
310-
311-
// Test the solver without scaling
312-
REQUIRE(highs.readModel(model_file) == HighsStatus::kOk);
313-
REQUIRE(highs.setOptionValue("simplex_scale_strategy", 0) ==
314-
HighsStatus::kOk);
315-
316-
return_status = highs.run();
317-
REQUIRE(return_status == HighsStatus::kOk);
318-
319-
// REQUIRE(info.simplex_iteration_count == 592); // differs on macOS
320-
}
321-
32228
TEST_CASE("mip-with-lp-solver", "[highs_lp_solver]") {
32329
// When solving the relaxation of a MIP. Exposed #1406
32430
HighsStatus status;

0 commit comments

Comments
 (0)