Gets the KKT failures for a variable. Value and dual are used compute the primal and dual infeasibility It's up to the calling method to ignore these if the value or dual are not valid.
| 565 | // It's up to the calling method to ignore these if the value or dual |
| 566 | // are not valid. |
| 567 | void getVariableKktFailures(const double primal_feasibility_tolerance, |
| 568 | const double dual_feasibility_tolerance, |
| 569 | const double mip_feasibility_tolerance, |
| 570 | const double lower, const double upper, |
| 571 | const double value, const double dual, |
| 572 | const HighsVarType integrality, |
| 573 | double& primal_infeasibility, |
| 574 | double& dual_infeasibility, |
| 575 | double& semi_infeasibility, uint8_t& at_status, |
| 576 | uint8_t& mid_status, const HighsInt index) { |
| 577 | // Return the primal residual (ie infeasibility with zero tolerance) |
| 578 | // as the primal infeasibility, ensuring (cf #2653) that it doesn't |
| 579 | // exceed the primal feasibility tolerance if the standard primal |
| 580 | // infeasibility (ie infeasibility exceeding the tolerance) is zero |
| 581 | auto infeasibility_residual = |
| 582 | infeasibility(lower, value, upper, primal_feasibility_tolerance); |
| 583 | primal_infeasibility = infeasibility_residual.second; |
| 584 | semi_infeasibility = 0; |
| 585 | // Determine whether this value is close to a bound |
| 586 | at_status = kHighsSolutionNo; |
| 587 | double bound_residual = std::fabs(lower - value); |
| 588 | if (bound_residual * bound_residual <= primal_feasibility_tolerance) { |
| 589 | // Close to lower bound |
| 590 | at_status = kHighsSolutionLo; |
| 591 | } else { |
| 592 | // Not close to lower bound: maybe close to upper bound |
| 593 | bound_residual = std::fabs(value - upper); |
| 594 | if (bound_residual * bound_residual <= primal_feasibility_tolerance) |
| 595 | at_status = kHighsSolutionUp; |
| 596 | } |
| 597 | // Look for dual sign errors that exceed the tolerance. For boxed |
| 598 | // variables the test is discontinuous at the midpoint, but any |
| 599 | // meaningful dual value on a meaningful interval will show up as a |
| 600 | // large complementarity error |
| 601 | mid_status = kHighsSolutionNo; |
| 602 | if (lower < upper) { |
| 603 | double length = upper - lower; |
| 604 | // Non-fixed variable |
| 605 | if (lower <= -kHighsInf && upper >= kHighsInf) { |
| 606 | // Free variable |
| 607 | dual_infeasibility = fabs(dual); |
| 608 | } else if (length * length > primal_feasibility_tolerance) { |
| 609 | // Interval length is meaningful |
| 610 | // |
| 611 | // Compute the mid-point of the bound interval. This will be |
| 612 | // +infinity for LB variables; -infinity for UB variables; |
| 613 | // finite for boxed and fixed variables |
| 614 | const double middle = (lower + upper) * 0.5; |
| 615 | if (value < middle) { |
| 616 | // Below the mid-point, so use lower bound optimality condition: |
| 617 | // feasibility is dual >= -tolerance |
| 618 | mid_status = kHighsSolutionLo; |
| 619 | dual_infeasibility = std::max(-dual, 0.); |
| 620 | } else { |
| 621 | // Below the mid-point, so use upper bound optimality condition: |
| 622 | // feasibility is dual <= tolerance |
| 623 | mid_status = kHighsSolutionUp; |
| 624 | dual_infeasibility = std::max(dual, 0.); |
no test coverage detected