Merge lp:~mathieu-jacomy/gephi/forceatlas2-multithread into lp:~gephi.team/gephi/0.8
- forceatlas2-multithread
- Merge into 0.8
Proposed by
Mathieu Bastian
Status: | Needs review |
---|---|
Proposed branch: | lp:~mathieu-jacomy/gephi/forceatlas2-multithread |
Merge into: | lp:~gephi.team/gephi/0.8 |
Diff against target: |
628 lines (+345/-32) 11 files modified
LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Bundle.properties (+5/-0) LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Bundle_fr.properties (+5/-0) LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/ForceAtlas2.java (+88/-27) LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/ForceFactory.java (+46/-3) LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/NodesThread.java (+64/-0) LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Operation.java (+13/-0) LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeNodeAttract.java (+32/-0) LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeNodeRepulse.java (+29/-0) LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeRegionRepulse.java (+32/-0) LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeRepulse.java (+29/-0) LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Region.java (+2/-2) |
To merge this branch: | bzr merge lp:~mathieu-jacomy/gephi/forceatlas2-multithread |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mathieu Bastian | Pending | ||
Review via email: mp+69478@code.launchpad.net |
Commit message
Description of the change
Multithread version of ForceAtlas2
To post a comment you must log in.
- 2260. By Mathieu Jacomy
-
ForceAtlas2 Multithread - better strategy. Tested and working.
- 2261. By Mathieu Jacomy
-
Better ThreadPool implementation, added strong gravity
Unmerged revisions
- 2261. By Mathieu Jacomy
-
Better ThreadPool implementation, added strong gravity
- 2260. By Mathieu Jacomy
-
ForceAtlas2 Multithread - better strategy. Tested and working.
- 2259. By Mathieu Jacomy
-
ForceAtlas2 Multithreading (basic implementation: consumer-producer paradigm)
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Bundle.properties' | |||
2 | --- LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Bundle.properties 2011-06-05 21:30:01 +0000 | |||
3 | +++ LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Bundle.properties 2011-08-30 14:28:25 +0000 | |||
4 | @@ -4,11 +4,14 @@ | |||
5 | 4 | ForceAtlas2.tuning=Tuning | 4 | ForceAtlas2.tuning=Tuning |
6 | 5 | ForceAtlas2.behavior=Behavior Alternatives | 5 | ForceAtlas2.behavior=Behavior Alternatives |
7 | 6 | ForceAtlas2.performance=Performance | 6 | ForceAtlas2.performance=Performance |
8 | 7 | ForceAtlas2.threads=Threads | ||
9 | 7 | 8 | ||
10 | 8 | ForceAtlas2.scalingRatio.name=Scaling | 9 | ForceAtlas2.scalingRatio.name=Scaling |
11 | 9 | ForceAtlas2.scalingRatio.desc=How much repulsion you want. More makes a more sparse graph. | 10 | ForceAtlas2.scalingRatio.desc=How much repulsion you want. More makes a more sparse graph. |
12 | 10 | ForceAtlas2.gravity.name=Gravity | 11 | ForceAtlas2.gravity.name=Gravity |
13 | 11 | ForceAtlas2.gravity.desc=Attracts nodes to the center. Prevents islands from drifting away. | 12 | ForceAtlas2.gravity.desc=Attracts nodes to the center. Prevents islands from drifting away. |
14 | 13 | ForceAtlas2.strongGravityMode.name=Stronger Gravity | ||
15 | 14 | ForceAtlas2.strongGravityMode.desc=A stronger gravity law | ||
16 | 12 | ForceAtlas2.distributedAttraction.name=Dissuade Hubs | 15 | ForceAtlas2.distributedAttraction.name=Dissuade Hubs |
17 | 13 | ForceAtlas2.distributedAttraction.desc=Distributes attraction along outbound edges. Hubs attract less and thus are pushed to the borders. | 16 | ForceAtlas2.distributedAttraction.desc=Distributes attraction along outbound edges. Hubs attract less and thus are pushed to the borders. |
18 | 14 | ForceAtlas2.linLogMode.name=LinLog mode | 17 | ForceAtlas2.linLogMode.name=LinLog mode |
19 | @@ -23,3 +26,5 @@ | |||
20 | 23 | ForceAtlas2.barnesHutTheta.desc=Theta of the Barnes Hut optimization. | 26 | ForceAtlas2.barnesHutTheta.desc=Theta of the Barnes Hut optimization. |
21 | 24 | ForceAtlas2.edgeWeightInfluence.name=Edge Weight Influence | 27 | ForceAtlas2.edgeWeightInfluence.name=Edge Weight Influence |
22 | 25 | ForceAtlas2.edgeWeightInfluence.desc=How much influence you give to the edges weight. 0 is "no influence" and 1 is "normal". | 28 | ForceAtlas2.edgeWeightInfluence.desc=How much influence you give to the edges weight. 0 is "no influence" and 1 is "normal". |
23 | 29 | ForceAtlas2.threads.name=Threads number | ||
24 | 30 | ForceAtlas2.threads.desc=More threads means more speed if your cores can handle it. | ||
25 | 26 | 31 | ||
26 | === modified file 'LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Bundle_fr.properties' | |||
27 | --- LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Bundle_fr.properties 2011-06-05 21:30:01 +0000 | |||
28 | +++ LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Bundle_fr.properties 2011-08-30 14:28:25 +0000 | |||
29 | @@ -4,11 +4,14 @@ | |||
30 | 4 | ForceAtlas2.tuning=R\u00e9glages fins | 4 | ForceAtlas2.tuning=R\u00e9glages fins |
31 | 5 | ForceAtlas2.behavior=Options de comportement | 5 | ForceAtlas2.behavior=Options de comportement |
32 | 6 | ForceAtlas2.performance=Performances | 6 | ForceAtlas2.performance=Performances |
33 | 7 | ForceAtlas2.threads=Processus | ||
34 | 7 | 8 | ||
35 | 8 | ForceAtlas2.scalingRatio.name=Dimensionnement | 9 | ForceAtlas2.scalingRatio.name=Dimensionnement |
36 | 9 | ForceAtlas2.scalingRatio.desc=Quantit\u00e9 de r\u00e9pulsion, par rapport \u00e0 l'attraction. Rend le graphe plus \u00e9tal\u00e9. | 10 | ForceAtlas2.scalingRatio.desc=Quantit\u00e9 de r\u00e9pulsion, par rapport \u00e0 l'attraction. Rend le graphe plus \u00e9tal\u00e9. |
37 | 10 | ForceAtlas2.gravity.name=Gravit\u00e9 | 11 | ForceAtlas2.gravity.name=Gravit\u00e9 |
38 | 11 | ForceAtlas2.gravity.desc=Attire les noeuds vers le centre. Emp\u00eache les \u00eelots de d\u00e9river \u00e0 l'infini. | 12 | ForceAtlas2.gravity.desc=Attire les noeuds vers le centre. Emp\u00eache les \u00eelots de d\u00e9river \u00e0 l'infini. |
39 | 13 | ForceAtlas2.strongGravityMode.name=Forte Gravit\u00e9 | ||
40 | 14 | ForceAtlas2.strongGravityMode.desc=Une loi de gravit\u00e9 plus forte | ||
41 | 12 | ForceAtlas2.distributedAttraction.name=Dissuader les Hubs | 15 | ForceAtlas2.distributedAttraction.name=Dissuader les Hubs |
42 | 13 | ForceAtlas2.distributedAttraction.desc=Distribue l'attraction dans les liens sortants. Les Hubs attirent moins et sont donc repouss\u00e9s en p\u00e9riph\u00e9rie. | 16 | ForceAtlas2.distributedAttraction.desc=Distribue l'attraction dans les liens sortants. Les Hubs attirent moins et sont donc repouss\u00e9s en p\u00e9riph\u00e9rie. |
43 | 14 | ForceAtlas2.linLogMode.name=Mode LinLog | 17 | ForceAtlas2.linLogMode.name=Mode LinLog |
44 | @@ -23,3 +26,5 @@ | |||
45 | 23 | ForceAtlas2.barnesHutTheta.desc=param\u00e8tre Theta de l'optimisation de Barnes Hut. | 26 | ForceAtlas2.barnesHutTheta.desc=param\u00e8tre Theta de l'optimisation de Barnes Hut. |
46 | 24 | ForceAtlas2.edgeWeightInfluence.name=Influence Poids des liens | 27 | ForceAtlas2.edgeWeightInfluence.name=Influence Poids des liens |
47 | 25 | ForceAtlas2.edgeWeightInfluence.desc=L'influence du poides des liens. 0 c'est aucune influence, 1 c'est une influence normale et au-del\u00e0 \u00e7a accentue l'importance du poids des liens dans la spatialisation. | 28 | ForceAtlas2.edgeWeightInfluence.desc=L'influence du poides des liens. 0 c'est aucune influence, 1 c'est une influence normale et au-del\u00e0 \u00e7a accentue l'importance du poids des liens dans la spatialisation. |
48 | 29 | ForceAtlas2.threads.name=Nb. processus | ||
49 | 30 | ForceAtlas2.threads.desc=Plus de processus multiplient les performances si vos processeurs peuvent les supporter. | ||
50 | 26 | 31 | ||
51 | === modified file 'LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/ForceAtlas2.java' | |||
52 | --- LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/ForceAtlas2.java 2011-06-05 21:30:01 +0000 | |||
53 | +++ LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/ForceAtlas2.java 2011-08-30 14:28:25 +0000 | |||
54 | @@ -22,6 +22,10 @@ | |||
55 | 22 | 22 | ||
56 | 23 | import java.util.ArrayList; | 23 | import java.util.ArrayList; |
57 | 24 | import java.util.List; | 24 | import java.util.List; |
58 | 25 | import java.util.concurrent.ExecutionException; | ||
59 | 26 | import java.util.concurrent.ExecutorService; | ||
60 | 27 | import java.util.concurrent.Executors; | ||
61 | 28 | import java.util.concurrent.Future; | ||
62 | 25 | import org.gephi.data.attributes.type.TimeInterval; | 29 | import org.gephi.data.attributes.type.TimeInterval; |
63 | 26 | import org.gephi.dynamic.DynamicUtilities; | 30 | import org.gephi.dynamic.DynamicUtilities; |
64 | 27 | import org.gephi.dynamic.api.DynamicController; | 31 | import org.gephi.dynamic.api.DynamicController; |
65 | @@ -37,6 +41,7 @@ | |||
66 | 37 | import org.gephi.layout.spi.LayoutBuilder; | 41 | import org.gephi.layout.spi.LayoutBuilder; |
67 | 38 | import org.gephi.layout.spi.LayoutProperty; | 42 | import org.gephi.layout.spi.LayoutProperty; |
68 | 39 | import org.gephi.project.api.Workspace; | 43 | import org.gephi.project.api.Workspace; |
69 | 44 | import org.openide.util.Exceptions; | ||
70 | 40 | import org.openide.util.Lookup; | 45 | import org.openide.util.Lookup; |
71 | 41 | import org.openide.util.NbBundle; | 46 | import org.openide.util.NbBundle; |
72 | 42 | 47 | ||
73 | @@ -60,10 +65,13 @@ | |||
74 | 60 | private boolean barnesHutOptimize; | 65 | private boolean barnesHutOptimize; |
75 | 61 | private double barnesHutTheta; | 66 | private double barnesHutTheta; |
76 | 62 | private boolean linLogMode; | 67 | private boolean linLogMode; |
77 | 68 | private boolean strongGravityMode; | ||
78 | 69 | private int threadCount; | ||
79 | 63 | private Region rootRegion; | 70 | private Region rootRegion; |
80 | 64 | double outboundAttCompensation = 1; | 71 | double outboundAttCompensation = 1; |
81 | 65 | //Dynamic Weight | 72 | //Dynamic Weight |
82 | 66 | private TimeInterval timeInterval; | 73 | private TimeInterval timeInterval; |
83 | 74 | private ExecutorService pool; | ||
84 | 67 | 75 | ||
85 | 68 | public ForceAtlas2(ForceAtlas2Builder layoutBuilder) { | 76 | public ForceAtlas2(ForceAtlas2Builder layoutBuilder) { |
86 | 69 | this.layoutBuilder = layoutBuilder; | 77 | this.layoutBuilder = layoutBuilder; |
87 | @@ -93,6 +101,9 @@ | |||
88 | 93 | nLayout.dx = 0; | 101 | nLayout.dx = 0; |
89 | 94 | nLayout.dy = 0; | 102 | nLayout.dy = 0; |
90 | 95 | } | 103 | } |
91 | 104 | |||
92 | 105 | pool = Executors.newFixedThreadPool(threadCount); | ||
93 | 106 | |||
94 | 96 | } | 107 | } |
95 | 97 | 108 | ||
96 | 98 | @Override | 109 | @Override |
97 | @@ -140,33 +151,45 @@ | |||
98 | 140 | outboundAttCompensation /= nodes.length; | 151 | outboundAttCompensation /= nodes.length; |
99 | 141 | } | 152 | } |
100 | 142 | 153 | ||
102 | 143 | // Repulsion | 154 | // Repulsion (and gravity) |
103 | 155 | // NB: Muti-threaded | ||
104 | 144 | RepulsionForce Repulsion = ForceFactory.builder.buildRepulsion(isAdjustSizes(), getScalingRatio()); | 156 | RepulsionForce Repulsion = ForceFactory.builder.buildRepulsion(isAdjustSizes(), getScalingRatio()); |
119 | 145 | if (isBarnesHutOptimize()) { | 157 | |
120 | 146 | for (Node n : nodes) { | 158 | int taskCount = 8*threadCount; // The threadPool Executor Service will manage the fetching of tasks and threads. |
121 | 147 | rootRegion.applyForce(n, Repulsion, getBarnesHutTheta()); | 159 | // We make more tasks than threads because some tasks may need more time to compute. |
122 | 148 | } | 160 | ArrayList<Future> threads = new ArrayList(); |
123 | 149 | } else { | 161 | for(int t=taskCount; t>0; t--){ |
124 | 150 | for (int n1Index = 0; n1Index < nodes.length; n1Index++) { | 162 | int from = (int) Math.floor(nodes.length*(t-1)/taskCount); |
125 | 151 | Node n1 = nodes[n1Index]; | 163 | int to = (int) Math.floor(nodes.length*t/taskCount); |
126 | 152 | for (int n2Index = 0; n2Index < n1Index; n2Index++) { | 164 | Future future = pool.submit(new NodesThread(nodes, from, to, isBarnesHutOptimize(), getBarnesHutTheta(), getGravity(), (isStrongGravityMode())?(ForceFactory.builder.getStrongGravity(getScalingRatio())):(Repulsion), getScalingRatio(), rootRegion, Repulsion)); |
127 | 153 | Node n2 = nodes[n2Index]; | 165 | threads.add(future); |
128 | 154 | Repulsion.apply(n1, n2); | 166 | } |
129 | 155 | } | 167 | for(Future future : threads) { |
130 | 156 | } | 168 | try { |
131 | 157 | } | 169 | future.get(); |
132 | 158 | 170 | } catch (InterruptedException ex) { | |
133 | 171 | Exceptions.printStackTrace(ex); | ||
134 | 172 | } catch (ExecutionException ex) { | ||
135 | 173 | Exceptions.printStackTrace(ex); | ||
136 | 174 | } | ||
137 | 175 | } | ||
138 | 176 | |||
139 | 159 | // Attraction | 177 | // Attraction |
140 | 160 | AttractionForce Attraction = ForceFactory.builder.buildAttraction(isLinLogMode(), isOutboundAttractionDistribution(), isAdjustSizes(), 1 * ((isOutboundAttractionDistribution()) ? (outboundAttCompensation) : (1))); | 178 | AttractionForce Attraction = ForceFactory.builder.buildAttraction(isLinLogMode(), isOutboundAttractionDistribution(), isAdjustSizes(), 1 * ((isOutboundAttractionDistribution()) ? (outboundAttCompensation) : (1))); |
150 | 161 | for (Edge e : edges) { | 179 | if(getEdgeWeightInfluence()==0){ |
151 | 162 | Attraction.apply(e.getSource(), e.getTarget(), Math.pow(getWeight(e), getEdgeWeightInfluence())); | 180 | for (Edge e : edges) { |
152 | 163 | } | 181 | Attraction.apply(e.getSource(), e.getTarget(), 1); |
153 | 164 | 182 | } | |
154 | 165 | // Gravity | 183 | } else if(getEdgeWeightInfluence()==1){ |
155 | 166 | for (Node n : nodes) { | 184 | for (Edge e : edges) { |
156 | 167 | Repulsion.apply(n, getGravity() / getScalingRatio()); | 185 | Attraction.apply(e.getSource(), e.getTarget(), getWeight(e)); |
157 | 168 | } | 186 | } |
158 | 169 | 187 | } else { | |
159 | 188 | for (Edge e : edges) { | ||
160 | 189 | Attraction.apply(e.getSource(), e.getTarget(), Math.pow(getWeight(e), getEdgeWeightInfluence())); | ||
161 | 190 | } | ||
162 | 191 | } | ||
163 | 192 | |||
164 | 170 | // Auto adjust speed | 193 | // Auto adjust speed |
165 | 171 | double totalSwinging = 0d; // How much irregular movement | 194 | double totalSwinging = 0d; // How much irregular movement |
166 | 172 | double totalEffectiveTraction = 0d; // Hom much useful movement | 195 | double totalEffectiveTraction = 0d; // Hom much useful movement |
167 | @@ -198,10 +221,10 @@ | |||
168 | 198 | // when the node swings. | 221 | // when the node swings. |
169 | 199 | double swinging = Math.sqrt((nLayout.old_dx - nLayout.dx) * (nLayout.old_dx - nLayout.dx) + (nLayout.old_dy - nLayout.dy) * (nLayout.old_dy - nLayout.dy)); | 222 | double swinging = Math.sqrt((nLayout.old_dx - nLayout.dx) * (nLayout.old_dx - nLayout.dx) + (nLayout.old_dy - nLayout.dy) * (nLayout.old_dy - nLayout.dy)); |
170 | 200 | double factor = 0.1 * speed / (1f + speed * Math.sqrt(swinging)); | 223 | double factor = 0.1 * speed / (1f + speed * Math.sqrt(swinging)); |
172 | 201 | 224 | ||
173 | 202 | double df = Math.sqrt(Math.pow(nLayout.dx, 2) + Math.pow(nLayout.dy, 2)); | 225 | double df = Math.sqrt(Math.pow(nLayout.dx, 2) + Math.pow(nLayout.dy, 2)); |
174 | 203 | factor = Math.min(factor * df, 10.) / df; | 226 | factor = Math.min(factor * df, 10.) / df; |
176 | 204 | 227 | ||
177 | 205 | double x = nData.x() + nLayout.dx * factor; | 228 | double x = nData.x() + nLayout.dx * factor; |
178 | 206 | double y = nData.y() + nLayout.dy * factor; | 229 | double y = nData.y() + nLayout.dy * factor; |
179 | 207 | 230 | ||
180 | @@ -220,7 +243,7 @@ | |||
181 | 220 | double swinging = Math.sqrt((nLayout.old_dx - nLayout.dx) * (nLayout.old_dx - nLayout.dx) + (nLayout.old_dy - nLayout.dy) * (nLayout.old_dy - nLayout.dy)); | 243 | double swinging = Math.sqrt((nLayout.old_dx - nLayout.dx) * (nLayout.old_dx - nLayout.dx) + (nLayout.old_dy - nLayout.dy) * (nLayout.old_dy - nLayout.dy)); |
182 | 221 | //double factor = speed / (1f + Math.sqrt(speed * swinging)); | 244 | //double factor = speed / (1f + Math.sqrt(speed * swinging)); |
183 | 222 | double factor = speed / (1f + speed * Math.sqrt(swinging)); | 245 | double factor = speed / (1f + speed * Math.sqrt(swinging)); |
185 | 223 | 246 | ||
186 | 224 | double x = nData.x() + nLayout.dx * factor; | 247 | double x = nData.x() + nLayout.dx * factor; |
187 | 225 | double y = nData.y() + nLayout.dy * factor; | 248 | double y = nData.y() + nLayout.dy * factor; |
188 | 226 | 249 | ||
189 | @@ -242,6 +265,7 @@ | |||
190 | 242 | for (Node n : graph.getNodes()) { | 265 | for (Node n : graph.getNodes()) { |
191 | 243 | n.getNodeData().setLayoutData(null); | 266 | n.getNodeData().setLayoutData(null); |
192 | 244 | } | 267 | } |
193 | 268 | pool.shutdown(); | ||
194 | 245 | graph.readUnlockAll(); | 269 | graph.readUnlockAll(); |
195 | 246 | } | 270 | } |
196 | 247 | 271 | ||
197 | @@ -251,6 +275,7 @@ | |||
198 | 251 | final String FORCEATLAS2_TUNING = NbBundle.getMessage(getClass(), "ForceAtlas2.tuning"); | 275 | final String FORCEATLAS2_TUNING = NbBundle.getMessage(getClass(), "ForceAtlas2.tuning"); |
199 | 252 | final String FORCEATLAS2_BEHAVIOR = NbBundle.getMessage(getClass(), "ForceAtlas2.behavior"); | 276 | final String FORCEATLAS2_BEHAVIOR = NbBundle.getMessage(getClass(), "ForceAtlas2.behavior"); |
200 | 253 | final String FORCEATLAS2_PERFORMANCE = NbBundle.getMessage(getClass(), "ForceAtlas2.performance"); | 277 | final String FORCEATLAS2_PERFORMANCE = NbBundle.getMessage(getClass(), "ForceAtlas2.performance"); |
201 | 278 | final String FORCEATLAS2_THREADS = NbBundle.getMessage(getClass(), "ForceAtlas2.threads"); | ||
202 | 254 | 279 | ||
203 | 255 | try { | 280 | try { |
204 | 256 | properties.add(LayoutProperty.createProperty( | 281 | properties.add(LayoutProperty.createProperty( |
205 | @@ -261,6 +286,13 @@ | |||
206 | 261 | "getScalingRatio", "setScalingRatio")); | 286 | "getScalingRatio", "setScalingRatio")); |
207 | 262 | 287 | ||
208 | 263 | properties.add(LayoutProperty.createProperty( | 288 | properties.add(LayoutProperty.createProperty( |
209 | 289 | this, Boolean.class, | ||
210 | 290 | NbBundle.getMessage(getClass(), "ForceAtlas2.strongGravityMode.name"), | ||
211 | 291 | FORCEATLAS2_TUNING, | ||
212 | 292 | NbBundle.getMessage(getClass(), "ForceAtlas2.strongGravityMode.desc"), | ||
213 | 293 | "isStrongGravityMode", "setStrongGravityMode")); | ||
214 | 294 | |||
215 | 295 | properties.add(LayoutProperty.createProperty( | ||
216 | 264 | this, Double.class, | 296 | this, Double.class, |
217 | 265 | NbBundle.getMessage(getClass(), "ForceAtlas2.gravity.name"), | 297 | NbBundle.getMessage(getClass(), "ForceAtlas2.gravity.name"), |
218 | 266 | FORCEATLAS2_TUNING, | 298 | FORCEATLAS2_TUNING, |
219 | @@ -315,6 +347,13 @@ | |||
220 | 315 | FORCEATLAS2_PERFORMANCE, | 347 | FORCEATLAS2_PERFORMANCE, |
221 | 316 | NbBundle.getMessage(getClass(), "ForceAtlas2.barnesHutTheta.desc"), | 348 | NbBundle.getMessage(getClass(), "ForceAtlas2.barnesHutTheta.desc"), |
222 | 317 | "getBarnesHutTheta", "setBarnesHutTheta")); | 349 | "getBarnesHutTheta", "setBarnesHutTheta")); |
223 | 350 | |||
224 | 351 | properties.add(LayoutProperty.createProperty( | ||
225 | 352 | this, Integer.class, | ||
226 | 353 | NbBundle.getMessage(getClass(), "ForceAtlas2.threads.name"), | ||
227 | 354 | FORCEATLAS2_THREADS, | ||
228 | 355 | NbBundle.getMessage(getClass(), "ForceAtlas2.threads.desc"), | ||
229 | 356 | "getThreadsCount", "setThreadsCount")); | ||
230 | 318 | 357 | ||
231 | 319 | } catch (Exception e) { | 358 | } catch (Exception e) { |
232 | 320 | e.printStackTrace(); | 359 | e.printStackTrace(); |
233 | @@ -337,6 +376,7 @@ | |||
234 | 337 | } else { | 376 | } else { |
235 | 338 | setScalingRatio(10.0); | 377 | setScalingRatio(10.0); |
236 | 339 | } | 378 | } |
237 | 379 | setStrongGravityMode(false); | ||
238 | 340 | setGravity(1.); | 380 | setGravity(1.); |
239 | 341 | 381 | ||
240 | 342 | // Behavior | 382 | // Behavior |
241 | @@ -359,6 +399,7 @@ | |||
242 | 359 | setBarnesHutOptimize(false); | 399 | setBarnesHutOptimize(false); |
243 | 360 | } | 400 | } |
244 | 361 | setBarnesHutTheta(1.2); | 401 | setBarnesHutTheta(1.2); |
245 | 402 | setThreadsCount(2); | ||
246 | 362 | } | 403 | } |
247 | 363 | 404 | ||
248 | 364 | @Override | 405 | @Override |
249 | @@ -418,6 +459,14 @@ | |||
250 | 418 | this.scalingRatio = scalingRatio; | 459 | this.scalingRatio = scalingRatio; |
251 | 419 | } | 460 | } |
252 | 420 | 461 | ||
253 | 462 | public Boolean isStrongGravityMode() { | ||
254 | 463 | return strongGravityMode; | ||
255 | 464 | } | ||
256 | 465 | |||
257 | 466 | public void setStrongGravityMode(Boolean strongGravityMode) { | ||
258 | 467 | this.strongGravityMode = strongGravityMode; | ||
259 | 468 | } | ||
260 | 469 | |||
261 | 421 | public Double getGravity() { | 470 | public Double getGravity() { |
262 | 422 | return gravity; | 471 | return gravity; |
263 | 423 | } | 472 | } |
264 | @@ -425,6 +474,18 @@ | |||
265 | 425 | public void setGravity(Double gravity) { | 474 | public void setGravity(Double gravity) { |
266 | 426 | this.gravity = gravity; | 475 | this.gravity = gravity; |
267 | 427 | } | 476 | } |
268 | 477 | |||
269 | 478 | public Integer getThreadsCount() { | ||
270 | 479 | return threadCount; | ||
271 | 480 | } | ||
272 | 481 | |||
273 | 482 | public void setThreadsCount(Integer threadCount) { | ||
274 | 483 | if(threadCount<1){ | ||
275 | 484 | setThreadsCount(1); | ||
276 | 485 | } else { | ||
277 | 486 | this.threadCount = threadCount; | ||
278 | 487 | } | ||
279 | 488 | } | ||
280 | 428 | 489 | ||
281 | 429 | public Boolean isOutboundAttractionDistribution() { | 490 | public Boolean isOutboundAttractionDistribution() { |
282 | 430 | return outboundAttractionDistribution; | 491 | return outboundAttractionDistribution; |
283 | 431 | 492 | ||
284 | === modified file 'LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/ForceFactory.java' | |||
285 | --- LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/ForceFactory.java 2011-06-05 21:30:01 +0000 | |||
286 | +++ LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/ForceFactory.java 2011-08-30 14:28:25 +0000 | |||
287 | @@ -22,6 +22,7 @@ | |||
288 | 22 | 22 | ||
289 | 23 | import org.gephi.graph.api.Node; | 23 | import org.gephi.graph.api.Node; |
290 | 24 | import org.gephi.graph.api.NodeData; | 24 | import org.gephi.graph.api.NodeData; |
291 | 25 | import org.openide.util.Exceptions; | ||
292 | 25 | 26 | ||
293 | 26 | /** | 27 | /** |
294 | 27 | * Generates the forces on demand, here are all the formulas for attraction and repulsion. | 28 | * Generates the forces on demand, here are all the formulas for attraction and repulsion. |
295 | @@ -43,6 +44,10 @@ | |||
296 | 43 | return new linRepulsion(coefficient); | 44 | return new linRepulsion(coefficient); |
297 | 44 | } | 45 | } |
298 | 45 | } | 46 | } |
299 | 47 | |||
300 | 48 | public RepulsionForce getStrongGravity(double coefficient){ | ||
301 | 49 | return new strongGravity(coefficient); | ||
302 | 50 | } | ||
303 | 46 | 51 | ||
304 | 47 | public AttractionForce buildAttraction(boolean logAttraction, boolean distributedAttraction, boolean adjustBySize, double coefficient) { | 52 | public AttractionForce buildAttraction(boolean logAttraction, boolean distributedAttraction, boolean adjustBySize, double coefficient) { |
305 | 48 | if (adjustBySize) { | 53 | if (adjustBySize) { |
306 | @@ -75,7 +80,7 @@ | |||
307 | 75 | } | 80 | } |
308 | 76 | } | 81 | } |
309 | 77 | } | 82 | } |
311 | 78 | 83 | ||
312 | 79 | public abstract class AttractionForce { | 84 | public abstract class AttractionForce { |
313 | 80 | 85 | ||
314 | 81 | public abstract void apply(Node n1, Node n2, double e); // Model for node-node attraction (e is for edge weight if needed) | 86 | public abstract void apply(Node n1, Node n2, double e); // Model for node-node attraction (e is for edge weight if needed) |
315 | @@ -141,7 +146,7 @@ | |||
316 | 141 | 146 | ||
317 | 142 | nLayout.dx += xDist * factor; | 147 | nLayout.dx += xDist * factor; |
318 | 143 | nLayout.dy += yDist * factor; | 148 | nLayout.dy += yDist * factor; |
320 | 144 | } | 149 | } |
321 | 145 | } | 150 | } |
322 | 146 | 151 | ||
323 | 147 | @Override | 152 | @Override |
324 | @@ -165,7 +170,7 @@ | |||
325 | 165 | } | 170 | } |
326 | 166 | 171 | ||
327 | 167 | /* | 172 | /* |
329 | 168 | * Repulsion force: Linear with Anti-collision | 173 | * Repulsion force: Strong Gravity (as a Repulsion Force because it is easier) |
330 | 169 | */ | 174 | */ |
331 | 170 | private class linRepulsion_antiCollision extends RepulsionForce { | 175 | private class linRepulsion_antiCollision extends RepulsionForce { |
332 | 171 | 176 | ||
333 | @@ -252,6 +257,44 @@ | |||
334 | 252 | } | 257 | } |
335 | 253 | } | 258 | } |
336 | 254 | 259 | ||
337 | 260 | private class strongGravity extends RepulsionForce { | ||
338 | 261 | |||
339 | 262 | private double coefficient; | ||
340 | 263 | |||
341 | 264 | public strongGravity(double c) { | ||
342 | 265 | coefficient = c; | ||
343 | 266 | } | ||
344 | 267 | |||
345 | 268 | @Override | ||
346 | 269 | public void apply(Node n1, Node n2) { | ||
347 | 270 | // Not Relevant | ||
348 | 271 | } | ||
349 | 272 | |||
350 | 273 | @Override | ||
351 | 274 | public void apply(Node n, Region r) { | ||
352 | 275 | // Not Relevant | ||
353 | 276 | } | ||
354 | 277 | |||
355 | 278 | @Override | ||
356 | 279 | public void apply(Node n, double g) { | ||
357 | 280 | NodeData nData = n.getNodeData(); | ||
358 | 281 | ForceAtlas2LayoutData nLayout = nData.getLayoutData(); | ||
359 | 282 | |||
360 | 283 | // Get the distance | ||
361 | 284 | double xDist = nData.x(); | ||
362 | 285 | double yDist = nData.y(); | ||
363 | 286 | double distance = (float) Math.sqrt(xDist * xDist + yDist * yDist); | ||
364 | 287 | |||
365 | 288 | if (distance > 0) { | ||
366 | 289 | // NB: factor = force / distance | ||
367 | 290 | double factor = coefficient * nLayout.mass * g; | ||
368 | 291 | |||
369 | 292 | nLayout.dx -= xDist * factor; | ||
370 | 293 | nLayout.dy -= yDist * factor; | ||
371 | 294 | } | ||
372 | 295 | } | ||
373 | 296 | } | ||
374 | 297 | |||
375 | 255 | /* | 298 | /* |
376 | 256 | * Attraction force: Linear | 299 | * Attraction force: Linear |
377 | 257 | */ | 300 | */ |
378 | 258 | 301 | ||
379 | === added file 'LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/NodesThread.java' | |||
380 | --- LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/NodesThread.java 1970-01-01 00:00:00 +0000 | |||
381 | +++ LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/NodesThread.java 2011-08-30 14:28:25 +0000 | |||
382 | @@ -0,0 +1,64 @@ | |||
383 | 1 | /* | ||
384 | 2 | * To change this template, choose Tools | Templates | ||
385 | 3 | * and open the template in the editor. | ||
386 | 4 | */ | ||
387 | 5 | package org.gephi.layout.plugin.forceAtlas2; | ||
388 | 6 | |||
389 | 7 | import org.gephi.graph.api.Node; | ||
390 | 8 | import org.gephi.layout.plugin.forceAtlas2.ForceFactory.RepulsionForce; | ||
391 | 9 | |||
392 | 10 | /** | ||
393 | 11 | * | ||
394 | 12 | * @author Mathieu | ||
395 | 13 | */ | ||
396 | 14 | public class NodesThread implements Runnable{ | ||
397 | 15 | private Node[] nodes; | ||
398 | 16 | private int from; | ||
399 | 17 | private int to; | ||
400 | 18 | private Region rootRegion; | ||
401 | 19 | private boolean barnesHutOptimize; | ||
402 | 20 | private RepulsionForce Repulsion; | ||
403 | 21 | private double barnesHutTheta; | ||
404 | 22 | private double gravity; | ||
405 | 23 | private RepulsionForce GravityForce; | ||
406 | 24 | private double scaling; | ||
407 | 25 | |||
408 | 26 | public NodesThread(Node[] nodes, int from, int to, boolean barnesHutOptimize, double barnesHutTheta, double gravity, RepulsionForce GravityForce, double scaling, Region rootRegion, RepulsionForce Repulsion){ | ||
409 | 27 | this.nodes = nodes; | ||
410 | 28 | this.from = from; | ||
411 | 29 | this.to = to; | ||
412 | 30 | this.rootRegion = rootRegion; | ||
413 | 31 | this.barnesHutOptimize = barnesHutOptimize; | ||
414 | 32 | this.Repulsion = Repulsion; | ||
415 | 33 | this.barnesHutTheta = barnesHutTheta; | ||
416 | 34 | this.gravity = gravity; | ||
417 | 35 | this.GravityForce = GravityForce; | ||
418 | 36 | this.scaling = scaling; | ||
419 | 37 | } | ||
420 | 38 | |||
421 | 39 | @Override | ||
422 | 40 | public void run() { | ||
423 | 41 | // Repulsion | ||
424 | 42 | if (barnesHutOptimize) { | ||
425 | 43 | for (int nIndex = from; nIndex < to; nIndex++) { | ||
426 | 44 | Node n = nodes[nIndex]; | ||
427 | 45 | rootRegion.applyForce(n, Repulsion, barnesHutTheta); | ||
428 | 46 | } | ||
429 | 47 | } else { | ||
430 | 48 | for (int n1Index = from; n1Index < to; n1Index++) { | ||
431 | 49 | Node n1 = nodes[n1Index]; | ||
432 | 50 | for (int n2Index = 0; n2Index < n1Index; n2Index++) { | ||
433 | 51 | Node n2 = nodes[n2Index]; | ||
434 | 52 | Repulsion.apply(n1, n2); | ||
435 | 53 | } | ||
436 | 54 | } | ||
437 | 55 | } | ||
438 | 56 | |||
439 | 57 | // Gravity | ||
440 | 58 | for (int nIndex = from; nIndex < to; nIndex++) { | ||
441 | 59 | Node n = nodes[nIndex]; | ||
442 | 60 | GravityForce.apply(n, gravity / scaling); | ||
443 | 61 | } | ||
444 | 62 | } | ||
445 | 63 | |||
446 | 64 | } | ||
447 | 0 | 65 | ||
448 | === added file 'LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Operation.java' | |||
449 | --- LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Operation.java 1970-01-01 00:00:00 +0000 | |||
450 | +++ LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Operation.java 2011-08-30 14:28:25 +0000 | |||
451 | @@ -0,0 +1,13 @@ | |||
452 | 1 | /* | ||
453 | 2 | * To change this template, choose Tools | Templates | ||
454 | 3 | * and open the template in the editor. | ||
455 | 4 | */ | ||
456 | 5 | package org.gephi.layout.plugin.forceAtlas2; | ||
457 | 6 | |||
458 | 7 | /** | ||
459 | 8 | * | ||
460 | 9 | * @author Mathieu | ||
461 | 10 | */ | ||
462 | 11 | public abstract class Operation { | ||
463 | 12 | public abstract void execute(); | ||
464 | 13 | } | ||
465 | 0 | 14 | ||
466 | === added file 'LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeNodeAttract.java' | |||
467 | --- LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeNodeAttract.java 1970-01-01 00:00:00 +0000 | |||
468 | +++ LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeNodeAttract.java 2011-08-30 14:28:25 +0000 | |||
469 | @@ -0,0 +1,32 @@ | |||
470 | 1 | /* | ||
471 | 2 | * To change this template, choose Tools | Templates | ||
472 | 3 | * and open the template in the editor. | ||
473 | 4 | */ | ||
474 | 5 | package org.gephi.layout.plugin.forceAtlas2; | ||
475 | 6 | |||
476 | 7 | import org.gephi.graph.api.Node; | ||
477 | 8 | import org.gephi.layout.plugin.forceAtlas2.ForceFactory.AttractionForce; | ||
478 | 9 | |||
479 | 10 | /** | ||
480 | 11 | * | ||
481 | 12 | * @author Mathieu | ||
482 | 13 | */ | ||
483 | 14 | public class OperationNodeNodeAttract extends Operation{ | ||
484 | 15 | private Node n1; | ||
485 | 16 | private Node n2; | ||
486 | 17 | private AttractionForce f; | ||
487 | 18 | private double coefficient; | ||
488 | 19 | |||
489 | 20 | public OperationNodeNodeAttract(Node n1, Node n2, AttractionForce f, double coefficient){ | ||
490 | 21 | this.n1 = n1; | ||
491 | 22 | this.n2 = n2; | ||
492 | 23 | this.f = f; | ||
493 | 24 | this.coefficient = coefficient; | ||
494 | 25 | } | ||
495 | 26 | |||
496 | 27 | @Override | ||
497 | 28 | public void execute() { | ||
498 | 29 | f.apply(n1, n2, coefficient); | ||
499 | 30 | } | ||
500 | 31 | |||
501 | 32 | } | ||
502 | 0 | 33 | ||
503 | === added file 'LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeNodeRepulse.java' | |||
504 | --- LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeNodeRepulse.java 1970-01-01 00:00:00 +0000 | |||
505 | +++ LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeNodeRepulse.java 2011-08-30 14:28:25 +0000 | |||
506 | @@ -0,0 +1,29 @@ | |||
507 | 1 | /* | ||
508 | 2 | * To change this template, choose Tools | Templates | ||
509 | 3 | * and open the template in the editor. | ||
510 | 4 | */ | ||
511 | 5 | package org.gephi.layout.plugin.forceAtlas2; | ||
512 | 6 | |||
513 | 7 | import org.gephi.graph.api.Node; | ||
514 | 8 | import org.gephi.layout.plugin.forceAtlas2.ForceFactory.RepulsionForce; | ||
515 | 9 | |||
516 | 10 | /** | ||
517 | 11 | * | ||
518 | 12 | * @author Mathieu | ||
519 | 13 | */ | ||
520 | 14 | public class OperationNodeNodeRepulse extends Operation{ | ||
521 | 15 | private Node n1; | ||
522 | 16 | private Node n2; | ||
523 | 17 | private RepulsionForce f; | ||
524 | 18 | |||
525 | 19 | public OperationNodeNodeRepulse(Node n1, Node n2, RepulsionForce f){ | ||
526 | 20 | this.n1 = n1; | ||
527 | 21 | this.n2 = n2; | ||
528 | 22 | this.f = f; | ||
529 | 23 | } | ||
530 | 24 | |||
531 | 25 | @Override | ||
532 | 26 | public void execute() { | ||
533 | 27 | f.apply(n1, n2); | ||
534 | 28 | } | ||
535 | 29 | } | ||
536 | 0 | 30 | ||
537 | === added file 'LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeRegionRepulse.java' | |||
538 | --- LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeRegionRepulse.java 1970-01-01 00:00:00 +0000 | |||
539 | +++ LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeRegionRepulse.java 2011-08-30 14:28:25 +0000 | |||
540 | @@ -0,0 +1,32 @@ | |||
541 | 1 | /* | ||
542 | 2 | * To change this template, choose Tools | Templates | ||
543 | 3 | * and open the template in the editor. | ||
544 | 4 | */ | ||
545 | 5 | package org.gephi.layout.plugin.forceAtlas2; | ||
546 | 6 | |||
547 | 7 | import org.gephi.graph.api.Node; | ||
548 | 8 | import org.gephi.layout.plugin.forceAtlas2.ForceFactory.RepulsionForce; | ||
549 | 9 | |||
550 | 10 | /** | ||
551 | 11 | * | ||
552 | 12 | * @author Mathieu | ||
553 | 13 | */ | ||
554 | 14 | public class OperationNodeRegionRepulse extends Operation{ | ||
555 | 15 | private Node n; | ||
556 | 16 | private Region r; | ||
557 | 17 | private RepulsionForce f; | ||
558 | 18 | private double theta; | ||
559 | 19 | |||
560 | 20 | public OperationNodeRegionRepulse(Node n, Region r, RepulsionForce f, double theta){ | ||
561 | 21 | this.n = n; | ||
562 | 22 | this.f = f; | ||
563 | 23 | this.r = r; | ||
564 | 24 | this.theta = theta; | ||
565 | 25 | } | ||
566 | 26 | |||
567 | 27 | @Override | ||
568 | 28 | public void execute() { | ||
569 | 29 | r.applyForce(n, f, theta); | ||
570 | 30 | } | ||
571 | 31 | |||
572 | 32 | } | ||
573 | 0 | 33 | ||
574 | === added file 'LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeRepulse.java' | |||
575 | --- LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeRepulse.java 1970-01-01 00:00:00 +0000 | |||
576 | +++ LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeRepulse.java 2011-08-30 14:28:25 +0000 | |||
577 | @@ -0,0 +1,29 @@ | |||
578 | 1 | /* | ||
579 | 2 | * To change this template, choose Tools | Templates | ||
580 | 3 | * and open the template in the editor. | ||
581 | 4 | */ | ||
582 | 5 | package org.gephi.layout.plugin.forceAtlas2; | ||
583 | 6 | |||
584 | 7 | import org.gephi.graph.api.Node; | ||
585 | 8 | import org.gephi.layout.plugin.forceAtlas2.ForceFactory.RepulsionForce; | ||
586 | 9 | |||
587 | 10 | /** | ||
588 | 11 | * | ||
589 | 12 | * @author Mathieu | ||
590 | 13 | */ | ||
591 | 14 | public class OperationNodeRepulse extends Operation{ | ||
592 | 15 | private Node n; | ||
593 | 16 | private RepulsionForce f; | ||
594 | 17 | private double coefficient; | ||
595 | 18 | |||
596 | 19 | public OperationNodeRepulse(Node n, RepulsionForce f, double coefficient){ | ||
597 | 20 | this.n = n; | ||
598 | 21 | this.f = f; | ||
599 | 22 | this.coefficient = coefficient; | ||
600 | 23 | } | ||
601 | 24 | |||
602 | 25 | @Override | ||
603 | 26 | public void execute() { | ||
604 | 27 | f.apply(n, coefficient); | ||
605 | 28 | } | ||
606 | 29 | } | ||
607 | 0 | 30 | ||
608 | === modified file 'LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Region.java' | |||
609 | --- LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Region.java 2011-06-05 21:30:01 +0000 | |||
610 | +++ LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Region.java 2011-08-30 14:28:25 +0000 | |||
611 | @@ -51,7 +51,7 @@ | |||
612 | 51 | updateMassAndGeometry(); | 51 | updateMassAndGeometry(); |
613 | 52 | } | 52 | } |
614 | 53 | 53 | ||
616 | 54 | public void updateMassAndGeometry() { | 54 | private void updateMassAndGeometry() { |
617 | 55 | if (nodes.size() > 1) { | 55 | if (nodes.size() > 1) { |
618 | 56 | // Compute Mass | 56 | // Compute Mass |
619 | 57 | mass = 0; | 57 | mass = 0; |
620 | @@ -77,7 +77,7 @@ | |||
621 | 77 | } | 77 | } |
622 | 78 | } | 78 | } |
623 | 79 | 79 | ||
625 | 80 | public void buildSubRegions() { | 80 | public synchronized void buildSubRegions() { |
626 | 81 | if (nodes.size() > 1) { | 81 | if (nodes.size() > 1) { |
627 | 82 | ArrayList<Node> leftNodes = new ArrayList<Node>(); | 82 | ArrayList<Node> leftNodes = new ArrayList<Node>(); |
628 | 83 | ArrayList<Node> rightNodes = new ArrayList<Node>(); | 83 | ArrayList<Node> rightNodes = new ArrayList<Node>(); |