All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.automatalib.util.graphs.apsp.FloydWarshallAPSP Maven / Gradle / Ivy

Go to download

This artifact provides various common utility operations for analyzing and manipulating automata and graphs, such as traversal, minimization and copying.

There is a newer version: 0.11.0
Show newest version
/* Copyright (C) 2013-2019 TU Dortmund
 * This file is part of AutomataLib, http://www.automatalib.net/.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.automatalib.util.graphs.apsp;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;

import net.automatalib.graphs.Graph;
import net.automatalib.graphs.concepts.EdgeWeights;
import net.automatalib.graphs.concepts.NodeIDs;
import net.automatalib.util.graphs.Graphs;

/**
 * Implementation of the Floyd-Warshall dynamic programming algorithm for the all pairs shortest paths problem.
 *
 * @param 
 *         node class
 * @param 
 *         edge class
 *
 * @author Malte Isberner
 */
@ParametersAreNonnullByDefault
public class FloydWarshallAPSP implements APSPResult {

    private final int size;
    @Nonnull
    private final NodeIDs ids;
    @Nonnull
    private final APSPRecord[][] table;

    @SuppressWarnings("unchecked")
    public FloydWarshallAPSP(Graph graph, EdgeWeights ew) {
        this.size = graph.size();
        this.ids = graph.nodeIDs();
        this.table = new APSPRecord[size][size];

        initialize(graph, ew);
    }

    private void initialize(Graph graph, EdgeWeights ew) {
        for (int i = 0; i < size; i++) {
            N src = ids.getNode(i);

            Collection edges = graph.getOutgoingEdges(src);

            for (E edge : edges) {
                N tgt = graph.getTarget(edge);
                if (tgt.equals(src)) {
                    continue;
                }

                int j = ids.getNodeId(tgt);
                float w = ew.getEdgeWeight(edge);
                APSPRecord prev = table[i][j];
                if (prev == null || prev.distance > w) {
                    table[i][j] = new APSPRecord<>(edge, w);
                }
            }
        }
    }

    @Nonnull
    public static  APSPResult findAPSP(Graph graph, EdgeWeights edgeWeights) {
        FloydWarshallAPSP fw = new FloydWarshallAPSP<>(graph, edgeWeights);
        fw.findAPSP();
        return fw;
    }

    public void findAPSP() {
        for (int k = 0; k < size; k++) {

            for (int i = 0; i < size; i++) {
                for (int j = 0; j < size; j++) {
                    if (j == i) {
                        continue;
                    }

                    APSPRecord currRec = table[i][j];

                    if (k == i || k == j) {
                        continue;
                    }

                    APSPRecord part1 = table[i][k], part2 = table[k][j];

                    if (part1 == null || part2 == null) {
                        continue;
                    }

                    float dist1 = part1.distance, dist2 = part2.distance;
                    float total = dist1 + dist2;

                    if (currRec == null) {
                        currRec = new APSPRecord<>(total, k, part1.numEdges + part2.numEdges);
                        table[i][j] = currRec;
                    } else if (currRec.distance > total) {
                        currRec.distance = total;
                        currRec.middle = k;
                        currRec.numEdges = part1.numEdges + part2.numEdges;
                    }

                }
            }
        }
    }

    @Override
    public float getShortestPathDistance(N src, N tgt) {
        int srcId = ids.getNodeId(src), tgtId = ids.getNodeId(tgt);

        APSPRecord rec = table[srcId][tgtId];
        if (rec == null) {
            return Graphs.INVALID_DISTANCE;
        }

        return rec.distance;
    }

    @Override
    public List getShortestPath(N src, N tgt) {
        int srcId = ids.getNodeId(src), tgtId = ids.getNodeId(tgt);

        APSPRecord rec = table[srcId][tgtId];

        if (rec == null) {
            return null;
        }

        List result = new ArrayList<>(rec.numEdges);

        buildPath(result, srcId, tgtId, rec);

        return result;
    }

    private void buildPath(List path, int srcId, int tgtId, APSPRecord rec) {
        if (rec.middle == -1) {
            path.add(rec.edge);
            return;
        }

        int middle = rec.middle;
        buildPath(path, srcId, middle, table[srcId][middle]);
        buildPath(path, middle, tgtId, table[middle][tgtId]);
    }

    @ParametersAreNonnullByDefault
    private static final class APSPRecord {

        @Nullable
        public final E edge;
        public float distance;
        public int middle;
        public int numEdges;

        APSPRecord(E edge, float distance) {
            this.edge = edge;
            this.distance = distance;
            this.middle = -1;
            this.numEdges = 1;
        }

        APSPRecord(float distance, int middle, int numEdges) {
            this.edge = null;
            this.distance = distance;
            this.middle = middle;
            this.numEdges = numEdges;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy