matching.edmonds1.Matching.java Source code

Java tutorial

Introduction

Here is the source code for matching.edmonds1.Matching.java

Source

/*
 * Copyright 2012 Arie Benichou
 * 
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */

package matching.edmonds1;

import graph.UndirectedGraph;
import graph.WeightedEdge;
import graph.features.degree.DegreeFeature;
import graph.features.degree.DegreeInterface;
import graph.features.shortestPath.PathInterface;
import graph.features.shortestPath.ShortestPathFeature;
import graph.features.shortestPath.ShortestPathInterface;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import matching.Matches;
import matching.MatchingAlgorithmInterface;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

/**
 * Minimum Weight Perfect Matching Algorithm
 */
public final class Matching implements MatchingAlgorithmInterface {

    private static <T> Map<T, T> buildMatchingMap(final MutableUndirectedGraph<T> maximumMatching) {
        final Builder<T, T> builder = new ImmutableMap.Builder<T, T>();
        final Set<T> set = Sets.newHashSet();
        for (final T endPoint1 : maximumMatching) {
            final T endPoint2 = maximumMatching.getEndPoints(endPoint1).iterator().next();
            if (!set.contains(endPoint2)) {
                set.add(endPoint1);
                set.add(endPoint2);
                builder.put(endPoint1, endPoint2);
            }
        }
        return builder.build();
    }

    private static <T> double computeCost(final UndirectedGraph<T> originalGraph, final Map<T, T> matching) {
        if (matching.isEmpty())
            return Double.POSITIVE_INFINITY;

        final ShortestPathInterface<T> pathFeature = originalGraph.fetch(ShortestPathFeature.class).up();

        double cost = 0;
        for (final Entry<T, T> entry : matching.entrySet())
            cost += pathFeature.getShortestPath(entry.getKey(), entry.getValue()).getWeight();
        return cost;
    }

    private static <T> boolean isPerfect(final MutableUndirectedGraph<T> maximumMatching) {
        for (final T MazeNode : maximumMatching)
            if (maximumMatching.getEndPoints(MazeNode).size() != 1)
                return false;
        return true;
    }

    private UndirectedGraph<?> originalGraph;

    private static <T> Map<WeightedEdge<T>, Integer> buildMap(final UndirectedGraph<T> originalGraph) {

        final Set<WeightedEdge<T>> edges = Sets.newHashSet();
        for (final T vertex : originalGraph)
            edges.addAll(originalGraph.getEdgesFrom(vertex));

        final Map<WeightedEdge<T>, Integer> map = Maps.newHashMap();
        for (final WeightedEdge<T> edge : edges)
            map.put(edge, 1);

        final DegreeInterface<T> degreeInterface = originalGraph.fetch(DegreeFeature.class).up();

        final Set<T> nodesWithDegree1 = degreeInterface.getNodesHavingDegree(1).keySet();

        for (final T t : nodesWithDegree1) {
            final WeightedEdge<T> endWayEdge = originalGraph.getEdgesFrom(t).iterator().next();
            map.put(endWayEdge, 2);
        }

        return map;
    }

    private static <T> Map<WeightedEdge<T>, Integer> eulerize(final UndirectedGraph<T> originalGraph,
            final Map<T, T> matching) {

        final Map<WeightedEdge<T>, Integer> map = buildMap(originalGraph);

        /*
        for (final Entry<WeightedEdge<T>, Integer> t : map.entrySet()) {
        System.out.println(t);
        }
        */

        final ShortestPathInterface<T> pathFeature = originalGraph.fetch(ShortestPathFeature.class).up();

        for (final Entry<T, T> entry : matching.entrySet()) {
            final T endPoint1 = entry.getKey();
            final T endPoint2 = entry.getValue();
            final PathInterface<T> path = pathFeature.getShortestPath(endPoint1, endPoint2);
            for (final WeightedEdge<T> edge : path.getEdges()) {
                map.put(edge, (map.get(edge) + 1) % 2 == 0 ? 2 : 1);
                //map.put(edge, 2);
            }
        }
        return map;
    }

