Skip to content

Commit b032016

Browse files
committed
[extensions] Performance improvements for side_robust strategy (#701)
* reorganize some parts of orient2d for a speedup * replace array in orient2d with own clearly named type.
1 parent 3186cf3 commit b032016

File tree

2 files changed

+139
-119
lines changed

2 files changed

+139
-119
lines changed

include/boost/geometry/extensions/triangulation/strategies/cartesian/detail/precise_math.hpp

Lines changed: 135 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -88,42 +88,6 @@ inline std::array<RealNumber, 2> two_diff(RealNumber const a,
8888
return {{ x, y }};
8989
}
9090

91-
// constexpr power-method, helper for splitter
92-
template
93-
<
94-
typename RealNumber
95-
>
96-
constexpr RealNumber int_pow(RealNumber const base,
97-
int exp,
98-
RealNumber out = 1.0)
99-
{
100-
return exp < 1 ? out :
101-
int_pow<RealNumber>(base*base, exp/2, (exp % 2) ? out*base : out);
102-
}
103-
104-
// consexpr method to compute 2^s + 1 as in Theorem 17, page 18
105-
template
106-
<
107-
typename RealNumber
108-
>
109-
constexpr RealNumber splitter()
110-
{
111-
return int_pow<RealNumber>(2.0,
112-
(std::numeric_limits<RealNumber>::digits + 1) / 2) + 1;
113-
}
114-
115-
// see theorem 17, page 18
116-
template
117-
<
118-
typename RealNumber
119-
>
120-
inline std::array<RealNumber, 2> split(RealNumber const a) {
121-
RealNumber c = splitter<RealNumber>() * a;
122-
RealNumber a_big = c - a;
123-
RealNumber a_hi = c - a_big;
124-
return {{ a_hi, a - a_hi }};
125-
}
126-
12791
// see theorem 18, page 19
12892
template
12993
<
@@ -133,12 +97,7 @@ inline RealNumber two_product_tail(RealNumber const a,
13397
RealNumber const b,
13498
RealNumber const x)
13599
{
136-
std::array<RealNumber, 2> a_expansion = split(a);
137-
std::array<RealNumber, 2> b_expansion = split(b);
138-
RealNumber err1 = x - (a_expansion[0] * b_expansion[0]);
139-
RealNumber err2 = err1 - (a_expansion[1] * b_expansion[0]);
140-
RealNumber err3 = err2 - (a_expansion[0] * b_expansion[1]);
141-
return (a_expansion[1] * b_expansion[1]) - err3;
100+
return std::fma(a, b, -x);
142101
}
143102

144103
// see theorem 18, page 19
@@ -199,45 +158,63 @@ inline int fast_expansion_sum_zeroelim(
199158
{
200159
std::array<RealNumber, 2> Qh;
201160
int i_e = 0, i_f = 0, i_h = 0;
202-
if (std::abs(f[0]) > std::abs(e[0])) {
161+
if (std::abs(f[0]) > std::abs(e[0]))
162+
{
203163
Qh[0] = e[i_e++];
204-
} else {
164+
}
165+
else
166+
{
205167
Qh[0] = f[i_f++];
206168
}
207169
i_h = 0;
208-
if ((i_e < m) && (i_f < n)) {
209-
if (std::abs(f[i_f]) > std::abs(e[i_e])) {
170+
if ((i_e < m) && (i_f < n))
171+
{
172+
if (std::abs(f[i_f]) > std::abs(e[i_e]))
173+
{
210174
Qh = fast_two_sum(e[i_e++], Qh[0]);
211-
} else {
175+
}
176+
else
177+
{
212178
Qh = fast_two_sum(f[i_f++], Qh[0]);
213179
}
214-
if (Qh[1] != 0.0) {
180+
if (Qh[1] != 0.0)
181+
{
215182
h[i_h++] = Qh[1];
216183
}
217-
while ((i_e < m) && (i_f < n)) {
218-
if (std::abs(f[i_f]) > std::abs(e[i_e])) {
184+
while ((i_e < m) && (i_f < n))
185+
{
186+
if (std::abs(f[i_f]) > std::abs(e[i_e]))
187+
{
219188
Qh = two_sum(Qh[0], e[i_e++]);
220-
} else {
189+
}
190+
else
191+
{
221192
Qh = two_sum(Qh[0], f[i_f++]);
222193
}
223-
if (Qh[1] != 0.0) {
194+
if (Qh[1] != 0.0)
195+
{
224196
h[i_h++] = Qh[1];
225197
}
226198
}
227199
}
228-
while (i_e < m) {
200+
while (i_e < m)
201+
{
229202
Qh = two_sum(Qh[0], e[i_e++]);
230-
if (Qh[1] != 0.0) {
203+
if (Qh[1] != 0.0)
204+
{
231205
h[i_h++] = Qh[1];
232206
}
233207
}
234-
while (i_f < n) {
208+
while (i_f < n)
209+
{
235210
Qh = two_sum(Qh[0], f[i_f++]);
236-
if (Qh[1] != 0.0) {
211+
if (Qh[1] != 0.0)
212+
{
237213
h[i_h++] = Qh[1];
238214
}
239215
}
240-
if ((Qh[0] != 0.0) || (i_h == 0)) {
216+
if ((Qh[0] != 0.0) || (i_h == 0))
217+
{
241218
h[i_h++] = Qh[0];
242219
}
243220
return i_h;
@@ -259,83 +236,76 @@ inline int scale_expansion_zeroelim(
259236
{
260237
std::array<RealNumber, 2> Qh = two_product(e[0], b);
261238
int i_h = 0;
262-
if (Qh[1] != 0) {
239+
if (Qh[1] != 0)
240+
{
263241
h[i_h++] = Qh[1];
264242
}
265-
for (int i_e = 1; i_e < e_non_zeros; i_e++) {
243+
for (int i_e = 1; i_e < e_non_zeros; i_e++)
244+
{
266245
std::array<RealNumber, 2> Tt = two_product(e[i_e], b);
267246
Qh = two_sum(Qh[0], Tt[1]);
268-
if (Qh[1] != 0) {
247+
if (Qh[1] != 0)
248+
{
269249
h[i_h++] = Qh[1];
270250
}
271251
Qh = fast_two_sum(Tt[0], Qh[0]);
272-
if (Qh[1] != 0) {
252+
if (Qh[1] != 0)
253+
{
273254
h[i_h++] = Qh[1];
274255
}
275256
}
276-
if ((Qh[0] != 0.0) || (i_h == 0)) {
257+
if ((Qh[0] != 0.0) || (i_h == 0))
258+
{
277259
h[i_h++] = Qh[0];
278260
}
279261
return i_h;
280262
}
281263

282-
// see page 38, Figure 21 for the calculations, notation follows the notation in the figure.
264+
template<typename RealNumber>
265+
struct vec2d
266+
{
267+
RealNumber x;
268+
RealNumber y;
269+
};
270+
283271
template
284272
<
285273
typename RealNumber,
286-
std::size_t Robustness = 3
274+
std::size_t Robustness
287275
>
288-
inline RealNumber orient2d(std::array<RealNumber, 2> const& p1,
289-
std::array<RealNumber, 2> const& p2,
290-
std::array<RealNumber, 2> const& p3)
276+
inline RealNumber orient2dtail(vec2d<RealNumber> const& p1,
277+
vec2d<RealNumber> const& p2,
278+
vec2d<RealNumber> const& p3,
279+
std::array<RealNumber, 2>& t1,
280+
std::array<RealNumber, 2>& t2,
281+
std::array<RealNumber, 2>& t3,
282+
std::array<RealNumber, 2>& t4,
283+
std::array<RealNumber, 2>& t5_01,
284+
std::array<RealNumber, 2>& t6_01,
285+
RealNumber const& magnitude
286+
)
291287
{
292-
if(Robustness == 0) {
293-
return (p1[0]-p3[0])*(p2[1]-p3[1]) - (p1[1]-p3[1])*(p2[0] - p3[0]);
294-
}
295-
std::array<RealNumber, 2> t1, t2, t3, t4;
296-
t1[0] = p1[0] - p3[0];
297-
t2[0] = p2[1] - p3[1];
298-
t3[0] = p1[1] - p3[1];
299-
t4[0] = p2[0] - p3[0];
300-
std::array<RealNumber, 2> t5_01, t6_01;
301-
t5_01[0] = t1[0] * t2[0];
302-
t6_01[0] = t3[0] * t4[0];
303-
RealNumber det = t5_01[0] - t6_01[0];
304-
if ( (t5_01[0] > 0 && t6_01[0] <= 0) || (t5_01[0] < 0 && t6_01[0] >= 0) ) {
305-
//if diagonal and antidiagonal have different sign, the sign of det is
306-
//obvious
307-
return det;
308-
}
309-
RealNumber const magnitude = std::abs(t5_01[0]) + std::abs(t6_01[0]);
310-
311-
// see p.39, mind the different definition of epsilon for error bound
312-
RealNumber const A_relative_bound =
313-
(1.5 + 4 * std::numeric_limits<RealNumber>::epsilon())
314-
* std::numeric_limits<RealNumber>::epsilon();
315-
RealNumber absolute_bound = A_relative_bound * magnitude;
316-
if ( std::abs(det) >= absolute_bound ) {
317-
return det; //A estimate
318-
}
319-
320288
t5_01[1] = two_product_tail(t1[0], t2[0], t5_01[0]);
321289
t6_01[1] = two_product_tail(t3[0], t4[0], t6_01[0]);
322290
std::array<RealNumber, 4> tA_03 = two_two_expansion_diff(t5_01, t6_01);
323-
det = std::accumulate(tA_03.begin(), tA_03.end(), static_cast<RealNumber>(0));
291+
RealNumber det = std::accumulate(tA_03.begin(), tA_03.end(), static_cast<RealNumber>(0));
324292
if(Robustness == 1) return det;
325293
// see p.39, mind the different definition of epsilon for error bound
326294
RealNumber B_relative_bound =
327295
(1 + 3 * std::numeric_limits<RealNumber>::epsilon())
328296
* std::numeric_limits<RealNumber>::epsilon();
329-
absolute_bound = B_relative_bound * magnitude;
330-
if (std::abs(det) >= absolute_bound) {
297+
RealNumber absolute_bound = B_relative_bound * magnitude;
298+
if (std::abs(det) >= absolute_bound)
299+
{
331300
return det; //B estimate
332301
}
333-
t1[1] = two_diff_tail(p1[0], p3[0], t1[0]);
334-
t2[1] = two_diff_tail(p2[1], p3[1], t2[0]);
335-
t3[1] = two_diff_tail(p1[1], p3[1], t3[0]);
336-
t4[1] = two_diff_tail(p2[0], p3[0], t4[0]);
302+
t1[1] = two_diff_tail(p1.x, p3.x, t1[0]);
303+
t2[1] = two_diff_tail(p2.y, p3.y, t2[0]);
304+
t3[1] = two_diff_tail(p1.y, p3.y, t3[0]);
305+
t4[1] = two_diff_tail(p2.x, p3.x, t4[0]);
337306

338-
if ((t1[1] == 0) && (t3[1] == 0) && (t2[1] == 0) && (t4[1] == 0)) {
307+
if ((t1[1] == 0) && (t3[1] == 0) && (t2[1] == 0) && (t4[1] == 0))
308+
{
339309
return det; //If all tails are zero, there is noething else to compute
340310
}
341311
RealNumber sub_bound =
@@ -348,7 +318,8 @@ inline RealNumber orient2d(std::array<RealNumber, 2> const& p1,
348318
* std::numeric_limits<RealNumber>::epsilon();
349319
absolute_bound = C_relative_bound * magnitude + sub_bound * std::abs(det);
350320
det += (t1[0] * t2[1] + t2[0] * t1[1]) - (t3[0] * t4[1] + t4[0] * t3[1]);
351-
if (Robustness == 2 || std::abs(det) >= absolute_bound) {
321+
if (Robustness == 2 || std::abs(det) >= absolute_bound)
322+
{
352323
return det; //C estimate
353324
}
354325
std::array<RealNumber, 8> D_left;
@@ -376,6 +347,50 @@ inline RealNumber orient2d(std::array<RealNumber, 2> const& p1,
376347
return(D[D_nz - 1]);
377348
}
378349

350+
// see page 38, Figure 21 for the calculations, notation follows the notation in the figure.
351+
template
352+
<
353+
typename RealNumber,
354+
std::size_t Robustness = 3
355+
>
356+
inline RealNumber orient2d(vec2d<RealNumber> const& p1,
357+
vec2d<RealNumber> const& p2,
358+
vec2d<RealNumber> const& p3)
359+
{
360+
if(Robustness == 0)
361+
{
362+
return (p1.x - p3.x) * (p2.y - p3.y) - (p1.y - p3.y) * (p2.x - p3.x);
363+
}
364+
std::array<RealNumber, 2> t1, t2, t3, t4;
365+
t1[0] = p1.x - p3.x;
366+
t2[0] = p2.y - p3.y;
367+
t3[0] = p1.y - p3.y;
368+
t4[0] = p2.x - p3.x;
369+
std::array<RealNumber, 2> t5_01, t6_01;
370+
t5_01[0] = t1[0] * t2[0];
371+
t6_01[0] = t3[0] * t4[0];
372+
RealNumber det = t5_01[0] - t6_01[0];
373+
RealNumber const magnitude = std::abs(t5_01[0]) + std::abs(t6_01[0]);
374+
375+
// see p.39, mind the different definition of epsilon for error bound
376+
RealNumber const A_relative_bound =
377+
(1.5 + 4 * std::numeric_limits<RealNumber>::epsilon())
378+
* std::numeric_limits<RealNumber>::epsilon();
379+
RealNumber absolute_bound = A_relative_bound * magnitude;
380+
if ( std::abs(det) >= absolute_bound )
381+
{
382+
return det; //A estimate
383+
}
384+
385+
if ( (t5_01[0] > 0 && t6_01[0] <= 0) || (t5_01[0] < 0 && t6_01[0] >= 0) )
386+
{
387+
//if diagonal and antidiagonal have different sign, the sign of det is
388+
//obvious
389+
return det;
390+
}
391+
return orient2dtail<RealNumber, Robustness>(p1, p2, p3, t1, t2, t3, t4, t5_01, t6_01, magnitude);
392+
}
393+
379394
// This method adaptively computes increasingly precise approximations of the following
380395
// determinant using Laplace expansion along the last column.
381396
// det A =
@@ -433,7 +448,8 @@ RealNumber incircle(std::array<RealNumber, 2> const& p1,
433448
(5 + 24 * std::numeric_limits<RealNumber>::epsilon())
434449
* std::numeric_limits<RealNumber>::epsilon();
435450
RealNumber absolute_bound = A_relative_bound * magnitude;
436-
if (std::abs(det) > absolute_bound) {
451+
if (std::abs(det) > absolute_bound)
452+
{
437453
return det;
438454
}
439455
// (p2_x - p4_x) * (p3_y - p4_y)
@@ -492,16 +508,16 @@ RealNumber incircle(std::array<RealNumber, 2> const& p1,
492508
std::array<RealNumber, 16> C_23_x_A_22_sq;
493509
// ( (cx - dx) * (ay - dy) - (ax - dx) * (cy - dy) ) * ( by - dy ) * ( by - dy )
494510
int C_23_x_A_22_sq_nz = scale_expansion_zeroelim(C_23_x_A_22, A_22,
495-
C_23_x_A_22_sq,
496-
C_23_x_A_22_nz);
511+
C_23_x_A_22_sq,
512+
C_23_x_A_22_nz);
497513
std::array<RealNumber, 32> A_23_x_C_23;
498-
// ( (cx - dx) * (ay - dy) - (ax - dx) * (cy - dy) )
499-
// * ( ( bx - dx ) * ( bx - dx ) + ( by - dy ) * ( by - dy ) )
514+
// ( (cx - dx) * (ay - dy) - (ax - dx) * (cy - dy) )
515+
// * ( ( bx - dx ) * ( bx - dx ) + ( by - dy ) * ( by - dy ) )
500516
int A_23_x_C_23_nz = fast_expansion_sum_zeroelim(C_23_x_A_21_sq,
501-
C_23_x_A_22_sq,
502-
A_23_x_C_23,
503-
C_23_x_A_21_sq_nz,
504-
C_23_x_A_22_sq_nz);
517+
C_23_x_A_22_sq,
518+
A_23_x_C_23,
519+
C_23_x_A_21_sq_nz,
520+
C_23_x_A_22_sq_nz);
505521

506522
// (ax - dx) * (by - dy)
507523
A_11_x_A_22[1] = two_product_tail(A_11, A_22, A_11_x_A_22[0]);
@@ -555,7 +571,8 @@ RealNumber incircle(std::array<RealNumber, 2> const& p1,
555571
(2 + 12 * std::numeric_limits<RealNumber>::epsilon())
556572
* std::numeric_limits<RealNumber>::epsilon();
557573
absolute_bound = B_relative_bound * magnitude;
558-
if (std::abs(det) >= absolute_bound) {
574+
if (std::abs(det) >= absolute_bound)
575+
{
559576
return det;
560577
}
561578
RealNumber A_11tail = two_diff_tail(p1[0], p4[0], A_11);
@@ -565,7 +582,8 @@ RealNumber incircle(std::array<RealNumber, 2> const& p1,
565582
RealNumber A_31tail = two_diff_tail(p3[0], p4[0], A_31);
566583
RealNumber A_32tail = two_diff_tail(p3[1], p4[1], A_32);
567584
if ((A_11tail == 0) && (A_21tail == 0) && (A_31tail == 0)
568-
&& (A_12tail == 0) && (A_22tail == 0) && (A_32tail == 0)) {
585+
&& (A_12tail == 0) && (A_22tail == 0) && (A_32tail == 0))
586+
{
569587
return det;
570588
}
571589
// RealNumber sub_bound = (1.5 + 2.0 * std::numeric_limits<RealNumber>::epsilon())
@@ -583,7 +601,8 @@ RealNumber incircle(std::array<RealNumber, 2> const& p1,
583601
+ ((A_31 * A_31 + A_32 * A_32) * ((A_11 * A_22tail + A_22 * A_11tail)
584602
- (A_12 * A_21tail + A_21 * A_12tail))
585603
+ 2 * (A_31 * A_31tail + A_32 * A_32tail) * (A_11 * A_22 - A_12 * A_21));
586-
//if (std::abs(det) >= absolute_bound) {
604+
//if (std::abs(det) >= absolute_bound)
605+
//{
587606
return det;
588607
//}
589608
}

include/boost/geometry/extensions/triangulation/strategies/cartesian/side_robust.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,10 @@ struct side_robust
4949
static inline PromotedType side_value(P1 const& p1, P2 const& p2,
5050
P const& p)
5151
{
52-
std::array<PromotedType, 2> pa {{ get<0>(p1), get<1>(p1) }};
53-
std::array<PromotedType, 2> pb {{ get<0>(p2), get<1>(p2) }};
54-
std::array<PromotedType, 2> pc {{ get<0>(p), get<1>(p) }};
52+
typedef ::boost::geometry::detail::precise_math::vec2d<PromotedType> vec2d;
53+
vec2d pa { get<0>(p1), get<1>(p1) };
54+
vec2d pb { get<0>(p2), get<1>(p2) };
55+
vec2d pc { get<0>(p), get<1>(p) };
5556
return ::boost::geometry::detail::precise_math::orient2d
5657
<PromotedType, Robustness>(pa, pb, pc);
5758
}

0 commit comments

Comments
 (0)