Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions check/TestModelProperties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,23 @@ TEST_CASE("afiro-ill-conditioning", "[highs_model_properties]") {
highs.getIllConditioning(ill_conditioning, constraint);
highs.getIllConditioning(ill_conditioning, !constraint);
}

TEST_CASE("infinite-bounds", "[highs_model_properties]") {
Highs h;
h.setOptionValue("output_flag", dev_run);
HighsLp lp;
// clang-format off
lp.col_lower_ = {-1e25, 0, -1e12, 0, -1e25, -1e12, -1e25, 0, -1e12, 0, -1e25, -1e12};
lp.col_upper_ = { 0, 1e25, 0, 1e12, 1e25, 1e12, 0, 1e25, 0, 1e12, 1e25, 1e12};
lp.num_col_ = static_cast<HighsInt>(lp.col_lower_.size());
lp.num_row_ = 0;
lp.col_cost_.assign(lp.num_col_, 0);
lp.integrality_ = {HighsVarType::kContinuous, HighsVarType::kContinuous,
HighsVarType::kInteger, HighsVarType::kInteger,
HighsVarType::kContinuous, HighsVarType::kInteger,
HighsVarType::kSemiContinuous, HighsVarType::kSemiContinuous,
HighsVarType::kSemiInteger, HighsVarType::kSemiInteger,
HighsVarType::kSemiContinuous, HighsVarType::kSemiInteger};
// clang-format on
REQUIRE(h.passModel(lp) == HighsStatus::kOk);
}
2 changes: 1 addition & 1 deletion docs/src/options/definitions.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
- Default: 1e+20

## [infinite\_bound](@id option-infinite-bound)
- Limit on |constraint bound|: values greater than or equal to this will be treated as infinite
- Limit on |variable/constraint bound|: values greater than or equal to this will be treated as infinite
- Type: double
- Range: [1e+15, inf]
- Default: 1e+20
Expand Down
1 change: 1 addition & 0 deletions highs/lp_data/HConst.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const double kExcessivelySmallObjectiveCoefficient = 1e-4;
const double kExcessivelyLargeObjectiveCoefficient = 1e6;
const double kExcessivelySmallBoundValue = 1e-4;
const double kExcessivelyLargeBoundValue = 1e6;
const double kExcessivelyLargeIntegerBoundValue = 1e5;

const HighsInt kNoThreadInstance = -1;
const bool kAllowDeveloperAssert = false;
Expand Down
12 changes: 8 additions & 4 deletions highs/lp_data/HighsLpUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,16 +461,20 @@ HighsStatus assessBounds(const HighsOptions& options, const std::string& type,
if (num_infinite_lower_bound) {
highsLogUser(options.log_options, HighsLogType::kInfo,
"%3ss:%12" HIGHSINT_FORMAT
" lower bounds less than or equal to %12g are treated as "
" lower bound%s less than or equal to %12g are treated as "
"-Infinity\n",
type.c_str(), num_infinite_lower_bound, -infinite_bound);
type.c_str(), num_infinite_lower_bound,
highsIntToPlural(num_infinite_lower_bound).c_str(),
-infinite_bound);
}
if (num_infinite_upper_bound) {
highsLogUser(options.log_options, HighsLogType::kInfo,
"%3ss:%12" HIGHSINT_FORMAT
" upper bounds greater than or equal to %12g are treated as "
" upper bound%s greater than or equal to %12g are treated as "
"+Infinity\n",
type.c_str(), num_infinite_upper_bound, infinite_bound);
type.c_str(), num_infinite_upper_bound,
highsIntToPlural(num_infinite_upper_bound).c_str(),
infinite_bound);
}

