Fréchet View  1.6.0
A Tool for Exploring Fréchet Distance Algorithms
optimise.cpp
Go to the documentation of this file.
1 
2 #include <poly/algorithm.h>
3 #include <poly/parallel.h>
4 
5 #include <poly/poly_utils.h>
7 #include <data/numeric.h>
8 #include <app/concurrency.h>
9 
10 #include <tbb/tbb.h>
11 
12 using namespace frechet;
13 using namespace poly;
14 using namespace reach;
15 using namespace numeric;
16 using namespace app;
17 
18 #include <optimise_impl.h>
19 
21 {
22  if (x >= 0.0) {
23  // Aufrunden an der allerletzen Stelle.
24  double dx = round_up((double)x,16);
25  currentCriticalValueList().push_back(dx);
26  }
27 }
28 
30  return criticalValues;
31 }
32 
34  return localCriticalValues.local();
35 }
36 
37 void Algorithm::collectCriticalValues(bool a, bool b, bool c, bool d)
38 {
39  const Curve& P = this->P->curve;
40  const Curve& Q = this->Q->curve;
41 
42  // (1) calculate critical values
43  criticalValues.clear();
44  if (a) collectCriticalValues_a();
45  if (b) {
46  collectCriticalValues_b(P,Q);
47  collectCriticalValues_b(Q,P);
48  }
49  if (c) {
50  collectCriticalValues_c(P,Q);
51  collectCriticalValues_c(Q,P);
52  }
53  if (d) collectCriticalValues_d();
54 
55  testCancelFlag();
56  combineCriticalValues();
57  removeDuplicates(criticalValues);
58 
59  testCancelFlag();
60  std::cout << " Data: "<<criticalValues.size()<<" critical values." << std::endl;
61  printDebugTimer("Critical Values");
62 }
63 
64 
66 {
67  // sort
68  std::sort(criticalValues.begin(), criticalValues.end());
69 }
70 
72 {
73  // reduce localValueSets to one globalValueSet
74  criticalValues = localCriticalValues.combine(AlgorithmMultiCore::combine);
75  // sort
76  tbb::parallel_sort(criticalValues.begin(),criticalValues.end());
77 
78  localCriticalValues.clear();
79 }
80 
81 
83 {
84  double* begin = &vector[0];
85  double* end = begin+vector.size();
86  double* a = begin;
87  double* b = begin;
88 
89  double eps = round_up(0.0,16);
90  while(a<end) {
91  while(*a-*b < eps)
92  if (++a>=end) break;
93  *++b = *a++;
94  }
95 
96  vector.resize(b+1 - begin);
97 }
98 
99 
102 {
103  size_t s1 = a.size();
104  size_t s2 = b.size();
105  a.resize(s1+s2);
106  memcpy(&a[s1], &b[0], s2*sizeof(double));
107  //b.clear();
108  return a;
109 }
110 
112 {
113  const Curve& P = this->P->curve;
114  const Curve& Q = this->Q->curve;
115 
116  // Critical Values Type (a)
117  // distance between endpoints; applies only to open curves
118  if (!P.isClosed() && !Q.isClosed())
119  {
120  collectCriticalValue( euclidean_distance<accurate_float>(P.front(),Q.front()));
121  collectCriticalValue( euclidean_distance<accurate_float>(P.back(),Q.back()));
122  }
123 }
124 
126 {
127  //std::cout << " Thread "<<ConcurrencyContext::instance.currentThread()<<" collect b ["<<i<<".."<<j<<"]"<<std::endl;
128  for(int k=1; k < Q.size(); ++k)
129  {
130  QLineF segment (Q[k-1],Q[k]);
131  accurate_float dist = segment_distance<accurate_float>(segment,p);
132  collectCriticalValue(dist);
133  }
134  testCancelFlag();
135 }
136 
138 {
139  // Critical Values Type (b)
140  // distance from a point to a segment
141  for(int i=0; i < P.length(); ++i)
143 }
144 
146 {
147  // Critical Values Type (b)
148  // distance from a point to a segment
149  auto lambda = [&](size_t i) {
151  };
152  // TODO [] (size_t i)
153 
154  tbb::parallel_for( (size_t)0, (size_t)P.size(), lambda);
155 }
156 
157 void Algorithm::collectCriticalValues_c(const QLineF& segment, const Curve& Q)
158 {
159  // for each segment of P
160  // for each pair of vertices in Q
161  // distance to intersection between segment
162  // and bisector
163  //std::cout << " Thread "<<ConcurrencyContext::instance.currentThread()<<" collect c ["<<i<<".."<<j<<"]"<<std::endl;
164 
165  for(int k=0; k < Q.size(); ++k) {
166  for (int l = k+1; l < Q.size(); ++l) {
167  /* detecting intersections: allow some tolerance.
168  * Better find too many critical values than missing one !!
169  */
170  accurate_float dist = bisector_distance<accurate_float> (Q[k], Q[l], segment, 1e-3);
171  collectCriticalValue(dist);
172  }
173  testCancelFlag();
174  }
175 }
176 
178 {
179  for(int i=1; i < P.length(); ++i) {
180  QLineF segment(P[i-1],P[i]);
182  }
183 }
184 
186 {
187  auto lambda = [&](size_t i) {
188  QLineF segment(P[i-1],P[i]);
190  };
191 
192  tbb::parallel_for( (size_t)1, (size_t)P.length(), lambda);
193 }
194 
195 void Algorithm::collectCriticalValues_d(const QLineF& diagonal)
196 {
197  // Critical values type (d)
198  // between a diagonal and reflex vertices
199 // const Curve& P = this->P->curve;
200  const Curve& Q = this->Q->curve;
201  const Polygon& R = this->Q->reflex;
202  Q_ASSERT(R.size() >= 1); // da Q nicht konvex ist
203 
204  //std::cout << " Thread "<<ConcurrencyContext::instance.currentThread()<<" collect d ["<<r1<<"]"<<std::endl;
205 
206  for(int r1=0; r1 < R.size(); ++r1)
207  {
208  const Point& q1 = Q[R[r1]];
209  // type (b)
210  accurate_float dist = segment_distance<accurate_float>(diagonal,q1);
211  collectCriticalValue(dist);
212  // type (c)
213  for (int r2 = r1+1; r2 < R.size(); ++r2) {
214  const Point& q2 = Q[R[r2]];
215  /* detecting intersections: allow some tolerance.
216  * Better find too many critical values than missing one !!
217  */
218  dist = bisector_distance<accurate_float> (q1, q2, diagonal, 1e-3);
219  collectCriticalValue(dist);
220  }
221  testCancelFlag();
222  }
223 }
224 
225 //for(const Segment& d : c_diagonals())
226 //QLineF segment(P[d.first], P[d.second]);
227 
229 {
230  const Curve& P = this->P->curve;
231  for(const Segment& d : c_diagonals())
232  {
233  QLineF diagonal(P[d.first], P[d.second]);
235  }
236 }
237 
239 {
240  const Curve& P = this->P->curve;
241  auto lambda = [&] (size_t i) {
242  Segment d = c_diagonals_vector[i];
243  QLineF diagonal(P[d.first], P[d.second]);
245  };
246 
247  tbb::parallel_for( (size_t)0, (size_t)c_diagonals_vector.size(), lambda);
248 }
249 
250 
251 
252 double Algorithm::optimisePolygon(frechet::reach::FSPath::ptr path, double approximation)
253 {
254  Q_ASSERT(canOptimisePoly());
255 
256  cleanup();
257  setStatus((approximation==0.0) ? RUNNING_OPT_POLY : RUNNING_APPROX_POLY);
258 
259  GraphPtr result;
260  double epsilon;
261  Pointer ignored;
262  reach::FSPath::ptr no_path;
263 
264  local_fs.reset(new FreeSpace(P->curve, Q->curve));
265 
266  if (approximation==0.0)
267  {
268  // === Binary Search on Critical Values ===
269 
270  // (1) calculate critical values
271  collectCriticalValues(false,true,true,true);
272 
273  // (2) binsearch on critical values
274  int lo = -1;
275  int hi = criticalValues.size();
276 
277  // find lower bound through decideCurve
278 // find higher bound through leaping bin search
279  lo = binarySearch<Pointer> (criticalValues, lo, hi,
280  &Algorithm::decideCurve, ignored);
281  Q_ASSERT(lo >= 0 && lo < criticalValues.size());
282  printDebugTimer("Lower Bound");
283 
284  epsilon = criticalValues[lo];
285  local_fs->calculateFreeSpace(epsilon);
286  result = decidePolygon(local_fs, no_path, epsilon, false);
287 
288  if (result) goto label_result;
289  // find hi
290  int step = 1;
291  for (;;) {
292  hi = lo + step;
293  if (hi >= criticalValues.size()) {
294  hi = criticalValues.size();
295  break;
296  }
297 
298  epsilon = criticalValues[hi];
299  local_fs->calculateFreeSpace(epsilon);
300  result = decidePolygon(local_fs, no_path, epsilon, false);
301 
302  if (result && step == 1) goto label_result;
303  if (result)
304  break; // found hi
305  else {
306  lo = hi;
307  step *= 2;
308  }
309  }
310 
311  int i = binarySearch(criticalValues, lo, hi, &Algorithm::decidePolygon, result);
312  Q_ASSERT(i >= 0 && i < criticalValues.size());
313  epsilon = criticalValues[i];
314  }
315  else
316  {
317  // === Nested Interval search ===
318  double upper_bound = frechet::max_euclidean_distance(P->curve, Q->curve) + 1.0;
319  // d_F for Curve constitues the lower bound (is quicker to calculate!)
320  epsilon = intervalSearch(0.0, upper_bound, approximation, &Algorithm::decideCurve, ignored);
321  local_fs->calculateFreeSpace(epsilon);
322  result = decidePolygon(local_fs, no_path, epsilon, false);
323 
324  if (result) goto label_result;
325  epsilon = intervalSearch<GraphPtr> (epsilon,upper_bound, approximation, &Algorithm::decidePolygon, result);
326  }
327 
328 label_result:
329  Q_ASSERT((bool)result);
330  local_fs.reset();
331 
332  if (path) {
333  // FSPath is very sensitive to round-off errors.
334  // Because it is only needed for visualisation, we can afford
335  // a bit of tolerance.
336  // TODO reduce round-off errors with float128.
337  double repsilon = round_up(epsilon,32);
338  updatePath(path, boost::static_pointer_cast<Graph>(result),repsilon);
339  }
340 
341  setStatus( result ? YES:NO );
342 
343  if (path) {
344  emit optimisationResult(epsilon);
345  emit pathUpdated((bool)result); // only after status has changed
346  }
347 
348  this->fs.reset();
349  criticalValues.clear();
350 
351  cleanup();
352  return epsilon;
353 }
354 
355 double Algorithm::optimiseCurve(double approximation)
356 {
357  Q_ASSERT(canOptimiseCurve());
358 
359  setStatus((approximation==0.0) ? RUNNING_OPT_CURVE : RUNNING_APPROX_CURVE);
360 
361  reach::Pointer result;
362  double epsilon;
363  local_fs.reset(new FreeSpace(P->curve, Q->curve));
364 
365  if (approximation==0.0)
366  {
367  // === Binary Search on Critical Values ===
368  // (1) calculate critical values
369  collectCriticalValues(true,true,true,false);
370 
371  int i = binarySearch<reach::Pointer> (criticalValues, -1, criticalValues.size(),
372  &Algorithm::decideCurve, result);
373  Q_ASSERT(i >= 0 && i < criticalValues.size());
374  epsilon = criticalValues[i];
375  }
376  else
377  {
378  // === Nested Interval search ===
379  double upper_bound = frechet::max_euclidean_distance(P->curve,Q->curve)+1.0;
380  epsilon = intervalSearch<reach::Pointer> (0.0,upper_bound, approximation, &Algorithm::decideCurve, result);
381  }
382 
383  Q_ASSERT((bool)result);
384  local_fs.reset();
385  criticalValues.clear();
386 
387  this->fs.reset();
388  setStatus(result ? YES:NO);
389 
390  emit optimisationResult(epsilon);
391  //return startPointer;
392  return epsilon;
393 }
394 
Represents a polygon line segment from node i to j.
Definition: types.h:39
frechet::reach::Graph::ptr GraphPtr
the result of the decision algorithm is a reachability Graph containing a feasible path
Definition: algorithm.h:116
double round_up(double x, int ulps=1)
rounding function with 'units in the last place' Roughly speaking, a ulp is the smallest representabl...
Definition: numeric.h:112
virtual void collectCriticalValues_d()=0
compute critical values for diagonals and reflex vertices
global definitions for all algorithms.
std::vector< double > CriticalValueList
a list of critical values
Definition: algorithm.h:230
virtual void combineCriticalValues() override
reduce thread-local lists to a global list, then sort it
Definition: optimise.cpp:71
virtual void collectCriticalValues_d() override
compute critical values for diagonals and reflex vertices
Definition: optimise.cpp:228
virtual void collectCriticalValues_b(const Curve &P, const Curve &Q) override
compute critical values of type (b)
Definition: optimise.cpp:137
virtual void combineCriticalValues() override
hook for post-processing of critical values
Definition: optimise.cpp:65
void removeDuplicates(CriticalValueList &vector)
remove duplicates from a sorted list of critical values
Definition: optimise.cpp:82
boundary interval in the reachability structure. Represents an interval on the boundary of the FreeSp...
Definition: boundary.h:285
virtual void collectCriticalValues_c(const Curve &P, const Curve &Q) override
compute critical values of type (c)
Definition: optimise.cpp:185
time_point printDebugTimer(std::string label)
clock benchmark and print elapsed time
GraphPtr decidePolygon(FreeSpace::ptr fs, reach::FSPath::ptr path, double epsilon, bool update_status)
execute the decision variant for simple polygons (Buchin et al.'s algorithm)
Definition: algorithm.cpp:429
static const CriticalValueList & combine(CriticalValueList &a, const CriticalValueList &b)
reduce two thread-local lists of critical values; the lists are simply appended
Definition: optimise.cpp:100
void collectCriticalValues_a()
compute critical values of type (a)
Definition: optimise.cpp:111
long double accurate_float
Definition: numeric.h:42
QPointF Point
a point in the plane; with double floating point precision. This type is heavily used throughout all ...
Definition: types.h:14
boost::shared_ptr< FSPath > ptr
smart pointer to an FSPath object
Definition: fs_path.h:65
void collectCriticalValues_c(const QLineF &pseg, const Curve &Q)
compute critical values of type (c)
Definition: optimise.cpp:157
QPolygonF Curve
a polygonal curve in the plane; with double floating point precision. This type is heavily used throu...
Definition: types.h:20
virtual void collectCriticalValues_c(const Curve &P, const Curve &Q) override
compute critical values of type (c)
Definition: optimise.cpp:177
void collectCriticalValues_b(const Point &p, const Curve &Q)
compute critical values of type (b)
Definition: optimise.cpp:125
reach::Pointer decideCurve(FreeSpace::ptr fs, reach::FSPath::ptr path, double ignored, bool update_status)
execute the decision variant for curves. (Alt and Godau's algorithm)
Definition: algorithm.cpp:238
double optimiseCurve(double approximation=0.0)
execute the optimisation variant for curves. (Alt and Godau's algorithm)
Definition: optimise.cpp:355
The FreeSpace class models the Free-Space Diagram calculated from two curves.
Definition: freespace.h:83
void collectCriticalValues(bool a, bool b, bool c, bool d)
compute a set of critical values for the optimisation variant
Definition: optimise.cpp:37
virtual void collectCriticalValues_d() override
compute critical values for diagonals and reflex vertices
Definition: optimise.cpp:238
virtual CriticalValueList & currentCriticalValueList()
thread-local copy of critical values
Definition: optimise.cpp:33
double optimisePolygon(reach::FSPath::ptr path, double approximation=0.0)
execute the optimisaion variant for simple polygons. (Buchin et al.'s algorithm) The result value is ...
Definition: optimise.cpp:252
std::vector< int > Polygon
Polygon a sub-set of vertex indexes.
Definition: types.h:113
virtual CriticalValueList & currentCriticalValueList()
get the set of current critical values
Definition: optimise.cpp:29
virtual void collectCriticalValues_b(const Curve &P, const Curve &Q) override
compute critical values of type (b)
Definition: optimise.cpp:145
double max_euclidean_distance(const Curve &P, const Curve &Q)
compute the maximum distance between two polygons This value serves as an upper bound for the Frechet...
Definition: numeric.h:318
virtual void collectCriticalValue(const accurate_float &x)
store a critical value. Duplicates are accepted but removed later.
Definition: optimise.cpp:20