OptimisationTools.h 3.56 KB
Newer Older
1
#pragma once
Valentin Platzgummer's avatar
Valentin Platzgummer committed
2 3
#include <QObject>

4
#include <functional>
5
#include <QPointF>
6

Valentin Platzgummer's avatar
Valentin Platzgummer committed
7
namespace OptimisationTools {
8 9 10 11 12 13 14 15 16 17
    /*!
     * \fn bool dijkstraAlgorithm(int startIndex, int endIndex, const QList<T> elements, QList<T> &elementPath, double(*distance)(const T &t1, const T &t2))
     * Calculates the shortest path between the elements stored in \a elements.
     * The \l {Dijkstra Algorithm} is used to find the shorest path.
     * Stores the result inside \a elementPath when sucessfull.
     * The function handle \a distance is used to calculate the distance between two elements. The distance must be positive.
     * Returns \c true if successful, \c false else.
     *
     * \sa QList
     */
18
    template <class T>
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
    bool dijkstraAlgorithm(const QList<T> &elements, int startIndex, int endIndex, QList<T> &elementPath, std::function<double(const T &, const T &)> distance)
    {
        if (    elements.isEmpty() || startIndex < 0
             || startIndex >= elements.size() || endIndex < 0
             || endIndex >= elements.size()) {
            return false;
        }
        //qWarning("optitools");
        // Each element of type T gets stuff into a Node
        /// @param distance is the distance between the Node and it's predecessor
        struct Node{
            T element;
            double distance = std::numeric_limits<qreal>::infinity();
            Node* predecessorNode = nullptr;
        };

        // The list with all Nodes (elements)
        QList<Node> nodeList;
        // This list will be initalized with (pointer to) all elements of nodeList.
        // Elements will be successively remove during the execution of the Dijkstra Algorithm.
        QList<Node*> workingSet;

        //append elements to node list
        for (int i = 0; i < elements.size(); i++) {
            Node node;
            node.element = elements[i];
            nodeList.append(node);
            workingSet.append(&nodeList[i]);
        }

        nodeList[startIndex].distance = 0;

        // Dijkstra Algorithm
        // https://de.wikipedia.org/wiki/Dijkstra-Algorithmus
        while (workingSet.size() > 0) {
            // serach Node with minimal distance
            double minDist = std::numeric_limits<qreal>::infinity();
            int minDistIndex = 0;
            for (int i = 0; i < workingSet.size(); i++) {
                Node* node = workingSet.value(i);
                double dist = node->distance;
                if (dist < minDist) {
                    minDist = dist;
                    minDistIndex = i;
                }
            }
            Node* u = workingSet.takeAt(minDistIndex);

            //update distance
            for (int i = 0; i < workingSet.size(); i++) {
                Node* v = workingSet[i];
                double dist = distance(u->element, v->element);
                // is ther a alternative path which is shorter?
                double alternative = u->distance + dist;
                if (alternative < v->distance)  {
                    v->distance         = alternative;
                    v->predecessorNode  = u;
                }
            }

        }
        // end Djikstra Algorithm


        // reverse assemble path
        Node* node = &nodeList[endIndex];
        while (1) {
            if (node == nullptr) {
                if (elementPath[0] == elements[startIndex])// check if starting point was reached
                    break;
                return false;
            }
            elementPath.prepend(node->element);

            //Update Node
            node = node->predecessorNode;

        }
        return true;
    }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
99 100
}

101