-
Notifications
You must be signed in to change notification settings - Fork 306
Allow slightly asymmetric square Hessians, and revert to using HighsHashTable (mainly) In assessMatrix
#2984
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
5e052e9
adbbfc6
0c202f8
4ec0e8b
25e2bf1
4816a03
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -403,10 +403,17 @@ HighsStatus normaliseHessian(const HighsOptions& options, | |
| upper_off_diagonal.assign(dim, 0); | ||
| // Should be no duplicates | ||
| HighsInt debug_num_duplicate = 0; | ||
| HighsInt num_non_symmetric = 0; | ||
| HighsInt num_summation = 0; | ||
| HighsInt num_upper_triangle = 0; | ||
| HighsInt num_hessian_el = 0; | ||
| const double kSquareHessianAsymmetryTolerance = 1e-10; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Open question whether to hard-code this or make it an option. The argument in favour of this hard-coding is that anyone wanting to change it needs a really good reason, and they should almost certainly just use the triangular input.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd rather hard code it, as you do in JuMP. If the difference is larger than 1e-10 due to inexact arithmetic, then users should be aware and handling it themselves |
||
| HighsInt num_illegal_asymmetry = 0; | ||
| double min_illegal_asymmetry = kHighsInf; | ||
| double max_illegal_asymmetry = 0; | ||
| HighsInt num_ok_asymmetry = 0; | ||
| double min_ok_asymmetry = kHighsInf; | ||
| double max_ok_asymmetry = 0; | ||
|
|
||
| // const bool expensive_2821_check = true; | ||
| for (HighsInt iCol = 0; iCol < dim; iCol++) { | ||
| for (HighsInt iEl = from_hessian.start_[iCol]; | ||
|
|
@@ -427,9 +434,23 @@ HighsStatus normaliseHessian(const HighsOptions& options, | |
| upper_off_diagonal[iRow] = upper.value_[iEl]; | ||
| if (square) { | ||
| // When square, ensure that the upper triangular value matches | ||
| // the corresponding lower triangular value | ||
| if (upper_off_diagonal[iRow] != lower_on_below_diagonal[iRow]) | ||
| num_non_symmetric++; | ||
| // the corresponding lower triangular value to within the | ||
| // tolaernace used by JuMP | ||
| const double asymmetry = | ||
| std::fabs(upper_off_diagonal[iRow] - lower_on_below_diagonal[iRow]); | ||
| if (asymmetry > kSquareHessianAsymmetryTolerance) { | ||
| num_illegal_asymmetry++; | ||
| min_illegal_asymmetry = std::min(asymmetry, min_illegal_asymmetry); | ||
| max_illegal_asymmetry = std::max(asymmetry, max_illegal_asymmetry); | ||
| } else if (asymmetry) { | ||
| num_ok_asymmetry++; | ||
| min_ok_asymmetry = std::min(asymmetry, min_ok_asymmetry); | ||
| max_ok_asymmetry = std::max(asymmetry, max_ok_asymmetry); | ||
| double average = | ||
| (upper_off_diagonal[iRow] + lower_on_below_diagonal[iRow]) * 0.5; | ||
| upper_off_diagonal[iRow] = average; | ||
| lower_on_below_diagonal[iRow] = average; | ||
| } | ||
| // Don't zero the upper off diagonal entry, so that it's | ||
| // possible to check that nonzeros in the lower off diagonal | ||
| // match the upper off diagonal entry | ||
|
|
@@ -505,11 +526,24 @@ HighsStatus normaliseHessian(const HighsOptions& options, | |
|
|
||
| bool warning_found = false; | ||
| bool error_found = false; | ||
| if (num_non_symmetric) { | ||
| if (num_ok_asymmetry) { | ||
| assert(square); | ||
| highsLogUser(options.log_options, HighsLogType::kInfo, | ||
| "Square Hessian contains %d non-symmetr%s in [%.2g, %.2g] " | ||
| "within tolerance of %.1g\n", | ||
| int(num_ok_asymmetry), num_ok_asymmetry == 1 ? "y" : "ies", | ||
| min_ok_asymmetry, max_ok_asymmetry, | ||
| kSquareHessianAsymmetryTolerance); | ||
| } | ||
| if (num_illegal_asymmetry) { | ||
| assert(square); | ||
| highsLogUser(options.log_options, HighsLogType::kError, | ||
| "Square Hessian contains %d non-symmetr%s\n", | ||
| int(num_non_symmetric), num_non_symmetric == 1 ? "y" : "ies"); | ||
| "Square Hessian contains %d non-symmetr%s in [%.2g, %.2g] " | ||
| "exceeding tolerance of %.1g\n", | ||
| int(num_illegal_asymmetry), | ||
| num_illegal_asymmetry == 1 ? "y" : "ies", | ||
| min_illegal_asymmetry, max_illegal_asymmetry, | ||
| kSquareHessianAsymmetryTolerance); | ||
| error_found = true; | ||
| } | ||
| if (num_upper_triangle) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you benchmark the before/after or should I do it with the Julia example?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When loading the LP neos row-by-row, It's about 3x faster with the two current ways of tracking duplicates than with 1.14. Using HighsHashTable (as before 1.14) is slightly faster than unordered_map (unsurprisingly) so I left that as the default - unless duplicates need to be summed