if (error_found)
Expand Down
2 changes: 1 addition & 1 deletion highs/lp_data/HighsOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -812,7 +812,7 @@ class HighsOptions : public HighsOptionsStruct {

record_double = new OptionRecordDouble(
"infinite_bound",
"Limit on |constraint bound|: values greater than or equal to "
"Limit on |variable/constraint bound|: values greater than or equal to "
"this will be treated as infinite",
advanced, &infinite_bound, 1e15, 1e20, kHighsInf);
records.push_back(record_double);
Expand Down
76 changes: 56 additions & 20 deletions highs/lp_data/HighsSolve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@ void assessExcessiveObjectiveBoundScaling(const HighsLogOptions log_options,
kExcessivelyLargeObjectiveCoefficient;
const double small_bound = kExcessivelySmallBoundValue;
const double large_bound = kExcessivelyLargeBoundValue;
const double large_integer_bound = kExcessivelyLargeIntegerBoundValue;
std::stringstream message;
if (user_cost_or_bound_scale) {
if (user_scale_data.user_objective_scale)
Expand Down Expand Up @@ -423,6 +424,8 @@ void assessExcessiveObjectiveBoundScaling(const HighsLogOptions log_options,
double max_continuous_matrix_value = -kHighsInf;
double max_noncontinuous_matrix_value = -kHighsInf;
const bool is_mip = lp.integrality_.size();
HighsInt num_continuous_variable = 0;
HighsInt num_noncontinuous_variable = 0;
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
if (is_mip && lp.integrality_[iCol] != HighsVarType::kContinuous) {
assessFiniteNonzero(lp.col_cost_[iCol], min_noncontinuous_col_cost,
Expand All @@ -431,23 +434,21 @@ void assessExcessiveObjectiveBoundScaling(const HighsLogOptions log_options,
max_noncontinuous_col_bound);
assessFiniteNonzero(lp.col_upper_[iCol], min_noncontinuous_col_bound,
max_noncontinuous_col_bound);
num_noncontinuous_variable++;
} else {
assessFiniteNonzero(lp.col_cost_[iCol], min_continuous_col_cost,
max_continuous_col_cost);
assessFiniteNonzero(lp.col_lower_[iCol], min_continuous_col_bound,
max_continuous_col_bound);
assessFiniteNonzero(lp.col_upper_[iCol], min_continuous_col_bound,
max_continuous_col_bound);
num_continuous_variable++;
}
}
double min_col_cost =
std::min(min_continuous_col_cost, min_noncontinuous_col_cost);
double max_col_cost =
std::max(max_continuous_col_cost, max_noncontinuous_col_cost);
double min_col_bound =
std::min(min_continuous_col_bound, min_noncontinuous_col_bound);
double max_col_bound =
std::max(max_continuous_col_bound, max_noncontinuous_col_bound);

double min_matrix_value = kHighsInf;
double max_matrix_value = -kHighsInf;
Expand Down Expand Up @@ -482,8 +483,11 @@ void assessExcessiveObjectiveBoundScaling(const HighsLogOptions log_options,

if (min_col_cost == kHighsInf) min_col_cost = 0;
if (max_col_cost == -kHighsInf) max_col_cost = 0;
if (min_col_bound == kHighsInf) min_col_bound = 0;
if (max_col_bound == -kHighsInf) max_col_bound = 0;
if (min_continuous_col_bound == kHighsInf) min_continuous_col_bound = 0;
if (max_continuous_col_bound == -kHighsInf) max_continuous_col_bound = 0;
if (min_noncontinuous_col_bound == kHighsInf) min_noncontinuous_col_bound = 0;
if (max_noncontinuous_col_bound == -kHighsInf)
max_noncontinuous_col_bound = 0;
if (min_row_bound == kHighsInf) min_row_bound = 0;
if (max_row_bound == -kHighsInf) max_row_bound = 0;

Expand All @@ -504,8 +508,16 @@ void assessExcessiveObjectiveBoundScaling(const HighsLogOptions log_options,
highsLogUser(log_options, HighsLogType::kInfo,
" Hessian [%5.0e, %5.0e]\n", min_hessian_value,
max_hessian_value);
highsLogUser(log_options, HighsLogType::kInfo, " Bound [%5.0e, %5.0e]\n",
min_col_bound, max_col_bound);
if (num_continuous_variable)
highsLogUser(log_options, HighsLogType::kInfo,
" Bound [%5.0e, %5.0e]%s\n", min_continuous_col_bound,
max_continuous_col_bound,
num_noncontinuous_variable > 0 ? " (continuous)" : "");
if (num_noncontinuous_variable)
highsLogUser(log_options, HighsLogType::kInfo,
" Bound [%5.0e, %5.0e]%s\n", min_noncontinuous_col_bound,
max_noncontinuous_col_bound,
num_continuous_variable > 0 ? " (non-continuous)" : "");
}
if (lp.num_row_)
highsLogUser(log_options, HighsLogType::kInfo, " RHS [%5.0e, %5.0e]\n",
Expand All @@ -515,8 +527,9 @@ void assessExcessiveObjectiveBoundScaling(const HighsLogOptions log_options,
// max_col_cost = 0
assert(max_col_cost >= 0);
// LPs with no columns or no finite nonzero bounds will have
// max_col_bound = 0
assert(max_col_bound >= 0);
// max_continuous_col_bound = 0 and max_noncontinuous_col_bound = 0
assert(max_continuous_col_bound >= 0);
assert(max_noncontinuous_col_bound >= 0);
// LPs with no rows or no finite nonzero bounds will have
// max_row_bound = 0
assert(max_row_bound >= 0);
Expand All @@ -538,20 +551,33 @@ void assessExcessiveObjectiveBoundScaling(const HighsLogOptions log_options,
highsLogUser(log_options, HighsLogType::kWarning,
"%s has some excessively large Hessian values\n",
problem.c_str());
if (0 < min_col_bound && min_col_bound < small_bound)
if (0 < min_continuous_col_bound && min_continuous_col_bound < small_bound)
highsLogUser(log_options, HighsLogType::kWarning,
"%s has some excessively small column bounds\n",
problem.c_str());
if (max_col_bound > large_bound)
"%s has some excessively small bounds on%s variables\n",
problem.c_str(), is_mip ? " continuous" : "");
if (max_continuous_col_bound > large_bound)
highsLogUser(log_options, HighsLogType::kWarning,
"%s has some excessively large column bounds\n",
problem.c_str());
"%s has some excessively large bounds on%s variables\n",
problem.c_str(), is_mip ? " continuous" : "");
if (0 < min_noncontinuous_col_bound &&
min_noncontinuous_col_bound < small_bound)
highsLogUser(
log_options, HighsLogType::kWarning,
"%s has some excessively small bounds on non-continuous variables\n",
problem.c_str());
if (max_noncontinuous_col_bound > large_integer_bound)
highsLogUser(
log_options, HighsLogType::kWarning,
"%s has some excessively large bounds on non-continuous variables\n",
problem.c_str());
if (0 < min_row_bound && min_row_bound < small_bound)
highsLogUser(log_options, HighsLogType::kWarning,
"%s has some excessively small row bounds\n", problem.c_str());
"%s has some excessively small bounds on constraints\n",
problem.c_str());
if (max_row_bound > large_bound)
highsLogUser(log_options, HighsLogType::kWarning,
"%s has some excessively large row bounds\n", problem.c_str());
"%s has some excessively large bounds on constraints\n",
problem.c_str());

// Lambda to determine recommended user scaling values
auto suggestScaling = [&](double min_value, double max_value,
Expand Down Expand Up @@ -632,6 +658,7 @@ void assessExcessiveObjectiveBoundScaling(const HighsLogOptions log_options,
HighsInt suggested_objective_scale_order_of_magnitude =
outerRoundedLog(suggested_objective_scaling, 10);

bool warning_issued = false;
// Only report the order of magnitude scaling if there is no user
// scaling
bool order_of_magnitude_message =
Expand All @@ -652,9 +679,11 @@ void assessExcessiveObjectiveBoundScaling(const HighsLogOptions log_options,
" setting the user_objective_scale option to %d",
int(user_scale_data.suggested_user_objective_scale));
}
if (order_of_magnitude_message || dl_user_objective_scale)
if (order_of_magnitude_message || dl_user_objective_scale) {
highsLogUser(log_options, HighsLogType::kWarning, "%s\n",
message.str().c_str());
warning_issued = true;
}

message.str(std::string());
order_of_magnitude_message = suggested_bound_scale_order_of_magnitude &&
Expand All @@ -674,9 +703,16 @@ void assessExcessiveObjectiveBoundScaling(const HighsLogOptions log_options,
" setting the user_bound_scale option to %d",
int(user_scale_data.suggested_user_bound_scale));
}
if (order_of_magnitude_message || dl_user_bound_scale)
if (order_of_magnitude_message || dl_user_bound_scale) {
highsLogUser(log_options, HighsLogType::kWarning, "%s\n",
message.str().c_str());
warning_issued = true;
}
if (warning_issued)
highsLogUser(log_options, HighsLogType::kWarning,
"%s is badly scaled, which may compromise the speed, accuracy "
"and reliability of solvers in HiGHS\n",
problem.c_str());
}

bool useIpm(const std::string& solver) {
Expand Down
Loading