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
 | 
			
		||||
 | 
			
		||||
.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 $@ $<
 | 
			
		||||
 | 
			
		||||
run_matching_dbg: OPTFLAGS = -Og
 | 
			
		||||
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 $@ $<
 | 
			
		||||
 | 
			
		||||
test_mwmatching: OPTFLAGS = -O1
 | 
			
		||||
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)
 | 
			
		||||
 | 
			
		||||
test_datastruct: OPTFLAGS = -O1
 | 
			
		||||
test_datastruct: DBGFLAGS = -fsanitize=address -fsanitize=undefined
 | 
			
		||||
test_datastruct: test_datastruct.cpp datastruct.h
 | 
			
		||||
test_concatenable_queue: OPTFLAGS = -O1
 | 
			
		||||
test_concatenable_queue: DBGFLAGS = -fsanitize=address -fsanitize=undefined
 | 
			
		||||
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)
 | 
			
		||||
 | 
			
		||||
.PHONY: 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 <cassert>
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <tuple>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* **************************************************
 | 
			
		||||
 * **        class ConcatenableQueue               **
 | 
			
		||||
 * ************************************************** */
 | 
			
		||||
namespace mwmatching {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Priority queue supporting efficient merge and split operations.
 | 
			
		||||
| 
						 | 
				
			
			@ -836,253 +836,6 @@ private:
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* **************************************************
 | 
			
		||||
 * **        class PriorityQueue                   **
 | 
			
		||||
 * ************************************************** */
 | 
			
		||||
} // 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_;
 | 
			
		||||
};
 | 
			
		||||
#endif  // MWMATCHING_CONCATENABLE_QUEUE_H_
 | 
			
		||||
| 
						 | 
				
			
			@ -19,7 +19,8 @@
 | 
			
		|||
#include <utility>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "datastruct.h"
 | 
			
		||||
#include "concatenable_queue.hpp"
 | 
			
		||||
#include "priority_queue.hpp"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
 * Tested with Boost v1.74, available from https://www.boost.org/
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <climits>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <random>
 | 
			
		||||
#include <set>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <tuple>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#define BOOST_TEST_MODULE datastruct
 | 
			
		||||
#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_CASE(test_single)
 | 
			
		||||
{
 | 
			
		||||
    using Queue = ConcatenableQueue<int, std::string, std::string>;
 | 
			
		||||
    using Queue = mwmatching::ConcatenableQueue<int, std::string, std::string>;
 | 
			
		||||
    Queue q("Q");
 | 
			
		||||
    BOOST_TEST(q.name() == std::string("Q"));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -49,7 +45,7 @@ BOOST_AUTO_TEST_CASE(test_single)
 | 
			
		|||
 | 
			
		||||
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 q1("A");
 | 
			
		||||
| 
						 | 
				
			
			@ -140,7 +136,7 @@ BOOST_AUTO_TEST_CASE(test_simple)
 | 
			
		|||
 | 
			
		||||
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);
 | 
			
		||||
    for (int i = 0; i < 14; i++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -255,7 +251,7 @@ BOOST_AUTO_TEST_CASE(test_medium)
 | 
			
		|||
 | 
			
		||||
BOOST_AUTO_TEST_CASE(test_random)
 | 
			
		||||
{
 | 
			
		||||
    using Queue = ConcatenableQueue<double, int, int>;
 | 
			
		||||
    using Queue = mwmatching::ConcatenableQueue<double, int, int>;
 | 
			
		||||
 | 
			
		||||
    constexpr int NUM_NODES = 4000;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -405,238 +401,3 @@ BOOST_AUTO_TEST_CASE(test_random)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
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_concatenable_queue
 | 
			
		||||
cpp/test_priority_queue
 | 
			
		||||
 | 
			
		||||
echo
 | 
			
		||||
echo ">> Running test graphs"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue