OR-Tools  9.6
lp_decomposer.cc
Go to the documentation of this file.
1 // Copyright 2010-2022 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
15 
16 #include <algorithm>
17 #include <vector>
18 
19 #include "absl/synchronization/mutex.h"
23 
24 namespace operations_research {
25 namespace glop {
26 
27 //------------------------------------------------------------------------------
28 // LPDecomposer
29 //------------------------------------------------------------------------------
31  : original_problem_(nullptr), clusters_(), mutex_() {}
32 
33 void LPDecomposer::Decompose(const LinearProgram* linear_problem) {
34  absl::MutexLock mutex_lock(&mutex_);
35  original_problem_ = linear_problem;
36  clusters_.clear();
37 
38  const SparseMatrix& transposed_matrix =
39  original_problem_->GetTransposeSparseMatrix();
40  MergingPartition partition(original_problem_->num_variables().value());
41 
42  // Iterate on all constraints, and merge all variables of each constraint.
43  const ColIndex num_ct = RowToColIndex(original_problem_->num_constraints());
44  for (ColIndex ct(0); ct < num_ct; ++ct) {
45  const SparseColumn& sparse_constraint = transposed_matrix.column(ct);
46  if (sparse_constraint.num_entries() > 1) {
47  const RowIndex first_row = sparse_constraint.GetFirstRow();
48  for (EntryIndex e(1); e < sparse_constraint.num_entries(); ++e) {
49  partition.MergePartsOf(first_row.value(),
50  sparse_constraint.EntryRow(e).value());
51  }
52  }
53  }
54 
55  std::vector<int> classes;
56  const int num_classes = partition.FillEquivalenceClasses(&classes);
57  clusters_.resize(num_classes);
58  for (int i = 0; i < classes.size(); ++i) {
59  clusters_[classes[i]].push_back(ColIndex(i));
60  }
61  for (int i = 0; i < num_classes; ++i) {
62  std::sort(clusters_[i].begin(), clusters_[i].end());
63  }
64 }
65 
67  absl::MutexLock mutex_lock(&mutex_);
68  return clusters_.size();
69 }
70 
72  absl::MutexLock mutex_lock(&mutex_);
73  return *original_problem_;
74 }
75 
76 void LPDecomposer::ExtractLocalProblem(int problem_index, LinearProgram* lp) {
77  CHECK(lp != nullptr);
78  CHECK_GE(problem_index, 0);
79  CHECK_LT(problem_index, clusters_.size());
80 
81  lp->Clear();
82 
83  absl::MutexLock mutex_lock(&mutex_);
84  const std::vector<ColIndex>& cluster = clusters_[problem_index];
86  original_problem_->num_variables(), kInvalidCol);
87  SparseBitset<RowIndex> constraints_to_use(
88  original_problem_->num_constraints());
89  lp->SetMaximizationProblem(original_problem_->IsMaximizationProblem());
90 
91  // Create variables and get all constraints of the cluster.
92  const SparseMatrix& original_matrix = original_problem_->GetSparseMatrix();
93  const SparseMatrix& transposed_matrix =
94  original_problem_->GetTransposeSparseMatrix();
95  for (int i = 0; i < cluster.size(); ++i) {
96  const ColIndex global_col = cluster[i];
97  const ColIndex local_col = lp->CreateNewVariable();
98  CHECK_EQ(local_col, ColIndex(i));
99  CHECK(global_to_local[global_col] == kInvalidCol ||
100  global_to_local[global_col] == local_col)
101  << "If the mapping is already assigned it has to be the same.";
102  global_to_local[global_col] = local_col;
103 
104  lp->SetVariableName(local_col,
105  original_problem_->GetVariableName(global_col));
106  lp->SetVariableType(local_col,
107  original_problem_->GetVariableType(global_col));
108  lp->SetVariableBounds(
109  local_col, original_problem_->variable_lower_bounds()[global_col],
110  original_problem_->variable_upper_bounds()[global_col]);
112  local_col, original_problem_->objective_coefficients()[global_col]);
113 
114  for (const SparseColumn::Entry e : original_matrix.column(global_col)) {
115  constraints_to_use.Set(e.row());
116  }
117  }
118  // Create the constraints.
119  for (const RowIndex global_row :
120  constraints_to_use.PositionsSetAtLeastOnce()) {
121  const RowIndex local_row = lp->CreateNewConstraint();
122  lp->SetConstraintName(local_row,
123  original_problem_->GetConstraintName(global_row));
125  local_row, original_problem_->constraint_lower_bounds()[global_row],
126  original_problem_->constraint_upper_bounds()[global_row]);
127 
128  for (const SparseColumn::Entry e :
129  transposed_matrix.column(RowToColIndex(global_row))) {
130  const ColIndex global_col = RowToColIndex(e.row());
131  const ColIndex local_col = global_to_local[global_col];
132  lp->SetCoefficient(local_row, local_col, e.coefficient());
133  }
134  }
135 }
136 
138  const std::vector<DenseRow>& assignments) const {
139  CHECK_EQ(assignments.size(), clusters_.size());
140 
141  absl::MutexLock mutex_lock(&mutex_);
142  DenseRow global_assignment(original_problem_->num_variables(),
143  Fractional(0.0));
144  for (int problem = 0; problem < assignments.size(); ++problem) {
145  const DenseRow& local_assignment = assignments[problem];
146  const std::vector<ColIndex>& cluster = clusters_[problem];
147  for (int i = 0; i < local_assignment.size(); ++i) {
148  const ColIndex global_col = cluster[i];
149  global_assignment[global_col] = local_assignment[ColIndex(i)];
150  }
151  }
152  return global_assignment;
153 }
154 
156  const DenseRow& assignment) {
157  CHECK_GE(problem_index, 0);
158  CHECK_LT(problem_index, clusters_.size());
159  CHECK_EQ(assignment.size(), original_problem_->num_variables());
160 
161  absl::MutexLock mutex_lock(&mutex_);
162  const std::vector<ColIndex>& cluster = clusters_[problem_index];
163  DenseRow local_assignment(ColIndex(cluster.size()), Fractional(0.0));
164  for (int i = 0; i < cluster.size(); ++i) {
165  const ColIndex global_col = cluster[i];
166  local_assignment[ColIndex(i)] = assignment[global_col];
167  }
168  return local_assignment;
169 }
170 
171 } // namespace glop
172 } // namespace operations_research
int MergePartsOf(int node1, int node2)
int FillEquivalenceClasses(std::vector< int > *node_equivalence_classes)
const std::vector< IntegerType > & PositionsSetAtLeastOnce() const
Definition: bitset.h:806
void Set(IntegerType index)
Definition: bitset.h:792
void Decompose(const LinearProgram *linear_problem) ABSL_LOCKS_EXCLUDED(mutex_)
const LinearProgram & original_problem() const ABSL_LOCKS_EXCLUDED(mutex_)
void ExtractLocalProblem(int problem_index, LinearProgram *lp) ABSL_LOCKS_EXCLUDED(mutex_)
DenseRow AggregateAssignments(const std::vector< DenseRow > &assignments) const ABSL_LOCKS_EXCLUDED(mutex_)
DenseRow ExtractLocalAssignment(int problem_index, const DenseRow &assignment) ABSL_LOCKS_EXCLUDED(mutex_)
int GetNumberOfProblems() const ABSL_LOCKS_EXCLUDED(mutex_)
void SetVariableBounds(ColIndex col, Fractional lower_bound, Fractional upper_bound)
Definition: lp_data.cc:250
std::string GetVariableName(ColIndex col) const
Definition: lp_data.cc:361
void SetConstraintName(RowIndex row, absl::string_view name)
Definition: lp_data.cc:246
const SparseMatrix & GetTransposeSparseMatrix() const
Definition: lp_data.cc:377
void SetCoefficient(RowIndex row, ColIndex col, Fractional value)
Definition: lp_data.cc:318
const SparseMatrix & GetSparseMatrix() const
Definition: lp_data.h:176
void SetVariableName(ColIndex col, absl::string_view name)
Definition: lp_data.cc:233
const DenseRow & variable_lower_bounds() const
Definition: lp_data.h:230
const DenseColumn & constraint_lower_bounds() const
Definition: lp_data.h:216
const DenseRow & objective_coefficients() const
Definition: lp_data.h:224
void SetConstraintBounds(RowIndex row, Fractional lower_bound, Fractional upper_bound)
Definition: lp_data.cc:310
VariableType GetVariableType(ColIndex col) const
Definition: lp_data.cc:373
void SetVariableType(ColIndex col, VariableType type)
Definition: lp_data.cc:237
std::string GetConstraintName(RowIndex row) const
Definition: lp_data.cc:367
const DenseColumn & constraint_upper_bounds() const
Definition: lp_data.h:219
void SetObjectiveCoefficient(ColIndex col, Fractional value)
Definition: lp_data.cc:327
const DenseRow & variable_upper_bounds() const
Definition: lp_data.h:233
void SetMaximizationProblem(bool maximize)
Definition: lp_data.cc:344
RowIndex EntryRow(EntryIndex i) const
Definition: sparse_column.h:53
const SparseColumn & column(ColIndex col) const
Definition: sparse.h:183
const Constraint * ct
constexpr ColIndex kInvalidCol(-1)
ColIndex RowToColIndex(RowIndex row)
Definition: lp_types.h:53
Collection of objects used to extend the Constraint Solver library.
std::optional< int64_t > end