#include <cassert>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <set>
#include "io/HighsIO.h"
#include "lp_data/HConst.h"
#include "parallel/HighsParallel.h"
#include "simplex/HEkkDual.h"
#include "simplex/SimplexTimer.h"
using std::cout;
using std::endl;
void HEkkDual::iterateMulti() {
slice_PRICE = 1;
majorChooseRow();
minorChooseRow();
if (row_out == kNoRowChosen) {
rebuild_reason = kRebuildReasonPossiblyOptimal;
return;
}
if (1.0 * multi_finish[multi_nFinish].row_ep->count / solver_num_row < 0.01)
slice_PRICE = 0;
if (slice_PRICE) {
chooseColumnSlice(multi_finish[multi_nFinish].row_ep);
} else {
chooseColumn(multi_finish[multi_nFinish].row_ep);
}
if (rebuild_reason) {
if (multi_nFinish) {
majorUpdate();
} else {
highsLogDev(
ekk_instance_.options_->log_options, HighsLogType::kWarning,
"PAMI skipping majorUpdate() due to multi_nFinish = %" HIGHSINT_FORMAT
"; "
"rebuild_reason = %" HIGHSINT_FORMAT "\n",
multi_nFinish, rebuild_reason);
}
return;
}
minorUpdate();
majorUpdate();
}
void HEkkDual::majorChooseRow() {
if (ekk_instance_.info_.update_count == 0) multi_chooseAgain = 1;
if (!multi_chooseAgain) return;
multi_chooseAgain = 0;
multi_iteration++;
std::vector<HighsInt> choiceIndex(multi_num, 0);
std::vector<double>& edge_weight = ekk_instance_.dual_edge_weight_;
for (;;) {
HighsInt initialCount = 0;
dualRHS.chooseMultiHyperGraphAuto(choiceIndex.data(), &initialCount,
multi_num);
if (initialCount == 0 && dualRHS.workCutoff == 0) {
return;
}
HighsInt choiceCount = 0;
for (HighsInt i = 0; i < initialCount; i++) {
HighsInt iRow = choiceIndex[i];
if (dualRHS.work_infeasibility[iRow] / edge_weight[iRow] >=
dualRHS.workCutoff) {
choiceIndex[choiceCount++] = iRow;
}
}
if (initialCount == 0 || choiceCount <= initialCount / 3) {
dualRHS.createInfeasList(ekk_instance_.info_.col_aq_density);
continue;
}
for (HighsInt ich = 0; ich < multi_num; ich++)
multi_choice[ich].row_out = kNoRowChosen;
for (HighsInt ich = 0; ich < choiceCount; ich++)
multi_choice[ich].row_out = choiceIndex[ich];
majorChooseRowBtran();
for (HighsInt ich = 0; ich < multi_num; ich++) {
if (multi_choice[ich].row_out >= 0) {
const double local_row_ep_density =
(double)multi_choice[ich].row_ep.count / solver_num_row;
ekk_instance_.updateOperationResultDensity(
local_row_ep_density, ekk_instance_.info_.row_ep_density);
}
}
if (edge_weight_mode == EdgeWeightMode::kSteepestEdge) {
HighsInt countWrongEdWt = 0;
for (HighsInt i = 0; i < multi_num; i++) {
const HighsInt iRow = multi_choice[i].row_out;
if (iRow < 0) continue;
double updated_edge_weight = edge_weight[iRow];
computed_edge_weight = edge_weight[iRow] = multi_choice[i].infeasEdWt;
if (!acceptDualSteepestEdgeWeight(updated_edge_weight)) {
multi_choice[i].row_out = kNoRowChosen;
countWrongEdWt++;
}
}
if (countWrongEdWt <= choiceCount / 3) break;
} else {
break;
}
}
multi_chosen = 0;
const double kPamiCutoff = 0.95;
for (HighsInt i = 0; i < multi_num; i++) {
const HighsInt iRow = multi_choice[i].row_out;
if (iRow < 0) continue;
multi_chosen++;
multi_choice[i].baseValue = baseValue[iRow];
multi_choice[i].baseLower = baseLower[iRow];
multi_choice[i].baseUpper = baseUpper[iRow];
multi_choice[i].infeasValue = dualRHS.work_infeasibility[iRow];
multi_choice[i].infeasEdWt = edge_weight[iRow];
multi_choice[i].infeasLimit =
dualRHS.work_infeasibility[iRow] / edge_weight[iRow];
multi_choice[i].infeasLimit *= kPamiCutoff;
}
multi_nFinish = 0;
}
void HEkkDual::majorChooseRowBtran() {
analysis->simplexTimerStart(BtranClock);
HighsInt multi_ntasks = 0;
HighsInt multi_iRow[kSimplexConcurrencyLimit];
HighsInt multi_iwhich[kSimplexConcurrencyLimit];
double multi_EdWt[kSimplexConcurrencyLimit];
HVector_ptr multi_vector[kSimplexConcurrencyLimit];
for (HighsInt ich = 0; ich < multi_num; ich++) {
if (multi_choice[ich].row_out >= 0) {
multi_iRow[multi_ntasks] = multi_choice[ich].row_out;
multi_vector[multi_ntasks] = &multi_choice[ich].row_ep;
multi_iwhich[multi_ntasks] = ich;
multi_ntasks++;
}
}
if (analysis->analyse_simplex_summary_data) {
for (HighsInt i = 0; i < multi_ntasks; i++)
analysis->operationRecordBefore(kSimplexNlaBtranEp, 1,
ekk_instance_.info_.row_ep_density);
}
std::vector<double>& edge_weight = ekk_instance_.dual_edge_weight_;
highs::parallel::for_each(0, multi_ntasks, [&](HighsInt start, HighsInt end) {
for (HighsInt i = start; i < end; i++) {
const HighsInt iRow = multi_iRow[i];
HVector_ptr work_ep = multi_vector[i];
work_ep->clear();
work_ep->count = 1;
work_ep->index[0] = iRow;
work_ep->array[iRow] = 1;
work_ep->packFlag = true;
HighsTimerClock* factor_timer_clock_pointer =
analysis->getThreadFactorTimerClockPointer();
ekk_instance_.simplex_nla_.btran(*work_ep,
ekk_instance_.info_.row_ep_density,
factor_timer_clock_pointer);
if (edge_weight_mode == EdgeWeightMode::kSteepestEdge) {
multi_EdWt[i] = work_ep->norm2();
} else {
multi_EdWt[i] = edge_weight[iRow];
}
}
});
if (analysis->analyse_simplex_summary_data) {
for (HighsInt i = 0; i < multi_ntasks; i++)
analysis->operationRecordAfter(kSimplexNlaBtranEp,
multi_vector[i]->count);
}
for (HighsInt i = 0; i < multi_ntasks; i++)
multi_choice[multi_iwhich[i]].infeasEdWt = multi_EdWt[i];
analysis->simplexTimerStop(BtranClock);
}
void HEkkDual::minorChooseRow() {
multi_iChoice = -1;
double bestMerit = 0;
for (HighsInt ich = 0; ich < multi_num; ich++) {
const HighsInt iRow = multi_choice[ich].row_out;
if (iRow < 0) continue;
double infeasValue = multi_choice[ich].infeasValue;
double infeasEdWt = multi_choice[ich].infeasEdWt;
double infeasMerit = infeasValue / infeasEdWt;
if (bestMerit < infeasMerit) {
bestMerit = infeasMerit;
multi_iChoice = ich;
}
}
row_out = kNoRowChosen;
if (multi_iChoice != -1) {
MChoice* workChoice = &multi_choice[multi_iChoice];
row_out = workChoice->row_out;
variable_out = ekk_instance_.basis_.basicIndex_[row_out];
double valueOut = workChoice->baseValue;
double lowerOut = workChoice->baseLower;
double upperOut = workChoice->baseUpper;
delta_primal = valueOut - (valueOut < lowerOut ? lowerOut : upperOut);
move_out = delta_primal < 0 ? -1 : 1;
MFinish* finish = &multi_finish[multi_nFinish];
finish->row_out = row_out;
finish->variable_out = variable_out;
finish->row_ep = &workChoice->row_ep;
finish->col_aq = &workChoice->col_aq;
finish->col_BFRT = &workChoice->col_BFRT;
finish->EdWt = workChoice->infeasEdWt;
workChoice->row_out = kNoRowChosen;
}
}
void HEkkDual::minorUpdate() {
MFinish* finish = &multi_finish[multi_nFinish];
finish->move_in = ekk_instance_.basis_.nonbasicMove_[variable_in];
finish->shiftOut = ekk_instance_.info_.workShift_[variable_out];
finish->flipList.clear();
for (HighsInt i = 0; i < dualRow.workCount; i++)
finish->flipList.push_back(dualRow.workData[i].first);
minorUpdateDual();
minorUpdatePrimal();
minorUpdatePivots();
minorUpdateRows();
if (minor_new_devex_framework) {
minorInitialiseDevexFramework();
}
multi_nFinish++;
iterationAnalysisMinor();
HighsInt countRemain = 0;
for (HighsInt i = 0; i < multi_num; i++) {
HighsInt iRow = multi_choice[i].row_out;
if (iRow < 0) continue;
double myInfeas = multi_choice[i].infeasValue;
double myWeight = multi_choice[i].infeasEdWt;
countRemain += (myInfeas / myWeight > multi_choice[i].infeasLimit);
}
if (countRemain == 0) multi_chooseAgain = 1;
}
void HEkkDual::minorUpdateDual() {
if (theta_dual == 0) {
shiftCost(variable_in, -workDual[variable_in]);
} else {
dualRow.updateDual(theta_dual);
if (slice_PRICE) {
for (HighsInt i = 0; i < slice_num; i++)
slice_dualRow[i].updateDual(theta_dual);
}
}
workDual[variable_in] = 0;
workDual[variable_out] = -theta_dual;
shiftBack(variable_out);
dualRow.updateFlip(multi_finish[multi_nFinish].col_BFRT);
for (HighsInt ich = 0; ich < multi_num; ich++) {
if (ich == multi_iChoice || multi_choice[ich].row_out >= 0) {
HVector* this_ep = &multi_choice[ich].row_ep;
for (HighsInt i = 0; i < dualRow.workCount; i++) {
double dot = a_matrix->computeDot(*this_ep, dualRow.workData[i].first);
multi_choice[ich].baseValue -= dualRow.workData[i].second * dot;
}
}
}
}
void HEkkDual::minorUpdatePrimal() {
MChoice* choice = &multi_choice[multi_iChoice];
MFinish* finish = &multi_finish[multi_nFinish];
double valueOut = choice->baseValue;
double lowerOut = choice->baseLower;
double upperOut = choice->baseUpper;
if (delta_primal < 0) {
theta_primal = (valueOut - lowerOut) / alpha_row;
finish->basicBound = lowerOut;
}
if (delta_primal > 0) {
theta_primal = (valueOut - upperOut) / alpha_row;
finish->basicBound = upperOut;
}
finish->theta_primal = theta_primal;
if (edge_weight_mode == EdgeWeightMode::kDevex && !new_devex_framework) {
std::vector<double>& edge_weight = ekk_instance_.dual_edge_weight_;
assert(row_out >= 0);
if (row_out < 0)
printf("ERROR: row_out = %" HIGHSINT_FORMAT " in minorUpdatePrimal\n",
row_out);
const double updated_edge_weight = edge_weight[row_out];
new_devex_framework = newDevexFramework(updated_edge_weight);
minor_new_devex_framework = new_devex_framework;
double new_pivotal_edge_weight =
computed_edge_weight / (alpha_row * alpha_row);
new_pivotal_edge_weight = max(1.0, new_pivotal_edge_weight);
finish->EdWt = new_pivotal_edge_weight;
}
for (HighsInt ich = 0; ich < multi_num; ich++) {
if (multi_choice[ich].row_out >= 0) {
HVector* this_ep = &multi_choice[ich].row_ep;
double dot = a_matrix->computeDot(*this_ep, variable_in);
multi_choice[ich].baseValue -= theta_primal * dot;
double value = multi_choice[ich].baseValue;
double lower = multi_choice[ich].baseLower;
double upper = multi_choice[ich].baseUpper;
double infeas = 0;
if (value < lower - Tp) infeas = value - lower;
if (value > upper + Tp) infeas = value - upper;
infeas *= infeas;
multi_choice[ich].infeasValue = infeas;
if (edge_weight_mode == EdgeWeightMode::kDevex) {
const double new_pivotal_edge_weight = finish->EdWt;
double aa_iRow = dot;
multi_choice[ich].infeasEdWt =
max(multi_choice[ich].infeasEdWt,
new_pivotal_edge_weight * aa_iRow * aa_iRow);
}
}
}
}
void HEkkDual::minorUpdatePivots() {
MFinish* finish = &multi_finish[multi_nFinish];
ekk_instance_.updatePivots(variable_in, row_out, move_out);
if (edge_weight_mode == EdgeWeightMode::kSteepestEdge) {
finish->EdWt /= (alpha_row * alpha_row);
}
finish->basicValue =
ekk_instance_.info_.workValue_[variable_in] + theta_primal;
ekk_instance_.updateMatrix(variable_in, variable_out);
finish->variable_in = variable_in;
finish->alpha_row = alpha_row;
numericalTrouble = -1;
ekk_instance_.iteration_count_++;
}
void HEkkDual::minorUpdateRows() {
analysis->simplexTimerStart(UpdateRowClock);
const HVector* Row = multi_finish[multi_nFinish].row_ep;
HighsInt updateRows_inDense =
(Row->count < 0) || (Row->count > 0.1 * solver_num_row);
if (updateRows_inDense) {
HighsInt multi_nTasks = 0;
HighsInt multi_iwhich[kSimplexConcurrencyLimit];
double multi_xpivot[kSimplexConcurrencyLimit];
HVector_ptr multi_vector[kSimplexConcurrencyLimit];
for (HighsInt ich = 0; ich < multi_num; ich++) {
if (multi_choice[ich].row_out >= 0) {
HVector* next_ep = &multi_choice[ich].row_ep;
double pivotX = a_matrix->computeDot(*next_ep, variable_in);
if (fabs(pivotX) < kHighsTiny) continue;
multi_vector[multi_nTasks] = next_ep;
multi_xpivot[multi_nTasks] = -pivotX / alpha_row;
multi_iwhich[multi_nTasks] = ich;
multi_nTasks++;
}
}
highs::parallel::for_each(
0, multi_nTasks, [&](HighsInt start, HighsInt end) {
for (HighsInt i = start; i < end; i++) {
HVector_ptr nextEp = multi_vector[i];
const double xpivot = multi_xpivot[i];
nextEp->saxpy(xpivot, Row);
nextEp->tight();
if (edge_weight_mode == EdgeWeightMode::kSteepestEdge) {
multi_xpivot[i] = nextEp->norm2();
}
}
});
if (edge_weight_mode == EdgeWeightMode::kSteepestEdge) {
for (HighsInt i = 0; i < multi_nTasks; i++)
multi_choice[multi_iwhich[i]].infeasEdWt = multi_xpivot[i];
}
} else {
for (HighsInt ich = 0; ich < multi_num; ich++) {
if (multi_choice[ich].row_out >= 0) {
HVector* next_ep = &multi_choice[ich].row_ep;
double pivotX = a_matrix->computeDot(*next_ep, variable_in);
if (fabs(pivotX) < kHighsTiny) continue;
next_ep->saxpy(-pivotX / alpha_row, Row);
next_ep->tight();
if (edge_weight_mode == EdgeWeightMode::kSteepestEdge) {
multi_choice[ich].infeasEdWt = next_ep->norm2();
}
}
}
}
analysis->simplexTimerStop(UpdateRowClock);
}
void HEkkDual::minorInitialiseDevexFramework() {
for (HighsInt i = 0; i < multi_num; i++) {
multi_choice[i].infeasEdWt = 1.0;
}
minor_new_devex_framework = false;
}
void HEkkDual::majorUpdate() {
if (rebuild_reason) multi_chooseAgain = 1;
if (!multi_chooseAgain) return;
majorUpdateFtranPrepare();
majorUpdateFtranParallel();
majorUpdateFtranFinal();
for (HighsInt iFn = 0; iFn < multi_nFinish; iFn++) {
MFinish* iFinish = &multi_finish[iFn];
HVector* iColumn = iFinish->col_aq;
HighsInt iRow_Out = iFinish->row_out;
if (ekk_instance_.reinvertOnNumericalTrouble(
"HEkkDual::majorUpdate", numericalTrouble, iColumn->array[iRow_Out],
iFinish->alpha_row, kMultiNumericalTroubleTolerance)) {
rebuild_reason = kRebuildReasonPossiblySingularBasis;
majorRollback();
return;
}
}
majorUpdatePrimal();
majorUpdateFactor();
if (new_devex_framework) initialiseDevexFramework();
iterationAnalysisMajor();
}
void HEkkDual::majorUpdateFtranPrepare() {
col_BFRT.clear();
for (HighsInt iFn = 0; iFn < multi_nFinish; iFn++) {
MFinish* finish = &multi_finish[iFn];
HVector* Vec = finish->col_BFRT;
a_matrix->collectAj(*Vec, finish->variable_in, finish->theta_primal);
for (HighsInt jFn = iFn - 1; jFn >= 0; jFn--) {
MFinish* jFinish = &multi_finish[jFn];
double* jRow_epArray = jFinish->row_ep->array.data();
double pivotX = 0;
for (HighsInt k = 0; k < Vec->count; k++) {
HighsInt iRow = Vec->index[k];
pivotX += Vec->array[iRow] * jRow_epArray[iRow];
}
if (fabs(pivotX) > kHighsTiny) {
pivotX /= jFinish->alpha_row;
a_matrix->collectAj(*Vec, jFinish->variable_in, -pivotX);
a_matrix->collectAj(*Vec, jFinish->variable_out, pivotX);
}
}
col_BFRT.saxpy(1.0, Vec);
}
for (HighsInt iFn = 0; iFn < multi_nFinish; iFn++) {
MFinish* iFinish = &multi_finish[iFn];
HVector* iColumn = iFinish->col_aq;
iColumn->clear();
iColumn->packFlag = true;
a_matrix->collectAj(*iColumn, iFinish->variable_in, 1);
}
}
void HEkkDual::majorUpdateFtranParallel() {
analysis->simplexTimerStart(FtranMixParClock);
HighsInt multi_ntasks = 0;
double multi_density[kSimplexConcurrencyLimit * 2 + 1];
HVector_ptr multi_vector[kSimplexConcurrencyLimit * 2 + 1];
if (analysis->analyse_simplex_summary_data)
analysis->operationRecordBefore(kSimplexNlaFtranBfrt, col_BFRT.count,
ekk_instance_.info_.col_aq_density);
multi_density[multi_ntasks] = ekk_instance_.info_.col_aq_density;
multi_vector[multi_ntasks] = &col_BFRT;
multi_ntasks++;
if (edge_weight_mode == EdgeWeightMode::kSteepestEdge) {
for (HighsInt iFn = 0; iFn < multi_nFinish; iFn++) {
if (analysis->analyse_simplex_summary_data)
analysis->operationRecordBefore(kSimplexNlaFtranDse,
multi_finish[iFn].row_ep->count,
ekk_instance_.info_.row_DSE_density);
multi_density[multi_ntasks] = ekk_instance_.info_.row_DSE_density;
multi_vector[multi_ntasks] = multi_finish[iFn].row_ep;
multi_ntasks++;
}
}
for (HighsInt iFn = 0; iFn < multi_nFinish; iFn++) {
if (analysis->analyse_simplex_summary_data)
analysis->operationRecordBefore(kSimplexNlaFtran,
multi_finish[iFn].col_aq->count,
ekk_instance_.info_.col_aq_density);
multi_density[multi_ntasks] = ekk_instance_.info_.col_aq_density;
multi_vector[multi_ntasks] = multi_finish[iFn].col_aq;
multi_ntasks++;
}
highs::parallel::for_each(0, multi_ntasks, [&](HighsInt start, HighsInt end) {
for (HighsInt i = start; i < end; i++) {
HVector_ptr rhs = multi_vector[i];
double density = multi_density[i];
HighsTimerClock* factor_timer_clock_pointer =
analysis->getThreadFactorTimerClockPointer();
ekk_instance_.simplex_nla_.ftran(*rhs, density,
factor_timer_clock_pointer);
}
});
for (HighsInt iFn = 0; iFn < multi_nFinish; iFn++) {
MFinish* finish = &multi_finish[iFn];
HVector* Col = finish->col_aq;
HVector* Row = finish->row_ep;
ekk_instance_.total_synthetic_tick_ += Col->synthetic_tick;
ekk_instance_.total_synthetic_tick_ += Row->synthetic_tick;
}
if (analysis->analyse_simplex_summary_data)
analysis->operationRecordAfter(kSimplexNlaFtranBfrt, col_BFRT.count);
for (HighsInt iFn = 0; iFn < multi_nFinish; iFn++) {
MFinish* finish = &multi_finish[iFn];
HVector* Col = finish->col_aq;
HVector* Row = finish->row_ep;
const double local_col_aq_density = (double)Col->count / solver_num_row;
ekk_instance_.updateOperationResultDensity(
local_col_aq_density, ekk_instance_.info_.col_aq_density);
if (analysis->analyse_simplex_summary_data)
analysis->operationRecordAfter(kSimplexNlaFtran, Col->count);
if (edge_weight_mode == EdgeWeightMode::kSteepestEdge) {
const double local_row_DSE_density = (double)Row->count / solver_num_row;
ekk_instance_.updateOperationResultDensity(
local_row_DSE_density, ekk_instance_.info_.row_DSE_density);
if (analysis->analyse_simplex_summary_data)
analysis->operationRecordAfter(kSimplexNlaFtranDse, Row->count);
}
}
analysis->simplexTimerStop(FtranMixParClock);
}
void HEkkDual::majorUpdateFtranFinal() {
analysis->simplexTimerStart(FtranMixFinalClock);
HighsInt updateFTRAN_inDense = dualRHS.workCount < 0;
if (updateFTRAN_inDense) {
for (HighsInt iFn = 0; iFn < multi_nFinish; iFn++) {
multi_finish[iFn].col_aq->count = -1;
multi_finish[iFn].row_ep->count = -1;
double* myCol = multi_finish[iFn].col_aq->array.data();
double* myRow = multi_finish[iFn].row_ep->array.data();
for (HighsInt jFn = 0; jFn < iFn; jFn++) {
HighsInt pivotRow = multi_finish[jFn].row_out;
const double pivotAlpha = multi_finish[jFn].alpha_row;
const double* pivotArray = multi_finish[jFn].col_aq->array.data();
double pivotX1 = myCol[pivotRow];
double pivotX2 = myRow[pivotRow];
if (fabs(pivotX1) > kHighsTiny) {
const double pivot = pivotX1 / pivotAlpha;
highs::parallel::for_each(
0, solver_num_row,
[&](HighsInt start, HighsInt end) {
for (HighsInt i = start; i < end; i++)
myCol[i] -= pivot * pivotArray[i];
},
100);
myCol[pivotRow] = pivot;
}
if (fabs(pivotX2) > kHighsTiny) {
const double pivot = pivotX2 / pivotAlpha;
highs::parallel::for_each(
0, solver_num_row,
[&](HighsInt start, HighsInt end) {
for (HighsInt i = start; i < end; i++)
myRow[i] -= pivot * pivotArray[i];
},
100);
myRow[pivotRow] = pivot;
}
}
}
} else {
for (HighsInt iFn = 0; iFn < multi_nFinish; iFn++) {
MFinish* finish = &multi_finish[iFn];
HVector* Col = finish->col_aq;
HVector* Row = finish->row_ep;
for (HighsInt jFn = 0; jFn < iFn; jFn++) {
MFinish* jFinish = &multi_finish[jFn];
HighsInt pivotRow = jFinish->row_out;
double pivotX1 = Col->array[pivotRow];
if (fabs(pivotX1) > kHighsTiny) {
pivotX1 /= jFinish->alpha_row;
Col->saxpy(-pivotX1, jFinish->col_aq);
Col->array[pivotRow] = pivotX1;
}
double pivotX2 = Row->array[pivotRow];
if (fabs(pivotX2) > kHighsTiny) {
pivotX2 /= jFinish->alpha_row;
Row->saxpy(-pivotX2, jFinish->col_aq);
Row->array[pivotRow] = pivotX2;
}
}
}
}
analysis->simplexTimerStop(FtranMixFinalClock);
}
void HEkkDual::majorUpdatePrimal() {
const bool updatePrimal_inDense = dualRHS.workCount < 0;
if (updatePrimal_inDense) {
const double* mixArray = col_BFRT.array.data();
double* local_work_infeasibility = dualRHS.work_infeasibility.data();
highs::parallel::for_each(
0, solver_num_row,
[&](HighsInt start, HighsInt end) {
for (HighsInt iRow = start; iRow < end; iRow++) {
baseValue[iRow] -= mixArray[iRow];
const double value = baseValue[iRow];
const double less = baseLower[iRow] - value;
const double more = value - baseUpper[iRow];
double infeas = less > Tp ? less : (more > Tp ? more : 0);
if (ekk_instance_.info_.store_squared_primal_infeasibility)
local_work_infeasibility[iRow] = infeas * infeas;
else
local_work_infeasibility[iRow] = fabs(infeas);
}
},
100);
if (edge_weight_mode == EdgeWeightMode::kSteepestEdge ||
(edge_weight_mode == EdgeWeightMode::kDevex && !new_devex_framework)) {
std::vector<double>& edge_weight = ekk_instance_.dual_edge_weight_;
for (HighsInt iFn = 0; iFn < multi_nFinish; iFn++) {
const double new_pivotal_edge_weight = multi_finish[iFn].EdWt;
const double* colArray = multi_finish[iFn].col_aq->array.data();
if (edge_weight_mode == EdgeWeightMode::kSteepestEdge) {
const double* dseArray = multi_finish[iFn].row_ep->array.data();
const double Kai = -2 / multi_finish[iFn].alpha_row;
highs::parallel::for_each(
0, solver_num_row,
[&](HighsInt start, HighsInt end) {
for (HighsInt iRow = start; iRow < end; iRow++) {
const double aa_iRow = colArray[iRow];
edge_weight[iRow] +=
aa_iRow * (new_pivotal_edge_weight * aa_iRow +
Kai * dseArray[iRow]);
edge_weight[iRow] =
max(kMinDualSteepestEdgeWeight, edge_weight[iRow]);
}
},
100);
} else {
for (HighsInt iRow = 0; iRow < solver_num_row; iRow++) {
const double aa_iRow = colArray[iRow];
edge_weight[iRow] = max(
edge_weight[iRow], new_pivotal_edge_weight * aa_iRow * aa_iRow);
}
}
}
}
} else {
dualRHS.updatePrimal(&col_BFRT, 1);
dualRHS.updateInfeasList(&col_BFRT);
for (HighsInt iFn = 0; iFn < multi_nFinish; iFn++) {
MFinish* finish = &multi_finish[iFn];
HVector* Col = finish->col_aq;
const double new_pivotal_edge_weight = finish->EdWt;
if (edge_weight_mode == EdgeWeightMode::kSteepestEdge) {
HVector* Row = finish->row_ep;
double Kai = -2 / finish->alpha_row;
ekk_instance_.updateDualSteepestEdgeWeights(row_out, variable_in, Col,
new_pivotal_edge_weight,
Kai, Row->array.data());
} else if (edge_weight_mode == EdgeWeightMode::kDevex &&
!new_devex_framework) {
ekk_instance_.updateDualDevexWeights(Col, new_pivotal_edge_weight);
}
dualRHS.updateInfeasList(Col);
}
}
for (HighsInt iFn = 0; iFn < multi_nFinish; iFn++) {
MFinish* finish = &multi_finish[iFn];
HighsInt iRow = finish->row_out;
double value = baseValue[iRow] - finish->basicBound + finish->basicValue;
dualRHS.updatePivots(iRow, value);
}
if (edge_weight_mode == EdgeWeightMode::kSteepestEdge ||
(edge_weight_mode == EdgeWeightMode::kDevex && !new_devex_framework)) {
std::vector<double>& edge_weight = ekk_instance_.dual_edge_weight_;
for (HighsInt iFn = 0; iFn < multi_nFinish; iFn++) {
const HighsInt iRow = multi_finish[iFn].row_out;
const double new_pivotal_edge_weight = multi_finish[iFn].EdWt;
const double* colArray = multi_finish[iFn].col_aq->array.data();
if (edge_weight_mode == EdgeWeightMode::kSteepestEdge) {
const double* dseArray = multi_finish[iFn].row_ep->array.data();
double Kai = -2 / multi_finish[iFn].alpha_row;
for (HighsInt jFn = 0; jFn < iFn; jFn++) {
HighsInt jRow = multi_finish[jFn].row_out;
double value = colArray[jRow];
edge_weight[jRow] +=
value * (new_pivotal_edge_weight * value + Kai * dseArray[jRow]);
edge_weight[jRow] =
max(kMinDualSteepestEdgeWeight, edge_weight[jRow]);
}
edge_weight[iRow] = new_pivotal_edge_weight;
} else {
for (HighsInt jFn = 0; jFn < iFn; jFn++) {
HighsInt jRow = multi_finish[jFn].row_out;
const double aa_iRow = colArray[iRow];
edge_weight[jRow] = max(edge_weight[jRow],
new_pivotal_edge_weight * aa_iRow * aa_iRow);
}
edge_weight[iRow] = new_pivotal_edge_weight;
num_devex_iterations++;
}
}
}
checkNonUnitWeightError("999");
}
void HEkkDual::majorUpdateFactor() {
HighsInt* iRows = new HighsInt[multi_nFinish];
for (HighsInt iCh = 0; iCh < multi_nFinish - 1; iCh++) {
multi_finish[iCh].row_ep->next = multi_finish[iCh + 1].row_ep;
multi_finish[iCh].col_aq->next = multi_finish[iCh + 1].col_aq;
iRows[iCh] = multi_finish[iCh].row_out;
}
iRows[multi_nFinish - 1] = multi_finish[multi_nFinish - 1].row_out;
if (multi_nFinish > 0)
ekk_instance_.updateFactor(multi_finish[0].col_aq, multi_finish[0].row_ep,
iRows, &rebuild_reason);
const double use_build_synthetic_tick =
ekk_instance_.build_synthetic_tick_ * kMultiBuildSyntheticTickMu;
const bool reinvert_syntheticClock =
ekk_instance_.total_synthetic_tick_ >= use_build_synthetic_tick;
const bool performed_min_updates =
ekk_instance_.info_.update_count >=
kMultiSyntheticTickReinversionMinUpdateCount;
if (reinvert_syntheticClock && performed_min_updates)
rebuild_reason = kRebuildReasonSyntheticClockSaysInvert;
delete[] iRows;
}
void HEkkDual::majorRollback() {
for (HighsInt iFn = multi_nFinish - 1; iFn >= 0; iFn--) {
MFinish* finish = &multi_finish[iFn];
ekk_instance_.basis_.nonbasicMove_[finish->variable_in] = finish->move_in;
ekk_instance_.basis_.nonbasicFlag_[finish->variable_in] = 1;
ekk_instance_.basis_.nonbasicMove_[finish->variable_out] = 0;
ekk_instance_.basis_.nonbasicFlag_[finish->variable_out] = 0;
ekk_instance_.basis_.basicIndex_[finish->row_out] = finish->variable_out;
ekk_instance_.updateMatrix(finish->variable_out, finish->variable_in);
for (HighsInt var : finish->flipList) {
ekk_instance_.flipBound(var);
}
ekk_instance_.info_.workShift_[finish->variable_in] = 0;
ekk_instance_.info_.workShift_[finish->variable_out] = finish->shiftOut;
ekk_instance_.iteration_count_--;
}
}
bool HEkkDual::checkNonUnitWeightError(std::string message) const {
bool error_found = false;
if (edge_weight_mode == EdgeWeightMode::kDantzig) {
std::vector<double>& edge_weight = ekk_instance_.dual_edge_weight_;
double unit_wt_error = 0;
for (HighsInt iRow = 0; iRow < solver_num_row; iRow++) {
unit_wt_error += fabs(edge_weight[iRow] - 1.0);
}
error_found = unit_wt_error > 1e-4;
if (error_found)
printf("Non-unit Edge weight error of %g: %s\n", unit_wt_error,
message.c_str());
}
return error_found;
}
void HEkkDual::iterationAnalysisMinorData() {
analysis->multi_iteration_count = multi_iteration;
analysis->multi_chosen = multi_chosen;
analysis->multi_finished = multi_nFinish;
}
void HEkkDual::iterationAnalysisMinor() {
alpha_col = alpha_row;
iterationAnalysisData();
iterationAnalysisMinorData();
analysis->iterationReport();
if (analysis->analyse_simplex_summary_data) analysis->iterationRecord();
}
void HEkkDual::iterationAnalysisMajorData() {
HighsSimplexInfo& info = ekk_instance_.info_;
analysis->numerical_trouble = numericalTrouble;
analysis->min_concurrency = info.min_concurrency;
analysis->num_concurrency = info.num_concurrency;
analysis->max_concurrency = info.max_concurrency;
}
void HEkkDual::iterationAnalysisMajor() {
iterationAnalysisMajorData();
if (edge_weight_mode == EdgeWeightMode::kSteepestEdge) {
bool switch_to_devex = false;
switch_to_devex = ekk_instance_.switchToDevex();
if (switch_to_devex) {
edge_weight_mode = EdgeWeightMode::kDevex;
initialiseDevexFramework();
}
}
if (analysis->analyse_simplex_summary_data) {
analysis->iterationRecord();
analysis->iterationRecordMajor();
}
}