Split datastruct.h
Split into separate files concatenable_queue.hpp and priority_queue.hpp. Move classes into namespace. Separate unit testse.
This commit is contained in:
		
							parent
							
								
									087799cdca
								
							
						
					
					
						commit
						0f18b7b05a
					
				
							
								
								
									
										23
									
								
								cpp/Makefile
								
								
								
								
							
							
						
						
									
										23
									
								
								cpp/Makefile
								
								
								
								
							| 
						 | 
					@ -6,27 +6,34 @@ CXXFLAGS = -std=c++11 -Wall -Wextra $(OPTFLAGS) $(DBGFLAGS)
 | 
				
			||||||
LIB_BOOST_TEST = -l:libboost_unit_test_framework.a
 | 
					LIB_BOOST_TEST = -l:libboost_unit_test_framework.a
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.PHONY: all
 | 
					.PHONY: all
 | 
				
			||||||
all: run_matching run_matching_dbg test_mwmatching
 | 
					all: run_matching run_matching_dbg test_mwmatching test_concatenable_queue test_priority_queue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
run_matching: run_matching.cpp mwmatching.h
 | 
					run_matching: run_matching.cpp mwmatching.h concatenable_queue.hpp priority_queue.hpp
 | 
				
			||||||
	$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $<
 | 
						$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
run_matching_dbg: OPTFLAGS = -Og
 | 
					run_matching_dbg: OPTFLAGS = -Og
 | 
				
			||||||
run_matching_dbg: DBGFLAGS = -g -fsanitize=address -fsanitize=undefined
 | 
					run_matching_dbg: DBGFLAGS = -g -fsanitize=address -fsanitize=undefined
 | 
				
			||||||
run_matching_dbg: run_matching.cpp mwmatching.h
 | 
					run_matching_dbg: run_matching.cpp mwmatching.h concatenable_queue.hpp priority_queue.hpp
 | 
				
			||||||
	$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $<
 | 
						$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $<
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_mwmatching: OPTFLAGS = -O1
 | 
					test_mwmatching: OPTFLAGS = -O1
 | 
				
			||||||
test_mwmatching: DBGFLAGS = -fsanitize=address -fsanitize=undefined
 | 
					test_mwmatching: DBGFLAGS = -fsanitize=address -fsanitize=undefined
 | 
				
			||||||
test_mwmatching: test_mwmatching.cpp mwmatching.h
 | 
					test_mwmatching: test_mwmatching.cpp mwmatching.h concatenable_queue.hpp priority_queue.hpp
 | 
				
			||||||
	$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $< $(LIB_BOOST_TEST)
 | 
						$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $< $(LIB_BOOST_TEST)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_datastruct: OPTFLAGS = -O1
 | 
					test_concatenable_queue: OPTFLAGS = -O1
 | 
				
			||||||
test_datastruct: DBGFLAGS = -fsanitize=address -fsanitize=undefined
 | 
					test_concatenable_queue: DBGFLAGS = -fsanitize=address -fsanitize=undefined
 | 
				
			||||||
test_datastruct: test_datastruct.cpp datastruct.h
 | 
					test_concatenable_queue: test_concatenable_queue.cpp concatenable_queue.hpp
 | 
				
			||||||
 | 
						$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $< $(LIB_BOOST_TEST)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_priority_queue: OPTFLAGS = -O1
 | 
				
			||||||
 | 
					test_priority_queue: DBGFLAGS = -fsanitize=address -fsanitize=undefined
 | 
				
			||||||
 | 
					test_priority_queue: test_priority_queue.cpp priority_queue.hpp
 | 
				
			||||||
	$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $< $(LIB_BOOST_TEST)
 | 
						$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $< $(LIB_BOOST_TEST)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.PHONY: clean
 | 
					.PHONY: clean
 | 
				
			||||||
clean:
 | 
					clean:
 | 
				
			||||||
	$(RM) run_matching run_matching_dbg test_mwmatching
 | 
						$(RM) run_matching run_matching_dbg
 | 
				
			||||||
 | 
						$(RM) test_mwmatching
 | 
				
			||||||
 | 
						$(RM) test_concatenable_queue test_priority_queue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,17 +1,17 @@
 | 
				
			||||||
/*
 | 
					/**
 | 
				
			||||||
 * Data structures for matching.
 | 
					 * Concatenable queue data structure.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef MWMATCHING_CONCATENABLE_QUEUE_H_
 | 
				
			||||||
 | 
					#define MWMATCHING_CONCATENABLE_QUEUE_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
#include <cassert>
 | 
					#include <cassert>
 | 
				
			||||||
#include <limits>
 | 
					 | 
				
			||||||
#include <tuple>
 | 
					#include <tuple>
 | 
				
			||||||
#include <vector>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* **************************************************
 | 
					namespace mwmatching {
 | 
				
			||||||
 * **        class ConcatenableQueue               **
 | 
					
 | 
				
			||||||
 * ************************************************** */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Priority queue supporting efficient merge and split operations.
 | 
					 * Priority queue supporting efficient merge and split operations.
 | 
				
			||||||
| 
						 | 
					@ -836,253 +836,6 @@ private:
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* **************************************************
 | 
					} // namespace mwmatching
 | 
				
			||||||
 * **        class PriorityQueue                   **
 | 
					 | 
				
			||||||
 * ************************************************** */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					#endif  // MWMATCHING_CONCATENABLE_QUEUE_H_
 | 
				
			||||||
 * Min-priority queue implemented as a binary heap.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Elements in a heap have a priority and associated "data".
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The following operations can be done efficiently:
 | 
					 | 
				
			||||||
 *  - Insert an element into the queue.
 | 
					 | 
				
			||||||
 *  - Remove an element from the queue.
 | 
					 | 
				
			||||||
 *  - Change the priority of a given element.
 | 
					 | 
				
			||||||
 *  - Find the element with lowest priority in the queue.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
