cleaning
This commit is contained in:
@@ -466,7 +466,7 @@ void BasisFactorization::RightSolveForProblemColumn(ColIndex col,
|
||||
}
|
||||
|
||||
Fractional BasisFactorization::RightSolveSquaredNorm(
|
||||
const SparseColumn& a) const {
|
||||
const ColumnView& a) const {
|
||||
SCOPED_TIME_STAT(&stats_);
|
||||
DCHECK(IsRefactorized());
|
||||
BumpDeterministicTimeForSolve(a.num_entries().value());
|
||||
|
||||
@@ -235,7 +235,7 @@ class BasisFactorization {
|
||||
// Returns the norm of B^{-1}.a, this is a specific function because
|
||||
// it is a bit faster and it avoids polluting the stats of RightSolve().
|
||||
// It can be called only when IsRefactorized() is true.
|
||||
Fractional RightSolveSquaredNorm(const SparseColumn& a) const;
|
||||
Fractional RightSolveSquaredNorm(const ColumnView& a) const;
|
||||
|
||||
// Returns the norm of (B^T)^{-1}.e_row where e is an unit vector.
|
||||
// This is a bit faster and avoids polluting the stats of LeftSolve().
|
||||
|
||||
@@ -21,14 +21,15 @@
|
||||
namespace operations_research {
|
||||
namespace glop {
|
||||
|
||||
InitialBasis::InitialBasis(const MatrixView& matrix, const DenseRow& objective,
|
||||
InitialBasis::InitialBasis(const CompactSparseMatrix& compact_matrix,
|
||||
const DenseRow& objective,
|
||||
const DenseRow& lower_bound,
|
||||
const DenseRow& upper_bound,
|
||||
const VariableTypeRow& variable_type)
|
||||
: max_scaled_abs_cost_(0.0),
|
||||
bixby_column_comparator_(*this),
|
||||
triangular_column_comparator_(*this),
|
||||
matrix_(matrix),
|
||||
compact_matrix_(compact_matrix),
|
||||
objective_(objective),
|
||||
lower_bound_(lower_bound),
|
||||
upper_bound_(upper_bound),
|
||||
@@ -38,7 +39,7 @@ void InitialBasis::CompleteBixbyBasis(ColIndex num_cols,
|
||||
RowToColMapping* basis) {
|
||||
// Initialize can_be_replaced ('I' in Bixby's paper) and has_zero_coefficient
|
||||
// ('r' in Bixby's paper).
|
||||
const RowIndex num_rows = matrix_.num_rows();
|
||||
const RowIndex num_rows = compact_matrix_.num_rows();
|
||||
DenseBooleanColumn can_be_replaced(num_rows, false);
|
||||
DenseBooleanColumn has_zero_coefficient(num_rows, false);
|
||||
DCHECK_EQ(num_rows, basis->size());
|
||||
@@ -51,7 +52,7 @@ void InitialBasis::CompleteBixbyBasis(ColIndex num_cols,
|
||||
}
|
||||
|
||||
// This is 'v' in Bixby's paper.
|
||||
DenseColumn scaled_diagonal_abs(matrix_.num_rows(), kInfinity);
|
||||
DenseColumn scaled_diagonal_abs(compact_matrix_.num_rows(), kInfinity);
|
||||
|
||||
// Compute a list of candidate indices and sort them using the heuristic
|
||||
// described in Bixby's paper.
|
||||
@@ -63,7 +64,7 @@ void InitialBasis::CompleteBixbyBasis(ColIndex num_cols,
|
||||
for (int i = 0; i < candidates.size(); ++i) {
|
||||
bool enter_basis = false;
|
||||
const ColIndex candidate_col_index = candidates[i];
|
||||
const SparseColumn& candidate_col = matrix_.column(candidate_col_index);
|
||||
const auto& candidate_col = compact_matrix_.column(candidate_col_index);
|
||||
|
||||
// Bixby's heuristic only works with scaled columns. This should be the
|
||||
// case by default since we only use this when the matrix is scaled, but
|
||||
@@ -120,7 +121,7 @@ template <bool only_allow_zero_cost_column>
|
||||
void InitialBasis::CompleteTriangularBasis(ColIndex num_cols,
|
||||
RowToColMapping* basis) {
|
||||
// Initialize can_be_replaced.
|
||||
const RowIndex num_rows = matrix_.num_rows();
|
||||
const RowIndex num_rows = compact_matrix_.num_rows();
|
||||
DenseBooleanColumn can_be_replaced(num_rows, false);
|
||||
DCHECK_EQ(num_rows, basis->size());
|
||||
basis->resize(num_rows, kInvalidCol);
|
||||
@@ -135,7 +136,7 @@ void InitialBasis::CompleteTriangularBasis(ColIndex num_cols,
|
||||
residual_pattern.Reset(num_rows, num_cols);
|
||||
for (ColIndex col(0); col < num_cols; ++col) {
|
||||
if (only_allow_zero_cost_column && objective_[col] != 0.0) continue;
|
||||
for (const SparseColumn::Entry e : matrix_.column(col)) {
|
||||
for (const SparseColumn::Entry e : compact_matrix_.column(col)) {
|
||||
if (can_be_replaced[e.row()]) {
|
||||
residual_pattern.AddEntry(e.row(), col);
|
||||
}
|
||||
@@ -173,7 +174,7 @@ void InitialBasis::CompleteTriangularBasis(ColIndex num_cols,
|
||||
RowIndex row(kInvalidRow);
|
||||
Fractional coeff = 0.0;
|
||||
Fractional max_magnitude = 0.0;
|
||||
for (const SparseColumn::Entry e : matrix_.column(candidate)) {
|
||||
for (const SparseColumn::Entry e : compact_matrix_.column(candidate)) {
|
||||
max_magnitude = std::max(max_magnitude, std::abs(e.coefficient()));
|
||||
if (can_be_replaced[e.row()]) {
|
||||
row = e.row();
|
||||
@@ -218,8 +219,8 @@ int InitialBasis::GetMarosPriority(ColIndex col) const {
|
||||
int InitialBasis::GetMarosPriority(RowIndex row) const {
|
||||
// Priority values for rows are equal to
|
||||
// 3 - row priority values as defined in Maros's book
|
||||
ColIndex slack_index(RowToColIndex(row) + matrix_.num_cols() -
|
||||
RowToColIndex(matrix_.num_rows()));
|
||||
ColIndex slack_index(RowToColIndex(row) + compact_matrix_.num_cols() -
|
||||
RowToColIndex(compact_matrix_.num_rows()));
|
||||
|
||||
return GetMarosPriority(slack_index);
|
||||
}
|
||||
@@ -229,7 +230,7 @@ void InitialBasis::GetMarosBasis(ColIndex num_cols, RowToColMapping* basis) {
|
||||
VLOG(1) << "Starting Maros crash procedure.";
|
||||
|
||||
// Initialize basis to the all-slack basis.
|
||||
const RowIndex num_rows = matrix_.num_rows();
|
||||
const RowIndex num_rows = compact_matrix_.num_rows();
|
||||
const ColIndex first_slack = num_cols - RowToColIndex(num_rows);
|
||||
DCHECK_EQ(num_rows, basis->size());
|
||||
basis->resize(num_rows);
|
||||
@@ -255,7 +256,7 @@ void InitialBasis::GetMarosBasis(ColIndex num_cols, RowToColMapping* basis) {
|
||||
MatrixNonZeroPattern residual_pattern;
|
||||
residual_pattern.Reset(num_rows, num_cols);
|
||||
for (ColIndex col(0); col < first_slack; ++col) {
|
||||
for (const SparseColumn::Entry e : matrix_.column(col)) {
|
||||
for (const SparseColumn::Entry e : compact_matrix_.column(col)) {
|
||||
if (available[RowToColIndex(e.row())] && available[col]) {
|
||||
residual_pattern.AddEntry(e.row(), col);
|
||||
}
|
||||
@@ -300,7 +301,7 @@ void InitialBasis::GetMarosBasis(ColIndex num_cols, RowToColMapping* basis) {
|
||||
// Make sure that the pivotal entry is not too small in magnitude.
|
||||
Fractional max_magnitude = 0;
|
||||
pivot_absolute_value = 0.0;
|
||||
const SparseColumn& column_values = matrix_.column(col);
|
||||
const auto& column_values = compact_matrix_.column(col);
|
||||
for (const SparseColumn::Entry e : column_values) {
|
||||
const Fractional absolute_value = std::fabs(e.coefficient());
|
||||
if (e.row() == max_rpf_row) pivot_absolute_value = absolute_value;
|
||||
@@ -355,7 +356,7 @@ void InitialBasis::ComputeCandidates(ColIndex num_cols,
|
||||
max_scaled_abs_cost_ = 0.0;
|
||||
for (ColIndex col(0); col < num_cols; ++col) {
|
||||
if (variable_type_[col] != VariableType::FIXED_VARIABLE &&
|
||||
matrix_.column(col).num_entries() > 0) {
|
||||
compact_matrix_.column(col).num_entries() > 0) {
|
||||
candidates->push_back(col);
|
||||
max_scaled_abs_cost_ =
|
||||
std::max(max_scaled_abs_cost_, std::abs(objective_[col]));
|
||||
@@ -427,10 +428,10 @@ bool InitialBasis::TriangularColumnComparator::operator()(
|
||||
//
|
||||
// TODO(user): Experiments more with this comparator or the
|
||||
// BixbyColumnComparator.
|
||||
if (initial_basis_.matrix_.column(col_a).num_entries() !=
|
||||
initial_basis_.matrix_.column(col_b).num_entries()) {
|
||||
return initial_basis_.matrix_.column(col_a).num_entries() >
|
||||
initial_basis_.matrix_.column(col_b).num_entries();
|
||||
if (initial_basis_.compact_matrix_.column(col_a).num_entries() !=
|
||||
initial_basis_.compact_matrix_.column(col_b).num_entries()) {
|
||||
return initial_basis_.compact_matrix_.column(col_a).num_entries() >
|
||||
initial_basis_.compact_matrix_.column(col_b).num_entries();
|
||||
}
|
||||
return initial_basis_.GetColumnPenalty(col_a) >
|
||||
initial_basis_.GetColumnPenalty(col_b);
|
||||
|
||||
@@ -44,8 +44,9 @@ namespace glop {
|
||||
class InitialBasis {
|
||||
public:
|
||||
// Takes references to the linear program data we need.
|
||||
InitialBasis(const MatrixView& matrix, const DenseRow& objective,
|
||||
const DenseRow& lower_bound, const DenseRow& upper_bound,
|
||||
InitialBasis(const CompactSparseMatrix& compact_matrix,
|
||||
const DenseRow& objective, const DenseRow& lower_bound,
|
||||
const DenseRow& upper_bound,
|
||||
const VariableTypeRow& variable_type);
|
||||
|
||||
// Completes the entries of the given basis that are equal to kInvalidCol with
|
||||
@@ -119,7 +120,7 @@ class InitialBasis {
|
||||
const InitialBasis& initial_basis_;
|
||||
} triangular_column_comparator_;
|
||||
|
||||
const MatrixView& matrix_;
|
||||
const CompactSparseMatrix& compact_matrix_;
|
||||
const DenseRow& objective_;
|
||||
const DenseRow& lower_bound_;
|
||||
const DenseRow& upper_bound_;
|
||||
|
||||
@@ -105,7 +105,7 @@ Fractional ComputeSquaredNormAndResetToZero(
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Fractional LuFactorization::RightSolveSquaredNorm(const SparseColumn& a) const {
|
||||
Fractional LuFactorization::RightSolveSquaredNorm(const ColumnView& a) const {
|
||||
SCOPED_TIME_STAT(&stats_);
|
||||
if (is_identity_factorization_) return SquaredNorm(a);
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ class LuFactorization {
|
||||
const SparseColumn& GetColumnOfU(ColIndex col) const;
|
||||
|
||||
// Returns the norm of B^{-1}.a
|
||||
Fractional RightSolveSquaredNorm(const SparseColumn& a) const;
|
||||
Fractional RightSolveSquaredNorm(const ColumnView& a) const;
|
||||
|
||||
// Returns the norm of (B^T)^{-1}.e_row where e is an unit vector.
|
||||
Fractional DualEdgeSquaredNorm(RowIndex row) const;
|
||||
|
||||
@@ -19,12 +19,10 @@
|
||||
namespace operations_research {
|
||||
namespace glop {
|
||||
|
||||
PrimalEdgeNorms::PrimalEdgeNorms(const MatrixView& matrix,
|
||||
const CompactSparseMatrix& compact_matrix,
|
||||
PrimalEdgeNorms::PrimalEdgeNorms(const CompactSparseMatrix& compact_matrix,
|
||||
const VariablesInfo& variables_info,
|
||||
const BasisFactorization& basis_factorization)
|
||||
: matrix_(matrix),
|
||||
compact_matrix_(compact_matrix),
|
||||
: compact_matrix_(compact_matrix),
|
||||
variables_info_(variables_info),
|
||||
basis_factorization_(basis_factorization),
|
||||
stats_(),
|
||||
@@ -115,10 +113,10 @@ void PrimalEdgeNorms::UpdateBeforeBasisPivot(ColIndex entering_col,
|
||||
|
||||
void PrimalEdgeNorms::ComputeMatrixColumnNorms() {
|
||||
SCOPED_TIME_STAT(&stats_);
|
||||
matrix_column_norms_.resize(matrix_.num_cols(), 0.0);
|
||||
for (ColIndex col(0); col < matrix_.num_cols(); ++col) {
|
||||
matrix_column_norms_[col] = sqrt(SquaredNorm(matrix_.column(col)));
|
||||
num_operations_ += matrix_.column(col).num_entries().value();
|
||||
matrix_column_norms_.resize(compact_matrix_.num_cols(), 0.0);
|
||||
for (ColIndex col(0); col < compact_matrix_.num_cols(); ++col) {
|
||||
matrix_column_norms_[col] = sqrt(SquaredNorm(compact_matrix_.column(col)));
|
||||
num_operations_ += compact_matrix_.column(col).num_entries().value();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,12 +126,12 @@ void PrimalEdgeNorms::ComputeEdgeSquaredNorms() {
|
||||
// Since we will do a lot of inversions, it is better to be as efficient and
|
||||
// precise as possible by refactorizing the basis.
|
||||
DCHECK(basis_factorization_.IsRefactorized());
|
||||
edge_squared_norms_.resize(matrix_.num_cols(), 0.0);
|
||||
edge_squared_norms_.resize(compact_matrix_.num_cols(), 0.0);
|
||||
for (const ColIndex col : variables_info_.GetIsRelevantBitRow()) {
|
||||
// Note the +1.0 in the squared norm for the component of the edge on the
|
||||
// 'entering_col'.
|
||||
edge_squared_norms_[col] =
|
||||
1.0 + basis_factorization_.RightSolveSquaredNorm(matrix_.column(col));
|
||||
edge_squared_norms_[col] = 1.0 + basis_factorization_.RightSolveSquaredNorm(
|
||||
compact_matrix_.column(col));
|
||||
}
|
||||
recompute_edge_squared_norms_ = false;
|
||||
}
|
||||
@@ -256,7 +254,7 @@ void PrimalEdgeNorms::ResetDevexWeights() {
|
||||
if (parameters_.initialize_devex_with_column_norms()) {
|
||||
devex_weights_ = GetMatrixColumnNorms();
|
||||
} else {
|
||||
devex_weights_.assign(matrix_.num_cols(), 1.0);
|
||||
devex_weights_.assign(compact_matrix_.num_cols(), 1.0);
|
||||
}
|
||||
num_devex_updates_since_reset_ = 0;
|
||||
reset_devex_weights_ = false;
|
||||
|
||||
@@ -55,8 +55,7 @@ class PrimalEdgeNorms {
|
||||
// Takes references to the linear program data we need. Note that we assume
|
||||
// that the matrix will never change in our back, but the other references are
|
||||
// supposed to reflect the correct state.
|
||||
PrimalEdgeNorms(const MatrixView& matrix,
|
||||
const CompactSparseMatrix& compact_matrix,
|
||||
PrimalEdgeNorms(const CompactSparseMatrix& compact_matrix,
|
||||
const VariablesInfo& variables_info,
|
||||
const BasisFactorization& basis_factorization);
|
||||
|
||||
@@ -162,7 +161,6 @@ class PrimalEdgeNorms {
|
||||
const UpdateRow& update_row);
|
||||
|
||||
// Problem data that should be updated from outside.
|
||||
const MatrixView& matrix_;
|
||||
const CompactSparseMatrix& compact_matrix_;
|
||||
const VariablesInfo& variables_info_;
|
||||
const BasisFactorization& basis_factorization_;
|
||||
|
||||
@@ -90,7 +90,7 @@ RevisedSimplex::RevisedSimplex()
|
||||
variable_values_(parameters_, compact_matrix_, basis_, variables_info_,
|
||||
basis_factorization_),
|
||||
dual_edge_norms_(basis_factorization_),
|
||||
primal_edge_norms_(matrix_with_slack_, compact_matrix_, variables_info_,
|
||||
primal_edge_norms_(compact_matrix_, variables_info_,
|
||||
basis_factorization_),
|
||||
update_row_(compact_matrix_, transposed_matrix_, variables_info_, basis_,
|
||||
basis_factorization_),
|
||||
@@ -177,9 +177,9 @@ Status RevisedSimplex::Solve(const LinearProgram& lp, TimeLimit* time_limit) {
|
||||
|
||||
const bool use_dual = parameters_.use_dual_simplex();
|
||||
VLOG(1) << "------ " << (use_dual ? "Dual simplex." : "Primal simplex.");
|
||||
VLOG(1) << "The matrix has " << matrix_with_slack_.num_rows() << " rows, "
|
||||
<< matrix_with_slack_.num_cols() << " columns, "
|
||||
<< matrix_with_slack_.num_entries() << " entries.";
|
||||
VLOG(1) << "The matrix has " << compact_matrix_.num_rows() << " rows, "
|
||||
<< compact_matrix_.num_cols() << " columns, "
|
||||
<< compact_matrix_.num_entries() << " entries.";
|
||||
|
||||
// TODO(user): Avoid doing the first phase checks when we know from the
|
||||
// incremental solve that the solution is already dual or primal feasible.
|
||||
@@ -589,10 +589,9 @@ void RevisedSimplex::UseSingletonColumnInInitialBasis(RowToColMapping* basis) {
|
||||
std::vector<ColIndex> singleton_column;
|
||||
DenseRow cost_variation(num_cols_, 0.0);
|
||||
for (ColIndex col(0); col < num_cols_; ++col) {
|
||||
if (matrix_with_slack_.column(col).num_entries() != 1) continue;
|
||||
if (compact_matrix_.column(col).num_entries() != 1) continue;
|
||||
if (lower_bound_[col] == upper_bound_[col]) continue;
|
||||
const Fractional slope =
|
||||
matrix_with_slack_.column(col).GetFirstCoefficient();
|
||||
const Fractional slope = compact_matrix_.column(col).GetFirstCoefficient();
|
||||
if (variable_values_.Get(col) == lower_bound_[col]) {
|
||||
cost_variation[col] = objective_[col] / std::abs(slope);
|
||||
} else {
|
||||
@@ -693,12 +692,6 @@ bool RevisedSimplex::InitializeMatrixAndTestIfUnchanged(
|
||||
// because they were checked by lp.IsInEquationForm() when Solve() was called.
|
||||
if (old_part_of_matrix_is_unchanged && lp.num_constraints() == num_rows_ &&
|
||||
lp.num_variables() == num_cols_) {
|
||||
// IMPORTANT: we need to recreate matrix_with_slack_ because this matrix
|
||||
// view was refering to a previous lp.GetSparseMatrix(). The matrices are
|
||||
// the same, but we do need to update the pointers.
|
||||
//
|
||||
// TODO(user): use compact_matrix_ everywhere instead.
|
||||
matrix_with_slack_.PopulateFromMatrix(lp.GetSparseMatrix());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -716,8 +709,7 @@ bool RevisedSimplex::InitializeMatrixAndTestIfUnchanged(
|
||||
*num_new_cols =
|
||||
*only_change_is_new_cols ? lp.num_variables() - num_cols_ : ColIndex(0);
|
||||
|
||||
// Initialize matrix_with_slack_.
|
||||
matrix_with_slack_.PopulateFromMatrix(lp.GetSparseMatrix());
|
||||
// Initialize first_slack_.
|
||||
first_slack_col_ = lp.GetFirstSlackVariable();
|
||||
|
||||
// Initialize the new dimensions.
|
||||
@@ -727,7 +719,8 @@ bool RevisedSimplex::InitializeMatrixAndTestIfUnchanged(
|
||||
// Populate compact_matrix_ and transposed_matrix_ if needed. Note that we
|
||||
// already added all the slack variables at this point, so matrix_ will not
|
||||
// change anymore.
|
||||
compact_matrix_.PopulateFromMatrixView(matrix_with_slack_);
|
||||
// TODO(user): This can be sped up by removing the MatrixView.
|
||||
compact_matrix_.PopulateFromMatrixView(MatrixView(lp.GetSparseMatrix()));
|
||||
if (parameters_.use_transposed_matrix()) {
|
||||
transposed_matrix_.PopulateFromTranspose(compact_matrix_);
|
||||
}
|
||||
@@ -951,7 +944,7 @@ Status RevisedSimplex::CreateInitialBasis() {
|
||||
// the value of the boxed singleton column with a non-zero cost to the best
|
||||
// of their two bounds.
|
||||
for (ColIndex col(0); col < num_cols_; ++col) {
|
||||
if (matrix_with_slack_.column(col).num_entries() != 1) continue;
|
||||
if (compact_matrix_.column(col).num_entries() != 1) continue;
|
||||
const VariableStatus status = variables_info_.GetStatusRow()[col];
|
||||
const Fractional objective = objective_[col];
|
||||
if (objective > 0 && IsFinite(lower_bound_[col]) &&
|
||||
@@ -991,7 +984,7 @@ Status RevisedSimplex::CreateInitialBasis() {
|
||||
return InitializeFirstBasis(basis);
|
||||
}
|
||||
if (parameters_.initial_basis() == GlopParameters::MAROS) {
|
||||
InitialBasis initial_basis(matrix_with_slack_, objective_, lower_bound_,
|
||||
InitialBasis initial_basis(compact_matrix_, objective_, lower_bound_,
|
||||
upper_bound_, variables_info_.GetTypeRow());
|
||||
if (parameters_.use_dual_simplex()) {
|
||||
// This dual version only uses zero-cost columns to complete the
|
||||
@@ -1027,7 +1020,7 @@ Status RevisedSimplex::CreateInitialBasis() {
|
||||
// Then complete the basis with an advanced initial basis algorithm.
|
||||
VLOG(1) << "Trying to remove " << num_fixed_variables
|
||||
<< " fixed variables from the initial basis.";
|
||||
InitialBasis initial_basis(matrix_with_slack_, objective_, lower_bound_,
|
||||
InitialBasis initial_basis(compact_matrix_, objective_, lower_bound_,
|
||||
upper_bound_, variables_info_.GetTypeRow());
|
||||
|
||||
if (parameters_.initial_basis() == GlopParameters::BIXBY) {
|
||||
@@ -1333,7 +1326,7 @@ void RevisedSimplex::SaveState() {
|
||||
RowIndex RevisedSimplex::ComputeNumberOfEmptyRows() {
|
||||
DenseBooleanColumn contains_data(num_rows_, false);
|
||||
for (ColIndex col(0); col < num_cols_; ++col) {
|
||||
for (const SparseColumn::Entry e : matrix_with_slack_.column(col)) {
|
||||
for (const SparseColumn::Entry e : compact_matrix_.column(col)) {
|
||||
contains_data[e.row()] = true;
|
||||
}
|
||||
}
|
||||
@@ -1350,7 +1343,7 @@ RowIndex RevisedSimplex::ComputeNumberOfEmptyRows() {
|
||||
ColIndex RevisedSimplex::ComputeNumberOfEmptyColumns() {
|
||||
ColIndex num_empty_cols(0);
|
||||
for (ColIndex col(0); col < num_cols_; ++col) {
|
||||
if (matrix_with_slack_.column(col).IsEmpty()) {
|
||||
if (compact_matrix_.column(col).IsEmpty()) {
|
||||
++num_empty_cols;
|
||||
VLOG(1) << "Column " << col << " is empty.";
|
||||
}
|
||||
@@ -3094,10 +3087,10 @@ void RevisedSimplex::DisplayProblem() const {
|
||||
for (RowIndex row(0); row < num_rows_; ++row) {
|
||||
output = "";
|
||||
for (ColIndex col(0); col < num_cols_; ++col) {
|
||||
absl::StrAppend(
|
||||
&output, StringifyMonomialWithFlags(
|
||||
matrix_with_slack_.column(col).LookUpCoefficient(row),
|
||||
variable_name_[col]));
|
||||
absl::StrAppend(&output,
|
||||
StringifyMonomialWithFlags(
|
||||
compact_matrix_.column(col).LookUpCoefficient(row),
|
||||
variable_name_[col]));
|
||||
}
|
||||
VLOG(3) << output << " = 0;";
|
||||
}
|
||||
|
||||
@@ -579,15 +579,7 @@ class RevisedSimplex {
|
||||
// it's as fast as std::unique_ptr as long as the size is properly reserved
|
||||
// beforehand.
|
||||
|
||||
// Temporary view of the matrix given to Solve(). Note that it is an error
|
||||
// to access this view once Solve() is finished since there is no guarantee
|
||||
// that the stored pointers are still valid.
|
||||
// TODO(user): The matrix view is identical to the matrix of the linear
|
||||
// program after pre-processing. Investigate if we could get rid of it and use
|
||||
// compact_matrix_ in all places.
|
||||
MatrixView matrix_with_slack_;
|
||||
|
||||
// The compact version of matrix_with_slack_.
|
||||
// Compact version of the matrix given to Solve().
|
||||
CompactSparseMatrix compact_matrix_;
|
||||
|
||||
// The transpose of compact_matrix_, it may be empty if it is not needed.
|
||||
|
||||
@@ -13,17 +13,28 @@
|
||||
|
||||
#include "ortools/lp_data/lp_utils.h"
|
||||
|
||||
#include "ortools/lp_data/sparse_column.h"
|
||||
|
||||
namespace operations_research {
|
||||
namespace glop {
|
||||
|
||||
Fractional SquaredNorm(const SparseColumn& v) {
|
||||
template <typename SparseColumnLike>
|
||||
Fractional SquaredNormTemplate(const SparseColumnLike& column) {
|
||||
Fractional sum(0.0);
|
||||
for (const SparseColumn::Entry e : v) {
|
||||
for (const SparseColumn::Entry e : column) {
|
||||
sum += Square(e.coefficient());
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
Fractional SquaredNorm(const SparseColumn& v) {
|
||||
return SquaredNormTemplate<SparseColumn>(v);
|
||||
}
|
||||
|
||||
Fractional SquaredNorm(const ColumnView& v) {
|
||||
return SquaredNormTemplate<ColumnView>(v);
|
||||
}
|
||||
|
||||
Fractional PreciseSquaredNorm(const SparseColumn& v) {
|
||||
KahanSum sum;
|
||||
for (const SparseColumn::Entry e : v) {
|
||||
@@ -75,14 +86,23 @@ Fractional InfinityNorm(const DenseColumn& v) {
|
||||
return infinity_norm;
|
||||
}
|
||||
|
||||
Fractional InfinityNorm(const SparseColumn& v) {
|
||||
template <typename SparseColumnLike>
|
||||
Fractional InfinityNormTemplate(const SparseColumnLike& column) {
|
||||
Fractional infinity_norm = 0.0;
|
||||
for (const SparseColumn::Entry e : v) {
|
||||
for (const SparseColumn::Entry e : column) {
|
||||
infinity_norm = std::max(infinity_norm, fabs(e.coefficient()));
|
||||
}
|
||||
return infinity_norm;
|
||||
}
|
||||
|
||||
Fractional InfinityNorm(const SparseColumn& v) {
|
||||
return InfinityNormTemplate<SparseColumn>(v);
|
||||
}
|
||||
|
||||
Fractional InfinityNorm(const ColumnView& v) {
|
||||
return InfinityNormTemplate<ColumnView>(v);
|
||||
}
|
||||
|
||||
double Density(const DenseRow& row) {
|
||||
if (row.empty()) return 0.0;
|
||||
int sum = 0.0;
|
||||
@@ -110,7 +130,7 @@ void RemoveNearZeroEntries(Fractional threshold, DenseColumn* column) {
|
||||
}
|
||||
}
|
||||
|
||||
Fractional RestrictedInfinityNorm(const SparseColumn& column,
|
||||
Fractional RestrictedInfinityNorm(const ColumnView& column,
|
||||
const DenseBooleanColumn& rows_to_consider,
|
||||
RowIndex* row_index) {
|
||||
Fractional infinity_norm = 0.0;
|
||||
@@ -123,7 +143,7 @@ Fractional RestrictedInfinityNorm(const SparseColumn& column,
|
||||
return infinity_norm;
|
||||
}
|
||||
|
||||
void SetSupportToFalse(const SparseColumn& column, DenseBooleanColumn* b) {
|
||||
void SetSupportToFalse(const ColumnView& column, DenseBooleanColumn* b) {
|
||||
for (const SparseColumn::Entry e : column) {
|
||||
if (e.coefficient() != 0.0) {
|
||||
(*b)[e.row()] = false;
|
||||
@@ -131,7 +151,7 @@ void SetSupportToFalse(const SparseColumn& column, DenseBooleanColumn* b) {
|
||||
}
|
||||
}
|
||||
|
||||
bool IsDominated(const SparseColumn& column, const DenseColumn& radius) {
|
||||
bool IsDominated(const ColumnView& column, const DenseColumn& radius) {
|
||||
for (const SparseColumn::Entry e : column) {
|
||||
DCHECK_GE(radius[e.row()], 0.0);
|
||||
if (fabs(e.coefficient()) > radius[e.row()]) return false;
|
||||
|
||||
@@ -142,6 +142,7 @@ Fractional PartialScalarProduct(const DenseRowOrColumn& u,
|
||||
// The precise version uses KahanSum and are about two times slower.
|
||||
Fractional SquaredNorm(const SparseColumn& v);
|
||||
Fractional SquaredNorm(const DenseColumn& column);
|
||||
Fractional SquaredNorm(const ColumnView& v);
|
||||
Fractional PreciseSquaredNorm(const SparseColumn& v);
|
||||
Fractional PreciseSquaredNorm(const DenseColumn& column);
|
||||
Fractional PreciseSquaredNorm(const ScatteredColumn& v);
|
||||
@@ -149,6 +150,7 @@ Fractional PreciseSquaredNorm(const ScatteredColumn& v);
|
||||
// Returns the maximum of the |coefficients| of 'v'.
|
||||
Fractional InfinityNorm(const DenseColumn& v);
|
||||
Fractional InfinityNorm(const SparseColumn& v);
|
||||
Fractional InfinityNorm(const ColumnView& v);
|
||||
|
||||
// Returns the fraction of non-zero entries of the given row.
|
||||
//
|
||||
@@ -169,17 +171,17 @@ const DenseColumn& Transpose(const DenseRow& row);
|
||||
// Returns the maximum of the |coefficients| of the given column restricted
|
||||
// to the rows_to_consider. Also returns the first RowIndex 'row' that attains
|
||||
// this maximum. If the maximum is 0.0, then row_index is left untouched.
|
||||
Fractional RestrictedInfinityNorm(const SparseColumn& column,
|
||||
Fractional RestrictedInfinityNorm(const ColumnView& column,
|
||||
const DenseBooleanColumn& rows_to_consider,
|
||||
RowIndex* row_index);
|
||||
|
||||
// Sets to false the entry b[row] if column[row] is non null.
|
||||
// Note that if 'b' was true only on the non-zero position of column, this can
|
||||
// be used as a fast way to clear 'b'.
|
||||
void SetSupportToFalse(const SparseColumn& column, DenseBooleanColumn* b);
|
||||
void SetSupportToFalse(const ColumnView& column, DenseBooleanColumn* b);
|
||||
|
||||
// Returns true iff for all 'row' we have '|column[row]| <= radius[row]'.
|
||||
bool IsDominated(const SparseColumn& column, const DenseColumn& radius);
|
||||
bool IsDominated(const ColumnView& column, const DenseColumn& radius);
|
||||
|
||||
// This cast based implementation should be safe, as long as DenseRow and
|
||||
// DenseColumn are implemented by the same underlying type.
|
||||
|
||||
@@ -97,6 +97,22 @@ class ColumnView {
|
||||
return Iterator(this->rows_, this->coefficients_, num_entries_);
|
||||
}
|
||||
|
||||
Fractional LookUpCoefficient(RowIndex index) const {
|
||||
Fractional value(0.0);
|
||||
for (const auto e : *this) {
|
||||
if (e.row() == index) {
|
||||
// Keep in mind the vector may contains several entries with the same
|
||||
// index. In such a case the last one is returned.
|
||||
// TODO(user): investigate whether an optimized version of
|
||||
// LookUpCoefficient for "clean" columns yields speed-ups.
|
||||
value = e.coefficient();
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
bool IsEmpty() const { return num_entries_ == EntryIndex(0); }
|
||||
|
||||
private:
|
||||
const EntryIndex num_entries_;
|
||||
const RowIndex* const rows_;
|
||||
|
||||
Reference in New Issue
Block a user