    private static <T> double computeCost(final Map<WeightedEdge<T>, Integer> edgeInstances) {
        double cost = 0;
        for (final Entry<WeightedEdge<T>, Integer> entry : edgeInstances.entrySet()) {
            final WeightedEdge<T> edge = entry.getKey();
            final Integer k = entry.getValue();
            cost += k * edge.getWeight();
        }
        return cost;
    }

    private <T> MutableUndirectedGraph<T> copyGraph(final UndirectedGraph<T> residualGraph) {
        final MutableUndirectedGraph<T> mutableResidualGraph = new MutableUndirectedGraph<T>();
        for (final T endPoint : residualGraph)
            mutableResidualGraph.addEndPoint(endPoint);
        for (final T endPoint1 : residualGraph)
            for (final T endPoint2 : residualGraph.getConnectedEndPoints(endPoint1))
                mutableResidualGraph.addEdge(endPoint1, endPoint2);
        return mutableResidualGraph;
    }

    private <T> UndirectedGraph<T> copyGraph(final MutableUndirectedGraph<T> graph) {
        final UndirectedGraph.Builder<T> residualGraphBuilder = new UndirectedGraph.Builder<T>(graph.getOrder(),
                UndirectedGraph.SUPERVISER_MODE);
        final Set<WeightedEdge<T>> edges = Sets.newHashSet();
        for (final T endPoint1 : graph)
            for (final T endPoint2 : graph)
                if (!endPoint1.equals(endPoint2)) { // TODO contains(u, v, w)
                    final WeightedEdge<T> edge = WeightedEdge.from(endPoint1, endPoint2, 1);
                    if (!edges.contains(edges))
                        edges.add(edge);
                }
        final List<WeightedEdge<T>> sortedEdges = Lists.newArrayList(edges);
        Collections.sort(sortedEdges);
        for (final WeightedEdge<T> weightedEdge : sortedEdges)
            residualGraphBuilder.addEdge(weightedEdge);
        return residualGraphBuilder.build();
    }

    // TODO ? pouvoir donner un traversal by edge en option
    @Override
    public <T> Matches<T> from(final UndirectedGraph<T> residualGraph) {
        final MutableUndirectedGraph<T> mutableResidualGraph = this.copyGraph(residualGraph);
        return this.bestMatching(residualGraph, mutableResidualGraph,
                new Matches<T>(new HashMap<T, T>(), Double.POSITIVE_INFINITY), 0);
    }

    public <T> void enumeration(final UndirectedGraph<T> residualGraph, final int i) {
        System.out.println(i);
        final MutableUndirectedGraph<T> mutableResidualGraph = this.copyGraph(residualGraph);
        MutableUndirectedGraph<T> maximumMatching;
        maximumMatching = EdmondsAlgorithm.maximumMatching(mutableResidualGraph);
        if (!isPerfect(maximumMatching))
            return;
        final MutableUndirectedGraph<T> mutableUndirectedGraph = new MutableUndirectedGraph<T>(
                mutableResidualGraph);
        final T node = maximumMatching.iterator().next();
        mutableUndirectedGraph.removeEdge(node, maximumMatching.getEndPoints(node).iterator().next());
        final UndirectedGraph<T> nextResidualGraph = this.copyGraph(mutableUndirectedGraph);
        this.enumeration(nextResidualGraph, i + 1);
    }

