001    /*
002     *  www.ti.bfh.ch
003     *
004     *  Copyright 2007, Berne University of Applied Sciences, 
005     *  School of Engineering and Information Technology
006     *  and individual contributors as indicated by the @authors tag.
007     *
008     *  This is free software; you can redistribute it and/or modify it under the terms of the 
009     *  GNU Lesser General Public License as published by the Free Software Foundation; 
010     *  either version 3 of the License, or (at your option) any later version.
011     *
012     *  This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
013     *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
014     *  See the GNU Lesser General Public License for more details.
015     *
016     *  You should have received a copy of the GNU Lesser General Public License along with this software; 
017     *  if not, see <http://www.gnu.org/licenses/>.
018     *
019     */
020    package ch.bfh.algo.example;
021    import java.util.HashMap;
022    import java.util.List;
023    import java.util.Map;
024    import java.util.Random;
025    
026    import ch.bfh.algo.Direction;
027    import ch.bfh.algo.Graph;
028    import ch.bfh.algo.Position;
029    import ch.bfh.algo.Sequence;
030    import ch.bfh.algo.graph.DefaultGraph;
031    import ch.bfh.algo.graph.DefaultGraphFactory;
032    import ch.bfh.algo.graph.Vertex;
033    import ch.bfh.algo.sequence.LinkedSequence;
034    
035    
036    /**
037     * The class <code>GraphStress</code> contains Stess Tests for the Graph 
038     *
039     * @author <a href="mailto:">Emmanuel Benoist</a>
040     * @version 1.0
041     */
042    public class GraphStress{
043        final static int MAX_NUMBER_OF_VERTICES = 9000;
044        final static int VERTICES_STEP = 3000;
045        final static int MAX_NUMBER_OF_EDGES = 30000; 
046        final static int EDGES_STEP = 10000;
047      
048    
049    
050            private class DecoratedVertex extends Vertex<Integer,String>{
051    
052                // We add two properties to this vertex,
053                //
054                // First we have the visited boolean which indicates if this node
055                // has already been inserted in the buffer.
056                boolean visited;
057    
058                // The second property is a return property to indicate to which
059                // connected component the vertex belong to.
060                int connectedComponentNumber;
061    
062                /**
063                 * Get the Visited value.
064                 * @return the Visited value.
065                 */
066                public boolean isVisited() {
067                    return visited;
068                }
069    
070                /**
071                 * Set the Visited value.
072                 * @param newVisited The new Visited value.
073                 */
074                public void setVisited(boolean newVisited) {
075                    this.visited = newVisited;
076                }
077    
078                /**
079                 * Get the ConnectedComponentNumber value.
080                 * @return the ConnectedComponentNumber value.
081                 */
082                public int getConnectedComponentNumber() {
083                    return connectedComponentNumber;
084                }
085    
086                /**
087                 * Set the ConnectedComponentNumber value.
088                 * @param newConnectedComponentNumber The new ConnectedComponentNumber value.
089                 */
090                public void setConnectedComponentNumber(int newConnectedComponentNumber) {
091                    this.connectedComponentNumber = newConnectedComponentNumber;
092                }
093    
094                public String toString(){
095                    return element().toString()+"("+connectedComponentNumber+")";
096                    
097                }
098                
099            }
100    
101            private class DecoratedGraphFactory extends DefaultGraphFactory<Integer,String>{
102                    
103                public Vertex<Integer,String> createVertex(){
104                    return new DecoratedVertex();
105                }
106                    
107                public Vertex<Integer,String> castVertex(Position<?> p){
108                    return (Vertex<Integer,String>) p;
109                }
110            }
111    
112    
113            private class GraphCopier{
114    
115                Map<Position<String>,Position<String>> vertices;
116    
117    
118                /**
119                 * Creates a new <code>GraphCopier</code> instance.
120                 *
121                 */
122                public GraphCopier(){
123                    vertices = new HashMap<Position<String>,Position<String>>();
124                }
125    
126                /**
127                 * Get the MappingVertices value.
128                 * @return the MappingVertices value.
129                 */
130                public Map<Position<String>,Position<String>> getVertices() {
131                    return vertices;
132                }
133    
134                /**
135                 * Set the MappingVertices value.
136                 * @param newVertices The new MappingVertices value.
137                 */
138                public void setVertices(Map<Position<String>,Position<String>> newMappingVertices) {
139                    this.vertices = newMappingVertices;
140                }
141    
142    
143                public Graph<Integer,String> copy(Graph<Integer,String> g){
144                    //Graph<E,V> gRes = new DefaultGraph<Integer,String>(g.factory());
145                    Graph<Integer,String> gRes = new DefaultGraph<Integer,String>(new DecoratedGraphFactory());
146                    for(Position<String> v : g.vertices()){
147                        if(v!=null){
148                            vertices.put(v , gRes.insertVertex(v.element()));
149                        }
150                    }
151                    for(Position<Integer> e : g.edges(Direction.DIRECTED)){
152                        Position<String> origin ,destination;
153                        origin = g.origin(e);
154                        destination = g.destination(e);
155                        Position<Integer> edge = gRes.insertEdge(e.element());
156                        gRes.setOrigin(edge,vertices.get(origin));
157                        gRes.setDestination(edge,vertices.get(destination));
158                        gRes.setDirected(edge);
159                    }
160                    return gRes;
161                }
162                
163                public List<Position<String>> reverseList(List<Position<String>> lVertices){
164                    Sequence<Position<String>> seq = new LinkedSequence<Position<String>>();
165                    for(Position<String> vertexG1 : lVertices){
166                        Position<String> vertexG2 = vertices.get(vertexG1);
167                        //seq.insertFirst(vertexG2);
168                        if(seq.isEmpty()){
169                            seq.add(vertexG2);
170                        }
171                        else{
172                            seq.insertBefore(seq.first(),vertexG2);
173                            //seq.insertAfter(seq.last(),vertexG2);
174                        }
175                    }
176                    return seq;
177                }
178    
179    
180            }
181    
182    
183    
184    
185        /**
186         * The <code>dfsTraversal</code> is an example of the possible
187         * implementation of a Depth First Search traversal of a
188         * <code>Graph</code>. In this case, we use the
189         * <code>DecoratedVertex</code> to store inside each vertex if it
190         * has been visited.
191         *
192         * @return a <code>Sequence</code> value
193         */
194        public static Sequence<DecoratedVertex> dfsTraversal(Graph<Integer,String> g, List<Position<String>> vertices){
195            Sequence<DecoratedVertex> buffer = new LinkedSequence<DecoratedVertex>();
196            Sequence<DecoratedVertex> result = new LinkedSequence<DecoratedVertex>();
197    
198            // ccNumber represents the number of the current Connected Component.
199            int ccNumber = 0;
200            for(Position<String> v1 : vertices){
201                DecoratedVertex v = (DecoratedVertex) v1;
202                if(!v.isVisited()){
203                            ccNumber++;
204                            buffer.add(v);
205                            v.setVisited(true);
206                            while(! buffer.isEmpty()){
207                                v = buffer.last().element();
208                                buffer.delete(buffer.last());
209                                result.add(v);
210                                v.setConnectedComponentNumber(ccNumber);
211                                for(Position<String> v2 : g.adjacentVertices(v,Direction.OUT)){
212                                            DecoratedVertex vv = (DecoratedVertex) v2;
213                                            if(vv !=null && !vv.isVisited() ){
214                                                vv.setVisited(true);
215                                                buffer.add(vv);
216                                            }
217                                }
218                            }
219                } 
220            }
221            return result;
222        }
223    
224    
225        public static void reverseAllEdges(Graph<Integer,String> g){
226            for(Position<Integer> e : g.edges(Direction.DIRECTED)){
227                g.reverse(e);
228            }
229        }
230    
231        /**
232         * The <code>constructDirectedGraph</code> method is used to
233         * initialize a default directed <code>Graph</code>.
234         *
235         * The returned graph contains <code>numberOfVertices</code> vertices and
236         * <code>numberOfEdges</code> directed edges.
237         *
238         * @return a <code>Graph</code> value
239         */
240        public Graph<Integer,String> constructDirectedGraph(int numberOfVertices,
241                                                            int numberOfEdges){
242        boolean directed=true;
243            Graph<Integer,String> g = 
244                new DefaultGraph<Integer,String>(new DecoratedGraphFactory(),directed);
245    
246            // Array containing all the vertices
247            Position<String>[] vertices = new Position[numberOfVertices];
248    
249            for(int i=0;i < numberOfVertices;i++){
250                vertices[i]= g.insertVertex(""+i);
251            }
252            
253            Random generator = new Random();
254            for(int j=0; j < numberOfEdges;j++){
255                Position<String> v1, v2;
256                int i1 = generator.nextInt(numberOfVertices);
257                int i2= generator.nextInt(numberOfVertices);
258    //          while(i1==i2) i2=generator.nextInt(numberOfVertices);
259                v1=vertices[i1];
260                v2=vertices[i2];
261                g.insertEdge(0,v1,v2);
262            }
263    
264            return g;
265        }
266    
267    
268        public void run(){
269                    for(int numbOfVertices = VERTICES_STEP; numbOfVertices <= MAX_NUMBER_OF_VERTICES; numbOfVertices +=VERTICES_STEP){
270                        for(int numbOfEdges = EDGES_STEP; numbOfEdges <=MAX_NUMBER_OF_EDGES; numbOfEdges +=EDGES_STEP){
271                                    try{
272                                            double[] t=new double[3];
273                                            t[0]=System.currentTimeMillis();
274                                            Graph<Integer,String> g = constructDirectedGraph( numbOfVertices,numbOfEdges);
275                                            t[1]=System.currentTimeMillis();
276                                            Sequence<DecoratedVertex> dfs = dfsTraversal(g,g.vertices());
277                                            t[2]=System.currentTimeMillis();
278                                            System.out.println("Vertices="+numbOfVertices+", \tEdges="+numbOfEdges+
279                                                                                    ", \tInit="+(t[1]-t[0])/1000+"s, \tDFS="+(t[2]-t[1])/1000+"s"+
280                                                                                    ", \tComponents=" + dfs.last().element().getConnectedComponentNumber());
281                                    }
282                                    catch(Exception e){
283                                            System.out.println("!!! Exception at Vertices="+numbOfVertices+", Edges="+numbOfEdges);
284                                            break;
285                                    }
286                        }
287                    }
288        }
289    
290    
291        public static void main(String[] args){
292            System.out.println("***************");
293            System.out.println("Stress Test.");
294            System.out.println("We generate random graphs with up to "+MAX_NUMBER_OF_VERTICES+" Vertices and "+MAX_NUMBER_OF_EDGES+" Edges");
295            System.out.println("incrementing the number of vertices and edges. Visiting each vertex by DFS:");
296            new GraphStress().run();
297            System.out.println("***************");
298            System.out.println("");
299    
300        }
301    
302    
303    }