1 package ini
.trakem2
.analysis
;
3 import java
.util
.ArrayList
;
4 import java
.util
.Collection
;
5 import java
.util
.HashMap
;
6 import java
.util
.HashSet
;
7 import java
.util
.Iterator
;
8 import java
.util
.LinkedList
;
13 /** Following pseudo-code from:
14 * Ulrik Brandes. 2001. A faster algorithm for betweenness centrality.
15 * Journal of Mathematical Sociology 25(2):163-177, (2001). */
16 public class Centrality
{
18 /** Like @see compute, but operates on a copy of all Vertex instances,
19 * and return a Collection with the same order as @param vs. */
20 static public final<T
> ArrayList
<Vertex
<T
>> safeCompute(final Collection
<Vertex
<T
>> vs
) {
21 final ArrayList
<Vertex
<T
>> copies
= Vertex
.clone(vs
);
26 /** Computes betweenness centrality of each vertex in the collection of vertices @param vs
27 * where all vertices are part of the same graph.
28 * Assumes the internal variables of each Vertex are reset to its initialization values,
29 * and that the neighbors array is proper as well.
30 * When done, the centrality of each Vertex is set in the homonymous Vertex field. */
31 static public final<T
> void compute(final Collection
<Vertex
<T
>> vs
) {
35 final LinkedList
<Vertex
<T
>> stack
= new LinkedList
<Vertex
<T
>>();
36 final LinkedList
<Vertex
<T
>> queue
= new LinkedList
<Vertex
<T
>>();
38 for (final Vertex
<T
> s
: vs
) {
40 for (final Vertex
<T
> t
: vs
) {
41 t
.predecessors
.clear();
50 while (!queue
.isEmpty()) {
51 final Vertex
<T
> v
= queue
.removeFirst();
53 for (final Vertex
<T
> w
: v
.neighbors
) {
54 // w found for the first time?
59 // shortest path to w via v?
61 w
.sigma
+= v
.sigma
; // sigma is always 1 in a tree
62 w
.predecessors
.add(v
);
66 for (final Vertex
<T
> v
: vs
) {
69 while (!stack
.isEmpty()) {
70 final Vertex
<T
> w
= stack
.removeLast();
71 for (final Vertex
<T
> v
: w
.predecessors
) {
72 v
.delta
+= (v
.sigma
/ (float)w
.sigma
) * (1 + w
.delta
); // sigma is always 1 in a tree
75 w
.centrality
+= w
.delta
;
81 /** Find the chain of nodes, over branch points if necessary, that have not yet been processed. */
82 static private final <T
> List
<Vertex
<T
>> findChain(
83 final Vertex
<T
> origin
,
84 final Vertex
<T
> parent
,
85 final Set
<Vertex
<T
>> processed
) {
86 final ArrayList
<Vertex
<T
>> chain
= new ArrayList
<Vertex
<T
>>();
93 if (1 == o
.neighbors
.size()) { break; }
95 for (final Vertex
<T
> v
: o
.neighbors
) {
96 if (v
== p
|| processed
.contains(v
) || v
.centrality
< p
.centrality
) {
102 continue A
; // there can only be one unexplored path
109 static public final<T
> ArrayList
<EtchingStep
<T
>> branchWise(final Collection
<Vertex
<T
>> vs_
, final int etching_multiplier
) {
112 final Set
<Vertex
<T
>> vs
= new HashSet
<Vertex
<T
>>(Vertex
.clone(vs_
));
114 // Map of original vertex instances
115 final HashMap
<T
,Vertex
<T
>> m
= new HashMap
<T
,Vertex
<T
>>();
116 for (final Vertex
<T
> v
: vs_
) {
120 // A set of the remaining branch vertices
121 final Set
<Vertex
<T
>> branch_vertices
= new HashSet
<Vertex
<T
>>();
122 for (final Vertex
<T
> v
: vs
) {
123 if (v
.getNeighborCount() > 2) branch_vertices
.add(v
);
126 // Map of the count of remaining branch vertices and vertices removed at that step
127 final ArrayList
<EtchingStep
<T
>> steps
= new ArrayList
<EtchingStep
<T
>>();
129 final HashSet
<Vertex
<T
>> processed
= new HashSet
<Vertex
<T
>>();
131 // TODO the node centrality needs to be computed only once!
132 // TODO the centrality value is thrown out!
134 while (vs
.size() > 0) {
135 // Reset all internal vars related to computing centrality
136 for (final Vertex
<T
> v
: vs
) {
139 // Recompute centrality for the now smaller graph
140 Centrality
.compute(vs
);
142 // Remove all vertices whose centrality falls below a certain threshold
143 final HashSet
<Vertex
<T
>> removed
= new HashSet
<Vertex
<T
>>();
144 final int vs_size
= vs
.size();
145 for (final Iterator
<Vertex
<T
>> it
= vs
.iterator(); it
.hasNext(); ) {
146 final Vertex
<T
> v
= it
.next();
147 if (v
.centrality
< etching_multiplier
* vs_size
) {
153 // Determine which branches have been removed at this etching step
154 final Set
<Collection
<Vertex
<T
>>> etched_branches
= new HashSet
<Collection
<Vertex
<T
>>>();
155 for (final Vertex
<T
> r
: removed
) {
156 for (final Vertex
<T
> w
: r
.neighbors
) {
157 if (w
.isBranching() && w
.centrality
>= r
.centrality
) {
158 final List
<Vertex
<T
>> branch
= findChain(m
.get(r
.data
), m
.get(w
.data
), processed
);
159 processed
.addAll(branch
);
160 etched_branches
.add(branch
);
165 if (etched_branches
.size() > 0) {
166 steps
.add(new EtchingStep
<T
>(branch_vertices
.size(), etched_branches
));
169 // Fix neighbors of remaining vertices
170 for (final Vertex
<T
> v
: removed
) {
171 for (final Iterator
<Vertex
<T
>> it
= v
.neighbors
.iterator(); it
.hasNext(); ) {
172 final Vertex
<T
> w
= it
.next();
173 if (removed
.contains(w
)) {
177 // to the vertex that remains, remove the vertex v from its neighbors:
178 w
.neighbors
.remove(v
);
181 // Remove branch vertices which aren't branch vertices anymore
182 for (final Iterator
<Vertex
<T
>> it
= branch_vertices
.iterator(); it
.hasNext(); ) {
183 final Vertex
<T
> v
= it
.next();
184 if (v
.neighbors
.size() < 3 || removed
.contains(v
)) {
188 if (0 == branch_vertices
.size()) {
193 for (final EtchingStep
<T
> es
: steps
) {
194 for (final Collection
<Vertex
<T
>> b
: es
.branches
) {
195 List
<Vertex
<T
>> b2
= new ArrayList
<Vertex
<T
>>(b
);
197 for (final Vertex
<T
> v
: b2
) {
198 b
.add(m
.get(v
.data
));
203 // The last, central branch
204 Set
<T
> done
= new HashSet
<T
>();
205 for (final Vertex
<T
> v
: processed
) {
208 HashMap
<T
,Vertex
<T
>> last
= new HashMap
<T
,Vertex
<T
>>(m
);
209 last
.keySet().removeAll(done
);
210 HashSet
<Collection
<Vertex
<T
>>> bs
= new HashSet
<Collection
<Vertex
<T
>>>();
211 bs
.add(last
.values());
212 steps
.add(new EtchingStep
<T
>(0, bs
));
217 /** An entry of the number of remaining branch vertices versus
218 * the set of branches (each as a List<Vertex<T>>) removed. */
219 static public class EtchingStep
<T
> implements Map
.Entry
<Integer
,Set
<Collection
<Vertex
<T
>>>> {
220 public int remaining_branch_vertices
= 0;
221 public Set
<Collection
<Vertex
<T
>>> branches
= null;
222 public EtchingStep(final int remaining_branch_vertices
, final Set
<Collection
<Vertex
<T
>>> branches
) {
223 this.remaining_branch_vertices
= remaining_branch_vertices
;
224 this.branches
= branches
;
227 public Integer
getKey() {
228 return remaining_branch_vertices
;
231 public Set
<Collection
<Vertex
<T
>>> getValue() {
235 public Set
<Collection
<Vertex
<T
>>> setValue(final Set
<Collection
<Vertex
<T
>>> value
) {
236 throw new UnsupportedOperationException();