EstimateDiameter.cpp
Go to the documentation of this file.
1 // ========================================================================================
2 // ApproxMVBB
3 // Copyright (C) 2014 by Gabriel Nützi <nuetzig (at) imes (d0t) mavt (d0t) ethz (døt) ch>
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 // ========================================================================================
9 
10 #include <limits>
11 
13 #include ApproxMVBB_TypeDefs_INCLUDE_FILE
14 
16 
17 
18 
19 // Implementation ===============================================
20 
23 
24 namespace ApproxMVBB
25 {
26 
28  Diameter::TypeSegment *theDiam,
29  double const**theList,
30  const int first,
31  const int last,
32  const int dim,
33  double epsilon)
34 {
35  using namespace Diameter;
40  return this->estimateDiameterInOneList(theDiam,theList,first,last,dim, epsilon);
41 }
42 
44  Diameter::TypeSegment *theDiam,
45  double const**theList,
46  const int first,
47  const int last,
48  const int dim,
49  double _epsilon_ )
50 {
51 
52  using namespace Diameter;
53 
54  int index;
55 
56  int f=first;
57  int l=last;
58 
59  int newEstimateIsSmallerThanCurrentEstimate;
60  TypeSegment theSeg;
61 
62  TypeListOfSegments theDoubleNormals;
63 
64  double newEstimate;
65 
66  int newlast;
67 
68 
69  int verboseWhenReducing = _GetVerboseWhenReducing();
71  int tryToReduceQ = _GetTryToReduceQ();
74  int _Q_scan_ = _GetQscan();
76 
77  int i, j, k, n;
78  int index1, index2;
79 
80  int suspicion_of_convex_hull = 0; // not used
81  int fdn, ldn, idn;
82 
83  double epsilon = _epsilon_;
84  double bound, upperBound = 0.0;
85 
86  double upperSquareDiameter = 0.0;
87 
88  theDoubleNormals.n = 0;
89  theDoubleNormals.nalloc = 0;
90  theDoubleNormals.seg = NULL;
91 
92  theDiam->extremity1 = (double*)NULL;
93  theDiam->extremity2 = (double*)NULL;
94  theDiam->squareDiameter = std::numeric_limits<double>::lowest();
95 
96  if ( first < 0 || last < 0 ) return( -1.0 );
97  if ( first > last )
98  {
99  l = first;
100  f = last;
101  }
102  if ( f == l )
103  {
104  theDiam->extremity1 = theList[f];
105  theDiam->extremity2 = theList[l];
106  return( 0.0 );
107  }
108 
109  index = getRandomInt( f, l );
110  do
111  {
112 
113  /* end conditions
114  */
115  newEstimateIsSmallerThanCurrentEstimate = 0;
116 
117  /* find a double normal
118  */
119  newEstimate = _MaximalSegmentInOneList( &theSeg, index, theList, &f, &l, dim );
120 
121  /* if we get a better estimation
122  */
123  if ( newEstimate > theDiam->squareDiameter )
124  {
125 
126  /* update variables
127  */
128  *theDiam = theSeg;
129 
130  /* keep the maximal segment in list
131  */
132  if ( _AddSegmentToList( &theSeg, &theDoubleNormals ) != 1 )
133  {
134  if ( theDoubleNormals.nalloc > 0 ) free( theDoubleNormals.seg );
135  return( -1.0 );
136  }
137 
138 
139  /* find the farthest point outside the sphere
140  */
141  newlast = l;
142  index = _FarthestPointFromSphere( &theSeg, theList,
143  f, &newlast, dim,
144  _reduction_mode_in_iterative_ );
145  if ( _reduction_mode_in_iterative_ == 1 )
146  {
147  if ( verboseWhenReducing )
148  //fprintf( stdout, "...processing frth: remove %d points\n", l-newlast );
149  if ( newlast == l )
150  {
151  suspicion_of_convex_hull = 1;
152  _reduction_mode_of_diameter_ = 0;
153  _reduction_mode_of_dbleNorm_ = 0;
154  }
155  l = newlast;
156  }
157 
158  /* stopping condition
159  no point outside the sphere
160  */
161  if ( index < f )
162  {
163  if ( theDoubleNormals.nalloc > 0 ) free( theDoubleNormals.seg );
164  return( theDiam->squareDiameter );
165  }
166 
167  /* other stopping condition
168 
169  the farthest point M outside the sphere
170  is not that far away with a ball of diameter AB (and center C)
171 
172  we have MA.MB = MC^2 - |AB|^2 / 4
173  leading to 4 * MC^2 = 4 * MA.MB + |AB|^2
174 
175  an upper bound of the diameter is then 2 MC
176  thus (4 * MA.MB + |AB|^2) is a squared upper bound of the diameter
177  */
178 
179  bound = 4.0 * _ScalarProduct( theList[index], theDiam->extremity1,
180  theList[index], theDiam->extremity2, dim ) +
181  theDiam->squareDiameter;
182 
183  /* stopping condition
184 
185  we want 2*MC < (1+epsilon) * d_estimate
186  d_estimate = |AB|
187 
188  4 * MC^2 < (1+epsilon)^2 * (d_estimate)^2
189  4 * MA.MB + (d_estimate)^2 < (1+epsilon)^2 * (d_estimate)^2
190  1 + 4 * MA.MB / (d_estimate)^2 < (1+epsilon)^2
191 
192  */
193  if ( 1.0 + 4.0 * _ScalarProduct( theList[index], theDiam->extremity1,
194  theList[index], theDiam->extremity2, dim ) /
195  theDiam->squareDiameter < ( 1.0 + epsilon ) * ( 1.0 + epsilon ) )
196  {
197  if ( theDoubleNormals.nalloc > 0 ) free( theDoubleNormals.seg );
198  return( bound ) ;
199  }
200 
201  }
202  else
203  {
204 
205  newEstimateIsSmallerThanCurrentEstimate = 1;
206 
207  /* I add the found segment to the list
208  there is no evidence that it is a maximal segment for
209  the initial set P (but it is for the current one
210  ie the initial minus the points which have been removed),
211  it may somehow help in case of reduction of the set
212  of potential extremities
213 
214 
215  The list of double normals is sorted (from 0 to n)
216  by increasing square diameter:
217  - the best diameter is added (again) at the end
218  - we search the right place for this new element
219 
220  */
221 
222  if ( _AddSegmentToList( theDiam, &theDoubleNormals ) != 1 )
223  {
224  if ( theDoubleNormals.nalloc > 0 ) free( theDoubleNormals.seg );
225  return( -1.0 );
226  }
227 
228  for ( n = theDoubleNormals.n-2; n >= 0 ; n-- )
229  {
230  if ( n == 0 )
231  {
232  theDoubleNormals.seg[ n ] = theSeg;
233  }
234  else
235  {
236  if ( theSeg.squareDiameter <= theDoubleNormals.seg[ n ].squareDiameter &&
237  theSeg.squareDiameter > theDoubleNormals.seg[ n-1 ].squareDiameter )
238  {
239  theDoubleNormals.seg[ n ] = theSeg;
240  n = -1;
241  }
242  else
243  {
244  theDoubleNormals.seg[ n ] = theDoubleNormals.seg[ n-1 ];
245  }
246  }
247  }
248 
249  }
250 
251  }
252  while ( newEstimateIsSmallerThanCurrentEstimate == 0 );
253 
254 
255  /* last processing with the found diameter
256  - points inside the smallest sphere of the
257  diameter may have been already removed
258  */
259  if ( _reduction_mode_in_iterative_ > 0 && _reduction_mode_of_diameter_ == 1 )
260  _reduction_mode_of_diameter_ = 0;
261 
262  newlast = l;
263  index = _LastPointOutsideSphereWithDiameter( theDiam, theDiam->squareDiameter,
264  theList, f, &newlast, dim,
265  _reduction_mode_of_diameter_ );
266  if ( _reduction_mode_of_diameter_ == 1 ||
267  _reduction_mode_of_diameter_ == 2 )
268  {
269  if ( verboseWhenReducing )
270  //fprintf( stdout, "...processing diam: remove %d points\n", l-newlast );
271  if ( newlast == l )
272  {
273  suspicion_of_convex_hull = 1;
274  _reduction_mode_of_dbleNorm_ = 0;
275  }
276  l = newlast;
277  }
278 
279 
280  /* in some (rare) case, the remaining points outside the largest
281  sphere are removed while searching for a better diameter
282  thus it is still an avantageous case.
283  if any, we have
284  #f -> #index : points outside the sphere
285  #index+1 -> #l : points inside the sphere
286  */
287  if ( index < f )
288  {
289  if ( theDoubleNormals.nalloc > 0 ) free( theDoubleNormals.seg );
290  return( theDiam->squareDiameter );
291  }
292 
293  /* do you have enough precision?
294  */
295  index2 = index;
296  upperSquareDiameter = theDiam->squareDiameter * (1.0 + epsilon) * (1.0 + epsilon);
297 
298 
299  index1 = _LastPointOutsideSphereWithDiameter( theDiam, upperSquareDiameter,
300  theList, f, &index2, dim, 0 );
301  /* there is no points outside the sphere of diameter d * (1 + epsilon)
302  find the farthest one to get a better upper bound of the diameter
303  */
304  if ( index1 < f )
305  {
306  if ( theDoubleNormals.nalloc > 0 ) free( theDoubleNormals.seg );
307 
308  upperBound = 4.0 * _ScalarProduct( theList[f], theDiam->extremity1,
309  theList[f], theDiam->extremity2, dim ) +
310  theDiam->squareDiameter;
311 
312  for ( k=f+1; k<=index2; k++ )
313  {
314  bound = 4.0 * _ScalarProduct( theList[k], theDiam->extremity1,
315  theList[k], theDiam->extremity2, dim ) +
316  theDiam->squareDiameter;
317  if ( upperBound < bound ) upperBound = bound;
318  }
319  return( upperBound );
320  }
321 
322  /* get an upper bound of the diameter with points in [#index1+1 -> #index2]
323  if there are points in this interval
324  else the upper bound is simply d
325 
326  we have
327  #f -> #index1 : points outside the sphere of diameter d (1+epsilon)
328  #index1+1 -> #index2 : points outside the sphere but inside the previous one
329  #index2+1 -> #l : points inside the sphere
330  */
331  if ( _tight_bounds_ )
332  {
333  upperBound = theDiam->squareDiameter;
334  if ( index1 < index2 )
335  {
336  for ( k=index1+1; k<=index2; k++ )
337  {
338  bound = 4.0 * _ScalarProduct( theList[k], theDiam->extremity1,
339  theList[k], theDiam->extremity2, dim ) +
340  theDiam->squareDiameter;
341  if ( upperBound < bound ) upperBound = bound;
342  }
343  }
344  }
345  else
346  {
347  upperBound = upperSquareDiameter;
348  }
349 
350  /* to get some information on
351  the points
352  */
353  if ( 0 )
354  {
355  for ( n = theDoubleNormals.n-1; n >= 0; n -- )
356  {
357  /*_CountPointsInSpheres( &theDoubleNormals.seg[ n ], theDiam->squareDiameter,
358  theList, f, l, dim );*/
359  }
360  }
361 
362  /* here we will reduce the set of potential extremities
363  for the diameter,
364  ie the set of points which are to be compared against all
365  the other points
366 
367  right now, we have
368  #f -> #index1 : points outside the sphere of diameter d+epsilon
369  #index1+1 -> #index2 : points outside the sphere of diameter d
370  #index2+1 -> #l : points inside the sphere
371 
372  we have a set of maximal segments
373  theDoubleNormals.seg[ #i ] for #i from 0 to theDoubleNormals.n-1
374  with
375  theDoubleNormals.seg[ theDoubleNormals.n-1 ] == theDiam
376 
377  */
378  index = index1;
379  /* right now, we have
380  #f -> #index : points outside the sphere of diameter d*(1+epsilon)
381  #index+1 -> #l : points inside the sphere of diameter d*(1+epsilon)
382  */
383 
384  if ( tryToReduceQ && theDoubleNormals.n > 1 )
385  {
386 
387  for ( k = 0; k < theDoubleNormals.n; k ++ )
388  theDoubleNormals.seg[k].reduction_mode = _reduction_mode_of_dbleNorm_;
389 
390  switch ( _Q_scan_ )
391  {
392  default :
393  case 0 :
394  /* backward
395  */
396  ldn = 0;
397  fdn = theDoubleNormals.n-2;
398  idn = -1;
399  break;
400  case 1 :
401  /* forward
402  */
403  fdn = 0;
404  ldn = theDoubleNormals.n-2;
405  idn = +1;
406  break;
407  }
408 
409  for ( n = fdn; n != (ldn+idn) && index >= f ; n += idn )
410  {
411 
412  /* in [ #f #index ] find the points outside the sphere
413  theDoubleNormals.seg[ n ]
414 
415  as a result
416  #f -> #i are to be compared with all other points
417  #i+1 -> #index are to be compared with a subset
418  if this subset is empty, continue
419 
420  */
421  i = _LastPointOutsideSphereWithDiameter( &theDoubleNormals.seg[ n ],
422  upperSquareDiameter,
423  theList, f, &index, dim, 0 );
424  if ( i >= index ) continue;
425 
426 
427  /* remise a jour de l'upper bound,
428  a partir des points de [#i+1 -> #index]
429  par rapport a la double normale courante
430 
431  Ce sont des points qui etaient candidats parce qu'au
432  dela de la precision demandee, mais qui sont maintenant en
433  deca de celle-ci pour la double normale courante,
434  donc on reste en deca de la precision, par contre je ne sais
435  s'il faut toujours mettre a jour la borne sup ...
436 
437  */
438  if ( _tight_bounds_ )
439  {
440  for ( k = i+1; k <= index; k++ )
441  {
442  bound = 4.0 * _ScalarProduct( theList[k], theDoubleNormals.seg[ n ].extremity1,
443  theList[k], theDoubleNormals.seg[ n ].extremity2, dim ) +
444  theDoubleNormals.seg[ n ].squareDiameter;
445  if ( upperBound < bound ) upperBound = bound;
446  }
447  }
448 
449 
450 
451  /* in [ #index+1 #l ] find the points outside the sphere
452  theDoubleNormals.seg[ n ]
453 
454  as a result
455  #index+1 -> #j are to be compared with the previous subset
456  */
457 
458  newlast = l;
459 
460  if ( _tight_bounds_ )
461  {
462  j = _LastPointOutsideSphereAndBoundWithDiameter( &theDoubleNormals.seg[ n ],
463  upperSquareDiameter,
464  theList, index+1, &newlast, dim,
465  theDoubleNormals.seg[ n ].reduction_mode,
466  &bound );
467  if ( upperBound < bound ) upperBound = bound;
468  }
469  else
470  {
471  j = _LastPointOutsideSphereWithDiameter( &theDoubleNormals.seg[ n ],
472  upperSquareDiameter,
473  theList, index+1, &newlast, dim,
474  theDoubleNormals.seg[ n ].reduction_mode );
475  }
476 
477  if ( theDoubleNormals.seg[ n ].reduction_mode == 1 ||
478  theDoubleNormals.seg[ n ].reduction_mode == 2 )
479  {
480 
481  if ( verboseWhenReducing )
482  //fprintf( stdout, "...processing dbNR: remove %d points\n", l-newlast );
483  if ( newlast == l )
484  {
485  suspicion_of_convex_hull = 1;
486  for ( k = 0; k < theDoubleNormals.n; k ++ )
487  theDoubleNormals.seg[k].reduction_mode = 0;
488  }
489  l = newlast;
490  }
491 
492  if ( j <= index )
493  {
494  index = i;
495  continue;
496  }
497 
498  /* right now
499  #f -> #i : points to be compared with all other points
500  #i+1 -> #index : points to be compared with the below set
501  #index+1 -> #j : points to be compared with the above set
502  #j+1 -> #l : remaining points
503 
504  */
505 
506  theSeg.extremity1 = (double*)NULL;
507  theSeg.extremity2 = (double*)NULL;
508  theSeg.squareDiameter = 0.0;
509 
510 
511  newEstimate = _QuadraticDiameterInTwoLists( &theSeg, NULL, NULL,
512  theList, i+1, index,
513  theList, index+1, j,
514  dim );
515 
516 
517 
518 
519  if ( newEstimate > theDiam->squareDiameter )
520  {
521  /* update variables
522  */
523  *theDiam = theSeg;
524  if ( upperBound < newEstimate ) upperBound = newEstimate;
525  if ( upperSquareDiameter < newEstimate ) upperSquareDiameter = newEstimate;
526  /* we find a better estimate
527  it is perhaps not the diameter, according that one
528  diameter extremity can be in [ #f #i ]
529  The question are :
530  1. have we to look for a maximal segment with these two points
531  or not ?
532  -> Seems not necessary ...
533  2. have we to consider this segment with the others ?
534  -> yes
535  but we can not reduce the whole set with it !!!
536  */
537  theDoubleNormals.seg[ n ] = theSeg;
538  theDoubleNormals.seg[ n ].reduction_mode = 0;
539  n -= idn;
540  }
541 
542 
543  /* Q is now reduced
544  */
545  index = i;
546 
547  }
548  }
549 
550  if ( theDoubleNormals.nalloc > 0 ) free( theDoubleNormals.seg );
551 
552  /* exhautive search
553 
554  comparison of points from #f to #index
555  against all others points
556  */
557 
558  if ( dim == 2 )
559  {
560  for ( i=f; i<=index; i++ )
561  for ( j=i+1; j<=l; j++ )
562  {
563  newEstimate = _SquareDistance2D( theList[i], theList[j] );
564  if ( newEstimate > theDiam->squareDiameter )
565  {
566  theDiam->extremity1 = theList[i];
567  theDiam->extremity2 = theList[j];
568  theDiam->squareDiameter = newEstimate;
569  if ( newEstimate > upperBound ) upperBound = newEstimate;
570  }
571  }
572  return( upperBound );
573  }
574 
575 
576  if ( dim == 3 )
577  {
578  for ( i=f; i<=index; i++ )
579  for ( j=i+1; j<=l; j++ )
580  {
581  newEstimate = _SquareDistance3D( theList[i], theList[j] );
582  if ( newEstimate > theDiam->squareDiameter )
583  {
584  theDiam->extremity1 = theList[i];
585  theDiam->extremity2 = theList[j];
586  theDiam->squareDiameter = newEstimate;
587  if ( newEstimate > upperBound ) upperBound = newEstimate;
588  }
589  }
590  return( upperBound );
591  }
592 
593 
594  for ( i=f; i<=index; i++ )
595  for ( j=i+1; j<=l; j++ )
596  {
597  newEstimate = _SquareDistance( theList[i], theList[j], dim );
598  if ( newEstimate > theDiam->squareDiameter )
599  {
600  theDiam->extremity1 = theList[i];
601  theDiam->extremity2 = theList[j];
602  theDiam->squareDiameter = newEstimate;
603  if ( newEstimate > upperBound ) upperBound = newEstimate;
604  }
605  }
606  return( upperBound );
607 }
608 
609 }
610 // ==============================================================
611 
APPROXMVBB_EXPORT int _FarthestPointFromSphere(TypeSegment *theSeg, double const **theList, const int first, int *last, const int dim, const int _reduction_mode_)
Definition: util.cpp:867
These are some container definitions.
double estimateDiameter(Diameter::TypeSegment *theDiam, double const **theList, const int first, const int last, const int dim, double epsilon)
APPROXMVBB_EXPORT double _MaximalSegmentInOneList(TypeSegment *theSeg, const int index, double const **theList, int *first, int *last, const int dim)
Definition: util.cpp:1115
APPROXMVBB_EXPORT double _SquareDistance3D(double const *a, double const *b)
Definition: util.cpp:1324
int getRandomInt(unsigned int min, unsigned int max)
APPROXMVBB_EXPORT double _QuadraticDiameterInTwoLists(TypeSegment *theDiam, int *index1, int *index2, double const **theList1, const int first1, const int last1, double const **theList2, const int first2, const int last2, const int dim)
Definition: util.cpp:1511
APPROXMVBB_EXPORT int _AddSegmentToList(TypeSegment *s, TypeListOfSegments *list)
Definition: alloc.cpp:64
APPROXMVBB_EXPORT int _LastPointOutsideSphereWithDiameter(TypeSegment *theSeg, double constsquareDiameter, double const **theList, const int first, int *last, const int dim, const int _reduction_mode_)
Definition: util.cpp:44
APPROXMVBB_EXPORT double _ScalarProduct(double const *a, double const *b, double const *c, double const *d, const int dim)
Definition: util.cpp:1354
APPROXMVBB_EXPORT double _SquareDistance2D(double const *a, double const *b)
Definition: util.cpp:1337
double estimateDiameterInOneList(Diameter::TypeSegment *theDiam, double const **theList, const int first, const int last, const int dim, double _epsilon_)
APPROXMVBB_EXPORT int _LastPointOutsideSphereAndBoundWithDiameter(TypeSegment *theSeg, double constsquareDiameter, double const **theList, const int first, int *last, const int dim, const int _reduction_mode_, double *bound)
Definition: util.cpp:386
APPROXMVBB_EXPORT double _SquareDistance(double const *a, double const *b, const int dim)
Definition: util.cpp:1303


asr_approx_mvbb
Author(s): Gassner Nikolai
autogenerated on Mon Jun 10 2019 12:38:08