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 General Public License (GPL): http://www.gnu.org/licenses/
004    
005    package graphlab.plugins.main.core;
006    
007    import graphlab.graph.graph.GraphPoint;
008    import graphlab.graph.graph.VertexModel;
009    import graphlab.library.BaseEdge;
010    import graphlab.library.BaseGraph;
011    import graphlab.library.BaseVertex;
012    import graphlab.library.Path;
013    import graphlab.library.algorithms.util.LibraryUtils;
014    
015    import java.awt.geom.Point2D;
016    import java.awt.geom.Rectangle2D;
017    import java.util.ArrayList;
018    import java.util.Collection;
019    import java.util.Iterator;
020    import java.util.Vector;
021    
022    /**
023     * Just some methods helping you to write Graph Algorithms easier,
024     *
025     * @see graphlab.library.algorithms.util.LibraryUtils
026     */
027    public class AlgorithmUtils {
028        public final static int Max_Int = 2100000000;
029    
030    
031        /**
032         * sets all vertex colors to 0.
033         */
034        public static void resetVertexColors(BaseGraph<BaseVertex, BaseEdge<BaseVertex>> g) {
035            for (BaseVertex v : g) {
036                v.setColor(0);
037            }
038        }
039    
040        /**
041         * sets all vertex marks to false
042         */
043        public static void resetVertexMarks(BaseGraph<BaseVertex, BaseEdge<BaseVertex>> g) {
044            for (BaseVertex v : g) {
045                v.setMark(false);
046            }
047        }
048    
049        /**
050         * determines wether g is connected or not
051         */
052        public static <VertexType extends BaseVertex, EdgeType extends BaseEdge<VertexType>>
053        boolean isConnected(BaseGraph<VertexType, EdgeType> g) {
054            ArrayList vs = new ArrayList();
055            int[] parent = new int[g.getVerticesCount()];
056            dfs(g, 0, vs, parent);
057            return vs.size() == g.getVerticesCount();
058        }
059    
060        /**
061         * determines wether g is complete or not
062         */
063        public static <VertexType extends BaseVertex, EdgeType extends BaseEdge<VertexType>>
064        boolean isCompleteGraph(BaseGraph<VertexType, EdgeType> g) {
065            int size = g.getVerticesCount();
066            for (int i : getDegreesList(g))
067                if (i != size - 1)
068                    return false;
069            return true;
070        }
071    
072        /**
073         * returns the adjacency list of g.
074         *
075         * @deprecated use BaseGraph.getEdgeArray instead
076         */
077        public static <VertexType extends BaseVertex, EdgeType extends BaseEdge<VertexType>>
078        ArrayList<ArrayList<Integer>> getAdjList(BaseGraph<VertexType, EdgeType> g) {
079            double[][] mat = g.getAdjacencyMatrix().getArray();
080            ArrayList<ArrayList<Integer>> alist = new ArrayList();
081            int vCount = mat.length;
082            for (int i = 0; i < vCount; i++) {
083                ArrayList<Integer> adjacencyList = new ArrayList();
084                for (int j = 0; j < vCount; j++)
085                    if (mat[i][j] == 1)
086                        adjacencyList.add(j);
087                alist.add(adjacencyList);
088            }
089            return alist;
090        }
091    
092        /**
093         * returns the degree of the node with the id
094         * @deprecated
095    
096          * @see graphlab.library.BaseGraph#getDegree(graphlab.library.BaseVertex)
097         */
098        public static <VertexType extends BaseVertex, EdgeType extends BaseEdge<VertexType>>
099        int getDegree(BaseGraph<VertexType, EdgeType> bg, int node) {
100            int result = 0;
101            double[][] mat = bg.getAdjacencyMatrix().getArray();
102            int vCount = mat.length;
103            if (node > vCount)
104                return -1;
105            for (int i = 0; i < vCount; i++)
106                if (mat[node][i] == 1)
107                    result++;
108    
109            return result;
110    
111        }
112    
113        /**
114         * returns all neighbors of the given vertex
115         * @deprecated
116         * @see graphlab.library.BaseGraph#getNeighbors(graphlab.library.BaseVertex)
117         */
118        public static <VertexType extends BaseVertex, EdgeType extends BaseEdge<VertexType>>
119        ArrayList<VertexType> getNeighbors(BaseGraph<VertexType, EdgeType> g, VertexType source) {
120            ArrayList<VertexType> ret = new ArrayList<VertexType>();
121            Iterator<EdgeType> ie = g.edgeIterator(source);
122            while (ie.hasNext()) {
123                EdgeType e = ie.next();
124                if (e.target == source && !ret.contains(e.source))
125                    ret.add(e.source);
126                if (e.source == source && !ret.contains(e.target))
127                    ret.add(e.target);
128            }
129            return ret;
130        }
131    
132        /**
133         * returns all neighbors of the given vertex
134         * @deprecated
135         * @see graphlab.library.BaseGraph#getNeighbors(graphlab.library.BaseVertex)
136         */
137        public static <VertexType extends BaseVertex, EdgeType extends BaseEdge<VertexType>>
138        ArrayList<VertexType> getNeighbors2(BaseGraph<VertexType, EdgeType> g, VertexType source) {
139            ArrayList<VertexType> ret = new ArrayList<VertexType>();
140            Iterator<EdgeType> ie = g.edgeIterator(source);
141            while (ie.hasNext()) {
142                EdgeType e = ie.next();
143    //            if (e.target == source && !ret.contains(e.source))
144    //                ret.add(e.source);
145                if (e.source == source && !ret.contains(e.target))
146                    ret.add(e.target);
147            }
148            return ret;
149        }
150    
151        /**
152         * returns a path from source to target
153         * path.get(0) = dest
154         */
155        public static <VertexType extends BaseVertex, EdgeType extends BaseEdge<VertexType>>
156        Path<VertexType> getPath(BaseGraph<VertexType, EdgeType> g, VertexType source, VertexType dest) {
157            boolean vertexMarksBackup[] = LibraryUtils.getVertexMarks(g);
158            clearVertexMarks(g);
159            Vector<VertexType> q = new Vector<VertexType>();
160            q.add(source);
161            source.setMark(true);
162    
163            BaseVertex[] parents = new BaseVertex[g.getVerticesCount()];
164            boolean found = false;
165            while (!q.isEmpty() && !found) {
166                VertexType v = q.remove(0);
167    
168                for (VertexType _ : getNeighbors(g, v)) {
169                    if (_ == dest) {
170                        found = true;
171    //                    break;
172                    }
173                    if (!_.getMark()) {
174                        q.add(_);
175                        _.setMark(true);
176                        parents[_.getId()] = v;
177                    }
178                }
179            }
180    
181            if (!found) {
182                return null;
183            }
184    
185            //extract the path
186            Path<VertexType> ret = new Path<VertexType>();
187    
188            int _ = dest.getId();
189            ret.insert(dest);
190            while (_ != source.getId()) {
191    //            System.out.println("_=" + _);
192    
193                ret.insert((VertexType) parents[_]);
194                if (parents[_] == null)
195                    return null;
196                _ = parents[_].getId();
197            }
198            LibraryUtils.setVertexMarks(g, vertexMarksBackup);
199            return ret;
200        }
201    
202        /**
203         * returns the parent of v, if ve DFS on parent
204         */
205        public static <VertexType extends BaseVertex, EdgeType extends BaseEdge<VertexType>>
206        VertexType getParent(BaseGraph<VertexType, EdgeType> g, VertexType treeRoot, VertexType v) {
207            return getPath(g, treeRoot, v).get(1);
208        }
209    
210        /**
211         * clears all vertex marks
212         */
213        public static <VertexType extends BaseVertex, EdgeType extends BaseEdge<VertexType>>
214        void clearVertexMarks(BaseGraph<VertexType, EdgeType> g) {
215            for (VertexType _ : g) {
216                _.setMark(false);
217            }
218        }
219    
220        /**
221         * returns the subtree rooted by subTreeRoot in the rooted tree tree with the root treeRoot
222         * the vertices are ordered by their distances to subTreeRoot
223         * the exact distance is placed in v.getProp().obj as an Integer, starting distance is 0 which is subTreeRoot
224         */
225        public static <Vertex extends BaseVertex, Edge extends BaseEdge<Vertex>>
226        ArrayList<Vertex> getSubTree(BaseGraph<Vertex, Edge> tree, Vertex treeRoot, Vertex subTreeRoot) {
227            boolean vertexMarksBackup[] = LibraryUtils.getVertexMarks(tree);
228            Path<Vertex> pathToRoot = getPath(tree, treeRoot, subTreeRoot);
229    
230            clearVertexMarks(tree);
231    
232    //close the path to tree root
233            for (Vertex _ : pathToRoot) {
234                _.setMark(true);
235            }
236            ArrayList<Vertex> ret = BFS(tree, subTreeRoot, null);
237            LibraryUtils.setVertexMarks(tree, vertexMarksBackup);
238    
239            return ret;
240    
241        }
242    
243        /**
244         * gets the vertices in the order of AlgorithmUtils.getSubTree()
245         */
246        public static <Vertex extends BaseVertex, Edge extends BaseEdge<Vertex>>
247        ArrayList<Vertex> BFSOrder(BaseGraph<Vertex, Edge> unRootedTree, Vertex treeRoot) {
248            boolean vertexMarksBackup[] = LibraryUtils.getVertexMarks(unRootedTree);
249            clearVertexMarks(unRootedTree);
250            ArrayList<Vertex> ret = BFS(unRootedTree, treeRoot, null);
251            LibraryUtils.setVertexMarks(unRootedTree, vertexMarksBackup);
252            return ret;
253        }
254    
255        /**
256         * runs a BFS on graph, starting the given vertex as the root
257         */
258        public static <Vertex extends BaseVertex, Edge extends BaseEdge<Vertex>>
259        void BFSrun(BaseGraph<Vertex, Edge> unRootedTree, Vertex treeRoot, BFSListener<Vertex> listener) {
260            boolean vertexMarksBackup[] = LibraryUtils.getVertexMarks(unRootedTree);
261            clearVertexMarks(unRootedTree);
262            BFS(unRootedTree, treeRoot, listener);
263            LibraryUtils.setVertexMarks(unRootedTree, vertexMarksBackup);
264        }
265    
266        /**
267         * performs a full BFS on graph, it selects the vertices with minimum degrees as the
268         * roots of the resulting forest
269         *
270         * @param unRootedTree
271         * @param listener
272         * @return
273         */
274        public static <Vertex extends BaseVertex, Edge extends BaseEdge<Vertex>>
275        void BFS(BaseGraph<Vertex, Edge> unRootedTree, BFSListener<Vertex> listener) {
276            boolean vertexMarksBackup[] = LibraryUtils.getVertexMarks(unRootedTree);
277            clearVertexMarks(unRootedTree);
278            for (Vertex v : unRootedTree) {
279                if (!v.getMark()) {
280                    BFS(unRootedTree, v, listener);
281                }
282            }
283            LibraryUtils.setVertexMarks(unRootedTree, vertexMarksBackup);
284        }
285    
286        /**
287         * performs a bfs on the given root,
288         * this method changes vertex marks, and also marked vertices will not be traversed
289         *
290         * @param unRootedTree
291         * @param treeRoot
292         * @param listener
293         * @return
294         */
295        public static <Vertex extends BaseVertex, Edge extends BaseEdge<Vertex>>
296        ArrayList<Vertex> BFS(BaseGraph<Vertex, Edge> unRootedTree, Vertex treeRoot, BFSListener<Vertex> listener) {
297            //do a bfs on the subTreeRoot
298            ArrayList<Vertex> q = new ArrayList<Vertex>();
299            ArrayList<Vertex> ret = new ArrayList<Vertex>();
300            q.add(treeRoot);
301            ret.add(treeRoot);
302            treeRoot.setMark(true);
303            treeRoot.getProp().obj = 0;
304            while (!q.isEmpty()) {
305                Vertex v = q.remove(0);
306                for (Vertex _ : getNeighbors(unRootedTree, v)) {
307                    if (!_.getMark()) {
308                        q.add(_);
309                        ret.add(_);
310                        _.setMark(true);
311                        _.getProp().obj = ((Integer) v.getProp().obj) + 1;  //set the distance
312                        if (listener != null)
313                            listener.visit(_, v);
314                    }
315                }
316            }
317            return ret;
318        }
319    
320    
321        /**
322         * runs a dfs and fills visit and parent, visit is the visiting order of vertices and parent[i] is the id of i'th vertex parent
323         */
324        public static <VertexType extends BaseVertex, EdgeType extends BaseEdge<VertexType>>
325        void dfs(BaseGraph<VertexType, EdgeType> g,
326                 int node, ArrayList visit, int parent[]) {
327            visit.add(node);
328            ArrayList e = getAdjList(g);
329            ArrayList neighbors = (ArrayList) e.get(node);
330            for (Object neighbor1 : neighbors) {
331                int neighbor = (Integer) neighbor1;
332                if (parent[neighbor] == -1) {
333                    parent[neighbor] = node;
334                    dfs(g, neighbor, visit, parent);
335                }
336            }
337        }
338    
339        /**
340         * retunrs the degree of vertex (indegree + outdegree)
341         */
342        public static int getTotalDegree(BaseGraph g, BaseVertex v) {
343            return g.getOutDegree(v) + g.getInDegree(v);
344        }
345    
346        /**
347         * returns the root which is assigned to each vertex
348         * it is the minimum id vertex in the corresponding component of vertex
349         */
350        public static <Vertex extends BaseVertex, Edge extends BaseEdge<Vertex>>
351        Vertex getRoot(BaseGraph<Vertex, Edge> g, Vertex v) {
352            ArrayList<Vertex> componentVertices = BFSOrder(g, v);
353            Vertex rootCandidate = v;
354    
355            for (Vertex _ : componentVertices) {
356                if (_.getId() < v.getId()) {
357                    rootCandidate = _;
358                }
359    
360            }
361    
362            return rootCandidate;
363    
364        }
365    
366        /**
367         * returns the angle between 3 vertices in graphical world!
368         */
369        public static double getAngle(VertexModel root, VertexModel v1, VertexModel v2) {
370    
371            GraphPoint rootp = root.getLocation();
372            GraphPoint v1p = v1.getLocation();
373            GraphPoint v2p = v2.getLocation();
374    
375            return getAngle(rootp, v1p, v2p);
376        }
377    
378        /**
379         * returns the angle between 3 points
380         */
381        public static double getAngle(GraphPoint rootp, GraphPoint v1p, GraphPoint v2p) {
382            double px = v1p.x - rootp.x;
383            double py = v1p.y - rootp.y;
384            double qx = v2p.x - rootp.x;
385            double qy = v2p.y - rootp.y;
386    
387    
388            double pDOTq = px * qx + py * qy;
389            double plength = getLength(px, py);
390            double qlength = getLength(qx, qy);
391    
392            double cartesianProd = py * qx - px * qy;
393            if (plength == 0 || qlength == 0)
394                return 0;
395            else {
396                double alfacos = pDOTq / (plength * qlength);
397                double alfa = Math.acos(alfacos);
398    //            return (Math.signum(cartesianProd) < 0 ? 2 * Math.PI - Math.acos(alfacos) : Math.acos(alfacos));
399                return alfa;
400            }
401        }
402    
403        /**
404         * returns the length of the given vector
405         */
406        public static double getLength(double dx, double dy) {
407            return Point2D.Double.distance(0, 0, dx, dy);
408        }
409    
410        /**
411         * moves the vertex relative to its current position
412         */
413        public static void move(VertexModel v, double dx, double dy) {
414            GraphPoint loc = v.getLocation();
415            v.setLocation(new GraphPoint(loc.x + dx, loc.y + dy));
416        }
417    
418        /**
419         * returns the distance between two vertices in pixels, (in graphics not the path length between them)
420         */
421        public static double getDistance(VertexModel v1, VertexModel v2) {
422            return GraphPoint.distance(v1.getLocation().x, v1.getLocation().y, v2.getLocation().x, v2.getLocation().y);
423    
424        }
425    
426        /**
427         * returns the distance between two points
428         */
429        public static double getDistance(GraphPoint p1, GraphPoint p2) {
430            return GraphPoint.distance(p1.x, p1.y, p2.x, p2.y);
431    
432        }
433    
434        /**
435         * @return the angle between vector p2-p1 and X-Axis
436         */
437        public static double getAngle(GraphPoint p1, GraphPoint p2) {
438            double angle = Math.atan2(p1.y - p2.y,
439                    p1.x - p2.x);
440            if (angle < 0) {
441                // atan2 returns getAngle in phase -pi to pi, which means
442                // we have to convert the answer into 0 to 2pi range.
443                angle += 2 * Math.PI;
444            }
445            return angle;
446        }
447    
448        /**
449         * locations v in a r-teta cordination
450         */
451        public static void setLocation(VertexModel v, GraphPoint center, double radius, double ang) {
452            v.setLocation(new GraphPoint(center.x + radius * Math.cos(ang), center.y + radius * Math.sin(ang)));
453        }
454    
455        /**
456         * @return the bounding rectangle arround vertices
457         */
458        public static Rectangle2D.Double getBoundingRegion(Collection<VertexModel> vertices) {
459            Rectangle2D.Double ret = new Rectangle2D.Double();
460            boolean first = true;
461            for (VertexModel v : vertices) {
462                GraphPoint p = v.getLocation();
463                if (first) {
464                    ret = new Rectangle2D.Double(p.x, p.y, 0, 0);
465                    first = false;
466                }
467                ret.add(p);
468            }
469            return ret;
470        }
471    
472        public static GraphPoint getCenter(Collection<VertexModel> V) {
473            GraphPoint center = new GraphPoint(0, 0);
474            for (VertexModel v : V) {
475                GraphPoint loc = v.getLocation();
476                center.x += loc.x;
477                center.y += loc.y;
478            }
479            center.x = center.x / V.size();
480            center.y = center.y / V.size();
481            return center;
482        }
483    
484        /**
485         * returns the vertex degrees as a list, sorted by vertex ids
486         */
487        public static <VertexType extends BaseVertex, EdgeType extends BaseEdge<VertexType>>
488        ArrayList<Integer> getDegreesList(BaseGraph<VertexType, EdgeType> g) {
489            ArrayList<Integer> result = new ArrayList<Integer>();
490            int vCount = g.getVertexArray().length;
491            for (int i = 0; i < vCount; i++)
492                result.add(getDegree(g, i));
493            return result;
494        }
495    
496        public interface BFSListener<Vertex extends BaseVertex> {
497            public void visit(Vertex v, Vertex parent);
498        }
499    
500        /**
501         * @param p1
502         * @param p2
503         * @return a point whose x and y are average of the given graph points.
504         */
505        public static GraphPoint getMiddlePoint(GraphPoint p1, GraphPoint p2) {
506            return new GraphPoint((p1.x + p2.x) / 2, (p1.y + p2.y) / 2);
507        }
508    
509        public static GraphPoint normalize(GraphPoint vector) {
510            double size = Math.sqrt(Math.pow(vector.x, 2) + Math.pow(vector.y, 2));
511            GraphPoint ret = new GraphPoint(vector);
512            if (size != 0)
513                ret.multiply(1 / size);
514            return ret;
515        }
516    }