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