Author: simonetripodi
Date: Tue Jul  5 15:19:02 2011
New Revision: 1143097

URL: http://svn.apache.org/viewvc?rev=1143097&view=rev
Log:
fixed Prim's algorithm implementation + TestCase

Added:
    
commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/ShortestEdges.java
   (with props)
    commons/sandbox/graph/trunk/src/test/java/org/apache/commons/graph/spanning/
    
commons/sandbox/graph/trunk/src/test/java/org/apache/commons/graph/spanning/PrimTestCase.java
   (with props)
Modified:
    
commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/Prim.java

Modified: 
commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/Prim.java
URL: 
http://svn.apache.org/viewvc/commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/Prim.java?rev=1143097&r1=1143096&r2=1143097&view=diff
==============================================================================
--- 
commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/Prim.java
 (original)
+++ 
commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/Prim.java
 Tue Jul  5 15:19:02 2011
@@ -23,11 +23,11 @@ import java.util.HashSet;
 import java.util.PriorityQueue;
 import java.util.Set;
 
-import org.apache.commons.graph.DirectedGraph;
+import org.apache.commons.graph.SpanningTree;
+import org.apache.commons.graph.UndirectedGraph;
 import org.apache.commons.graph.Vertex;
 import org.apache.commons.graph.WeightedEdge;
 import org.apache.commons.graph.WeightedGraph;
-import org.apache.commons.graph.shared.ShortestDistances;
 
 /**
  * Prim's algorithm is a greedy algorithm that finds a minimum spanning tree 
for a connected weighted undirected graph.
@@ -43,47 +43,39 @@ public final class Prim
      * @param graph the Graph for which minimum spanning tree (or forest) has 
to be calculated.
      * @return  the minimum spanning tree (or forest) of the input Graph.
      */
-    public static <V extends Vertex, WE extends WeightedEdge> WeightedGraph<V, 
WE> minimumSpanningTree( WeightedGraph<V, WE> graph,
-                                                                               
                         V source )
+    public static <V extends Vertex, WE extends WeightedEdge, G extends 
WeightedGraph<V, WE> & UndirectedGraph<V, WE>> SpanningTree<V, WE> 
minimumSpanningTree( G graph,
+                                                                               
                                                                                
 V source )
     {
-        final ShortestDistances<V> shortestDistances = new 
ShortestDistances<V>();
-        shortestDistances.setWeight( source, 0D );
+        final ShortestEdges<V, WE> shortesEdges = new ShortestEdges<V, WE>( 
graph, source );
 
-        final PriorityQueue<V> unsettledNodes = new PriorityQueue<V>( 
graph.getOrder(), shortestDistances );
+        final PriorityQueue<V> unsettledNodes = new PriorityQueue<V>( 
graph.getOrder(), shortesEdges );
         unsettledNodes.offer( source );
 
-        final Set<V> settledNodes = new HashSet<V>();
+        final Set<WE> settledEdges = new HashSet<WE>();
 
         // extract the node with the shortest distance
         while ( !unsettledNodes.isEmpty() )
         {
             V vertex = unsettledNodes.poll();
 
-            @SuppressWarnings( "unchecked" ) // Vertex/Edge type driven by 
input class
-            Iterable<V> connectedVertices = ( graph instanceof DirectedGraph )
-                                            ? ( ( DirectedGraph<V, WE> ) graph 
).getOutbound( vertex )
-                                            : graph.getConnectedVertices( 
vertex );
-
-            for ( V v : connectedVertices )
+            for ( V v : graph.getConnectedVertices( vertex ) )
             {
-                // skip node already settled
-                if ( !settledNodes.contains( v ) )
-                {
-                    WE edge = graph.getEdge( vertex, v );
+                WE edge = graph.getEdge( vertex, v );
 
-                    if ( edge.getWeight().compareTo( 
shortestDistances.getWeight( v ) ) < 0 )
+                // if the edge has not been already visited and its weight is 
less then the current Vertex weight
+                if ( settledEdges.add( edge ) && edge.getWeight().compareTo( 
shortesEdges.getWeight( v ) ) < 0 )
+                {
+                    if ( !unsettledNodes.contains( v ) )
                     {
-                        // assign new shortest distance and mark unsettled
-                        shortestDistances.setWeight( v, edge.getWeight() );
                         unsettledNodes.offer( v );
-
-                        // TODO assign predecessor in shortest path
                     }
+
+                    shortesEdges.addPredecessor( v, edge );
                 }
             }
         }
 
-        return null;
+        return shortesEdges.createSpanningTree();
     }
 
 }

