Java tutorial
/* * 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 graph.features.cpp; import graph.UndirectedGraph; import graph.UndirectedGraph.Builder; import graph.WeightedEdge; import graph.features.degree.DegreeFeature; import graph.features.degree.DegreeInterface; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import matching.MatchingAlgorithmInterface; import com.google.common.base.Preconditions; import com.google.common.base.Stopwatch; import com.google.common.base.Supplier; import com.google.common.collect.Maps; // TODO vrifier que le graphe est connect final class OpenCPP<T> implements OpenCPPInterface<T> { //public final static MatchingAlgorithmInterface DEFAULT_MATCHING_ALGORITHM = ClosedCPP.DEFAULT_MATCHING_ALGORITHM; public final static MatchingAlgorithmInterface DEFAULT_MATCHING_ALGORITHM = new matching.edmonds1.Matching(); // TODO private static class Box<T> { private final T data; public T getData() { return this.data; } private final int hashcode; @Override public int hashCode() { return this.hashcode; } public Box(final T data) { this.data = data; this.hashcode = data == null ? -1 : this.data.hashCode(); } @Override public boolean equals(final Object object) { if (object == null) return false; if (object == this) return true; if (!(object instanceof Box)) return false; final Box<?> that = (Box<?>) object; if (this.getData() != null) return this.getData().equals(that.getData()); else return that.getData() == null; } @Override public String toString() { return this.data == null ? "NULL" : this.data.toString(); } } private final UndirectedGraph<T> graph; public UndirectedGraph<T> getGraph() { return this.graph; } public ClosedCPPSolution<T> getClosedCPPSolution() { if (this.closedCPPSolution == null) { final ClosedCPPInterface<T> closedCPPInterface = this.getGraph().fetch(ClosedCPPFeature.class).up(); //this.closedCPPSolution = ClosedCPP.from(this.getGraph(), this.matchingAlgorithm).solve(); //TODO this.closedCPPSolution = closedCPPInterface.solve(); // TODO !! inutile } return this.closedCPPSolution; } private UndirectedGraph<Box<T>> boxedGraph; private final MatchingAlgorithmInterface matchingAlgorithm; private ClosedCPPSolution<T> closedCPPSolution; // TODO !! virer: pouvoir obtenir un LowerBound du graphe public static <T> OpenCPP<T> from(final UndirectedGraph<T> graph, final MatchingAlgorithmInterface matchingAlgorithm) { Preconditions.checkArgument(graph != null); Preconditions.checkArgument(matchingAlgorithm != null); return new OpenCPP<T>(graph, matchingAlgorithm); } public static <T> OpenCPP<T> from(final Supplier<UndirectedGraph<T>> graphSupplier, final MatchingAlgorithmInterface matchingAlgorithm) { Preconditions.checkArgument(graphSupplier != null); Preconditions.checkArgument(matchingAlgorithm != null); return OpenCPP.from(graphSupplier.get(), matchingAlgorithm); } public static <T> OpenCPP<T> from(final UndirectedGraph<T> graph) { //return OpenCPP.from(graph, ClosedCPP.DEFAULT_MATCHING_ALGORITHM); // TODO return OpenCPP.from(graph, DEFAULT_MATCHING_ALGORITHM); } public static <T> OpenCPP<T> from(final Supplier<UndirectedGraph<T>> graphSupplier) { //return OpenCPP.from(graphSupplier, ClosedCPP.DEFAULT_MATCHING_ALGORITHM); // TODO return OpenCPP.from(graphSupplier, DEFAULT_MATCHING_ALGORITHM); // TODO } public static <T> OpenCPP<T> from(final ClosedCPPSolution<T> closedCPPSolution) { Preconditions.checkArgument(closedCPPSolution != null); return new OpenCPP<T>(closedCPPSolution); } private UndirectedGraph<Box<T>> getBoxedGraph() { if (this.boxedGraph == null) { final Builder<Box<T>> builder = new UndirectedGraph.Builder<Box<T>>(this.getGraph().getOrder(), UndirectedGraph.SUPERVISER_MODE); for (final T MazeNode : this.getGraph()) { final Set<WeightedEdge<T>> edges = this.getGraph().getEdgesFrom(MazeNode); for (final WeightedEdge<T> weightedEdge : edges) { final WeightedEdge<Box<T>> edge = WeightedEdge.from(new Box<T>(weightedEdge.getEndPoint1()), new Box<T>(weightedEdge.getEndPoint2()), weightedEdge.getWeight()); if (!builder.contains(edge)) builder.addEdge(edge); } } this.boxedGraph = builder.build(); } return this.boxedGraph; } private OpenCPP(final UndirectedGraph<T> graph, final MatchingAlgorithmInterface matchingAlgorithm) { this.graph = graph; this.matchingAlgorithm = matchingAlgorithm; } public OpenCPP(final ClosedCPPSolution<T> closedCPPSolution) { this(closedCPPSolution.getGraph(), closedCPPSolution.getMatchingAlgorithm()); this.closedCPPSolution = closedCPPSolution; } @Override public Double getLowerBoundCost() { return this.getClosedCPPSolution().getLowerBoundCost(); } // TODO optimisation possible private UndirectedGraph<Box<T>> buildVirtualGraph(final UndirectedGraph<Box<T>> boxedGraph, final T startingMazeNode, final T oddVertice) { final Builder<Box<T>> builder = new UndirectedGraph.Builder<Box<T>>(boxedGraph.getOrder() + 1, UndirectedGraph.SUPERVISER_MODE); for (final Box<T> MazeNode : boxedGraph) { final Set<WeightedEdge<Box<T>>> edges = boxedGraph.getEdgesFrom(MazeNode); for (final WeightedEdge<Box<T>> edge : edges) if (!builder.contains(edge)) builder.addEdge(edge); } final WeightedEdge<Box<T>> virtualEdge1 = WeightedEdge.from(new Box<T>(null), new Box<T>(startingMazeNode), this.getLowerBoundCost()); builder.addEdge(virtualEdge1); final DegreeInterface<T> degreeInterface = boxedGraph.fetch(DegreeFeature.class).up();// TODO ? utiliser le graph original if (!degreeInterface.isEulerian()) { final WeightedEdge<Box<T>> virtualEdge2 = WeightedEdge.from(new Box<T>(oddVertice), new Box<T>(null), this.getLowerBoundCost()); if (!builder.contains(virtualEdge2)) builder.addEdge(virtualEdge2); } return builder.build(); } @Override public OpenCPPSolution<T> solveFrom(final T startingMazeNode) { Preconditions.checkArgument(startingMazeNode != null); Preconditions.checkState(this.getGraph().hasEndPoint(startingMazeNode)); final OpenCPPSolution<Box<T>> bestSolution = this.bestSolution(this.getBoxedGraph(), startingMazeNode); final Map<WeightedEdge<T>, Integer> traversalByEdge = Maps.newHashMap(); final Map<WeightedEdge<Box<T>>, Integer> boxedTraversalByEdge = bestSolution.getTraversalByEdge(); //System.out.println(bestSolution); for (final Entry<WeightedEdge<Box<T>>, Integer> entry : boxedTraversalByEdge.entrySet()) { final WeightedEdge<Box<T>> edge = entry.getKey(); final T data1 = edge.getEndPoint1().getData(); final T data2 = edge.getEndPoint2().getData(); if (data1 == null || data2 == null) continue; traversalByEdge.put(this.getGraph().getEdge(data1, data2), entry.getValue()); } final OpenCPPSolution<T> unboxedSolution = new OpenCPPSolution<T>(bestSolution.getEndPoint().getData(), this.getGraph(), traversalByEdge, this.getLowerBoundCost(), this.getLowerBoundCost() + (bestSolution.getUpperBoundCost() - bestSolution.getLowerBoundCost())); return unboxedSolution; } // TODO vrifier qu'il suffit d'itrer sur les noeuds de degr impair private OpenCPPSolution<Box<T>> bestSolution(final UndirectedGraph<Box<T>> boxedGraph, final T startingMazeNode) { OpenCPPSolution<Box<T>> bestSolution = new OpenCPPSolution<Box<T>>(null, null, null, null, 2 * this.getLowerBoundCost() * 2); final Stopwatch stopwatch = new Stopwatch(); final DegreeInterface<T> degreeInterface = this.getGraph().fetch(DegreeFeature.class).up(); //final int i = 0; for (final T oddVertice : degreeInterface.getNodesWithOddDegree().keySet()) { stopwatch.start(); final UndirectedGraph<Box<T>> virtualGraph = this.buildVirtualGraph(boxedGraph, startingMazeNode, oddVertice); //final ClosedCPP<Box<T>> cppSolver = ClosedCPP.from(virtualGraph); final ClosedCPPInterface<Box<T>> closedCPPInterface = virtualGraph.fetch(ClosedCPPFeature.class).up(); final ClosedCPPSolution<Box<T>> cppSolution = closedCPPInterface.solve(); if (cppSolution.getUpperBoundCost() < bestSolution.getUpperBoundCost()) { bestSolution = new OpenCPPSolution<Box<T>>(new Box<T>(oddVertice), virtualGraph, cppSolution.getTraversalByEdge(), cppSolution.getLowerBoundCost(), cppSolution.getUpperBoundCost()); } /* System.out.println(); System.out.println(++i + "/" + this.oddVertices.size() + " : " + stopwatch.elapsedTime(TimeUnit.MILLISECONDS) + " " + TimeUnit.MILLISECONDS); System.out.println(oddVertice + " -> " + cppSolver.getUpperBoundCost() + "$"); System.out.println(); */ stopwatch.reset(); } return bestSolution; } }