Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
|
#include <dynamic_partition.h>
Classes | |
struct | IterablePart |
Public Member Functions | |
DynamicPartition (int num_elements) | |
DynamicPartition (const std::vector< int > &initial_part_of_element) | |
int | NumElements () const |
Accessors. | |
int | NumParts () const |
IterablePart | ElementsInPart (int i) const |
*** Implementation of inline methods of the above classes. *** | |
int | PartOf (int element) const |
int | SizeOfPart (int part) const |
int | ParentOfPart (int part) const |
IterablePart | ElementsInSamePartAs (int i) const |
uint64_t | FprintOfPart (int part) const |
void | Refine (absl::Span< const int > distinguished_subset) |
void | UndoRefineUntilNumPartsEqual (int original_num_parts) |
std::string | DebugString (bool sort_parts_lexicographically) const |
const std::vector< int > & | ElementsInHierarchicalOrder () const |
Partition class that supports incremental splitting, with backtracking. See http://en.wikipedia.org/wiki/Partition_refinement . More precisely, the supported edit operations are:
S
<<< N) of elements are all considered non-equivalent to any element in ¬S. Typically, this should be done in O(S
).Undo the above operations (backtracking).
Definition at line 51 of file dynamic_partition.h.
|
explicit |
Creates a DynamicPartition on n elements, numbered 0..n-1. Start with the trivial partition (only one subset containing all elements).
Definition at line 36 of file dynamic_partition.cc.
|
explicit |
Ditto, but specify the initial part of each elements. Part indices must form a dense integer set starting at 0; eg. [2, 1, 0, 1, 1, 3, 0] is valid.
Compute the part fingerprints.
Compute the actual start indices of each part, knowing that we'll sort them as they were given implicitly in "initial_part_of_element". The code looks a bit weird to do it in-place, with no additional memory.
Now that we have the correct start indices, we set the end indices to the start indices, and incrementally add all elements to their part, adjusting the end indices as we go.
Verify that we did it right.
Definition at line 52 of file dynamic_partition.cc.
std::string operations_research::DynamicPartition::DebugString | ( | bool | sort_parts_lexicographically | ) | const |
Converts the current partition to a string, like "3 | 1 2 | 0 4 5". Within each part, elements are sorted. And if sort_parts_lexicographically=true, the parts are sorted lexicographically instead of by their natural order.
Definition at line 189 of file dynamic_partition.cc.
|
inline |
ADVANCED USAGE: All elements (0..n-1) of the partition, sorted in a way that's compatible with the hierarchical partitioning:
Definition at line 132 of file dynamic_partition.h.
|
inline |
*** Implementation of inline methods of the above classes. ***
Definition at line 303 of file dynamic_partition.h.
|
inline |
A handy shortcut to ElementsInPart(PartOf(e)). The returned IterablePart will never be empty, since it contains at least i.
Definition at line 330 of file dynamic_partition.h.
|
inline |
Returns a fingerprint of the given part. While collisions are possible, their probability is quite low. Two parts that have the same size and the same fingerprint are most likely identical. Also, two parts that have the exact same set of elements will always have the same fingerprint.
Definition at line 335 of file dynamic_partition.h.
|
inline |
Accessors.
Definition at line 62 of file dynamic_partition.h.
|
inline |
Definition at line 63 of file dynamic_partition.h.
|
inline |
Definition at line 324 of file dynamic_partition.h.
|
inline |
Definition at line 311 of file dynamic_partition.h.
void operations_research::DynamicPartition::Refine | ( | absl::Span< const int > | distinguished_subset | ) |
Refines the partition such that elements that are in distinguished_subset never share the same part as elements that aren't in that subset. This might be a no-op: in that case, NumParts() won't change, but the order of elements inside each part may change.
ORDERING OF PARTS: For each i such that Part #i has a non-trivial intersection with "distinguished_subset" (neither empty, nor the full Part); Part #i is stripped out of all elements that are in "distinguished_subset", and those elements are sent to a newly created part, whose parent_part = i. The parts newly created by a single Refine() operations are sorted by parent_part. Example: a Refine() on a partition with 6 parts causes parts #1, #3 and #4 to be split: the partition will now contain 3 new parts: part #6 (with parent_part = 1), part #7 (with parent_part = 3) and part #8 (with parent_part = 4).
tmp_counter_of_part_[i] will contain the number of elements in distinguished_subset that were part of part #i.
We remember the Parts that were actually affected.
Is this the first time that we touch this element's part?
Move the element to the end of its current Part.
Perform the swap, keeping index_of_ up to date.
Sort affected parts. This is important to behave as advertised in the .h.
Iterate on each affected part and split it, or keep it intact if all of its elements were distinguished.
Do nothing if all elements were distinguished.
Compute the fingerprint of the new part.
Perform the split.
Definition at line 101 of file dynamic_partition.cc.
|
inline |
Definition at line 317 of file dynamic_partition.h.
void operations_research::DynamicPartition::UndoRefineUntilNumPartsEqual | ( | int | original_num_parts | ) |
Undo one or several Refine() operations, until the number of parts becomes equal to "original_num_parts". Prerequisite: NumParts() >= original_num_parts.
Update the part contents: actually merge "part" onto its parent.
Definition at line 166 of file dynamic_partition.cc.