template <typename PrioType,
 | 
					 | 
				
			||||||
          typename DataType>
 | 
					 | 
				
			||||||
class PriorityQueue
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
    typedef unsigned int IndexType;
 | 
					 | 
				
			||||||
    static constexpr IndexType INVALID_INDEX =
 | 
					 | 
				
			||||||
        std::numeric_limits<IndexType>::max();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * A Node instance represents an element in a PriorityQueue.
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * A Node instance must remain valid while it is contained in a queue.
 | 
					 | 
				
			||||||
     * The containing queue holds a pointer to the Node.
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * A Node instance may be destructed if it is not contained in any queue.
 | 
					 | 
				
			||||||
     * Alternatively, a Node instance may be destructed after its containing
 | 
					 | 
				
			||||||
     * queue instance has been destructed.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    class Node
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      public:
 | 
					 | 
				
			||||||
        /** Construct an invalid node, not contained in any queue. */
 | 
					 | 
				
			||||||
        Node()
 | 
					 | 
				
			||||||
          : index_(INVALID_INDEX)
 | 
					 | 
				
			||||||
        { }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Prevent copying.
 | 
					 | 
				
			||||||
        Node(const Node&) = delete;
 | 
					 | 
				
			||||||
        Node& operator=(const Node&) = delete;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /** Return true if this node is contained in a queue. */
 | 
					 | 
				
			||||||
        bool valid() const
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return (index_ != INVALID_INDEX);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /**
 | 
					 | 
				
			||||||
         * Return the priority of this node in the queue.
 | 
					 | 
				
			||||||
         *
 | 
					 | 
				
			||||||
         * The node must be contained in a queue.
 | 
					 | 
				
			||||||
         * This function takes time O(1).
 | 
					 | 
				
			||||||
         */
 | 
					 | 
				
			||||||
        PrioType prio() const
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            assert(index_ != INVALID_INDEX);
 | 
					 | 
				
			||||||
            return prio_;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      private:
 | 
					 | 
				
			||||||
        IndexType       index_;
 | 
					 | 
				
			||||||
        PrioType        prio_;
 | 
					 | 
				
			||||||
        DataType        data_;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        friend class PriorityQueue;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /** Construct an empty queue. */
 | 
					 | 
				
			||||||
    PriorityQueue()
 | 
					 | 
				
			||||||
    { }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Prevent copying.
 | 
					 | 
				
			||||||
    PriorityQueue(const PriorityQueue&) = delete;
 | 
					 | 
				
			||||||
    PriorityQueue& operator=(const PriorityQueue&) = delete;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Remove all elements from the queue.
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * This function takes time O(n).
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    void clear()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        for (Node* node : heap_) {
 | 
					 | 
				
			||||||
            node->index_ = INVALID_INDEX;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        heap_.clear();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /** Return true if the queue is empty. */
 | 
					 | 
				
			||||||
    bool empty() const
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return heap_.empty();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Return the minimum priority of any element in the queue.
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * The queue must be non-empty.
 | 
					 | 
				
			||||||
     * This function takes time O(1).
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    PrioType min_prio() const
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        assert(! heap_.empty());
 | 
					 | 
				
			||||||
        Node* top = heap_.front();
 | 
					 | 
				
			||||||
        return top->prio_;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Return the element with minimum priority.
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * The queue must be non-empty.
 | 
					 | 
				
			||||||
     * This function takes time O(1).
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    DataType min_elem() const
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        assert(! heap_.empty());
 | 
					 | 
				
			||||||
        Node* top = heap_.front();
 | 
					 | 
				
			||||||
        return top->data_;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Insert the given node into the queue with associated data.
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * The node must not currently be contained in any queue.
 | 
					 | 
				
			||||||
     * This function takes amortized time O(log(n)).
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    void insert(Node* node, PrioType prio, const DataType& data)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        assert(node->index_ == INVALID_INDEX);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        node->index_ = heap_.size();
 | 
					 | 
				
			||||||
        node->prio_ = prio;
 | 
					 | 
				
			||||||
        node->data_ = data;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        heap_.push_back(node);
 | 
					 | 
				
			||||||
        sift_up(node->index_);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Update priority of an existing node.
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * This function takes time O(log(n)).
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    void set_prio(Node* node, PrioType prio)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        IndexType index = node->index_;
 | 
					 | 
				
			||||||
        assert(index != INVALID_INDEX);
 | 
					 | 
				
			||||||
        assert(heap_[index] == node);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        PrioType prev_prio = node->prio_;
 | 
					 | 
				
			||||||
        node->prio_ = prio;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (prio < prev_prio) {
 | 
					 | 
				
			||||||
            sift_up(index);
 | 
					 | 
				
			||||||
        } else if (prio > prev_prio) {
 | 
					 | 
				
			||||||
            sift_down(index);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Remove the specified element from the queue.
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * This function takes time O(log(n)).
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    void remove(Node* node)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        IndexType index = node->index_;
 | 
					 | 
				
			||||||
        assert(index != INVALID_INDEX);
 | 
					 | 
				
			||||||
        assert(heap_[index] == node);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        node->index_ = INVALID_INDEX;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Node* move_node = heap_.back();
 | 
					 | 
				
			||||||
        heap_.pop_back();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (index < heap_.size()) {
 | 
					 | 
				
			||||||
            heap_[index] = move_node;
 | 
					 | 
				
			||||||
            move_node->index_ = index;
 | 
					 | 
				
			||||||
            if (move_node->prio_ < node->prio_) {
 | 
					 | 
				
			||||||
                sift_up(index);
 | 
					 | 
				
			||||||
            } else if (move_node->prio_ > node->prio_) {
 | 
					 | 
				
			||||||
                sift_down(index);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
private:
 | 
					 | 
				
			||||||
    /** Repair the heap along an ascending path to the root. */
 | 
					 | 
				
			||||||
    void sift_up(IndexType index)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        Node* node = heap_[index];
 | 
					 | 
				
			||||||
        PrioType prio = node->prio_;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        while (index > 0) {
 | 
					 | 
				
			||||||
            IndexType next_index = (index - 1) / 2;
 | 
					 | 
				
			||||||
            Node* next_node = heap_[next_index];
 | 
					 | 
				
			||||||
            if (next_node->prio_ <= prio) {
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            heap_[index] = next_node;
 | 
					 | 
				
			||||||
            next_node->index_ = index;
 | 
					 | 
				
			||||||
            index = next_index;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        node->index_ = index;
 | 
					 | 
				
			||||||
        heap_[index] = node;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /** Repair the heap along a descending path. */
 | 
					 | 
				
			||||||
    void sift_down(IndexType index)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        Node* node = heap_[index];
 | 
					 | 
				
			||||||
        PrioType prio = node->prio_;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        IndexType num_elem = heap_.size();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        while (index < num_elem / 2) {
 | 
					 | 
				
			||||||
            IndexType next_index = 2 * index + 1;
 | 
					 | 
				
			||||||
            Node* next_node = heap_[next_index];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (next_index + 1 < num_elem) {
 | 
					 | 
				
			||||||
                Node* tmp_node = heap_[next_index + 1];
 | 
					 | 
				
			||||||
                if (tmp_node->prio_ <= next_node->prio_) {
 | 
					 | 
				
			||||||
                    ++next_index;
 | 
					 | 
				
			||||||
                    next_node = tmp_node;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (next_node->prio_ >= prio) {
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            heap_[index] = next_node;
 | 
					 | 
				
			||||||
            next_node->index_ = index;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            index = next_index;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        heap_[index] = node;
 | 
					 | 
				
			||||||
        node->index_ = index;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /** Heap data structure. */
 | 
					 | 
				
			||||||
    std::vector<Node*> heap_;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
| 
						 | 
					@ -19,7 +19,8 @@
 | 
				
			||||||
#include <utility>
 | 
					#include <utility>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "datastruct.h"
 | 
					#include "concatenable_queue.hpp"
 | 
				
			||||||
 | 
					#include "priority_queue.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace mwmatching {
 | 
					namespace mwmatching {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,266 @@
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Priority queue data structure.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef MWMATCHING_PRIORITY_QUEUE_H_
 | 
				
			||||||
 | 
					#define MWMATCHING_PRIORITY_QUEUE_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cassert>
 | 
				
			||||||
 | 
					#include <limits>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace mwmatching {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Min-priority queue implemented as a binary heap.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Elements in a heap have a priority and associated "data".
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The following operations can be done efficiently:
 | 
				
			||||||
 | 
					 *  - Insert an element into the queue.
 | 
				
			||||||
 | 
					 *  - Remove an element from the queue.
 | 
				
			||||||
 | 
					 *  - Change the priority of a given element.
 | 
				
			||||||
 | 
					 *  - Find the element with lowest priority in the queue.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					template <typename PrioType,
 | 
				
			||||||
 | 
					          typename DataType>
 | 
				
			||||||
 | 
					class PriorityQueue
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    typedef unsigned int IndexType;
 | 
				
			||||||
 | 
					    static constexpr IndexType INVALID_INDEX =
 | 
				
			||||||
 | 
					        std::numeric_limits<IndexType>::max();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * A Node instance represents an element in a PriorityQueue.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * A Node instance must remain valid while it is contained in a queue.
 | 
				
			||||||
 | 
					     * The containing queue holds a pointer to the Node.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * A Node instance may be destructed if it is not contained in any queue.
 | 
				
			||||||
 | 
					     * Alternatively, a Node instance may be destructed after its containing
 | 
				
			||||||
 | 
					     * queue instance has been destructed.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    class Node
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      public:
 | 
				
			||||||
 | 
					        /** Construct an invalid node, not contained in any queue. */
 | 
				
			||||||
 | 
					        Node()
 | 
				
			||||||
 | 
					          : index_(INVALID_INDEX)
 | 
				
			||||||
 | 
					        { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Prevent copying.
 | 
				
			||||||
 | 
					        Node(const Node&) = delete;
 | 
				
			||||||
 | 
					        Node& operator=(const Node&) = delete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /** Return true if this node is contained in a queue. */
 | 
				
			||||||
 | 
					        bool valid() const
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return (index_ != INVALID_INDEX);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * Return the priority of this node in the queue.
 | 
				
			||||||
 | 
					         *
 | 
				
			||||||
 | 
					         * The node must be contained in a queue.
 | 
				
			||||||
 | 
					         * This function takes time O(1).
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        PrioType prio() const
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            assert(index_ != INVALID_INDEX);
 | 
				
			||||||
 | 
					            return prio_;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      private:
 | 
				
			||||||
 | 
					        IndexType       index_;
 | 
				
			||||||
 | 
					        PrioType        prio_;
 | 
				
			||||||
 | 
					        DataType        data_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        friend class PriorityQueue;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Construct an empty queue. */
 | 
				
			||||||
 | 
					    PriorityQueue()
 | 
				
			||||||
 | 
					    { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Prevent copying.
 | 
				
			||||||
 | 
					    PriorityQueue(const PriorityQueue&) = delete;
 | 
				
			||||||
 | 
					    PriorityQueue& operator=(const PriorityQueue&) = delete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Remove all elements from the queue.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * This function takes time O(n).
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    void clear()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        for (Node* node : heap_) {
 | 
				
			||||||
 | 
					            node->index_ = INVALID_INDEX;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        heap_.clear();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Return true if the queue is empty. */
 | 
				
			||||||
 | 
					    bool empty() const
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return heap_.empty();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Return the minimum priority of any element in the queue.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * The queue must be non-empty.
 | 
				
			||||||
 | 
					     * This function takes time O(1).
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    PrioType min_prio() const
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        assert(! heap_.empty());
 | 
				
			||||||
 | 
					        Node* top = heap_.front();
 | 
				
			||||||
 | 
					        return top->prio_;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Return the element with minimum priority.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * The queue must be non-empty.
 | 
				
			||||||
 | 
					     * This function takes time O(1).
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    DataType min_elem() const
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        assert(! heap_.empty());
 | 
				
			||||||
 | 
					        Node* top = heap_.front();
 | 
				
			||||||
 | 
					        return top->data_;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Insert the given node into the queue with associated data.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * The node must not currently be contained in any queue.
 | 
				
			||||||
 | 
					     * This function takes amortized time O(log(n)).
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    void insert(Node* node, PrioType prio, const DataType& data)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        assert(node->index_ == INVALID_INDEX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        node->index_ = heap_.size();
 | 
				
			||||||
 | 
					        node->prio_ = prio;
 | 
				
			||||||
 | 
					        node->data_ = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        heap_.push_back(node);
 | 
				
			||||||
 | 
					        sift_up(node->index_);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Update priority of an existing node.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * This function takes time O(log(n)).
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    void set_prio(Node* node, PrioType prio)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        IndexType index = node->index_;
 | 
				
			||||||
 | 
					        assert(index != INVALID_INDEX);
 | 
				
			||||||
 | 
					        assert(heap_[index] == node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        PrioType prev_prio = node->prio_;
 | 
				
			||||||
 | 
					        node->prio_ = prio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (prio < prev_prio) {
 | 
				
			||||||
 | 
					            sift_up(index);
 | 
				
			||||||
 | 
					        } else if (prio > prev_prio) {
 | 
				
			||||||
 | 
					            sift_down(index);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Remove the specified element from the queue.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * This function takes time O(log(n)).
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    void remove(Node* node)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        IndexType index = node->index_;
 | 
				
			||||||
 | 
					        assert(index != INVALID_INDEX);
 | 
				
			||||||
 | 
					        assert(heap_[index] == node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        node->index_ = INVALID_INDEX;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Node* move_node = heap_.back();
 | 
				
			||||||
 | 
					        heap_.pop_back();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (index < heap_.size()) {
 | 
				
			||||||
 | 
					            heap_[index] = move_node;
 | 
				
			||||||
 | 
					            move_node->index_ = index;
 | 
				
			||||||
 | 
					            if (move_node->prio_ < node->prio_) {
 | 
				
			||||||
 | 
					                sift_up(index);
 | 
				
			||||||
 | 
					            } else if (move_node->prio_ > node->prio_) {
 | 
				
			||||||
 | 
					                sift_down(index);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    /** Repair the heap along an ascending path to the root. */
 | 
				
			||||||
 | 
					    void sift_up(IndexType index)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Node* node = heap_[index];
 | 
				
			||||||
 | 
					        PrioType prio = node->prio_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while (index > 0) {
 | 
				
			||||||
 | 
					            IndexType next_index = (index - 1) / 2;
 | 
				
			||||||
 | 
					            Node* next_node = heap_[next_index];
 | 
				
			||||||
 | 
					            if (next_node->prio_ <= prio) {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            heap_[index] = next_node;
 | 
				
			||||||
 | 
					            next_node->index_ = index;
 | 
				
			||||||
 | 
					            index = next_index;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        node->index_ = index;
 | 
				
			||||||
 | 
					        heap_[index] = node;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Repair the heap along a descending path. */
 | 
				
			||||||
 | 
					    void sift_down(IndexType index)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Node* node = heap_[index];
 | 
				
			||||||
 | 
					        PrioType prio = node->prio_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        IndexType num_elem = heap_.size();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while (index < num_elem / 2) {
 | 
				
			||||||
 | 
					            IndexType next_index = 2 * index + 1;
 | 
				
			||||||
 | 
					            Node* next_node = heap_[next_index];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (next_index + 1 < num_elem) {
 | 
				
			||||||
 | 
					                Node* tmp_node = heap_[next_index + 1];
 | 
				
			||||||
 | 
					                if (tmp_node->prio_ <= next_node->prio_) {
 | 
				
			||||||
 | 
					                    ++next_index;
 | 
				
			||||||
 | 
					                    next_node = tmp_node;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (next_node->prio_ >= prio) {
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            heap_[index] = next_node;
 | 
				
			||||||
 | 
					            next_node->index_ = index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            index = next_index;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        heap_[index] = node;
 | 
				
			||||||
 | 
					        node->index_ = index;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Heap data structure. */
 | 
				
			||||||
 | 
					    std::vector<Node*> heap_;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace mwmatching
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif  // MWMATCHING_PRIORITY_QUEUE_H_
 | 
				
			||||||
| 
						 | 
					@ -1,33 +1,29 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Unit tests for data structures.
 | 
					 * Unit tests for ConcatenableQueue data structure.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Depends on the Boost.Test unit test framework.
 | 
					 * Depends on the Boost.Test unit test framework.
 | 
				
			||||||
 * Tested with Boost v1.74, available from https://www.boost.org/
 | 
					 * Tested with Boost v1.74, available from https://www.boost.org/
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
#include <climits>
 | 
					 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
#include <random>
 | 
					#include <random>
 | 
				
			||||||
#include <set>
 | 
					#include <set>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <tuple>
 | 
					 | 
				
			||||||
#include <unordered_map>
 | 
					#include <unordered_map>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define BOOST_TEST_MODULE datastruct
 | 
					#define BOOST_TEST_MODULE datastruct
 | 
				
			||||||
#include <boost/test/unit_test.hpp>
 | 
					#include <boost/test/unit_test.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "datastruct.h"
 | 
					#include "concatenable_queue.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* **********  Test ConcatenableQueue  ********** */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
BOOST_AUTO_TEST_SUITE(test_concatenable_queue)
 | 
					BOOST_AUTO_TEST_SUITE(test_concatenable_queue)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BOOST_AUTO_TEST_CASE(test_single)
 | 
					BOOST_AUTO_TEST_CASE(test_single)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    using Queue = ConcatenableQueue<int, std::string, std::string>;
 | 
					    using Queue = mwmatching::ConcatenableQueue<int, std::string, std::string>;
 | 
				
			||||||
    Queue q("Q");
 | 
					    Queue q("Q");
 | 
				
			||||||
    BOOST_TEST(q.name() == std::string("Q"));
 | 
					    BOOST_TEST(q.name() == std::string("Q"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,7 +45,7 @@ BOOST_AUTO_TEST_CASE(test_single)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BOOST_AUTO_TEST_CASE(test_simple)
 | 
					BOOST_AUTO_TEST_CASE(test_simple)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    using Queue = ConcatenableQueue<int, std::string, char>;
 | 
					    using Queue = mwmatching::ConcatenableQueue<int, std::string, char>;
 | 
				
			||||||
    Queue::Node n1, n2, n3, n4, n5;
 | 
					    Queue::Node n1, n2, n3, n4, n5;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Queue q1("A");
 | 
					    Queue q1("A");
 | 
				
			||||||
| 
						 | 
					@ -140,7 +136,7 @@ BOOST_AUTO_TEST_CASE(test_simple)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BOOST_AUTO_TEST_CASE(test_medium)
 | 
					BOOST_AUTO_TEST_CASE(test_medium)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    using Queue = ConcatenableQueue<int, char, char>;
 | 
					    using Queue = mwmatching::ConcatenableQueue<int, char, char>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::vector<char> queue_names(19);
 | 
					    std::vector<char> queue_names(19);
 | 
				
			||||||
    for (int i = 0; i < 14; i++) {
 | 
					    for (int i = 0; i < 14; i++) {
 | 
				
			||||||
| 
						 | 
					@ -255,7 +251,7 @@ BOOST_AUTO_TEST_CASE(test_medium)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BOOST_AUTO_TEST_CASE(test_random)
 | 
					BOOST_AUTO_TEST_CASE(test_random)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    using Queue = ConcatenableQueue<double, int, int>;
 | 
					    using Queue = mwmatching::ConcatenableQueue<double, int, int>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constexpr int NUM_NODES = 4000;
 | 
					    constexpr int NUM_NODES = 4000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -405,238 +401,3 @@ BOOST_AUTO_TEST_CASE(test_random)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BOOST_AUTO_TEST_SUITE_END()
 | 
					BOOST_AUTO_TEST_SUITE_END()
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* **********  Test PriorityQueue  ********** */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
BOOST_AUTO_TEST_SUITE(test_priority_queue)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
BOOST_AUTO_TEST_CASE(test_empty)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    using Queue = PriorityQueue<int, std::string>;
 | 
					 | 
				
			||||||
    Queue q;
 | 
					 | 
				
			||||||
    BOOST_TEST(q.empty() == true);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
BOOST_AUTO_TEST_CASE(test_single)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    using Queue = PriorityQueue<int, std::string>;
 | 
					 | 
				
			||||||
    Queue q;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Queue::Node n1;
 | 
					 | 
				
			||||||
    BOOST_TEST(n1.valid() == false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.insert(&n1, 5, "a");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    BOOST_TEST(n1.valid() == true);
 | 
					 | 
				
			||||||
    BOOST_TEST(n1.prio() == 5);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.empty() == false);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_prio() == 5);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_elem() == std::string("a"));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.set_prio(&n1, 3);
 | 
					 | 
				
			||||||
    BOOST_TEST(n1.prio() == 3);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_prio() == 3);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_elem() == std::string("a"));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.remove(&n1);
 | 
					 | 
				
			||||||
    BOOST_TEST(n1.valid() == false);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.empty() == true);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
BOOST_AUTO_TEST_CASE(test_simple)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    using Queue = PriorityQueue<int, char>;
 | 
					 | 
				
			||||||
    Queue q;
 | 
					 | 
				
			||||||
    Queue::Node nodes[10];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.insert(&nodes[0], 9, 'a');
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_prio() == 9);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_elem() == 'a');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.insert(&nodes[1], 4, 'b');
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_prio() == 4);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_elem() == 'b');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.insert(&nodes[2], 7, 'c');
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_prio() == 4);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_elem() == 'b');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.insert(&nodes[3], 5, 'd');
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_prio() == 4);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_elem() == 'b');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.insert(&nodes[4], 8, 'e');
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_prio() == 4);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_elem() == 'b');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.insert(&nodes[5], 6, 'f');
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_prio() == 4);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_elem() == 'b');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.insert(&nodes[6], 4, 'g');
 | 
					 | 
				
			||||||
    q.insert(&nodes[7], 5, 'h');
 | 
					 | 
				
			||||||
    q.insert(&nodes[8], 2, 'i');
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_prio() == 2);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_elem() == 'i');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.insert(&nodes[9], 6, 'j');
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_prio() == 2);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_elem() == 'i');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.set_prio(&nodes[2], 1);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_prio() == 1);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_elem() == 'c');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.set_prio(&nodes[4], 3);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_prio() == 1);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_elem() == 'c');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.remove(&nodes[2]);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_prio() == 2);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_elem() == 'i');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.remove(&nodes[8]);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_prio() == 3);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_elem() == 'e');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.remove(&nodes[4]);
 | 
					 | 
				
			||||||
    q.remove(&nodes[1]);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_prio() == 4);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_elem() == 'g');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.remove(&nodes[3]);
 | 
					 | 
				
			||||||
    q.remove(&nodes[9]);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_prio() == 4);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_elem() == 'g');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.remove(&nodes[6]);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_prio() == 5);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_elem() == 'h');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    BOOST_TEST(q.empty() == false);
 | 
					 | 
				
			||||||
    q.clear();
 | 
					 | 
				
			||||||
    BOOST_TEST(q.empty() == true);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
