Skip to content

Commit ca9daad

Browse files
authored
Merge pull request #2289 from ERGO-Code/features-doc-mods
Features doc mods
2 parents a179eb6 + e144a48 commit ca9daad

17 files changed

+109
-63
lines changed

FEATURES.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,12 @@ Fixed incorrect assertion in `HighsMipSolver::solutionFeasible()` (fixing [#2204
77
getColIntegrality now returns `HighsVarType::kContinuous` when `model_.lp_.integrality_` is empty (fixing [#2261](https://github.com/ERGO-Code/HiGHS/issues/2261))
88

99
Now ensuring that when solving a scaled LP with useful but unvalidated basis, it does not lose its scaling after validation, since the scaling factors will be applied to the solution (fixing [#2267](https://github.com/ERGO-Code/HiGHS/issues/2267))
10+
11+
By setting non-empty values of options `read_solution_file`, `read_basis_file`, `write_model_file` (with extension `.lp` or `.mps`), `write_solution_file`, `solution_file`, `write_basis_file`, these files will be read or written when calling `Highs::run()`. Hence options previously only available via the command line interface can be use (for example) by modelling languages that only call `Highs::run()` (fixing [#2269](https://github.com/ERGO-Code/HiGHS/issues/2269)).
12+
13+
Bug [#2273](https://github.com/ERGO-Code/HiGHS/issues/2273)) fixed
14+
15+
As part of [#2286](https://github.com/ERGO-Code/HiGHS/pull/2286)), the root of the HiGHS source files is now `highs/`, rather than `src/`
16+
17+
ZI rounding and shifting MIP primal heuristics have been added (see [#2287](https://github.com/ERGO-Code/HiGHS/pull/2287)). They are off by default, but can be activated by setting the options `mip_heuristic_run_zi_round` and `mip_heuristic_run_shifting` to be true. Options `mip_heuristic_run_rins`, `mip_heuristic_run_rens` and `mip_heuristic_run_root_reduced_cost` to run the RINS, RENS and rootReducedCost heuristics have been added. These are true by default, but setting them to be false can accelerate the MIP solver on easy problems.
18+

check/TestBasis.cpp

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,19 @@
55
#include "catch.hpp"
66

77
const bool dev_run = false;
8-
const std::string basis_file = "adlittle.bas";
98
HighsBasis basis_data;
109

11-
void testBasisReloadModel(Highs& highs, const bool from_file);
12-
void testBasisRestart(Highs& highs, const bool from_file);
10+
void testBasisReloadModel(Highs& highs, const std::string& basis_file,
11+
const bool from_file);
12+
void testBasisRestart(Highs& highs, const std::string& basis_file,
13+
const bool from_file);
1314

1415
// No commas in test case name.
1516
TEST_CASE("Basis-file", "[highs_basis_file]") {
17+
const std::string test_name = Catch::getResultCapture().getCurrentTestName();
18+
const std::string basis_file = test_name + ".bas";
19+
const std::string invalid_basis_file = test_name + "-Invalid.bas";
20+
1621
HighsStatus return_status;
1722
std::string model0_file =
1823
std::string(HIGHS_DIR) + "/check/instances/adlittle.mps";
@@ -38,7 +43,6 @@ TEST_CASE("Basis-file", "[highs_basis_file]") {
3843
REQUIRE(return_status == HighsStatus::kError);
3944

4045
// Check error return for some invalid basis files
41-
std::string invalid_basis_file = "InvalidBasis.bas";
4246
std::ofstream f;
4347
// Write and read a file for unsupported HiGHS version
4448
f.open(invalid_basis_file, std::ios::out);
@@ -64,14 +68,16 @@ TEST_CASE("Basis-file", "[highs_basis_file]") {
6468
return_status = highs.readBasis(invalid_basis_file);
6569
REQUIRE(return_status == HighsStatus::kError);
6670

67-
testBasisRestart(highs, true);
68-
testBasisReloadModel(highs, true);
71+
testBasisRestart(highs, basis_file, true);
72+
testBasisReloadModel(highs, basis_file, true);
6973

7074
std::remove(basis_file.c_str());
7175
std::remove(invalid_basis_file.c_str());
7276
}
7377

7478
TEST_CASE("Basis-data", "[highs_basis_data]") {
79+
const std::string test_name = Catch::getResultCapture().getCurrentTestName();
80+
const std::string basis_file = test_name + "adlittle.bas";
7581
HighsStatus return_status;
7682
std::string model0_file =
7783
std::string(HIGHS_DIR) + "/check/instances/adlittle.mps";
@@ -93,8 +99,8 @@ TEST_CASE("Basis-data", "[highs_basis_data]") {
9399
basis_data = highs.getBasis();
94100
REQUIRE(return_status == HighsStatus::kOk);
95101

96-
testBasisRestart(highs, false);
97-
testBasisReloadModel(highs, false);
102+
testBasisRestart(highs, basis_file, false);
103+
testBasisReloadModel(highs, basis_file, false);
98104
}
99105

100106
TEST_CASE("set-pathological-basis", "[highs_basis_data]") {
@@ -179,7 +185,8 @@ TEST_CASE("Basis-singular", "[highs_basis_data]") {
179185
}
180186

181187
// No commas in test case name.
182-
void testBasisReloadModel(Highs& highs, const bool from_file) {
188+
void testBasisReloadModel(Highs& highs, const std::string& basis_file,
189+
const bool from_file) {
183190
// Checks that no simplex iterations are required if a saved optimal
184191
// basis is used for the original LP after solving a different LP
185192
HighsStatus return_status;
@@ -227,7 +234,8 @@ void testBasisReloadModel(Highs& highs, const bool from_file) {
227234
REQUIRE(highs.getInfo().simplex_iteration_count == 0);
228235
}
229236

230-
void testBasisRestart(Highs& highs, const bool from_file) {
237+
void testBasisRestart(Highs& highs, const std::string& basis_file,
238+
const bool from_file) {
231239
// Checks that no simplex iterations are required if a saved optimal
232240
// basis is used for the original LP after changing a bound, solving
233241
// - so that the internal basis changes - and then restoring the

check/TestCheckSolution.cpp

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88

99
const bool dev_run = false;
1010

11-
void runWriteReadCheckSolution(Highs& highs, const std::string model,
11+
void runWriteReadCheckSolution(Highs& highs, const std::string& test_name,
12+
const std::string& model,
1213
const HighsModelStatus require_model_status,
1314
const HighsInt write_solution_style);
1415

1516
void runSetLpSolution(const std::string model);
1617

1718
TEST_CASE("check-solution", "[highs_check_solution]") {
19+
std::string test_name = Catch::getResultCapture().getCurrentTestName();
1820
std::string model = "";
1921
std::string model_file;
2022
HighsStatus read_status;
@@ -42,7 +44,8 @@ TEST_CASE("check-solution", "[highs_check_solution]") {
4244
REQUIRE(read_status == require_read_status);
4345

4446
require_model_status = HighsModelStatus::kOptimal;
45-
runWriteReadCheckSolution(highs, model, require_model_status,
47+
test_name += "-";
48+
runWriteReadCheckSolution(highs, test_name, model, require_model_status,
4649
write_solution_style);
4750
SpecialLps special_lps;
4851
HighsLp lp;
@@ -51,21 +54,24 @@ TEST_CASE("check-solution", "[highs_check_solution]") {
5154
model = "distillation";
5255
special_lps.distillationMip(lp, require_model_status, optimal_objective);
5356
highs.passModel(lp);
54-
runWriteReadCheckSolution(highs, model, require_model_status,
57+
test_name += "-";
58+
runWriteReadCheckSolution(highs, test_name, model, require_model_status,
5559
write_solution_style);
5660

5761
lp.clear();
5862
model = "primalDualInfeasible1Lp";
5963
special_lps.primalDualInfeasible1Lp(lp, require_model_status);
6064
highs.passModel(lp);
61-
runWriteReadCheckSolution(highs, model, require_model_status,
65+
test_name += "-";
66+
runWriteReadCheckSolution(highs, test_name, model, require_model_status,
6267
write_solution_style);
6368
// Second pass uses sparse format
6469
write_solution_style = kSolutionStyleSparse;
6570
}
6671
}
6772

6873
TEST_CASE("check-set-mip-solution", "[highs_check_solution]") {
74+
const std::string test_name = Catch::getResultCapture().getCurrentTestName();
6975
HighsStatus return_status;
7076
const std::string model = "flugpl";
7177
std::string model_file =
@@ -83,7 +89,7 @@ TEST_CASE("check-set-mip-solution", "[highs_check_solution]") {
8389
HighsInt scratch_num_nodes = info.mip_node_count;
8490
if (dev_run) printf("Num nodes = %d\n", int(scratch_num_nodes));
8591

86-
std::string solution_file = model + ".sol";
92+
std::string solution_file = test_name + model + ".sol";
8793
if (dev_run) return_status = highs.writeSolution("");
8894
return_status = highs.writeSolution(solution_file);
8995
REQUIRE(return_status == HighsStatus::kOk);
@@ -354,8 +360,9 @@ TEST_CASE("check-set-rowwise-lp-solution", "[highs_check_solution]") {
354360
}
355361

356362
TEST_CASE("check-set-mip-solution-extra-row", "[highs_check_solution]") {
363+
const std::string test_name = Catch::getResultCapture().getCurrentTestName();
364+
const std::string solution_file_name = test_name + ".sol";
357365
Highs highs;
358-
const std::string solution_file_name = "temp.sol";
359366
highs.setOptionValue("output_flag", dev_run);
360367
highs.addVar(0, 2);
361368
highs.addVar(0, 2);
@@ -396,6 +403,7 @@ TEST_CASE("check-set-illegal-solution", "[highs_check_solution]") {
396403
}
397404

398405
TEST_CASE("read-miplib-solution", "[highs_check_solution]") {
406+
const std::string test_name = Catch::getResultCapture().getCurrentTestName();
399407
HighsLp lp;
400408
lp.num_col_ = 5;
401409
lp.num_row_ = 1;
@@ -417,7 +425,7 @@ TEST_CASE("read-miplib-solution", "[highs_check_solution]") {
417425
REQUIRE(h.run() == HighsStatus::kOk);
418426
// REQUIRE(h.writeSolution("", kSolutionStylePretty) == HighsStatus::kOk);
419427
const std::vector<double>& col_value = h.getSolution().col_value;
420-
std::string miplib_sol_file = "miplib.sol";
428+
std::string miplib_sol_file = test_name + ".sol";
421429
FILE* file = fopen(miplib_sol_file.c_str(), "w");
422430
REQUIRE(file != 0);
423431
fprintf(file, "=obj= 22\n");
@@ -441,7 +449,8 @@ TEST_CASE("read-miplib-solution", "[highs_check_solution]") {
441449
std::remove(miplib_sol_file.c_str());
442450
}
443451

444-
void runWriteReadCheckSolution(Highs& highs, const std::string model,
452+
void runWriteReadCheckSolution(Highs& highs, const std::string& test_name,
453+
const std::string& model,
445454
const HighsModelStatus require_model_status,
446455
const HighsInt write_solution_style) {
447456
HighsStatus run_status;
@@ -455,7 +464,7 @@ void runWriteReadCheckSolution(Highs& highs, const std::string model,
455464
status = highs.getModelStatus();
456465
REQUIRE(status == require_model_status);
457466

458-
solution_file = model + ".sol";
467+
solution_file = test_name + model + ".sol";
459468
if (dev_run)
460469
printf("Writing solution in style %d to %s\n", int(write_solution_style),
461470
solution_file.c_str());

check/TestFilereader.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ TEST_CASE("filereader-free-format-parser-lp", "[highs_filereader]") {
199199

200200
// No commas in test case name.
201201
TEST_CASE("filereader-read-mps-ems-lp", "[highs_filereader]") {
202+
const std::string test_name = Catch::getResultCapture().getCurrentTestName();
202203
std::string filename;
203204
filename = std::string(HIGHS_DIR) + "/check/instances/adlittle.mps";
204205

@@ -212,14 +213,14 @@ TEST_CASE("filereader-read-mps-ems-lp", "[highs_filereader]") {
212213
HighsLp lp_mps = highs.getLp();
213214

214215
// Write lp
215-
std::string filename_lp = "adlittle.lp";
216+
std::string filename_lp = test_name + ".lp";
216217
status = highs.writeModel(filename_lp);
217218
REQUIRE(status == HighsStatus::kOk);
218219

219220
/*
220221
bool are_the_same;
221222
// Write ems
222-
std::string filename_ems = "adlittle.ems";
223+
std::string filename_ems = test_name + ".ems";
223224
status = highs.writeModel(filename_ems);
224225
REQUIRE(status == HighsStatus::kOk);
225226
@@ -357,9 +358,10 @@ TEST_CASE("filereader-dD2e", "[highs_filereader]") {
357358
// }
358359

359360
TEST_CASE("writeLocalModel", "[highs_filereader]") {
361+
const std::string test_name = Catch::getResultCapture().getCurrentTestName();
362+
std::string write_model_file = test_name + ".mps";
360363
Highs h;
361364
h.setOptionValue("output_flag", dev_run);
362-
std::string write_model_file = "foo.mps";
363365
HighsModel model;
364366
HighsLp& lp = model.lp_;
365367
;
@@ -415,7 +417,8 @@ TEST_CASE("writeLocalModel", "[highs_filereader]") {
415417
}
416418

417419
TEST_CASE("write-MI-bound-model", "[highs_filereader]") {
418-
std::string write_model_file = "temp.mps";
420+
const std::string test_name = Catch::getResultCapture().getCurrentTestName();
421+
std::string write_model_file = test_name + ".mps";
419422
Highs h;
420423
h.setOptionValue("output_flag", dev_run);
421424
h.addCol(1, -kHighsInf, 1, 0, nullptr, nullptr);

check/TestInfo.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
const bool dev_run = false;
1010

1111
TEST_CASE("highs-info", "[highs_info]") {
12+
const std::string test_name = Catch::getResultCapture().getCurrentTestName();
13+
const std::string highs_info_file = test_name + ".info";
1214
std::string filename;
1315
filename = std::string(HIGHS_DIR) + "/check/instances/avgas.mps";
1416
filename = std::string(HIGHS_DIR) + "/check/instances/adlittle.mps";
@@ -62,7 +64,6 @@ TEST_CASE("highs-info", "[highs_info]") {
6264
REQUIRE(return_status == HighsStatus::kOk);
6365
}
6466

65-
std::string highs_info_file = "Highs.info";
6667
return_status = highs.writeInfo(highs_info_file);
6768
REQUIRE(return_status == HighsStatus::kOk);
6869

check/TestLogging.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
const bool dev_run = false;
88

99
TEST_CASE("logging", "[highs_logging]") {
10+
const std::string test_name = Catch::getResultCapture().getCurrentTestName();
11+
const std::string log_file = test_name + ".log";
1012
std::string model;
1113
std::string model_file;
12-
std::string log_file;
1314
HighsStatus return_status;
1415

1516
model = "avgas";
1617
model_file = std::string(HIGHS_DIR) + "/check/instances/" + model + ".mps";
17-
log_file = "temp.log";
1818

1919
Highs highs;
2020
if (!dev_run) highs.setOptionValue("output_flag", false);

check/TestLpSolvers.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -406,10 +406,11 @@ bool fileExists(const std::string& file_name) {
406406
}
407407

408408
TEST_CASE("highs-files-lp", "[highs_lp_solver]") {
409+
const std::string test_name = Catch::getResultCapture().getCurrentTestName();
410+
const std::string write_solution_file = test_name + ".sol";
411+
const std::string write_basis_file = test_name + ".bas";
412+
const std::string write_model_file = test_name + ".mps";
409413
Highs h;
410-
std::string write_solution_file = "lp-temp.sol";
411-
std::string write_basis_file = "lp-temp.bas";
412-
std::string write_model_file = "lp-temp.mps";
413414
h.setOptionValue("output_flag", dev_run);
414415
std::string model_file =
415416
std::string(HIGHS_DIR) + "/check/instances/avgas.mps";
@@ -443,10 +444,11 @@ TEST_CASE("highs-files-lp", "[highs_lp_solver]") {
443444
}
444445

445446
TEST_CASE("highs-files-mip", "[highs_lp_solver]") {
447+
const std::string test_name = Catch::getResultCapture().getCurrentTestName();
448+
const std::string write_solution_file = test_name + ".sol";
449+
const std::string write_basis_file = test_name + ".bas";
450+
const std::string write_model_file = test_name + ".mps";
446451
Highs h;
447-
std::string write_solution_file = "mip-temp.sol";
448-
std::string write_basis_file = "mip-temp.bas";
449-
std::string write_model_file = "mip-temp.mps";
450452
h.setOptionValue("output_flag", dev_run);
451453
std::string model_file =
452454
std::string(HIGHS_DIR) + "/check/instances/flugpl.mps";

check/TestMipSolver.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,8 @@ TEST_CASE("MIP-infeasible-start", "[highs_test_mip_solver]") {
509509
TEST_CASE("get-integrality", "[highs_test_mip_solver]") {}
510510

511511
TEST_CASE("MIP-bounds", "[highs_test_mip_solver]") {
512+
const std::string test_name = Catch::getResultCapture().getCurrentTestName();
513+
const std::string test_mps = test_name + ".mps";
512514
// Introduced due to #1325 observing that LI and UI are needed
513515
HighsLp lp;
514516
lp.num_col_ = 6;
@@ -536,7 +538,6 @@ TEST_CASE("MIP-bounds", "[highs_test_mip_solver]") {
536538
const double obj0 = highs.getObjectiveValue();
537539
if (dev_run) printf("Optimum at first run: %g\n", obj0);
538540
// now write out to MPS and load again
539-
const std::string test_mps = "test.mps";
540541
highs.writeModel(test_mps);
541542
highs.readModel(test_mps);
542543
highs.run();
@@ -549,8 +550,9 @@ TEST_CASE("MIP-bounds", "[highs_test_mip_solver]") {
549550
}
550551

551552
TEST_CASE("MIP-get-saved-solutions", "[highs_test_mip_solver]") {
553+
const std::string test_name = Catch::getResultCapture().getCurrentTestName();
554+
const std::string solution_file = test_name + ".sol";
552555
const std::string model = "flugpl";
553-
const std::string solution_file = "MipImproving.sol";
554556
const std::string model_file =
555557
std::string(HIGHS_DIR) + "/check/instances/" + model + ".mps";
556558
Highs highs;
@@ -617,7 +619,8 @@ TEST_CASE("MIP-max-offset-test", "[highs_test_mip_solver]") {
617619
}
618620

619621
TEST_CASE("MIP-get-saved-solutions-presolve", "[highs_test_mip_solver]") {
620-
const std::string solution_file = "MipImproving.sol";
622+
const std::string test_name = Catch::getResultCapture().getCurrentTestName();
623+
const std::string solution_file = test_name + ".sol";
621624
Highs highs;
622625
highs.setOptionValue("output_flag", dev_run);
623626
highs.setOptionValue("mip_improving_solution_save", true);
@@ -835,14 +838,13 @@ TEST_CASE("issue-2204", "[highs_test_mip_solver]") {
835838
}
836839

837840
TEST_CASE("ZI Round and Shifting Heuristics", "[highs_test_mip_solver]") {
838-
std::string model_file =
839-
std::string(HIGHS_DIR) + "/check/instances/rgn.mps";
841+
std::string model_file = std::string(HIGHS_DIR) + "/check/instances/rgn.mps";
840842

841843
Highs highs;
842844
highs.setOptionValue("output_flag", dev_run);
843845
// Enable both heuristics
844846
highs.setOptionValue("mip_heuristic_run_zi_round", true);
845-
highs.setOptionValue("mip_heuristic_run_shifting", true);
847+
highs.setOptionValue("mip_heuristic_run_shifting", true);
846848
highs.readModel(model_file);
847849
const HighsModelStatus require_model_status = HighsModelStatus::kOptimal;
848850
const double optimal_objective = 82.19999924;

check/TestNames.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
const bool dev_run = false;
88
TEST_CASE("highs-names", "[highs_names]") {
9+
const std::string test_name = Catch::getResultCapture().getCurrentTestName();
10+
const std::string solution_file = test_name + ".sol";
911
std::string name;
1012
const std::string model = "avgas";
1113
const std::string model_file =
@@ -109,7 +111,6 @@ TEST_CASE("highs-names", "[highs_names]") {
109111
local_lp.col_names_.clear();
110112
local_lp.row_names_.clear();
111113
highs.passModel(local_lp);
112-
const std::string solution_file = "temp.sol";
113114
REQUIRE(highs.writeSolution(solution_file, 1) == HighsStatus::kOk);
114115

115116
// Cannot get name of column or row 0

0 commit comments

Comments
 (0)