gephi.team team mailing list archive
-
gephi.team team
-
Mailing list archive
-
Message #02215
[Merge] lp:~mathieu-jacomy/gephi/forceatlas2-multithread into lp:gephi
Mathieu Bastian has proposed merging lp:~mathieu-jacomy/gephi/forceatlas2-multithread into lp:gephi.
Requested reviews:
Mathieu Bastian (mathieu.bastian)
For more details, see:
https://code.launchpad.net/~mathieu-jacomy/gephi/forceatlas2-multithread/+merge/69478
Multithread version of ForceAtlas2
--
https://code.launchpad.net/~mathieu-jacomy/gephi/forceatlas2-multithread/+merge/69478
Your team Gephi Team is subscribed to branch lp:gephi.
=== modified file 'LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Bundle.properties'
--- LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Bundle.properties 2011-06-05 21:30:01 +0000
+++ LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Bundle.properties 2011-07-27 14:56:45 +0000
@@ -4,6 +4,7 @@
ForceAtlas2.tuning=Tuning
ForceAtlas2.behavior=Behavior Alternatives
ForceAtlas2.performance=Performance
+ForceAtlas2.threads=Threads
ForceAtlas2.scalingRatio.name=Scaling
ForceAtlas2.scalingRatio.desc=How much repulsion you want. More makes a more sparse graph.
@@ -23,3 +24,5 @@
ForceAtlas2.barnesHutTheta.desc=Theta of the Barnes Hut optimization.
ForceAtlas2.edgeWeightInfluence.name=Edge Weight Influence
ForceAtlas2.edgeWeightInfluence.desc=How much influence you give to the edges weight. 0 is "no influence" and 1 is "normal".
+ForceAtlas2.threads.name=Threads number
+ForceAtlas2.threads.desc=More threads means more speed if your cores can handle it.
=== modified file 'LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Bundle_fr.properties'
--- LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Bundle_fr.properties 2011-06-05 21:30:01 +0000
+++ LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Bundle_fr.properties 2011-07-27 14:56:45 +0000
@@ -4,6 +4,7 @@
ForceAtlas2.tuning=R\u00e9glages fins
ForceAtlas2.behavior=Options de comportement
ForceAtlas2.performance=Performances
+ForceAtlas2.threads=Processus
ForceAtlas2.scalingRatio.name=Dimensionnement
ForceAtlas2.scalingRatio.desc=Quantit\u00e9 de r\u00e9pulsion, par rapport \u00e0 l'attraction. Rend le graphe plus \u00e9tal\u00e9.
@@ -23,3 +24,5 @@
ForceAtlas2.barnesHutTheta.desc=param\u00e8tre Theta de l'optimisation de Barnes Hut.
ForceAtlas2.edgeWeightInfluence.name=Influence Poids des liens
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.
+ForceAtlas2.threads.name=Nb. processus
+ForceAtlas2.threads.desc=Plus de processus multiplient les performances si vos processeurs peuvent les supporter.
=== modified file 'LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/ForceAtlas2.java'
--- LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/ForceAtlas2.java 2011-06-05 21:30:01 +0000
+++ LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/ForceAtlas2.java 2011-07-27 14:56:45 +0000
@@ -22,6 +22,9 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
import org.gephi.data.attributes.type.TimeInterval;
import org.gephi.dynamic.DynamicUtilities;
import org.gephi.dynamic.api.DynamicController;
@@ -37,6 +40,7 @@
import org.gephi.layout.spi.LayoutBuilder;
import org.gephi.layout.spi.LayoutProperty;
import org.gephi.project.api.Workspace;
+import org.openide.util.Exceptions;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
@@ -60,6 +64,7 @@
private boolean barnesHutOptimize;
private double barnesHutTheta;
private boolean linLogMode;
+ private int threadCount;
private Region rootRegion;
double outboundAttCompensation = 1;
//Dynamic Weight
@@ -142,31 +147,72 @@
// Repulsion
RepulsionForce Repulsion = ForceFactory.builder.buildRepulsion(isAdjustSizes(), getScalingRatio());
+
+ BlockingQueue<Operation> queue = new LinkedBlockingQueue();
+ ArrayList<ForceThread> threads = new ArrayList();
+ for(int t=threadCount; t>0; t--){
+ threads.add(new ForceThread(queue));
+ }
+ for(ForceThread t:threads){
+ t.start();
+ }
+
if (isBarnesHutOptimize()) {
for (Node n : nodes) {
- rootRegion.applyForce(n, Repulsion, getBarnesHutTheta());
+ //rootRegion.applyForce(n, Repulsion, getBarnesHutTheta());
+ try {
+ queue.put(new OperationNodeRegionRepulse(n, rootRegion, Repulsion, getBarnesHutTheta()));
+ } catch (InterruptedException ex) {
+ Exceptions.printStackTrace(ex);
+ }
}
} else {
for (int n1Index = 0; n1Index < nodes.length; n1Index++) {
Node n1 = nodes[n1Index];
- for (int n2Index = 0; n2Index < n1Index; n2Index++) {
- Node n2 = nodes[n2Index];
- Repulsion.apply(n1, n2);
+ for (int n2Index = 0; n2Index < n1Index; n2Index++) {
+ Node n2 = nodes[n2Index];
+ //Repulsion.apply(n1, n2);
+ try {
+ queue.put(new OperationNodeNodeRepulse(n1, n2, Repulsion));
+ } catch (InterruptedException ex) {
+ Exceptions.printStackTrace(ex);
+ }
}
}
}
-
+
// Attraction
AttractionForce Attraction = ForceFactory.builder.buildAttraction(isLinLogMode(), isOutboundAttractionDistribution(), isAdjustSizes(), 1 * ((isOutboundAttractionDistribution()) ? (outboundAttCompensation) : (1)));
for (Edge e : edges) {
- Attraction.apply(e.getSource(), e.getTarget(), Math.pow(getWeight(e), getEdgeWeightInfluence()));
+ //Attraction.apply(e.getSource(), e.getTarget(), Math.pow(getWeight(e), getEdgeWeightInfluence()));
+ try {
+ queue.put(new OperationNodeNodeAttract(e.getSource(), e.getTarget(), Attraction, Math.pow(getWeight(e), getEdgeWeightInfluence())));
+ } catch (InterruptedException ex) {
+ Exceptions.printStackTrace(ex);
+ }
}
// Gravity
for (Node n : nodes) {
- Repulsion.apply(n, getGravity() / getScalingRatio());
+ //Repulsion.apply(n, getGravity() / getScalingRatio());
+ try {
+ queue.put(new OperationNodeRepulse(n, Repulsion, getGravity() / getScalingRatio()));
+ } catch (InterruptedException ex) {
+ Exceptions.printStackTrace(ex);
+ }
}
+ for(ForceThread t:threads){
+ t.setAllPushed();
+ }
+ try {
+ for(ForceThread t:threads){
+ t.join();
+ }
+ } catch (InterruptedException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+
// Auto adjust speed
double totalSwinging = 0d; // How much irregular movement
double totalEffectiveTraction = 0d; // Hom much useful movement
@@ -198,10 +244,10 @@
// when the node swings.
double swinging = Math.sqrt((nLayout.old_dx - nLayout.dx) * (nLayout.old_dx - nLayout.dx) + (nLayout.old_dy - nLayout.dy) * (nLayout.old_dy - nLayout.dy));
double factor = 0.1 * speed / (1f + speed * Math.sqrt(swinging));
-
+
double df = Math.sqrt(Math.pow(nLayout.dx, 2) + Math.pow(nLayout.dy, 2));
factor = Math.min(factor * df, 10.) / df;
-
+
double x = nData.x() + nLayout.dx * factor;
double y = nData.y() + nLayout.dy * factor;
@@ -220,7 +266,7 @@
double swinging = Math.sqrt((nLayout.old_dx - nLayout.dx) * (nLayout.old_dx - nLayout.dx) + (nLayout.old_dy - nLayout.dy) * (nLayout.old_dy - nLayout.dy));
//double factor = speed / (1f + Math.sqrt(speed * swinging));
double factor = speed / (1f + speed * Math.sqrt(swinging));
-
+
double x = nData.x() + nLayout.dx * factor;
double y = nData.y() + nLayout.dy * factor;
@@ -251,6 +297,7 @@
final String FORCEATLAS2_TUNING = NbBundle.getMessage(getClass(), "ForceAtlas2.tuning");
final String FORCEATLAS2_BEHAVIOR = NbBundle.getMessage(getClass(), "ForceAtlas2.behavior");
final String FORCEATLAS2_PERFORMANCE = NbBundle.getMessage(getClass(), "ForceAtlas2.performance");
+ final String FORCEATLAS2_THREADS = NbBundle.getMessage(getClass(), "ForceAtlas2.threads");
try {
properties.add(LayoutProperty.createProperty(
@@ -315,6 +362,13 @@
FORCEATLAS2_PERFORMANCE,
NbBundle.getMessage(getClass(), "ForceAtlas2.barnesHutTheta.desc"),
"getBarnesHutTheta", "setBarnesHutTheta"));
+
+ properties.add(LayoutProperty.createProperty(
+ this, Integer.class,
+ NbBundle.getMessage(getClass(), "ForceAtlas2.threads.name"),
+ FORCEATLAS2_THREADS,
+ NbBundle.getMessage(getClass(), "ForceAtlas2.threads.desc"),
+ "getThreadsCount", "setThreadsCount"));
} catch (Exception e) {
e.printStackTrace();
@@ -359,6 +413,7 @@
setBarnesHutOptimize(false);
}
setBarnesHutTheta(1.2);
+ setThreadsCount(3);
}
@Override
@@ -425,6 +480,14 @@
public void setGravity(Double gravity) {
this.gravity = gravity;
}
+
+ public Integer getThreadsCount() {
+ return threadCount;
+ }
+
+ public void setThreadsCount(Integer threadCount) {
+ this.threadCount = threadCount;
+ }
public Boolean isOutboundAttractionDistribution() {
return outboundAttractionDistribution;
=== modified file 'LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/ForceFactory.java'
--- LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/ForceFactory.java 2011-06-05 21:30:01 +0000
+++ LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/ForceFactory.java 2011-07-27 14:56:45 +0000
@@ -22,6 +22,7 @@
import org.gephi.graph.api.Node;
import org.gephi.graph.api.NodeData;
+import org.openide.util.Exceptions;
/**
* Generates the forces on demand, here are all the formulas for attraction and repulsion.
@@ -141,7 +142,7 @@
nLayout.dx += xDist * factor;
nLayout.dy += yDist * factor;
- }
+ }
}
@Override
=== added file 'LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/ForceThread.java'
--- LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/ForceThread.java 1970-01-01 00:00:00 +0000
+++ LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/ForceThread.java 2011-07-27 14:56:45 +0000
@@ -0,0 +1,52 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.gephi.layout.plugin.forceAtlas2;
+
+import java.util.Stack;
+import java.util.concurrent.BlockingQueue;
+import org.gephi.graph.api.Node;
+import org.gephi.layout.plugin.forceAtlas2.ForceFactory.RepulsionForce;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author Mathieu
+ */
+public class ForceThread extends Thread{
+ private BlockingQueue<Operation> q;
+ private boolean allPushed = false;
+
+ public ForceThread(BlockingQueue<Operation> q) {
+ this.q = q;
+ }
+
+ public synchronized void run() {
+ while(!allPushed || !q.isEmpty()){
+ Operation o = q.poll();
+ while(o!=null){
+ o.execute();
+ o = q.poll();
+ }
+ try {
+ sleep(10);
+ } catch (InterruptedException ex) {
+ Exceptions.printStackTrace(ex);
+ }
+ }
+ return;
+ /*while(!allPushed || !q.isEmpty()){
+ try {
+ Operation o = q.take();
+ o.execute();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }*/
+ }
+
+ public void setAllPushed(){
+ allPushed = true;
+ }
+}
=== added file 'LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Operation.java'
--- LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Operation.java 1970-01-01 00:00:00 +0000
+++ LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Operation.java 2011-07-27 14:56:45 +0000
@@ -0,0 +1,13 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.gephi.layout.plugin.forceAtlas2;
+
+/**
+ *
+ * @author Mathieu
+ */
+public abstract class Operation {
+ public abstract void execute();
+}
=== added file 'LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeNodeAttract.java'
--- LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeNodeAttract.java 1970-01-01 00:00:00 +0000
+++ LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeNodeAttract.java 2011-07-27 14:56:45 +0000
@@ -0,0 +1,32 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.gephi.layout.plugin.forceAtlas2;
+
+import org.gephi.graph.api.Node;
+import org.gephi.layout.plugin.forceAtlas2.ForceFactory.AttractionForce;
+
+/**
+ *
+ * @author Mathieu
+ */
+public class OperationNodeNodeAttract extends Operation{
+ private Node n1;
+ private Node n2;
+ private AttractionForce f;
+ private double coefficient;
+
+ public OperationNodeNodeAttract(Node n1, Node n2, AttractionForce f, double coefficient){
+ this.n1 = n1;
+ this.n2 = n2;
+ this.f = f;
+ this.coefficient = coefficient;
+ }
+
+ @Override
+ public void execute() {
+ f.apply(n1, n2, coefficient);
+ }
+
+}
=== added file 'LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeNodeRepulse.java'
--- LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeNodeRepulse.java 1970-01-01 00:00:00 +0000
+++ LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeNodeRepulse.java 2011-07-27 14:56:45 +0000
@@ -0,0 +1,29 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.gephi.layout.plugin.forceAtlas2;
+
+import org.gephi.graph.api.Node;
+import org.gephi.layout.plugin.forceAtlas2.ForceFactory.RepulsionForce;
+
+/**
+ *
+ * @author Mathieu
+ */
+public class OperationNodeNodeRepulse extends Operation{
+ private Node n1;
+ private Node n2;
+ private RepulsionForce f;
+
+ public OperationNodeNodeRepulse(Node n1, Node n2, RepulsionForce f){
+ this.n1 = n1;
+ this.n2 = n2;
+ this.f = f;
+ }
+
+ @Override
+ public void execute() {
+ f.apply(n1, n2);
+ }
+}
=== added file 'LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeRegionRepulse.java'
--- LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeRegionRepulse.java 1970-01-01 00:00:00 +0000
+++ LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeRegionRepulse.java 2011-07-27 14:56:45 +0000
@@ -0,0 +1,32 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.gephi.layout.plugin.forceAtlas2;
+
+import org.gephi.graph.api.Node;
+import org.gephi.layout.plugin.forceAtlas2.ForceFactory.RepulsionForce;
+
+/**
+ *
+ * @author Mathieu
+ */
+public class OperationNodeRegionRepulse extends Operation{
+ private Node n;
+ private Region r;
+ private RepulsionForce f;
+ private double theta;
+
+ public OperationNodeRegionRepulse(Node n, Region r, RepulsionForce f, double theta){
+ this.n = n;
+ this.f = f;
+ this.r = r;
+ this.theta = theta;
+ }
+
+ @Override
+ public void execute() {
+ r.applyForce(n, f, theta);
+ }
+
+}
=== added file 'LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeRepulse.java'
--- LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeRepulse.java 1970-01-01 00:00:00 +0000
+++ LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/OperationNodeRepulse.java 2011-07-27 14:56:45 +0000
@@ -0,0 +1,29 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.gephi.layout.plugin.forceAtlas2;
+
+import org.gephi.graph.api.Node;
+import org.gephi.layout.plugin.forceAtlas2.ForceFactory.RepulsionForce;
+
+/**
+ *
+ * @author Mathieu
+ */
+public class OperationNodeRepulse extends Operation{
+ private Node n;
+ private RepulsionForce f;
+ private double coefficient;
+
+ public OperationNodeRepulse(Node n, RepulsionForce f, double coefficient){
+ this.n = n;
+ this.f = f;
+ this.coefficient = coefficient;
+ }
+
+ @Override
+ public void execute() {
+ f.apply(n, coefficient);
+ }
+}
=== modified file 'LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Region.java'
--- LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Region.java 2011-06-05 21:30:01 +0000
+++ LayoutPlugin/src/org/gephi/layout/plugin/forceAtlas2/Region.java 2011-07-27 14:56:45 +0000
@@ -51,7 +51,7 @@
updateMassAndGeometry();
}
- public void updateMassAndGeometry() {
+ public synchronized void updateMassAndGeometry() {
if (nodes.size() > 1) {
// Compute Mass
mass = 0;
@@ -77,7 +77,7 @@
}
}
- public void buildSubRegions() {
+ public synchronized void buildSubRegions() {
if (nodes.size() > 1) {
ArrayList<Node> leftNodes = new ArrayList<Node>();
ArrayList<Node> rightNodes = new ArrayList<Node>();