BOOST_AUTO_TEST_CASE(test_increase_prio)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    using Queue = PriorityQueue<int, char>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Queue q;
 | 
					 | 
				
			||||||
    Queue::Node n1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.insert(&n1, 5, 'a');
 | 
					 | 
				
			||||||
    q.set_prio(&n1, 8);
 | 
					 | 
				
			||||||
    BOOST_TEST(n1.prio() == 8);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_prio() == 8);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.clear();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Queue::Node n2, n3, n4;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.insert(&n1, 9, 'A');
 | 
					 | 
				
			||||||
    q.insert(&n2, 4, 'b');
 | 
					 | 
				
			||||||
    q.insert(&n3, 7, 'c');
 | 
					 | 
				
			||||||
    q.insert(&n4, 5, 'd');
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_prio() == 4);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_elem() == 'b');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.set_prio(&n2, 8);
 | 
					 | 
				
			||||||
    BOOST_TEST(n2.prio() == 8);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_elem() == 'd');
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_prio() == 5);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.set_prio(&n3, 10);
 | 
					 | 
				
			||||||
    BOOST_TEST(n3.prio() == 10);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_elem() == 'd');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.remove(&n4);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_elem() == 'b');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.remove(&n2);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_prio() == 9);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_elem() == 'A');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.remove(&n1);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_elem() == 'c');
 | 
					 | 
				
			||||||
    BOOST_TEST(q.min_prio() == 10);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    q.remove(&n3);
 | 
					 | 
				
			||||||
    BOOST_TEST(q.empty() == true);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