    private <T> Matches<T> _bestMatching( // TODO  revoir...
            final UndirectedGraph<T> residualGraph, final MutableUndirectedGraph<T> mutableResidualGraph,
            Matches<T> bestMatch, final int level) {

        //System.out.println(level);

        final MutableUndirectedGraph<T> maximumMatching = EdmondsAlgorithm.maximumMatching(mutableResidualGraph);

        if (!isPerfect(maximumMatching))
            return bestMatch;

        /*
        System.out.println();
        System.out.println("Perfect Matching");
        for (final T t : maximumMatching) {
        System.out.println(t + " - " + maximumMatching.getEndPoints(t).iterator().next());
        }
        System.out.println();
        */

        final Map<T, T> matching = buildMatchingMap(maximumMatching);

        System.out.println();
        System.out.println("Perfect Matching");
        for (final Entry<T, T> entry : matching.entrySet()) {
            System.out.println(entry);
        }
        System.out.println();

        //final double cost = computeCost(residualGraph, matching);
        //System.out.println(cost);
        final double cost = computeCost(eulerize((UndirectedGraph<T>) this.originalGraph, matching));

        //System.err.println(cost + " |" + bestMatch.getCost());
        if (Double.compare(cost, bestMatch.getCost()) == -1)
            bestMatch = new Matches<T>(matching, cost);

        for (final Entry<T, T> entry : matching.entrySet()) {
            final MutableUndirectedGraph<T> nextMutableResidualGraph = new MutableUndirectedGraph<T>(
                    mutableResidualGraph);
            nextMutableResidualGraph.removeEdge(entry.getKey(), entry.getValue());
            bestMatch = this.bestMatching(residualGraph, nextMutableResidualGraph, bestMatch, level + 1);
        }

        /*
        final MutableUndirectedGraph<T> nextMutableResidualGraph = new MutableUndirectedGraph<T>(mutableResidualGraph);
        for (final Entry<T, T> entry : matching.entrySet()) {
        nextMutableResidualGraph.removeEdge(entry.getKey(), entry.getValue());
        }
        bestMatch = this.bestMatching(residualGraph, nextMutableResidualGraph, bestMatch, level + 1);
        */

        /*
        System.out.println("ok");
        final MutableUndirectedGraph<T> nextMutableResidualGraph = new MutableUndirectedGraph<T>(mutableResidualGraph);
        for (final Entry<T, T> entry : matching.entrySet())
        nextMutableResidualGraph.removeEdge(entry.getKey(), entry.getValue());
        bestMatch = this.bestMatching(residualGraph, nextMutableResidualGraph, bestMatch, level + 1);
        */

        return bestMatch;
    }

    private <T> Matches<T> bestMatching(final UndirectedGraph<T> residualGraph,
            final MutableUndirectedGraph<T> mutableResidualGraph, Matches<T> bestMatch, final int level) {

        final MutableUndirectedGraph<T> maximumMatching = EdmondsAlgorithm.maximumMatching(mutableResidualGraph);
        if (!isPerfect(maximumMatching))
            return bestMatch;
        final Map<T, T> matching = buildMatchingMap(maximumMatching);
        //final double cost = computeCost(residualGraph, matching);
        final double cost = computeCost(eulerize((UndirectedGraph<T>) this.originalGraph, matching));
        if (Double.compare(cost, bestMatch.getCost()) == -1)
            bestMatch = new Matches<T>(matching, cost);
        final MutableUndirectedGraph<T> nextMutableResidualGraph = new MutableUndirectedGraph<T>(
                mutableResidualGraph);
        for (final Entry<T, T> entry : matching.entrySet()) {
            //final MutableUndirectedGraph<T> nextMutableResidualGraph = new MutableUndirectedGraph<T>(mutableResidualGraph);
            nextMutableResidualGraph.removeEdge(entry.getKey(), entry.getValue());
            //bestMatch = this.bestMatching(residualGraph, nextMutableResidualGraph, bestMatch, level + 1);
        }
        bestMatch = this.bestMatching(residualGraph, nextMutableResidualGraph, bestMatch, level + 1);
        return bestMatch;
    }

    @Override
    public <T> void setOriginalGraph(final UndirectedGraph<T> graph) {
        this.originalGraph = graph;
    }
}