fix bug in glop
This commit is contained in:
@@ -79,7 +79,6 @@ RevisedSimplex::RevisedSimplex()
|
||||
num_rows_(0),
|
||||
num_cols_(0),
|
||||
first_slack_col_(kInvalidCol),
|
||||
current_objective_(),
|
||||
objective_(),
|
||||
lower_bound_(),
|
||||
upper_bound_(),
|
||||
@@ -96,8 +95,8 @@ RevisedSimplex::RevisedSimplex()
|
||||
basis_factorization_),
|
||||
update_row_(compact_matrix_, transposed_matrix_, variables_info_, basis_,
|
||||
basis_factorization_),
|
||||
reduced_costs_(compact_matrix_, current_objective_, basis_,
|
||||
variables_info_, basis_factorization_, &random_),
|
||||
reduced_costs_(compact_matrix_, objective_, basis_, variables_info_,
|
||||
basis_factorization_, &random_),
|
||||
entering_variable_(variables_info_, &random_, &reduced_costs_,
|
||||
&primal_edge_norms_),
|
||||
num_iterations_(0),
|
||||
@@ -172,8 +171,6 @@ Status RevisedSimplex::Solve(const LinearProgram& lp, TimeLimit* time_limit) {
|
||||
<< matrix_with_slack_.num_cols() << " columns, "
|
||||
<< matrix_with_slack_.num_entries() << " entries.";
|
||||
|
||||
current_objective_ = objective_;
|
||||
|
||||
// TODO(user): Avoid doing the first phase checks when we know from the
|
||||
// incremental solve that the solution is already dual or primal feasible.
|
||||
VLOG(1) << "------ First phase: feasibility.";
|
||||
@@ -200,7 +197,7 @@ Status RevisedSimplex::Solve(const LinearProgram& lp, TimeLimit* time_limit) {
|
||||
DisplayIterationInfo();
|
||||
|
||||
// After the primal phase I, we need to restore the objective.
|
||||
current_objective_ = objective_;
|
||||
InitializeObjectiveAndTestIfUnchanged(lp);
|
||||
reduced_costs_.ResetForNewObjective();
|
||||
}
|
||||
|
||||
@@ -800,7 +797,6 @@ bool RevisedSimplex::InitializeObjectiveAndTestIfUnchanged(
|
||||
const LinearProgram& lp) {
|
||||
DCHECK_EQ(num_cols_, lp.num_variables());
|
||||
SCOPED_TIME_STAT(&function_stats_);
|
||||
current_objective_.assign(num_cols_, 0.0);
|
||||
|
||||
// Note that we use the minimization version of the objective.
|
||||
bool objective_is_unchanged = true;
|
||||
@@ -871,7 +867,7 @@ void RevisedSimplex::InitializeObjectiveLimit(const LinearProgram& lp) {
|
||||
|
||||
void RevisedSimplex::InitializeVariableStatusesForWarmStart(
|
||||
const BasisState& state, ColIndex num_new_cols) {
|
||||
variables_info_.Initialize();
|
||||
variables_info_.InitializeAndComputeType();
|
||||
RowIndex num_basic_variables(0);
|
||||
DCHECK_LE(num_new_cols, first_slack_col_);
|
||||
const ColIndex first_new_col(first_slack_col_ - num_new_cols);
|
||||
@@ -931,7 +927,7 @@ Status RevisedSimplex::CreateInitialBasis() {
|
||||
// dual-feasible later by MakeBoxedVariableDualFeasible(), so it doesn't
|
||||
// really matter at which of their two finite bounds they start.
|
||||
int num_free_variables = 0;
|
||||
variables_info_.Initialize();
|
||||
variables_info_.InitializeAndComputeType();
|
||||
for (ColIndex col(0); col < num_cols_; ++col) {
|
||||
const VariableStatus status = ComputeDefaultVariableStatus(col);
|
||||
SetNonBasicVariableStatusAndDeriveValue(col, status);
|
||||
@@ -1656,10 +1652,10 @@ void RevisedSimplex::UpdatePrimalPhaseICosts(const Rows& rows) {
|
||||
} else if (value < lower_bound_[col] - tolerance) {
|
||||
cost = -1.0;
|
||||
}
|
||||
if (current_objective_[col] != cost) {
|
||||
if (objective_[col] != cost) {
|
||||
objective_changed = true;
|
||||
}
|
||||
current_objective_[col] = cost;
|
||||
objective_[col] = cost;
|
||||
}
|
||||
// If the objective changed, the reduced costs need to be recomputed.
|
||||
if (objective_changed) {
|
||||
@@ -2233,7 +2229,8 @@ Status RevisedSimplex::Minimize(TimeLimit* time_limit) {
|
||||
|
||||
if (feasibility_phase_) {
|
||||
// Initialize the primal phase-I objective.
|
||||
current_objective_.assign(num_cols_, 0.0);
|
||||
// Note that this temporarily erases the problem objective.
|
||||
objective_.assign(num_cols_, 0.0);
|
||||
UpdatePrimalPhaseICosts(IntegerRange<RowIndex>(RowIndex(0), num_rows_));
|
||||
}
|
||||
|
||||
@@ -2452,8 +2449,8 @@ Status RevisedSimplex::Minimize(TimeLimit* time_limit) {
|
||||
if (feasibility_phase_ && leaving_row != kInvalidRow) {
|
||||
// Set the leaving variable to its exact bound.
|
||||
variable_values_.SetNonBasicVariableValueFromStatus(leaving_col);
|
||||
reduced_costs_.SetNonBasicVariableCostToZero(
|
||||
leaving_col, ¤t_objective_[leaving_col]);
|
||||
reduced_costs_.SetNonBasicVariableCostToZero(leaving_col,
|
||||
&objective_[leaving_col]);
|
||||
}
|
||||
|
||||
// Stats about consecutive degenerate iterations.
|
||||
@@ -2769,7 +2766,7 @@ void RevisedSimplex::DisplayAllStats() {
|
||||
|
||||
Fractional RevisedSimplex::ComputeObjectiveValue() const {
|
||||
SCOPED_TIME_STAT(&function_stats_);
|
||||
return PreciseScalarProduct(current_objective_,
|
||||
return PreciseScalarProduct(objective_,
|
||||
Transpose(variable_values_.GetDenseRow()));
|
||||
}
|
||||
|
||||
@@ -2866,7 +2863,7 @@ void RevisedSimplex::DisplayInfoOnVariables() const {
|
||||
if (VLOG_IS_ON(3)) {
|
||||
for (ColIndex col(0); col < num_cols_; ++col) {
|
||||
const Fractional variable_value = variable_values_.Get(col);
|
||||
const Fractional objective_coefficient = current_objective_[col];
|
||||
const Fractional objective_coefficient = objective_[col];
|
||||
const Fractional objective_contribution =
|
||||
objective_coefficient * variable_value;
|
||||
VLOG(3) << SimpleVariableInfo(col) << ". " << variable_name_[col] << " = "
|
||||
@@ -2965,7 +2962,7 @@ void RevisedSimplex::DisplayProblem() const {
|
||||
std::string output = "min: ";
|
||||
bool has_objective = false;
|
||||
for (ColIndex col(0); col < num_cols_; ++col) {
|
||||
const Fractional coeff = current_objective_[col];
|
||||
const Fractional coeff = objective_[col];
|
||||
has_objective |= (coeff != 0.0);
|
||||
StrAppend(&output,
|
||||
StringifyMonomialWithFlags(coeff, variable_name_[col]));
|
||||
|
||||
@@ -24,29 +24,33 @@ VariablesInfo::VariablesInfo(const CompactSparseMatrix& matrix,
|
||||
upper_bound_(upper_bound),
|
||||
boxed_variables_are_relevant_(true) {}
|
||||
|
||||
void VariablesInfo::Initialize() {
|
||||
boxed_variables_are_relevant_ = true;
|
||||
void VariablesInfo::InitializeAndComputeType() {
|
||||
const ColIndex num_cols = matrix_.num_cols();
|
||||
num_entries_in_relevant_columns_ = 0;
|
||||
variable_type_.resize(num_cols, VariableType::UNCONSTRAINED);
|
||||
variable_status_.resize(num_cols, VariableStatus::FREE);
|
||||
can_increase_.ClearAndResize(num_cols);
|
||||
can_decrease_.ClearAndResize(num_cols);
|
||||
relevance_.ClearAndResize(num_cols);
|
||||
is_basic_.ClearAndResize(num_cols);
|
||||
not_basic_.ClearAndResize(num_cols);
|
||||
non_basic_boxed_variables_.ClearAndResize(num_cols);
|
||||
|
||||
num_entries_in_relevant_columns_ = 0;
|
||||
boxed_variables_are_relevant_ = true;
|
||||
relevance_.ClearAndResize(num_cols);
|
||||
|
||||
variable_status_.resize(num_cols, VariableStatus::FREE);
|
||||
variable_type_.resize(num_cols, VariableType::UNCONSTRAINED);
|
||||
for (ColIndex col(0); col < num_cols; ++col) {
|
||||
variable_type_[col] = ComputeVariableType(col);
|
||||
}
|
||||
}
|
||||
|
||||
void VariablesInfo::MakeBoxedVariableRelevant(bool value) {
|
||||
if (value == boxed_variables_are_relevant_) return;
|
||||
boxed_variables_are_relevant_ = value;
|
||||
if (value) {
|
||||
boxed_variables_are_relevant_ = true;
|
||||
for (const ColIndex col : non_basic_boxed_variables_) {
|
||||
SetRelevance(col, variable_status_[col] != VariableStatus::FIXED_VALUE);
|
||||
SetRelevance(col, variable_type_[col] != VariableType::FIXED_VARIABLE);
|
||||
}
|
||||
} else {
|
||||
boxed_variables_are_relevant_ = false;
|
||||
for (const ColIndex col : non_basic_boxed_variables_) {
|
||||
SetRelevance(col, false);
|
||||
}
|
||||
@@ -62,7 +66,6 @@ void VariablesInfo::Update(ColIndex col, VariableStatus status) {
|
||||
}
|
||||
|
||||
void VariablesInfo::UpdateToBasicStatus(ColIndex col) {
|
||||
variable_type_[col] = ComputeVariableType(col);
|
||||
variable_status_[col] = VariableStatus::BASIC;
|
||||
is_basic_.Set(col, true);
|
||||
not_basic_.Set(col, false);
|
||||
@@ -75,8 +78,6 @@ void VariablesInfo::UpdateToBasicStatus(ColIndex col) {
|
||||
void VariablesInfo::UpdateToNonBasicStatus(ColIndex col,
|
||||
VariableStatus status) {
|
||||
DCHECK_NE(status, VariableStatus::BASIC);
|
||||
const VariableType type = ComputeVariableType(col);
|
||||
variable_type_[col] = type;
|
||||
variable_status_[col] = status;
|
||||
is_basic_.Set(col, false);
|
||||
not_basic_.Set(col, true);
|
||||
@@ -84,11 +85,12 @@ void VariablesInfo::UpdateToNonBasicStatus(ColIndex col,
|
||||
status == VariableStatus::FREE);
|
||||
can_decrease_.Set(col, status == VariableStatus::AT_UPPER_BOUND ||
|
||||
status == VariableStatus::FREE);
|
||||
non_basic_boxed_variables_.Set(col,
|
||||
type == VariableType::UPPER_AND_LOWER_BOUNDED);
|
||||
|
||||
const bool boxed =
|
||||
variable_type_[col] == VariableType::UPPER_AND_LOWER_BOUNDED;
|
||||
non_basic_boxed_variables_.Set(col, boxed);
|
||||
const bool relevance = status != VariableStatus::FIXED_VALUE &&
|
||||
(boxed_variables_are_relevant_ ||
|
||||
type != VariableType::UPPER_AND_LOWER_BOUNDED);
|
||||
(boxed_variables_are_relevant_ || !boxed);
|
||||
SetRelevance(col, relevance);
|
||||
}
|
||||
|
||||
@@ -128,9 +130,10 @@ EntryIndex VariablesInfo::GetNumEntriesInRelevantColumns() const {
|
||||
|
||||
VariableType VariablesInfo::ComputeVariableType(ColIndex col) const {
|
||||
DCHECK_LE(lower_bound_[col], upper_bound_[col]);
|
||||
if (lower_bound_[col] == -kInfinity && upper_bound_[col] == kInfinity) {
|
||||
return VariableType::UNCONSTRAINED;
|
||||
} else if (lower_bound_[col] == -kInfinity) {
|
||||
if (lower_bound_[col] == -kInfinity) {
|
||||
if (upper_bound_[col] == kInfinity) {
|
||||
return VariableType::UNCONSTRAINED;
|
||||
}
|
||||
return VariableType::UPPER_BOUNDED;
|
||||
} else if (upper_bound_[col] == kInfinity) {
|
||||
return VariableType::LOWER_BOUNDED;
|
||||
|
||||
@@ -32,10 +32,12 @@ class VariablesInfo {
|
||||
VariablesInfo(const CompactSparseMatrix& matrix, const DenseRow& lower_bound,
|
||||
const DenseRow& upper_bound);
|
||||
|
||||
// Resets all the quantities to a default value. Note that nothing can be
|
||||
// assumed on the return values of the getters until Update() has been called
|
||||
// at least once on all the columns.
|
||||
void Initialize();
|
||||
// Recomputes the variable types from the bounds (this is the only function
|
||||
// that changes them). This also resets all the non-type quantities to a
|
||||
// default value. Note however that nothing should be assumed on the return
|
||||
// values of the getters until Update() has been called at least once on all
|
||||
// the columns.
|
||||
void InitializeAndComputeType();
|
||||
|
||||
// Updates the information of the given variable. Note that it is not needed
|
||||
// to call this if the status or the bound of a variable didn't change.
|
||||
@@ -101,7 +103,8 @@ class VariablesInfo {
|
||||
DenseBitRow can_decrease_;
|
||||
|
||||
// Indicates if we should consider this variable for entering the basis during
|
||||
// the simplex algorithm. Only non-fixed and non-basic columns are relevant.
|
||||
// the simplex algorithm. We never consider fixed variables and in the dual
|
||||
// feasibility phase, we don't consider boxed variable.
|
||||
DenseBitRow relevance_;
|
||||
|
||||
// Indicates if a variable is BASIC or not. There are currently two members
|
||||
|
||||
Reference in New Issue
Block a user