BOOST_AUTO_TEST_CASE(test_random)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    using Queue = PriorityQueue<int, int>;
 | 
					 | 
				
			||||||
    Queue q;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const int num_elem = 1000;
 | 
					 | 
				
			||||||
    std::vector<std::tuple<std::unique_ptr<Queue::Node>, int, int>> elems;
 | 
					 | 
				
			||||||
    int next_data = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::mt19937 rng(34567);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    auto check = [&q,&elems]() {
 | 
					 | 
				
			||||||
        int min_prio = q.min_prio();
 | 
					 | 
				
			||||||
        int min_data = q.min_elem();
 | 
					 | 
				
			||||||
        int best_prio = INT_MAX;
 | 
					 | 
				
			||||||
        bool found = false;
 | 
					 | 
				
			||||||
        for (const auto& v : elems) {
 | 
					 | 
				
			||||||
            int this_prio = std::get<1>(v);
 | 
					 | 
				
			||||||
            int this_data = std::get<2>(v);
 | 
					 | 
				
			||||||
            best_prio = std::min(best_prio, this_prio);
 | 
					 | 
				
			||||||
            if ((this_prio == min_prio) && (this_data == min_data)) {
 | 
					 | 
				
			||||||
                found = true;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        BOOST_TEST(found == true);
 | 
					 | 
				
			||||||
        BOOST_TEST(min_prio == best_prio);
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (int i = 0; i < num_elem; ++i) {
 | 
					 | 
				
			||||||
        ++next_data;
 | 
					 | 
				
			||||||
        int prio = std::uniform_int_distribution<>(0, 1000000)(rng);
 | 
					 | 
				
			||||||
        std::unique_ptr<Queue::Node> nptr(new Queue::Node);
 | 
					 | 
				
			||||||
        q.insert(nptr.get(), prio, next_data);
 | 
					 | 
				
			||||||
        elems.push_back(std::make_tuple(std::move(nptr), prio, next_data));
 | 
					 | 
				
			||||||
        check();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (int i = 0; i < 10000; ++i) {
 | 
					 | 
				
			||||||
        int p = std::uniform_int_distribution<>(0, num_elem - 1)(rng);
 | 
					 | 
				
			||||||
        Queue::Node* node = std::get<0>(elems[p]).get();
 | 
					 | 
				
			||||||
        int prio = std::get<1>(elems[p]);
 | 
					 | 
				
			||||||
        prio = std::uniform_int_distribution<>(0, 1000000)(rng);
 | 
					 | 
				
			||||||
        q.set_prio(node, prio);
 | 
					 | 
				
			||||||
        std::get<1>(elems[p]) = prio;
 | 
					 | 
				
			||||||
        check();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        p = std::uniform_int_distribution<>(0, num_elem - 1)(rng);
 | 
					 | 
				
			||||||
        node = std::get<0>(elems[p]).get();
 | 
					 | 
				
			||||||
        q.remove(node);
 | 
					 | 
				
			||||||
        elems.erase(elems.begin() + p);
 | 
					 | 
				
			||||||
        check();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        ++next_data;
 | 
					 | 
				
			||||||
        prio = std::uniform_int_distribution<>(0, 1000000)(rng);
 | 
					 | 
				
			||||||
        std::unique_ptr<Queue::Node> nptr(new Queue::Node);
 | 
					 | 
				
			||||||
        q.insert(nptr.get(), prio, next_data);
 | 
					 | 
				
			||||||
        elems.push_back(std::make_tuple(std::move(nptr), prio, next_data));
 | 
					 | 
				
			||||||
        check();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (int i = 0; i < num_elem; ++i) {
 | 
					 | 
				
			||||||
        int p = std::uniform_int_distribution<>(0, num_elem - 1 - i)(rng);
 | 
					 | 
				
			||||||
        Queue::Node* node = std::get<0>(elems[p]).get();
 | 
					 | 
				
			||||||
        q.remove(node);
 | 
					 | 
				
			||||||
        elems.erase(elems.begin() + p);
 | 
					 | 
				
			||||||
        if (! elems.empty()) {
 | 
					 | 
				
			||||||
            check();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    BOOST_TEST(q.empty() == true);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
BOOST_AUTO_TEST_SUITE_END()
 | 
					 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,252 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Unit tests for PriorityQueue data structure.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Depends on the Boost.Test unit test framework.
 | 
				
			||||||
 | 
					 * Tested with Boost v1.74, available from https://www.boost.org/
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					#include <climits>
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
 | 
					#include <random>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <tuple>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BOOST_TEST_MODULE datastruct
 | 
				
			||||||
 | 
					#include <boost/test/unit_test.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "priority_queue.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BOOST_AUTO_TEST_SUITE(test_priority_queue)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BOOST_AUTO_TEST_CASE(test_empty)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    using Queue = mwmatching::PriorityQueue<int, std::string>;
 | 
				
			||||||
 | 
					    Queue q;
 | 
				
			||||||
 | 
					    BOOST_TEST(q.empty() == true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BOOST_AUTO_TEST_CASE(test_single)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    using Queue = mwmatching::PriorityQueue<int, std::string>;
 | 
				
			||||||
 | 
					    Queue q;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Queue::Node n1;
 | 
				
			||||||
 | 
					    BOOST_TEST(n1.valid() == false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.insert(&n1, 5, "a");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    BOOST_TEST(n1.valid() == true);
 | 
				
			||||||
 | 
					    BOOST_TEST(n1.prio() == 5);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.empty() == false);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_prio() == 5);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_elem() == std::string("a"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.set_prio(&n1, 3);
 | 
				
			||||||
 | 
					    BOOST_TEST(n1.prio() == 3);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_prio() == 3);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_elem() == std::string("a"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.remove(&n1);
 | 
				
			||||||
 | 
					    BOOST_TEST(n1.valid() == false);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.empty() == true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BOOST_AUTO_TEST_CASE(test_simple)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    using Queue = mwmatching::PriorityQueue<int, char>;
 | 
				
			||||||
 | 
					    Queue q;
 | 
				
			||||||
 | 
					    Queue::Node nodes[10];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.insert(&nodes[0], 9, 'a');
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_prio() == 9);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_elem() == 'a');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.insert(&nodes[1], 4, 'b');
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_prio() == 4);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_elem() == 'b');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.insert(&nodes[2], 7, 'c');
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_prio() == 4);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_elem() == 'b');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.insert(&nodes[3], 5, 'd');
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_prio() == 4);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_elem() == 'b');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.insert(&nodes[4], 8, 'e');
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_prio() == 4);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_elem() == 'b');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.insert(&nodes[5], 6, 'f');
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_prio() == 4);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_elem() == 'b');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.insert(&nodes[6], 4, 'g');
 | 
				
			||||||
 | 
					    q.insert(&nodes[7], 5, 'h');
 | 
				
			||||||
 | 
					    q.insert(&nodes[8], 2, 'i');
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_prio() == 2);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_elem() == 'i');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.insert(&nodes[9], 6, 'j');
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_prio() == 2);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_elem() == 'i');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.set_prio(&nodes[2], 1);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_prio() == 1);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_elem() == 'c');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.set_prio(&nodes[4], 3);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_prio() == 1);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_elem() == 'c');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.remove(&nodes[2]);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_prio() == 2);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_elem() == 'i');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.remove(&nodes[8]);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_prio() == 3);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_elem() == 'e');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.remove(&nodes[4]);
 | 
				
			||||||
 | 
					    q.remove(&nodes[1]);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_prio() == 4);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_elem() == 'g');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.remove(&nodes[3]);
 | 
				
			||||||
 | 
					    q.remove(&nodes[9]);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_prio() == 4);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_elem() == 'g');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.remove(&nodes[6]);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_prio() == 5);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_elem() == 'h');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    BOOST_TEST(q.empty() == false);
 | 
				
			||||||
 | 
					    q.clear();
 | 
				
			||||||
 | 
					    BOOST_TEST(q.empty() == true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BOOST_AUTO_TEST_CASE(test_increase_prio)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    using Queue = mwmatching::PriorityQueue<int, char>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Queue q;
 | 
				
			||||||
 | 
					    Queue::Node n1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.insert(&n1, 5, 'a');
 | 
				
			||||||
 | 
					    q.set_prio(&n1, 8);
 | 
				
			||||||
 | 
					    BOOST_TEST(n1.prio() == 8);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_prio() == 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Queue::Node n2, n3, n4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.insert(&n1, 9, 'A');
 | 
				
			||||||
 | 
					    q.insert(&n2, 4, 'b');
 | 
				
			||||||
 | 
					    q.insert(&n3, 7, 'c');
 | 
				
			||||||
 | 
					    q.insert(&n4, 5, 'd');
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_prio() == 4);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_elem() == 'b');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.set_prio(&n2, 8);
 | 
				
			||||||
 | 
					    BOOST_TEST(n2.prio() == 8);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_elem() == 'd');
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_prio() == 5);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.set_prio(&n3, 10);
 | 
				
			||||||
 | 
					    BOOST_TEST(n3.prio() == 10);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_elem() == 'd');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.remove(&n4);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_elem() == 'b');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.remove(&n2);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_prio() == 9);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_elem() == 'A');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.remove(&n1);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_elem() == 'c');
 | 
				
			||||||
 | 
					    BOOST_TEST(q.min_prio() == 10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    q.remove(&n3);
 | 
				
			||||||
 | 
					    BOOST_TEST(q.empty() == true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BOOST_AUTO_TEST_CASE(test_random)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    using Queue = mwmatching::PriorityQueue<int, int>;
 | 
				
			||||||
 | 
					    Queue q;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const int num_elem = 1000;
 | 
				
			||||||
 | 
					    std::vector<std::tuple<std::unique_ptr<Queue::Node>, int, int>> elems;
 | 
				
			||||||
 | 
					    int next_data = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::mt19937 rng(34567);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto check = [&q,&elems]() {
 | 
				
			||||||
 | 
					        int min_prio = q.min_prio();
 | 
				
			||||||
 | 
					        int min_data = q.min_elem();
 | 
				
			||||||
 | 
					        int best_prio = INT_MAX;
 | 
				
			||||||
 | 
					        bool found = false;
 | 
				
			||||||
 | 
					        for (const auto& v : elems) {
 | 
				
			||||||
 | 
					            int this_prio = std::get<1>(v);
 | 
				
			||||||
 | 
					            int this_data = std::get<2>(v);
 | 
				
			||||||
 | 
					            best_prio = std::min(best_prio, this_prio);
 | 
				
			||||||
 | 
					            if ((this_prio == min_prio) && (this_data == min_data)) {
 | 
				
			||||||
 | 
					                found = true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        BOOST_TEST(found == true);
 | 
				
			||||||
 | 
					        BOOST_TEST(min_prio == best_prio);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (int i = 0; i < num_elem; ++i) {
 | 
				
			||||||
 | 
					        ++next_data;
 | 
				
			||||||
 | 
					        int prio = std::uniform_int_distribution<>(0, 1000000)(rng);
 | 
				
			||||||
 | 
					        std::unique_ptr<Queue::Node> nptr(new Queue::Node);
 | 
				
			||||||
 | 
					        q.insert(nptr.get(), prio, next_data);
 | 
				
			||||||
 | 
					        elems.push_back(std::make_tuple(std::move(nptr), prio, next_data));
 | 
				
			||||||
 | 
					        check();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (int i = 0; i < 10000; ++i) {
 | 
				
			||||||
 | 
					        int p = std::uniform_int_distribution<>(0, num_elem - 1)(rng);
 | 
				
			||||||
 | 
					        Queue::Node* node = std::get<0>(elems[p]).get();
 | 
				
			||||||
 | 
					        int prio = std::get<1>(elems[p]);
 | 
				
			||||||
 | 
					        prio = std::uniform_int_distribution<>(0, 1000000)(rng);
 | 
				
			||||||
 | 
					        q.set_prio(node, prio);
 | 
				
			||||||
 | 
					        std::get<1>(elems[p]) = prio;
 | 
				
			||||||
 | 
					        check();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        p = std::uniform_int_distribution<>(0, num_elem - 1)(rng);
 | 
				
			||||||
 | 
					        node = std::get<0>(elems[p]).get();
 | 
				
			||||||
 | 
					        q.remove(node);
 | 
				
			||||||
 | 
					        elems.erase(elems.begin() + p);
 | 
				
			||||||
 | 
					        check();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ++next_data;
 | 
				
			||||||
 | 
					        prio = std::uniform_int_distribution<>(0, 1000000)(rng);
 | 
				
			||||||
 | 
					        std::unique_ptr<Queue::Node> nptr(new Queue::Node);
 | 
				
			||||||
 | 
					        q.insert(nptr.get(), prio, next_data);
 | 
				
			||||||
 | 
					        elems.push_back(std::make_tuple(std::move(nptr), prio, next_data));
 | 
				
			||||||
 | 
					        check();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (int i = 0; i < num_elem; ++i) {
 | 
				
			||||||
 | 
					        int p = std::uniform_int_distribution<>(0, num_elem - 1 - i)(rng);
 | 
				
			||||||
 | 
					        Queue::Node* node = std::get<0>(elems[p]).get();
 | 
				
			||||||
 | 
					        q.remove(node);
 | 
				
			||||||
 | 
					        elems.erase(elems.begin() + p);
 | 
				
			||||||
 | 
					        if (! elems.empty()) {
 | 
				
			||||||
 | 
					            check();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    BOOST_TEST(q.empty() == true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BOOST_AUTO_TEST_SUITE_END()
 | 
				
			||||||
| 
						 | 
					@ -9,8 +9,10 @@ echo
 | 
				
			||||||
g++ --version
 | 
					g++ --version
 | 
				
			||||||
echo
 | 
					echo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
make -C cpp run_matching test_mwmatching
 | 
					make -C cpp run_matching test_mwmatching test_concatenable_queue test_priority_queue
 | 
				
			||||||
cpp/test_mwmatching
 | 
					cpp/test_mwmatching
 | 
				
			||||||
 | 
					cpp/test_concatenable_queue
 | 
				
			||||||
 | 
					cpp/test_priority_queue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
echo
 | 
					echo
 | 
				
			||||||
echo ">> Running test graphs"
 | 
					echo ">> Running test graphs"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue