001/* A mirror transformer for graphs. 002 003 Copyright (c) 2003-2014 The University of Maryland. All rights reserved. 004 Permission is hereby granted, without written agreement and without 005 license or royalty fees, to use, copy, modify, and distribute this 006 software and its documentation for any purpose, provided that the above 007 copyright notice and the following two paragraphs appear in all copies 008 of this software. 009 010 IN NO EVENT SHALL THE UNIVERSITY OF MARYLAND BE LIABLE TO ANY PARTY 011 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 012 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 013 THE UNIVERSITY OF MARYLAND HAS BEEN ADVISED OF THE POSSIBILITY OF 014 SUCH DAMAGE. 015 016 THE UNIVERSITY OF MARYLAND SPECIFICALLY DISCLAIMS ANY WARRANTIES, 017 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 018 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 019 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 020 MARYLAND HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 021 ENHANCEMENTS, OR MODIFICATIONS. 022 023 024 */ 025package ptolemy.graph.analysis.strategy; 026 027import java.util.ArrayList; 028import java.util.Collection; 029import java.util.HashSet; 030import java.util.Iterator; 031 032import ptolemy.graph.Edge; 033import ptolemy.graph.Graph; 034import ptolemy.graph.Node; 035import ptolemy.graph.analysis.analyzer.ClusterNodesTransformer; 036 037/////////////////////////////////////////////////////////////////// 038//// ClusterNodesTransformerStrategy 039 040/** 041 Strategy for cluster transformers for graphs. The nodes of a graph given 042 in a collection are being removed (clustered) and all of them are replaced 043 by a single node called super node. 044 <p> 045 046 @see ptolemy.graph.analysis.ClusterNodesAnalysis 047 @since Ptolemy II 4.0 048 @Pt.ProposedRating Red (shahrooz) 049 @Pt.AcceptedRating Red (ssb) 050 @author Shahrooz Shahparnia based on a method by Ming Yung Ko. 051 @version $Id$ 052 */ 053public class ClusterNodesTransformerStrategy extends CachedStrategy 054 implements ClusterNodesTransformer { 055 /** Construct a clusterer for a given graph. 056 * @param graph The given graph. 057 * @param nodeCollection The collection of nodes to be clustered. 058 * @param superNode The super node that replaces the clustered nodes. 059 */ 060 public ClusterNodesTransformerStrategy(Graph graph, 061 Collection nodeCollection, Node superNode) { 062 super(graph); 063 _nodeCollection = nodeCollection; 064 _superNode = superNode; 065 } 066 067 /////////////////////////////////////////////////////////////////// 068 //// public methods //// 069 070 /** Return the clustered Graph. 071 * 072 * @return Return the clustered Graph. 073 */ 074 @Override 075 public Graph clusterNodes() { 076 return (Graph) _result(); 077 } 078 079 /** Specify if this transformation has a mapping from the transformed 080 * version to the original version or not. This implementation does not. 081 * 082 * @return True If the implementation of the transformer supports backward 083 * mapping. 084 */ 085 @Override 086 public boolean hasBackwardMapping() { 087 return false; 088 } 089 090 /** Specify if this transformation has a mapping from the original 091 * version to the transformed version or not. This implementation does not. 092 * 093 * @return True If the implementation of the transformer supports forward 094 * mapping. 095 */ 096 @Override 097 public boolean hasForwardMapping() { 098 return false; 099 } 100 101 /** Unsupported operation. 102 * 103 * @exception UnsupportedOperationException If this method is called 104 * in any case. 105 */ 106 @Override 107 public Object originalVersionOf(Object dummy) { 108 throw new UnsupportedOperationException(); 109 } 110 111 /** Unsupported operation. 112 * 113 * @exception UnsupportedOperationException If this method is called 114 * in any case. 115 */ 116 @Override 117 public Object transformedVersionOf(Object dummy) { 118 throw new UnsupportedOperationException(); 119 } 120 121 /** Always valid. 122 * 123 * @return True always. 124 */ 125 @Override 126 public boolean valid() { 127 return true; 128 } 129 130 /////////////////////////////////////////////////////////////////// 131 //// protected methods //// 132 133 /** The computation associated with this strategy. 134 * 135 * @return The mirror graph as an {@link Object}. 136 */ 137 @Override 138 protected Object _compute() { 139 // When removing nodes and edges, we have to be careful about 140 // concurrent modification problems with the associated iterators. 141 Graph graph = graph(); 142 Graph subgraph = graph.subgraph(_nodeCollection); 143 graph.addNode(_superNode); 144 145 HashSet nodesToRemove = new HashSet(_nodeCollection); 146 147 // Remove all edges that are inside the induced subgraph. 148 Iterator edges = graph.edges().iterator(); 149 ArrayList removeList = new ArrayList(); 150 151 while (edges.hasNext()) { 152 Edge edge = (Edge) edges.next(); 153 154 if (nodesToRemove.contains(edge.source()) 155 && nodesToRemove.contains(edge.sink())) { 156 removeList.add(edge); 157 } 158 } 159 160 Iterator edgesToRemove = removeList.iterator(); 161 162 while (edgesToRemove.hasNext()) { 163 graph.removeEdge((Edge) edgesToRemove.next()); 164 } 165 166 // For each edge that connects a node Z outside the induced subgraph 167 // to a node inside the subgraph, replace the edge that connects 168 // Z to the super node. 169 removeList.clear(); 170 171 ArrayList addList = new ArrayList(); 172 edges = graph.edges().iterator(); 173 174 while (edges.hasNext()) { 175 Edge edge = (Edge) edges.next(); 176 Edge newEdge = null; 177 178 if (nodesToRemove.contains(edge.source())) { 179 if (edge.hasWeight()) { 180 newEdge = new Edge(_superNode, edge.sink(), 181 edge.getWeight()); 182 } else { 183 newEdge = new Edge(_superNode, edge.sink()); 184 } 185 } else if (nodesToRemove.contains(edge.sink())) { 186 if (edge.hasWeight()) { 187 newEdge = new Edge(edge.source(), _superNode, 188 edge.getWeight()); 189 } else { 190 newEdge = new Edge(edge.source(), _superNode); 191 } 192 } 193 194 if (newEdge != null) { 195 removeList.add(edge); 196 addList.add(newEdge); 197 } 198 } 199 200 // Add edges for super nodes. 201 Iterator edgesToAdd = addList.iterator(); 202 203 while (edgesToAdd.hasNext()) { 204 graph.addEdge((Edge) edgesToAdd.next()); 205 } 206 207 // Remove old edges connecting members outside the subgraph to members 208 // of N. 209 edgesToRemove = removeList.iterator(); 210 211 while (edgesToRemove.hasNext()) { 212 graph.removeEdge((Edge) edgesToRemove.next()); 213 } 214 215 // Remove the nodes in the specified collection. 216 Iterator nodes = _nodeCollection.iterator(); 217 218 while (nodes.hasNext()) { 219 graph.removeNode((Node) nodes.next()); 220 } 221 222 // Return the subgraph that was induced by the collection of nodes. 223 return subgraph; 224 } 225 226 /////////////////////////////////////////////////////////////////// 227 //// private variables //// 228 private Node _superNode; 229 230 private Collection _nodeCollection; 231}