001    // GraphLab Project: http://graphlab.sharif.edu
002    // Copyright (C) 2008 Mathematical Science Department of Sharif University of Technology
003    // Distributed under the terms of the GNU Lesser General Public License (LGPL): http://www.gnu.org/licenses/
004    
005    /*
006     * MatrixGraph.java
007     *
008     * Created on November 13, 2004, 8:32 PM
009     * Last Modify on November 15, 2004, 05:03 AM
010     */
011    
012    package graphlab.library;
013    
014    
015    import Jama.Matrix;
016    import graphlab.library.event.handlers.PreWorkHandler;
017    import graphlab.library.event.handlers.PreWorkPostWorkHandler;
018    import graphlab.library.exceptions.InvalidEdgeException;
019    import graphlab.library.exceptions.InvalidGraphException;
020    import graphlab.library.exceptions.InvalidVertexException;
021    import graphlab.library.genericcloners.EdgeVertexCopier;
022    import graphlab.library.genericcloners.GraphConverter;
023    
024    import java.util.ArrayList;
025    import java.util.Iterator;
026    
027    
028    /**
029     * Adjacency Matrix Graph.
030     * For information about Adjacency Matrix refer to http://en.wikipedia.org/wiki/Adjacency_matrix * @author Omid Aladini
031     *
032     * @author Omid Aladini
033     * @param <VertexType> Type of the vertices the graph can work with.
034     * @param <EdgeType> Type of the edges the graph can work with.
035     */
036    public class MatrixGraph<VertexType extends BaseVertex, EdgeType extends BaseEdge<VertexType>>
037            extends BaseGraph<VertexType, EdgeType> {
038        /**
039         * The data structure to store graph data, it looks like a three dimensional matrix with EdgeType elements.
040         * The third dimension is designed to store multiple edges between two vertices.
041         * ArrayLists can work with generic type's arameters and they are as fast as arrays for indexing, but
042         * they are not thread safe. So MatrixGraph operations are not thread-safe and should be synchronized
043         * externally.
044         */
045        private ArrayList<ArrayList<ArrayList<EdgeType>>> adjacencyMatrix;
046    
047        //list of vertices
048        private ArrayList<VertexType> vertices;
049    
050        //In-degree of vertices by order stored in <code>vertices</code> object.
051        //More clearly, the number of edges which their sources are connected to the vertex.
052        private ArrayList<Integer> inDegree;
053        //Out-degree of vertices by order stored in <code>vertices</code> object.
054        //More clearly, the number of edges which their targets are connected to the vertex.
055        private ArrayList<Integer> outDegree;
056    
057        //Specified whether the graph is directed.
058        private boolean directed;
059        private int edgeCount = 0;
060    
061        /**
062         * Constructs a graph object that stores graph data using adjacency matrix data structure.
063         *
064         * @param directed                 Indicated whether the graph is directed.
065         * @param expectedNumberOfVertices Approximate number of vertices that will be
066         *                                 added to the graph. This paramether is optional and is available for performance
067         *                                 reasons.
068         */
069        public MatrixGraph(boolean directed, int expectedNumberOfVertices) {
070            this.directed = directed;
071    
072            adjacencyMatrix = new ArrayList<ArrayList<ArrayList<EdgeType>>>(expectedNumberOfVertices);
073            for (int rowCount = 0; rowCount < expectedNumberOfVertices; rowCount++) {
074                ArrayList<ArrayList<EdgeType>> columns = new ArrayList<ArrayList<EdgeType>>(expectedNumberOfVertices);
075                adjacencyMatrix.add(columns);
076            }
077            vertices = new ArrayList<VertexType>(expectedNumberOfVertices);
078    
079            inDegree = new ArrayList<Integer>(expectedNumberOfVertices);
080    
081            if (!directed)
082                outDegree = inDegree;
083            else
084                outDegree = new ArrayList<Integer>(expectedNumberOfVertices);
085        }
086    
087        /**
088         * Constructs a MatrixGraph object
089         *
090         * @param directed Whether the graph is directed or undirected.
091         */
092        public MatrixGraph(boolean directed) {
093            this(directed, 5);
094        }
095    
096        /**
097         * Constructs an undirected graph object that stores graph data using
098         * adjacency list data structure.
099         */
100        public MatrixGraph() {
101            this(false, 5);
102        }
103    
104        /**
105         * Constructs a graph object that stores graph data using adjacency matrix data structure by importing
106         * graph data from a pre-existing graph. A GraphConvertor object is passed as a parameter which is
107         * reponsible for duplication/type-convertion of graph elements.
108         *
109         * @param <ImportVertexType> The type of vertex object which the input graph contain.
110         * @param <ImportEdgeType>   The type of edge object which the input graph contain.
111         * @param graph
112         * @param converter          A GraphConverter object which is responsible for duplicating/converting graph
113         *                           elements.
114         * @throws InvalidGraphException Throws when the input graph is an invalid graph object.
115         */
116        public <ImportVertexType extends BaseVertex,
117                ImportEdgeType extends BaseEdge<ImportVertexType>,
118                ImportGraphType extends BaseGraph<ImportVertexType, ImportEdgeType>
119                >
120        MatrixGraph(BaseGraph<ImportVertexType, ImportEdgeType> graph,
121                    GraphConverter<ImportVertexType,
122                            VertexType,
123                            ImportEdgeType,
124                            EdgeType,
125                            ImportGraphType,
126                            MatrixGraph<VertexType, EdgeType>> gc)
127                throws InvalidGraphException {
128            ArrayList<VertexType> tempAL = new ArrayList<VertexType>(getVerticesCount());
129    
130            for (ImportVertexType v : graph) {
131                insertVertex(gc.convert(v));
132                tempAL.add(gc.convert(v));
133            }
134    
135            Iterator<ImportEdgeType> iet = graph.edgeIterator();
136    
137            ImportEdgeType edge;
138            try {
139                while (iet.hasNext()) {
140                    edge = iet.next();
141                    insertEdge(gc.convert(edge, tempAL.get(edge.source.getId()), tempAL.get(edge.target.getId())));
142                }
143            } catch (InvalidVertexException e) {
144                throw new InvalidGraphException();
145            }
146        }
147    
148        /* (non-Javadoc)
149          * @see graphlab.library.BaseGraph#getVerticesCount()
150          */
151        @Override
152        public int getVerticesCount() {
153            return vertices.size();
154        }
155    
156        /**
157         * Checks if a vertex with internal id <i>id</i> exist.
158         *
159         * @param id Id of the vertex.
160         * @return true of exist false if not.
161         */
162        private boolean vertexIdOutOfRange(int id) {
163            return id < 0 || id >= vertices.size();
164    
165        }
166    
167        /**
168         * Returns the vertex with internal id <I>id</I>
169         *
170         * @param id Internal index of the vertex.
171         * @return Reference of the vertex object.
172         */
173        private VertexType getVertex(int id)
174                throws InvalidVertexException {
175            if (vertexIdOutOfRange(id))
176                throw new InvalidVertexException();
177    
178            return vertices.get(id);
179        }
180    
181        /**
182         * Lables the vertices using their internal Id property by the index they live inside the graph.
183         */
184        private void setVertexIds() {
185            try {
186                for (int i = 0; i < getVerticesCount(); i++)
187                    getVertex(i).setId(i);
188            } catch (InvalidVertexException e) {
189                System.out.println("NEVER-HAPPENS EXCEPTION");
190                e.printStackTrace();
191            }
192        }
193    
194    
195        /* (non-Javadoc)
196          * @see graphlab.library.BaseGraph#insertEdge(null)
197          */
198        @Override
199        public void insertEdge(EdgeType newEdge)
200                throws InvalidVertexException {
201            VertexType sourceObj, targetObj;
202            int source, target;
203    
204            sourceObj = newEdge.source;
205            targetObj = newEdge.target;
206            source = newEdge.source.getId();
207            target = newEdge.target.getId();
208    
209            checkVertex(sourceObj);
210            checkVertex(targetObj);
211    
212            ArrayList<EdgeType> edges;
213    
214            if (adjacencyMatrix.get(source).get(target) == null) {
215                edges = new ArrayList<EdgeType>(5);
216                adjacencyMatrix.get(source).set(target, edges);
217            } else {
218                edges = adjacencyMatrix.get(source).get(target);
219            }
220    
221            edges.add(newEdge);
222    
223            if (!directed)
224                adjacencyMatrix.get(target).set(source, edges);
225    
226            outDegree.set(source, inDegree.get(source) + 1);
227            inDegree.set(target, inDegree.get(target) + 1);
228    
229            if (!directed) {
230                inDegree.set(source, inDegree.get(source) + 1);
231                outDegree.set(target, inDegree.get(target) + 1);
232            }
233    
234            ++edgeCount;
235    
236        }
237    
238        /**
239         * Returns all edges between two vertices.
240         *
241         * @param source Index of the edges' start point.
242         * @param target Index of the edges' end point.
243         * @return An ArrayList of <I>EdgeType</I> containing all edges between <I>from</I> and <I>to</I>.
244         * @throws graphlab.library.exceptions.InvalidVertexException
245         *          Thrown when two supplied indexes of vertices are invalid.
246         */
247        private ArrayList<EdgeType> getEdges(int source, int target)
248                throws InvalidVertexException {
249            if (vertexIdOutOfRange(source) || vertexIdOutOfRange(target))
250                throw new InvalidVertexException();
251    
252            return adjacencyMatrix.get(source).get(target);
253        }
254    
255        /**
256         * Returns all edges between two vertices.
257         *
258         * @param from Index of the edges' start point.
259         * @param to   Index of the edges' end point.
260         * @return An ArrayList of <I>EdgeType</I> containing all edges between <I>from</I> and <I>to</I>.
261         * @throws graphlab.library.exceptions.InvalidVertexException
262         *          Thrown when two supplied indexes of vertices are invalid.
263         */
264        @Override
265        public ArrayList<EdgeType> getEdges(VertexType source, VertexType target)
266                throws InvalidVertexException {
267            int sourceId = source.getId();
268            int targetId = target.getId();
269    
270            checkVertex(target);
271            checkVertex(source);
272    
273            return adjacencyMatrix.get(sourceId).get(targetId);
274        }
275    
276        /* (non-Javadoc)
277        * @see graphlab.library.BaseGraph#insertVertex(null)
278        */
279        @Override
280        public void insertVertex(VertexType newVertex) {
281            vertices.add(newVertex);
282            int size = getVerticesCount();
283            newVertex.setId(size - 1);
284    
285            if (adjacencyMatrix.size() < size) {
286                adjacencyMatrix.ensureCapacity(size * 2);
287                adjacencyMatrix.add(new ArrayList<ArrayList<EdgeType>>());
288            }
289    
290            int newSize = adjacencyMatrix.size();
291            for (int row = 0; row < newSize; row++) {
292                if (row == newSize - 1) {
293                    for (int newSizeIndex = 0; newSizeIndex < newSize; newSizeIndex++) {
294                        adjacencyMatrix.get(row).add(null);
295                    }
296                } else {
297                    adjacencyMatrix.get(row).add(null);
298                }
299            }
300    
301            inDegree.add(0);
302            outDegree.add(0);
303    
304        }
305    
306        /**
307         * Runs Depth First Search (DFS) algorithm on the graph starting from vertex <I>vertexId</I>.
308         * A reference to a PreWorkPostWorkHandler is supplied that contains implementation
309         * of pre-work and post-work operations that depends on the application of DFS.
310         *
311         * @param vertex  Starting vertex of the traversal.
312         * @param handler A reference to a PreWorkPostWorkHandler that contains implementation
313         *                of pre-work and post-work operations that depends on the application of DFS.
314         * @return Whether the traversal has stopped at the middle by the handler.
315         * @throws InvalidVertexException
316         */
317    
318        public boolean depthFirstSearch(VertexType vertex, PreWorkPostWorkHandler<VertexType> handler) throws InvalidVertexException {
319            return new graphlab.library.algorithms.traversal.DepthFirstSearch<VertexType, EdgeType>(this)
320                    .doSearch(vertex, handler);
321        }
322    
323    
324        /**
325         * Runs Breadth First Search (BFS) algorithm on the graph starting from vertex <I>vertexId</I>.
326         * A reference to a PreWorkHandler is supplied that contains implementation
327         * of pre-work operation that depends on the application of BFS.
328         *
329         * @param vertex  Starting vertex of the traversal.
330         * @param handler A reference to a PreWorkHandler that contains implementation
331         *                of pre-work operation that depends on the application of DFS.
332         * @return Whether the traversal has stopped at the middle by the handler.
333         * @throws InvalidVertexException
334         */
335        public boolean breadthFirstSearch(VertexType vertex, PreWorkHandler<VertexType> handler) throws InvalidVertexException {
336            return new graphlab.library.algorithms.traversal.BreadthFirstSearch<VertexType, EdgeType>(this)
337                    .doSearch(vertex, handler);
338    
339        }
340    
341        /**
342         * Checks whether the current graph is a connected graph.
343         *
344         * @return True if graph is connected and false otherwise.
345         */
346        public boolean isGraphConnected() {
347            try {
348                return graphlab.library.algorithms.util.ConnectivityChecker.isGraphConnected(this);
349    
350            } catch (InvalidGraphException e) {
351                //Generally should not happen. So I don't bother the user by
352                //adding throws declaration.
353                e.printStackTrace();
354                return false;
355            }
356        }
357    
358        /**
359         * Checks whether the current graph is acyclic.
360         *
361         * @return True if graph is acyclic and false otherwise.
362         */
363        public boolean isGraphAcyclic() {
364            try {
365                //Soooo easy to use!
366                return graphlab.library.algorithms.util.AcyclicChecker.isGraphAcyclic(this);
367            } catch (InvalidGraphException e) {
368                //Generally should not happen. So I don't bother the user by
369                //adding throws declaration.
370                e.printStackTrace();
371                return false;
372            }
373        }
374    
375        /* (non-Javadoc)
376        * @see java.lang.Iterable#iterator()
377        */
378        @Override
379        public Iterator<VertexType> iterator() {
380            return vertices.iterator();
381        }
382    
383        /* (non-Javadoc)
384        * @see graphlab.library.BaseGraph#isDirected()
385        */
386        @Override
387        public boolean isDirected() {
388            return directed;
389        }
390    
391        /**
392         * Returns in-degree of vertex <I>vertexId</I>, the number of edges which
393         * their target goes to the specified vertex.
394         *
395         * @return in-degree of vertex <I>vertexId</I>.
396         * @throws InvalidVertexException
397         */
398        private int getInDegree(int vertexId) throws InvalidVertexException {
399            if (vertexIdOutOfRange(vertexId))
400                throw new InvalidVertexException();
401            return inDegree.get(vertexId);
402        }
403    
404        /**
405         * Returns out-degree of vertex <I>vertexId</I>, the number of edges which
406         * their tale is attached to the specified vertex.
407         *
408         * @return out-degree of vertex <I>vertexId</I>.
409         * @throws InvalidVertexException
410         */
411        private int getOutDegree(int vertexId) throws InvalidVertexException {
412            if (vertexIdOutOfRange(vertexId))
413                throw new InvalidVertexException();
414            return outDegree.get(vertexId);
415        }
416    
417        /**
418         * This class iterates all, edges coming from or going to a specified vertex.
419         * The order of edges the iterator iterate is undefined because of future code changes.
420         *
421         * @author Omid Aladini
422         */
423        private class EdgeIterator implements Iterator<EdgeType> {
424            private Iterator<EdgeType> edgesIterator;
425            private EdgeType lastEdge = null;
426    
427            /**
428             * Constructs an Edge Iterator object which iterates through all the edges in the graph.
429             * Note that if the graph object is changed during iteration, the iteration may not
430             * actually represent current state of the graph. For example, if you deleted an edge
431             * after construction of this object, the edge would be included in the iteration.
432             */
433            public EdgeIterator() {
434                ArrayList<EdgeType> edges = new ArrayList<EdgeType>();
435                if (directed) {
436                    for (ArrayList<ArrayList<EdgeType>> aae : adjacencyMatrix)
437                        for (ArrayList<EdgeType> ae : aae)
438                            for (EdgeType e : ae)
439                                edges.add(e);
440                } else {
441                    int iCount = 0;
442                    int jCount;
443                    for (ArrayList<ArrayList<EdgeType>> aae : adjacencyMatrix) {
444                        Iterator<ArrayList<EdgeType>> it = aae.iterator();
445                        jCount = 0;
446                        while (iCount >= jCount) {
447                            ++jCount;
448    
449                            ArrayList<EdgeType> ae = it.next();
450    
451                            if (ae == null)
452                                continue;
453    
454                            for (EdgeType e : ae)
455                                edges.add(e);
456                        }
457                        ++iCount;
458                    }
459                }
460                edgesIterator = edges.iterator();
461            }
462    
463    
464            /**
465             * Number of times edge Iteration is called. This will set as a temporary flag into
466             * edges in order to reduce running time of edge iteration back to O(n^2).
467             */
468            int edgeIterationIndex = 0;
469    
470            /**
471             * Constructs an Edge Iterator object which iterates through all the edges going to
472             * or coming from the specified vertex <code>v</code>.
473             * Note that if the graph object is changed during iteration, the iteration may not
474             * actually represent current state of the graph. For example, if you deleted an edge
475             * after construction of this object, the edge would be included in the iteration.
476             *
477             * @param v Source or target of desired edges.
478             */
479            private EdgeIterator(VertexType v)
480                    throws InvalidVertexException {
481                checkVertex(v);
482    
483                if (!directed)
484                    ++edgeIterationIndex;
485    
486                ArrayList<EdgeType> edges = new ArrayList<EdgeType>();
487    
488                ArrayList<ArrayList<EdgeType>> row = adjacencyMatrix.get(v.getId());
489    
490                for (ArrayList<EdgeType> ae : row)
491                    for (EdgeType e : ae) {
492                        edges.add(e);
493    
494                        if (!directed)
495                            e.edgeIterationIndex = edgeIterationIndex;
496                    }
497    
498                for (ArrayList<ArrayList<EdgeType>> aae : adjacencyMatrix) {
499                    if (row == aae)
500                        continue;
501                    for (ArrayList<EdgeType> ae : aae)
502                        for (EdgeType e : ae) {
503                            if (e.target == v) {
504                                if (directed) {
505                                    edges.add(e);
506                                } else if (e.edgeIterationIndex != edgeIterationIndex) {
507                                    e.edgeIterationIndex = edgeIterationIndex;
508                                    edges.add(e);
509                                }
510                            }
511                        }
512                }
513    
514                edgesIterator = edges.iterator();
515            }
516    
517            /**
518             * Constructs an Edge Iterator object which iterates through all the edges going to
519             * or coming from (depending on the second parameter) the specified vertex <code>v</code>.
520             * If the second parameter it true, then the first parameter is considered to be source of
521             * all desired edges, and if it's false the first parameter is considered to be target of desired edges.
522             * Note that if the graph object is changed during iteration, the iteration may not
523             * actually represent current state of the graph. For example, if you deleted an edge
524             * after construction of this object, the edge would be included in the iteration.
525             *
526             * @param v      If the second parameter is true indicated the vertex which is source of desired edges, otherwise
527             *               it is considered to be target of desired edges.
528             * @param source True means the first parameter should be considered source of desired edges.
529             */
530            public EdgeIterator(VertexType v, boolean source)
531                    throws InvalidVertexException {
532                checkVertex(v);
533    
534                if (!directed)
535                    ++edgeIterationIndex;
536    
537                ArrayList<EdgeType> edges = new ArrayList<EdgeType>();
538    
539                ArrayList<ArrayList<EdgeType>> row = adjacencyMatrix.get(v.getId());
540    
541                if (source) {
542                    for (ArrayList<EdgeType> ae : row)
543                        for (EdgeType e : ae) {
544                            edges.add(e);
545                            if (!directed)
546                                e.edgeIterationIndex = edgeIterationIndex;
547                        }
548                } else {
549                    for (ArrayList<ArrayList<EdgeType>> aae : adjacencyMatrix) {
550                        if (row == aae)
551                            continue;
552                        for (ArrayList<EdgeType> ae : aae)
553                            for (EdgeType e : ae) {
554                                if (e.target == v) {
555                                    if (directed) {
556                                        edges.add(e);
557                                    } else if (e.edgeIterationIndex != edgeIterationIndex) {
558                                        e.edgeIterationIndex = edgeIterationIndex;
559                                        edges.add(e);
560                                    }
561                                }
562                            }
563                    }
564                }
565                edgesIterator = edges.iterator();
566    
567            }
568    
569            public boolean hasNext() {
570                return edgesIterator.hasNext();
571            }
572    
573            public EdgeType next() {
574                lastEdge = edgesIterator.next();
575                return lastEdge;
576            }
577    
578            public void remove() {
579                try {
580                    removeEdge(lastEdge);
581                } catch (InvalidEdgeException e) {
582                    System.out.println("Invalid remove operation.");
583                    e.printStackTrace();
584                }
585            }
586    
587        }
588    
589        /**
590         * Returns iterator object for the edges.
591         *
592         * @return iterator object for the edges.
593         */
594        public Iterator<EdgeType> edgeIterator() {
595            return new EdgeIterator();
596    
597        }
598    
599        public Iterable<EdgeType> edges() {
600            return new Iterable<EdgeType>() {
601                public Iterator<EdgeType> iterator() {
602                    return edgeIterator();
603                }
604            };
605        }
606    
607        /* (non-Javadoc)
608          * @see graphlab.library.BaseGraph#edgeIterator(null)
609          */
610        @Override
611        public Iterator<EdgeType> edgeIterator(VertexType v)
612                throws InvalidVertexException {
613            return new EdgeIterator(v);
614        }
615    
616        /* (non-Javadoc)
617        * @see graphlab.library.BaseGraph#getAdjacencyMatrix()
618        */
619        @Override
620        public Matrix getAdjacencyMatrix() {
621            Matrix matrix = new Matrix(getVerticesCount(), getVerticesCount());
622            try {
623                if (directed) {
624                    for (int i = 0; i < getVerticesCount(); i++)
625                        for (int j = 0; j < getVerticesCount(); j++)
626                            if (getEdges(i, j) != null)
627                                matrix.set(i, j, getEdges(i, j).size());
628                } else {
629                    for (int i = 0; i < getVerticesCount(); i++)
630                        for (int j = 0; j <= i; j++)
631                            if (getEdges(i, j) != null) {
632                                matrix.set(i, j, getEdges(i, j).size());
633                                if (i != j)
634                                    matrix.set(j, i, getEdges(i, j).size());
635                            }
636                }
637            } catch (Exception e) {
638                //never happens
639                System.out.println("NEVER-HAPPENS-BUG:getAdjMatrix:");
640                e.printStackTrace();
641            }
642            return matrix;
643        }
644    
645        /* (non-Javadoc)
646        * @see graphlab.library.BaseGraph#dump()
647        */
648        @Override
649        public void dump() {
650            System.out.print('\n');
651            for (int i = 0; i < getVerticesCount(); i++) {
652                for (int j = 0; j < getVerticesCount(); j++) {
653                    System.out.print(" ");
654                    System.out.print(adjacencyMatrix.get(i).get(j) == null ? 0 : 1);
655                }
656                System.out.println("");
657            }
658        }
659    
660        /* (non-Javadoc)
661          * @see graphlab.library.BaseGraph#removeAllEdges(null, null)
662          */
663        @Override
664        public void removeAllEdges(VertexType source, VertexType target) throws InvalidVertexException {
665            if (vertexIdOutOfRange(source.getId()) || vertexIdOutOfRange(target.getId()) ||
666                    source != vertices.get(source.getId()) || target != vertices.get(target.getId()))
667                throw new InvalidVertexException();
668    
669            adjacencyMatrix.get(source.getId()).get(target.getId()).clear();
670    
671            if (!directed)
672                removeAllEdges(target, source);
673        }
674    
675        /**
676         * Removes a vertex and all it's connected edges.
677         *
678         * @param vertexId index of the vertex to be removed
679         */
680        private void removeVertex(int vertexId)
681                throws InvalidVertexException {
682            for (ArrayList<ArrayList<EdgeType>> c : adjacencyMatrix) {
683                c.remove(vertexId);
684            }
685            adjacencyMatrix.remove(vertexId);
686    
687            vertices.remove(vertexId);
688            inDegree.remove(vertexId);
689            outDegree.remove(vertexId);
690    
691            setVertexIds();
692        }
693    
694        /* (non-Javadoc)
695          * @see graphlab.library.BaseGraph#removeVertex(null)
696          */
697        @Override
698        public void removeVertex(VertexType v) throws InvalidVertexException {
699            checkVertex(v);
700            removeVertex(v.getId());
701        }
702    
703        /* (non-Javadoc)
704          * @see graphlab.library.BaseGraph#getInDegree(null)
705          */
706        @Override
707        public int getInDegree(VertexType v) throws InvalidVertexException {
708            checkVertex(v);
709            return getInDegree(v.getId());
710        }
711    
712        /* (non-Javadoc)
713          * @see graphlab.library.BaseGraph#getOutDegree(null)
714          */
715        @Override
716        public int getOutDegree(VertexType v) throws InvalidVertexException {
717            checkVertex(v);
718            return getOutDegree(v.getId());
719        }
720    
721        /* (non-Javadoc)
722          * @see graphlab.library.BaseGraph#removeEdge(null)
723          */
724        @Override
725        public void removeEdge(EdgeType edge)
726                throws InvalidEdgeException {
727            int source = edge.source.getId();
728            int target = edge.target.getId();
729    
730            try {
731                checkVertex(edge.target);
732                checkVertex(edge.source);
733            } catch (InvalidVertexException e) {
734                throw new InvalidEdgeException();
735            }
736    
737            adjacencyMatrix.get(target).get(source).remove(edge);
738    
739            if (!directed)
740                adjacencyMatrix.get(source).get(target).remove(edge);
741    
742            --edgeCount;
743        }
744    
745        public VertexType getAVertex() {
746            Iterator<VertexType> it = iterator();
747            if (it.hasNext())
748                return it.next();
749            else
750                return null;
751        }
752    
753        /* (non-Javadoc)
754          * @see graphlab.library.BaseGraph#copy(graphlab.library.GraphConverter)
755          */
756        @Override
757        public BaseGraph<VertexType, EdgeType>
758               copy(EdgeVertexCopier<VertexType, EdgeType> gc)
759                throws InvalidGraphException {
760            MatrixGraph<VertexType, EdgeType> oGraph = new MatrixGraph<VertexType, EdgeType>(directed, getVerticesCount());
761    
762            ArrayList<VertexType> tempAL = new ArrayList<VertexType>(getVerticesCount());
763    
764            VertexType tempVertex;
765            for (VertexType v : this) {
766                tempVertex = gc.convert(v);
767                oGraph.insertVertex(tempVertex);
768                tempAL.add(tempVertex);
769            }
770    
771            Iterator<EdgeType> iet = edgeIterator();
772    
773            EdgeType edge;
774            try {
775                while (iet.hasNext()) {
776                    edge = iet.next();
777                    oGraph.insertEdge(gc.convert(edge, tempAL.get(edge.source.getId()), tempAL.get(edge.target.getId())));
778                }
779            } catch (InvalidVertexException e) {
780                throw new InvalidGraphException();
781    
782            }
783    
784            return oGraph;
785        }
786    
787        /* (non-Javadoc)
788          * @see graphlab.library.BaseGraph#containsVertex(null)
789          */
790        @Override
791        public boolean containsVertex(VertexType v) {
792            return vertices.contains(v);
793        }
794    
795        /* (non-Javadoc)
796          * @see graphlab.library.BaseGraph#checkVertex(null)
797          */
798        @Override
799        public void checkVertex(VertexType v)
800                throws InvalidVertexException {
801            if (vertexIdOutOfRange(v.getId()) || v != vertices.get(v.getId()))
802                throw new InvalidVertexException();
803        }
804    
805        @Override
806        public boolean isEdge(VertexType source, VertexType target)
807                throws InvalidVertexException {
808            return (getEdges(source, target) != null) && (getEdges(source, target).size() != 0);
809        }
810    
811        @Override
812        public MatrixGraph<VertexType, EdgeType> createEmptyGraph() {
813            return new MatrixGraph<VertexType, EdgeType>(directed, 0);
814        }
815    
816        @Override
817        public void setDirected(boolean isDirected) {
818            //TODO: Stub
819            throw new RuntimeException("Not yet implemented.");
820        }
821    
822        /* (non-Javadoc)
823          * @see graphlab.library.BaseGraph#getVertexArray()
824          */
825        @Override
826        public BaseVertex[] getVertexArray() {
827            BaseVertex[] arr = new BaseVertex[getVerticesCount()];
828    
829            for (VertexType v : this)
830                arr[v.getId()] = v;
831    
832            return arr;
833        }
834    
835        /* (non-Javadoc)
836          * @see graphlab.library.BaseGraph#getEdgeArray()
837          */
838        @Override
839        public int[][] getEdgeArray() {
840            int[][] arr = new int[getVerticesCount()][];
841    
842            int i = 0;
843            int j;
844            int k;
845    
846            for (ArrayList<ArrayList<EdgeType>> ll : adjacencyMatrix) {
847                j = 0;
848    
849                ArrayList<Integer> temp = new ArrayList<Integer>();
850    
851                for (ArrayList<EdgeType> alet : ll) {
852                    if (alet != null && alet.size() != 0)
853                        temp.add(j++);
854                }
855    
856                arr[i] = new int[temp.size()];
857    
858                k = 0;
859                for (Integer vertexId : temp)
860                    arr[i][k++] = vertexId;
861    
862                ++i;
863            }
864            return arr;
865        }
866    
867        /* (non-Javadoc)
868          * @see graphlab.library.BaseGraph#lightEdgeIterator()
869          */
870        @Override
871        public Iterator<EdgeType> lightEdgeIterator() {
872            //TODO: Stub, not yet light.
873            return edgeIterator();
874        }
875    
876        /* (non-Javadoc)
877          * @see graphlab.library.BaseGraph#lightEdgeIterator(null)
878          */
879        @Override
880        public Iterator<EdgeType> lightEdgeIterator(VertexType v) throws InvalidVertexException {
881            //TODO: Stub, not yet light.
882            return edgeIterator(v);
883        }
884    
885        /* (non-Javadoc)
886          * @see graphlab.library.BaseGraph#clear()
887          */
888        @Override
889        public void clear() {
890            int expectedNumberOfVertices = 0;
891            adjacencyMatrix = new ArrayList<ArrayList<ArrayList<EdgeType>>>(expectedNumberOfVertices);
892            for (int rowCount = 0; rowCount < expectedNumberOfVertices; rowCount++) {
893                ArrayList<ArrayList<EdgeType>> columns = new ArrayList<ArrayList<EdgeType>>(expectedNumberOfVertices);
894                adjacencyMatrix.add(columns);
895            }
896            vertices = new ArrayList<VertexType>(expectedNumberOfVertices);
897    
898            inDegree = new ArrayList<Integer>(expectedNumberOfVertices);
899    
900            if (!directed)
901                outDegree = inDegree;
902            else
903                outDegree = new ArrayList<Integer>(expectedNumberOfVertices);
904    
905            edgeCount = 0;
906        }
907    
908        @Override
909        public int getEdgesCount() {
910            return edgeCount;
911        }
912    }
913