Skip to content

Commit cac98b9

Browse files
authored
Merge pull request #2577 from ERGO-Code/fix-2460
Correct and enhanced handling of `user_cost_scale` and `user_bound_scale` options
2 parents b161f68 + 5d2b67e commit cac98b9

30 files changed

+1507
-864
lines changed

check/TestCAPI.c

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ HighsInt doubleArraysEqual(const double dim, const double* array0,
214214

215215
void assertDoubleValuesEqual(const char* name, const double is,
216216
const double should_be) {
217-
const double dl = fabs(is - should_be);
217+
const double dl = fabs(is - should_be)/(1e0 + fabs(should_be));
218218
if (dl > double_equal_tolerance) {
219219
printf("Value %s = %g differs from %g by %g but should be equal\n", name,
220220
is, should_be, dl);
@@ -2241,6 +2241,67 @@ void testIis() {
22412241
Highs_destroy(highs);
22422242
}
22432243

2244+
void testUserObjectiveBoundScaling() {
2245+
void* highs = Highs_create();
2246+
Highs_setBoolOptionValue(highs, "output_flag", dev_run);
2247+
HighsInt ret;
2248+
double inf = Highs_getInfinity(highs);
2249+
const HighsInt num_col = 2;
2250+
const HighsInt num_row = 2;
2251+
const HighsInt num_nz = 4;
2252+
HighsInt a_format = kHighsMatrixFormatColwise;
2253+
HighsInt sense = kHighsObjSenseMinimize;
2254+
double offset = 1e-4;
2255+
2256+
// Define the column costs, lower bounds and upper bounds
2257+
double col_cost[2] = {-4e6, -7e6};
2258+
double col_lower[2] = {1e-8, 1e-8};
2259+
double col_upper[2] = {1e8, 1e8};
2260+
// Define the row lower bounds and upper bounds
2261+
double row_lower[3] = {-inf, -2e+8};
2262+
double row_upper[3] = {6e+8, inf};
2263+
// Define the constraint matrix column-wise
2264+
HighsInt a_start[2] = {0, 2};
2265+
HighsInt a_index[5] = {0, 1, 0, 1};
2266+
double a_value[5] = {1.0, 1.0, 1.0, -1.0};
2267+
2268+
HighsInt return_status =
2269+
Highs_passLp(highs, num_col, num_row, num_nz,
2270+
a_format, sense, offset,
2271+
col_cost, col_lower, col_upper, row_lower, row_upper,
2272+
a_start, a_index, a_value);
2273+
assert(return_status == kHighsStatusOk);
2274+
2275+
return_status = Highs_run(highs);
2276+
assert(return_status == kHighsStatusOk);
2277+
HighsInt model_status = Highs_getModelStatus(highs);
2278+
assert(model_status == kHighsModelStatusOptimal);
2279+
2280+
double unscaled_objective_value = Highs_getObjectiveValue(highs);
2281+
double dual_objective_value;
2282+
return_status = Highs_getDualObjectiveValue(highs, &dual_objective_value);
2283+
assert(return_status == kHighsStatusOk);
2284+
2285+
assertDoubleValuesEqual("PDobjective", unscaled_objective_value, dual_objective_value);
2286+
2287+
HighsInt suggested_objective_scale;
2288+
HighsInt suggested_bound_scale;
2289+
return_status = Highs_getObjectiveBoundScaling(highs,
2290+
&suggested_objective_scale,
2291+
&suggested_bound_scale);
2292+
assert(return_status == kHighsStatusOk);
2293+
2294+
Highs_setIntOptionValue(highs, "user_cost_scale", suggested_objective_scale);
2295+
Highs_setIntOptionValue(highs, "user_bound_scale", suggested_bound_scale);
2296+
2297+
Highs_clearSolver(highs);
2298+
return_status = Highs_run(highs);
2299+
assert(return_status == kHighsStatusOk);
2300+
2301+
double scaled_objective_value = Highs_getObjectiveValue(highs);
2302+
assertDoubleValuesEqual("objective_value", unscaled_objective_value, scaled_objective_value);
2303+
}
2304+
22442305
void testFixedLp() {
22452306
// The use of Highs_getFixedLp is illustrated for the MIP
22462307
//
@@ -2374,6 +2435,7 @@ int main() {
23742435
testDualRayTwice();
23752436
testDeleteRowResolveWithBasis();
23762437
testIis();
2438+
testUserObjectiveBoundScaling();
23772439
testFixedLp();
23782440
return 0;
23792441
}

check/TestSpecialLps.cpp

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ void solve(Highs& highs, std::string presolve, std::string solver,
1010
const double require_optimal_objective = 0,
1111
const double require_iteration_count = -1) {
1212
SpecialLps special_lps;
13-
if (!dev_run) highs.setOptionValue("output_flag", false);
13+
highs.setOptionValue("output_flag", dev_run);
1414
if (dev_run)
1515
REQUIRE(highs.setOptionValue("log_dev_level", kHighsLogDevLevelDetailed) ==
1616
HighsStatus::kOk);
@@ -649,108 +649,108 @@ void smallValue(Highs& highs) {
649649

650650
TEST_CASE("LP-distillation", "[highs_test_special_lps]") {
651651
Highs highs;
652-
if (!dev_run) highs.setOptionValue("output_flag", false);
652+
highs.setOptionValue("output_flag", dev_run);
653653
distillation(highs);
654654
}
655655

656656
TEST_CASE("LP-272", "[highs_test_special_lps]") {
657657
Highs highs;
658-
if (!dev_run) highs.setOptionValue("output_flag", false);
658+
highs.setOptionValue("output_flag", dev_run);
659659
issue272(highs);
660660
}
661661
TEST_CASE("LP-280", "[highs_test_special_lps]") {
662662
Highs highs;
663-
if (!dev_run) highs.setOptionValue("output_flag", false);
663+
highs.setOptionValue("output_flag", dev_run);
664664
issue280(highs);
665665
}
666666
TEST_CASE("LP-282", "[highs_test_special_lps]") {
667667
Highs highs;
668-
if (!dev_run) highs.setOptionValue("output_flag", false);
668+
highs.setOptionValue("output_flag", dev_run);
669669
issue282(highs);
670670
}
671671
TEST_CASE("LP-285", "[highs_test_special_lps]") {
672672
Highs highs;
673-
if (!dev_run) highs.setOptionValue("output_flag", false);
673+
highs.setOptionValue("output_flag", dev_run);
674674
issue285(highs);
675675
}
676676

677677
TEST_CASE("LP-295", "[highs_test_special_lps]") {
678678
Highs highs;
679-
if (!dev_run) highs.setOptionValue("output_flag", false);
679+
highs.setOptionValue("output_flag", dev_run);
680680
issue295(highs);
681681
}
682682

683683
TEST_CASE("LP-306", "[highs_test_special_lps]") {
684684
Highs highs;
685-
if (!dev_run) highs.setOptionValue("output_flag", false);
685+
highs.setOptionValue("output_flag", dev_run);
686686
issue306(highs);
687687
}
688688
TEST_CASE("LP-316", "[highs_test_special_lps]") {
689689
Highs highs;
690-
if (!dev_run) highs.setOptionValue("output_flag", false);
690+
highs.setOptionValue("output_flag", dev_run);
691691
issue316(highs);
692692
}
693693
TEST_CASE("LP-425", "[highs_test_special_lps]") {
694694
Highs highs;
695-
if (!dev_run) highs.setOptionValue("output_flag", false);
695+
highs.setOptionValue("output_flag", dev_run);
696696
issue425(highs);
697697
}
698698
TEST_CASE("LP-669", "[highs_test_special_lps]") {
699699
Highs highs;
700-
if (!dev_run) highs.setOptionValue("output_flag", false);
700+
highs.setOptionValue("output_flag", dev_run);
701701
issue669(highs);
702702
}
703703
TEST_CASE("LP-galenet", "[highs_test_special_lps]") {
704704
Highs highs;
705-
if (!dev_run) highs.setOptionValue("output_flag", false);
705+
highs.setOptionValue("output_flag", dev_run);
706706
mpsGalenet(highs);
707707
}
708708
TEST_CASE("LP-primal-dual-infeasible1", "[highs_test_special_lps]") {
709709
Highs highs;
710-
if (!dev_run) highs.setOptionValue("output_flag", false);
710+
highs.setOptionValue("output_flag", dev_run);
711711
primalDualInfeasible1(highs);
712712
}
713713
TEST_CASE("LP-primal-dual-infeasible2", "[highs_test_special_lps]") {
714714
Highs highs;
715-
if (!dev_run) highs.setOptionValue("output_flag", false);
715+
highs.setOptionValue("output_flag", dev_run);
716716
primalDualInfeasible2(highs);
717717
}
718718
TEST_CASE("LP-primal-dual-infeasible3", "[highs_test_special_lps]") {
719719
Highs highs;
720-
if (!dev_run) highs.setOptionValue("output_flag", false);
720+
highs.setOptionValue("output_flag", dev_run);
721721
primalDualInfeasible3(highs);
722722
}
723723
TEST_CASE("LP-unbounded", "[highs_test_special_lps]") {
724724
Highs highs;
725-
if (!dev_run) highs.setOptionValue("output_flag", false);
725+
highs.setOptionValue("output_flag", dev_run);
726726
mpsUnbounded(highs);
727727
}
728728

729729
// for some reason hangs on IPX with presolve off: add to doctest
730730
TEST_CASE("LP-gas11", "[highs_test_special_lps]") {
731731
Highs highs;
732-
if (!dev_run) highs.setOptionValue("output_flag", false);
732+
highs.setOptionValue("output_flag", dev_run);
733733
mpsGas11(highs);
734734
}
735735

736736
TEST_CASE("LP-almost-not-unbounded", "[highs_test_special_lps]") {
737737
Highs highs;
738-
if (!dev_run) highs.setOptionValue("output_flag", false);
738+
highs.setOptionValue("output_flag", dev_run);
739739
almostNotUnbounded(highs);
740740
}
741741
TEST_CASE("LP-singular-starting-basis", "[highs_test_special_lps]") {
742742
Highs highs;
743-
if (!dev_run) highs.setOptionValue("output_flag", false);
743+
highs.setOptionValue("output_flag", dev_run);
744744
singularStartingBasis(highs);
745745
}
746746
TEST_CASE("LP-unconstrained", "[highs_test_special_lps]") {
747747
Highs highs;
748-
if (!dev_run) highs.setOptionValue("output_flag", false);
748+
highs.setOptionValue("output_flag", dev_run);
749749
unconstrained(highs);
750750
}
751751

752752
TEST_CASE("LP-small-value", "[highs_test_special_lps]") {
753753
Highs highs;
754-
if (!dev_run) highs.setOptionValue("output_flag", false);
754+
highs.setOptionValue("output_flag", dev_run);
755755
smallValue(highs);
756756
}

0 commit comments

Comments
 (0)