Added: 
commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/ShortestEdges.java
URL: 
http://svn.apache.org/viewvc/commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/ShortestEdges.java?rev=1143097&view=auto
==============================================================================
--- 
commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/ShortestEdges.java
 (added)
+++ 
commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/ShortestEdges.java
 Tue Jul  5 15:19:02 2011
@@ -0,0 +1,157 @@
+package org.apache.commons.graph.spanning;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.graph.Edge;
+import org.apache.commons.graph.Graph;
+import org.apache.commons.graph.GraphException;
+import org.apache.commons.graph.SpanningTree;
+import org.apache.commons.graph.Vertex;
+import org.apache.commons.graph.VertexPair;
+import org.apache.commons.graph.WeightedEdge;
+import org.apache.commons.graph.model.MutableSpanningTree;
+
+/**
+ * The predecessor list is a list of {@link Vertex} of a {@link 
org.apache.commons.graph.Graph}.
+ * Each {@link Vertex}' entry contains the index of its predecessor in a path 
through the graph.
+ *
+ * @param <V> the Graph vertices type
+ * @param <E> the Graph edges type
+ */
+final class ShortestEdges<V extends Vertex, WE extends WeightedEdge>
+    implements Comparator<V>
+{
+
+    private final Map<V, WE> predecessors = new HashMap<V, WE>();
+
+    private final Graph<V, WE> graph;
+
+    private final V source;
+
+    public ShortestEdges(Graph<V, WE> graph, V source )
+    {
+        this.graph = graph;
+        this.source = source;
+    }
+
+    /**
+     * Add an {@link Edge} in the predecessor list associated to the input 
{@link Vertex}.
+     *
+     * @param tail the predecessor vertex
+     * @param head the edge that succeeds to the input vertex
+     */
+    public void addPredecessor( V tail, WE head )
+    {
+        predecessors.put( tail, head );
+    }
+
+    /**
+     * 
+     *
+     * @return
+     */
+    public SpanningTree<V, WE> createSpanningTree()
+    {
+        MutableSpanningTree<V, WE> spanningTree = new MutableSpanningTree<V, 
WE>();
+
+        for ( WE edge : this.predecessors.values() )
+        {
+            VertexPair<V> vertices = graph.getVertices( edge );
+
+            V head = vertices.getHead();
+            V tail = vertices.getTail();
+
+            addEdgeIgnoringExceptions( head, spanningTree );
+            addEdgeIgnoringExceptions( tail, spanningTree );
+
+            spanningTree.addEdge( head, graph.getEdge( head, tail ), tail );
+        }
+
+        return spanningTree;
+    }
+
+    private static <V extends Vertex, WE extends WeightedEdge> void 
addEdgeIgnoringExceptions( V vertex,
+                                                                               
                MutableSpanningTree<V, WE> spanningTree )
+    {
+        try
+        {
+            spanningTree.addVertex( vertex );
+        }
+        catch ( GraphException e )
+        {
+            // just swallow it
+        }
+    }
+
+    /**
+     * Checks the predecessor list has no elements.
+     *
+     * @return true, if the predecessor list has no elements, false otherwise.
+     */
+    public boolean isEmpty()
+    {
+        return predecessors.isEmpty();
+    }
+
+    /**
+     * Returns the distance related to input vertex, or {@code INFINITY} if it 
wasn't previously visited.
+     *
+     * @param vertex the vertex for which the distance has to be retrieved
+     * @return the distance related to input vertex, or {@code INFINITY} if it 
wasn't previously visited.
+     */
+    public Double getWeight( V vertex )
+    {
+        if ( source.equals( vertex ) )
+        {
+            return 0D;
+        }
+
+        WE edge = predecessors.get( vertex );
+
+        if ( edge == null )
+        {
+            return Double.POSITIVE_INFINITY;
+        }
+
+        return edge.getWeight();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int compare( V left, V right )
+    {
+        return getWeight( left ).compareTo( getWeight( right ) );
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString()
+    {
+        return predecessors.toString();
+    }
+
+}

Propchange: 
commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/ShortestEdges.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/ShortestEdges.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: 
commons/sandbox/graph/trunk/src/main/java/org/apache/commons/graph/spanning/ShortestEdges.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
commons/sandbox/graph/trunk/src/test/java/org/apache/commons/graph/spanning/PrimTestCase.java
URL: 
http://svn.apache.org/viewvc/commons/sandbox/graph/trunk/src/test/java/org/apache/commons/graph/spanning/PrimTestCase.java?rev=1143097&view=auto
==============================================================================
--- 
commons/sandbox/graph/trunk/src/test/java/org/apache/commons/graph/spanning/PrimTestCase.java
 (added)
+++ 
commons/sandbox/graph/trunk/src/test/java/org/apache/commons/graph/spanning/PrimTestCase.java
 Tue Jul  5 15:19:02 2011
@@ -0,0 +1,104 @@
+package org.apache.commons.graph.spanning;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import static junit.framework.Assert.assertEquals;
+import static org.apache.commons.graph.spanning.Prim.minimumSpanningTree;
+
+import org.apache.commons.graph.SpanningTree;
+import org.apache.commons.graph.model.BaseLabeledVertex;
+import org.apache.commons.graph.model.BaseLabeledWeightedEdge;
+import org.apache.commons.graph.model.MutableSpanningTree;
+import org.apache.commons.graph.model.UndirectedMutableWeightedGraph;
+import org.junit.Test;
+
+public final class PrimTestCase
+{
+
+    /**
+     * Test Graph and Prim's solution can be seen on these
+     * <a 
href="http://gauguin.info.uniroma2.it/~italiano/Teaching/Algoritmi/Lezioni/cap12.pdf";>slides</a>
+     */
+    @Test
+    public void verifyMinimumSpanningTree2()
+    {
+        UndirectedMutableWeightedGraph<BaseLabeledVertex, 
BaseLabeledWeightedEdge> input
+            = new UndirectedMutableWeightedGraph<BaseLabeledVertex, 
BaseLabeledWeightedEdge>();
+
+        BaseLabeledVertex a = new BaseLabeledVertex( "a" );
+        BaseLabeledVertex b = new BaseLabeledVertex( "b" );
+        BaseLabeledVertex c = new BaseLabeledVertex( "c" );
+        BaseLabeledVertex d = new BaseLabeledVertex( "d" );
+        BaseLabeledVertex e = new BaseLabeledVertex( "e" );
+        BaseLabeledVertex f = new BaseLabeledVertex( "f" );
+        BaseLabeledVertex g = new BaseLabeledVertex( "g" );
+
+        input.addVertex( a );
+        input.addVertex( b );
+        input.addVertex( c );
+        input.addVertex( d );
+        input.addVertex( e );
+        input.addVertex( f );
+        input.addVertex( g );
+
+        input.addEdge( a, new BaseLabeledWeightedEdge( "a <-> b", 7D ), b );
+        input.addEdge( a, new BaseLabeledWeightedEdge( "a <-> c", 14D ), c );
+        input.addEdge( a, new BaseLabeledWeightedEdge( "a <-> d", 30D ), d );
+
+        input.addEdge( b, new BaseLabeledWeightedEdge( "b <-> c", 21D ), c );
+
+        input.addEdge( c, new BaseLabeledWeightedEdge( "c <-> d", 10D ), d );
+        input.addEdge( c, new BaseLabeledWeightedEdge( "c <-> e", 1D ), e );
+
+        input.addEdge( e, new BaseLabeledWeightedEdge( "e <-> f", 6D ), f );
+        input.addEdge( e, new BaseLabeledWeightedEdge( "e <-> g", 9D ), g );
+
+        input.addEdge( f, new BaseLabeledWeightedEdge( "f <-> g", 4D ), g );
+
+        // expected
+
+        MutableSpanningTree<BaseLabeledVertex, BaseLabeledWeightedEdge> 
expected =
+            new MutableSpanningTree<BaseLabeledVertex, 
BaseLabeledWeightedEdge>();
+
+        for ( BaseLabeledVertex vertex : input.getVertices() )
+        {
+            expected.addVertex( vertex );
+        }
+
+        expected.addEdge( a, new BaseLabeledWeightedEdge( "a <-> b", 7D ), b );
+        expected.addEdge( a, new BaseLabeledWeightedEdge( "a <-> c", 14D ), c 
);
+
+        expected.addEdge( c, new BaseLabeledWeightedEdge( "c <-> d", 10D ), d 
);
+        expected.addEdge( c, new BaseLabeledWeightedEdge( "c <-> e", 1D ), e );
+
+        expected.addEdge( e, new BaseLabeledWeightedEdge( "e <-> f", 6D ), f );
+
+        expected.addEdge( f, new BaseLabeledWeightedEdge( "f <-> g", 4D ), g );
+
+        // actual
+
+        SpanningTree<BaseLabeledVertex, BaseLabeledWeightedEdge> actual = 
minimumSpanningTree( input, a );
+
+        // assert!
+
+        assertEquals( expected, actual );
+    }
+
+}

Propchange: 
commons/sandbox/graph/trunk/src/test/java/org/apache/commons/graph/spanning/PrimTestCase.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
commons/sandbox/graph/trunk/src/test/java/org/apache/commons/graph/spanning/PrimTestCase.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: 
commons/sandbox/graph/trunk/src/test/java/org/apache/commons/graph/spanning/PrimTestCase.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain


Reply via email to