8 #ifndef INCLUDE_MOLASSEMBLER_TEMPLE_BOUNDED_NODE_TRIE_H
9 #define INCLUDE_MOLASSEMBLER_TEMPLE_BOUNDED_NODE_TRIE_H
16 #include "boost/dynamic_bitset.hpp"
19 namespace Molassembler {
31 template<
typename ChoiceIndex>
33 static_assert(std::is_integral<ChoiceIndex>::value,
"ChoiceIndex must be an integral type");
44 using ChoosingFunction = std::function<ChoiceIndex(const std::vector<ChoiceIndex>&,
const boost::dynamic_bitset<>&)>;
78 throw std::logic_error(
"No bounds are set!");
86 InsertResult result = root_->insert(values, bounds_, 0);
88 if(result.insertedSomething) {
92 return result.insertedSomething;
110 if(bounds_.empty()) {
111 throw std::logic_error(
"No bounds are set!");
118 if(size_ == capacity_) {
119 throw std::logic_error(
"Trie is at capacity!");
123 values.reserve(bounds_.size());
125 InsertResult result = root_->generate(chooseFunction, values, bounds_, 0);
127 if(!result.insertedSomething) {
128 throw std::logic_error(
"Trie has failed to generate a new entry");
141 bounds_ = std::move(bounds);
144 assert(!bounds_.empty());
149 [](
const ChoiceIndex value) ->
bool {
192 return root_->contains(values, 0);
206 assert(root_->size() == size_);
226 bool insertedSomething;
233 virtual bool contains(
const ChoiceList& values,
unsigned depth)
const = 0;
248 virtual unsigned size()
const = 0;
252 using NodePtr = std::unique_ptr<AbstractNode>;
257 Node(
const ChoiceIndex U) : children(U), fullChildren(U) {
261 bool contains(
const ChoiceList& values,
const unsigned depth)
const final {
262 const ChoiceIndex& branch = values.at(depth);
263 const NodePtr& childPtr = children.at(branch);
269 return childPtr->contains(values, depth + 1);
273 const ChoiceIndex& branchChoice = values.at(depth);
274 NodePtr& childPtr = children.at(branchChoice);
278 bool insertedSomething =
false;
280 if(depth + 1 == bounds.size() - 1) {
281 childPtr = std::make_unique<Leaf>(bounds.at(depth + 1));
283 childPtr = std::make_unique<Node>(bounds.at(depth + 1));
286 insertedSomething =
true;
289 subtreeResult = childPtr->insert(values, bounds, depth + 1);
290 subtreeResult.insertedSomething |= insertedSomething;
292 if(subtreeResult.subtreeIsFull) {
293 fullChildren.set(branchChoice);
296 subtreeResult.subtreeIsFull = fullChildren.all();
298 return subtreeResult;
308 const unsigned N = children.size();
309 boost::dynamic_bitset<> existingChildren(N);
310 for(
unsigned i = 0; i < N; ++i) {
312 existingChildren.set(i);
316 std::vector<ChoiceIndex> viableIndices;
317 viableIndices.reserve(N);
318 for(
unsigned i = 0; i < N; ++i) {
319 if(!fullChildren.test(i)) {
320 viableIndices.push_back(i);
324 const ChoiceIndex choice = choosingFunction(viableIndices, existingChildren);
328 values.push_back(choice);
329 NodePtr& childPtr = children.at(choice);
331 bool insertedSomething =
false;
333 insertedSomething =
true;
334 if(depth + 1 == bounds.size() - 1) {
335 childPtr = std::make_unique<Leaf>(bounds.at(depth + 1));
337 childPtr = std::make_unique<Node>(bounds.at(depth + 1));
341 InsertResult subtreeResult = childPtr->generate(choosingFunction, values, bounds, depth + 1);
343 subtreeResult.insertedSomething |= insertedSomething;
345 if(subtreeResult.subtreeIsFull) {
346 fullChildren.set(choice);
349 subtreeResult.subtreeIsFull = fullChildren.all();
351 return subtreeResult;
354 unsigned size()
const final {
357 for(
const NodePtr& nodePtr : children) {
359 count += nodePtr->size();
367 std::vector<NodePtr> children;
368 boost::dynamic_bitset<> fullChildren;
374 Leaf(
const ChoiceIndex U) : children(U) {
378 bool contains(
const ChoiceList& values,
const unsigned depth)
const final {
379 const ChoiceIndex& choice = values.at(depth);
380 return children.test(choice);
384 const ChoiceIndex& choice = values.at(depth);
385 assert(choice < children.size());
388 result.insertedSomething = !children.test(choice);
389 result.subtreeIsFull = children.all();
391 children.set(choice);
402 std::vector<ChoiceIndex> viableIndices;
403 const ChoiceIndex N = children.size();
404 viableIndices.reserve(N);
405 for(ChoiceIndex i = 0; i < N; ++i) {
406 if(!children.test(i)) {
407 viableIndices.push_back(i);
411 const ChoiceIndex choice = choosingFunction(viableIndices, children);
416 result.insertedSomething = !children.test(choice);
418 values.push_back(choice);
419 children.set(choice);
421 result.subtreeIsFull = children.all();
426 unsigned size()
const final {
427 return children.count();
431 boost::dynamic_bitset<> children;
439 if(bounds_.size() == 1) {
440 root_ = std::make_unique<Leaf>(bounds_.front());
442 root_ = std::make_unique<Node>(bounds_.front());
460 unsigned capacity_ = 0;
unsigned capacity() const
Returns the total number of value lists this trie might contain.
Definition: BoundedNodeTrie.h:216
std::unique_ptr< AbstractNode > NodePtr
Owning pointer to base class.
Definition: BoundedNodeTrie.h:252
const ChoiceList & bounds() const
Accessor for underlying bounds.
Definition: BoundedNodeTrie.h:196
BoundedNodeTrie()=default
Construct an empty trie, setting the upper exclusive bound on values at each level.
Leaf node at bottom of the tree.
Definition: BoundedNodeTrie.h:372
void clear()
Removes all inserted lists from the trie.
Definition: BoundedNodeTrie.h:163
BoundedNodeTrie(ChoiceList bounds)
Construct an empty trie, setting the upper exclusive bound on values at each level.
Definition: BoundedNodeTrie.h:56
Data structure to store chains of discrete choices with an finite range of choices at each position...
Definition: BoundedNodeTrie.h:32
T accumulate(const Container &container, T init, BinaryFunction &&reductionFunction)
Accumulate shorthand.
Definition: Functional.h:216
unsigned size() const
Returns the number of value lists this trie contains.
Definition: BoundedNodeTrie.h:204
Definition: BoundedNodeTrie.h:224
std::function< std::uint8_t(const std::vector< std::uint8_t > &, const boost::dynamic_bitset<> &)> ChoosingFunction
Function signature needed to choose which child to descend to at a level in the tree.
Definition: BoundedNodeTrie.h:44
void setBounds(ChoiceList bounds)
Changes the bounds of the trie. Clears the trie.
Definition: BoundedNodeTrie.h:140
void establishRoot_()
Generate a root node.
Definition: BoundedNodeTrie.h:438
bool contains(const ChoiceList &values) const
Checks whether a value list is present in the trie.
Definition: BoundedNodeTrie.h:187
auto makeContainsPredicate(const Container &container)
Creates a predicate that uses std::find for the container's value type.
Definition: Functional.h:398
Abstract base class for nodes to allow differentiation.
Definition: BoundedNodeTrie.h:230
bool insert(const ChoiceList &values)
Inserts a value list into the prefix trie if not already present.
Definition: BoundedNodeTrie.h:75
Functional-style container-related algorithms.
ChoiceList generateNewEntry(const ChoosingFunction &chooseFunction)
Create a new entry by choosing branch at each level of the trie.
Definition: BoundedNodeTrie.h:109
std::vector< std::uint8_t > ChoiceList
Type used to represent choices made at each level of the tree.
Definition: BoundedNodeTrie.h:39
void establishCapacity_()
Generate a root node.
Definition: BoundedNodeTrie.h:446
bool all_of(const Container &container, UnaryPredicate &&predicate=UnaryPredicate{})
all_of shorthand
Definition: Functional.h:234
Most common type of nodes have other AbstractNodes as children.
Definition: BoundedNodeTrie.h:255