Skip to content

Commit b62c64e

Browse files
committed
Now to test inline std::pair<double, double> infeasiblity
1 parent 19b13ec commit b62c64e

File tree

2 files changed

+72
-0
lines changed

2 files changed

+72
-0
lines changed

highs/lp_data/HighsSolution.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,12 @@ void getVariableKktFailures(const double primal_feasibility_tolerance,
561561
// Above upper
562562
primal_infeasibility = value - upper;
563563
}
564+
std::pair<double, double> infeasiblity_residual =
565+
infeasiblity(&lower, &value, &upper, &primal_feasibility_tolerance);
566+
// #2653
567+
//
568+
// assert(infeasiblity_residual.second == primal_infeasibility);
569+
564570
// Determine whether this value is close to a bound
565571
at_status = kHighsSolutionNo;
566572
double residual = std::fabs(lower - value);

highs/util/HighsUtils.h

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,4 +214,70 @@ inline T fractionality(T input, T* intval = nullptr) {
214214
if (intval != nullptr) *intval = val;
215215
return abs(input - val);
216216
}
217+
218+
inline std::pair<double, double> infeasiblity(const double* lower,
219+
const double* value,
220+
const double* upper,
221+
const double* tolerance) {
222+
using std::fabs;
223+
using std::min;
224+
double residual = 0;
225+
double infeasiblity = 0;
226+
std::string bound_type = "";
227+
double bound_value = 0;
228+
// Determine the infeasiblity exceeding the tolerance used in
229+
// computing the number of infeasibilities - which defines
230+
// feasibility of a solution
231+
if (*value < *lower - *tolerance) {
232+
infeasiblity = *lower - *value;
233+
}
234+
if (*value > *upper + *tolerance) {
235+
infeasiblity = *value - *upper;
236+
}
237+
// Determine the residual used in computing the sum of
238+
// infeasibilities and max infeasibility - which are just for
239+
// reporting
240+
if (*tolerance > 0) {
241+
if (*value < *lower) {
242+
bound_type = "LB";
243+
bound_value = *lower;
244+
residual = *lower - *value;
245+
}
246+
if (*value > *upper) {
247+
bound_type = "UB";
248+
bound_value = *upper;
249+
residual = *value - *upper;
250+
}
251+
} else {
252+
residual = infeasiblity;
253+
}
254+
// Now, if the bound defining the residual is large, it's possible
255+
// for the infeasiblity to be zero, but the residual to exceed the
256+
// tolerance due to numerical rounding
257+
//
258+
// Case in point is #2653 where row 1 has l = 157345 and the
259+
// activity gives zero infeasiblity, but a residual of
260+
// 1.00000761449e-06, exceeding the tolerance of 1e-6 by delta =
261+
// 7.61449e-12.
262+
//
263+
// Now delta / l = 4.83937e-17, which is less than machine precision
264+
// (2.22045e-16), so the reliable residual value should ignore this
265+
// delta.
266+
//
267+
// In general, it might be possible to subtract delta from the
268+
// residual conditional on (something like)
269+
//
270+
// delta < 1e1 * max(1.0, fabs(bound_value)) * kHighsMacheps
271+
//
272+
// to give a reasonable value but, in practice, when infeasiblity is
273+
// 0, it would seem fine to set
274+
//
275+
// residual = min(residual, tolerance)
276+
//
277+
// so that values of maximum infeasibility defined by residual
278+
// doesn't exceed the tolerance
279+
//
280+
// if (infeasiblity == 0) residual = min(residual, *tolerance);
281+
return std::make_pair(infeasiblity, residual);
282+
}
217283
#endif // UTIL_HIGHSUTILS_H_

0 commit comments

Comments
 (0)