001/*
002 * Copyright 2006 - 2013
003 *     Stefan Balev     <stefan.balev@graphstream-project.org>
004 *     Julien Baudry    <julien.baudry@graphstream-project.org>
005 *     Antoine Dutot    <antoine.dutot@graphstream-project.org>
006 *     Yoann Pigné      <yoann.pigne@graphstream-project.org>
007 *     Guilhelm Savin   <guilhelm.savin@graphstream-project.org>
008 * 
009 * This file is part of GraphStream <http://graphstream-project.org>.
010 * 
011 * GraphStream is a library whose purpose is to handle static or dynamic
012 * graph, create them from scratch, file or any source and display them.
013 * 
014 * This program is free software distributed under the terms of two licenses, the
015 * CeCILL-C license that fits European law, and the GNU Lesser General Public
016 * License. You can  use, modify and/ or redistribute the software under the terms
017 * of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following
018 * URL <http://www.cecill.info> or under the terms of the GNU LGPL as published by
019 * the Free Software Foundation, either version 3 of the License, or (at your
020 * option) any later version.
021 * 
022 * This program is distributed in the hope that it will be useful, but WITHOUT ANY
023 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
024 * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
025 * 
026 * You should have received a copy of the GNU Lesser General Public License
027 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
028 * 
029 * The fact that you are presently reading this means that you have had
030 * knowledge of the CeCILL-C and LGPL licenses and that you accept their terms.
031 */
032package org.graphstream.algorithm;
033
034import java.util.Comparator;
035import java.util.HashSet;
036import java.util.Iterator;
037import java.util.LinkedList;
038import java.util.PriorityQueue;
039import java.util.Set;
040
041import org.graphstream.graph.Edge;
042import org.graphstream.graph.Element;
043import org.graphstream.graph.Graph;
044import org.graphstream.graph.Node;
045
046/**
047 * Compute the "betweenness" centrality of each vertex of a given graph.
048 * 
049 * <p>
050 * The betweenness centrality counts how many shortest paths between each
051 * pair of nodes of the graph pass by a node. It does it for all nodes of
052 * the graph.
053 * </p>
054 * 
055 * <h2>Usage</h2>
056 * 
057 * <p>
058 * This algorithm, by default, stores the centrality values for each node inside
059 * the "Cb" attribute. You can change this attribute name at construction time.
060 * </p>
061 * 
062 * <p>
063 * <b>This algorithm does not accept multi-graphs (p-graphs with p>1) yet.</b>
064 * </p>
065 * 
066 * <p>
067 * This algorithm does not take into account edge direction yet.
068 * </p>
069 * 
070 * <p>
071 * By default the
072 * weight attribute name is "weight", you can activate the weights using
073 * {@link #setWeighted()}. You can change the weight attribute name using the
074 * dedicated constructor or the {@link #setWeightAttributeName(String)} method.
075 * This method implicitly enable weights in the computation. Use
076 * {@link #setUnweighted()} to disable weights.
077 * </p>
078 * 
079 * <p>
080 * The result of the computation is stored on each node inside the "Cb"
081 * attribute. You can change the name of this attribute using the dedicated
082 * constructor or the {@link #setCentralityAttributeName(String)} method.
083 * </p>
084 * 
085 * <p>
086 * As the computing of centrality can take a lot of time, you can provide a
087 * progress 'callback' to get notified each time the algorithm finished
088 * processing a node (however the centrality values are usable only when the
089 * algorithm finished). See the {@link #registerProgressIndicator(Progress)}
090 * method.
091 * </p>
092 * 
093 * <h2>Complexity</h2>
094 * 
095 * <p>
096 * By default the algorithm performs on a graph considered as not weighted with
097 * complexity O(nm). You can specify that the graph edges contain weights in
098 * which case the algorithm complexity is O(nm + n^2 log n).
099 * </p>
100 * 
101 * <h2>Example</h2>
102 * 
103 * <pre>
104 *              Graph graph = new SingleGraph("Betweenness Test");
105 *              
106 *              //    E----D  AB=1, BC=5, CD=3, DE=2, BE=6, EA=4  
107 *              //   /|    |  Cb(A)=4
108 *              //  / |    |  Cb(B)=2
109 *              // A  |    |  Cb(C)=0
110 *              //  \ |    |  Cb(D)=2
111 *              //   \|    |  Cb(E)=4
112 *              //    B----C
113 *              
114 *              Node A = graph.addNode("A");
115 *              Node B = graph.addNode("B");
116 *              Node E = graph.addNode("E");
117 *              Node C = graph.addNode("C");
118 *              Node D = graph.addNode("D");
119 *
120 *              graph.addEdge("AB", "A", "B");
121 *              graph.addEdge("BE", "B", "E");
122 *              graph.addEdge("BC", "B", "C");
123 *              graph.addEdge("ED", "E", "D");
124 *              graph.addEdge("CD", "C", "D");
125 *              graph.addEdge("AE", "A", "E");
126 *              
127 *              bcb.setWeight(A, B, 1);
128 *              bcb.setWeight(B, E, 6);
129 *              bcb.setWeight(B, C, 5);
130 *              bcb.setWeight(E, D, 2);
131 *              bcb.setWeight(C, D, 3);
132 *              bcb.setWeight(A, E, 4);
133 *
134 *              BetweennessCentrality bcb = new BetweennessCentrality();
135 *              bcb.setWeightAttributeName("weight");
136 *              bcb.init(graph);
137 *              bcb.compute();
138 *              
139 *              System.out.println("A="+ graph.getNode("A").getAttribute("Cb"));
140 *              System.out.println("B="+ graph.getNode("B").getAttribute("Cb"));
141 *              System.out.println("C="+ graph.getNode("C").getAttribute("Cb"));
142 *              System.out.println("D="+ graph.getNode("D").getAttribute("Cb"));
143 *              System.out.println("E="+ graph.getNode("E").getAttribute("Cb"));
144 * </pre>
145 * 
146 * <h2>Reference</h2>
147 *
148 * <p>
149 * This is based on the algorithm described in "A Faster Algorithm for
150 * Betweenness Centrality", Ulrik Brandes, Journal of Mathematical Sociology,
151 * 2001, and in
152 * "On variants of shortest-path betweenness centrality and their generic computation",
153 * of the same author, 2008.
154 * </p>
155 * 
156 * @reference A Faster Algorithm for Betweenness Centrality, Ulrik Brandes,
157 * Journal of Mathematical Sociology, 2001, 25:2, pp. 163 - 177",
158 * "DOI: 10.1080/0022250X.2001.9990249"
159 * 
160 * @reference On variants of shortest-path betweenness centrality and their generic computation,
161 * Ulrik Brandes, Social Networks, vol 30:2", pp. 136 - 145, 2008,
162 * issn 0378-8733, "DOI: 10.1016/j.socnet.2007.11.001".
163 */
164public class BetweennessCentrality implements Algorithm {
165
166        protected static double INFINITY = 1000000.0;
167
168        /** Store the centrality value in this attribute on nodes and edges. */
169        protected String centralityAttributeName = "Cb";
170
171        /** The predecessors. */
172        protected String predAttributeName = "brandes.P";
173
174        /** The sigma value. */
175        protected String sigmaAttributeName = "brandes.sigma";
176
177        /** The distance value. */
178        protected String distAttributeName = "brandes.d";
179
180        /** The delta value. */
181        protected String deltaAttributeName = "brandes.delta";
182
183        /** Name of the attribute used to retrieve weights on edges. */
184        protected String weightAttributeName = "weight";
185
186        /** Do not use weights ? */
187        protected boolean unweighted = true;
188
189        /** The graph to modify. */
190        protected Graph graph;
191
192        /** The progress call-back method. */
193        protected Progress progress = null;
194
195        /** Compute the centrality of edges. */
196        protected boolean doEdges = true;
197        
198        /**
199         * New centrality algorithm that will perform as if the graph was
200         * unweighted. By default the centrality will be stored in a "Cb" attribute
201         * on each node.
202         */
203        public BetweennessCentrality() {
204                unweighted = true;
205        }
206
207        /**
208         * New centrality algorithm that will perform as if the graph was
209         * unweighted. The centrality for each node will be stored in an attribute
210         * whose name is specified by the <code>centralityAttributeName</code>
211         * argument.
212         * 
213         * @param centralityAttributeName
214         *            The name of the attribute used to store the result of the
215         *            algorithm on each node.
216         */
217        public BetweennessCentrality(String centralityAttributeName) {
218                this.centralityAttributeName = centralityAttributeName;
219                this.unweighted = true;
220        }
221
222        /**
223         * New centrality algorithm that will perform on a weighted graph, taking
224         * the weight of each edge in the given <code>weightAttributeName</code>.
225         * The result of the algorithm is stored for each node using the given
226         * <code>centralityAttributeName</code>. If an edge has no weight attribute,
227         * it is considered as having a weight of one.
228         * 
229         * @param centralityAttributeName
230         *            Name to use to store the centrality results on each node.
231         * @param weightAttributeName
232         *            Name to use to retrieve the edge weights.
233         */
234        public BetweennessCentrality(String centralityAttributeName,
235                        String weightAttributeName) {
236                this.centralityAttributeName = centralityAttributeName;
237                this.weightAttributeName = weightAttributeName;
238                this.unweighted = false;
239        }
240
241        /**
242         * Name of the attribute used to retrieve weights on edges.
243         */
244        public String getWeightAttributeName() {
245                return weightAttributeName;
246        }
247
248        /**
249         * Name of the attribute used to store centrality values on nodes.
250         */
251        public String getCentralityAttributeName() {
252                return centralityAttributeName;
253        }
254
255        /**
256         * Specify the name of the weight attribute to retrieve edge attributes.
257         * This automatically set the algorithm to perform on the graph as if it was
258         * weighted.
259         */
260        public void setWeightAttributeName(String weightAttributeName) {
261                unweighted = false;
262                this.weightAttributeName = weightAttributeName;
263        }
264
265        /**
266         * Consider the edges to have a weight. By default the weight is stored in a
267         * "weight" attribute. You can change this attribute using
268         * {@link #setWeightAttributeName(String)}. If an edge has no weight the
269         * value 1.0 is used.
270         */
271        public void setWeighted() {
272                unweighted = false;
273        }
274
275        /**
276         * Consider all the edges to have the weight.
277         */
278        public void setUnweighted() {
279                unweighted = true;
280        }
281        
282        /**
283         * Activate or deactivate the centrality computation on edges. By default it is
284         * activated. Notice that this does not change the complexity of the algorithm.
285         * Only one more access on the edges is done to store the centrality in addition
286         * to the node access.
287         * @param on If true, the edges centrality is also computed.
288         */
289        public void computeEdgeCentrality(boolean on) {
290                doEdges = on;
291        }
292
293        /**
294         * Specify the name of the attribute used to store the computed centrality
295         * values for each node.
296         */
297        public void setCentralityAttributeName(String centralityAttributeName) {
298                this.centralityAttributeName = centralityAttributeName;
299        }
300
301        /**
302         * Specify an interface to call in order to indicate the algorithm progress.
303         * Pass null to remove the progress indicator. The progress indicator will
304         * be called regularly to indicate the computation progress.
305         */
306        public void registerProgressIndicator(Progress progress) {
307                this.progress = progress;
308        }
309
310        /**
311         * Setup the algorithm to work on the given graph.
312         */
313        public void init(Graph graph) {
314                this.graph = graph;
315        }
316
317        /**
318         * Compute the betweenness centrality on the given graph for each node. The
319         * result is by default stored in the "Cb" attribute on each node.
320         */
321        public void compute() {
322                if (graph != null) {
323                        betweennessCentrality(graph);
324                }
325        }
326
327        /**
328         * Compute the betweenness centrality on the given graph for each node and
329         * eventually edges. This method is equivalent to a call in sequence to the
330         * two methods {@link #init(Graph)} then {@link #compute()}.
331         */
332        public void betweennessCentrality(Graph graph) {
333                init(graph);
334                initAllNodes(graph);
335                initAllEdges(graph);
336
337                float n = graph.getNodeCount();
338                float i = 0;
339
340                for (Node s : graph) {
341                        PriorityQueue<Node> S = null;
342
343                        if (unweighted)
344                                S = simpleExplore(s, graph);
345                        else
346                                S = dijkstraExplore2(s, graph);
347
348                        // The really new things in the Brandes algorithm are here:
349                        // Accumulation phase:
350
351                        while (!S.isEmpty()) {
352                                Node w = S.poll();
353
354                                for (Node v : predecessorsOf(w)) {
355                                        double c = ((sigma(v) / sigma(w)) * (1.0 + delta(w)));
356                                        if(doEdges) {
357                                                Edge e = w.getEdgeBetween(v);
358                                                setCentrality(e, centrality(e) + c);
359                                        }
360                                        setDelta(v, delta(v) + c);
361                                }
362                                if (w != s) {
363                                        setCentrality(w, centrality(w) + delta(w));
364                                }
365                        }
366
367                        if (progress != null)
368                                progress.progress(i / n);
369
370                        i++;
371                }
372        }
373
374        /**
375         * Compute single-source multiple-targets shortest paths on an unweighted
376         * graph.
377         * 
378         * @param source
379         *            The source node.
380         * @param graph
381         *            The graph.
382         * @return A priority queue of explored nodes with sigma values usable to
383         *         compute the centrality.
384         */
385        protected PriorityQueue<Node> simpleExplore(Node source, Graph graph) {
386                LinkedList<Node> Q = new LinkedList<Node>();
387                PriorityQueue<Node> S = new PriorityQueue<Node>(graph.getNodeCount(),
388                                new BrandesNodeComparatorLargerFirst());
389
390                setupAllNodes(graph);
391                Q.add(source);
392                setSigma(source, 1.0);
393                setDistance(source, 0.0);
394
395                while (!Q.isEmpty()) {
396                        Node v = Q.removeFirst();
397
398                        S.add(v);
399                        Iterator<? extends Edge> ww = v.getLeavingEdgeIterator();
400
401                        while (ww.hasNext()) {
402                                Edge l = ww.next();
403                                Node w = l.getOpposite(v);//ww.next();
404
405                                if (distance(w) == INFINITY) {
406                                        setDistance(w, distance(v) + 1);
407                                        Q.add(w);
408                                }
409
410                                if (distance(w) == (distance(v) + 1.0)) {
411                                        setSigma(w, sigma(w) + sigma(v));
412                                        addToPredecessorsOf(w, v);
413                                }
414                        }
415                }
416
417                return S;
418        }
419
420        /**
421         * Compute single-source multiple-targets paths on a weighted graph.
422         * 
423         * @param source
424         *            The source node.
425         * @param graph
426         *            The graph.
427         * @return A priority queue of explored nodes with sigma values usable to
428         *         compute the centrality.
429         */
430        protected PriorityQueue<Node> dijkstraExplore(Node source, Graph graph) {
431                PriorityQueue<Node> S = new PriorityQueue<Node>(graph.getNodeCount(),
432                                new BrandesNodeComparatorLargerFirst());
433                PriorityQueue<Node> Q = new PriorityQueue<Node>(graph.getNodeCount(),
434                                new BrandesNodeComparatorSmallerFirst());
435
436                setupAllNodes(graph);
437                setDistance(source, 0.0);
438                setSigma(source, 1.0);
439
440                Q.add(source);
441
442                while (!Q.isEmpty()) {
443                        Node u = Q.poll();
444
445                        if (distance(u) < 0.0) { // XXX Can happen ??? XXX
446                                Q.clear();
447                                throw new RuntimeException("negative distance ??");
448                        } else {
449                                S.add(u);
450
451//                              Iterator<? extends Node> k = u.getNeighborNodeIterator();
452                                Iterator<? extends Edge> k = u.getLeavingEdgeIterator();
453
454                                while (k.hasNext()) {
455//                                      Node v = k.next();
456                                        Edge l = k.next();
457                                        Node v = l.getOpposite(u);
458                                        
459                                        double alt = distance(u) + weight(u, v);
460
461                                        if (alt < distance(v)) {
462                                                if (distance(v) == INFINITY) {
463                                                        setDistance(v, alt);
464                                                        updatePriority(S, v);
465                                                        updatePriority(Q, v);
466                                                        Q.add(v);
467                                                        setSigma(v, sigma(v) + sigma(u)); // XXX
468                                                                                                                                // sigma(v)==0,
469                                                                                                                                // always ?? XXX
470                                                } else {
471                                                        setDistance(v, alt);
472                                                        updatePriority(S, v);
473                                                        updatePriority(Q, v);
474                                                        setSigma(v, sigma(u));
475                                                }
476                                                replacePredecessorsOf(v, u);
477                                        } else if (alt == distance(v)) {
478                                                setSigma(v, sigma(v) + sigma(u));
479                                                addToPredecessorsOf(v, u);
480                                        }
481                                }
482                        }
483                }
484
485                return S;
486        }
487
488        /**
489         * The implementation of the Brandes paper.
490         * 
491         * <ul>
492         * <li>title =
493         * "On variants of shortest-path betweenness centrality and their generic computation"
494         * ,</li>
495         * <li>author = "Ulrik Brandes",</li>
496         * <li>journal = "Social Networks",</li>
497         * <li>volume = "30",</li>
498         * <li>number = "2",</li>
499         * <li>pages = "136 - 145",</li>
500         * <li>year = "2008",</li>
501         * <li>note = "",</li>
502         * <li>issn = "0378-8733",</li>
503         * <li>doi = "DOI: 10.1016/j.socnet.2007.11.001",</li> </li>
504         */
505        protected PriorityQueue<Node> dijkstraExplore2(Node source, Graph graph) {
506                PriorityQueue<Node> S = new PriorityQueue<Node>(graph.getNodeCount(),
507                                new BrandesNodeComparatorLargerFirst());
508                PriorityQueue<Node> Q = new PriorityQueue<Node>(graph.getNodeCount(),
509                                new BrandesNodeComparatorSmallerFirst());
510
511                setupAllNodes(graph);
512                setDistance(source, 0.0);
513                setSigma(source, 1.0);
514                Q.add(source);
515
516                while (!Q.isEmpty()) {
517                        Node v = Q.poll();
518
519                        S.add(v);
520
521                        //Iterator<? extends Node> k = v.getNeighborNodeIterator();
522                        Iterator<? extends Edge> k = v.getLeavingEdgeIterator();
523
524                        while (k.hasNext()) {
525                                //Node w = k.next();
526                                Edge l = k.next();
527                                Node w = l.getOpposite(v);
528                                
529                                double alt = distance(v) + weight(v, w);
530                                double dw = distance(w);
531
532                                if (alt < dw) {
533                                        setDistance(w, alt);
534                                        updatePriority(S, w);
535                                        updatePriority(Q, w);
536                                        if (dw == INFINITY) {
537                                                Q.add(w);
538                                        }
539                                        setSigma(w, 0.0);
540                                        clearPredecessorsOf(w);
541                                }
542                                if (distance(w) == alt) {
543                                        setSigma(w, sigma(w) + sigma(v));
544                                        addToPredecessorsOf(w, v);
545                                }
546                        }
547                }
548
549                return S;
550        }
551
552        /**
553         * Update the given priority queue if the given node changed its priority
554         * (here distance) and if the node is already part of the queue.
555         * 
556         * @param Q
557         *            The queue.
558         * @param node
559         *            The node.
560         */
561        protected void updatePriority(PriorityQueue<Node> Q, Node node) {
562                if (Q.contains(node)) {
563                        Q.remove(node);
564                        Q.add(node);
565                }
566        }
567
568        /**
569         * The sigma value of the given node.
570         * 
571         * @param node
572         *            Extract the sigma value of this node.
573         * @return The sigma value.
574         */
575        protected double sigma(Node node) {
576                return node.getNumber(sigmaAttributeName);
577        }
578
579        /**
580         * The distance value of the given node.
581         * 
582         * @param node
583         *            Extract the distance value of this node.
584         * @return The distance value.
585         */
586        protected double distance(Node node) {
587                return node.getNumber(distAttributeName);
588        }
589
590        /**
591         * The delta value of the given node.
592         * 
593         * @param node
594         *            Extract the delta value of this node.
595         * @return The delta value.
596         */
597        protected double delta(Node node) {
598                return node.getNumber(deltaAttributeName);
599        }
600
601        /**
602         * The centrality value of the given node or edge.
603         * 
604         * @param elt
605         *            Extract the centrality of this node or edge.
606         * @return The centrality value.
607         */
608        public double centrality(Element elt) {
609                return elt.getNumber(centralityAttributeName);
610        }
611        
612        /**
613         * List of predecessors of the given node.
614         * 
615         * @param node
616         *            Extract the predecessors of this node.
617         * @return The list of predecessors.
618         */
619        @SuppressWarnings("all")
620        protected Set<Node> predecessorsOf(Node node) {
621                return (HashSet<Node>) node.getAttribute(predAttributeName);
622        }
623
624        /**
625         * Set the sigma value of the given node.
626         * 
627         * @param node
628         *            The node to modify.
629         * @param sigma
630         *            The sigma value to store on the node.
631         */
632        protected void setSigma(Node node, double sigma) {
633                node.setAttribute(sigmaAttributeName, sigma);
634        }
635
636        /**
637         * Set the distance value of the given node.
638         * 
639         * @param node
640         *            The node to modify.
641         * @param distance
642         *            The delta value to store on the node.
643         */
644        protected void setDistance(Node node, double distance) {
645                node.setAttribute(distAttributeName, distance);
646        }
647
648        /**
649         * Set the delta value of the given node.
650         * 
651         * @param node
652         *            The node to modify.
653         * @param delta
654         *            The delta value to store on the node.
655         */
656        protected void setDelta(Node node, double delta) {
657                node.setAttribute(deltaAttributeName, delta);
658        }
659
660        /**
661         * Set the centrality of the given node or edge.
662         * 
663         * @param elt
664         *            The node or edge to modify.
665         * @param centrality
666         *            The centrality to store on the node.
667         */
668        public void setCentrality(Element elt, double centrality) {
669                elt.setAttribute(centralityAttributeName, centrality);
670        }
671        
672        /**
673         * Set the weight of the edge between 'from' and 'to'.
674         * 
675         * @param from
676         *            The source node.
677         * @param to
678         *            The target node.
679         * @param weight
680         *            The weight to store on the edge between 'from' and 'to'.
681         */
682        public void setWeight(Node from, Node to, double weight) {
683                if (from.hasEdgeBetween(to.getId()))
684                        from.getEdgeBetween(to.getId()).setAttribute(weightAttributeName,
685                                        weight);
686        }
687
688        /**
689         * The weight of the edge between 'from' and 'to'.
690         * 
691         * @param from
692         *            The origin node.
693         * @param to
694         *            The target node.
695         * @return The weight on the edge between 'form' and 'to'.
696         */
697        public double weight(Node from, Node to) {
698                Edge edge = from.getEdgeBetween(to.getId());
699
700                if (edge != null) {
701                        if (edge.hasAttribute(weightAttributeName))
702                                return edge.getNumber(weightAttributeName);
703                        else
704                                return 1.0;
705                } else {
706                        return 0.0;
707                }
708        }
709
710        /**
711         * Remove all predecessors of the given node and then add it a first
712         * predecessor.
713         * 
714         * @param node
715         *            The node to modify.
716         * @param predecessor
717         *            The predecessor to add.
718         */
719        protected void replacePredecessorsOf(Node node, Node predecessor) {
720                HashSet<Node> set = new HashSet<Node>();
721
722                set.add(predecessor);
723                node.setAttribute(predAttributeName, set);
724        }
725
726        /**
727         * Add a node to the predecessors of another.
728         * 
729         * @param node
730         *            Modify the predecessors of this node.
731         * @param predecessor
732         *            The predecessor to add.
733         */
734        @SuppressWarnings("all")
735        protected void addToPredecessorsOf(Node node, Node predecessor) {
736                HashSet<Node> preds = (HashSet<Node>) node
737                                .getAttribute(predAttributeName);
738
739                preds.add(predecessor);
740        }
741
742        /**
743         * Remove all predecessors of the given node.
744         * 
745         * @param node
746         *            Remove all predecessors of this node.
747         */
748        protected void clearPredecessorsOf(Node node) {
749                HashSet<Node> set = new HashSet<Node>();
750                node.setAttribute(predAttributeName, set);
751        }
752
753        /**
754         * Set a default centrality of 0 to all nodes.
755         * 
756         * @param graph
757         *            The graph to modify.
758         */
759        protected void initAllNodes(Graph graph) {
760                for (Node node : graph) {
761                        setCentrality(node, 0.0);
762                }
763        }
764        
765        /**
766         * Set a default centrality of 0 to all edges.
767         *
768         * @param graph
769         *                      The graph to modify.
770         */
771        protected void initAllEdges(Graph graph) {
772                if(doEdges) {
773                        for(Edge edge : graph.getEachEdge()) {
774                                setCentrality(edge, 0.0);
775                        }
776                }
777        }
778
779        /**
780         * Add a default value for attributes used during computation.
781         * 
782         * @param graph
783         *            The graph to modify.
784         */
785        protected void setupAllNodes(Graph graph) {
786                for (Node node : graph) {
787                        clearPredecessorsOf(node);
788                        setSigma(node, 0.0);
789                        setDistance(node, INFINITY);
790                        setDelta(node, 0.0);
791                }
792        }
793
794        /**
795         * Delete attributes used by this algorithm in nodes and edges of the graph
796         */
797        public void cleanGraph(){
798                cleanElement(graph.getEachEdge());
799                cleanElement(graph.getEachNode());
800        }
801
802        /**
803         * Delete attributes used by this algorithm in nodes of the graph
804         */
805        public void cleanNodes(){
806                cleanElement(graph.getEachNode());
807        }
808
809        /**
810         * Delete attributes used by this algorithm in edges of the graph
811         */
812        public void cleanEdges(){
813                cleanElement(graph.getEachEdge());
814        }
815
816        /**
817         * Delete attributes used by this algorithm in elements of a graph
818         * @param it the list of elements
819         */
820        private void cleanElement(Iterable<? extends Element> it){
821                for(Element e : it){
822                        if(e.hasAttribute(predAttributeName))
823                                e.removeAttribute(predAttributeName);
824                        if(e.hasAttribute(sigmaAttributeName))
825                                e.removeAttribute(sigmaAttributeName);
826                        if(e.hasAttribute(distAttributeName))
827                                e.removeAttribute(distAttributeName);
828                        if(e.hasAttribute(deltaAttributeName))
829                                e.removeAttribute(deltaAttributeName);
830                }
831        }
832
833        /**
834         * Increasing comparator used for priority queues.
835         */
836        protected class BrandesNodeComparatorLargerFirst implements
837                        Comparator<Node> {
838                public int compare(Node x, Node y) {
839                        // return (int) ( (distance(y)*1000.0) - (distance(x)*1000.0) );
840                        double yy = distance(y);
841                        double xx = distance(x);
842
843                        if (xx > yy)
844                                return -1;
845                        else if (xx < yy)
846                                return 1;
847
848                        return 0;
849                }
850        }
851
852        /**
853         * Decreasing comparator used for priority queues.
854         */
855        protected class BrandesNodeComparatorSmallerFirst implements
856                        Comparator<Node> {
857                public int compare(Node x, Node y) {
858                        // return (int) ( (distance(x)*1000.0) - (distance(y)*1000.0) );
859                        double yy = distance(y);
860                        double xx = distance(x);
861
862                        if (xx > yy)
863                                return 1;
864                        else if (xx < yy)
865                                return -1;
866
867                        return 0;
868                }
869        }
870
871        /**
872         * Interface allowing to be notified of the algorithm progress.
873         */
874        public interface Progress {
875                /**
876                 * Progress of the algorithm.
877                 * 
878                 * @param percent
879                 *            a value between 0 and 1, 0 meaning 0% and 1 meaning 100%.
880                 */
881                void progress(float percent);
882        }
883}