fix bug in glop

This commit is contained in:
Laurent Perron
2017-07-07 11:12:32 -07:00
parent d8f3b2adb0
commit c3b4efcc6f
3 changed files with 44 additions and 41 deletions

View File

@@ -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, &current_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]));

View File

@@ -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;

View File

@@ -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