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}