new dynamic partition class

This commit is contained in:
Laurent Perron
2022-06-29 17:03:49 +02:00
parent 80934bd261
commit ffefef9136
5 changed files with 107 additions and 5 deletions

View File

@@ -293,4 +293,74 @@ std::string MergingPartition::DebugString() {
return out;
}
void SimpleDynamicPartition::Refine(
absl::Span<const int> distinguished_subset) {
// Compute the size of the non-empty intersection of each part with the
// distinguished_subset.
temp_to_clean_.clear();
std::vector<int>& local_sizes = temp_data_by_part_;
local_sizes.resize(size_of_part_.size(), 0);
for (const int element : distinguished_subset) {
const int part = part_of_[element];
if (local_sizes[part] == 0) temp_to_clean_.push_back(part);
local_sizes[part]++;
}
// Reuse local_sizes to store new_part index or zero (no remapping).
// Also update the size of each part.
for (const int part : temp_to_clean_) {
if (local_sizes[part] == size_of_part_[part]) {
// No need to remap if the whole part is in distinguished_subset.
local_sizes[part] = 0;
continue;
}
const int new_part_index = size_of_part_.size();
size_of_part_[part] -= local_sizes[part];
size_of_part_.push_back(local_sizes[part]);
local_sizes[part] = new_part_index;
}
// For each part not completely included or excluded, split out the element
// from distinguished_subset into a new part.
for (const int element : distinguished_subset) {
const int new_part = local_sizes[part_of_[element]];
if (new_part != 0) part_of_[element] = new_part;
}
// Sparse clean.
for (const int part : temp_to_clean_) {
local_sizes[part] = 0;
}
}
std::vector<absl::Span<const int>> SimpleDynamicPartition::GetParts(
std::vector<int>* buffer) {
const int num_elements = part_of_.size();
const int num_parts = size_of_part_.size();
buffer->resize(num_elements);
std::vector<absl::Span<const int>> result(num_parts);
if (result.empty()) return result;
// Compute start of each part in buffer.
std::vector<int>& starts = temp_data_by_part_;
starts.resize(num_parts, 0);
for (int i = 1; i < num_parts; ++i) {
starts[i] = starts[i - 1] + size_of_part_[i - 1];
}
// Fill result.
for (int i = 0; i < num_parts; ++i) {
result[i] = absl::MakeSpan(&(*buffer)[starts[i]], size_of_part_[i]);
}
// Copy elements in order and at their place.
for (int element = 0; element < num_elements; ++element) {
(*buffer)[starts[part_of_[element]]++] = element;
}
starts.clear();
return result;
}
} // namespace operations_research

View File

@@ -36,6 +36,8 @@
#include "ortools/base/logging.h"
#include "absl/types/span.h"
namespace operations_research {
// Partition class that supports incremental splitting, with backtracking.
@@ -272,6 +274,35 @@ class MergingPartition {
std::vector<bool> tmp_part_bit_;
};
// A subset of the API of DynamicPartition without backtrack support. The
// Refine() here is about twice as fast, but we have limited query support until
// a batch ComputeElementsByPart() is called.
class SimpleDynamicPartition {
public:
explicit SimpleDynamicPartition(int num_elements)
: part_of_(num_elements, 0),
size_of_part_(num_elements > 0 ? 1 : 0, num_elements) {}
int NumElements() const { return part_of_.size(); }
const int NumParts() const { return size_of_part_.size(); }
int PartOf(int element) const { return part_of_[element]; }
int SizeOfPart(int part) const { return size_of_part_[part]; }
void Refine(absl::Span<const int> distinguished_subset);
// This is meant to be called once after a bunch of Refine().
// The returned Span<> points into the given buffer which is re-initialized.
std::vector<absl::Span<const int>> GetParts(std::vector<int>* buffer);
private:
std::vector<int> part_of_;
std::vector<int> size_of_part_;
// Temp data. Always empty or all zero.
std::vector<int> temp_to_clean_;
std::vector<int> temp_data_by_part_;
};
// *** Implementation of inline methods of the above classes. ***
inline DynamicPartition::IterablePart DynamicPartition::ElementsInPart(

View File

@@ -44,9 +44,10 @@
%rename (setTimeLimit) operations_research::KnapsackSolver::set_time_limit; // untested
%unignore operations_research::KnapsackSolver::SolverType;
%unignore operations_research::KnapsackSolver::KNAPSACK_BRUTE_FORCE_SOLVER; // untested
%unignore operations_research::KnapsackSolver::KNAPSACK_64ITEMS_SOLVER; // untested
%unignore operations_research::KnapsackSolver::KNAPSACK_DYNAMIC_PROGRAMMING_SOLVER; // untested
%unignore operations_research::KnapsackSolver::KNAPSACK_BRUTE_FORCE_SOLVER;
%unignore operations_research::KnapsackSolver::KNAPSACK_64ITEMS_SOLVER;
%unignore operations_research::KnapsackSolver::KNAPSACK_DIVIDE_AND_CONQUER_SOLVER;
%unignore operations_research::KnapsackSolver::KNAPSACK_DYNAMIC_PROGRAMMING_SOLVER;
%unignore operations_research::KnapsackSolver::KNAPSACK_MULTIDIMENSION_CBC_MIP_SOLVER; // untested
%unignore operations_research::KnapsackSolver::KNAPSACK_MULTIDIMENSION_GLPK_MIP_SOLVER; // untested
%unignore operations_research::KnapsackSolver::KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER;

View File

@@ -20,8 +20,6 @@
#include <string>
#include <vector>
#include "absl/memory/memory.h"
#include "ortools/base/basictypes.h"
#include "ortools/base/integral_types.h"
#include "ortools/base/logging.h"
#include "ortools/base/macros.h"

View File

@@ -47,6 +47,8 @@
KNAPSACK_MULTIDIMENSION_CBC_MIP_SOLVER;
%unignore operations_research::KnapsackSolver::
KNAPSACK_MULTIDIMENSION_SCIP_MIP_SOLVER;
%unignore operations_research::KnapsackSolver::
KNAPSACK_DIVIDE_AND_CONQUER_SOLVER;
%include "ortools/algorithms/knapsack_solver.h"