| 117 | } |
| 118 | |
| 119 | bool checkDualRayValue(Highs& highs, const vector<double>& dual_ray_value) { |
| 120 | const HighsLp& lp = highs.getLp(); |
| 121 | HighsInt numCol = lp.num_col_; |
| 122 | HighsInt numRow = lp.num_row_; |
| 123 | double ray_error_norm = 0; |
| 124 | const vector<double>& rowLower = lp.row_lower_; |
| 125 | const vector<double>& rowUpper = lp.row_upper_; |
| 126 | const vector<HighsBasisStatus>& col_status = highs.getBasis().col_status; |
| 127 | const vector<HighsBasisStatus>& row_status = highs.getBasis().row_status; |
| 128 | vector<double> dual_unboundedness_direction_value; |
| 129 | dual_unboundedness_direction_value.assign(numCol, 0.0); |
| 130 | for (HighsInt iCol = 0; iCol < numCol; iCol++) { |
| 131 | if (col_status[iCol] == HighsBasisStatus::kBasic) continue; |
| 132 | // Get the tableau row entry for this nonbasic column |
| 133 | for (HighsInt iEl = lp.a_matrix_.start_[iCol]; |
| 134 | iEl < lp.a_matrix_.start_[iCol + 1]; iEl++) |
| 135 | dual_unboundedness_direction_value[iCol] += |
| 136 | dual_ray_value[lp.a_matrix_.index_[iEl]] * lp.a_matrix_.value_[iEl]; |
| 137 | } |
| 138 | bool check_ok = checkDualUnboundednessDirection( |
| 139 | highs, dual_unboundedness_direction_value); |
| 140 | if (!check_ok) return check_ok; |
| 141 | for (HighsInt iRow = 0; iRow < numRow; iRow++) { |
| 142 | if (row_status[iRow] == HighsBasisStatus::kBasic || |
| 143 | rowLower[iRow] == rowUpper[iRow]) |
| 144 | continue; |
| 145 | if (row_status[iRow] == HighsBasisStatus::kLower) { |
| 146 | // At lower bound so value should be non-negative |
| 147 | if (dual_ray_value[iRow] < 0) { |
| 148 | ray_error_norm += fabs(dual_ray_value[iRow]); |
| 149 | if (dual_ray_value[iRow] < -zero_ray_value_tolerance && dev_run) |
| 150 | printf("Row %3" HIGHSINT_FORMAT |
| 151 | " is at lower bound so dual step should be " |
| 152 | "non-negative, and is %g\n", |
| 153 | iRow, dual_ray_value[iRow]); |
| 154 | } |
| 155 | } else if (row_status[iRow] == HighsBasisStatus::kUpper) { |
| 156 | // At upper bound so value should be non-positive |
| 157 | if (dual_ray_value[iRow] > 0) { |
| 158 | ray_error_norm += fabs(dual_ray_value[iRow]); |
| 159 | if (dual_ray_value[iRow] > zero_ray_value_tolerance && dev_run) |
| 160 | printf("Row %3" HIGHSINT_FORMAT |
| 161 | " is at upper bound so dual step should be " |
| 162 | "non-positive, and is %g\n", |
| 163 | iRow, dual_ray_value[iRow]); |
| 164 | } |
| 165 | } else { |
| 166 | // Free so value should be zero |
| 167 | assert(row_status[iRow] == HighsBasisStatus::kZero); |
| 168 | if (fabs(dual_ray_value[iRow]) > 0) { |
| 169 | ray_error_norm += fabs(dual_ray_value[iRow]); |
| 170 | if (fabs(dual_ray_value[iRow]) > zero_ray_value_tolerance && dev_run) |
| 171 | printf("Row %3" HIGHSINT_FORMAT |
| 172 | " is free so dual step should be zero, and is %g\n", |
| 173 | iRow, dual_ray_value[iRow]); |
| 174 | } |
| 175 | } |
| 176 | } |
no test coverage detected