Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

FMEKernel.h
Go to the documentation of this file.
1 
32 #pragma once
33 
34 #include <ogdf/basic/basic.h>
38 
39 #include <list>
40 
41 namespace ogdf {
42 namespace fast_multipole_embedder {
43 
44 class FMEKernel {
45 public:
46  explicit FMEKernel(FMEThread* pThread) : m_pThread(pThread) { }
47 
48  inline void sync() { m_pThread->sync(); }
49 
51  inline uint32_t threadNr() const { return m_pThread->threadNr(); }
52 
54  inline uint32_t numThreads() const { return m_pThread->numThreads(); }
55 
57  inline bool isMainThread() const { return m_pThread->isMainThread(); }
58 
60  inline bool isSingleThreaded() const { return m_pThread->numThreads() == 1; };
61 
62 private:
64 };
65 
66 #define OGDF_FME_KERNEL_USE_OLD
67 
68 #define OGDF_FME_KERNEL_COMPUTE_FORCE_PROTECTION_FACTOR 0.25f
69 // makro for force computation via SSE s / max(s*0.5, (dx*dx + dy*dy))
70 #define OGDF_FME_KERNEL_MM_COMPUTE_FORCE(dx, dy, s) \
71  _mm_div_ps((s), \
72  _mm_max_ps(_mm_mul_ps((s), _mm_set1_ps(OGDF_FME_KERNEL_COMPUTE_FORCE_PROTECTION_FACTOR)), \
73  _mm_add_ps(_mm_mul_ps((dx), (dx)), _mm_mul_ps((dy), (dy)))))
74 #define OGDF_FME_KERNEL_COMPUTE_FORCE(dx, dy, s) \
75  (s / (max<float>(s * OGDF_FME_KERNEL_COMPUTE_FORCE_PROTECTION_FACTOR, (dx) * (dx) + (dy) * (dy))))
76 
77 inline double move_nodes(float* x, float* y, const uint32_t begin, const uint32_t end,
78  const float* fx, const float* fy, const float t) {
79  double dsq_max = 0.0;
80  for (uint32_t i = begin; i <= end; i++) {
81  double dsq = fx[i] * fx[i] + fy[i] * fy[i];
82  x[i] += fx[i] * t;
83  y[i] += fy[i] * t;
84  Math::updateMax(dsq_max, dsq);
85  }
86  return dsq_max;
87 }
88 
89 inline void eval_edges(const ArrayGraph& graph, const uint32_t begin, const uint32_t end, float* fx,
90  float* fy) {
91  const float* x = graph.nodeXPos();
92  const float* y = graph.nodeYPos();
93  const float* e = graph.desiredEdgeLength();
94  for (uint32_t i = begin; i <= end; i++) {
95  const auto& e_info = graph.edgeInfo(i);
96  const uint32_t a = e_info.a;
97  const uint32_t b = e_info.b;
98  const auto& a_info = graph.nodeInfo(a);
99  const auto& b_info = graph.nodeInfo(b);
100 
101  float dx = x[a] - x[b];
102  float dy = y[a] - y[b];
103  float dsq = dx * dx + dy * dy;
104  float f = dsq == 0 ? 0 : (logf(dsq) * 0.5f - logf(e[i])) * 0.25f;
105  float fa = (float)(f / ((float)a_info.degree));
106  float fb = (float)(f / ((float)b_info.degree));
107  fx[a] -= dx * fa;
108  fy[a] -= dy * fa;
109  fx[b] += dx * fb;
110  fy[b] += dy * fb;
111  }
112 }
113 
115 inline void eval_direct(float* x, float* y, float* s, float* fx, float* fy, size_t n) {
116  for (uint32_t i = 0; i < n; i++) {
117  for (uint32_t j = i + 1; j < n; j++) {
118  float dx = x[i] - x[j];
119  float dy = y[i] - y[j];
120 #ifdef OGDF_FME_KERNEL_USE_OLD
121  float s_sum = s[i] + s[j];
122 #else
123  float s_sum = s[i] * s[j];
124 #endif
125  float f = OGDF_FME_KERNEL_COMPUTE_FORCE(dx, dy, s_sum);
126  fx[i] += dx * f;
127  fy[i] += dy * f;
128  fx[j] -= dx * f;
129  fy[j] -= dy * f;
130  }
131  }
132 }
133 
135 inline void eval_direct(float* x1, float* y1, float* s1, float* fx1, float* fy1, size_t n1,
136  float* x2, float* y2, float* s2, float* fx2, float* fy2, size_t n2) {
137  for (uint32_t i = 0; i < n1; i++) {
138  for (uint32_t j = 0; j < n2; j++) {
139  float dx = x1[i] - x2[j];
140  float dy = y1[i] - y2[j];
141 #ifdef OGDF_FME_KERNEL_USE_OLD
142  float s_sum = s1[i] + s2[j];
143 #else
144  float s_sum = s1[i] * s2[j];
145 #endif
146  float f = OGDF_FME_KERNEL_COMPUTE_FORCE(dx, dy, s_sum);
147  fx1[i] += dx * f;
148  fy1[i] += dy * f;
149  fx2[j] -= dx * f;
150  fy2[j] -= dy * f;
151  }
152  }
153 }
154 
155 
156 #ifndef OGDF_FME_KERNEL_USE_SSE_DIRECT
157 inline void eval_direct_fast(float* x, float* y, float* s, float* fx, float* fy, size_t n) {
159  eval_direct(x, y, s, fx, fy, n);
160 }
161 
163 inline void eval_direct_fast(float* x1, float* y1, float* s1, float* fx1, float* fy1, size_t n1,
164  float* x2, float* y2, float* s2, float* fx2, float* fy2, size_t n2) {
165  eval_direct(x1, y1, s1, fx1, fy1, n1, x2, y2, s2, fx2, fy2, n2);
166 }
167 
168 #else
169 void eval_direct_fast(float* x, float* y, float* s, float* fx, float* fy, size_t n);
172 void eval_direct_fast(float* x1, float* y1, float* s1, float* fx1, float* fy1, size_t n1, float* x2,
173  float* y2, float* s2, float* fx2, float* fy2, size_t n2);
174 #endif
175 
177 void fast_multipole_l2p(double* localCoeffiecients, uint32_t numCoeffiecients, double centerX,
178  double centerY, float x, float y, float q, float& fx, float& fy);
179 
180 void fast_multipole_p2m(double* mulitCoeffiecients, uint32_t numCoeffiecients, double centerX,
181  double centerY, float x, float y, float q);
182 
184 public:
185  inline void edgeForces(const ArrayGraph& graph, float* fx, float* fy) {
186  eval_edges(graph, 0, graph.numEdges() - 1, fx, fy);
187  }
188 
189  inline void repForces(ArrayGraph& graph, float* fx, float* fy) {
190  eval_direct_fast(graph.nodeXPos(), graph.nodeYPos(), graph.nodeSize(), fx, fy,
191  graph.numNodes());
192  }
193 
194  inline double moveNodes(ArrayGraph& graph, float* fx, float* fy, float timeStep) {
195  return move_nodes(graph.nodeXPos(), graph.nodeYPos(), 0, graph.numNodes() - 1, fx, fy,
196  timeStep);
197  }
198 
199  inline double simpleIteration(ArrayGraph& graph, float* fx, float* fy, float timeStep) {
200  repForces(graph, fx, fy);
201  edgeForces(graph, fx, fy);
202  return moveNodes(graph, fx, fy, timeStep);
203  }
204 
205  inline double simpleEdgeIteration(ArrayGraph& graph, float* fx, float* fy, float timeStep) {
206  edgeForces(graph, fx, fy);
207  return moveNodes(graph, fx, fy, timeStep);
208  }
209 
210  inline void simpleForceDirected(ArrayGraph& graph, float timeStep, uint32_t minIt,
211  uint32_t maxIt, uint32_t preProcIt, double threshold) {
212  bool earlyExit = false;
213  float* fx = (float*)OGDF_MALLOC_16(sizeof(float) * graph.numNodes());
214  float* fy = (float*)OGDF_MALLOC_16(sizeof(float) * graph.numNodes());
215 
216  for (uint32_t i = 0; i < preProcIt; i++) {
217  for (uint32_t j = 0; j < graph.numNodes(); j++) {
218  fx[j] = 0.0f;
219  fy[j] = 0.0f;
220  }
221  simpleEdgeIteration(graph, fx, fy, timeStep);
222  }
223  for (uint32_t i = 0; i < maxIt && !earlyExit; i++) {
224  for (uint32_t j = 0; j < graph.numNodes(); j++) {
225  fx[j] = 0.0f;
226  fy[j] = 0.0f;
227  }
228  double dsq = simpleIteration(graph, fx, fy, timeStep);
229  if (dsq < threshold && i > (minIt)) {
230  earlyExit = true;
231  }
232  }
233 
234  OGDF_FREE_16(fx);
235  OGDF_FREE_16(fy);
236  }
237 
238 private:
239 };
240 
242 public:
243 #if 0
244  FMESingleKernel(FMEThread* pThread) : FMEKernel(pThread) {};
245 #endif
246 
247  void operator()(ArrayGraph& graph, float timeStep, uint32_t minIt, uint32_t maxIt,
248  double threshold) {
249  simpleForceDirected(graph, timeStep, minIt, maxIt, 20, threshold);
250  }
251 };
252 
253 }
254 }
ogdf
The namespace for all OGDF objects.
Definition: AugmentationModule.h:36
ogdf::fast_multipole_embedder::eval_edges
void eval_edges(const ArrayGraph &graph, const uint32_t begin, const uint32_t end, float *fx, float *fy)
Definition: FMEKernel.h:89
OGDF_FREE_16
#define OGDF_FREE_16(ptr)
16-byte aligned memory deallocation macro
Definition: FastUtils.h:119
ogdf::fast_multipole_embedder::FMEKernel::sync
void sync()
Definition: FMEKernel.h:48
ogdf::fast_multipole_embedder::fast_multipole_l2p
void fast_multipole_l2p(double *localCoeffiecients, uint32_t numCoeffiecients, double centerX, double centerY, float x, float y, float q, float &fx, float &fy)
kernel function to evalute a local expansion at point x,y result is added to fx, fy
ogdf::fast_multipole_embedder::ArrayGraph
Definition: ArrayGraph.h:40
ogdf::fast_multipole_embedder::FMEThread
The fast multipole embedder work thread class.
Definition: FMEThread.h:76
ogdf::fast_multipole_embedder::FMEBasicKernel::simpleForceDirected
void simpleForceDirected(ArrayGraph &graph, float timeStep, uint32_t minIt, uint32_t maxIt, uint32_t preProcIt, double threshold)
Definition: FMEKernel.h:210
ogdf::fast_multipole_embedder::FMEThread::isMainThread
bool isMainThread() const
returns true if this is the main thread ( the main thread is always the first thread )
Definition: FMEThread.h:89
ogdf::begin
HypergraphRegistry< HypernodeElement >::iterator begin(const HypergraphRegistry< HypernodeElement > &self)
ogdf::fast_multipole_embedder::EdgeAdjInfo::a
uint32_t a
First node of the pair.
Definition: EdgeChain.h:54
ogdf::fast_multipole_embedder::ArrayGraph::numNodes
uint32_t numNodes() const
Returns the number of nodes.
Definition: ArrayGraph.h:56
ogdf::fast_multipole_embedder::ArrayGraph::nodeXPos
float * nodeXPos()
Returns the x coord array for all nodes.
Definition: ArrayGraph.h:162
ogdf::fast_multipole_embedder::FMEBasicKernel::simpleEdgeIteration
double simpleEdgeIteration(ArrayGraph &graph, float *fx, float *fy, float timeStep)
Definition: FMEKernel.h:205
ArrayGraph.h
Declaration of class ArrayGraph.
OGDF_MALLOC_16
#define OGDF_MALLOC_16(s)
16-byte aligned memory allocation macro
Definition: FastUtils.h:116
ogdf::fast_multipole_embedder::FMESingleKernel
Definition: FMEKernel.h:241
FastUtils.h
Definition of utility functions for FME layout.
ogdf::fast_multipole_embedder::FMEKernel
Definition: FMEKernel.h:44
ogdf::fast_multipole_embedder::ArrayGraph::nodeInfo
NodeAdjInfo & nodeInfo(uint32_t i)
Returns the adjacency information for the node at index i in m_nodeAdj.
Definition: ArrayGraph.h:138
ogdf::fast_multipole_embedder::FMEBasicKernel::repForces
void repForces(ArrayGraph &graph, float *fx, float *fy)
Definition: FMEKernel.h:189
ogdf::fast_multipole_embedder::FMEBasicKernel::simpleIteration
double simpleIteration(ArrayGraph &graph, float *fx, float *fy, float timeStep)
Definition: FMEKernel.h:199
ogdf::fast_multipole_embedder::FMEThread::numThreads
uint32_t numThreads() const
returns the total number of threads in the pool
Definition: FMEThread.h:86
ogdf::fast_multipole_embedder::FMEBasicKernel
Definition: FMEKernel.h:183
ogdf::fast_multipole_embedder::eval_direct
void eval_direct(float *x, float *y, float *s, float *fx, float *fy, size_t n)
kernel function to evaluate forces between n points with coords x, y directly. result is stored in fx...
Definition: FMEKernel.h:115
ogdf::fast_multipole_embedder::ArrayGraph::desiredEdgeLength
float * desiredEdgeLength()
Returns the edge length array for all edges.
Definition: ArrayGraph.h:183
ogdf::fast_multipole_embedder::move_nodes
double move_nodes(float *x, float *y, const uint32_t begin, const uint32_t end, const float *fx, const float *fy, const float t)
Definition: FMEKernel.h:77
ogdf::fast_multipole_embedder::ArrayGraph::nodeSize
float * nodeSize()
Returns the node size array for all nodes.
Definition: ArrayGraph.h:174
ogdf::fast_multipole_embedder::FMEThread::sync
void sync()
thread sync call
ogdf::fast_multipole_embedder::ArrayGraph::nodeYPos
float * nodeYPos()
Returns the y coord array for all nodes.
Definition: ArrayGraph.h:168
ogdf::Math::updateMax
void updateMax(T &max, const T &newValue)
Stores the maximum of max and newValue in max.
Definition: Math.h:90
ogdf::fast_multipole_embedder::FMEKernel::isSingleThreaded
bool isSingleThreaded() const
returns true if this run only uses one thread )
Definition: FMEKernel.h:60
basic.h
Basic declarations, included by all source files.
ogdf::end
HypergraphRegistry< HypernodeElement >::iterator end(const HypergraphRegistry< HypernodeElement > &self)
ogdf::fast_multipole_embedder::FMEKernel::m_pThread
FMEThread * m_pThread
Definition: FMEKernel.h:60
ogdf::fast_multipole_embedder::ArrayGraph::numEdges
uint32_t numEdges() const
Returns the number of edges.
Definition: ArrayGraph.h:59
ogdf::fast_multipole_embedder::FMEKernel::threadNr
uint32_t threadNr() const
returns the index of the thread ( 0.. numThreads()-1 )
Definition: FMEKernel.h:51
ogdf::fast_multipole_embedder::FMEKernel::numThreads
uint32_t numThreads() const
returns the total number of threads in the pool
Definition: FMEKernel.h:54
ogdf::fast_multipole_embedder::FMEKernel::isMainThread
bool isMainThread() const
returns true if this is the main thread ( the main thread is always the first thread )
Definition: FMEKernel.h:57
ogdf::fast_multipole_embedder::FMEKernel::FMEKernel
FMEKernel(FMEThread *pThread)
Definition: FMEKernel.h:46
ogdf::fast_multipole_embedder::FMESingleKernel::operator()
void operator()(ArrayGraph &graph, float timeStep, uint32_t minIt, uint32_t maxIt, double threshold)
Definition: FMEKernel.h:247
ogdf::fast_multipole_embedder::FMEBasicKernel::moveNodes
double moveNodes(ArrayGraph &graph, float *fx, float *fy, float timeStep)
Definition: FMEKernel.h:194
ogdf::fast_multipole_embedder::FMEBasicKernel::edgeForces
void edgeForces(const ArrayGraph &graph, float *fx, float *fy)
Definition: FMEKernel.h:185
ogdf::fast_multipole_embedder::FMEThread::threadNr
uint32_t threadNr() const
returns the index of the thread ( 0.. numThreads()-1 )
Definition: FMEThread.h:83
ogdf::fast_multipole_embedder::fast_multipole_p2m
void fast_multipole_p2m(double *mulitCoeffiecients, uint32_t numCoeffiecients, double centerX, double centerY, float x, float y, float q)
ogdf::fast_multipole_embedder::ArrayGraph::edgeInfo
EdgeAdjInfo & edgeInfo(uint32_t i)
Returns the adjacency information for the edge at index i in m_edgeAdj.
Definition: ArrayGraph.h:144
OGDF_FME_KERNEL_COMPUTE_FORCE
#define OGDF_FME_KERNEL_COMPUTE_FORCE(dx, dy, s)
Definition: FMEKernel.h:74
FMEThread.h
Declaration of class FMEThread.
ogdf::fast_multipole_embedder::eval_direct_fast
void eval_direct_fast(float *x, float *y, float *s, float *fx, float *fy, size_t n)
kernel function to evaluate forces between n points with coords x, y directly. result is stored in fx...
Definition: FMEKernel.h:158