Skip to content
Snippets Groups Projects
OptimisationTools.h 3.91 KiB
Newer Older
  • Learn to ignore specific revisions
  • Valentin Platzgummer's avatar
    Valentin Platzgummer committed
    #include <QObject>
    
    
    #include <functional>
    
    Valentin Platzgummer's avatar
    Valentin Platzgummer committed
    namespace OptimisationTools {
    
        /*!
         * \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
         */
    
        template <class T>
    
    Valentin Platzgummer's avatar
    Valentin Platzgummer committed
        bool dijkstraAlgorithm(const QList<T> &elements, int startIndex, int endIndex, QList<T> &elementPath, std::function<double(const T &, const T &)> distanceDij)
    
        {
            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]);
            }
    
    
    Valentin Platzgummer's avatar
    Valentin Platzgummer committed
    //        double d1 = distanceDij(elements[0], elements[1]);
    //        double d2 = distanceDij(elements[0], elements[5]);
    //        double d3 = distanceDij(elements[5], elements[1]);
    
    
            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();
    
    Valentin Platzgummer's avatar
    Valentin Platzgummer committed
                int minDistIndex = -1;
    
                for (int i = 0; i < workingSet.size(); i++) {
                    Node* node = workingSet.value(i);
                    double dist = node->distance;
                    if (dist < minDist) {
                        minDist = dist;
                        minDistIndex = i;
                    }
                }
    
    Valentin Platzgummer's avatar
    Valentin Platzgummer committed
                if (minDistIndex == -1)
                        return false;
    
    
                Node* u = workingSet.takeAt(minDistIndex);
    
    
    Valentin Platzgummer's avatar
    Valentin Platzgummer committed
                if (u->element == elements[endIndex]) // shortest path found
                    break;
    
    
                //update distance
                for (int i = 0; i < workingSet.size(); i++) {
                    Node* v = workingSet[i];
    
    Valentin Platzgummer's avatar
    Valentin Platzgummer committed
                    double dist = distanceDij(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;
        }