Skip to content

Commit 809da37

Browse files
committed
Have to introduce new basis file format with names: make old format deprecated - like old solution format
1 parent ee4dfdb commit 809da37

File tree

3 files changed

+76
-31
lines changed

3 files changed

+76
-31
lines changed

check/TestCheckSolution.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,50 @@ TEST_CASE("read-lp-file-solution", "[highs_check_solution]") {
496496
h.resetGlobalScheduler(true);
497497
}
498498

499+
TEST_CASE("read-lp-file-basis", "[highs_check_solution]") {
500+
const std::string test_name = Catch::getResultCapture().getCurrentTestName();
501+
const std::string model_file_name = test_name + ".lp";
502+
const std::string basis_file_name = test_name + ".bas";
503+
const bool with_names = false;
504+
HighsLp lp;
505+
lp.num_col_ = 3;
506+
lp.num_row_ = 2;
507+
lp.col_cost_ = {0, 1, 1};
508+
lp.col_lower_ = {0, 10, 0};
509+
lp.col_upper_ = {kHighsInf, kHighsInf, kHighsInf};
510+
if (with_names) lp.col_names_ = {"x", "y", "z"};
511+
lp.row_lower_ = {1, -kHighsInf};
512+
lp.row_upper_ = {kHighsInf, 2};
513+
if (with_names) lp.row_names_ = {"r-lo", "r-up"};
514+
lp.a_matrix_.start_ = {0, 2, 2, 4};
515+
lp.a_matrix_.index_ = {0, 1, 0, 1};
516+
lp.a_matrix_.value_ = {1, 1, 1, 1};
517+
Highs h;
518+
// h.setOptionValue("output_flag", dev_run);
519+
REQUIRE(h.passModel(lp) == HighsStatus::kOk);
520+
h.run();
521+
// Optimally x - basic; y - lower; z - lower
522+
h.writeModel(model_file_name);
523+
h.writeSolution("", 1);
524+
h.writeBasis("");
525+
h.writeBasis(basis_file_name);
526+
527+
h.readModel(model_file_name);
528+
// Variables now ordered y; z; x
529+
h.writeModel("");
530+
h.readBasis(basis_file_name);
531+
// Initial basis: y - basic; z - lower; x - lower, using basis for
532+
// original ordering with new ordering. Not optimal - in fact basis
533+
// matrix B = [0] is singular!
534+
h.run();
535+
REQUIRE(h.getInfo().simplex_iteration_count == 0);
536+
537+
std::remove(model_file_name.c_str());
538+
// std::remove(basis_file_name.c_str());
539+
540+
h.resetGlobalScheduler(true);
541+
}
542+
499543
void runWriteReadCheckSolution(Highs& highs, const std::string& test_name,
500544
const std::string& model,
501545
const HighsModelStatus require_model_status,

check/TestFilereader.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -496,17 +496,22 @@ TEST_CASE("handle-blank-space-names", "[highs_filereader]") {
496496
REQUIRE(h.writeSolution("", 1) == HighsStatus::kOk);
497497
REQUIRE(h.writeModel("") == HighsStatus::kOk);
498498

499-
lp.col_names_ = {"Column0", ""};
499+
lp.col_names_ = {"Column", "Column"};
500500
lp.row_names_ = {"Row0", "Row1"};
501501
REQUIRE(h.passModel(lp) == HighsStatus::kOk);
502+
REQUIRE(h.writeModel("") == HighsStatus::kError);
503+
504+
lp.col_names_ = {"Column0", ""};
505+
REQUIRE(h.passModel(lp) == HighsStatus::kOk);
502506
h.run();
503-
REQUIRE(h.writeSolution("") == HighsStatus::kOk);
507+
REQUIRE(h.writeSolution("", -1) == HighsStatus::kOk);
504508
REQUIRE(h.writeModel("") == HighsStatus::kOk);
505509

506510
std::vector<HighsInt> index = {0, 1};
507511
std::vector<double> value = {2, 3};
508512
REQUIRE(h.addRow(5, inf, 2, index.data(), value.data()) == HighsStatus::kOk);
509513
h.run();
514+
REQUIRE(h.writeBasis("") == HighsStatus::kOk);
510515
REQUIRE(h.writeSolution("", 1) == HighsStatus::kOk);
511516
REQUIRE(h.writeModel("") == HighsStatus::kOk);
512517

highs/lp_data/HighsModelUtils.cpp

Lines changed: 25 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -417,47 +417,43 @@ HighsStatus normaliseNames(const HighsLogOptions& log_options,
417417
name_suffix = 0;
418418
names.resize(num_name_required);
419419
highsLogUser(log_options, HighsLogType::kWarning,
420-
"%6s names are blank or not present: using "
420+
"%s names are blank or not present: using "
421421
"names with prefix \"%s\", beginning with suffix %d\n",
422-
column ? "Column" : "Row", name_prefix.c_str(), int(name_suffix));
422+
column ? "Column" : "Row ", name_prefix.c_str(), int(name_suffix));
423423
for (HighsInt ix = 0; ix < num_name_required; ix++)
424424
names[ix] = name_prefix + std::to_string(name_suffix++);
425425
return HighsStatus::kOk;
426426
}
427427
names.resize(num_name_required);
428-
// Form the hash table to check for duplicates
429-
if (!name_hash.name2index.size()) name_hash.form(names);
430-
428+
HighsInt num_blank = 0;
429+
const HighsInt from_name_suffix = name_suffix;
431430
for (HighsInt ix = 0; ix < num_name_required; ix++) {
432431
if (HighsInt(names[ix].length()) == 0) {
433432
// Name is blank, so create one
433+
num_blank++;
434434
name_prefix = column ? kHighsUniqueColNamePrefix : kHighsUniquerowNamePrefix;
435-
std::string name = name_prefix + std::to_string(name_suffix++);
436-
auto search = name_hash.name2index.find(name);
437-
if (search == name_hash.name2index.end()) {
438-
// Name not found in hash, so replace blank name
439-
names[ix] = name;
440-
// Add name to hash, checking for duplicate
441-
const bool duplicate =
442-
!name_hash.name2index.emplace(name, ix).second;
443-
assert(!duplicate);
444-
assert(names[ix] == name);
445-
assert(name_hash.name2index.find(name)->second == ix);
446-
} else {
447-
name_hash.name2index.clear();
448-
return HighsStatus::kError;
449-
}
450-
} else {
451-
size_t space_pos = names[ix].find(" ");
452-
if (space_pos != std::string::npos) {
453-
highsLogUser(log_options, HighsLogType::kError,
454-
"%s %d name \"%s\" contains a space character\n",
455-
column ? "Column" : "Row",
456-
int(ix), names[ix].c_str());
457-
return HighsStatus::kError;
458-
}
435+
names[ix] = name_prefix + std::to_string(name_suffix++);
436+
} else if (names[ix].find(" ") != std::string::npos) {
437+
// Name contains a space, so return error
438+
highsLogUser(log_options, HighsLogType::kError,
439+
"%s %d name \"%s\" contains a space character\n",
440+
column ? "Column" : "Row",
441+
int(ix), names[ix].c_str());
442+
return HighsStatus::kError;
459443
}
460444
}
445+
// Check for duplicates
446+
if (name_hash.hasDuplicate(names)) {
447+
name_hash.name2index.clear();
448+
return HighsStatus::kError;
449+
}
450+
if (num_blank)
451+
highsLogUser(log_options, HighsLogType::kWarning,
452+
"Replaced %d blank %6s name%s by name%s with prefix \"%s\", beginning with suffix %d\n",
453+
int(num_blank), column ? "column" : "row",
454+
num_blank > 1 ? "s" : "",
455+
num_blank > 1 ? "s" : "",
456+
name_prefix.c_str(), int(from_name_suffix));
461457
return HighsStatus::kOk;
462458
}
463459

0 commit comments

Comments
 (0)