Skip to content

Commit f166e24

Browse files
committed
Now to add suggested_user_cost_scale and suggested_user_bound_scale to user_scale_data and generalise assessExcessiveBoundCost
1 parent 3d0254f commit f166e24

File tree

2 files changed

+167
-147
lines changed

2 files changed

+167
-147
lines changed

check/TestUserScale.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ TEST_CASE("user-small-cost-scale", "[highs_user_scale]") {
6565
Highs highs;
6666
const HighsInfo& info = highs.getInfo();
6767
const HighsSolution& solution = highs.getSolution();
68-
highs.setOptionValue("output_flag", dev_run);
68+
// highs.setOptionValue("output_flag", dev_run);
6969
highs.setOptionValue("presolve", kHighsOffString);
7070
HighsLp lp;
7171
lp.num_col_ = 2;

highs/lp_data/HighsSolve.cpp

Lines changed: 166 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
* @brief Class-independent utilities for HiGHS
1010
*/
1111

12+
#include <sstream>
13+
1214
#include "ipm/IpxWrapper.h"
1315
#include "lp_data/HighsSolutionDebug.h"
1416
#include "pdlp/CupdlpWrapper.h"
@@ -347,6 +349,21 @@ HighsStatus solveUnconstrainedLp(const HighsOptions& options, const HighsLp& lp,
347349
void assessExcessiveBoundCost(const HighsLogOptions log_options,
348350
const HighsModel& model,
349351
const HighsUserScaleData& user_scale_data) {
352+
const bool user_cost_or_bound_scale = user_scale_data.user_cost_scale || user_scale_data.user_bound_scale;
353+
std::stringstream message;
354+
if (user_cost_or_bound_scale) {
355+
if (user_scale_data.user_cost_scale)
356+
message << highsFormatToString(" user_cost_scale option value of %d",
357+
user_scale_data.user_cost_scale);
358+
if (user_scale_data.user_bound_scale) {
359+
if (user_scale_data.user_cost_scale) message << " and";
360+
message << highsFormatToString(" user_bound_scale option value of %d",
361+
user_scale_data.user_bound_scale);
362+
}
363+
highsLogUser(log_options, HighsLogType::kInfo,
364+
"Assessing excessive costs or bounds after applying%s\n", message.str().c_str());
365+
}
366+
// Lambda for assessing a finite nonzero
350367
auto assessFiniteNonzero = [&](const double value, double& min_value,
351368
double& max_value) {
352369
double abs_value = std::abs(value);
@@ -439,43 +456,7 @@ void assessExcessiveBoundCost(const HighsLogOptions log_options,
439456
if (lp.num_row_)
440457
highsLogUser(log_options, HighsLogType::kInfo, " RHS [%5.0e, %5.0e]\n",
441458
min_row_bound, max_row_bound);
442-
443-
// Determine recommended user scaling values
444-
HighsInt recommend_user_bound_scale_setting = 0;
445-
HighsInt recommend_user_cost_scale_setting = 0;
446-
double ratio = 1;
447-
if (min_scalable_bound > kExcessivelyLargeBoundValue) {
448-
// All scalable bounds are excessively large, so obviously suggest
449-
// scaling them down
450-
ratio = kExcessivelyLargeBoundValue / min_scalable_bound;
451-
} else if (0 < max_scalable_bound && max_scalable_bound < kExcessivelySmallBoundValue) {
452-
// All scalable bounds are excessively small, so obviously suggest
453-
// scaling them up
454-
ratio = kExcessivelySmallBoundValue / min_scalable_bound;
455-
} else {
456-
if (max_scalable_bound > kExcessivelyLargeBoundValue) {
457-
// Max bound is excessively large, so look to scale it down
458-
ratio = kExcessivelyLargeBoundValue / max_scalable_bound;
459-
if (0 < min_scalable_bound && min_scalable_bound < kExcessivelySmallBoundValue) {
460-
// Min nonzero bound is excessively small: look for balance
461-
462-
} else {
463-
// Ensure that scaling down large bounds doesn't lead to min
464-
// bound being too small
465-
}
466-
} else if (0 < min_scalable_bound && min_scalable_bound < kExcessivelySmallBoundValue) {
467-
// Min bound is excessively small, so look to scale it up,
468-
// ensuring that it doesn't lead to max bounds being too large
469-
}
470-
}
471-
const double user_cost_scale_value =
472-
std::pow(2, user_scale_data.user_cost_scale);
473-
const double user_bound_scale_value =
474-
std::pow(2, user_scale_data.user_bound_scale);
475-
const std::string problem =
476-
(user_scale_data.user_cost_scale || user_scale_data.user_bound_scale)
477-
? "User-scaled problem"
478-
: "Problem";
459+
479460
// LPs with no columns or no finite nonzero costs will have
480461
// max_col_cost = 0
481462
assert(max_col_cost >= 0);
@@ -485,121 +466,160 @@ void assessExcessiveBoundCost(const HighsLogOptions log_options,
485466
// LPs with no rows or no finite nonzero bounds will have
486467
// max_row_bound = 0
487468
assert(max_row_bound >= 0);
488-
489-
if (max_col_cost > kExcessivelyLargeCostValue) {
490-
// Warn that costs are excessively large, and suggest scaling
491-
double ratio =
492-
kExcessivelyLargeCostValue / (max_col_cost / user_cost_scale_value);
493-
HighsInt suggested_user_cost_scale_setting = std::floor(std::log2(ratio));
494-
HighsInt suggested_cost_scale_exponent = std::floor(std::log10(ratio));
495-
highsLogUser(
496-
log_options, HighsLogType::kWarning,
497-
"%s has excessively large costs: consider scaling the costs "
498-
"by 1e%+1d or less, or setting option user_cost_scale to %d or less\n",
499-
problem.c_str(), int(-suggested_cost_scale_exponent),
500-
int(suggested_user_cost_scale_setting));
501-
}
502-
if (max_col_bound > kExcessivelyLargeBoundValue) {
503-
// Warn that bounds are excessively large, and suggest scaling
504-
double ratio =
505-
kExcessivelyLargeBoundValue / (max_col_bound / user_bound_scale_value);
506-
HighsInt suggested_user_bound_scale = std::floor(std::log2(ratio));
507-
HighsInt suggested_bound_scale_exponent = std::floor(std::log10(ratio));
508-
if (lp.isMip()) {
509-
highsLogUser(
510-
log_options, HighsLogType::kWarning,
511-
"%s has excessively large bounds: consider scaling the bounds "
512-
"by 1e%+1d or less\n",
513-
problem.c_str(), int(-suggested_bound_scale_exponent));
514-
} else {
515-
highsLogUser(
516-
log_options, HighsLogType::kWarning,
517-
"%s has excessively large bounds: consider scaling the bounds "
518-
"by 1e%+1d or less, "
519-
"or setting option user_bound_scale to %d or less\n",
520-
problem.c_str(), int(-suggested_bound_scale_exponent),
521-
int(suggested_user_bound_scale));
522-
}
523-
}
524-
if (max_row_bound > kExcessivelyLargeBoundValue) {
525-
// Warn that bounds are excessively large, and suggest scaling
526-
double ratio =
527-
kExcessivelyLargeBoundValue / (max_row_bound / user_bound_scale_value);
528-
HighsInt suggested_user_bound_scale = std::floor(std::log2(ratio));
529-
HighsInt suggested_bound_scale_exponent = std::floor(std::log10(ratio));
530-
if (lp.isMip()) {
531-
highsLogUser(
532-
log_options, HighsLogType::kWarning,
533-
"%s has excessively large bounds: consider scaling the bounds "
534-
"by 1e%+1d or less\n",
535-
problem.c_str(), int(-suggested_bound_scale_exponent));
469+
470+
const std::string problem = user_cost_or_bound_scale ? "User-scaled problem" : "Problem";
471+
472+
if (0 < min_col_cost && min_col_cost < kExcessivelySmallCostValue)
473+
highsLogUser(log_options, HighsLogType::kWarning,
474+
"%s has excessively small costs\n", problem.c_str());
475+
if (max_col_cost > kExcessivelyLargeCostValue)
476+
highsLogUser(log_options, HighsLogType::kWarning,
477+
"%s has excessively large costs\n", problem.c_str());
478+
479+
if (0 < min_col_bound && min_col_bound < kExcessivelySmallBoundValue)
480+
highsLogUser(log_options, HighsLogType::kWarning,
481+
"%s has excessively small column bounds\n", problem.c_str());
482+
if (max_col_bound > kExcessivelyLargeBoundValue)
483+
highsLogUser(log_options, HighsLogType::kWarning,
484+
"%s has excessively large column bounds\n", problem.c_str());
485+
486+
if (0 < min_row_bound && min_row_bound < kExcessivelySmallBoundValue)
487+
highsLogUser(log_options, HighsLogType::kWarning,
488+
"%s has excessively small row bounds\n", problem.c_str());
489+
if (max_row_bound > kExcessivelyLargeBoundValue)
490+
highsLogUser(log_options, HighsLogType::kWarning,
491+
"%s has excessively large row bounds\n", problem.c_str());
492+
493+
// Determine recommended user scaling values
494+
auto suggestScaling = [&](double min_value, double max_value, double small_value, double large_value) {
495+
double ratio = 1;
496+
if (min_value > large_value) {
497+
// All scalable values are excessively large, so obviously suggest
498+
// scaling them down
499+
ratio = 1.0 / min_value;
500+
assert(0 == 11);
501+
} else if (0 < max_value && max_value < small_value) {
502+
// All scalable values are excessively small, so obviously suggest
503+
// scaling them up
504+
ratio = 1.0 / max_value;
536505
} else {
537-
highsLogUser(
538-
log_options, HighsLogType::kWarning,
539-
"%s has excessively large bounds: consider scaling the bounds "
540-
"by 1e%+1d or less, "
541-
"or setting option user_bound_scale to %d or less\n",
542-
problem.c_str(), int(-suggested_bound_scale_exponent),
543-
int(suggested_user_bound_scale));
506+
if (max_value > large_value) {
507+
// Max value is excessively large, so look to scale it down
508+
if (0 < min_value) {
509+
// Chance that small values may be scaled down below
510+
// small_value, so look for balance
511+
ratio = 1.0 / max_value;
512+
if (ratio * min_value < small_value) {
513+
ratio = std::sqrt(1.0 / (max_value * min_value));
514+
assert(0 == 325);
515+
}
516+
assert(0 == 33);
517+
} else {
518+
ratio = 1.0 / max_value;
519+
assert(0 == 44);
520+
}
521+
} else if (0 < min_value && min_value < small_value) {
522+
// Min value is excessively small, so look to scale it up,
523+
if (0 < max_value) {
524+
// Chance that large values may be scaled up above
525+
// large_value, so look for balance
526+
ratio = 1.0 / min_value;
527+
if (ratio * max_value > large_value) {
528+
ratio = std::sqrt(1.0 / (max_value * min_value));
529+
assert(0 == 545);
530+
}
531+
assert(0 == 55);
532+
} else {
533+
ratio = 1.0 / min_value;
534+
assert(0 == 66);
535+
}
536+
}
544537
}
545-
}
546-
// Now consider warning relating to small maximum costs and bounds
547-
if (max_col_cost > 0 && max_col_cost < kExcessivelySmallCostValue) {
548-
// Warn that costs are excessively small, and suggest scaling
549-
double ratio =
550-
kExcessivelySmallCostValue / (max_col_cost / user_cost_scale_value);
551-
HighsInt suggested_user_cost_scale_setting = std::ceil(std::log2(ratio));
552-
HighsInt suggested_cost_scale_exponent = std::ceil(std::log10(ratio));
553-
highsLogUser(
554-
log_options, HighsLogType::kWarning,
555-
"%s has excessively small costs: consider scaling the costs up "
556-
"by 1e%+1d or more, "
557-
"or setting option user_cost_scale to %d or more\n",
558-
problem.c_str(), int(suggested_cost_scale_exponent),
559-
int(suggested_user_cost_scale_setting));
560-
}
561-
if (max_col_bound > 0 && max_col_bound < kExcessivelySmallBoundValue) {
562-
// Warn that bounds are excessively small, and suggest scaling
563-
double ratio =
564-
kExcessivelySmallBoundValue / (max_col_bound / user_bound_scale_value);
565-
HighsInt suggested_user_bound_scale = std::ceil(std::log2(ratio));
566-
HighsInt suggested_bound_scale_exponent = std::ceil(std::log10(ratio));
567-
if (lp.isMip()) {
568-
highsLogUser(
569-
log_options, HighsLogType::kWarning,
570-
"%s has excessively small bounds: consider scaling the bounds "
571-
"by 1e%+1d or more\n",
572-
problem.c_str(), int(suggested_bound_scale_exponent));
538+
assert(ratio);
539+
return ratio;
540+
};
541+
542+
double suggested_bound_scaling = suggestScaling(min_scalable_bound,
543+
max_scalable_bound,
544+
kExcessivelySmallBoundValue,
545+
kExcessivelyLargeBoundValue);
546+
// Determine the suggested (new) value for user_bound_scale,
547+
// allowing for the fact that the current value has been applied
548+
HighsInt suggested_user_bound_scale =
549+
user_scale_data.user_bound_scale +
550+
std::ceil(std::log2(suggested_bound_scaling));
551+
// Determine the order of magnitude of the suggested bound scaling -
552+
// just for logging
553+
HighsInt suggested_bound_scale_order_of_magnitude =
554+
std::ceil(std::log10(suggested_bound_scaling));
555+
// Applying the suggested bound scaling requires the costs and
556+
// matrix columns of non-continuous variables to be scaled
557+
//
558+
// Determine the corresponding extreme non-continuous costs and
559+
// update the extreme costs so that cost scalign can be suggested
560+
double suggested_user_bound_scale_value = pow(2.0, suggested_user_bound_scale);
561+
min_noncontinuous_col_cost *= suggested_user_bound_scale_value;
562+
max_noncontinuous_col_cost *= suggested_user_bound_scale_value;
563+
min_col_cost =
564+
std::min(min_continuous_col_cost, min_noncontinuous_col_cost);
565+
max_col_cost =
566+
std::max(max_continuous_col_cost, max_noncontinuous_col_cost);
567+
if (min_col_cost == kHighsInf) min_col_cost = 0;
568+
if (max_col_cost == -kHighsInf) max_col_cost = 0;
569+
570+
double suggested_cost_scaling = suggestScaling(min_col_cost,
571+
max_col_cost,
572+
kExcessivelySmallCostValue,
573+
kExcessivelyLargeCostValue);
574+
// Determine the suggested (new) value for user_cost_scale,
575+
// allowing for the fact that the current value has been applied
576+
HighsInt suggested_user_cost_scale =
577+
user_scale_data.user_cost_scale +
578+
std::ceil(std::log2(suggested_cost_scaling));
579+
// Determine the order of magnitude of the suggested cost scaling -
580+
// just for logging
581+
HighsInt suggested_cost_scale_order_of_magnitude =
582+
std::ceil(std::log10(suggested_cost_scaling));
583+
584+
// Only report the order of magnitude scaling if there is no user
585+
// scaling
586+
bool order_of_magnitude_message =
587+
suggested_cost_scale_order_of_magnitude &&
588+
!user_scale_data.user_cost_scale;
589+
message.str(std::string());
590+
if (order_of_magnitude_message)
591+
message << highsFormatToString(" Consider scaling the costs by 1e%+1d",
592+
int(suggested_cost_scale_order_of_magnitude));
593+
if (suggested_user_cost_scale) {
594+
if (!order_of_magnitude_message) {
595+
message << " Consider";
573596
} else {
574-
highsLogUser(
575-
log_options, HighsLogType::kWarning,
576-
"%s has excessively small bounds: consider scaling the bounds "
577-
"by 1e%+1d or more, "
578-
"or setting option user_bound_scale to %d or more\n",
579-
problem.c_str(), int(suggested_bound_scale_exponent),
580-
int(suggested_user_bound_scale));
597+
message << ", or";
581598
}
599+
message << highsFormatToString(" setting the user_cost_scale option to %d\n",
600+
int(suggested_user_cost_scale));
582601
}
583-
if (max_row_bound > 0 && max_row_bound < kExcessivelySmallBoundValue) {
584-
// Warn that bounds are excessively small, and suggest scaling
585-
double ratio =
586-
kExcessivelySmallBoundValue / (max_row_bound / user_bound_scale_value);
587-
HighsInt suggested_user_bound_scale = std::ceil(std::log2(ratio));
588-
HighsInt suggested_bound_scale_exponent = std::ceil(std::log10(ratio));
589-
if (lp.isMip()) {
590-
highsLogUser(
591-
log_options, HighsLogType::kWarning,
592-
"%s has excessively small bounds: consider scaling the bounds "
593-
"by 1e%+1d or more\n",
594-
problem.c_str(), int(suggested_bound_scale_exponent));
602+
if (order_of_magnitude_message || suggested_user_cost_scale)
603+
highsLogUser(log_options, HighsLogType::kWarning, "%s\n", message.str().c_str());
604+
605+
message.str(std::string());
606+
order_of_magnitude_message =
607+
suggested_bound_scale_order_of_magnitude &&
608+
!user_scale_data.user_bound_scale;
609+
message.str(std::string());
610+
if (order_of_magnitude_message)
611+
message << highsFormatToString(" Consider scaling the bounds by 1e%+1d",
612+
int(suggested_bound_scale_order_of_magnitude));
613+
if (suggested_user_bound_scale) {
614+
if (!order_of_magnitude_message) {
615+
message << " Consider";
595616
} else {
596-
highsLogUser(
597-
log_options, HighsLogType::kWarning,
598-
"%s has excessively small bounds: consider scaling the bounds "
599-
"by 1e%+1d or more, "
600-
"or setting option user_bound_scale to %d or more\n",
601-
problem.c_str(), int(suggested_bound_scale_exponent),
602-
int(suggested_user_bound_scale));
617+
message << ", or";
603618
}
619+
message << highsFormatToString(" setting the user_bound_scale option to %d\n",
620+
int(suggested_user_bound_scale));
604621
}
622+
if (order_of_magnitude_message || suggested_user_bound_scale)
623+
highsLogUser(log_options, HighsLogType::kWarning, "%s\n", message.str().c_str());
624+
605625
}

0 commit comments

Comments
 (0)