#include "util/HFactor.h"
#include <cassert>
#include <iostream>
#include "../extern/pdqsort/pdqsort.h"
#include "lp_data/HConst.h"
#include "util/FactorTimer.h"
#include "util/HFactorDebug.h"
#include "util/HVector.h"
#include "util/HVectorBase.h"
#include "util/HighsTimer.h"
using std::fabs;
using std::copy;
using std::fill_n;
using std::make_pair;
using std::min;
using std::pair;
static void solveMatrixT(const HighsInt X_Start, const HighsInt x_end,
const HighsInt y_start, const HighsInt y_end,
const HighsInt* t_index, const double* t_value,
const double t_pivot, HighsInt* rhs_count,
HighsInt* rhs_index, double* rhs_array) {
double pivot_multiplier = 0;
for (HighsInt k = X_Start; k < x_end; k++)
pivot_multiplier += t_value[k] * rhs_array[t_index[k]];
if (fabs(pivot_multiplier) > kHighsTiny) {
HighsInt work_count = *rhs_count;
pivot_multiplier /= t_pivot;
for (HighsInt k = y_start; k < y_end; k++) {
const HighsInt index = t_index[k];
const double value0 = rhs_array[index];
const double value1 = value0 - pivot_multiplier * t_value[k];
if (value0 == 0) rhs_index[work_count++] = index;
rhs_array[index] = (fabs(value1) < kHighsTiny) ? kHighsZero : value1;
}
*rhs_count = work_count;
}
}
static void solveHyper(const HighsInt h_size, const HighsInt* h_lookup,
const HighsInt* h_pivot_index,
const double* h_pivot_value, const HighsInt* h_start,
const HighsInt* h_end, const HighsInt* h_index,
const double* h_value, HVector* rhs) {
HighsInt rhs_count = rhs->count;
HighsInt* rhs_index = rhs->index.data();
double* rhs_array = rhs->array.data();
char* list_mark = rhs->cwork.data();
HighsInt* list_index = rhs->iwork.data();
HighsInt* list_stack = &rhs->iwork[h_size];
HighsInt list_count = 0;
HighsInt count_pivot = 0;
HighsInt count_entry = 0;
for (HighsInt i = 0; i < rhs_count; i++) {
HighsInt i_trans =
h_lookup[rhs_index[i]]; if (list_mark[i_trans]) continue;
HighsInt Hi = i_trans; HighsInt Hk = h_start[Hi]; HighsInt n_stack = -1;
list_mark[Hi] = 1;
for (;;) {
if (Hk < h_end[Hi]) {
HighsInt Hi_sub = h_lookup[h_index[Hk++]];
if (list_mark[Hi_sub] == 0) { list_mark[Hi_sub] = 1; list_stack[++n_stack] = Hi; list_stack[++n_stack] = Hk;
Hi = Hi_sub; Hk = h_start[Hi];
if (Hi >= h_size) {
count_pivot++;
count_entry += h_end[Hi] - h_start[Hi];
}
}
} else {
list_index[list_count++] = Hi;
if (n_stack == -1) break;
Hk = list_stack[n_stack--]; Hi = list_stack[n_stack--];
}
}
}
rhs->synthetic_tick += count_pivot * 20 + count_entry * 10;
if (h_pivot_value == 0) {
rhs_count = 0;
for (HighsInt iList = list_count - 1; iList >= 0; iList--) {
HighsInt i = list_index[iList];
list_mark[i] = 0;
HighsInt pivotRow = h_pivot_index[i];
double pivot_multiplier = rhs_array[pivotRow];
if (fabs(pivot_multiplier) > kHighsTiny) {
rhs_index[rhs_count++] = pivotRow;
const HighsInt start = h_start[i];
const HighsInt end = h_end[i];
for (HighsInt k = start; k < end; k++)
rhs_array[h_index[k]] -= pivot_multiplier * h_value[k];
} else
rhs_array[pivotRow] = 0;
}
rhs->count = rhs_count;
} else {
rhs_count = 0;
for (HighsInt iList = list_count - 1; iList >= 0; iList--) {
HighsInt i = list_index[iList];
list_mark[i] = 0;
HighsInt pivotRow = h_pivot_index[i];
double pivot_multiplier = rhs_array[pivotRow];
if (fabs(pivot_multiplier) > kHighsTiny) {
pivot_multiplier /= h_pivot_value[i];
rhs_array[pivotRow] = pivot_multiplier;
rhs_index[rhs_count++] = pivotRow;
const HighsInt start = h_start[i];
const HighsInt end = h_end[i];
for (HighsInt k = start; k < end; k++)
rhs_array[h_index[k]] -= pivot_multiplier * h_value[k];
} else
rhs_array[pivotRow] = 0;
}
rhs->count = rhs_count;
}
}
void HFactor::setup(const HighsSparseMatrix& a_matrix,
std::vector<HighsInt>& basic_index,
const double pivot_threshold, const double pivot_tolerance,
const HighsInt highs_debug_level,
const HighsLogOptions* log_options) {
HighsInt basic_index_size = basic_index.size();
if (basic_index_size <= 0) return;
this->setupGeneral(&a_matrix, basic_index_size, basic_index.data(),
pivot_threshold, pivot_tolerance, highs_debug_level,
log_options);
return;
}
void HFactor::setupGeneral(const HighsSparseMatrix* a_matrix,
HighsInt num_basic, HighsInt* basic_index,
const double pivot_threshold,
const double pivot_tolerance,
const HighsInt highs_debug_level,
const HighsLogOptions* log_options) {
this->setupGeneral(a_matrix->num_col_, a_matrix->num_row_, num_basic,
a_matrix->start_.data(), a_matrix->index_.data(),
a_matrix->value_.data(), basic_index, pivot_threshold,
pivot_tolerance, highs_debug_level, log_options, true,
kUpdateMethodFt);
}
void HFactor::setup(
const HighsInt num_col_, const HighsInt num_row_, const HighsInt* a_start_,
const HighsInt* a_index_, const double* a_value_, HighsInt* basic_index_,
const double pivot_threshold_, const double pivot_tolerance_,
const HighsInt highs_debug_level_, const HighsLogOptions* log_options_,
const bool use_original_HFactor_logic_, const HighsInt update_method_) {
setupGeneral(num_col_, num_row_, num_row_, a_start_, a_index_, a_value_,
basic_index_, pivot_threshold_, pivot_tolerance_,
highs_debug_level_, log_options_, use_original_HFactor_logic_,
update_method_);
}
void HFactor::setupGeneral(
const HighsInt num_col_, const HighsInt num_row_, HighsInt num_basic_,
const HighsInt* a_start_, const HighsInt* a_index_, const double* a_value_,
HighsInt* basic_index_, const double pivot_threshold_,
const double pivot_tolerance_, const HighsInt highs_debug_level_,
const HighsLogOptions* log_options_, const bool use_original_HFactor_logic_,
const HighsInt update_method_) {
num_row = num_row_;
num_col = num_col_;
num_basic = num_basic_;
inv_num_row = 1.0 / num_row;
this->a_matrix_valid = true;
a_start = a_start_;
a_index = a_index_;
a_value = a_value_;
basic_index = basic_index_;
pivot_threshold =
max(kMinPivotThreshold, min(pivot_threshold_, kMaxPivotThreshold));
pivot_tolerance =
max(kMinPivotTolerance, min(pivot_tolerance_, kMaxPivotTolerance));
highs_debug_level = highs_debug_level_;
time_limit_ = kHighsInf;
log_data = decltype(log_data)(new LogData());
log_options.output_flag = &log_data->output_flag;
log_options.log_to_console = &log_data->log_to_console;
log_options.log_dev_level = &log_data->log_dev_level;
if (!log_options_) {
log_data->output_flag = false;
log_data->log_to_console = true;
log_data->log_dev_level = 0;
log_options.log_stream = nullptr;
} else {
log_data->output_flag = *(log_options_->output_flag);
log_data->log_to_console = *(log_options_->log_to_console);
log_data->log_dev_level = *(log_options_->log_dev_level);
log_options.log_stream = log_options_->log_stream;
}
use_original_HFactor_logic = use_original_HFactor_logic_;
update_method = update_method_;
iwork.reserve(num_row * 2);
dwork.assign(num_row, 0);
basis_matrix_limit_size = 0;
iwork.assign(num_row + 1, 0);
for (HighsInt i = 0; i < num_col; i++) iwork[a_start[i + 1] - a_start[i]]++;
const HighsInt b_max_dim = max(num_row, num_basic);
for (HighsInt i = num_row, counted = 0; i >= 0 && counted < b_max_dim; i--)
basis_matrix_limit_size += i * iwork[i], counted += iwork[i];
basis_matrix_limit_size += b_max_dim;
b_var.resize(b_max_dim);
b_start.resize(b_max_dim + 1, 0);
b_index.resize(basis_matrix_limit_size);
b_value.resize(basis_matrix_limit_size);
const HighsInt permute_max_dim = max(num_row, num_basic);
permute.resize(permute_max_dim);
const HighsInt mc_dim = num_basic;
mc_var.resize(mc_dim);
mc_start.resize(mc_dim);
mc_count_a.resize(mc_dim);
mc_count_n.resize(mc_dim);
mc_space.resize(mc_dim);
mc_min_pivot.resize(mc_dim);
mc_index.resize(basis_matrix_limit_size * kMCExtraEntriesMultiplier);
mc_value.resize(basis_matrix_limit_size * kMCExtraEntriesMultiplier);
mr_start.resize(num_row);
mr_count.resize(num_row);
mr_space.resize(num_row);
mr_count_before.resize(num_row);
mr_index.resize(basis_matrix_limit_size * kMRExtraEntriesMultiplier);
mwz_column_mark.assign(num_row, 0);
mwz_column_index.resize(num_row);
mwz_column_array.assign(num_row, 0);
const HighsInt col_link_max_count = num_row;
const HighsInt col_link_dim = num_basic;
col_link_first.assign(col_link_max_count + 1, -1);
col_link_next.resize(col_link_dim);
col_link_last.resize(col_link_dim);
const HighsInt row_link_max_count = num_basic;
const HighsInt row_link_dim = num_row;
row_link_first.resize(row_link_max_count + 1);
row_link_first.assign(row_link_max_count + 1, -1);
row_link_next.resize(row_link_dim);
row_link_last.resize(row_link_dim);
l_pivot_lookup.resize(num_row);
l_pivot_index.reserve(num_row);
l_start.reserve(num_row + 1);
l_index.reserve(basis_matrix_limit_size * kLFactorExtraEntriesMultiplier);
l_value.reserve(basis_matrix_limit_size * kLFactorExtraEntriesMultiplier);
lr_start.reserve(num_row + 1);
lr_index.reserve(basis_matrix_limit_size * kLFactorExtraEntriesMultiplier);
lr_value.reserve(basis_matrix_limit_size * kLFactorExtraEntriesMultiplier);
u_pivot_lookup.resize(num_row);
u_pivot_index.reserve(num_row + kUFactorExtraVectors);
u_pivot_value.reserve(num_row + kUFactorExtraVectors);
u_start.reserve(num_row + kUFactorExtraVectors + 1);
u_last_p.reserve(num_row + kUFactorExtraVectors);
u_index.reserve(basis_matrix_limit_size * kUFactorExtraEntriesMultiplier);
u_value.reserve(basis_matrix_limit_size * kUFactorExtraEntriesMultiplier);
ur_start.reserve(num_row + kUFactorExtraVectors + 1);
ur_lastp.reserve(num_row + kUFactorExtraVectors);
ur_space.reserve(num_row + kUFactorExtraVectors);
ur_index.reserve(basis_matrix_limit_size * kUFactorExtraEntriesMultiplier);
ur_value.reserve(basis_matrix_limit_size * kUFactorExtraEntriesMultiplier);
pf_pivot_value.reserve(kPFFPivotEntries);
pf_pivot_index.reserve(kPFFPivotEntries);
pf_start.reserve(kPFVectors + 1);
pf_index.reserve(basis_matrix_limit_size * kPFEntriesMultiplier);
pf_value.reserve(basis_matrix_limit_size * kPFEntriesMultiplier);
rhs_.setup(num_row);
rhs_.count = -1;
}
void HFactor::setupMatrix(const HighsInt* a_start_, const HighsInt* a_index_,
const double* a_value_) {
a_start = a_start_;
a_index = a_index_;
a_value = a_value_;
this->a_matrix_valid = true;
}
void HFactor::setupMatrix(const HighsSparseMatrix* a_matrix) {
setupMatrix(a_matrix->start_.data(), a_matrix->index_.data(),
a_matrix->value_.data());
}
HighsInt HFactor::build(HighsTimerClock* factor_timer_clock_pointer) {
HighsTimer build_timer;
build_timer_ = &build_timer;
build_timer.start();
const bool report_lu = false;
assert(this->a_matrix_valid);
FactorTimer factor_timer;
if (refactor_info_.use) {
factor_timer.start(FactorReinvert, factor_timer_clock_pointer);
rank_deficiency = rebuild(factor_timer_clock_pointer);
factor_timer.stop(FactorReinvert, factor_timer_clock_pointer);
if (!rank_deficiency) return 0;
}
refactor_info_.clear();
factor_timer.start(FactorInvert, factor_timer_clock_pointer);
build_synthetic_tick = 0;
factor_timer.start(FactorInvertSimple, factor_timer_clock_pointer);
buildSimple();
if (report_lu) {
printf("\nAfter units and singletons\n");
reportLu(kReportLuBoth, false);
}
factor_timer.stop(FactorInvertSimple, factor_timer_clock_pointer);
factor_timer.start(FactorInvertKernel, factor_timer_clock_pointer);
const HighsInt build_kernel_return = buildKernel();
factor_timer.stop(FactorInvertKernel, factor_timer_clock_pointer);
if (build_kernel_return == kBuildKernelReturnTimeout)
return kBuildKernelReturnTimeout;
rank_deficiency = build_kernel_return;
const bool incomplete_basis = num_basic < num_row;
if (rank_deficiency || incomplete_basis) {
factor_timer.start(FactorInvertDeficient, factor_timer_clock_pointer);
if (num_basic == num_row)
highsLogDev(log_options, HighsLogType::kWarning,
"Rank deficiency of %" HIGHSINT_FORMAT
" identified in basis matrix\n",
rank_deficiency);
buildHandleRankDeficiency();
buildMarkSingC();
factor_timer.stop(FactorInvertDeficient, factor_timer_clock_pointer);
}
if (incomplete_basis) {
this->refactor_info_.clear();
assert(!this->refactor_info_.use);
const HighsInt basic_index_rank_deficiency =
rank_deficiency - (num_row - num_basic);
return basic_index_rank_deficiency;
}
if (report_lu) {
printf("\nFactored INVERT\n");
reportLu(kReportLuBoth, false);
}
factor_timer.start(FactorInvertFinish, factor_timer_clock_pointer);
buildFinish();
factor_timer.stop(FactorInvertFinish, factor_timer_clock_pointer);
if (rank_deficiency) {
this->refactor_info_.clear();
} else {
assert(!this->refactor_info_.use);
this->refactor_info_.build_synthetic_tick = this->build_synthetic_tick;
}
invert_num_el = l_start[num_row] + u_last_p[num_row - 1] + num_row;
kernel_dim -= rank_deficiency;
debugLogRankDeficiency(highs_debug_level, log_options, rank_deficiency,
basis_matrix_num_el, invert_num_el, kernel_dim,
kernel_num_el, nwork);
factor_timer.stop(FactorInvert, factor_timer_clock_pointer);
return rank_deficiency;
}
void HFactor::ftranCall(HVector& vector, const double expected_density,
HighsTimerClock* factor_timer_clock_pointer) const {
const bool use_indices = vector.count >= 0;
FactorTimer factor_timer;
factor_timer.start(FactorFtran, factor_timer_clock_pointer);
ftranL(vector, expected_density, factor_timer_clock_pointer);
ftranU(vector, expected_density, factor_timer_clock_pointer);
if (use_indices) vector.reIndex();
factor_timer.stop(FactorFtran, factor_timer_clock_pointer);
}
void HFactor::ftranCall(std::vector<double>& vector,
HighsTimerClock* factor_timer_clock_pointer) {
FactorTimer factor_timer;
factor_timer.start(FactorFtran, factor_timer_clock_pointer);
this->rhs_.clearScalars();
this->rhs_.array = std::move(vector);
this->rhs_.count = -1;
const double expected_density = 1;
ftranCall(this->rhs_, expected_density, factor_timer_clock_pointer);
vector = std::move(this->rhs_.array);
factor_timer.stop(FactorFtran, factor_timer_clock_pointer);
}
void HFactor::btranCall(HVector& vector, const double expected_density,
HighsTimerClock* factor_timer_clock_pointer) const {
const bool use_indices = vector.count >= 0;
FactorTimer factor_timer;
factor_timer.start(FactorBtran, factor_timer_clock_pointer);
btranU(vector, expected_density, factor_timer_clock_pointer);
btranL(vector, expected_density, factor_timer_clock_pointer);
if (use_indices) vector.reIndex();
factor_timer.stop(FactorBtran, factor_timer_clock_pointer);
}
void HFactor::btranCall(std::vector<double>& vector,
HighsTimerClock* factor_timer_clock_pointer) {
this->rhs_.clearScalars();
this->rhs_.array = std::move(vector);
this->rhs_.count = -1;
const double expected_density = 1;
btranCall(this->rhs_, expected_density, factor_timer_clock_pointer);
vector = std::move(this->rhs_.array);
}
void HFactor::update(HVector* aq, HVector* ep, HighsInt* iRow, HighsInt* hint) {
this->refactor_info_.clear();
if (aq->next) {
updateCFT(aq, ep, iRow);
return;
}
if (update_method == kUpdateMethodFt) updateFT(aq, ep, *iRow);
if (update_method == kUpdateMethodPf) updatePF(aq, *iRow, hint);
if (update_method == kUpdateMethodMpf) updateMPF(aq, ep, *iRow, hint);
if (update_method == kUpdateMethodApf) updateAPF(aq, ep, *iRow);
}
bool HFactor::setPivotThreshold(const double new_pivot_threshold) {
if (new_pivot_threshold < kMinPivotThreshold) return false;
if (new_pivot_threshold > kMaxPivotThreshold) return false;
pivot_threshold = new_pivot_threshold;
return true;
}
void HFactor::setTimeLimit(const double time_limit) {
this->time_limit_ = kHighsInf;
if (time_limit < 0) return;
this->time_limit_ = time_limit;
}
void HFactor::luClear() {
l_start.clear();
l_start.push_back(0);
l_index.clear();
l_value.clear();
u_pivot_index.clear();
u_pivot_value.clear();
u_start.clear();
u_start.push_back(0);
u_index.clear();
u_value.clear();
}
void HFactor::buildSimple() {
luClear();
const bool progress_report = false;
const HighsInt progress_frequency = 100000;
const HighsInt permute_dim = num_basic;
permute.resize(permute_dim);
permute.assign(permute_dim, -1);
const bool report_unit = false;
const bool report_singletons = false;
const bool report_markowitz = false;
const bool report_anything =
report_unit || report_singletons || report_markowitz;
HighsInt BcountX = 0;
fill_n(mr_count_before.data(), num_row, 0);
nwork = 0;
if (report_anything) printf("\nFactor\n");
const HighsInt iwork_dim = num_basic;
iwork.resize(iwork_dim + 1, 0);
iwork.assign(iwork_dim + 1, 0);
for (HighsInt iCol = 0; iCol < num_basic; iCol++) {
if (progress_report && iCol) {
if (iCol % progress_frequency == 0)
printf("HFactor::buildSimple stage = %6d\n", (int)iCol);
}
HighsInt iMat = basic_index[iCol];
HighsInt iRow = -1;
int8_t pivot_type = kPivotIllegal;
if (iMat >= num_col) {
HighsInt lc_iRow = iMat - num_col;
if (mr_count_before[lc_iRow] >= 0) {
if (report_unit)
printf("Stage %d: Logical\n", (int)(l_start.size() - 1));
pivot_type = kPivotLogical;
iRow = lc_iRow;
} else {
mr_count_before[lc_iRow]++;
b_index[BcountX] = lc_iRow;
b_value[BcountX++] = 1.0;
iwork[nwork++] = iCol;
}
} else {
HighsInt start = a_start[iMat];
HighsInt count = a_start[iMat + 1] - start;
bool ok_unit_col = false;
if (count == 1) {
ok_unit_col =
a_value[start] == 1 && mr_count_before[a_index[start]] >= 0;
}
if (ok_unit_col) {
if (report_unit) printf("Stage %d: Unit\n", (int)(l_start.size() - 1));
pivot_type = kPivotColSingleton; iRow = a_index[start];
} else {
for (HighsInt k = start; k < start + count; k++) {
mr_count_before[a_index[k]]++;
assert(BcountX < (HighsInt)b_index.size());
b_index[BcountX] = a_index[k];
b_value[BcountX++] = a_value[k];
}
iwork[nwork++] = iCol;
}
}
if (iRow >= 0) {
permute[iCol] = iRow;
l_start.push_back(l_index.size());
u_pivot_index.push_back(iRow);
u_pivot_value.push_back(1);
u_start.push_back(u_index.size());
mr_count_before[iRow] = -num_basic;
assert(pivot_type != kPivotIllegal);
this->refactor_info_.pivot_row.push_back(iRow);
this->refactor_info_.pivot_var.push_back(iMat);
this->refactor_info_.pivot_type.push_back(pivot_type);
}
b_start[iCol + 1] = BcountX;
b_var[iCol] = iMat;
}
basis_matrix_num_el = num_row - nwork + BcountX;
build_synthetic_tick += BcountX * 60 + (num_row - nwork) * 80;
double t2_search = 0;
double t2_store_l = l_index.size();
double t2_store_u = u_index.size();
double t2_store_p = nwork;
while (nwork > 0) {
HighsInt nworkLast = nwork;
nwork = 0;
for (HighsInt i = 0; i < nworkLast; i++) {
const HighsInt iCol = iwork[i];
const HighsInt start = b_start[iCol];
const HighsInt end = b_start[iCol + 1];
HighsInt pivot_k = -1;
HighsInt found_row_singleton = 0;
HighsInt count = 0;
t2_search += end - start;
for (HighsInt k = start; k < end; k++) {
const HighsInt iRow = b_index[k];
if (mr_count_before[iRow] == 1) {
pivot_k = k;
found_row_singleton = 1;
break;
}
if (mr_count_before[iRow] > 1) {
pivot_k = k;
count++;
}
}
if (found_row_singleton) {
const double pivot_multiplier = 1 / b_value[pivot_k];
if (report_singletons)
printf("Stage %d: Row singleton (%4d, %g)\n",
(int)(l_start.size() - 1), (int)pivot_k, pivot_multiplier);
for (HighsInt section = 0; section < 2; section++) {
HighsInt p0 = section == 0 ? start : pivot_k + 1;
HighsInt p1 = section == 0 ? pivot_k : end;
for (HighsInt k = p0; k < p1; k++) {
HighsInt iRow = b_index[k];
if (mr_count_before[iRow] > 0) {
if (report_singletons)
printf("Row singleton: L En (%4d, %11.4g)\n", (int)iRow,
b_value[k] * pivot_multiplier);
l_index.push_back(iRow);
l_value.push_back(b_value[k] * pivot_multiplier);
} else {
if (report_singletons)
printf("Row singleton: U En (%4d, %11.4g)\n", (int)iRow,
b_value[k]);
u_index.push_back(iRow);
u_value.push_back(b_value[k]);
}
mr_count_before[iRow]--;
}
}
HighsInt iRow = b_index[pivot_k];
mr_count_before[iRow] = 0;
permute[iCol] = iRow;
l_start.push_back(l_index.size());
if (report_singletons)
printf("Row singleton: U Pv (%4d, %11.4g)\n", (int)iRow,
b_value[pivot_k]);
u_pivot_index.push_back(iRow);
u_pivot_value.push_back(b_value[pivot_k]);
u_start.push_back(u_index.size());
assert(b_var[iCol] == basic_index[iCol]);
this->refactor_info_.pivot_row.push_back(iRow);
this->refactor_info_.pivot_var.push_back(basic_index[iCol]);
this->refactor_info_.pivot_type.push_back(kPivotRowSingleton);
} else if (count == 1) {
if (report_singletons)
printf("Stage %d: Col singleton \n", (int)(l_start.size() - 1));
for (HighsInt k = start; k < pivot_k; k++) {
if (report_singletons)
printf("Col singleton: U En (%4d, %11.4g)\n", (int)b_index[k],
b_value[k]);
u_index.push_back(b_index[k]);
u_value.push_back(b_value[k]);
}
for (HighsInt k = pivot_k + 1; k < end; k++) {
if (report_singletons)
printf("Col singleton: U En (%4d, %11.4g)\n", (int)b_index[k],
b_value[k]);
u_index.push_back(b_index[k]);
u_value.push_back(b_value[k]);
}
HighsInt iRow = b_index[pivot_k];
mr_count_before[iRow] = 0;
permute[iCol] = iRow;
l_start.push_back(l_index.size());
if (report_singletons)
printf("Col singleton: U Pv (%4d, %11.4g)\n", (int)iRow,
b_value[pivot_k]);
u_pivot_index.push_back(iRow);
u_pivot_value.push_back(b_value[pivot_k]);
u_start.push_back(u_index.size());
assert(b_var[iCol] == basic_index[iCol]);
this->refactor_info_.pivot_row.push_back(iRow);
this->refactor_info_.pivot_var.push_back(basic_index[iCol]);
this->refactor_info_.pivot_type.push_back(kPivotColSingleton);
} else {
iwork[nwork++] = iCol;
}
}
if (nworkLast == nwork) break;
}
if (report_anything) reportLu(kReportLuBoth, false);
t2_store_l = static_cast<double>(l_index.size()) - t2_store_l;
t2_store_u = static_cast<double>(u_index.size()) - t2_store_u;
t2_store_p = t2_store_p - nwork;
build_synthetic_tick +=
t2_search * 20 + (t2_store_p + t2_store_l + t2_store_u) * 80;
row_link_first.assign(num_basic + 1, -1);
mr_count.assign(num_row, 0);
HighsInt mr_countX = 0;
kernel_num_el = 0;
for (HighsInt iRow = 0; iRow < num_row; iRow++) {
HighsInt count = mr_count_before[iRow];
if (count > 0) {
mr_start[iRow] = mr_countX;
mr_space[iRow] = count * 2;
mr_countX += count * 2;
rlinkAdd(iRow, count);
kernel_num_el += count + 1;
}
}
mr_index.resize(mr_countX);
col_link_first.assign(num_row + 1, -1);
const HighsInt mc_dim = num_basic;
mc_index.clear();
mc_value.clear();
mc_count_a.assign(mc_dim, 0);
mc_count_n.assign(mc_dim, 0);
HighsInt MCcountX = 0;
for (HighsInt i = 0; i < nwork; i++) {
HighsInt iCol = iwork[i];
mc_var[iCol] = b_var[iCol];
mc_start[iCol] = MCcountX;
mc_space[iCol] = (b_start[iCol + 1] - b_start[iCol]) * 2;
MCcountX += mc_space[iCol];
mc_index.resize(MCcountX);
mc_value.resize(MCcountX);
for (HighsInt k = b_start[iCol]; k < b_start[iCol + 1]; k++) {
const HighsInt iRow = b_index[k];
const double value = b_value[k];
if (mr_count_before[iRow] > 0) {
colInsert(iCol, iRow, value);
rowInsert(iCol, iRow);
} else {
colStoreN(iCol, iRow, value);
}
}
colFixMax(iCol);
clinkAdd(iCol, mc_count_a[iCol]);
}
build_synthetic_tick += (num_row + nwork + MCcountX) * 40 + mr_countX * 20;
kernel_dim = nwork;
assert((HighsInt)this->refactor_info_.pivot_row.size() == num_basic - nwork);
}
HighsInt HFactor::buildKernel() {
double fake_search = 0;
double fake_fill = 0;
double fake_eliminate = 0;
const bool progress_report = false; const HighsInt progress_frequency = 10000;
HighsInt timer_frequency = 100;
double previous_iteration_time = 0;
double average_iteration_time = 0;
const bool check_for_timeout = this->time_limit_ < kHighsInf;
HighsInt search_k = 0;
const HighsInt check_nwork = -11;
while (nwork-- > 0) {
if (nwork == check_nwork) {
reportAsm();
}
if (check_for_timeout && search_k % timer_frequency == 0) {
double current_time = build_timer_->read();
double time_difference = current_time - previous_iteration_time;
previous_iteration_time = current_time;
double iteration_time = time_difference / (1.0 * timer_frequency);
average_iteration_time =
0.9 * average_iteration_time + 0.1 * iteration_time;
if (time_difference > this->time_limit_ / 1e3)
timer_frequency = std::max(HighsInt(1), timer_frequency / 10);
HighsInt iterations_left = kernel_dim - search_k + 1;
double remaining_time_bound = average_iteration_time * iterations_left;
double total_time_bound = current_time + remaining_time_bound;
if (current_time > this->time_limit_ ||
total_time_bound > this->time_limit_)
return kBuildKernelReturnTimeout;
}
HighsInt jColPivot = -1;
HighsInt iRowPivot = -1;
HighsInt searchLimit = min(nwork, HighsInt{8});
HighsInt searchCount = 0;
double merit_limit = 1.0 * num_basic * num_row;
double merit_pivot = merit_limit;
if (progress_report && search_k) {
if (search_k % progress_frequency == 0) {
HighsInt min_col_count = kHighsIInf;
HighsInt min_row_count = kHighsIInf;
for (HighsInt count = 1; count < num_row; count++) {
if (col_link_first[count] >= 0) {
min_col_count = count;
break;
}
}
for (HighsInt count = 1; count < num_basic; count++) {
if (row_link_first[count] >= 0) {
min_row_count = count;
break;
}
}
printf(
"HFactor::buildKernel stage = %6d: min_col_count = %3d; "
"min_row_count = %3d\n",
(int)search_k, (int)min_col_count, (int)min_row_count);
}
}
search_k++;
bool foundPivot = false;
if (!foundPivot && col_link_first[1] != -1) {
jColPivot = col_link_first[1];
iRowPivot = mc_index[mc_start[jColPivot]];
foundPivot = true;
}
if (!foundPivot && row_link_first[1] != -1) {
iRowPivot = row_link_first[1];
jColPivot = mr_index[mr_start[iRowPivot]];
foundPivot = true;
}
const bool singleton_pivot = foundPivot;
#ifndef NDEBUG
double candidate_pivot_value = 0;
#endif
const HighsInt max_count = max(num_row, num_basic);
for (HighsInt count = 2; !foundPivot && count <= max_count; count++) {
if (count <= num_row) {
for (HighsInt j = col_link_first[count]; j != -1;
j = col_link_next[j]) {
double min_pivot = mc_min_pivot[j];
HighsInt start = mc_start[j];
HighsInt end = start + mc_count_a[j];
for (HighsInt k = start; k < end; k++) {
if (fabs(mc_value[k]) >= min_pivot) {
HighsInt i = mc_index[k];
HighsInt row_count = mr_count[i];
double merit_local = 1.0 * (count - 1) * (row_count - 1);
if (merit_pivot > merit_local) {
#ifndef NDEBUG
candidate_pivot_value = fabs(mc_value[k]);
#endif
merit_pivot = merit_local;
jColPivot = j;
iRowPivot = i;
foundPivot = foundPivot || (row_count < count);
}
}
}
if (searchCount++ >= searchLimit && merit_pivot < merit_limit)
foundPivot = true;
if (foundPivot) break;
fake_search += count;
}
}
if (count <= num_basic) {
for (HighsInt i = row_link_first[count]; i != -1;
i = row_link_next[i]) {
HighsInt start = mr_start[i];
HighsInt end = start + mr_count[i];
for (HighsInt k = start; k < end; k++) {
HighsInt j = mr_index[k];
HighsInt column_count = mc_count_a[j];
double merit_local = 1.0 * (count - 1) * (column_count - 1);
if (merit_local < merit_pivot) {
HighsInt ifind = mc_start[j];
while (mc_index[ifind] != i) ifind++;
if (fabs(mc_value[ifind]) >= mc_min_pivot[j]) {
#ifndef NDEBUG
candidate_pivot_value = fabs(mc_value[ifind]);
#endif
merit_pivot = merit_local;
jColPivot = j;
iRowPivot = i;
foundPivot = foundPivot || (column_count <= count);
}
}
}
if (searchCount++ >= searchLimit && merit_pivot < merit_limit)
foundPivot = true;
if (foundPivot) break;
}
fake_search += count;
}
}
if (iRowPivot < 0) {
assert(jColPivot < 0);
assert(!foundPivot);
rank_deficiency = nwork + 1;
highsLogDev(log_options, HighsLogType::kWarning,
"Factorization identifies rank deficiency of %d\n",
(int)rank_deficiency);
return rank_deficiency;
}
#ifndef NDEBUG
const HighsInt original_pivotal_row_count = mr_count[iRowPivot];
const HighsInt original_pivotal_col_count = mc_count_a[jColPivot];
#endif
double pivot_multiplier = colDelete(jColPivot, iRowPivot);
rowDelete(jColPivot, iRowPivot);
clinkDel(jColPivot);
rlinkDel(iRowPivot);
if (!singleton_pivot)
assert(candidate_pivot_value == fabs(pivot_multiplier));
if (fabs(pivot_multiplier) < pivot_tolerance) {
highsLogDev(log_options, HighsLogType::kWarning,
"Defer singular pivot = %11.4g\n", pivot_multiplier);
assert(mr_count[iRowPivot] == original_pivotal_row_count - 1);
if (mr_count[iRowPivot] == 0) {
assert(mc_count_a[jColPivot] == original_pivotal_col_count - 1);
clinkAdd(jColPivot, mc_count_a[jColPivot]);
} else {
zeroCol(jColPivot);
assert(mr_count[iRowPivot] == original_pivotal_row_count - 1);
rlinkAdd(iRowPivot, mr_count[iRowPivot]);
}
nwork++;
continue;
}
permute[jColPivot] = iRowPivot;
assert(mc_var[jColPivot] == basic_index[jColPivot]);
this->refactor_info_.pivot_row.push_back(iRowPivot);
this->refactor_info_.pivot_var.push_back(basic_index[jColPivot]);
this->refactor_info_.pivot_type.push_back(kPivotMarkowitz);
HighsInt start_A = mc_start[jColPivot];
HighsInt end_A = start_A + mc_count_a[jColPivot];
HighsInt mwz_column_count = 0;
for (HighsInt k = start_A; k < end_A; k++) {
const HighsInt iRow = mc_index[k];
const double value = mc_value[k] / pivot_multiplier;
mwz_column_index[mwz_column_count++] = iRow;
mwz_column_array[iRow] = value;
mwz_column_mark[iRow] = 1;
l_index.push_back(iRow);
l_value.push_back(value);
mr_count_before[iRow] = mr_count[iRow];
rowDelete(jColPivot, (int)iRow);
}
l_start.push_back(l_index.size());
fake_fill += 2 * mc_count_a[jColPivot];
HighsInt end_N = start_A + mc_space[jColPivot];
HighsInt start_N = end_N - mc_count_n[jColPivot];
for (HighsInt i = start_N; i < end_N; i++) {
u_index.push_back(mc_index[i]);
u_value.push_back(mc_value[i]);
}
u_pivot_index.push_back(iRowPivot);
u_pivot_value.push_back(pivot_multiplier);
u_start.push_back(u_index.size());
fake_fill += end_N - start_N;
const HighsInt row_start = mr_start[iRowPivot];
const HighsInt row_end = row_start + mr_count[iRowPivot];
for (HighsInt row_k = row_start; row_k < row_end; row_k++) {
HighsInt iCol = mr_index[row_k];
const HighsInt my_count = mc_count_a[iCol];
const HighsInt my_start = mc_start[iCol];
const HighsInt my_end = my_start + my_count - 1;
double my_pivot = colDelete(iCol, iRowPivot);
colStoreN(iCol, iRowPivot, my_pivot);
HighsInt nFillin = mwz_column_count;
HighsInt nCancel = 0;
for (HighsInt my_k = my_start; my_k < my_end; my_k++) {
HighsInt iRow = mc_index[my_k];
double value = mc_value[my_k];
if (mwz_column_mark[iRow]) {
mwz_column_mark[iRow] = 0;
nFillin--;
value -= my_pivot * mwz_column_array[iRow];
if (fabs(value) < kHighsTiny) {
value = 0;
nCancel++;
}
mc_value[my_k] = value;
}
}
fake_eliminate += mwz_column_count;
fake_eliminate += nFillin * 2;
if (nCancel > 0) {
HighsInt new_end = my_start;
for (HighsInt my_k = my_start; my_k < my_end; my_k++) {
if (mc_value[my_k] != 0) {
mc_index[new_end] = mc_index[my_k];
mc_value[new_end++] = mc_value[my_k];
} else {
rowDelete(iCol, mc_index[my_k]);
}
}
mc_count_a[iCol] = new_end - my_start;
}
if (nFillin > 0) {
if (mc_count_a[iCol] + mc_count_n[iCol] + nFillin > mc_space[iCol]) {
HighsInt p1 = mc_start[iCol];
HighsInt p2 = p1 + mc_count_a[iCol];
HighsInt p3 = p1 + mc_space[iCol] - mc_count_n[iCol];
HighsInt p4 = p1 + mc_space[iCol];
mc_space[iCol] += max(mc_space[iCol], nFillin);
HighsInt p5 = mc_start[iCol] = mc_index.size();
HighsInt p7 = p5 + mc_space[iCol] - mc_count_n[iCol];
mc_index.resize(p5 + mc_space[iCol]);
mc_value.resize(p5 + mc_space[iCol]);
copy(&mc_index[p1], &mc_index[p2], &mc_index[p5]);
copy(&mc_value[p1], &mc_value[p2], &mc_value[p5]);
copy(&mc_index[p3], &mc_index[p4], &mc_index[p7]);
copy(&mc_value[p3], &mc_value[p4], &mc_value[p7]);
}
for (HighsInt i = 0; i < mwz_column_count; i++) {
HighsInt iRow = mwz_column_index[i];
if (mwz_column_mark[iRow])
colInsert(iCol, iRow, -my_pivot * mwz_column_array[iRow]);
}
for (HighsInt i = 0; i < mwz_column_count; i++) {
HighsInt iRow = mwz_column_index[i];
if (mwz_column_mark[iRow]) {
if (mr_count[iRow] == mr_space[iRow]) {
HighsInt p1 = mr_start[iRow];
HighsInt p2 = p1 + mr_count[iRow];
HighsInt p3 = mr_start[iRow] = mr_index.size();
mr_space[iRow] *= 2;
mr_index.resize(p3 + mr_space[iRow]);
copy(&mr_index[p1], &mr_index[p2], &mr_index[p3]);
}
rowInsert(iCol, iRow);
}
}
}
for (HighsInt i = 0; i < mwz_column_count; i++)
mwz_column_mark[mwz_column_index[i]] = 1;
colFixMax(iCol);
if (my_count != mc_count_a[iCol]) {
clinkDel(iCol);
clinkAdd(iCol, mc_count_a[iCol]);
}
}
for (HighsInt i = 0; i < mwz_column_count; i++)
mwz_column_mark[mwz_column_index[i]] = 0;
for (HighsInt i = start_A; i < end_A; i++) {
HighsInt iRow = mc_index[i];
if (mr_count_before[iRow] != mr_count[iRow]) {
rlinkDel(iRow);
rlinkAdd(iRow, mr_count[iRow]);
}
}
}
build_synthetic_tick +=
fake_search * 20 + fake_fill * 160 + fake_eliminate * 80;
rank_deficiency = 0;
return rank_deficiency;
}
void HFactor::buildHandleRankDeficiency() {
debugReportRankDeficiency(0, highs_debug_level, log_options, num_row, permute,
iwork, basic_index, rank_deficiency,
row_with_no_pivot, col_with_no_pivot);
if (num_basic < num_row) {
rank_deficiency += num_row - num_basic;
}
row_with_no_pivot.resize(rank_deficiency);
col_with_no_pivot.resize(rank_deficiency);
HighsInt lc_rank_deficiency = 0;
if (num_basic < num_row) {
iwork.resize(num_row);
} else if (num_basic > num_row) {
iwork.resize(num_basic);
}
for (HighsInt i = 0; i < num_row; i++) iwork[i] = -1;
for (HighsInt i = 0; i < num_basic; i++) {
HighsInt perm_i = permute[i];
if (perm_i >= 0) {
iwork[perm_i] = basic_index[i];
} else {
col_with_no_pivot[lc_rank_deficiency++] = i;
}
}
if (num_basic < num_row) {
permute.resize(num_row);
for (HighsInt i = num_basic; i < num_row; i++) {
col_with_no_pivot[lc_rank_deficiency++] = i;
permute[i] = -1;
}
}
assert(lc_rank_deficiency == rank_deficiency);
lc_rank_deficiency = 0;
for (HighsInt i = 0; i < num_row; i++) {
if (iwork[i] < 0) {
row_with_no_pivot[lc_rank_deficiency] = i;
iwork[i] = -(lc_rank_deficiency + 1);
lc_rank_deficiency++;
}
}
if (num_row < num_basic) {
for (HighsInt i = num_row; i < num_basic; i++) {
row_with_no_pivot[lc_rank_deficiency] = i;
iwork[i] = -(lc_rank_deficiency + 1);
lc_rank_deficiency++;
}
}
assert(lc_rank_deficiency == rank_deficiency);
debugReportRankDeficiency(1, highs_debug_level, log_options, num_row, permute,
iwork, basic_index, rank_deficiency,
row_with_no_pivot, col_with_no_pivot);
const HighsInt row_rank_deficiency =
rank_deficiency - max(num_basic - num_row, (HighsInt)0);
for (HighsInt k = 0; k < rank_deficiency; k++) {
HighsInt iRow = row_with_no_pivot[k];
HighsInt iCol = col_with_no_pivot[k];
assert(permute[iCol] == -1);
permute[iCol] = iRow;
if (k < row_rank_deficiency) {
l_start.push_back(l_index.size());
u_pivot_index.push_back(iRow);
u_pivot_value.push_back(1);
u_start.push_back(u_index.size());
}
}
debugReportRankDeficiency(2, highs_debug_level, log_options, num_row, permute,
iwork, basic_index, rank_deficiency,
row_with_no_pivot, col_with_no_pivot);
debugReportRankDeficientASM(
highs_debug_level, log_options, num_row, mc_start, mc_count_a, mc_index,
mc_value, iwork, rank_deficiency, col_with_no_pivot, row_with_no_pivot);
}
void HFactor::buildMarkSingC() {
debugReportMarkSingC(0, highs_debug_level, log_options, num_row, iwork,
basic_index);
const HighsInt basic_index_rank_deficiency =
rank_deficiency - max(num_row - num_basic, (HighsInt)0);
var_with_no_pivot.resize(rank_deficiency);
for (HighsInt k = 0; k < rank_deficiency; k++) {
HighsInt ASMrow = row_with_no_pivot[k];
HighsInt ASMcol = col_with_no_pivot[k];
assert(ASMrow < (HighsInt)iwork.size());
assert(-iwork[ASMrow] - 1 >= 0 && -iwork[ASMrow] - 1 < rank_deficiency);
iwork[ASMrow] = -(ASMcol + 1);
if (ASMcol < num_basic) {
assert(k < basic_index_rank_deficiency);
var_with_no_pivot[k] = basic_index[ASMcol];
basic_index[ASMcol] = num_col + ASMrow;
} else if (num_basic < num_row) {
assert(ASMcol == num_basic + k - basic_index_rank_deficiency);
var_with_no_pivot[k] = -1;
}
}
debugReportMarkSingC(1, highs_debug_level, log_options, num_row, iwork,
basic_index);
}
void HFactor::buildFinish() {
assert(num_basic >= num_row);
for (HighsInt i = 0; i < num_row; i++) u_pivot_lookup[u_pivot_index[i]] = i;
l_pivot_index = u_pivot_index;
l_pivot_lookup = u_pivot_lookup;
HighsInt LcountX = l_index.size();
lr_index.resize(LcountX);
lr_value.resize(LcountX);
iwork.assign(num_row, 0);
for (HighsInt k = 0; k < LcountX; k++) iwork[l_pivot_lookup[l_index[k]]]++;
lr_start.assign(num_row + 1, 0);
for (HighsInt i = 1; i <= num_row; i++)
lr_start[i] = lr_start[i - 1] + iwork[i - 1];
iwork.assign(&lr_start[0], &lr_start[num_row]);
for (HighsInt i = 0; i < num_row; i++) {
const HighsInt index = l_pivot_index[i];
for (HighsInt k = l_start[i]; k < l_start[i + 1]; k++) {
HighsInt iRow = l_pivot_lookup[l_index[k]];
HighsInt i_put = iwork[iRow]++;
lr_index[i_put] = index;
lr_value[i_put] = l_value[k];
}
}
u_start.push_back(0);
u_last_p.assign(&u_start[1], &u_start[num_row + 1]);
u_start.resize(num_row);
HighsInt u_countX = u_index.size();
HighsInt ur_stuff_size = update_method == kUpdateMethodFt ? 5 : 0;
HighsInt ur_count_size = u_countX + ur_stuff_size * num_row;
ur_index.resize(ur_count_size);
ur_value.resize(ur_count_size);
ur_start.assign(num_row + 1, 0);
ur_lastp.assign(num_row, 0);
ur_space.assign(num_row, ur_stuff_size);
for (HighsInt k = 0; k < u_countX; k++)
ur_lastp[u_pivot_lookup[u_index[k]]]++;
for (HighsInt i = 1; i <= num_row; i++)
ur_start[i] = ur_start[i - 1] + ur_lastp[i - 1] + ur_stuff_size;
ur_start.resize(num_row);
ur_lastp = ur_start;
for (HighsInt i = 0; i < num_row; i++) {
const HighsInt index = u_pivot_index[i];
for (HighsInt k = u_start[i]; k < u_last_p[i]; k++) {
HighsInt iRow = u_pivot_lookup[u_index[k]];
HighsInt i_put = ur_lastp[iRow]++;
ur_index[i_put] = index;
ur_value[i_put] = u_value[k];
}
}
u_merit_x = num_row + (LcountX + u_countX) * 1.5;
u_total_x = u_countX;
if (update_method == kUpdateMethodPf) u_merit_x = num_row + u_countX * 4;
if (update_method == kUpdateMethodMpf) u_merit_x = num_row + u_countX * 3;
pf_pivot_value.clear();
pf_pivot_index.clear();
pf_start.clear();
pf_start.push_back(0);
pf_index.clear();
pf_value.clear();
if (!this->refactor_info_.use) {
iwork.assign(basic_index, basic_index + num_basic);
for (HighsInt i = 0; i < num_basic; i++) basic_index[permute[i]] = iwork[i];
for (HighsInt i = num_row; i < num_basic; i++)
assert(basic_index[i] >= num_col);
build_synthetic_tick += num_row * 80 + (LcountX + u_countX) * 60;
}
}
void HFactor::zeroCol(const HighsInt jCol) {
const HighsInt a_count = mc_count_a[jCol];
const HighsInt a_start = mc_start[jCol];
const HighsInt a_end = a_start + a_count;
for (HighsInt iEl = a_start; iEl < a_end; iEl++) {
const double abs_value = std::abs(mc_value[iEl]);
const HighsInt iRow = mc_index[iEl];
const HighsInt original_row_count = mr_count[iRow];
rowDelete(jCol, iRow);
rlinkDel(iRow);
assert(mr_count[iRow] == original_row_count - 1);
rlinkAdd(iRow, mr_count[iRow]);
assert(abs_value < pivot_tolerance);
}
clinkDel(jCol);
mc_count_a[jCol] = 0;
mc_count_n[jCol] = 0;
}
void HFactor::ftranL(HVector& rhs, const double expected_density,
HighsTimerClock* factor_timer_clock_pointer) const {
FactorTimer factor_timer;
factor_timer.start(FactorFtranLower, factor_timer_clock_pointer);
if (update_method == kUpdateMethodApf) {
assert(!(update_method == kUpdateMethodApf));
factor_timer.start(FactorFtranLowerAPF, factor_timer_clock_pointer);
rhs.tight();
rhs.pack();
ftranAPF(rhs);
factor_timer.stop(FactorFtranLowerAPF, factor_timer_clock_pointer);
rhs.tight();
}
double current_density = 1.0 * rhs.count * inv_num_row;
const bool sparse_solve = rhs.count < 0 || current_density > kHyperCancel ||
expected_density > kHyperFtranL;
if (sparse_solve) {
factor_timer.start(FactorFtranLowerSps, factor_timer_clock_pointer);
HighsInt* rhs_index = rhs.index.data();
double* rhs_array = rhs.array.data();
const HighsInt* l_start = this->l_start.data();
const HighsInt* l_index = this->l_index.data();
const double* l_value = this->l_value.data();
HighsInt rhs_count = 0;
for (HighsInt i = 0; i < num_row; i++) {
HighsInt pivotRow = l_pivot_index[i];
const double pivot_multiplier = rhs_array[pivotRow];
if (fabs(pivot_multiplier) > kHighsTiny) {
rhs_index[rhs_count++] = pivotRow;
const HighsInt start = l_start[i];
const HighsInt end = l_start[i + 1];
for (HighsInt k = start; k < end; k++)
rhs_array[l_index[k]] -= pivot_multiplier * l_value[k];
} else
rhs_array[pivotRow] = 0;
}
rhs.count = rhs_count;
factor_timer.stop(FactorFtranLowerSps, factor_timer_clock_pointer);
} else {
factor_timer.start(FactorFtranLowerHyper, factor_timer_clock_pointer);
const HighsInt* l_index = this->l_index.data();
const double* l_value = this->l_value.data();
solveHyper(num_row, l_pivot_lookup.data(), l_pivot_index.data(), 0,
l_start.data(), &l_start[1], &l_index[0], &l_value[0], &rhs);
factor_timer.stop(FactorFtranLowerHyper, factor_timer_clock_pointer);
}
factor_timer.stop(FactorFtranLower, factor_timer_clock_pointer);
}
void HFactor::btranL(HVector& rhs, const double expected_density,
HighsTimerClock* factor_timer_clock_pointer) const {
FactorTimer factor_timer;
factor_timer.start(FactorBtranLower, factor_timer_clock_pointer);
const double current_density = 1.0 * rhs.count * inv_num_row;
const bool sparse_solve = rhs.count < 0 || current_density > kHyperCancel ||
expected_density > kHyperBtranL;
if (sparse_solve) {
factor_timer.start(FactorBtranLowerSps, factor_timer_clock_pointer);
HighsInt* rhs_index = rhs.index.data();
double* rhs_array = rhs.array.data();
const HighsInt* lr_start = this->lr_start.data();
const HighsInt* lr_index = this->lr_index.data();
const double* lr_value = this->lr_value.data();
HighsInt rhs_count = 0;
for (HighsInt i = num_row - 1; i >= 0; i--) {
HighsInt pivotRow = l_pivot_index[i];
const double pivot_multiplier = rhs_array[pivotRow];
if (fabs(pivot_multiplier) > kHighsTiny) {
rhs_index[rhs_count++] = pivotRow;
rhs_array[pivotRow] = pivot_multiplier;
const HighsInt start = lr_start[i];
const HighsInt end = lr_start[i + 1];
for (HighsInt k = start; k < end; k++)
rhs_array[lr_index[k]] -= pivot_multiplier * lr_value[k];
} else
rhs_array[pivotRow] = 0;
}
rhs.count = rhs_count;
factor_timer.stop(FactorBtranLowerSps, factor_timer_clock_pointer);
} else {
factor_timer.start(FactorBtranLowerHyper, factor_timer_clock_pointer);
const HighsInt* lr_index = this->lr_index.data();
const double* lr_value = this->lr_value.data();
solveHyper(num_row, l_pivot_lookup.data(), l_pivot_index.data(), 0,
lr_start.data(), &lr_start[1], &lr_index[0], &lr_value[0], &rhs);
factor_timer.stop(FactorBtranLowerHyper, factor_timer_clock_pointer);
}
if (update_method == kUpdateMethodApf) {
factor_timer.start(FactorBtranLowerAPF, factor_timer_clock_pointer);
btranAPF(rhs);
rhs.tight();
rhs.pack();
factor_timer.stop(FactorBtranLowerAPF, factor_timer_clock_pointer);
}
factor_timer.stop(FactorBtranLower, factor_timer_clock_pointer);
}
void HFactor::ftranU(HVector& rhs, const double expected_density,
HighsTimerClock* factor_timer_clock_pointer) const {
assert(rhs.count >= 0);
FactorTimer factor_timer;
factor_timer.start(FactorFtranUpper, factor_timer_clock_pointer);
if (update_method == kUpdateMethodFt) {
factor_timer.start(FactorFtranUpperFT, factor_timer_clock_pointer);
ftranFT(rhs);
rhs.tight();
rhs.pack();
factor_timer.stop(FactorFtranUpperFT, factor_timer_clock_pointer);
} else if (update_method == kUpdateMethodMpf) {
assert(!(update_method == kUpdateMethodMpf));
factor_timer.start(FactorFtranUpperMPF, factor_timer_clock_pointer);
ftranMPF(rhs);
rhs.tight();
rhs.pack();
factor_timer.stop(FactorFtranUpperMPF, factor_timer_clock_pointer);
}
const double current_density = 1.0 * rhs.count * inv_num_row;
const bool sparse_solve = rhs.count < 0 || current_density > kHyperCancel ||
expected_density > kHyperFtranU;
if (sparse_solve) {
const bool report_ftran_upper_sparse =
false; HighsInt use_clock;
if (current_density < 0.1)
use_clock = FactorFtranUpperSps2;
else if (current_density < 0.5)
use_clock = FactorFtranUpperSps1;
else
use_clock = FactorFtranUpperSps0;
factor_timer.start(use_clock, factor_timer_clock_pointer);
double rhs_synthetic_tick = 0;
HighsInt* rhs_index = rhs.index.data();
double* rhs_array = rhs.array.data();
const HighsInt* u_start = this->u_start.data();
const HighsInt* u_end = this->u_last_p.data();
const HighsInt* u_index = this->u_index.data();
const double* u_value = this->u_value.data();
HighsInt rhs_count = 0;
HighsInt u_pivot_count = u_pivot_index.size();
for (HighsInt i_logic = u_pivot_count - 1; i_logic >= 0; i_logic--) {
if (u_pivot_index[i_logic] == -1) continue;
const HighsInt pivotRow = u_pivot_index[i_logic];
double pivot_multiplier = rhs_array[pivotRow];
if (fabs(pivot_multiplier) > kHighsTiny) {
pivot_multiplier /= u_pivot_value[i_logic];
rhs_index[rhs_count++] = pivotRow;
rhs_array[pivotRow] = pivot_multiplier;
const HighsInt start = u_start[i_logic];
const HighsInt end = u_end[i_logic];
if (i_logic >= num_row) {
rhs_synthetic_tick += (end - start);
}
for (HighsInt k = start; k < end; k++)
rhs_array[u_index[k]] -= pivot_multiplier * u_value[k];
} else
rhs_array[pivotRow] = 0;
}
rhs.count = rhs_count;
rhs.synthetic_tick +=
rhs_synthetic_tick * 15 + (u_pivot_count - num_row) * 10;
factor_timer.stop(use_clock, factor_timer_clock_pointer);
if (report_ftran_upper_sparse) {
const double final_density = 1.0 * rhs.count * inv_num_row;
printf(
"FactorFtranUpperSps: expected_density = %10.4g; current_density = "
"%10.4g; final_density = %10.4g\n",
expected_density, current_density, final_density);
}
} else {
HighsInt use_clock = -1;
if (current_density < 5e-6)
use_clock = FactorFtranUpperHyper5;
else if (current_density < 1e-5)
use_clock = FactorFtranUpperHyper4;
else if (current_density < 1e-4)
use_clock = FactorFtranUpperHyper3;
else if (current_density < 1e-3)
use_clock = FactorFtranUpperHyper2;
else if (current_density < 1e-2)
use_clock = FactorFtranUpperHyper1;
else
use_clock = FactorFtranUpperHyper0;
factor_timer.start(use_clock, factor_timer_clock_pointer);
const HighsInt* u_index = this->u_index.data();
const double* u_value = this->u_value.data();
solveHyper(num_row, u_pivot_lookup.data(), u_pivot_index.data(),
u_pivot_value.data(), u_start.data(), u_last_p.data(),
&u_index[0], &u_value[0], &rhs);
factor_timer.stop(use_clock, factor_timer_clock_pointer);
}
if (update_method == kUpdateMethodPf) {
assert(!(update_method == kUpdateMethodPf));
factor_timer.start(FactorFtranUpperPF, factor_timer_clock_pointer);
ftranPF(rhs);
rhs.tight();
rhs.pack();
factor_timer.stop(FactorFtranUpperPF, factor_timer_clock_pointer);
}
factor_timer.stop(FactorFtranUpper, factor_timer_clock_pointer);
}
void HFactor::btranU(HVector& rhs, const double expected_density,
HighsTimerClock* factor_timer_clock_pointer) const {
FactorTimer factor_timer;
factor_timer.start(FactorBtranUpper, factor_timer_clock_pointer);
if (update_method == kUpdateMethodPf) {
assert(!(update_method == kUpdateMethodPf));
factor_timer.start(FactorBtranUpperPF, factor_timer_clock_pointer);
btranPF(rhs);
factor_timer.stop(FactorBtranUpperPF, factor_timer_clock_pointer);
}
const double current_density = 1.0 * rhs.count * inv_num_row;
const bool sparse_solve = rhs.count < 0 || current_density > kHyperCancel ||
expected_density > kHyperBtranU;
if (sparse_solve) {
factor_timer.start(FactorBtranUpperSps, factor_timer_clock_pointer);
double rhs_synthetic_tick = 0;
double* rhs_array = rhs.array.data();
HighsInt* rhs_index = rhs.index.data();
const HighsInt* ur_start = this->ur_start.data();
const HighsInt* ur_end = this->ur_lastp.data();
const HighsInt* ur_index = this->ur_index.data();
const double* ur_value = this->ur_value.data();
HighsInt rhs_count = 0;
HighsInt u_pivot_count = u_pivot_index.size();
for (HighsInt i_logic = 0; i_logic < u_pivot_count; i_logic++) {
if (u_pivot_index[i_logic] == -1) continue;
const HighsInt pivotRow = u_pivot_index[i_logic];
double pivot_multiplier = rhs_array[pivotRow];
if (fabs(pivot_multiplier) > kHighsTiny) {
pivot_multiplier /= u_pivot_value[i_logic];
rhs_index[rhs_count++] = pivotRow;
rhs_array[pivotRow] = pivot_multiplier;
const HighsInt start = ur_start[i_logic];
const HighsInt end = ur_end[i_logic];
if (i_logic >= num_row) {
rhs_synthetic_tick += (end - start);
}
for (HighsInt k = start; k < end; k++)
rhs_array[ur_index[k]] -= pivot_multiplier * ur_value[k];
} else
rhs_array[pivotRow] = 0;
}
rhs.count = rhs_count;
rhs.synthetic_tick +=
rhs_synthetic_tick * 15 + (u_pivot_count - num_row) * 10;
factor_timer.stop(FactorBtranUpperSps, factor_timer_clock_pointer);
} else {
factor_timer.start(FactorBtranUpperHyper, factor_timer_clock_pointer);
solveHyper(num_row, u_pivot_lookup.data(), u_pivot_index.data(),
u_pivot_value.data(), &ur_start[0], ur_lastp.data(),
&ur_index[0], &ur_value[0], &rhs);
factor_timer.stop(FactorBtranUpperHyper, factor_timer_clock_pointer);
}
assert(rhs.count >= 0);
if (update_method == kUpdateMethodFt) {
factor_timer.start(FactorBtranUpperFT, factor_timer_clock_pointer);
rhs.tight();
rhs.pack();
btranFT(rhs);
rhs.tight();
factor_timer.stop(FactorBtranUpperFT, factor_timer_clock_pointer);
}
if (update_method == kUpdateMethodMpf) {
assert(!(update_method == kUpdateMethodMpf));
factor_timer.start(FactorBtranUpperMPF, factor_timer_clock_pointer);
rhs.tight();
rhs.pack();
btranMPF(rhs);
rhs.tight();
factor_timer.stop(FactorBtranUpperMPF, factor_timer_clock_pointer);
}
factor_timer.stop(FactorBtranUpper, factor_timer_clock_pointer);
}
void HFactor::ftranFT(HVector& vector) const {
assert(vector.count >= 0);
HighsInt rhs_count = vector.count;
HighsInt* rhs_index = vector.index.data();
double* rhs_array = vector.array.data();
const HighsInt pf_pivot_count = pf_pivot_index.size();
const HighsInt* pf_pivot_index = this->pf_pivot_index.data();
const HighsInt* pf_start = this->pf_start.data();
const HighsInt* pf_index = this->pf_index.data();
const double* pf_value = this->pf_value.data();
for (HighsInt i = 0; i < pf_pivot_count; i++) {
HighsInt iRow = pf_pivot_index[i];
double value0 = rhs_array[iRow];
double value1 = value0;
const HighsInt start = pf_start[i];
const HighsInt end = pf_start[i + 1];
for (HighsInt k = start; k < end; k++)
value1 -= rhs_array[pf_index[k]] * pf_value[k];
if (value0 || value1) {
if (value0 == 0) rhs_index[rhs_count++] = iRow;
rhs_array[iRow] = (fabs(value1) < kHighsTiny) ? kHighsZero : value1;
}
}
vector.count = rhs_count;
vector.synthetic_tick += pf_pivot_count * 20 + pf_start[pf_pivot_count] * 5;
if (pf_start[pf_pivot_count] / (pf_pivot_count + 1) < 5) {
vector.synthetic_tick += pf_start[pf_pivot_count] * 5;
}
}
void HFactor::btranFT(HVector& vector) const {
assert(vector.count >= 0);
HighsInt rhs_count = vector.count;
HighsInt* rhs_index = vector.index.data();
double* rhs_array = vector.array.data();
const HighsInt pf_pivot_count = pf_pivot_index.size();
const HighsInt* pf_pivot_index = this->pf_pivot_index.data();
const HighsInt* pf_start = this->pf_start.data();
const HighsInt* pf_index = this->pf_index.data();
const double* pf_value = this->pf_value.data();
double rhs_synthetic_tick = 0;
for (HighsInt i = pf_pivot_count - 1; i >= 0; i--) {
HighsInt pivotRow = pf_pivot_index[i];
double pivot_multiplier = rhs_array[pivotRow];
if (pivot_multiplier) {
const HighsInt start = pf_start[i];
const HighsInt end = pf_start[i + 1];
rhs_synthetic_tick += (end - start);
for (HighsInt k = start; k < end; k++) {
HighsInt iRow = pf_index[k];
double value0 = rhs_array[iRow];
double value1 = value0 - pivot_multiplier * pf_value[k];
if (value0 == 0) rhs_index[rhs_count++] = iRow;
rhs_array[iRow] = (fabs(value1) < kHighsTiny) ? kHighsZero : value1;
}
}
}
vector.synthetic_tick += rhs_synthetic_tick * 15 + pf_pivot_count * 10;
vector.count = rhs_count;
}
void HFactor::ftranPF(HVector& vector) const {
const HighsInt pf_pivot_count = pf_pivot_index.size();
const HighsInt* pf_pivot_index = this->pf_pivot_index.data();
const double* pf_pivot_value = this->pf_pivot_value.data();
const HighsInt* pf_start = this->pf_start.data();
const HighsInt* pf_index = this->pf_index.data();
const double* pf_value = this->pf_value.data();
HighsInt rhs_count = vector.count;
HighsInt* rhs_index = vector.index.data();
double* rhs_array = vector.array.data();
for (HighsInt i = 0; i < pf_pivot_count; i++) {
HighsInt pivotRow = pf_pivot_index[i];
double pivot_multiplier = rhs_array[pivotRow];
if (fabs(pivot_multiplier) > kHighsTiny) {
pivot_multiplier /= pf_pivot_value[i];
rhs_array[pivotRow] = pivot_multiplier;
for (HighsInt k = pf_start[i]; k < pf_start[i + 1]; k++) {
const HighsInt index = pf_index[k];
const double value0 = rhs_array[index];
const double value1 = value0 - pivot_multiplier * pf_value[k];
if (value0 == 0) rhs_index[rhs_count++] = index;
rhs_array[index] = (fabs(value1) < kHighsTiny) ? kHighsZero : value1;
}
}
}
vector.count = rhs_count;
}
void HFactor::btranPF(HVector& vector) const {
const HighsInt pf_pivot_count = pf_pivot_index.size();
const HighsInt* pf_pivot_index = this->pf_pivot_index.data();
const double* pf_pivot_value = this->pf_pivot_value.data();
const HighsInt* pf_start = this->pf_start.data();
const HighsInt* pf_index = this->pf_index.data();
const double* pf_value = this->pf_value.data();
HighsInt rhs_count = vector.count;
HighsInt* rhs_index = vector.index.data();
double* rhs_array = vector.array.data();
for (HighsInt i = pf_pivot_count - 1; i >= 0; i--) {
HighsInt pivotRow = pf_pivot_index[i];
double pivot_multiplier = rhs_array[pivotRow];
for (HighsInt k = pf_start[i]; k < pf_start[i + 1]; k++)
pivot_multiplier -= pf_value[k] * rhs_array[pf_index[k]];
pivot_multiplier /= pf_pivot_value[i];
if (rhs_array[pivotRow] == 0) rhs_index[rhs_count++] = pivotRow;
rhs_array[pivotRow] =
(fabs(pivot_multiplier) < kHighsTiny) ? 1e-100 : pivot_multiplier;
}
vector.count = rhs_count;
}
void HFactor::ftranMPF(HVector& vector) const {
HighsInt rhs_count = vector.count;
HighsInt* rhs_index = vector.index.data();
double* rhs_array = vector.array.data();
HighsInt pf_pivot_count = pf_pivot_value.size();
for (HighsInt i = 0; i < pf_pivot_count; i++) {
solveMatrixT(pf_start[i * 2 + 1], pf_start[i * 2 + 2], pf_start[i * 2],
pf_start[i * 2 + 1], pf_index.data(), pf_value.data(),
pf_pivot_value[i], &rhs_count, rhs_index, rhs_array);
}
vector.count = rhs_count;
}
void HFactor::btranMPF(HVector& vector) const {
HighsInt rhs_count = vector.count;
HighsInt* rhs_index = vector.index.data();
double* rhs_array = vector.array.data();
for (HighsInt i = pf_pivot_value.size() - 1; i >= 0; i--) {
solveMatrixT(pf_start[i * 2], pf_start[i * 2 + 1], pf_start[i * 2 + 1],
pf_start[i * 2 + 2], pf_index.data(), pf_value.data(),
pf_pivot_value[i], &rhs_count, rhs_index, rhs_array);
}
vector.count = rhs_count;
}
void HFactor::ftranAPF(HVector& vector) const {
HighsInt rhs_count = vector.count;
HighsInt* rhs_index = vector.index.data();
double* rhs_array = vector.array.data();
HighsInt pf_pivot_count = pf_pivot_value.size();
for (HighsInt i = pf_pivot_count - 1; i >= 0; i--) {
solveMatrixT(pf_start[i * 2 + 1], pf_start[i * 2 + 2], pf_start[i * 2],
pf_start[i * 2 + 1], pf_index.data(), pf_value.data(),
pf_pivot_value[i], &rhs_count, rhs_index, rhs_array);
}
vector.count = rhs_count;
}
void HFactor::btranAPF(HVector& vector) const {
HighsInt rhs_count = vector.count;
HighsInt* rhs_index = vector.index.data();
double* rhs_array = vector.array.data();
HighsInt pf_pivot_count = pf_pivot_value.size();
for (HighsInt i = 0; i < pf_pivot_count; i++) {
solveMatrixT(pf_start[i * 2], pf_start[i * 2 + 1], pf_start[i * 2 + 1],
pf_start[i * 2 + 2], pf_index.data(), pf_value.data(),
pf_pivot_value[i], &rhs_count, rhs_index, rhs_array);
}
vector.count = rhs_count;
}
void HFactor::updateCFT(HVector* aq, HVector* ep, HighsInt* iRow
) {
HighsInt num_update = 0;
for (HVector* vec = aq; vec != 0; vec = vec->next) num_update++;
HVector** aq_work = new HVector*[num_update];
HVector** ep_work = new HVector*[num_update];
for (HighsInt i = 0; i < num_update; i++) {
aq_work[i] = aq;
ep_work[i] = ep;
aq = aq->next;
ep = ep->next;
}
HighsInt pf_np0 = pf_pivot_index.size();
HighsInt* p_logic = new HighsInt[num_update];
double* p_value = new double[num_update];
double* p_alpha = new double[num_update];
for (HighsInt cp = 0; cp < num_update; cp++) {
HighsInt c_row = iRow[cp];
HighsInt i_logic = u_pivot_lookup[c_row];
p_logic[cp] = i_logic;
p_value[cp] = u_pivot_value[i_logic];
p_alpha[cp] = aq_work[cp]->array[c_row];
}
HighsInt* t_start = new HighsInt[num_update + 1];
double* t_pivot = new double[num_update];
t_start[0] = u_index.size();
vector<pair<HighsInt, HighsInt>> sorted_pp;
for (HighsInt cp = 0; cp < num_update; cp++) {
iwork.clear();
for (HighsInt i = 0; i < aq_work[cp]->packCount; i++) {
HighsInt index = aq_work[cp]->packIndex[i];
double value = aq_work[cp]->packValue[i];
iwork.push_back(index);
dwork[index] = value;
}
for (HighsInt pp = 0; pp < cp; pp++) {
HighsInt p_row = iRow[pp];
double value = dwork[p_row];
HighsInt pf_pp = pp + pf_np0;
for (HighsInt i = pf_start[pf_pp]; i < pf_start[pf_pp + 1]; i++)
value -= dwork[pf_index[i]] * pf_value[i];
iwork.push_back(p_row); dwork[p_row] = value;
}
double ppaq = dwork[iRow[cp]]; dwork[iRow[cp]] = 0;
HighsInt u_countX = t_start[cp];
HighsInt u_startX = u_countX;
for (HighsInt index : iwork) {
double value = dwork[index];
dwork[index] = 0; if (fabs(value) > kHighsTiny) {
u_index.push_back(index);
u_value.push_back(value);
}
}
u_countX = u_index.size();
t_start[cp + 1] = u_countX;
t_pivot[cp] = p_value[cp] * p_alpha[cp];
iwork.clear();
for (HighsInt i = 0; i < ep_work[cp]->packCount; i++) {
HighsInt index = ep_work[cp]->packIndex[i];
double value = ep_work[cp]->packValue[i];
iwork.push_back(index);
dwork[index] = value;
}
for (HighsInt isort = 0; isort < cp; isort++) {
HighsInt pp = sorted_pp[isort].second;
HighsInt p_row = iRow[pp];
double multiplier = -p_value[pp] * dwork[p_row];
if (fabs(dwork[p_row]) > kHighsTiny) {
for (HighsInt i = 0; i < ep_work[pp]->packCount; i++) {
HighsInt index = ep_work[pp]->packIndex[i];
double value = ep_work[pp]->packValue[i];
iwork.push_back(index);
dwork[index] += value * multiplier;
}
}
dwork[p_row] = 0; }
for (HighsInt pp = 0; pp < cp; pp++) {
HighsInt kpivot = iRow[pp];
double value = dwork[kpivot];
for (HighsInt k = t_start[pp]; k < t_start[pp + 1]; k++)
value -= dwork[u_index[k]] * u_value[k];
value /= t_pivot[pp];
iwork.push_back(kpivot);
dwork[kpivot] = value; }
double thex = 0;
for (HighsInt k = u_startX; k < u_countX; k++) {
HighsInt index = u_index[k];
double value = u_value[k];
thex += dwork[index] * value;
}
t_pivot[cp] = ppaq + thex * p_value[cp];
dwork[iRow[cp]] = 0;
double pivot_multiplier = -p_value[cp];
for (HighsInt index : iwork) {
double value = dwork[index];
dwork[index] = 0;
if (fabs(value) > kHighsTiny) {
pf_index.push_back(index);
pf_value.push_back(value * pivot_multiplier);
}
}
pf_pivot_index.push_back(iRow[cp]);
u_total_x += pf_index.size() - pf_start.back();
pf_start.push_back(pf_index.size());
sorted_pp.push_back(make_pair(p_logic[cp], cp));
pdqsort(sorted_pp.begin(), sorted_pp.end());
}
for (HighsInt cp = 0; cp < num_update; cp++) {
HighsInt cIndex = iRow[cp];
HighsInt cLogic = p_logic[cp];
u_total_x -= ur_lastp[cLogic] - ur_start[cLogic];
for (HighsInt k = ur_start[cLogic]; k < ur_lastp[cLogic]; k++) {
HighsInt i_logic = u_pivot_lookup[ur_index[k]];
HighsInt i_find = u_start[i_logic];
HighsInt i_last = --u_last_p[i_logic];
for (; i_find <= i_last; i_find++)
if (u_index[i_find] == cIndex) break;
u_index[i_find] = u_index[i_last];
u_value[i_find] = u_value[i_last];
}
u_total_x -= u_last_p[cLogic] - u_start[cLogic];
for (HighsInt k = u_start[cLogic]; k < u_last_p[cLogic]; k++) {
HighsInt i_logic = u_pivot_lookup[u_index[k]];
HighsInt i_find = ur_start[i_logic];
HighsInt i_last = --ur_lastp[i_logic];
for (; i_find <= i_last; i_find++)
if (ur_index[i_find] == cIndex) break;
ur_space[i_logic]++;
ur_index[i_find] = ur_index[i_last];
ur_value[i_find] = ur_value[i_last];
}
HighsInt u_startX = t_start[cp];
HighsInt u_endX = t_start[cp + 1];
u_total_x += u_endX - u_startX;
for (HighsInt k = u_startX; k < u_endX; k++) {
HighsInt i_logic = u_pivot_lookup[u_index[k]];
if (ur_space[i_logic] == 0) {
HighsInt row_start = ur_start[i_logic];
HighsInt row_count = ur_lastp[i_logic] - row_start;
HighsInt new_start = ur_index.size();
HighsInt new_space = row_count * 1.1 + 5;
ur_index.resize(new_start + new_space);
ur_value.resize(new_start + new_space);
HighsInt i_from = row_start;
HighsInt i_end = row_start + row_count;
HighsInt i_to = new_start;
copy(&ur_index[i_from], &ur_index[i_end], &ur_index[i_to]);
copy(&ur_value[i_from], &ur_value[i_end], &ur_value[i_to]);
ur_start[i_logic] = new_start;
ur_lastp[i_logic] = new_start + row_count;
ur_space[i_logic] = new_space - row_count;
}
ur_space[i_logic]--;
HighsInt i_put = ur_lastp[i_logic]++;
ur_index[i_put] = cIndex;
ur_value[i_put] = u_value[k];
}
u_start.push_back(u_startX);
u_last_p.push_back(u_endX);
ur_start.push_back(ur_start[cLogic]);
ur_lastp.push_back(ur_start[cLogic]);
ur_space.push_back(ur_space[cLogic] + ur_lastp[cLogic] - ur_start[cLogic]);
u_pivot_lookup[cIndex] = u_pivot_index.size();
u_pivot_index[cLogic] = -1;
u_pivot_index.push_back(cIndex);
u_pivot_value.push_back(t_pivot[cp]);
}
delete[] aq_work;
delete[] ep_work;
delete[] p_logic;
delete[] p_value;
delete[] p_alpha;
delete[] t_start;
delete[] t_pivot;
}
void HFactor::updateFT(HVector* aq, HVector* ep, HighsInt iRow
) {
HighsInt p_logic = u_pivot_lookup[iRow];
double pivot = u_pivot_value[p_logic];
double alpha = aq->array[iRow];
u_pivot_index[p_logic] = -1;
for (HighsInt k = ur_start[p_logic]; k < ur_lastp[p_logic]; k++) {
HighsInt i_logic = u_pivot_lookup[ur_index[k]];
HighsInt i_find = u_start[i_logic];
HighsInt i_last = --u_last_p[i_logic];
for (; i_find <= i_last; i_find++)
if (u_index[i_find] == iRow) break;
u_index[i_find] = u_index[i_last];
u_value[i_find] = u_value[i_last];
}
for (HighsInt k = u_start[p_logic]; k < u_last_p[p_logic]; k++) {
HighsInt i_logic = u_pivot_lookup[u_index[k]];
HighsInt i_find = ur_start[i_logic];
HighsInt i_last = --ur_lastp[i_logic];
for (; i_find <= i_last; i_find++)
if (ur_index[i_find] == iRow) break;
ur_space[i_logic]++;
ur_index[i_find] = ur_index[i_last];
ur_value[i_find] = ur_value[i_last];
}
u_start.push_back(u_index.size());
for (HighsInt i = 0; i < aq->packCount; i++)
if (aq->packIndex[i] != iRow) {
u_index.push_back(aq->packIndex[i]);
u_value.push_back(aq->packValue[i]);
}
u_last_p.push_back(u_index.size());
HighsInt u_startX = u_start.back();
HighsInt u_endX = u_last_p.back();
u_total_x += u_endX - u_startX + 1;
for (HighsInt k = u_startX; k < u_endX; k++) {
HighsInt i_logic = u_pivot_lookup[u_index[k]];
if (ur_space[i_logic] == 0) {
HighsInt row_start = ur_start[i_logic];
HighsInt row_count = ur_lastp[i_logic] - row_start;
HighsInt new_start = ur_index.size();
HighsInt new_space = row_count * 1.1 + 5;
ur_index.resize(new_start + new_space);
ur_value.resize(new_start + new_space);
HighsInt i_from = row_start;
HighsInt i_end = row_start + row_count;
HighsInt i_to = new_start;
copy(&ur_index[i_from], &ur_index[i_end], &ur_index[i_to]);
copy(&ur_value[i_from], &ur_value[i_end], &ur_value[i_to]);
ur_start[i_logic] = new_start;
ur_lastp[i_logic] = new_start + row_count;
ur_space[i_logic] = new_space - row_count;
}
ur_space[i_logic]--;
HighsInt i_put = ur_lastp[i_logic]++;
ur_index[i_put] = iRow;
ur_value[i_put] = u_value[k];
}
ur_start.push_back(ur_start[p_logic]);
ur_lastp.push_back(ur_start[p_logic]);
ur_space.push_back(ur_space[p_logic] + ur_lastp[p_logic] - ur_start[p_logic]);
u_pivot_lookup[iRow] = u_pivot_index.size();
u_pivot_index.push_back(iRow);
u_pivot_value.push_back(pivot * alpha);
for (HighsInt i = 0; i < ep->packCount; i++) {
if (ep->packIndex[i] != iRow) {
pf_index.push_back(ep->packIndex[i]);
pf_value.push_back(-ep->packValue[i] * pivot);
}
}
u_total_x += pf_index.size() - pf_start.back();
pf_pivot_index.push_back(iRow);
pf_start.push_back(pf_index.size());
u_total_x -= u_last_p[p_logic] - u_start[p_logic];
u_total_x -= ur_lastp[p_logic] - ur_start[p_logic];
}
void HFactor::updatePF(HVector* aq, HighsInt iRow, HighsInt* hint) {
const HighsInt column_count = aq->packCount;
const HighsInt* variable_index = aq->packIndex.data();
const double* columnArray = aq->packValue.data();
for (HighsInt i = 0; i < column_count; i++) {
HighsInt index = variable_index[i];
double value = columnArray[i];
if (index != iRow) {
pf_index.push_back(index);
pf_value.push_back(value);
}
}
pf_pivot_index.push_back(iRow);
pf_pivot_value.push_back(aq->array[iRow]);
pf_start.push_back(pf_index.size());
u_total_x += aq->packCount;
if (u_total_x > u_merit_x) *hint = 1;
}
void HFactor::updateMPF(HVector* aq, HVector* ep, HighsInt iRow,
HighsInt* hint) {
for (HighsInt i = 0; i < aq->packCount; i++) {
pf_index.push_back(aq->packIndex[i]);
pf_value.push_back(aq->packValue[i]);
}
HighsInt p_logic = u_pivot_lookup[iRow];
HighsInt u_startX = u_start[p_logic];
HighsInt u_endX = u_start[p_logic + 1];
for (HighsInt k = u_startX; k < u_endX; k++) {
pf_index.push_back(u_index[k]);
pf_value.push_back(-u_value[k]);
}
pf_index.push_back(iRow);
pf_value.push_back(-u_pivot_value[p_logic]);
pf_start.push_back(pf_index.size());
for (HighsInt i = 0; i < ep->packCount; i++) {
pf_index.push_back(ep->packIndex[i]);
pf_value.push_back(ep->packValue[i]);
}
pf_start.push_back(pf_index.size());
pf_pivot_value.push_back(aq->array[iRow]);
u_total_x += aq->packCount + ep->packCount;
if (u_total_x > u_merit_x) *hint = 1;
}
void HFactor::updateAPF(HVector* aq, HVector* ep, HighsInt iRow
) {
for (HighsInt i = 0; i < aq->packCount; i++) {
pf_index.push_back(aq->packIndex[i]);
pf_value.push_back(aq->packValue[i]);
}
HighsInt variable_out = basic_index[iRow];
if (variable_out >= num_col) {
pf_index.push_back(variable_out - num_col);
pf_value.push_back(-1);
} else {
for (HighsInt k = a_start[variable_out]; k < a_start[variable_out + 1];
k++) {
pf_index.push_back(a_index[k]);
pf_value.push_back(-a_value[k]);
}
}
pf_start.push_back(pf_index.size());
for (HighsInt i = 0; i < ep->packCount; i++) {
pf_index.push_back(ep->packIndex[i]);
pf_value.push_back(ep->packValue[i]);
}
pf_start.push_back(pf_index.size());
pf_pivot_value.push_back(aq->array[iRow]);
}
InvertibleRepresentation HFactor::getInvert() const {
InvertibleRepresentation invert;
invert.l_pivot_index = this->l_pivot_index;
invert.l_pivot_lookup = this->l_pivot_lookup;
invert.l_start = this->l_start;
invert.l_index = this->l_index;
invert.l_value = this->l_value;
invert.lr_start = this->lr_start;
invert.lr_index = this->lr_index;
invert.lr_value = this->lr_value;
invert.u_pivot_lookup = this->u_pivot_lookup;
invert.u_pivot_index = this->u_pivot_index;
invert.u_pivot_value = this->u_pivot_value;
invert.u_start = this->u_start;
invert.u_last_p = this->u_last_p;
invert.u_index = this->u_index;
invert.u_value = this->u_value;
invert.ur_start = this->ur_start;
invert.ur_lastp = this->ur_lastp;
invert.ur_space = this->ur_space;
invert.ur_index = this->ur_index;
invert.ur_value = this->ur_value;
invert.pf_start = this->pf_start;
invert.pf_index = this->pf_index;
invert.pf_value = this->pf_value;
invert.pf_pivot_index = this->pf_pivot_index;
invert.pf_pivot_value = this->pf_pivot_value;
return invert;
}
void HFactor::setInvert(const InvertibleRepresentation& invert) {
this->l_pivot_index = invert.l_pivot_index;
this->l_pivot_lookup = invert.l_pivot_lookup;
this->l_start = invert.l_start;
this->l_index = invert.l_index;
this->l_value = invert.l_value;
this->lr_start = invert.lr_start;
this->lr_index = invert.lr_index;
this->lr_value = invert.lr_value;
this->u_pivot_lookup = invert.u_pivot_lookup;
this->u_pivot_index = invert.u_pivot_index;
this->u_pivot_value = invert.u_pivot_value;
this->u_start = invert.u_start;
this->u_last_p = invert.u_last_p;
this->u_index = invert.u_index;
this->u_value = invert.u_value;
this->ur_start = invert.ur_start;
this->ur_lastp = invert.ur_lastp;
this->ur_space = invert.ur_space;
this->ur_index = invert.ur_index;
this->ur_value = invert.ur_value;
this->pf_start = invert.pf_start;
this->pf_index = invert.pf_index;
this->pf_value = invert.pf_value;
this->pf_pivot_index = invert.pf_pivot_index;
this->pf_pivot_value = invert.pf_pivot_value;
}
void InvertibleRepresentation::clear() {
this->l_pivot_index.clear();
this->l_pivot_lookup.clear();
this->l_start.clear();
this->l_index.clear();
this->l_value.clear();
this->lr_start.clear();
this->lr_index.clear();
this->lr_value.clear();
this->u_pivot_lookup.clear();
this->u_pivot_index.clear();
this->u_pivot_value.clear();
this->u_start.clear();
this->u_last_p.clear();
this->u_index.clear();
this->u_value.clear();
this->ur_start.clear();
this->ur_lastp.clear();
this->ur_space.clear();
this->ur_index.clear();
this->ur_value.clear();
this->pf_start.clear();
this->pf_index.clear();
this->pf_value.clear();
this->pf_pivot_index.clear();
this->pf_pivot_value.clear();
}