Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

Loading...
Searching...
No Matches
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>
39#include <ogdf/energybased/fast_multipole_embedder/FastUtils.h> // IWYU pragma: keep
40
41#include <algorithm>
42#include <cmath>
43#include <cstddef>
44#include <cstdint>
45
46namespace ogdf {
47namespace fast_multipole_embedder {
48
49class FMEKernel {
50public:
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
67private:
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
82inline 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
94inline 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
120inline 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
140inline 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
163inline 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
168inline 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
175void eval_direct_fast(float* x, float* y, float* s, float* fx, float* fy, size_t n);
177void 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
182void fast_multipole_l2p(double* localCoeffiecients, uint32_t numCoeffiecients, double centerX,
183 double centerY, float x, float y, float q, float& fx, float& fy);
184
185void fast_multipole_p2m(double* mulitCoeffiecients, uint32_t numCoeffiecients, double centerX,
186 double centerY, float x, float y, float q);
187
189public:
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
243private:
244};
245
247public:
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}
Declaration of class ArrayGraph.
Datastructures for edge chains itself and the edge chains of nodes.
#define OGDF_FME_KERNEL_COMPUTE_FORCE(dx, dy, s)
Definition FMEKernel.h:79
Declaration of class FMEThread.
Definition of utility functions for FME layout.
#define OGDF_MALLOC_16(s)
16-byte aligned memory allocation macro
Definition FastUtils.h:130
#define OGDF_FREE_16(ptr)
16-byte aligned memory deallocation macro
Definition FastUtils.h:133
Mathematical Helpers.
Basic declarations, included by all source files.
float * nodeXPos()
Returns the x coord array for all nodes.
Definition ArrayGraph.h:168
uint32_t numEdges() const
Returns the number of edges.
Definition ArrayGraph.h:65
EdgeAdjInfo & edgeInfo(uint32_t i)
Returns the adjacency information for the edge at index i in m_edgeAdj.
Definition ArrayGraph.h:150
float * nodeYPos()
Returns the y coord array for all nodes.
Definition ArrayGraph.h:174
NodeAdjInfo & nodeInfo(uint32_t i)
Returns the adjacency information for the node at index i in m_nodeAdj.
Definition ArrayGraph.h:144
float * nodeSize()
Returns the node size array for all nodes.
Definition ArrayGraph.h:180
uint32_t numNodes() const
Returns the number of nodes.
Definition ArrayGraph.h:62
float * desiredEdgeLength()
Returns the edge length array for all edges.
Definition ArrayGraph.h:189
uint32_t a
First node of the pair.
Definition EdgeChain.h:55
double simpleEdgeIteration(ArrayGraph &graph, float *fx, float *fy, float timeStep)
Definition FMEKernel.h:210
void edgeForces(const ArrayGraph &graph, float *fx, float *fy)
Definition FMEKernel.h:190
double moveNodes(ArrayGraph &graph, float *fx, float *fy, float timeStep)
Definition FMEKernel.h:199
double simpleIteration(ArrayGraph &graph, float *fx, float *fy, float timeStep)
Definition FMEKernel.h:204
void simpleForceDirected(ArrayGraph &graph, float timeStep, uint32_t minIt, uint32_t maxIt, uint32_t preProcIt, double threshold)
Definition FMEKernel.h:215
void repForces(ArrayGraph &graph, float *fx, float *fy)
Definition FMEKernel.h:194
bool isMainThread() const
returns true if this is the main thread ( the main thread is always the first thread )
Definition FMEKernel.h:62
uint32_t threadNr() const
returns the index of the thread ( 0.. numThreads()-1 )
Definition FMEKernel.h:56
bool isSingleThreaded() const
returns true if this run only uses one thread )
Definition FMEKernel.h:65
uint32_t numThreads() const
returns the total number of threads in the pool
Definition FMEKernel.h:59
void operator()(ArrayGraph &graph, float timeStep, uint32_t minIt, uint32_t maxIt, double threshold)
Definition FMEKernel.h:252
The fast multipole embedder work thread class.
Definition FMEThread.h:77
bool isMainThread() const
returns true if this is the main thread ( the main thread is always the first thread )
Definition FMEThread.h:89
uint32_t numThreads() const
returns the total number of threads in the pool
Definition FMEThread.h:86
uint32_t threadNr() const
returns the index of the thread ( 0.. numThreads()-1 )
Definition FMEThread.h:83
void updateMax(T &max, const T &newValue)
Stores the maximum of max and newValue in max.
Definition Math.h:94
void fast_multipole_p2m(double *mulitCoeffiecients, uint32_t numCoeffiecients, double centerX, double centerY, float x, float y, float q)
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
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
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
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
void eval_edges(const ArrayGraph &graph, const uint32_t begin, const uint32_t end, float *fx, float *fy)
Definition FMEKernel.h:94
The namespace for all OGDF objects.
HypergraphRegistry< HypernodeElement >::iterator begin(const HypergraphRegistry< HypernodeElement > &self)
HypergraphRegistry< HypernodeElement >::iterator end(const HypergraphRegistry< HypernodeElement > &self)