convex-hull algorithms in c++...4 1. introduction the problem of computing the convex hull for a...

107
Convex-hull algorithms in C++ Ask Neve Gamby 1 and Jyrki Katajainen 1,2 1 Department of Computer Science, University of Copenhagen, Universitetsparken 5, 2100 Copenhagen East, Denmark 2 Jyrki Katajainen and Company, 3390 Hundested, Denmark; [email protected] Abstract. In the two-dimensional convex-hull problem we are given a multiset S of points and the task is to find those points of S that are the vertices of the smallest convex polygon enclosing all the points of S. In the output the vertices must be reported in the order in which they appear along the boundary of the polygon— either in clockwise or counterclockwise order. Further, when the coordinates of the points are integers, the computed output should always be correct. This collection contains our implementations of the following convex-hull al- gorithms: plane-sweep, torch, divide & conquer, quickhull, poles-first, throw-away, introhull, and bucketing. For an input of size n, none of our implementations use more than O( n) extra words of memory and all run in linear expected time when the input points are randomly distributed. As far as we know, this collection contains the best known algorithms—both with respect to time and space usage. If you know a better algorithm—or a better implementation written in C++—and think that it should be in this collection, let us know. Keep in mind that we promise a reward of 2.56 brownie points for every person who is the first to report an error in one of the programs released in this collection. Keywords. Computational geometry, convex hull, algorithm collection, quality of implementation, robustness CPH STL Report 2018-1, February 2018. Revised March 2018, August 2018, September 2018, October 2018, February 2019, September 2019, May 2020

Upload: others

Post on 27-Aug-2020

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

Convex-hull algorithms in C++

Ask Neve Gamby1 and Jyrki Katajainen1,2

1 Department of Computer Science, University of Copenhagen,Universitetsparken 5, 2100 Copenhagen East, Denmark

2 Jyrki Katajainen and Company, 3390 Hundested, Denmark;[email protected]

Abstract. In the two-dimensional convex-hull problem we are given a multiset Sof points and the task is to find those points of S that are the vertices of the smallestconvex polygon enclosing all the points of S. In the output the vertices must bereported in the order in which they appear along the boundary of the polygon—either in clockwise or counterclockwise order. Further, when the coordinates of thepoints are integers, the computed output should always be correct.

This collection contains our implementations of the following convex-hull al-gorithms: plane-sweep, torch, divide&conquer, quickhull, poles-first,throw-away, introhull, and bucketing. For an input of size n, none of ourimplementations use more than O(

√n) extra words of memory and all run in linear

expected time when the input points are randomly distributed.As far as we know, this collection contains the best known algorithms—both

with respect to time and space usage. If you know a better algorithm—or a betterimplementation written in C++—and think that it should be in this collection, letus know. Keep in mind that we promise a reward of 2.56 brownie points for everyperson who is the first to report an error in one of the programs released in thiscollection.

Keywords. Computational geometry, convex hull, algorithm collection, quality ofimplementation, robustness

CPH STL Report 2018-1, February 2018. Revised March 2018, August 2018,September 2018, October 2018, February 2019, September 2019, May 2020

Page 2: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

Contents

Abstract . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 Simple use case . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 Use of the makefile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7A Source code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

A.1 Copyright notice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8A.2 Release date . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

B Convex-hull algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9B.1 plane_sweep.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9B.2 plane_sweep_with_bucketsort.h++ . . . . . . . . . . . . . . . . . . . . . . . 14B.3 torch.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14B.4 divide_and_conquer.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19B.5 quickhull.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24B.6 poles_first.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28B.7 throw_away.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31B.8 introhull.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36B.9 bucketing.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

C Micro-benchmarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47C.1 multiple_precision.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47C.2 double_precision.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47C.3 floating_point_filter.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48C.4 fhistogram.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48C.5 ihistogram.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50C.6 minmax_element.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52C.7 partition.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52C.8 copy.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53C.9 sort.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53C.10lexicographic_sort.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53C.11angular_sort.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54C.12bsort.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55C.13tsort.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55C.14shuffle.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56

D Helpers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57D.1 point.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57D.2 validation.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67D.3 bucketsort.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73D.4 two_phase_bucketsort.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76D.5 cphstl/slices.h++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78

2

Page 3: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

3

E Drivers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85E.1 check−driver.c++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85E.2 test−driver.c++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85E.3 driver.c++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95

F Makefile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104F.1 makefile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104

Page 4: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

4

1. Introduction

The problem of computing the convex hull for a multiset of points in theEuclidean plane is well studied in computational geometry. One may thinkthat this problem is easy and solved, but many of the descriptions andprograms one can find from the Internet are of low quality. Actually, itis a non-trivial task to write a program that handles all the special casescorrectly. In particular, we want to solve the problem without the usualsimplifying assumptions about the input: there can be duplicates amongthe input and the points need not be in a general position.

For a proper introduction to the topic, we refer to the textbook by Cormenet al. [4, Section 33.3]. This book makes good job in explaining Graham’srotational-sweep algorithm [11], but this algorithm is not very efficientin practice. The convex-hull algorithms (plane-sweep [2], torch [10], di-vide&conquer [14], quickhull [6], poles-first [1], throw-away [5],introhull [8], and bucketing [9]), the implementations of which are in-cluded in this collection, are known to be faster. We have tried to implementthese algorithms in the best possible way, but we have to admit that we havemade many embarrassing errors on the journey. Some of the algorithms caneven be implemented space-optimally if needed. Still, there are certainlyroom for improvements. Do not hesitate to contact us if you have any con-structive feedback.

Our hope is that people start to use these programs as baselines in theirfuture studies. If you can implement an algorithm that beats all the algo-rithms in this collection, we can just congratulate you. In this case, it isquite probable that you have something that could be published.

Recall that a point q of a convex set X is called an extreme point if notwo other points p and r exist in X such that q lies on the line segment pr.Hence, the vertices of the convex polygon P describing the convex hull areprecisely the extreme points of the smallest convex set enclosing the pointsof S.

Let us assume that the input points are given in a sequence, i.e. in astd::vector. An in-place convex-hull algorithm (see, for example, [3]) parti-tions this sequence into two parts: (1) the first part contains all the extremepoints in clockwise or counterclockwise order of their appearance on P and(2) the second part contains all the remaining points that are inside P oron the periphery of P .

All the algorithms in this collection rearrange the points in the inputsequence in place. In addition to this side effect, the algorithms return aniterator to the first interior point. Thus, for two iterators i and k, if therange Ji . . k M specifies the input and j is the returned output, the rangeJi . . j M contains the extreme points in circular order and the range Jj . . k Mcontains the interior points eliminated during the computation.

Each algorithm is implemented in its own namespace which provides thefunction solve that can be used to compute the convex hull for a givensequence, and the function check that can be used to verify the correctness

Page 5: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

5

of the corresponding solver. If I is the iterator type used by the inputsequence, the signatures of these two functions are as follows:

template<typename I>using solver = I (∗)(I , I) ;

template<typename I>using checker = bool (∗)(I , I) ;

That is, the signature of an in-place solver is similar to that of the genericfunction std::partition in the C++ standard library.

To summarize, a solver takes two iterators specifying the first and thepast-the-end positions of the input sequence and, after reordering the points,the return value specifies the end of the computed convex hull and thebeginning of all interior points in the very same sequence. Even if theusers think that the computation is done in place, the solvers may use sometemporary storage to speed up the computation.

A checker should have no side effects. Therefore, it takes a copy of theinput, solves the problem with a solver, and uses the tools in our test frame-work to check that we still have the same points in the output, that theoutput is actually a convex polygon, and that all the input points are insideor on the boundary of the computed convex polygon.

2. Simple use case

Consider now a simple use case where we want to compute the convex hullfor a multiset of four points (0, 0), (0, 1), (0, 2), and (0, 1). Let us use theplane-sweep algorithm to do the computation.

#include <cassert> // assert macro#include <iostream> // std streams#include ”plane sweep.h++” // plane sweep : : solve#include ”point .h++” // point#include <vector> // std : : vector

int main( ) {using P = point<int> ;using S = std : :vector<P> ;using I = typename S : :iterator ;

S bag{P(0 , 0) , P(0 , 1) , P(0 , 2) , P(0 , 1)};

I rest = plane_sweep : :solve(bag.begin( ) , bag.end( )) ;auto h = rest − bag.begin( ) ;assert(h == 2) ;for (I i = bag.begin( ) ; i =6== rest ; ++i) {std : :cout << ∗i << ” ”;}std : :cout << ”\n”;}

Page 6: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

6

As shown below, when this program was run on a terminal, it printed outtwo points: (0, 0) (0, 2). In this case, a checker would have accepted theoutput even if the extreme points were reported in opposite order.

shell> g++−8 −O3 −std=c++2a −Wall −Wextra −x c++ use-case.c++shell> ./a.out(0 , 0) (0 , 2)

If you want to perform the experiments with the multiple-precision in-tegers, you have to install the CPH STL integers [13] and the CPH MPL[12]. Since both of these library components rely on concepts, you shouldcompile the code with the option −fconcepts. We had these tools in theparent directory, so we also had to use the compiler option −I.. .

3. Use of the makefile

You can use make to redo the experiments done in the papers [7, 8, 9]. Foreach convex-hull algorithm x, the makefile provides the following facilities.For the sake of concreteness, we fix x to be quickhull.quickhull.check. Run a unittest to check that the code compiles.quickhull.test. Run the program through all our test cases.quickhull.square. Run the CPU benchmark for the square data set.quickhull.disc. Run the CPU benchmark for the disc data set.quickhull.bell. Run the CPU benchmark for the bell data set—i.e. the

points are drawn according to a discrete normal distribution.quickhull.sorted. Run the CPU benchmark for a presorted data set—

i.e. the points are given in sorted order according to their x-coordinates.quickhull.universe. Run the CPU benchmark for the saturated-universe

data set.quickhull.special. Run the CPU benchmark for the special data set where

there are four poles and many duplicates in the centre.quickhull.line. Run the CPU benchmark for a multiset of random points

on a line.quickhull.parabola. Run the CPU benchmark for a multiset of random

points on a parabola.quickhull.turn. Measure how many times an orientation test is called.quickhull.comp. Measure how many coordinate comparisons are performed.quickhull.move. Measure how many coordinate moves are performed.quickhull.benchmark. Redo the most relevant experiments for quickhull

in one go. For algorithm x, the results will be placed in the log filex.log.

If you want to run the benchmarks for the largest data set (n = 230),you have to enable it in the makefile. Each of these huge experiments tookabout 10 minutes in our Linux computer.

As an example, let us run the plane-sweep algorithm for the squaredata set. In this case the driver driver.c++ will report the size of the input(n) and the running time in nanoseconds divided by n.

Page 7: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

7

shell> make plane_sweep.squareg++−8 −O3 −std=c++2a −Wall −Wextra −x c++ −fconcepts −DNDEBUG −I. . −DNAME=plane_sweep

↪→ driver.c++1024 59.332768 75.71048576 92.9433554432 111.3

The same makefile can also handle the micro-benchmarks since theseare packaged in the same way as the convex-hull algorithms. Each micro-benchmark is defined its own namespace—the name of this namespace is thesame as the name of the file without the trailing suffix h++ —and the driverwill run the function solve in this namespace. To give an example, let ussee how fast introsort can sort a sorted sequence of points according totheir x-coordinates:

shell> make sort.sortedg++−8 −O3 −std=c++2a −Wall −Wextra −x c++ −fconcepts −DNDEBUG −I. . −DSORTED −DNAME=sort

↪→ driver.c++1024 7.18732768 10.831048576 15.233554432 20.84

It is amazing that, even in this case, bucketsort can speed things up(but two-phase bucketsort makes things slower—try it yourself). Inthe plane-sweep algorithm, two-phase bucketsort can be used by dis-abling the macro definition TWO_PHASE_BUCKETSORT.

shell> make bsort.sortedg++−8 −O3 −std=c++2a −Wall −Wextra −x c++ −fconcepts −DNDEBUG −I. . −DSORTED −

↪→ DNAME=bsort driver.c++1024 6.88932768 7.1241048576 8.44733554432 13.08

References

[1] S. G. Akl and G. T. Toussaint, A fast convex hull algorithm, Inform. Process. Lett.7, 5 (1978), 219–222. https://doi.org/10.1016/0020-0190(78)90003-0

[2] A. M. Andrew, Another efficient algorithm for convex hulls in two dimensions, In-form. Process. Lett. 9, 5 (1979), 216–219. https://doi.org/10.1016/0020-0190(79)90072-3

[3] H. Bronnimann, J. Iacono, J. Katajainen, P. Morin, J. Morrison, and G. Toussaint,Space-efficient planar convex hull algorithms, Theoret. Comput. Sci. 321, 1 (2004),25–40. https://doi.org/10.1016/j.tcs.2003.05.004

[4] T. H. Cormen, C. E. Leiserson, R. L. Rivest, and C. Stein, Introduction toAlgorithms, 3rd edition, The MIT Press (2009). https://isbnsearch.org/isbn/978-0-262-03384-8

[5] L. Devroye and G. T. Toussaint, A note on linear expected time algorithms forfinding convex hulls, Computing 26, 4 (1981), 361–366. https://doi.org/10.1007/

Page 8: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

8

BF02237955[6] W. F. Eddy, A new convex hull algorithm for planar sets, ACM Trans. Math. Software

3, 4 (1977), 398–403. https://doi.org/10.1145/355759.355766[7] A. N. Gamby and J. Katajainen, A note on the implementation quality of a convex-

hull algorithm, CPH STL report 2017-3, Dept. Comput. Sci., Univ. Copenhagen(2017). Retrieved 27 November 2018 from http://hjemmesider.diku.dk/~jyrki/Myris/GK2017R.html

[8] A. N. Gamby and J. Katajainen, Convex-hull algorithms: Implementation, test-ing, and experimentation, Algorithms 11, 12 (2018). https://doi.org/10.3390/a11120195

[9] Ask Neve Gamby and Jyrki Katajainen, A faster convex-hull algorithm via bucket-ing, Proceedings of the 18th International Symposium on Experimental Algorithms,Lecture Notes in Computer Science, Springer (2019). Retrieved 8 September 2019from http://hjemmesider.diku.dk/~jyrki/Myris/GK2019C.html

[10] A. J. P. Gomes, A total order heuristic-based convex hull algorithm for points inthe plane, Comput.-Aided Design 70 (2016), 153–160. https://doi.org/10.1016/j.cad.2015.07.013

[11] R. L. Graham, An efficient algorithm for determining the convex hull of a finiteplanar set, Inform. Process. Lett. 1, 4 (1972), 132–133. https://doi.org/10.1016/0020-0190(72)90045-2

[12] J. Katajainen, Pure compile-time functions and classes in the CPH MPL, CPH STLreport 2017-2, Dept. Comput. Sci., Univ. Copenhagen (2017). Retrieved 27 Novem-ber 2018 from http://hjemmesider.diku.dk/~jyrki/Myris/Kat2017R.html

[13] J. Katajainen, Class templates cphstl::N and cphstl::Z for fixed-precision arith-metic, Work in progress (2017–2019).

[14] F. P. Preparata and S. J. Hong, Convex hulls of finite sets of points in two andthree dimensions, Commun. ACM 20, 2 (1977), 87–93. https://doi.org/10.1145/359423.359430

A. Source code

A.1 Copyright notice

Copyright© 2000–2019 by Performance Engineering Laboratory (University of Copen-hagen)© 2000–2020 by The authors

The programs included in the CPH STL may be freely copied and dis-tributed, provided that no changes whatsoever are made. Changes are per-missible only if the modified files are given new names, different from thenames of existing files in the CPH STL, and only if the modified files areclearly identified as not being part of the library. The programs may alsobe used in part, as long as they are attributed to the original source. Usageof the source code in derived works is otherwise unrestricted.

The authors have tried to produce correct and useful programs, but nowarranty of any kind should be assumed.

A.2 Release date

2020-05-14

Page 9: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

9

B. Convex-hull algorithms

B.1 plane_sweep.h++

1 /∗2 Performance Engineering Laboratory © 2017−20193 ∗/4

5 #ifndef __PLANE_SWEEP__6 #define __PLANE_SWEEP__7

8 #define FLOATING_POINT_FILTER9

10 #include <algorithm> // std : : sort std : : partition . . .11 #include <cassert> // assert macro12 #include ”cphmpl/functions .h++” // cphmpl type functions13 #include ”cphstl/s l ices .h++” // cphstl s l ices14 #include <cstdlib> // std : : s ize t15 #include <functional> // std : : less std : : greater16 #include <iterator> // std : : next std : : prev std : : distance17 #include ”point .h++” // left turn right turn18 #include <tuple> // std : : tuple std : : make tuple std : : t ie19 #include <utility> // std : : pair std : : get . . .20 #include ”validation .h++” // same multiset convex polygon all inside21

22 #ifdef TWO_PHASE_BUCKETSORT23

24 #include ”two phase bucketsort.h++” // two phase bucketsort : : sort25

26 #endif27

28 namespace plane_sweep {29

30 template<typename variable>31 void ignore_warning(variable) {32 }33

34 template<typename T , typename I = typename std : :tuple_element<0, T> : :type>35 requires cphmpl : :is_pair<T> and cphmpl : :is_iterator<I>36 constexpr void parallel_iter_swap(T a , T b) {37 I a1 ;38 I a2 ;39 std : :tie(a1 , a2 ) = a ;40 I b1 ;41 I b2 ;42 std : :tie(b1 , b2 ) = b ;43 assert(a1 =6== a2 and b1 =6== b2 ) ;44 std : :iter_swap(a1 , b1 ) ;45 i f (a1 == b2 ) {46 std : :iter_swap(a2 , b1 ) ;47 }48 else {

Page 10: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

10

49 std : :iter_swap(a2 , b2 ) ;50 }51 }52

53 template<typename R , typename I = cphmpl : :iterator<R>>54 requires cphmpl : :specifies_range<R> and is_point<cphmpl : :value<R>>55 constexpr std : :pair<I , I> find_poles(R const& range) {56 I first = std : :cbegin(range) ;57 I past = std : :cend(range) ;58 using P = cphmpl : :value<I> ;59 std : :pair<I , I> pair = std : :minmax_element(first, past,60 [ ](P const& a , P const& b) → bool {61 return (a.x < b.x) or (a.x == b.x and a.y < b.y) ;62 }) ;63 return pair ;64 }65

66 template<typename R , typename I>67 requires cphmpl : :specifies_range<R> and is_point<cphmpl : :value<R>> and

↪→ cphmpl : :is_iterator<I> and is_point<cphmpl : :value<I>>68 I partition_above_below(R& range, I pole, I antipole) {69 I first = std : :begin(range) ;70 I past = std : :end(range) ;71 using P = cphmpl : :value<I> ;72 using T = typename P : :coordinate ;73 T upper_limit = std : :max((∗pole) .y , (∗antipole) .y) ;74 T lower_limit = std : :min((∗pole) .y , (∗antipole) .y) ;75 I mid = std : :partition(first, past,76 [&](P const& q) → bool {77 i f (q.y ≥ upper_limit) {78 return true ;79 }80 else if (q.y ≤ lower_limit) {81 return false ;82 }83 return not left_turn(∗pole, q , ∗antipole) ;84 }) ;85 return mid ;86 }87

88 template<typename I , typename C>89 std : :pair<I , I> clean(I pole, I past, C compare) {90 assert(pole =6== past) ;91 using P = cphmpl : :value<I> ;92 I k = std : :next(pole) ;93 while (k =6== past and (∗k) .x == (∗pole) .x) {94 ++k ;95 }96 i f (k == std : :next(pole)) {97 return std : :make_pair(pole, std : :next(pole)) ; // (top , next)98 }99 I top = std : :max_element(std : :next(pole) , k ,

Page 11: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

11

100 [&](P const& p , P const& q) → bool {101 return compare(p.y , q.y) ;102 }) ;103 i f ((∗top) .y == (∗pole) .y) {104 return std : :make_pair(pole, k) ;105 }106 std : :iter_swap(std : :next(pole) , top) ;107 return std : :make_pair(std : :next(pole) , k) ;108 }109

110 template<typename R , typename I>111 requires cphmpl : :specifies_range<R> and cphmpl : :is_iterator<I>112 constexpr I swap_ranges(R& range, I target) {113 using J = cphmpl : :iterator<R> ;114 J source = std : :begin(range) ;115 J past = std : :end(range) ;116 i f (source == past) {117 return target ;118 }119 i f (source == target) {120 return past ;121 }122 using V = cphmpl : :value<I> ;123 I hole = target ;124 V const t = std : :move(∗target) ;125 I const last = std : :prev(past) ;126 while (true) {127 ∗hole = std : :move(∗source) ;128 ++hole ;129 i f (source == last) {130 break;131 }132 ∗source = std : :move(∗hole) ;133 ++source ;134 }135 ∗source = std : :move(t) ;136 return hole ;137 }138

139 template<typename I , typename C , typename K>140 void sort(I first, I past, C compare, K key) {141

142 #ifdef TWO_PHASE_BUCKETSORT143

144 two_phase_bucketsort : :sort(first, past, compare, key) ;145

146 #else147

148 ignore_warning(key) ;149 std : :sort(first, past, compare) ;150

151 #endif

Page 12: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

12

152

153 }154

155 template<typename I>156 I scan(I first, I top, I next, I past) {157 assert(first =6== past) ;158 for (I i = next ; i =6== past ; ++i) {159 while (top =6== first and not right_turn(∗std : :prev(top) , ∗top, ∗i)) {160 −−top ;161 }162 ++top ;163 std : :iter_swap(i , top) ;164 }165 return ++top ;166 }167

168 template<typename I>169 I scan_one_more(I first, I top, I extra) {170 while (top =6== first and not right_turn(∗std : :prev(top) , ∗top, ∗extra)) {171 −−top ;172 }173 return ++top ;174 }175

176 template<typename I , typename C>177 I chain(I pole, I rest, I antipole, C compare) {178 using P = cphmpl : :value<I> ;179 using T = typename P : :coordinate ;180 i f (std : :distance(pole, rest) == 1) {181 return rest ;182 }183 sort(std : :next(pole) , rest,184 [&](P const& p , P const& q) → bool {185 return compare(p.x , q.x) ;186 } ,187 [ ](P const& p) → T {188 return p.x ;189 }) ;190 std : :pair<I , I> pair = clean(pole, rest, compare) ;191 I top = std : :get<0>(pair) ;192 I next = std : :get<1>(pair) ;193 I interior = scan(pole, top, next, rest) ;194 interior = scan_one_more(pole, std : :prev(interior) , antipole) ;195 return interior ;196 }197

198 template<typename I>199 I solve(I first, I past) {200 using P = cphmpl : :value<I> ;201 using T = typename P : :coordinate ;202 std : :size_t n = std : :distance(first, past) ;203 i f (n < 2) {

Page 13: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

13

204 return past ;205 }206 auto sequence = cphstl : :slice(first, past) ;207 std : :pair<I , I> poles = find_poles(sequence) ;208 I last = std : :prev(past) ;209 parallel_iter_swap(std : :make_pair(first, last) , poles) ;210 i f (∗first == ∗last) {211 return std : :next(first) ;212 }213 auto whole_range = cphstl : :slice(std : :next(first) , last) ;214 I middle = partition_above_below(whole_range, first, last) ;215 I continuation = chain(first, middle, last, std : :less<T>( )) ;216 std : :iter_swap(middle, last) ;217 I rest = chain(middle, past, first, std : :greater<T>( )) ;218 auto second_part = cphstl : :slice(middle, rest) ;219 I interior = swap_ranges(second_part, continuation) ;220 return interior ;221 }222

223 template<typename R>224 requires cphmpl : :specifies_range<R> and is_point<cphmpl : :value<R>>225 cphmpl : :iterator<R> solve(R& sequence) {226 return solve(std : :begin(sequence) , std : :end(sequence)) ;227 }228

229 template<typename I>230 bool check(I first, I past) {231 using P = typename std : :iterator_traits<I> : :value_type ;232 using S = std : :vector<P> ;233 using J = typename S : :iterator ;234 S data ;235 std : :size_t n = std : :distance(first, past) ;236 data.resize(n) ;237 std : :copy(first, past, data.begin( )) ;238 J rest = solve(data.begin( ) , data.end( )) ;239 bool ok = validation : :same_multiset(data.begin( ) , data.end( ) , first, past) and

↪→ validation : :convex_polygon(data.begin( ) , rest) and validation : :all_inside(rest,↪→ data.end( ) , data.begin( ) , rest) ;

240 return ok ;241 }242

243 template<typename R>244 requires cphmpl : :specifies_range<R> and is_point<cphmpl : :value<R>>245 bool check(R const& sequence) {246 return check(std : :cbegin(sequence) , std : :cend(sequence)) ;247 }248 }249

250 #endif

Page 14: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

14

B.2 plane_sweep_with_bucketsort.h++

1 /∗2 Performance Engineering Laboratory © 2017−20193 ∗/4

5 #ifndef __PLANE_SWEEP_WITH_BUCKETSORT__6 #define __PLANE_SWEEP_WITH_BUCKETSORT__7

8 #define TWO_PHASE_BUCKETSORT9

10 #include ”two phase bucketsort.h++” // two phase bucketsort : : sort11 #include ”plane sweep.h++” // plane sweep : : solve plane sweep : : check12

13 namespace plane_sweep_with_bucketsort {14

15 template<typename I>16 I solve(I first, I past) {17 I rest = plane_sweep : :solve(first, past) ;18 return rest ;19 }20

21 template<typename I>22 bool check(I first, I past) {23 bool ok = plane_sweep : :check(first, past) ;24 return ok ;25 }26 }27

28 #endif

B.3 torch.h++

1 /∗2 Performance Engineering Laboratory © 2017−20183 ∗/4

5 #ifndef __TORCH__6 #define __TORCH__7

8 #define FLOATING_POINT_FILTER9

10 #include <algorithm> // std : : sort std : : partition . . .11 #include <cassert> // assert macro12 #include <cstdlib> // std : : s ize t13 #include <iterator> // std : : iterator traits std : : distance . . .14 #include ”point .h++” // right turn15 #include <utility> // std : : pair std : : get16 #include ”validation .h++” // same multiset convex polygon all inside17

18 namespace torch {

Page 15: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

15

19

20 // move ∗st <− ∗rd and ∗nd <− ∗th by swaps in parallel21

22 template<typename I>23 void parallel_iter_swap(I st , I nd , I rd , I th) {24 assert(st =6== nd and rd =6== th) ;25 std : :iter_swap(st , rd) ;26 i f (th == st) {27 std : :iter_swap(nd , rd) ;28 }29 else {30 std : :iter_swap(nd , th) ;31 }32 }33

34 template<typename I>35 I go_upstairs(I first, I past) {36 i f (first == past) {37 return past ;38 }39 using P = typename std : :iterator_traits<I> : :value_type ;40 using T = typename P : :coordinate ;41 T max = (∗first) .y ;42 I i = std : :next(first) ;43 for (I j = std : :next(first) ; j =6== past ; ++j) {44 i f ((∗j) .y ≥ max) {45 max = (∗j) .y ;46 std : :iter_swap(i , j) ;47 ++i ;48 }49 }50 return i ;51 }52

53 template<typename I>54 I go_downstairs(I first, I past) {55 i f (first == past) {56 return past ;57 }58 using P = typename std : :iterator_traits<I> : :value_type ;59 using T = typename P : :coordinate ;60 T min = (∗first) .y ;61 I i = std : :next(first) ;62 for (I j = std : :next(first) ; j =6== past ; ++j) {63 i f ((∗j) .y ≤ min) {64 min = (∗j) .y ;65 std : :iter_swap(i , j) ;66 ++i ;67 }68 }69 return i ;70 }

Page 16: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

16

71

72 template<typename I>73 I scan(I first, I past) {74 assert(first =6== past) ;75 I top = first ;76 for (I i = std : :next(first) ; i =6== past ; ++i) {77 while (top =6== first and not right_turn(∗std : :prev(top) , ∗top, ∗i)) {78 −−top ;79 }80 ++top ;81 std : :iter_swap(i , top) ;82 }83 return ++top ;84 }85

86 template<typename I>87 I scan_one_more(I first, I top, I extra) {88 while (top =6== first and not right_turn(∗std : :prev(top) , ∗top, ∗extra)) {89 −−top ;90 }91 return ++top ;92 }93

94 template<typename I>95 I solve(I first, I past) {96 using P = typename std : :iterator_traits<I> : :value_type ;97 using T = typename P : :coordinate ;98 std : :size_t n = std : :distance(first, past) ;99 i f (n < 2) {

100 return past ;101 }102

103 // find the west and east poles104

105 std : :pair<I , I> pair = std : :minmax_element(first, past,106 [ ](P const& a , P const& b) → bool {107 return (a.x < b.x) or (a.x == b.x and a.y < b.y) ;108 }) ;109 I west = std : :get<0>(pair) ;110 I east = std : :get<1>(pair) ;111

112 // al l points equal?113

114 i f (∗west == ∗east) {115 return std : :next(first) ;116 }117

118 // al l points on a vertical line?119

120 i f ((∗west) .x == (∗east) .x) {121 parallel_iter_swap(first, std : :next(first) , west, east) ;122 return std : :next(std : :next(first)) ;

Page 17: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

17

123 }124

125 // move west to its f inal place and east temporarily to the end126

127 I last = std : :prev(past) ;128 parallel_iter_swap(first, last, west, east) ;129 west = first ;130 east = last ;131

132 // find the south and north poles133

134 pair = std : :minmax_element(first, past,135 [ ](P const& a , P const& b) → bool {136 return (a.y < b.y) or (a.y == b.y and a.x < b.x) ;137 }) ;138 I south = std : :get<0>(pair) ;139 I north = std : :get<1>(pair) ;140

141 bool east_north_same = (∗east == ∗north) ;142 bool west_south_same = (∗west == ∗south) ;143 bool west_north_same = (∗west == ∗north) ;144 bool east_south_same = (∗east == ∗south) ;145

146 // recall the quadrant borders147

148 T westy = (∗west) .y ;149 T easty = (∗east) .y ;150 T northx = (∗north) .x ;151 T southx = (∗south) .x ;152

153 // north−west corner154

155 I done = std : :next(west) ;156 i f (not west_north_same) {157 I rest = std : :partition(done, last,158 [&](P const& a) → bool {159 return (a.x ≤ northx ) and (a.y ≥ westy ) ;160 }) ;161 i f (rest =6== done) {162 std : :sort(done, rest,163 [ ](P const& a , P const& b) → bool {164 return (a.x < b.x) ;165 }) ;166 rest = go_upstairs(west, rest) ;167 rest = scan(west, rest) ;168 done = scan_one_more(west, std : :prev(rest) , east) ;169 }170 }171

172 // move east to Q2

173

174 std : :iter_swap(done, east) ;

Page 18: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

18

175 east = done ;176 done = std : :next(done) ;177

178 // north−east corner179

180 i f (not east_north_same) {181 I top = std : :prev(east) ;182 I rest = std : :partition(done, past,183 [&](P const& a) → bool {184 return (a.x ≥ northx ) and (a.y ≥ easty ) ;185 }) ;186 i f (rest =6== done) {187 std : :iter_swap(top, east) ;188 std : :swap(top, east) ;189 std : :iter_swap(top, std : :prev(rest)) ;190 top = std : :prev(rest) ;191 std : :sort(std : :next(east) , top,192 [ ](P const& a , P const& b) → bool {193 return (a.x > b.x) ;194 }) ;195 rest = go_upstairs(east, rest) ;196 std : :reverse(east, rest) ;197 top = east ;198 done = scan(top, rest) ;199 east = std : :prev(done) ;200 }201 }202

203 // south−east corner204

205 i f (not east_south_same) {206 I rest = std : :partition(done, past,207 [&](P const& a) → bool {208 return (a.x ≥ southx ) and (a.y ≤ easty ) ;209 }) ;210 i f (rest =6== done) {211 std : :sort(done, rest,212 [ ](P const& a , P const& b) → bool {213 return (a.x > b.x) ;214 }) ;215 rest = go_downstairs(east, rest) ;216 rest = scan(east, rest) ;217 done = scan_one_more(east, std : :prev(rest) , west) ;218 }219 }220

221 // south−west corner222

223 i f (not west_south_same) {224 I bottom = std : :prev(done) ;225 I rest = std : :partition(done, past,226 [&](P const& a) → bool {

Page 19: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

19

227 return (a.x ≤ southx ) and (a.y ≤ westy ) ;228 }) ;229 i f (rest =6== done) {230 std : :iter_swap(bottom, std : :prev(rest)) ;231 std : :sort(bottom, std : :prev(rest) ,232 [ ](P const& a , P const& b) → bool {233 return (a.x < b.x) ;234 }) ;235 rest = go_downstairs(bottom, rest) ;236 std : :reverse(bottom, rest) ;237 rest = scan(bottom, rest) ;238 done = scan_one_more(bottom, std : :prev(rest) , west) ;239 }240 }241 return done ;242 }243

244 template<typename I>245 bool check(I first, I past) {246 using P = typename std : :iterator_traits<I> : :value_type ;247 using S = std : :vector<P> ;248 using J = typename S : :iterator ;249 S data ;250 std : :size_t n = std : :distance(first, past) ;251 data.resize(n) ;252 std : :copy(first, past, data.begin( )) ;253 J rest = solve(data.begin( ) , data.end( )) ;254 bool ok = validation : :same_multiset(data.begin( ) , data.end( ) , first, past) and

↪→ validation : :convex_polygon(data.begin( ) , rest) and validation : :all_inside(rest,↪→ data.end( ) , data.begin( ) , rest) ;

255 return ok ;256 }257 }258

259 #endif

B.4 divide_and_conquer.h++

1 /∗2 Performance Engineering Laboratory © 2018−20193 ∗/4

5 #ifndef __DIVIDE_AND_CONQUER__6 #define __DIVIDE_AND_CONQUER__7

8 #define FLOATING_POINT_FILTER9

10 #include <algorithm> // std : : sort std : : partition . . .11 #include <cassert> // assert macro12 #include <cstdlib> // std : : s ize t13 #include <functional> // std : : less std : : greater

Page 20: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

20

14 #include <iterator> // std : : iterator traits15 #include <list> // std : : l i s t16 #include ”point .h++” // left turn right turn17 #include <utility> // std : : pair std : : get . . .18 #include ”validation .h++” // same multiset convex polygon all inside19 #include <vector> // std : : vector20

21 namespace divide_and_conquer {22

23 // move ∗st <− ∗rd and ∗nd <− ∗th by swaps in parallel24

25 template<typename I>26 void parallel_iter_swap(I st , I nd , I rd , I th) {27 assert(st =6== nd and rd =6== th) ;28 std : :iter_swap(st , rd) ;29 i f (th == st) {30 std : :iter_swap(nd , rd) ;31 }32 else {33 std : :iter_swap(nd , th) ;34 }35 }36

37 template<typename I>38 std : :pair<I , I> find_poles(I first, I past) {39 using P = typename std : :iterator_traits<I> : :value_type ;40 auto pair = std : :minmax_element(first, past,41 [ ](P const& a , P const& b) → bool {42 return (a.x < b.x) or (a.x == b.x and a.y < b.y) ;43 }) ;44 return pair ;45 }46

47 template<typename I>48 I partition_upper_lower(I first, I past) {49 assert(first =6== past) ;50 using P = typename std : :iterator_traits<I> : :value_type ;51 using T = typename P : :coordinate ;52 std : :pair<I , I> pair = find_poles(first, past) ;53 I west = first ;54 I east = std : :prev(past) ;55 parallel_iter_swap(west, east, std : :get<0>(pair) , std : :get<1>(pair)) ;56

57 T upper_limit = std : :max((∗west) .y , (∗east) .y) ;58 T lower_limit = std : :min((∗west) .y , (∗east) .y) ;59 I i = std : :partition(std : :next(west) , east,60 [&](P const& q) → bool {61 i f (q.y ≥ upper_limit) {62 return true ;63 }64 else if (q.y ≤ lower_limit) {65 return false ;

Page 21: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

21

66 }67 return not left_turn(∗west, q , ∗east) ;68 }) ;69 std : :iter_swap(i , east) ;70 return std : :next(i) ;71 }72

73 template<typename I , typename C>74 std : :pair<I , I> clean(I pole, I rest, C compare) {75 assert(pole =6== rest) ;76 I k = std : :next(pole) ;77 while (k =6== rest and (∗k) .x == (∗pole) .x) {78 ++k ;79 }80 i f (k == std : :next(pole)) {81 return std : :make_pair(pole, std : :next(pole)) ; // (top , next)82 }83 I bottom = std : :min_element(pole, k , compare) ;84 std : :iter_swap(pole, bottom) ;85 I top = std : :max_element(std : :next(pole) , k , compare) ;86 i f ((∗top) .y == (∗pole) .y) {87 return std : :make_pair(pole, k) ;88 }89 std : :iter_swap(std : :next(pole) , top) ;90 return std : :make_pair(std : :next(pole) , k) ;91 }92

93 template<typename I>94 void swap_blocks(I source, I past, I target) {95 // retains the order in [ source , past)96 i f (source == target or source == past) {97 return;98 }99 using P = typename std : :iterator_traits<I> : :value_type ;

100 I hole = target ;101 P p = ∗target ;102 I const last = std : :prev(past) ;103 while (true) {104 ∗hole = ∗source ;105 ++hole ;106 i f (source == last) {107 break;108 }109 ∗source = ∗hole ;110 ++source ;111 }112 ∗source = p ;113 }114

115 template<typename I>116 I scan(I first, I top, I next, I past) {117 assert(first =6== past) ;

Page 22: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

22

118 for (I i = next ; i =6== past ; ++i) {119 while (top =6== first and not right_turn(∗std : :prev(top) , ∗top, ∗i)) {120 −−top ;121 }122 ++top ;123 std : :iter_swap(i , top) ;124 }125 return ++top ;126 }127

128 template<typename I>129 I scan_one_more(I first, I top, I extra) {130 while (top =6== first and not right_turn(∗std : :prev(top) , ∗top, ∗extra)) {131 −−top ;132 }133 return ++top ;134 }135

136 template<typename I , typename C>137 I brute_force(I first, I past, C compare) {138 std : :size_t n = std : :distance(first, past) ;139 assert(n ≤ 2) ;140 i f (n ≤ 1) {141 return past ;142 }143 I second = std : :next(first) ;144 i f (compare((∗first) .x , (∗second) .x)) {145 return std : :next(second) ;146 }147 i f (compare((∗second) .x , (∗first) .x)) {148 std : :iter_swap(first, second) ;149 return std : :next(second) ;150 }151 i f (compare((∗first) .y , (∗second) .y)) {152 return std : :next(second) ;153 }154 i f (compare((∗second) .y , (∗first) .y)) {155 std : :iter_swap(first, second) ;156 return std : :next(second) ;157 }158 return std : :next(first) ;159 }160

161 template<typename I , typename C>162 I conquer(I first, I past, C compare) {163 std : :size_t n = std : :distance(first, past) ;164 i f (n ≤ 2) {165 return brute_force(first, past, compare) ;166 }167 I middle = first ;168 std : :advance(middle, n / 2) ;169 I rest1 = conquer(first, middle, compare) ;

Page 23: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

23

170 I rest2 = conquer(middle, past, compare) ;171 std : :size_t h2 = std : :distance(middle, rest2 ) ;172 I rest = rest1 ;173 std : :advance(rest, h2 ) ;174 swap_blocks(middle, rest2 , rest1 ) ;175 using P = typename std : :iterator_traits<I> : :value_type ;176 std : :inplace_merge(first, rest1 , rest,177 [&](P const& p , P const& q) → bool {178 return compare(p.x , q.x) ;179 }) ;180 std : :pair<I , I> pair = clean(first, rest,181 [&](P const& p , P const& q) → bool {182 return compare(p.y , q.y) ;183 }) ;184 I top = std : :get<0>(pair) ;185 I next = std : :get<1>(pair) ;186 rest = scan(first, top, next, rest) ;187 return rest ;188 }189

190 template<typename I>191 I solve(I first, I past) {192 using P = typename std : :iterator_traits<I> : :value_type ;193 using T = typename P : :coordinate ;194 std : :size_t n = std : :distance(first, past) ;195 i f (n < 2) {196 return past ;197 }198 I middle = partition_upper_lower(first, past) ;199 I rest1 = conquer(first, middle, std : :less<T>( )) ;200 i f (middle == past) {201 return rest1 ;202 }203 I west = first ;204 std : :iter_swap(std : :prev(rest1 ) , std : :prev(middle)) ;205 I east = std : :prev(middle) ;206 I rest2 = conquer(east, past, std : :greater<T>( )) ;207 i f (rest2 =6== east) {208 rest2 = scan_one_more(east, std : :prev(rest2 ) , west) ;209 }210 std : :size_t h2 = std : :distance(east, rest2 ) ;211 I rest = rest1 ;212 std : :advance(rest, h2 − 1) ;213 swap_blocks(east, rest2 , std : :prev(rest1 )) ;214 return rest ;215 }216

217 template<typename I>218 bool check(I first, I past) {219 using P = typename std : :iterator_traits<I> : :value_type ;220 using S = std : :list<P> ;221 using J = typename S : :iterator ;

Page 24: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

24

222 S data ;223 std : :size_t n = std : :distance(first, past) ;224 data.resize(n) ;225 std : :copy(first, past, data.begin( )) ;226 J rest = solve(data.begin( ) , data.end( )) ;227 bool ok = validation : :same_multiset(data.begin( ) , data.end( ) , first, past) and

↪→ validation : :convex_polygon(data.begin( ) , rest) and validation : :all_inside(rest,↪→ data.end( ) , data.begin( ) , rest) ;

228 return ok ;229 }230 }231

232 #endif

B.5 quickhull.h++

1 /∗2 Performance Engineering Laboratory © 2017−20183 ∗/4

5 #ifndef __QUICKHULL__6 #define __QUICKHULL__7

8 #define FLOATING_POINT_FILTER9

10 #include <algorithm> // std : :minmax element std : : partitioning . . .11 #include <cassert> // assert macro12 #include <cstdlib> // std : : s ize t13 #include <iterator> // std : : iterator traits std : : distance . . .14 #include <list> // std : : l i s t15 #include ”point .h++” // signed area left turn no turn16 #include <utility> // std : : pair std : : make pair . . .17 #include ”validation .h++” // same multiset convex polygon all inside18 #include <vector> // std : : vector19

20 namespace quickhull {21

22 // move ∗st <− ∗rd and ∗nd <− ∗th by swaps in parallel23

24 template<typename I>25 void parallel_iter_swap(I st , I nd , I rd , I th) {26 assert(st =6== nd and rd =6== th) ;27 std : :iter_swap(st , rd) ;28 i f (th == st) {29 std : :iter_swap(nd , rd) ;30 }31 else {32 std : :iter_swap(nd , th) ;33 }34 }35

Page 25: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

25

36 template<typename I>37 std : :pair<I , I> find_poles(I first, I past) {38 using P = typename std : :iterator_traits<I> : :value_type ;39 auto pair = std : :minmax_element(first, past,40 [ ](P const& a , P const& b) → bool {41 return (a.x < b.x) or (a.x == b.x and a.y < b.y) ;42 }) ;43 return pair ;44 }45

46 template<typename I>47 I find_furthest(I first, I past, I antipole) {48 assert(first =6== past) ;49 I pole = first ;50 I answer = pole ;51 using U = decltype(signed_area(∗pole, ∗pole, ∗pole)) ;52 U best = 0;53 i f ((∗antipole) .x == (∗pole) .x) { // vertical54 for (I i = std : :next(first) ; i =6== past ; ++i) {55 U Φ = signed_area(∗pole, ∗antipole, ∗i) ;56 i f ( Φ > best or ( Φ == best and (∗i) .y < (∗answer) .y)) {57 answer = i ;58 best = Φ ;59 }60 }61 }62 else {63 for (I i = std : :next(first) ; i =6== past ; ++i) {64 U Φ = signed_area(∗pole, ∗antipole, ∗i) ;65 i f ( Φ > best or ( Φ == best and (∗i) .x < (∗answer) .x)) {66 answer = i ;67 best = Φ ;68 }69 }70 }71 return answer ;72 }73

74 template<typename I>75 I partition_left_right(I first, I past, I antipole) {76 assert(first =6== past) ;77 using P = typename std : :iterator_traits<I> : :value_type ;78 I pole = first ;79 I middle = std : :partition(std : :next(pole) , past,80 [&](P const& q) → bool {81 return not left_turn(∗pole, q , ∗antipole) ;82 }) ;83 return middle ;84 }85

86 template<typename I>87 void swap_blocks(I source, I past, I target) {

Page 26: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

26

88 i f (source == target or source == past) {89 return;90 }91 using P = typename std : :iterator_traits<I> : :value_type ;92 I hole = target ;93 P p = ∗target ;94 I const last = std : :prev(past) ;95 while (true) {96 ∗hole = ∗source ;97 ++hole ;98 i f (source == last) {99 break;

100 }101 ∗source = ∗hole ;102 ++source ;103 }104 ∗source = p ;105 }106

107 template<typename I>108 void move_away(I here, I rest, I past) {109 i f (here == rest or rest == past) {110 return;111 }112 i f (std : :distance(here, rest) < std : :distance(rest, past)) {113 I target = past ;114 std : :advance(target, − std : :distance(here, rest)) ;115 swap_blocks(here, rest, target) ;116 }117 else {118 swap_blocks(rest, past, here) ;119 }120 }121

122 template<typename I>123 I chain(I pole, I past, I antipole) {124 std : :size_t n = std : :distance(pole, past) ;125 i f (n == 1) {126 return past ;127 }128 i f (n == 2) {129 i f (no_turn(∗std : :next(pole) , ∗pole, ∗antipole)) {130 return std : :next(pole) ;131 }132 else {133 return past ;134 }135 }136 I pivot = find_furthest(pole, past, antipole) ;137 i f (no_turn(∗pivot, ∗pole, ∗antipole)) {138 return std : :next(pole) ;139 }

Page 27: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

27

140 I last = std : :prev(past) ;141 std : :iter_swap(pivot, last) ; // pivot at the end142 I mid = partition_left_right(pole, last, last) ;143 I eliminated = chain(pole, mid, last) ;144 std : :iter_swap(mid, last) ;145 std : :iter_swap(eliminated, mid) ; // pivot at its f inal place146 pivot = eliminated ;147 std : :size_t m = std : :distance(mid, past) ;148 ++mid ;149 ++eliminated ;150 move_away(eliminated, mid, past) ;151 I border = pivot ;152 std : :advance(border, m) ;153 I interior = partition_left_right(pivot, border, antipole) ;154 eliminated = chain(pivot, interior, antipole) ;155 return eliminated ;156 }157

158 template<typename I>159 I solve(I first, I past) {160 std : :size_t n = std : :distance(first, past) ;161 i f (n < 2 or (n == 2 and ∗first =6== ∗std : :next(first))) {162 return past ;163 }164 std : :pair<I , I> pair = find_poles(first, past) ;165 I west = first ;166 I east = std : :prev(past) ;167 parallel_iter_swap(west, east, std : :get<0>(pair) , std : :get<1>(pair)) ;168 i f (∗west == ∗east) {169 return std : :next(first) ;170 }171 I middle = partition_left_right(west, east, east) ;172 std : :size_t m = std : :distance(middle, past) ;173 I eliminated = chain(first, middle, east) ;174 std : :iter_swap(middle, east) ;175 std : :iter_swap(eliminated, middle) ; // east at its f inal place176 east = eliminated ;177 ++middle ;178 ++eliminated ;179 move_away(eliminated, middle, past) ;180 I border = east ;181 std : :advance(border, m) ;182 eliminated = chain(east, border, west) ; // downunder183 return eliminated ;184 }185

186 template<typename I>187 bool check(I first, I past) {188 using P = typename std : :iterator_traits<I> : :value_type ;189 using S = std : :list<P> ;190 using J = typename S : :iterator ;191 S data ;

Page 28: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

28

192 std : :size_t n = std : :distance(first, past) ;193 data.resize(n) ;194 std : :copy(first, past, data.begin( )) ;195 J rest = solve(data.begin( ) , data.end( )) ;196 bool ok = validation : :same_multiset(data.begin( ) , data.end( ) , first, past) and

↪→ validation : :convex_polygon(data.begin( ) , rest) and validation : :all_inside(rest,↪→ data.end( ) , data.begin( ) , rest) ;

197 return ok ;198 }199 }200

201 #endif

B.6 poles_first.h++

1 /∗2 Performance Engineering Laboratory © 2017−20183

4 Find the extrema in four directions and eliminate al l points inside5 the convex hull of these points .6 ∗/7

8 #ifndef __POLES_FIRST__9 #define __POLES_FIRST__

10

11 #include <algorithm> // std : : sort std : : partition . . .12 #include <cassert> // assert macro13 #include <cstdlib> // std : : s ize t14 #include <iterator> // std : : iterator traits std : : distance15 #include ”plane sweep.h++” // plane sweep : : solve16 #include ”point .h++” // left turn17 #include <utility> // std : : iter swap std : : pair std : : get . . .18 #include ”validation .h++” // same multiset convex polygon all inside19 #include <vector> // std : : vector20

21 namespace poles_first {22

23 template<typename I>24 std : :vector<I> find_poles(I first, I past) {25 assert(first =6== past) ;26 using P = typename std : :iterator_traits<I> : :value_type ;27 std : :vector<I> position ;28 position.resize(4) ;29 std : :pair<I , I> pair = std : :minmax_element(first, past,30 [ ](P const& a , P const& b) → bool {31 return (a.x < b.x) or (a.x == b.x and a.y < b.y) ;32 }) ;33 enum {west = 0, east = 1, south = 2, north = 3};34 position [west ] = std : :get<0>(pair) ;35 position [east ] = std : :get<1>(pair) ;36 pair = std : :minmax_element(first, past,

Page 29: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

29

37 [ ](P const& a , P const& b) → bool {38 return (a.y < b.y) or (a.y == b.y and a.x < b.x) ;39 }) ;40 position [south ] = std : :get<0>(pair) ;41 position [north ] = std : :get<1>(pair) ;42 return position ;43 }44

45 template<typename S>46 void remove_duplicates(S& sequence) {47 assert(sequence.size( ) =6== 0) ;48 assert(std : :is_sorted(sequence.begin( ) , sequence.end( ))) ;49 std : :size_t i = 0;50 std : :size_t j = 1;51 auto v = sequence [ 0 ] ;52 while (j =6== sequence.size( )) {53 i f (not (sequence [j ] == v)) {54 std : :swap(sequence [i ] , v) ;55 ++i ;56 v = sequence [j ] ;57 }58 ++j ;59 }60 std : :swap(sequence [i ] , v) ;61 ++i ;62 std : :size_t leftovers = sequence.size( ) − i ;63 while (leftovers =6== 0) {64 sequence.pop_back( ) ;65 −−leftovers ;66 }67 }68

69 template<typename P , typename I>70 bool inside_quadrilateral(P const& p , I upper, I lower, I past) {71 assert(std : :distance(upper, past) > 2) ;72 assert(∗upper == ∗std : :prev(past)) ;73 assert(∗upper < ∗std : :next(upper)) ;74 assert(∗upper < ∗std : :prev(std : :prev(past))) ;75 I i = upper ;76 do {77 ++i ;78 } while (i =6== lower and ∗i < p) ;79 i f (left_turn(∗std : :prev(i) , ∗i , p)) {80 return false ;81 }82 I last = std : :prev(past) ;83 I j = lower ;84 do {85 ++j ;86 } while (j =6== last and ∗j > p) ;87 i f (left_turn(∗std : :prev(j) , ∗j , p)) {88 return false ;

Page 30: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

30

89 }90 return true ;91 }92

93 template<typename I>94 I remove_inner_part(I first, I past, I polygon, I rest) {95 assert(polygon =6== rest) ;96 I i = first ;97 i f (std : :distance(polygon, rest) == 1) {98 for (I j = first ; j =6== past ; ++j) {99 i f (not (∗j == ∗polygon)) {

100 std : :iter_swap(i , j) ;101 ++i ;102 }103 }104 return i ;105 }106 i f (std : :distance(polygon, rest) == 2) {107 for (I j = first ; j =6== past ; ++j) {108 i f (not (on_line_segment(∗polygon, ∗std : :next(polygon) , ∗j))) {109 std : :iter_swap(i , j) ;110 ++i ;111 }112 }113 return i ;114 }115 // rest − polygon > 2116 using P = typename std : :iterator_traits<I> : :value_type ;117 std : :vector<P> approximate_hull ;118 for (I k = polygon ; k =6== rest ; ++k) {119 approximate_hull.push_back(∗k) ;120 }121 approximate_hull.push_back(∗polygon) ;122 auto upper = approximate_hull.begin( ) ;123 auto lower = upper ;124 auto end = approximate_hull.end( ) ;125 for (auto k = std : :next(upper) ; k =6== std : :prev(end) ; ++k) {126 i f (∗lower < ∗k) {127 lower = k ;128 }129 }130 for (I j = first ; j =6== past ; ++j) {131 i f (not inside_quadrilateral(∗j , upper, lower, end)) {132 std : :iter_swap(i , j) ;133 ++i ;134 }135 }136 return i ;137 }138

139 template<typename I>140 I prune(I first, I past) {

Page 31: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

31

141 i f (std : :distance(first, past) < 2) {142 return past ;143 }144 std : :vector<I> poles = find_poles(first, past) ;145 std : :sort(poles.begin( ) , poles.end( )) ;146 remove_duplicates(poles) ;147 std : :size_t n = poles.size( ) ;148 I q = first ;149 for (std : :size_t i = 0; i =6== n ; ++i , ++q) {150 std : :iter_swap(q , poles [i ] ) ;151 }152 I rest = plane_sweep : :solve(first, q) ;153 I eliminated = remove_inner_part(rest, past, first, rest) ;154 return eliminated ;155 }156

157 template<typename I>158 I solve(I first, I past) {159 I rest = prune(first, past) ;160 #if defined(PRUNING)161

162 pruning_efficiency += std : :distance(first, rest) ;163

164 #endif165 return plane_sweep : :solve(first, rest) ;166 }167

168 template<typename I>169 bool check(I first, I past) {170 using P = typename std : :iterator_traits<I> : :value_type ;171 using S = std : :vector<P> ;172 using J = typename S : :iterator ;173 S data ;174 std : :size_t n = std : :distance(first, past) ;175 data.resize(n) ;176 std : :copy(first, past, data.begin( )) ;177 J rest = solve(data.begin( ) , data.end( )) ;178 bool ok = validation : :same_multiset(data.begin( ) , data.end( ) , first, past) and

↪→ validation : :convex_polygon(data.begin( ) , rest) and validation : :all_inside(rest,↪→ data.end( ) , data.begin( ) , rest) ;

179 return ok ;180 }181 }182

183 #endif

B.7 throw_away.h++

1 /∗2 Performance Engineering Laboratory © 2017−20193

Page 32: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

32

4 Find the extrema in eight directions and eliminate al l points5 inside the convex hull of these points .6 ∗/7

8 #ifndef __THROW_AWAY__9 #define __THROW_AWAY__

10

11 #define FLOATING_POINT_FILTER12

13 #include <algorithm> // std : : sort std : :min std : :minmax element14 #include <cassert> // assert macro15 #include <cmath> // std : : sqrt16 #include ”cphmpl/functions .h++” // cphmpl : : width17 #include ”cphstl/integers .h++” // cphstl : :Z18 #include <cstddef> // std : : s ize t19 #include <iterator> // std : : next std : : prev20 #include <limits> // std : : numeric limits21 #include ”plane sweep.h++”22 #include ”point .h++”23 #include <utility> // std : : pair std : : get24 #include ”validation .h++” // same multiset convex polygon all inside25 #include <vector> // std : : vector26

27 namespace throw_away {28

29 template<typename I>30 requires cphmpl : :is_iterator<I> and is_point<cphmpl : :value<I>>31 std : :vector<I> find_extrema(I first, I past) {32 assert(first =6== past) ;33 using P = typename std : :iterator_traits<I> : :value_type ;34 using T = typename P : :coordinate ;35 constexpr std : :size_t w = cphmpl : :width<T> ;36 using Z = cphstl : :Z<w + 2> ;37 std : :vector<I> max_position(8 , first) ;38 T xmin = (∗first) .x ;39 T xmax = (∗first) .x ;40 T ymin = (∗first) .y ;41 T ymax = (∗first) .y ;42 Z ne = Z(xmin) + Z(ymin) ;43 Z se = Z(xmin) − Z(ymin) ;44 Z sw = −(Z(xmin) + Z(ymin)) ;45 Z nw = Z(ymin) − Z(xmin) ;46 for (I i = first ; i =6== past ; ++i) {47 i f ((∗i) .x < xmin) {48 xmin = (∗i) .x ;49 max_position [0 ] = i ;50 }51 i f ((∗i) .x > xmax) {52 xmax = (∗i) .x ;53 max_position [1 ] = i ;54 }55 i f ((∗i) .y < ymin) {

Page 33: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

33

56 ymin = (∗i) .y ;57 max_position [2 ] = i ;58 }59 i f ((∗i) .y > ymax) {60 ymax = (∗i) .y ;61 max_position [3 ] = i ;62 }63 Z dot = Z((∗i) .x) + Z((∗i) .y) ;64 #if defined(MEASURE_COMPS)65

66 ++comps ;67

68 #endif69 i f (dot > ne) {70 ne = dot ;71 max_position [4 ] = i ;72 }73 dot = Z((∗i) .x) − Z((∗i) .y) ;74 #if defined(MEASURE_COMPS)75

76 ++comps ;77

78 #endif79 i f (dot > se) {80 se = dot ;81 max_position [5 ] = i ;82 }83 dot = −(Z((∗i) .x) + Z((∗i) .y)) ;84 #if defined(MEASURE_COMPS)85

86 ++comps ;87

88 #endif89 i f (dot > sw) {90 sw = dot ;91 max_position [6 ] = i ;92 }93 dot = Z((∗i) .y) − Z((∗i) .x) ;94 #if defined(MEASURE_COMPS)95

96 ++comps ;97

98 #endif99 i f (dot > nw) {

100 nw = dot ;101 max_position [7 ] = i ;102 }103 }104 return max_position ;105 }106

107 template<typename S>

Page 34: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

34

108 void remove_duplicates(S& sequence) {109 assert(sequence.size( ) =6== 0) ;110 assert(std : :is_sorted(sequence.begin( ) , sequence.end( ))) ;111 std : :size_t i = 0;112 std : :size_t j = 1;113 auto v = sequence [ 0 ] ;114 while (j =6== sequence.size( )) {115 i f (not (sequence [j ] == v)) {116 std : :swap(sequence [i ] , v) ;117 ++i ;118 v = sequence [j ] ;119 }120 ++j ;121 }122 std : :swap(sequence [i ] , v) ;123 ++i ;124 std : :size_t leftovers = sequence.size( ) − i ;125 while (leftovers =6== 0) {126 sequence.pop_back( ) ;127 −−leftovers ;128 }129 }130

131 template<typename P , typename I>132 bool between_polygonal_chains(P const& p , I upper, I uend, I lower, I lend) {133 I i = upper ;134 I last = std : :prev(uend) ;135 do {136 ++i ;137 } while (i =6== last and (∗i) .x < p.x) ;138 i f (left_turn(∗std : :prev(i) , ∗i , p)) {139 return false ;140 }141 last = std : :prev(lend) ;142 I j = lower ;143 do {144 ++j ;145 } while (j =6== last and (∗j) .x > p.x) ;146 i f (left_turn(∗std : :prev(j) , ∗j , p)) {147 return false ;148 }149 return true ;150 }151

152 template<typename I>153 I eliminate_inner_points(I first, I past, I polygon, I rest) {154 assert(polygon =6== rest) ;155 using P = cphmpl : :value<I> ;156 i f (std : :distance(polygon, rest) == 1) {157 I mid = std : :partition(first, past,158 [&](P const& r) → bool {159 return not (r == ∗polygon) ;

Page 35: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

35

160 }) ;161 return mid ;162 }163 i f (std : :distance(polygon, rest) == 2) {164 I mid = std : :partition(first, past,165 [&](P const& r) → bool {166 return not on_line_segment(∗polygon, ∗std : :next(polygon) , r) ;167 }) ;168 return mid ;169 }170 assert(std : :distance(polygon, rest) > 2) ;171 std : :vector<P> approximate_hull ;172 for (I k = polygon ; k =6== rest ; ++k) {173 approximate_hull.push_back(∗k) ;174 }175 approximate_hull.push_back(∗polygon) ;176 auto upper = approximate_hull.begin( ) ;177 i f ((∗upper) .x == (∗std : :next(upper)) .x) {178 ++upper ;179 }180 auto lower = upper ;181 auto last = std : :prev(approximate_hull.end( )) ;182 for (auto k = std : :next(upper) ; k =6== last ; ++k) {183 i f (∗lower < ∗k) {184 lower = k ;185 }186 }187 auto uend = std : :next(lower) ;188 i f ((∗lower) .x == (∗std : :next(lower)) .x) {189 ++lower ;190 }191 auto lend = approximate_hull.end( ) ;192 I mid = std : :partition(first, past,193 [&](P const& r) → bool {194 return not between_polygonal_chains(r , upper, uend, lower, lend) ;195 }) ;196 return mid ;197 }198

199 template<typename I>200 I prune(I first, I past) {201 i f (std : :distance(first, past) < 2) {202 return past ;203 }204 // Step 1205 std : :vector<I> extrema = find_extrema(first, past) ;206 std : :sort(extrema.begin( ) , extrema.end( )) ;207 remove_duplicates(extrema) ;208 I q = first ;209 for (std : :size_t i = 0; i =6== extrema.size( ) ; ++i , ++q) {210 std : :iter_swap(q , extrema [i ] ) ;211 }

Page 36: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

36

212 // Step 2213 I rest = plane_sweep : :solve(first, q) ;214 // Step 3215 I interior = eliminate_inner_points(rest, past, first, rest) ;216 return interior ;217 }218

219 template<typename I>220 I solve(I first, I past) {221 I rest = prune(first, past) ;222 #if defined(PRUNING)223

224 pruning_efficiency += std : :distance(first, rest) ;225

226 #endif227 return plane_sweep : :solve(first, rest) ;228 }229

230 template<typename R>231 requires cphmpl : :specifies_range<R> and is_point<cphmpl : :value<R>>232 cphmpl : :iterator<R> solve(R& sequence) {233 return solve(std : :begin(sequence) , std : :end(sequence)) ;234 }235

236 template<typename I>237 bool check(I first, I past) {238 using P = cphmpl : :value<I> ;239 using S = std : :vector<P> ;240 using J = typename S : :iterator ;241 S data ;242 std : :size_t n = std : :distance(first, past) ;243 data.resize(n) ;244 std : :copy(first, past, data.begin( )) ;245 J rest = solve(data.begin( ) , data.end( )) ;246 bool ok = validation : :same_multiset(data.begin( ) , data.end( ) , first, past) and

↪→ validation : :convex_polygon(data.begin( ) , rest) and validation : :all_inside(rest,↪→ data.end( ) , data.begin( ) , rest) ;

247 return ok ;248 }249

250 template<typename R>251 requires cphmpl : :specifies_range<R> and is_point<cphmpl : :value<R>>252 bool check(R const& sequence) {253 return check(std : :cbegin(sequence) , std : :cend(sequence)) ;254 }255 }256

257 #endif

B.8 introhull.h++

Page 37: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

37

1 /∗2 Performance Engineering Laboratory © 2017−20193

4 Execute the some levels of quickhull and process the remaining5 regions using the plane−sweep algorithm6 ∗/7

8 #ifndef __INTROHULL__9 #define __INTROHULL__

10

11 #include <algorithm> // std : : sort std : : partition . . .12 #include <cassert> // assert macro13 #include <cstdlib> // std : : s ize t14 #include <functional> // std : : less15 #include <iterator> // std : : iterator traits std : : distance std : : next . . .16 #include ”plane sweep.h++” // plane sweep : : solve17 #include ”point .h++” // left turn18 #include <utility> // std : : pair std : : get . . .19 #include ”validation .h++” // same multiset convex polygon all inside20 #include <vector> // std : : vector21

22 namespace introhull {23

24 template<typename N>25 inline N lg(N n) {26 N k ;27 for (k = 0; n =6== 0; n>>= 1) {28 ++k ;29 }30 return k − 1;31 }32

33 inline int lg(int n) {34 using N = std : :size_t ;35 constexpr N char_bit = std : :numeric_limits<unsigned char> : :digits ;36 return sizeof(int) ∗ char_bit − 1 − __builtin_clz(n) ;37 }38

39 inline long lg(long n) {40 using N = std : :size_t ;41 constexpr N char_bit = std : :numeric_limits<unsigned char> : :digits ;42 return sizeof(long) ∗ char_bit − 1 − __builtin_clzl(n) ;43 }44

45 inline long long lg(long long n) {46 using N = std : :size_t ;47 constexpr N char_bit = std : :numeric_limits<unsigned char> : :digits ;48 return sizeof(long long) ∗ char_bit − 1 − __builtin_clzll(n) ;49 }50

51 // move ∗st <− ∗rd and ∗nd <− ∗th by swaps in parallel52

Page 38: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

38

53 template<typename I>54 void parallel_iter_swap(I st , I nd , I rd , I th) {55 assert(st =6== nd and rd =6== th) ;56 std : :iter_swap(st , rd) ;57 i f (th == st) {58 std : :iter_swap(nd , rd) ;59 }60 else {61 std : :iter_swap(nd , th) ;62 }63 }64

65 template<typename I>66 std : :pair<I , I> find_poles(I first, I past) {67 using P = typename std : :iterator_traits<I> : :value_type ;68 auto pair = std : :minmax_element(first, past,69 [ ](P const& a , P const& b) → bool {70 return (a.x < b.x) or (a.x == b.x and a.y < b.y) ;71 }) ;72 return pair ;73 }74

75 template<typename I>76 I find_furthest(I first, I past, I east) {77 assert(first =6== past) ;78 I west = first ;79 I answer = west ;80 using U = decltype(signed_area(∗west, ∗west, ∗west)) ;81 U best = 0;82 i f ((∗east) .x == (∗west) .x) { // vertical83 for (I i = first + 1; i =6== past ; ++i) {84 U Φ = signed_area(∗west, ∗east, ∗i) ;85 i f ( Φ > best or ( Φ == best and (∗i) .y < (∗answer) .y)) {86 answer = i ;87 best = Φ ;88 }89 }90 }91 else {92 for (I i = first + 1; i =6== past ; ++i) {93 U Φ = signed_area(∗west, ∗east, ∗i) ;94 i f ( Φ > best or ( Φ == best and (∗i) .x < (∗answer) .x)) {95 answer = i ;96 best = Φ ;97 }98 }99 }

100 return answer ;101 }102

103 template<typename I>104 I partition_left_right(I first, I past, I east) {

Page 39: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

39

105 assert(first =6== past) ;106 using P = typename std : :iterator_traits<I> : :value_type ;107 I west = first ;108 I middle = std : :partition(std : :next(west) , past,109 [&](P const& q) → bool {110 return not left_turn(∗west, q , ∗east) ;111 }) ;112 return middle ;113 }114

115 template <typename I>116 void swap_blocks(I source, I past_source, I target) {117 using P = typename std : :iterator_traits<I> : :value_type ;118 I hole = target ;119 P p = ∗target ;120 I const last = std : :prev(past_source) ;121 while (true) {122 ∗hole = ∗source ;123 ++hole ;124 i f (source == last) {125 break;126 }127 ∗source = ∗hole ;128 ++source ;129 }130 ∗source = p ;131 }132

133 template <typename I>134 void move_away(I here, I rest, I past) {135 i f (here == rest or rest == past) {136 return;137 }138 i f (std : :distance(here, rest) < std : :distance(rest, past)) {139 I target = past ;140 std : :advance(target, − std : :distance(here, rest)) ;141 swap_blocks(here, rest, target) ;142 }143 else {144 swap_blocks(rest, past, here) ;145 }146 }147

148 template<typename I , typename C>149 I chain(I pole, I past, I antipole, std : :size_t depth, C compare) {150 std : :size_t n = std : :distance(pole, past) ;151 i f (n == 1) {152 return past ;153 }154 i f (n == 2) {155 i f (no_turn(∗std : :next(pole) , ∗pole, ∗antipole)) {156 return std : :next(pole) ;

Page 40: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

40

157 }158 else {159 return past ;160 }161 }162 i f (depth == 0) {163 #if defined(PRUNING)164

165 pruning_efficiency += std : :distance(pole, rest) ;166

167 #endif168 return plane_sweep : :chain(pole, past, antipole, compare) ;169 }170 I pivot = find_furthest(pole, past, antipole) ;171 i f (no_turn(∗pivot, ∗pole, ∗antipole)) {172 return std : :next(pole) ;173 }174 I last = std : :prev(past) ;175 std : :iter_swap(pivot, last) ; // pivot at the end176 I mid = partition_left_right(pole, last, last) ;177 I eliminated = chain(pole, mid, last, depth − 1, compare) ;178 std : :iter_swap(mid, last) ;179 std : :iter_swap(eliminated, mid) ; // pivot at its f inal place180 pivot = eliminated ;181 std : :size_t m = std : :distance(mid, past) ;182 ++mid ;183 ++eliminated ;184 move_away(eliminated, mid, past) ;185 I border = pivot ;186 std : :advance(border, m) ;187 I interior = partition_left_right(pivot, border, antipole) ;188 eliminated = chain(pivot, interior, antipole, depth − 1, compare) ;189 return eliminated ;190 }191

192 template<typename I>193 I solve(I first, I past) {194 using P = typename std : :iterator_traits<I> : :value_type ;195 using T = typename P : :coordinate ;196 std : :size_t n = std : :distance(first, past) ;197 i f (n < 2 or (n == 2 and ∗first =6== ∗std : :next(first))) {198 return past ;199 }200 std : :size_t max_depth = lg(n) ;201 std : :pair<I , I> pair = find_poles(first, past) ;202 I west = first ;203 I east = std : :prev(past) ;204 parallel_iter_swap(west, east, std : :get<0>(pair) , std : :get<1>(pair)) ;205 i f (∗west == ∗east) {206 return std : :next(first) ;207 }208 I middle = partition_left_right(west, east, east) ;

Page 41: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

41

209 std : :size_t m = std : :distance(middle, past) ;210 I eliminated = chain(first, middle, east, max_depth, std : :less<T>( )) ;211 std : :iter_swap(middle, east) ;212 std : :iter_swap(eliminated, middle) ; // east at its f inal place213 east = eliminated ;214 ++middle ;215 ++eliminated ;216 move_away(eliminated, middle, past) ;217 I border = east ;218 std : :advance(border, m) ;219 I rest = chain(east, border, west, max_depth, std : :greater<T>( )) ;220 return rest ;221 }222

223 template<typename I>224 bool check(I first, I past) {225 using P = typename std : :iterator_traits<I> : :value_type ;226 using S = std : :vector<P> ;227 using J = typename S : :iterator ;228 S data ;229 std : :size_t n = std : :distance(first, past) ;230 data.resize(n) ;231 std : :copy(first, past, data.begin( )) ;232 J rest = solve(data.begin( ) , data.end( )) ;233 bool ok = validation : :same_multiset(data.begin( ) , data.end( ) , first, past) and

↪→ validation : :convex_polygon(data.begin( ) , rest) and validation : :all_inside(rest,↪→ data.end( ) , data.begin( ) , rest) ;

234 return ok ;235 }236 }237

238 #endif

B.9 bucketing.h++

1 /∗2 Performance Engineering Laboratory © 2017−20193 ∗/4

5 #ifndef __BUCKETING__6 #define __BUCKETING__7

8 #define FLOATING_POINT_FILTER9

10 #include <cmath> // std : : sqrt std : : ce i l11 #include <cstdlib> // std : : s ize t12 #include <iterator> // std : : iterator traits13 #include <limits> // std : : numeric limits14 #include ”plane sweep.h++” // plane sweep : : solve15 #include ”point .h++”16 #include <utility> // std : : pair std : : forward

Page 42: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

42

17 #include <vector> // std : : vector18

19 namespace bucketing {20

21 template<typename V>22 class identity {23 public :24

25 constexpr V&& operator( )(V&& v) const {26 return std : :forward<V>(v) ;27 }28

29 constexpr V const& operator( )(V const& v) const {30 return v ;31 }32 };33

34 // precomputing the slab−association formula35

36 template<typename D , typename V , typename K = identity<V>>37 class formula {38 public :39

40 formula(D m , V const& min, V const& max, K key = K( ))41 : a(double(m − 1) / (double(key(max)) − double(key(min)))) ,42 b(double(m − 1) ∗ double(key(min)) / (double(key(max)) − double(key(min)))) ,43 key(key) {44 }45

46 D operator( )(V const& x) {47 return D(a ∗ double(key(x)) − b) ;48 }49

50 private :51

52 double a ;53 double b ;54 K key ;55 };56

57 // move ∗st <− ∗rd and ∗nd <− ∗th by swaps in parallel58

59 template<typename I>60 void parallel_iter_swap(I st , I nd , I rd , I th) {61 assert(st =6== nd and rd =6== th) ;62 std : :iter_swap(st , rd) ;63 i f (th == st) {64 std : :iter_swap(nd , rd) ;65 }66 else {67 std : :iter_swap(nd , th) ;68 }

Page 43: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

43

69 }70

71 // al l points on the same vertical line72

73 template<typename I>74 I vertical_case(I first, I past) {75 assert(std : :distance(first, past) ≥ 2) ;76 using P = typename std : :iterator_traits<I> : :value_type ;77 std : :pair<I , I> pair = std : :minmax_element(first, past,78 [ ](P const& p , P const& q) → bool {79 return (p.y < q.y) ;80 }) ;81 I south = std : :get<0>(pair) ;82 I north = std : :get<1>(pair) ;83 i f ((∗south) .y == (∗north) .y) {84 std : :iter_swap(first, south) ;85 return std : :next(first) ;86 }87 parallel_iter_swap(first, std : :next(first) , south, north) ;88 return std : :next(std : :next(first)) ;89 }90

91 template<typename I>92 I prune(I first, I past) {93 using P = typename std : :iterator_traits<I> : :value_type ;94 using T = typename P : :coordinate ;95 using D = typename std : :iterator_traits<I> : :difference_type ;96 D n = std : :distance(first, past) ;97 i f (n < 2) {98 return past ;99 }

100

101 // find the extreme values in the ±x directions102

103 std : :pair<I , I> pair = std : :minmax_element(first, past,104 [ ](P const& p , P const& q) → bool {105 return p.x < q.x ;106 }) ;107 I west = std : :get<0>(pair) ;108 I east = std : :get<1>(pair) ;109 i f ((∗west) .x == (∗east) .x) {110 return vertical_case(first, past) ;111 }112 D m = std : :ceil(std : :sqrt(n)) ; // divided by 2 was an ε faster113 formula slab(m , (∗west) .x , (∗east) .x) ;114

115 T∗ slab_min = new T [m ] ;116 T∗ slab_max = new T [m ] ;117 for (D j = 0; j =6== m ; ++j) {118 slab_max [j ] = std : :numeric_limits<T> : :min( ) ;119 slab_min [j ] = std : :numeric_limits<T> : :max( ) ;120 }

Page 44: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

44

121

122 // calculate the slab extrema123

124 for (I j = first ; j =6== past ; ++j) {125 D i = slab((∗j) .x) ;126 i f ((∗j) .y < slab_min [i ] ) {127 slab_min [i ] = (∗j) .y ;128 }129 i f ((∗j) .y > slab_max [i ] ) {130 slab_max [i ] = (∗j) .y ;131 }132 }133

134 // find the extreme values in the ±y directions135

136 D bottom = 0;137 D top = 0;138 T ymin = std : :numeric_limits<T> : :max( ) ;139 T ymax = std : :numeric_limits<T> : :min( ) ;140 for (D i = 0; i =6== m ; ++i) {141 i f (slab_max [i ] > ymax) {142 ymax = slab_max [i ] ;143 top = i ;144 }145 i f (slab_min [i ] < ymin) {146 ymin = slab_min [i ] ;147 bottom = i ;148 }149 }150

151 // determine the boundaries for the extreme values152

153 T roof = (∗east) .y ; // Q1 go backwards upstairs154 T previous = roof ;155 for (D j = m − 1; j ≥ top ; −−j) {156 previous = roof ;157 roof = std : :max(roof, slab_max [j ] ) ;158 slab_max [j ] = previous ;159 }160

161 T floor = (∗east) .y ; // Q2 go backwards downstairs162 previous = floor ;163 for (D j = m − 1; j ≥ bottom ; −−j) {164 previous = floor ;165 floor = std : :min(floor, slab_min [j ] ) ;166 slab_min [j ] = previous ;167 }168

169 floor = (∗west) .y ; // Q3 go downstairs170 previous = floor ;171 for (D j = 0; j < bottom ; ++j) {172 previous = floor ;

Page 45: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

45

173 floor = std : :min(floor, slab_min [j ] ) ;174 slab_min [j ] = previous ;175 }176 slab_min [bottom ] = std : :max(previous, slab_min [bottom ] ) ;177

178 roof = (∗west) .y ; // Q4 go upstairs179 previous = roof ;180 for (D j = 0; j < top ; ++j) {181 previous = roof ;182 roof = std : :max(roof, slab_max [j ] ) ;183 slab_max [j ] = previous ;184 }185 slab_max [top ] = std : :min(previous, slab_max [top ] ) ;186

187 // partition the input188

189 I o = first ;190 for (I j = first ; j =6== past ; ++j) {191 D column = slab((∗j) .x) ;192 i f ((∗j) .y ≥ slab_max [column ] or (∗j) .y ≤ slab_min [column ] ) {193 std : :iter_swap(j , o) ;194 ++o ;195 }196 }197 delete[ ] slab_min ;198 delete[ ] slab_max ;199 return o ;200 }201

202 template<typename I>203 I solve(I first, I past) {204 I rest = prune(first, past) ;205 #if defined(PRUNING)206

207 pruning_efficiency += std : :distance(first, rest) ;208

209 #endif210 I interior = plane_sweep : :solve(first, rest) ;211 return interior ;212 }213

214 template<typename I>215 bool check(I first, I past) {216 using P = typename std : :iterator_traits<I> : :value_type ;217 using S = std : :vector<P> ;218 using J = typename S : :iterator ;219 S data ;220 std : :size_t n = std : :distance(first, past) ;221 data.resize(n) ;222 std : :copy(first, past, data.begin( )) ;223 J rest = solve(data.begin( ) , data.end( )) ;224 bool ok = validation : :same_multiset(data.begin( ) , data.end( ) , first, past) and

Page 46: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

46

↪→ validation : :convex_polygon(data.begin( ) , rest) and validation : :all_inside(rest,↪→ data.end( ) , data.begin( ) , rest) ;

225 return ok ;226 }227 }228

229 #endif

Page 47: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

47

C. Micro-benchmarks

C.1 multiple_precision.h++

1 /∗2 This dummy performs Graham' s scan3 ∗/4

5 #define MULTIPLE_PRECISION6

7 #include <functional>8 #include <iterator>9 #include ”plane sweep.h++”

10 #include ”point .h++”11 #include <utility>12

13 namespace multiple_precision {14

15 template<typename I>16 I solve(I first, I past) {17 using P = typename std : :iterator_traits<I> : :value_type ;18 using T = typename P : :coordinate ;19 std : :pair<I , I> pair = plane_sweep : :clean(first, past, std : :less<T>( )) ;20 I top = std : :get<0>(pair) ;21 I next = std : :get<1>(pair) ;22 I interior = plane_sweep : :scan(first, top, next, past) ;23 return interior ;24 }25 }

C.2 double_precision.h++

1 /∗2 This dummy performs Graham' s scan3 ∗/4

5 #define DOUBLE_PRECISION6

7 #include <functional>8 #include <iterator>9 #include ”plane sweep.h++”

10 #include <utility>11

12 namespace double_precision {13

14 template<typename I>15 I solve(I first, I past) {16 using P = typename std : :iterator_traits<I> : :value_type ;17 using T = typename P : :coordinate ;18 std : :pair<I , I> pair = plane_sweep : :clean(first, past, std : :less<T>( )) ;19 I top = std : :get<0>(pair) ;

Page 48: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

48

20 I next = std : :get<1>(pair) ;21 I interior = plane_sweep : :scan(first, top, next, past) ;22 return interior ;23 }24 }

C.3 floating_point_filter.h++

1 /∗2 This dummy performs Graham' s scan3 ∗/4

5 #define FLOATING_POINT_FILTER6

7 #include <functional>8 #include <iterator>9 #include ”plane sweep.h++”

10 #include <utility>11

12 namespace floating_point_filter {13

14 template<typename I>15 I solve(I first, I past) {16 using P = typename std : :iterator_traits<I> : :value_type ;17 using T = typename P : :coordinate ;18 std : :pair<I , I> pair = plane_sweep : :clean(first, past, std : :less<T>( )) ;19 I top = std : :get<0>(pair) ;20 I next = std : :get<1>(pair) ;21 I interior = plane_sweep : :scan(first, top, next, past) ;22 return interior ;23 }24 }

C.4 fhistogram.h++

1 /∗2 This dummy calculates a histogram of the number of points in3 different buckets4 ∗/5

6 #include <algorithm> // std : :minmax element7 #include ”cphmpl/functions .h++” // cphmpl : : is power of two8 #include <cstddef> // std : : ptrdiff t9 #include <iterator> // std : : iterator traits

10 #include <utility> // std : : pair std : : forward11

12 using size_type = std : :size_t ;13 constexpr size_type m = TABLESIZE−TAG ;14 static assert(cphmpl : :is_power_of_two<m>) ;15

Page 49: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

49

16 class identity {17 public :18

19 template<typename V>20 constexpr V&& operator( )(V&& v) const {21 return std : :forward<V>(v) ;22 }23 };24

25 // partial evaluation of the bucket−association formula26

27 template<typename D , typename V , typename K = identity>28 class formula {29 public :30

31 formula(D m , V const& min, V const& max, K key = K( ))32 : a(double(m − 1) / (double(key(max)) − double(key(min)))) ,33 b(double(m − 1) ∗ double(key(min)) / (double(key(max)) − double(key(min)))) ,34 key(key) {35 }36

37 D operator( )(V const& x) {38 return D(a ∗ double(key(x)) − b) ;39 }40

41 private :42

43 double a ;44 double b ;45 K key ;46 };47

48 namespace fhistogram {49

50 template<typename I>51 I solve(I first, I past) {52 using P = typename std : :iterator_traits<I> : :value_type ;53 using T = typename P : :coordinate ;54 using index = std : :size_t ;55

56 std : :pair<I , I> pair = std : :minmax_element(first, past,57 [ ](P const& a , P const& b) → bool {58 return a.x < b.x ;59 }) ;60 I leftmost = std : :get<0>(pair) ;61 I rightmost = std : :get<1>(pair) ;62 i f ((∗leftmost) .x == (∗rightmost) .x) {63 assert(false) ;64 return leftmost ;65 }66

67 formula bucket(m , ∗leftmost, ∗rightmost,

Page 50: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

50

68 [ ](P const& p) → T {69 return p.x ;70 }) ;71

72 index∗ counter = new index [m ] ;73 for (size_type j = 0; j =6== m ; ++j) {74 counter [j ] = 0;75 }76

77 for (I p = first ; p =6== past ; ++p) {78 index i = bucket(∗p) ;79 assert(i ≥ 0 and i < m) ;80 counter [i ] = counter [i ] + 1;81 }82

83 delete[ ] counter ;84 return first ;85 }86 }

C.5 ihistogram.h++

1 /∗2 This dummy calculates a histogram of the number of points in3 different buckets4 ∗/5

6 #include <algorithm> // std : :minmax element7 #include <cassert> // assert macro8 #include ”cphmpl/functions .h++” // cphmpl : : width cphmpl : : is power of two9 #include ”cphstl/integers .h++” // cphstl integers

10 #include <cstddef> // std : : ptrdiff t11 #include <iterator> // std : : iterator traits12 #include <utility> // std : : pair std : : forward13

14 using size_type = std : :size_t ;15 constexpr size_type m = TABLESIZE−TAG ;16 static assert(cphmpl : :is_power_of_two<m>) ;17

18 // partial evaluation of the bucket−association formula19

20 template<typename V , typename S = std : :size_t>21 requires cphmpl : :is_integer<V>22 class formula {23 private :24

25 static constexpr std : :size_t w = cphmpl : :width<V> ;26 using Z = cphstl : :Z<2 ∗ w + 3> ;27

28 public :29

Page 51: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

51

30 formula(S m , V const& min, V const& max)31 : subtrahend(Z(min)) ,32 multiplier(cphstl : :cast<Z>(m − 1)) ,33 denominator(Z(max) − Z(min)) {34 assert(denominator =6== V( )) ;35 }36

37 S operator( )(V const& value) {38 Z index = (Z(value) − subtrahend) ∗ multiplier / denominator ;39 return cphstl : :cast<S>(index) ;40 }41

42 private :43

44 Z subtrahend ;45 Z multiplier ;46 Z denominator ;47 };48

49 namespace ihistogram {50

51 template<typename I>52 I solve(I first, I past) {53 using P = typename std : :iterator_traits<I> : :value_type ;54 using index = std : :size_t ;55

56 std : :pair<I , I> pair = std : :minmax_element(first, past,57 [ ](P const& a , P const& b) → bool {58 return a.x < b.x ;59 }) ;60 I leftmost = std : :get<0>(pair) ;61 I rightmost = std : :get<1>(pair) ;62 i f ((∗leftmost) .x == (∗rightmost) .x) {63 assert(false) ;64 return leftmost ;65 }66

67 formula bucket(m , (∗leftmost) .x , (∗rightmost) .x) ;68

69 index∗ counter = new index [m ] ;70 for (size_type j = 0; j =6== m ; ++j) {71 counter [j ] = 0;72 }73

74 for (I p = first ; p =6== past ; ++p) {75 index i = bucket((∗p) .x) ;76 assert(i ≥ 0 and i < m) ;77 counter [i ] = counter [i ] + 1;78 }79

80 delete[ ] counter ;81 return first ;

Page 52: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

52

82 }83 }

C.6 minmax_element.h++

1 /∗2 This dummy finds the two extreme points on the le f t and the right3 ∗/4

5 #include <algorithm>6 #include <utility>7

8 namespace minmax_element {9

10 template<typename I>11 I solve(I first, I past) {12 using P = typename std : :iterator_traits<I> : :value_type ;13 std : :pair<I , I> pair = std : :minmax_element(first, past,14 [ ](P const& a , P const& b) → bool {15 return (a.x < b.x) or (a.x == b.x and a.y < b.y) ;16 }) ;17 return std : :get<0>(pair) ;18 }19 }

C.7 partition.h++

1 /∗2 This dummy partitions the sequence into two by the line which3 passes through two points4 ∗/5

6 #include <iterator>7

8 #define FLOATING_POINT_FILTER9 #include ”point .h++”

10

11 namespace partition {12

13 template<typename I>14 I solve(I first, I past) {15 using P = typename std : :iterator_traits<I> : :value_type ;16 I west = first ;17 I east = past − 1;18 I middle = std : :partition(west + 1, past,19 [&](P const& q) → bool {20 return not left_turn(∗west, q , ∗east) ;21 }) ;22 return middle ;23 }

Page 53: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

53

24 }

C.8 copy.h++

1 /∗2 This dummy copies the points from a vector to an array3 ∗/4

5 #include <algorithm>6 #include <iterator>7 #include <vector>8

9 namespace copy {10

11 template<typename I>12 I solve(I first, I past) {13 using point = typename std : :iterator_traits<I> : :value_type ;14 auto n = std : :distance(first, past) ;15 point∗ copy = new point [n ] ;16 std : :copy(first, past, &copy [0 ] ) ;17 delete[ ] copy ;18 return past ;19 }20 }

C.9 sort.h++

1 /∗2 This dummy sorts the points according to their x−coordinates3 ∗/4

5 #include <algorithm> // std : : sort6 #include <iterator> // std : : iterator traits7

8 namespace sort {9

10 template<typename I>11 I solve(I first, I past) {12 using P = typename std : :iterator_traits<I> : :value_type ;13 std : :sort(first, past,14 [ ](P const& p , P const& q) {15 return p.x < q.x ;16 }) ;17 return past ;18 }19 }

C.10 lexicographic_sort.h++

Page 54: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

54

1 /∗2 This dummy sorts the points in ascending lexicographic order3 ∗/4

5 #include <algorithm> // std : : sort6 #include <iterator> // std : : iterator traits7

8 namespace lexicographic_sort {9

10 template<typename I>11 I solve(I first, I past) {12 using P = typename std : :iterator_traits<I> : :value_type ;13 std : :sort(first, past,14 [ ](P const& a , P const& b) → bool {15 return (a.x < b.x) or (a.x == b.x and a.y < b.y) ;16 }) ;17 return past ;18 }19 }

C.11 angular_sort.h++

1 /∗2 Sort a l l the points around o lexicographically by polar angle and3 distance from o4 ∗/5

6 #include <algorithm> // std : : sort7 #include <cstddef> // std : : s ize t8 #include <iterator> // std : : iterator traits9

10 #define MULTIPLE_PRECISION11

12 #include ”point .h++”13

14 namespace angular_sort {15

16 template<typename I>17 I solve(I first, I past) {18 using P = typename std : :iterator_traits<I> : :value_type ;19 I west = std : :min_element(first, past,20 [ ](P const& p , P const& q) → bool {21 return (p.x < q.x) or (p.x == q.x and p.y < q.y) ;22 }) ;23 P o = ∗west ;24 std : :sort(first, past,25 [&](P const& p , P const& q) → bool {26 int turn = orientation(o , p , q) ;27 i f (turn == 0) {28 return (L∞distance(o , p) < L∞distance(o , q)) ;29 }

Page 55: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

55

30 return (turn == +1) ;31 }) ;32 return past ;33 }34 }

C.12 bsort.h++

1 /∗2 This dummy sorts the points according to their x−coordinates3 ∗/4

5 #include ”bucketsort .h++”6 #include <iterator> // std : : iterator traits7

8 namespace bsort {9

10 template<typename I>11 I solve(I first, I past) {12 using P = typename std : :iterator_traits<I> : :value_type ;13 using T = typename P : :coordinate ;14 bucketsort : :sort(first, past,15 [ ](P const& p , P const& q) → bool {16 return p.x < q.x ;17 } ,18 [ ](P const& p) → T {19 return p.x ;20 }) ;21 return past ;22 }23 }

C.13 tsort.h++

1 /∗2 This dummy sorts the points according to their x−coordinates3 ∗/4

5 #include <iterator> // std : : iterator traits6 #include ”two phase bucketsort.h++”7

8 namespace tsort {9

10 template<typename I>11 I solve(I first, I past) {12 using P = typename std : :iterator_traits<I> : :value_type ;13 using T = typename P : :coordinate ;14 two_phase_bucketsort : :sort(first, past,15 [ ](P const& p , P const& q) → bool {16 return p.x < q.x ;

Page 56: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

56

17 } ,18 [ ](P const& p) → T {19 return p.x ;20 }) ;21 return past ;22 }23 }

C.14 shuffle.h++

1 /∗2 This dummy shuffles the points randomly3 ∗/4

5 #include <algorithm> // std : : shuffle6 #include <random> // random−number generators7

8 using N = unsigned long long ;9 using linear_congruential_engine = std : :linear_congruential_engine<N ,

↪→ 6364136223846793005U , 1442695040888963407U , 0U> ;10 constexpr N init = 10164167376618180197U ;11 linear_congruential_engine generator{init};12

13 namespace shuffle {14

15 template<typename I>16 void solve(I first, I past) {17 std : :shuffle(first, past, generator) ;18 }19 }

Page 57: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

57

D. Helpers

D.1 point.h++

1 #ifndef __POINT__2 #define __POINT__3

4 #include <algorithm> // std : :min std : :max5 #include <cassert> // assert macro6 #include ”cphmpl/functions .h++” // cphmpl : : width7 #include ”cphstl/integers .h++” // cphstl : :Z8 #include <cstddef> // std : : s ize t9 #include <functional> // std : : less

10 #include <limits> // std : : numeric limits11 #include <string> // std : : string std : : to string12

13 // is point14

15 template<typename P>16 concept bool is_point =17 requires (P p , P q) {18 typename P : :coordinate ;19 {p.x} → typename P : :coordinate ;20 {p.y} → typename P : :coordinate ;21 P( ) ;22 P(p.x , p.y) ;23 {p == q} → bool ;24 {p =6== q} → bool ;25 };26

27 // point28

29 template<typename T>30 class point {31 public :32

33 using self = point<T> ;34 using coordinate = T ;35

36 T x ;37 T y ;38

39 explicit point( )40 : x(0) , y(0) {41 }42

43 point(T x_coordinate, T y_coordinate)44 : x(x_coordinate) , y(y_coordinate) {45 }46

47 std : :string to_string( ) const {48 return ”(” + std : :to_string(x) + ” , ” + std : :to_string(y) + ”)”;

Page 58: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

58

49 }50

51 bool operator==(point<T> const& other) const {52 return x == other.x and y == other.y ;53 }54

55 bool operator=6== (point<T> const& other) const {56 return not (∗this == other) ;57 }58

59 bool operator<(point<T> const& other) const {60 return (x < other.x) or (x == other.x and y < other.y) ;61 }62

63 bool operator>(point<T> const& other) const {64 return other < ∗this ;65 }66

67 friend std : :ostream& operator<<(std : :ostream& os , point<T> const& p) {68 return os << p.to_string( ) ;69 }70 };71

72 #if defined(MULTIPLE_PRECISION) or defined(FLOATING_POINT_FILTER) or↪→ defined(PARTIALLY_EVALUATED)

73

74 namespace multiple_precision {75

76 template<typename P>77 requires is_point<P>78 bool left_turn(P const& p , P const& q , P const& r) {79

80 #ifdef MEASURE_TURNS81

82 ++turns ;83

84 #endif85

86 using N = std : :size_t ;87 using T = decltype(p.x) ;88 constexpr N w = cphmpl : :width<T> ;89 using Z = cphstl : :Z<2 ∗ w + 4> ;90 Z px (p.x) ;91 Z py (p.y) ;92 Z qx (q.x) ;93 Z qy (q.y) ;94 Z rx (r.x) ;95 Z ry (r.y) ;96 Z lhs = (qx − px ) ∗ (ry − py ) ;97 Z rhs = (rx − px ) ∗ (qy − py ) ;98 return lhs > rhs ;99 }

Page 59: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

59

100

101 template<typename P>102 bool no_turn(P const& p , P const& q , P const& r) {103

104 #ifdef MEASURE_TURNS105

106 ++turns ;107

108 #endif109

110 using N = std : :size_t ;111 using T = decltype(p.x) ;112 constexpr N w = cphmpl : :width<T> ;113 using Z = cphstl : :Z<2 ∗ w + 4> ;114 Z px (p.x) ;115 Z py (p.y) ;116 Z qx (q.x) ;117 Z qy (q.y) ;118 Z rx (r.x) ;119 Z ry (r.y) ;120 Z lhs = (qx − px ) ∗ (ry − py ) ;121 Z rhs = (rx − px ) ∗ (qy − py ) ;122 return lhs == rhs ;123 }124

125 // compute the signed area of the parallelogram spanned by126 // −→pq and −→pr .127

128 template<typename P>129 auto signed_area(P const& p , P const& q , P const& r) {130

131 #ifdef MEASURE_TURNS132

133 ++turns ;134

135 #endif136

137 using N = std : :size_t ;138 using T = decltype(p.x) ;139 constexpr N w = cphmpl : :width<T> ;140 using Z = cphstl : :Z<2 ∗ w + 5> ;141 Z px (p.x) ;142 Z py (p.y) ;143 Z qx (q.x) ;144 Z qy (q.y) ;145 Z rx (r.x) ;146 Z ry (r.y) ;147 Z lhs = (qx − px ) ∗ (ry − py ) ;148 Z rhs = (rx − px ) ∗ (qy − py ) ;149 Z result = lhs − rhs ;150 return result ;151 }

Page 60: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

60

152

153 // return the square of the distance between p and q154

155 template<typename P>156 auto distance_squared(P const& p , P const& q) {157 using N = std : :size_t ;158 using T = decltype(p.x) ;159 constexpr N w = cphmpl : :width<T> ;160 using Z = cphstl : :Z<2 ∗ w + 5> ;161 Z px = Z(p.x) ;162 Z py = Z(p.y) ;163 Z qx = Z(q.x) ;164 Z qy = Z(q.y) ;165 return (px − qx ) ∗ (px − qx ) + (py − qy ) ∗ (py − qy ) ;166 }167

168 template<typename P>169 auto L∞distance(P const& p , P const& q) {170 using N = std : :size_t ;171 using T = decltype(p.x) ;172 constexpr N w = cphmpl : :width<T> ;173 using Z = cphstl : :Z<w + 2> ;174 Z px = Z(p.x) ;175 Z py = Z(p.y) ;176 Z qx = Z(q.x) ;177 Z qy = Z(q.y) ;178 Z dx = (qx > px ) ? qx − px : px − qx ;179 Z dy = (qy > py ) ? qy − py : py − qy ;180 return std : :max(dx , dy) ;181 }182

183 template<typename P>184 auto L1_distance(P const& p , P const& q) {185 using N = std : :size_t ;186 using T = decltype(p.x) ;187 constexpr N w = cphmpl : :width<T> ;188 using Z = cphstl : :Z<w + 3> ;189 Z px = Z(p.x) ;190 Z py = Z(p.y) ;191 Z qx = Z(q.x) ;192 Z qy = Z(q.y) ;193 Z dx = (qx > px ) ? qx − px : px − qx ;194 Z dy = (qy > py ) ? qy − py : py − qy ;195 return dx + dy ;196 }197

198 // return the orientation when moving from p to r via q199 // +1: le f t turn200 // 0: p, q, and r are collinear201 // −1: right turn202

203 template<typename P>

Page 61: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

61

204 int orientation(P const& p , P const& q , P const& r) {205 using N = std : :size_t ;206 using T = decltype(p.x) ;207 constexpr N w = cphmpl : :width<T> ;208 using Z = cphstl : :Z<2 ∗ w + 4> ;209 Z px = Z(p.x) ;210 Z py = Z(p.y) ;211 Z qx = Z(q.x) ;212 Z qy = Z(q.y) ;213 Z rx = Z(r.x) ;214 Z ry = Z(r.y) ;215 Z lhs = (qx − px ) ∗ (ry − py ) ;216 Z rhs = (rx − px ) ∗ (qy − py ) ;217 i f (lhs == rhs) {218 return 0;219 }220 return (lhs > rhs) ? +1 : −1;221 }222 }223

224 #endif225

226 #if defined(DOUBLE_PRECISION)227

228 namespace double_precision {229

230 template<typename P>231 bool left_turn(P const& p , P const& q , P const& r) {232

233 #ifdef MEASURE_TURNS234

235 ++turns ;236

237 #endif238

239 using Z = long long int ;240 using U = unsigned long long int ;241 Z px = Z(p.x) ;242 Z py = Z(p.y) ;243 Z qx = Z(q.x) ;244 Z qy = Z(q.y) ;245 Z rx = Z(r.x) ;246 Z ry = Z(r.y) ;247 Z dx1 = qx − px ;248 Z dx2 = rx − qx ;249 Z dy1 = qy − py ;250 Z dy2 = ry − qy ;251

252 enum {non_negative = 0, negative = 1};253 bool dx1_sign = dx1 < Z( ) ;254 bool dy2_sign = dy2 < Z( ) ;255 bool dx2_sign = dx2 < Z( ) ;

Page 62: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

62

256 bool dy1_sign = dy1 < Z( ) ;257

258 bool lhs_sign = dx1_sign =6== dy2_sign ;259 bool rhs_sign = dx2_sign =6== dy1_sign ;260

261 i f (dx1 == Z( ) or dy2 == Z( )) {262 i f (dx2 == Z( ) or dy1 == Z( )) {263 return false ;264 }265 return rhs_sign ;266 }267 i f (lhs_sign =6== rhs_sign) {268 return rhs_sign ;269 }270 else {271 U ux1 = dx1_sign == negative ? U(−dx1) : U(dx1) ;272 U uy2 = dy2_sign == negative ? U(−dy2) : U(dy2) ;273 U ux2 = dx2_sign == negative ? U(−dx2) : U(dx2) ;274 U uy1 = dy1_sign == negative ? U(−dy1) : U(dy1) ;275 U lhs = ux1 ∗ uy2 ;276 U rhs = ux2 ∗ uy1 ;277 i f (lhs_sign == negative) {278 return lhs < rhs ;279 }280 else {281 return lhs > rhs ;282 }283 }284 }285

286 template<typename P>287 bool no_turn(P const& p , P const& q , P const& r) {288

289 #ifdef MEASURE_TURNS290

291 ++turns ;292

293 #endif294

295 using T = decltype(p.x) ;296 using Z = long long ;297 Z px = Z(p.x) ;298 Z py = Z(p.y) ;299 Z qx = Z(q.x) ;300 Z qy = Z(q.y) ;301 Z rx = Z(r.x) ;302 Z ry = Z(r.y) ;303 Z dx1 = qx − px ;304 Z dx2 = rx − qx ;305 Z dy1 = qy − py ;306 Z dy2 = ry − qy ;307

Page 63: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

63

308 bool check1 = Z(T(dx1 )) =6== dx1 and Z(T(dy2 )) =6== dy2 ;309 bool check2 = Z(T(dx2 )) =6== dx2 and Z(T(dy1 )) =6== dy1 ;310 i f (check1 or check2) {311 // i f they do not both overflow , they must be different312 i f (check1 and check2) {313 // i f overflow direction not the same, they are different314 i f (((dx1 > 0) == (dy2 > 0)) == ((dx2 > 0) == (dy1 > 0))) {315 // the non−overflow part must also be the same316 return dx1 ∗ dy2 == dx2 ∗ dy1 ;317 }318 }319 return false ;320 }321 else {322 return dx1 ∗ dy2 == dx2 ∗ dy1 ;323 }324 }325

326 // may do controlled overflow on very large values327

328 template<typename P>329 auto signed_area(P const& p , P const& q , P const& r) {330 assert(not right_turn(p , q , r)) ;331

332 #ifdef MEASURE_TURNS333

334 ++turns ;335

336 #endif337

338 using Z = long long ;339 using U = unsigned long long ;340 Z px = Z(p.x) ;341 Z py = Z(p.y) ;342 Z qx = Z(q.x) ;343 Z qy = Z(q.y) ;344 Z rx = Z(r.x) ;345 Z ry = Z(r.y) ;346 Z dx1 = qx − px ;347 Z dx2 = rx − qx ;348 Z dy1 = qy − py ;349 Z dy2 = ry − qy ;350 return (U) (dx1 ∗ dy2 − dx2 ∗ dy1 ) ;351 }352 }353

354 #endif355

356 #if defined(FLOATING_POINT_FILTER)357

358 namespace floating_point_filter {359

Page 64: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

64

360 template<typename P>361 bool left_turn(P const& p , P const& q , P const& r) {362

363 #ifdef MEASURE_TURNS364

365 ++turns ;366

367 #endif368

369 using R = double;370 constexpr R u = std : :numeric_limits<R> : :epsilon( ) ;371 R px = R(p.x) ;372 R py = R(p.y) ;373 R qx = R(q.x) ;374 R qy = R(q.y) ;375 R rx = R(r.x) ;376 R ry = R(r.y) ;377 R lhs = (qx − px ) ∗ (ry − py ) ;378 R rhs = (rx − px ) ∗ (qy − py ) ;379 R det = lhs − rhs ;380 R detsum = 0. 0;381 i f (lhs > 0. 0) {382 i f (rhs ≤ 0. 0) {383 return lhs > rhs ;384 }385 else {386 detsum = lhs + rhs ;387 }388 }389 else if (lhs < 0. 0) {390 i f (rhs ≥ 0. 0) {391 return lhs > rhs ;392 }393 else {394 detsum = −lhs − rhs ;395 }396 }397 else {398 return lhs > rhs ;399 }400 R errbound = (3 ∗ u + 16 ∗ u ∗ u) ∗ detsum ;401 i f (det ≥ errbound or −det ≥ errbound) {402 return lhs > rhs ;403 }404 return multiple_precision : :left_turn(p , q , r) ;405 }406

407 template<typename P>408 bool no_turn(P const& p , P const& q , P const& r) {409

410 #ifdef MEASURE_TURNS411

Page 65: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

65

412 ++turns ;413

414 #endif415

416 using R = double;417 constexpr R u = std : :numeric_limits<R> : :epsilon( ) ;418 R px = R(p.x) ;419 R py = R(p.y) ;420 R qx = R(q.x) ;421 R qy = R(q.y) ;422 R rx = R(r.x) ;423 R ry = R(r.y) ;424 R lhs = (qx − px ) ∗ (ry − py ) ;425 R rhs = (rx − px ) ∗ (qy − py ) ;426 R det = lhs − rhs ;427 R detsum = 0. 0;428 i f (lhs > 0. 0) {429 i f (rhs ≤ 0. 0) {430 return false ;431 }432 else {433 detsum = lhs + rhs ;434 }435 }436 else if (lhs < 0. 0) {437 i f (rhs ≥ 0. 0) {438 return false ;439 }440 else {441 detsum = −lhs − rhs ;442 }443 }444 else {445 return lhs == rhs ;446 }447 R errbound = (3 ∗ u + 16 ∗ u ∗ u) ∗ detsum ;448 i f (det ≥ errbound or −det ≥ errbound) {449 return lhs == rhs ;450 }451 return multiple_precision : :no_turn(p , q , r) ;452 }453

454 template<typename P>455 auto signed_area(P const& p , P const& q , P const& r) {456 return multiple_precision : :signed_area(p , q , r) ;457 }458 }459

460 #endif461

462 #if defined(MULTIPLE_PRECISION)463

Page 66: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

66

464 using namespace multiple_precision ;465

466 #elif defined(DOUBLE_PECISION)467

468 using namespace double_precision ;469

470 #elif defined(FLOATING_POINT_FILTER)471

472 using namespace floating_point_filter ;473

474 #elif defined(PARTIALLY_EVALUATED)475

476 using namespace multiple_precision ;477

478 #endif479

480 template<typename P>481 bool right_turn(P const& p , P const& q , P const& r) {482 return left_turn(r , q , p) ;483 }484

485 // is p on the line segment {q, r}?486

487 template<typename P>488 bool on_line_segment(P const& p , P const& q , P const& r) {489 P left = std : :min(q , r) ;490 P right = std : :max(q , r) ;491 i f (p < left) {492 return false ;493 }494 i f (p > right) {495 return false ;496 }497 return no_turn(p , q , r) ;498 }499

500 // is p on the le f t of q?501

502 template<typename C>503 class on_the_left {504 public :505

506 on_the_left(C compare)507 : less(compare) {508 }509

510 template<typename P>511 bool operator( )(P const& p , P const& q) {512 return less(p.x , q.x) or (p.x == q.x and less(p.y , q.y)) ;513 }514

515 private :

Page 67: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

67

516

517 C less ;518 };519

520 #endif

D.2 validation.h++

1 #ifndef __VALIDATION__2 #define __VALIDATION__3

4 #include <algorithm> // std : : copy std : : sort std : : equal std : : rotate5 #include <cassert> // assert macro6 #include <cstdlib> // std : : s ize t7 #include <iostream> // std streams8 #include <iterator> // std : : iterator traits std : : distance . . .9 #include ”point .h++” // left turn right turn

10 #include <vector> // std : : vector11

12 namespace validation {13

14 template<typename I , typename J>15 bool same_multiset(I p , I q , J r , J s) {16 using P = typename std : :iterator_traits<I> : :value_type ;17 using S = std : :vector<P> ;18 std : :size_t n = std : :distance(p , q) ;19 std : :size_t m = std : :distance(r , s) ;20 i f (m =6== n) {21 return false ;22 }23 S backup ;24 backup.resize(n) ;25 std : :copy(p , q , backup.begin( )) ;26 std : :sort(backup.begin( ) , backup.end( ) ,27 [ ](P const& a , P const& b) → bool {28 return (a.x < b.x) or (a.x == b.x and a.y < b.y) ;29 }) ;30 S other ;31 other.resize(n) ;32 std : :copy(r , s , other.begin( )) ;33 std : :sort(other.begin( ) , other.end( ) ,34 [ ](P const& a , P const& b) → bool {35 return (a.x < b.x) or (a.x == b.x and a.y < b.y) ;36 }) ;37 return std : :equal(backup.begin( ) , backup.end( ) , other.begin( ) ,38 [ ](P const& a , P const& b) → bool {39 return (a.x == b.x) and (a.y == b.y) ;40 }) ;41 }42

43 // [p, r) circular chain of vertices

Page 68: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

68

44

45 template<typename I>46 bool left_turns_only(I p , I r) {47 std : :size_t h = std : :distance(p , r) ;48 i f (h < 3) {49 return true ;50 }51 for (I q = p ; q =6== r ; ++q) {52 I next = std : :next(q) ;53 I next_after = std : :next(next) ;54 i f (q == std : :prev(std : :prev(r))) {55 next_after = p ;56 }57 else if (q == std : :prev(r)) {58 next = p ;59 next_after = std : :next(p) ;60 }61 i f (not left_turn(∗q , ∗next, ∗next_after)) {62 std : :cerr << ”Left−turn : ” << ∗q << ” ” << ∗next << ” ”63 << ∗next_after << ” failed\n”;64 return false ;65 }66 }67 return true ;68 }69

70 // [p, r) circular chain of vertices71

72 template<typename I>73 bool right_turns_only(I p , I r) {74 std : :size_t h = std : :distance(p , r) ;75 i f (h < 3) {76 return true ;77 }78 for (I q = p ; q =6== r ; ++q) {79 I next = std : :next(q) ;80 I next_after = std : :next(next) ;81 i f (q == std : :prev(std : :prev(r))) {82 next_after = p ;83 }84 else if (q == std : :prev(r)) {85 next = p ;86 next_after = std : :next(p) ;87 }88 i f (not right_turn(∗q , ∗next, ∗next_after)) {89 std : :cerr << ”Right−turn : ” << ∗q << ” ” << ∗next << ” ”90 << ∗next_after << ” failed\n”;91 return false ;92 }93 }94 return true ;95 }

Page 69: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

69

96

97 // [p, r) half−circular chain of vertices98

99 template<typename I>100 bool monotone(I p , I r) {101 assert(p =6== r) ;102 using P = typename std : :iterator_traits<I> : :value_type ;103 std : :size_t h = std : :distance(p , r) ;104 i f (h == 0 or h == 1) {105 return true ;106 }107 I q = p ;108 while (q =6== std : :prev(r)) {109 P a = ∗q ;110 P b = ∗std : :next(q) ;111 i f (not (a.x < b.x or (a.x == b.x and a.y < b.y))) {112 std : :cerr << ”Convex: ” << a << ” ” << b113 << ”: not monotone\n”;114 return false ;115 }116 ++q ;117 }118 return true ;119 }120

121 // [p, r) circular chain of vertices122

123 template<typename I>124 bool convex_polygon(I p , I r) {125 using P = typename std : :iterator_traits<I> : :value_type ;126 using S = std : :vector<P> ;127 using J = typename S : :iterator ;128 std : :size_t h = std : :distance(p , r) ;129 i f (h == 0 or h == 1) {130 return true ;131 }132 i f (h == 2) {133 i f (∗p =6== ∗std : :next(p)) {134 return true ;135 }136 else {137 std : :cerr << ”Convex: h = 2: two equal points\n”;138 return false ;139 }140 }141 // h ≥ 3142 bool clockwise = right_turn(∗p , ∗std : :next(p) , ∗std : :next(std : :next(p))) ;143 i f (clockwise and (not right_turns_only(p , r))) {144 std : :cerr << ”Convex: h = ” << h145 << ”: not a spiral (cw)\n”;146 return false ;147 }

Page 70: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

70

148 i f (not clockwise and (not left_turns_only(p , r))) {149 std : :cerr << ”Convex: h = ” << h150 << ”: not a spiral (ccw)\n”;151 return false ;152 }153

154 using P = typename std : :iterator_traits<I> : :value_type ;155 using S = std : :vector<P> ;156 using J = typename S : :iterator ;157 S hull ;158 hull.resize(h) ;159 std : :copy(p , r , hull.begin( )) ;160 J west = std : :min_element(hull.begin( ) , hull.end( ) ,161 [ ](P const& a , P const& b) → bool {162 return (a.x < b.x) or (a.x == b.x and a.y < b.y) ;163 }) ;164 (void) std : :rotate(hull.begin( ) , west, hull.end( )) ;165 hull.push_back(∗west) ;166 west = hull.begin( ) ;167 J east = std : :max_element(hull.begin( ) , std : :prev(hull.end( )) ,168 [ ](P const& a , P const& b) → bool {169 return (a.x < b.x) or (a.x == b.x and a.y < b.y) ;170 }) ;171 assert(west =6== east) ;172 i f (clockwise) {173 i f (not monotone(west, std : :next(east))) {174 std : :cerr << ”Convex: h = ” << h175 << ”: upper hull not monotone (cw)\n”;176 return false ;177 }178 std : :reverse(east, hull.end( )) ;179 i f (not monotone(east, hull.end( ))) {180 std : :cerr << ”Convex: h = ” << h181 << ”: lower hull not monotone (cw)\n”;182 return false ;183 }184 return true ;185 }186 // counterclockwise187 i f (not monotone(west, std : :next(east))) {188 std : :cerr << ”Convex: h = ” << h189 << ”: lower hull not monotone (ccw)\n”;190 return false ;191 }192 std : :reverse(east, hull.end( )) ;193 i f (not monotone(east, hull.end( ))) {194 std : :cerr << ”Convex: h = ” << h195 << ”: upper hull not monotone (ccw)\n”;196 return false ;197 }198 return true ;199 }

Page 71: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

71

200

201 // [p, r) upper hull from le f t to right202

203 template<typename I , typename P>204 bool above(I p , I r , P const& u) {205 std : :size_t h = std : :distance(p , r) ;206 assert(h > 1) ;207 I last = std : :prev(r) ;208 assert(u.x ≥ (∗p) .x and u.x ≤ (∗last) .x) ;209 i f ((∗p) .x == (∗std : :next(p)) .x) {210 ++p ;211 }212 i f (h =6== 1 and (∗last) .x == (∗std : :prev(last)) .x) {213 −−r ;214 }215 I q = std : :lower_bound(p , r , u ,216 [ ](P const& a , P const& b) → bool {217 return (a.x < b.x) ;218 }) ;219 i f (q == p) {220 return u.y > (∗p) .y ;221 }222 return left_turn(∗std : :prev(q) , ∗q , u) ;223 }224

225 // [p, r) lower hull from le f t to right226

227 template<typename I , typename P>228 bool below(I p , I r , P const& u) {229 std : :size_t h = std : :distance(p , r) ;230 assert(h > 1) ;231 I last = std : :prev(r) ;232 assert(u.x ≥ (∗p) .x and u.x ≤ (∗last) .x) ;233 i f ((∗p) .x == (∗std : :next(p)) .x) {234 ++p ;235 }236 i f (h =6== 1 and (∗last) .x == (∗(last − 1)) .x) {237 −−r ;238 }239 I q = std : :lower_bound(p , r , u ,240 [ ](P const& a , P const& b) → bool {241 return (a.x < b.x) ;242 }) ;243 i f (q == p) {244 return u.y < (∗p) .y ;245 }246 return right_turn(∗std : :prev(q) , ∗q , u) ;247 }248

249 // [ r , s) multiset of points ; [p, q) convex polygon250

251 template<typename I , typename J>

Page 72: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

72

252 bool all_inside(I r , I s , J p , J q) {253 std : :size_t h = std : :distance(p , q) ;254 i f (h == 0) {255 i f (r =6== s) {256 std : :cerr << ”Inside : h = 0: no points can be inside\n”;257 return false ;258 }259 return true ;260 }261 i f (h == 1) {262 for (J i = r ; i =6== s ; ++i) {263 i f (∗i =6== ∗p) {264 std : :cerr << ”Inside : h = 1: a l l points not equal\n”;265 return false ;266 }267 }268 return true ;269 }270 i f (h == 2) {271 for (J i = r ; i =6== s ; ++i) {272 i f (not on_line_segment(∗i , ∗p , ∗std : :next(p))) {273 std : :cerr << ”Inside : h = 2: a l l points not collinear\n”;274 return false ;275 }276 }277 return true ;278 }279 using P = typename std : :iterator_traits<I> : :value_type ;280 using S = std : :vector<P> ;281 using K = typename S : :iterator ;282 S hull ;283 hull.resize(h) ;284 std : :copy(p , q , hull.begin( )) ;285 K west = std : :min_element(hull.begin( ) , hull.end( ) ,286 [ ](P const& a , P const& b) → bool {287 return (a.x < b.x) or (a.x == b.x and a.y < b.y) ;288 }) ;289 (void) std : :rotate(hull.begin( ) , west, hull.end( )) ;290 hull.push_back(∗west) ;291 west = hull.begin( ) ;292 K east = std : :max_element(hull.begin( ) , std : :prev(hull.end( )) ,293 [ ](P const& a , P const& b) → bool {294 return (a.x < b.x) or (a.x == b.x and a.y < b.y) ;295 }) ;296 assert(west =6== east) ;297 for (I i = r ; i =6== s ; ++i) {298 i f ((∗i) .x < (∗west) .x) {299 std : :cerr << ”Inside : ” << ∗i300 << ” on le f t of the output\n”;301 return false ;302 }303 i f ((∗i) .x > (∗east) .x) {

Page 73: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

73

304 std : :cerr << ”Inside : ” << ∗i305 << ” on right of the output\n”;306 return false ;307 }308 }309 bool clockwise = right_turn(∗west, ∗std : :next(west) , ∗std : :next(std : :next(west))) ;310 i f (clockwise) {311 for (I i = r ; i =6== s ; ++i) {312 i f (above(west, std : :next(east) , ∗i)) {313 std : :cerr << ”Inside : ” << ∗i314 << ” above the upper hull (cw)\n”;315 return false ;316 }317 }318 std : :reverse(east, hull.end( )) ;319 for (I i = r ; i =6== s ; ++i) {320 i f (below(east, hull.end( ) , ∗i)) {321 std : :cerr << ”Inside : ” << ∗i322 << ” below the lower hull (cw)\n”;323 return false ;324 }325 }326 }327 else { // counterclockwise328 for (I i = r ; i =6== s ; ++i) {329 i f (below(west, std : :next(east) , ∗i)) {330 std : :cerr << ”Inside : ” << ∗i331 << ” below the lower hull (ccw)\n”;332 return false ;333 }334 }335 std : :reverse(east, hull.end( )) ;336 for (I i = r ; i =6== s ; ++i) {337 i f (above(east, hull.end( ) , ∗i)) {338 std : :cerr << ”Inside : ” << ∗i339 << ” above the upper hull (ccw)\n”;340 return false ;341 }342 }343 }344 return true ;345 }346 }347

348 #endif

D.3 bucketsort.h++

1 /∗2 This program implements bucketsort3

Page 74: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

74

4 Source : O. Nevalainen and T. Raita , An internal hybrid sort5 algorithm revisited , The Computer Journal 35,2 (1992) , 177−1836

7 Author: Jyrki Katajainen © 20188

9 Worst−case running time : O(n lg n)

10 Parameter: m = min(n/5, 216)11 Average−case running time : O(n lg(n/m))12 Extra space : n elements , m+O(lg n) words13

14 Observed sorting time per n lg n [ ns ] ; input : random permutation15 1024 1.0716 32768 0.8217 1048576 1.1718 33554432 2.0419 ∗/20

21 #ifndef __BUCKETSORT__22 #define __BUCKETSORT__23

24 #include <algorithm> // std : : sort std : : copy25 #include <cassert> // assert macro26 #include <cstddef> // std : : ptrdiff t27 #include <iterator> // std : : distance std : : iterator traits28 #include <utility> // std : : pair29

30 namespace bucketsort {31

32 constexpr std : :ptrdiff_t threshold = 100;33 constexpr std : :ptrdiff_t max_m = (1 << 16) ;34

35 template<typename V>36 class identity {37 public :38

39 constexpr V&& operator( )(V&& v) const {40 return std : :forward<V>(v) ;41 }42

43 constexpr V const& operator( )(V const& v) const {44 return v ;45 }46

47 constexpr V& operator( )(V& v) const {48 return v ;49 }50 };51

52 template<typename D , typename V , typename K = identity<V>>53 class bucket {54 public :

Page 75: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

75

55

56 bucket(D m , V const& min, V const& max, K key = K( ))57 : a(double(m − 1) / (double(key(max)) − double(key(min)))) ,58 b(double(m − 1) ∗ double(key(min)) / (double(key(max)) − double(key(min)))) ,59 key(key) {60 }61

62 D operator( )(V const& x) {63 return D(a ∗ double(key(x)) − b) ;64 }65

66 private :67

68 double a ;69 double b ;70 K key ;71 };72

73 template<typename R , typename C , typename K = identity<typename↪→ std : :iterator_traits<R> : :value_type>>

74 void sort(R data, R past, C compare, K key = K( )) {75 using V = typename std : :iterator_traits<R> : :value_type ;76 using D = typename std : :iterator_traits<R> : :difference_type ;77 D const n = std : :distance(data, past) ;78

79 // small input80

81 i f (n < threshold) {82 std : :sort(data, past, compare) ;83 return;84 }85 D m = std : :min(n / 5, max_m) ;86 V∗ copy = new V [n ] ;87 D∗ counter = new D [m + 1] ;88

89 // init ial ization90

91 std : :pair<R , R> pair = std : :minmax_element(data, past, compare) ;92 R leftmost = std : :get<0>(pair) ;93 R rightmost = std : :get<1>(pair) ;94 i f (key(∗leftmost) == key(∗rightmost)) {95 return;96 }97 bucket formula(m , ∗leftmost, ∗rightmost, key) ;98 for (D j = 0; j ≤ m ; ++j) {99 counter [j ] = 0;

100 }101

102 // determination of the number of elements in the buckets103

104 for (D i = 0; i =6== n ; ++i) {105 D j = formula(∗(data + i)) ;

Page 76: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

76

106 counter [j ] = counter [j ] + 1;107 copy [i ] = ∗(data + i) ;108 }109 assert(counter [m ] == 0) ;110

111 // init ial ization of the cursors to the buckets112

113 for (D j = 1; j ≤ m ; ++j) {114 counter [j ] = counter [j − 1] + counter [j ] ;115 }116

117 // construction of the buckets118

119 for (D i = n − 1; i ≥ 0; −−i) {120 D j = formula(copy [i ] ) ;121 counter [j ] = counter [j ] − 1;122 data [counter [j ] ] = copy [i ] ;123 }124

125 // sorting the buckets126

127 for (D j = 0; j =6== m ; ++j) {128 std : :sort(data + counter [j ] , data + counter [j + 1] , compare) ;129 }130 delete[ ] copy ;131 delete[ ] counter ;132 }133 }134

135 #endif

D.4 two_phase_bucketsort.h++

1 /∗2 This program implements two−phase bucketsort3

4 Author: Jyrki Katajainen © 20185

6 Worst−case running time : O(n lg n)7 Parameter: m8 Average−case running time : O(n)9 Extra space : O(

√n+m) words

10

11 Observed sorting time per n lg n [ ns ] ; input : random permutation12 1024 3.3313 32768 1.9214 1048576 2.0915 33554432 2.4116 ∗/17

18 #ifndef __TWO_PHASE_BUCKETSORT__

Page 77: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

77

19 #define __TWO_PHASE_BUCKETSORT__20

21 #include <algorithm> // std : : sort std : : copy22 #include ”bucketsort .h++”23 #include <cassert> // assert macro24 #include <cmath> // std : : sqrt25 #include <cstddef> // std : : ptrdiff t26 #include <iterator> // std : : distance std : : iterator traits27 #include <utility> // std : : pair28

29 namespace two_phase_bucketsort {30

31 constexpr std : :ptrdiff_t threshold = 100;32

33 template<typename R , typename C , typename K = bucketsort : :identity<typename↪→ std : :iterator_traits<R> : :value_type>>

34 void sort(R data, R past, C compare, K key = K( )) {35 using D = typename std : :iterator_traits<R> : :difference_type ;36 D const n = std : :distance(data, past) ;37

38 // small input39

40 i f (n < threshold) {41 std : :sort(data, past, compare) ;42 return;43 }44 D m = D(std : :sqrt(n)) ;45 D∗ counter = new D [m ] ;46 D∗ cursor = new D [m + 1] ;47

48 // in i t ia l i ze the bucket formula49

50 std : :pair<R , R> pair = std : :minmax_element(data, past, compare) ;51 R leftmost = std : :get<0>(pair) ;52 R rightmost = std : :get<1>(pair) ;53 i f (key(∗leftmost) == key(∗rightmost)) {54 return;55 }56 bucketsort : :bucket formula(m , ∗leftmost, ∗rightmost, key) ;57 for (D j = 0; j =6== m ; ++j) {58 counter [j ] = 0;59 }60

61 // determine the number of elements in the buckets62

63 for (D i = 0; i =6== n ; ++i) {64 D j = formula(∗(data + i)) ;65 counter [j ] = counter [j ] + 1;66 }67

68 // in i t ia l i ze the cursors to the buckets69

Page 78: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

78

70 cursor [0 ] = counter [ 0 ] ;71 for (D j = 1; j =6== m ; ++j) {72 cursor [j ] = cursor [j − 1] + counter [j ] ;73 }74 cursor [m ] = n ;75

76 // move the elements into the buckets77

78 D home = m − 1;79 for (D k = 0; k =6== n ; ++k) {80 while (counter [home ] == 0) {81 −−home ;82 }83 D j = formula(data [cursor [home ] − 1]) ;84 i f (home =6== j) {85 std : :swap(data [cursor [home ] − 1] , data [cursor [j ] − 1]) ;86 }87 counter [j ] = counter [j ] − 1;88 cursor [j ] = cursor [j ] − 1;89 }90

91 // sort the buckets92

93 for (D j = 0; j =6== m ; ++j) {94 bucketsort : :sort(data + cursor [j ] , data + cursor [j + 1] , compare, key) ;95 }96 delete[ ] counter ;97 delete[ ] cursor ;98 }99 }

100

101 #endif

D.5 cphstl/slices.h++

1 /∗2 Author: Jyrki Katajainen © 2006, 2019−20203 ∗/4

5 #ifndef __CPHSTL_SLICES__6 #define __CPHSTL_SLICES__7

8 #include ”cphmpl/concepts.h++” // cpp20 iterator categories9 #include ”cphmpl/functions .h++” // cphmpl type functions

10 #include <cstddef> // std : : s ize t std : : ptrdiff t11 #include <initializer_list> // std : : i n i t i a l i z e r l i s t12 #include <iterator> // std : : iterator traits std : : distance13 #include <tuple> // std : : tuple14 #include <type_traits> // std : : is same v . . .15 #include <utility> // std : : pair std : :move16

Page 79: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

79

17 namespace cphstl {18

19 /∗20 We say that a container specif ies a range i f i t can be given as21 an argument for the functions : std : : begin , std : : cbegin , std : : end,22 std : : cend, std : : size , and std : :empty. A sl ice can be used to give23 these fac i l i t e s for part of a container .24 ∗/25

26 // Class : s l ice< iterator , sentinel>27

28 // Description : The purpose of this class is to define a subrange29 // of iterators for part of some unspecified container . Hereafter a30 // container and a s l ice can be used in the same way in many31 // generic algorithms .32

33 // Precondition :34 // − the given iterators should refer to the same container .35

36 template<typename T , typename U = T>37 requires cpp20 : :is_iterator<T> and cpp20 : :is_sentinel<U , T>38 class slice {39 private :40

41 T first ;42 U past ;43

44 using V = typename std : :iterator_traits<T> : :value_type ;45

46 public :47

48 // types49

50 using iterator = T ;51 using const_iterator = T ; // sorry : cphmpl : : const iterator<T> ;52 using sentinel = U ;53 using const_sentinel = U ; // sorry !54 using value_type = V ;55 using reference = typename std : :iterator_traits<T> : :reference ;56 using const_reference = cphmpl : :const_reference<T> ;57 using size_type = std : :size_t ;58 using difference_type = std : :ptrdiff_t ;59

60 // structors61

62 template<typename C>63 requires cphmpl : :is_container<C>64 constexpr slice(C& container)65 : first(container.begin( )) , past(container.end( )) {66 }67

68 template<typename S>

Page 80: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

80

69 requires cphmpl : :is_slice<S>70 constexpr slice(S& another)71 : first(another.begin( )) , past(another.end( )) {72 }73

74 constexpr slice(T const& x , U const& y)75 : first(x) , past(y) {76 }77

78 constexpr slice(T&& x , U&& y)79 : first(std : :move(x)) , past(std : :move(y)) {80 }81

82 constexpr slice(std : :initializer_list<T> s)83 : first(∗s.begin( )) , past(∗std : :next(s.begin( ))) {84 }85

86 constexpr slice(std : :tuple<T , U> const& t)87 : first(std : :get<0>(t)) , past(std : :get<1>(t)) {88 }89

90 constexpr slice(std : :pair<T , U> const& p)91 : first(std : :get<0>(p)) , past(std : :get<1>(p)) {92 }93

94 slice(slice const&) = default ;95 slice(slice&&) = default ;96

97 // assignments98

99 slice& operator=(slice const&) = default ;100 slice& operator=(slice&&) = default ;101

102 // iterators103

104 constexpr auto begin( ) const {105 return empty( ) ? past : first ;106 }107

108 constexpr auto begin( ) {109 return empty( ) ? past : first ;110 }111

112 constexpr auto cbegin( ) const {113 return empty( ) ? const_sentinel(past) : const_iterator(first) ;114 }115

116 constexpr const_sentinel end( ) const {117 return past ;118 }119

120 constexpr sentinel end( ) {

Page 81: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

81

121 return past ;122 }123

124 constexpr const_sentinel cend( ) const {125 return past ;126 }127

128 // properties129

130 constexpr size_type size( ) const {131 return std : :distance(first, past) ;132 }133

134 constexpr size_type empty( ) const {135 return first == past ;136 }137

138 // accessors139

140 constexpr const_reference operator[ ](size_type position) const141 requires cpp20 : :is_random_access_iterator<T> {142 return ∗(cbegin( ) + position) ;143 }144

145 reference operator[ ](size_type position)146 requires cpp20 : :is_random_access_iterator<T> {147 return ∗(begin( ) + position) ;148 }149

150 // comparisons151

152 constexpr bool operator==(slice const& other) const {153 return first == other.first and past == other.past ;154 }155

156 constexpr bool operator=6== (slice const& other) const {157 return ∗this =6== other ;158 }159

160 template<typename X , typename Y>161 requires std : :is_swappable_with_v<T , X> and std : :is_swappable_with_v<U , Y>162 constexpr void swap(slice<X , Y>& other) {163 std : :swap(first, other.first) ;164 std : :swap(past, other.past) ;165 }166 };167

168 /∗169 some range−based algorithms as examples170 ∗/171

172 // Function : void copy(range , range)

Page 82: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

82

173

174 // Effect : Copies the elements in the source range , let us say175 // [ f i rst , past) , to the target range.176

177 // Preconditions :178 // − std : : size (source) == std : : size (target)179 // − std : : begin(target) should not be within ( f irst , past)180

181 // Complexity: n assignments , where n = std : : size (source)182

183 template<typename S , typename T>184 requires185 /∗ 1 ∗/ cphmpl : :specifies_range<S> and186 /∗ 2 ∗/ cphmpl : :specifies_range<T> and187 /∗ 3 ∗/ cpp17 : :is_input_iterator<cphmpl : :iterator<S>> and188 /∗ 4 ∗/ cpp17 : :is_output_iterator<cphmpl : :iterator<T>> and189 /∗ 5 ∗/ std : :is_same_v<cphmpl : :value<S> , cphmpl : :value<T>>190 constexpr void copy(S const& source, T& target) {191 assert(std : :size(source) == std : :size(target)) ;192 using I = cphmpl : :const_iterator<S> ;193 using J = cphmpl : :iterator<T> ;194 I const past = std : :cend(source) ;195 I p = std : :cbegin(source) ;196 J q = std : :begin(target) ;197 while (p =6== past) {198 ∗q++ = ∗p++;199 }200 }201

202 // Function : void copy backward(range , range)203

204 // Effect : Copies the elements from the source range , let us say205 // [ f i rst , past) , to some target range in reverse order , but the206 // relative order of the copied elements is preserved .207

208 // Preconditions :209 // − std : : size (source) == std : : size (target)210 // − std : : end(target) should not be within ( f irst , past)211

212 // Complexity: n assignments , where n = std : : size (range)213

214 template<typename S , typename T>215 requires216 /∗ 1 ∗/ cphmpl : :specifies_range<S> and217 /∗ 2 ∗/ cphmpl : :specifies_range<T> and218 /∗ 3 ∗/ cpp20 : :is_bidirectional_iterator<cphmpl : :iterator<S>> and219 /∗ 4 ∗/ cpp20 : :is_bidirectional_iterator<cphmpl : :iterator<T>> and220 /∗ 5 ∗/ std : :is_same_v<cphmpl : :value<S> , cphmpl : :value<T>>221 constexpr void copy_backward(S const& source, T& target) {222 assert(std : :size(source) == std : :size(target)) ;223 using I = cphmpl : :const_iterator<S> ;224 using J = cphmpl : :iterator<T> ;

Page 83: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

83

225 I const first = std : :cbegin(source) ;226 I p = std : :cend(source) ;227 J q = std : :end(target) ;228 while (p =6== first) {229 −−p ;230 −−q ;231 ∗q = ∗p ;232 }233 }234

235 // Function : void f i l l (range , value)236

237 // Effect : Assigns the given value to the elements in the range.238

239 // Complexity: n assignments , where n = std : : size (range)240

241 template<typename T , typename V>242 requires243 /∗ 1 ∗/ cphmpl : :specifies_range<T> and244 /∗ 2 ∗/ cpp20 : :is_forward_iterator<cphmpl : :iterator<T>> and245 /∗ 3 ∗/ std : :is_same_v<cphmpl : :value<T> , V>246 constexpr void fill(T& range, V const& value) {247 using J = cphmpl : :iterator<T> ;248 J current = std : :begin(range) ;249 J const past = std : :end(range) ;250 for ( ; current =6== past ; ++current) {251 ∗current = value ;252 }253 }254

255 // Function : void swap ranges(range , range)256

257 // Effect : Exchanges the elements between a range , let us say258 // [ f i rst , past) , and some other range. The operation is259 // semi−stable , i . e. the order of elements is retained in the f i r s t260 // range , but not necessarily in the second.261

262 // Preconditions :263 // − std : : size (range) == std : : size (other)264 // − std : : begin(other) should not be within ( f irst , past)265 // − std : : end(other) should not be within ( f irst , past)266

267 // Complexity: 2n + O(1) element moves where n = std : : size (range)268

269 template<typename S , typename T>270 requires271 /∗ 1 ∗/ cphmpl : :specifies_range<S> and272 /∗ 2 ∗/ cphmpl : :specifies_range<T> and273 /∗ 3 ∗/ cpp20 : :is_forward_iterator<cphmpl : :iterator<S>> and274 /∗ 4 ∗/ cpp20 : :is_forward_iterator<cphmpl : :iterator<T>> and275 /∗ 5 ∗/ std : :is_same_v<cphmpl : :value<S> , cphmpl : :value<T>>276 constexpr void swap_ranges(S& range, T& other) {

Page 84: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

84

277 assert(std : :size(range) == std : :size(other)) ;278 using I = cphmpl : :iterator<S> ;279 using J = cphmpl : :iterator<T> ;280 auto past = std : :cend(range) ;281 I p = std : :begin(range) ;282 auto first = std : :cbegin(other) ;283 i f (p == past) {284 return;285 }286 i f constexpr (std : :is_same_v<I , J>) {287 i f (p == first) {288 return;289 }290 }291 using V = cphmpl : :value<S> ;292 V const value = std : :move(∗first) ;293 J hole = first ;294 while (true) {295 ∗hole = std : :move(∗p) ;296 ++hole ;297 i f (std : :next(p) == past) {298 break;299 }300 ∗p = std : :move(∗hole) ;301 ++p ;302 }303 ∗p = std : :move(value) ;304 }305 }306

307 #endif

Page 85: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

85

E. Drivers

E.1 check−driver.c++

1 #include ”algorithm.h++” // NAME: : solve NAME: : check2 #include <cassert> // assert macro3 #include <iterator> // std : : distance4 #include ”point .h++” // point5 #include <vector> // std : : vector6

7 int main( ) {8 using P = point<int> ;9 using S = std : :vector<P> ;

10 using I = typename S : :iterator ;11

12 S bag{P(0 , 0) , P(0 , 1) , P(0 , 2) , P(0 , 1)};13 I rest = NAME : :solve(bag.begin( ) , bag.end( )) ;14 auto h = std : :distance(bag.begin( ) , rest) ;15 assert(h == 2) ;16 assert(NAME : :check(bag.begin( ) , bag.end( ))) ;17 }

E.2 test−driver.c++

1 /∗2 Performance Engineering Laboratory © 2017−20193

4 Brownie points :5 11 Sep 2017: The test cases for overflow detection by Marius−Florin Cristian6 16 Sep 2019: The input points in a linked l i s t by Bjørn Leth Møl l e r7 ∗/8

9 #include <algorithm> // std : : copy std : : equal10 #include <cassert> // assert macro11 #include <cstdlib> // std : : rand std : : s ize t12 #include <exception> // std : : exception13 #include <iostream> // std : : cout std : : cerr14 #include <iterator> // std : : iterator traits15 #include <limits> // std : : numeric limits16 #include <list> // std : : l i s t17 #include <random> // std : : linear congruential engine18 #include <vector> // std : : vector19

20 #define DOUBLE_PRECISION21 #include ”algorithm.h++” // NAME: : check22 #include ”point .h++” // point23

24 using linear_congruential_engine = std : :linear_congruential_engine<unsigned long long,↪→ 6364136223846793005U , 1442695040888963407U , 0U> ;

25 unsigned long long const seed = 10164167376618180197U ;26 linear_congruential_engine random_number_generator{seed};

Page 86: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

86

27

28 template<typename I>29 using checker = bool (∗)(I , I) ;30

31 template<typename A>32 using testcase = void (∗)(A) ;33

34 template<typename I>35 void generate(I p , I r) {36 using P = typename std : :iterator_traits<I> : :value_type ;37 using T = typename P : :coordinate ;38 T t = 100;39 std : :uniform_int_distribution<T> distribution(−t , t) ;40 for (I q = p ; q =6== r ; ++q) {41 T x = distribution(random_number_generator) ;42 T y = distribution(random_number_generator) ;43 ∗q = P(x , y) ;44 }45 }46

47 template<typename checker>48 void empty_set(checker f) {49 std : :cout << ”empty set\n”;50 using P = point<int> ;51 using S = std : :list<P> ;52 S input ;53 assert(f(input.begin( ) , input.end( ))) ;54 }55

56 template<typename checker>57 void one_point(checker f) {58 std : :cout << ”one point\n”;59 using P = point<int> ;60 using S = std : :list<P> ;61 S input ;62 P origo ;63 input.push_back(origo) ;64 assert(f(input.begin( ) , input.end( ))) ;65 }66

67 template<typename checker>68 void two_points(checker f) {69 std : :cout << ”two points\n”;70 using P = point<int> ;71 using S = std : :list<P> ;72 S input ;73 P origo ;74 P another(1 , 1) ;75 input.push_back(origo) ;76 input.push_back(another) ;77 assert(f(input.begin( ) , input.end( ))) ;78 }

Page 87: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

87

79

80 template<typename checker>81 void three_points_on_a_vertical_line(checker f) {82 std : :cout << ”three points on a vertical line\n”;83 using P = point<int> ;84 P origo ;85 P st(0 , 1) ;86 P nd(0 , 2) ;87 using S = std : :list<P> ;88 S input ;89 input.push_back(origo) ;90 input.push_back(st) ;91 input.push_back(nd) ;92 assert(f(input.begin( ) , input.end( ))) ;93 }94

95 template<typename checker>96 void three_points_on_a_horizontal_line(checker f) {97 std : :cout << ”three points on a horizontal line\n”;98 using P = point<int> ;99 P origo ;

100 P up(1 , 0) ;101 P top(2 , 0) ;102 using S = std : :list<P> ;103 S input ;104 input.push_back(origo) ;105 input.push_back(up) ;106 input.push_back(top) ;107 assert(f(input.begin( ) , input.end( ))) ;108 }109

110 template<typename checker>111 void ten_equal_points(checker f) {112 std : :cout << ”ten equal points\n”;113 using P = point<int> ;114 P p(1 , 1) ;115 using S = std : :list<P> ;116 S input ;117 for (std : :size_t i = 0; i =6== 10; ++i) {118 input.push_back(p) ;119 }120 assert(f(input.begin( ) , input.end( ))) ;121 }122

123 template<typename checker>124 void four_poles_and_many_duplicates_inside(checker f) {125 std : :cout << ”four poles and many duplicates inside\n”;126 using P = point<int> ;127 using S = std : :list<P> ;128 std : :size_t n = 10;129 P origin(0 , 0) ;130 P west(−1, 0) ;

Page 88: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

88

131 P north(0 , 1) ;132 P east(1 , 0) ;133 P south(0 , −1) ;134 S input ;135 input.push_back(west) ;136 input.push_back(north) ;137 input.push_back(east) ;138 input.push_back(south) ;139 for (std : :size_t i = 0; i =6== n ; ++i) {140 input.push_back(origin) ;141 }142 assert(f(input.begin( ) , input.end( ))) ;143 }144

145 template<typename checker>146 void four_poles_with_duplicates(checker f) {147 std : :cout << ”four poles with duplicates\n”;148 using P = point<int> ;149 P west(−1, 0) ;150 P north(0 , 1) ;151 P east(1 , 0) ;152 P south(0 , −1) ;153 using S = std : :list<P> ;154 S input ;155 for (std : :size_t i = 0; i < 5; ++i) {156 input.push_back(south) ;157 input.push_back(north) ;158 input.push_back(west) ;159 input.push_back(east) ;160 }161 assert(f(input.begin( ) , input.end( ))) ;162 }163

164 template<typename checker>165 void quadrilateral_with_duplicates(checker f) {166 std : :cout << ”quadrilateral with duplicates\n”;167 using P = point<int> ;168 P bottom_left(0 , 0) ;169 P top_left(1 , 1) ;170 P bottom_right(4 , 0) ;171 P top_right(3 , 1) ;172 using S = std : :list<P> ;173 S input ;174 for (std : :size_t i = 0; i < 5; ++i) {175 input.push_back(bottom_left) ;176 input.push_back(top_left) ;177 input.push_back(bottom_right) ;178 input.push_back(top_right) ;179 }180 assert(f(input.begin( ) , input.end( ))) ;181 }182

Page 89: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

89

183 template<typename checker>184 void duplicates_on_the_periphery(checker f) {185 std : :cout << ”duplicates on the periphery\n”;186 using P = point<int> ;187 using S = std : :list<P> ;188 S input ;189 for (std : :size_t i = 0; i < 2; ++i) {190 input.push_back(P(0 , 0)) ;191 input.push_back(P(1 , 1)) ;192 input.push_back(P(2 , 2)) ;193 input.push_back(P(3 , 2)) ;194 input.push_back(P(3 , 0)) ;195 input.push_back(P(4 , 2)) ;196 input.push_back(P(4 , 0)) ;197 input.push_back(P(5 , 2)) ;198 input.push_back(P(5 , 0)) ;199 input.push_back(P(6 , 2)) ;200 input.push_back(P(6 , 0)) ;201 input.push_back(P(7 , 1)) ;202 input.push_back(P(8 , 0)) ;203 }204 assert(f(input.begin( ) , input.end( ))) ;205 }206

207 template<typename checker>208 void many_east_pole_candidates(checker f) {209 std : :cout << ”many east−pole candidates\n”;210 using P = point<int> ;211 P west(0 , 0) ;212 P east(1 , 4) ;213 P three(1 , 3) ;214 P two(1 , 2) ;215 P one(1 , 1) ;216 P zero(1 , 0) ;217 using S = std : :list<P> ;218 S input ;219 for (std : :size_t i = 0; i < 5; ++i) {220 input.push_back(west) ;221 input.push_back(east) ;222 input.push_back(three) ;223 input.push_back(two) ;224 input.push_back(zero) ;225 input.push_back(one) ;226 }227 assert(f(input.begin( ) , input.end( ))) ;228 }229

230 template<typename checker>231 void line_quadrilateral_line(checker f) {232 std : :cout << ”line quadrilateral line\n”;233 using P = point<int> ;234 using S = std : :list<P> ;

Page 90: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

90

235 S input ;236 input.push_back(P(0 , 0)) ;237 input.push_back(P(1 , 0)) ;238 input.push_back(P(2 , 0)) ;239 input.push_back(P(2 , 0)) ;240 input.push_back(P(3 , 0)) ;241

242 input.push_back(P(4 , 1)) ;243 input.push_back(P(5 , 2)) ;244 input.push_back(P(6 , 3)) ;245 input.push_back(P(6 , 3)) ;246 input.push_back(P(7 , 2)) ;247 input.push_back(P(8 , 1)) ;248

249 input.push_back(P(4 , −1)) ;250 input.push_back(P(5 , −2)) ;251 input.push_back(P(6 , −3)) ;252 input.push_back(P(6 , −3)) ;253 input.push_back(P(7 , −2)) ;254 input.push_back(P(8 , −1)) ;255

256 input.push_back(P(9 , 0)) ;257 input.push_back(P(10, 0)) ;258 input.push_back(P(11, 0)) ;259 input.push_back(P(12, 0)) ;260 assert(f(input.begin( ) , input.end( ))) ;261 }262

263 template<typename checker>264 void many_big_numbers(checker f) {265 std : :cout << ”many big numbers\n”;266 using T = int ;267 using P = point<int> ;268 T max = std : :numeric_limits<T> : :max( ) ;269 P origo(0 , 0) ;270 P left_bottom(−max, −max) ;271 P just_above(−max, −max + 1) ;272 P right_top(max, max) ;273 P left_top(−max, max) ;274 P neighbour_below(−max, max − 1) ;275 P neighbour_beside(−max − 1, max) ;276 using S = std : :list<P> ;277 S input ;278 input.push_back(left_bottom) ;279 input.push_back(just_above) ;280 input.push_back(origo) ;281 input.push_back(left_top) ;282 input.push_back(right_top) ;283 input.push_back(neighbour_below) ;284 input.push_back(neighbour_beside) ;285 assert(f(input.begin( ) , input.end( ))) ;286 }

Page 91: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

91

287

288 template<typename checker>289 void noisy_box(checker f) {290 std : :cout << ”noisy box\n”;291 using T = int ;292 using P = point<T> ;293 T max = std : :numeric_limits<T> : :max( ) ;294 using S = std : :list<P> ;295 using I = typename S : :iterator ;296 constexpr std : :size_t n = 10;297 S input(n) ;298 std : :uniform_int_distribution<T> distribution(−max + 1, max − 1) ;299 for (I q = input.begin( ) ; q =6== input.end( ) ; ++q) {300 T x = distribution(random_number_generator) ;301 T y = distribution(random_number_generator) ;302 ∗q = P(x , y) ;303 }304 input.push_back(P(max, max)) ;305 input.push_back(P(max, −max)) ;306 input.push_back(P(−max, −max)) ;307 input.push_back(P(−max, max)) ;308 assert(f(input.begin( ) , input.end( ))) ;309 }310

311 template<typename checker>312 void random_points_on_a_parabola(checker f) {313 std : :cout << ”random points on a parabola\n”;314 using P = point<int> ;315 using T = std : :vector<P> ;316 using I = typename T : :iterator ;317 std : :size_t const n = 4;318 T temporary(n) ;319 int j = 0;320 for (I q = temporary.begin( ) ; q =6== temporary.end( ) ; ++q) {321 ∗q = P(j , j ∗ j) ;322 ++j ;323 }324 std : :shuffle(temporary.begin( ) , temporary.end( ) , random_number_generator) ;325 using S = std : :list<P> ;326 S input ;327 for (I q = temporary.begin( ) ; q =6== temporary.end( ) ; ++q) {328 input.push_back(∗q) ;329 }330 assert(f(input.begin( ) , input.end( ))) ;331 }332

333 template<typename checker>334 void random_points_in_a_square(checker f) {335 std : :cout << ”random points in a square\n”;336 std : :size_t const bign = 10000;337 for (std : :size_t n = 0; n ≤ bign ; ++n) {338 i f (n % 100 == 0) {

Page 92: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

92

339 std : :cout << ”.” << std : :flush ;340 }341 using P = point<int> ;342 using S = std : :list<P> ;343 S input(n) ;344 generate(input.begin( ) , input.end( )) ;345 assert(f(input.begin( ) , input.end( ))) ;346 }347 std : :cout << ”\n” << std : :flush ;348 }349

350 template<typename checker>351 void positive_overflow(checker f) {352 std : :cout << ”positive overflow\n”;353 using T = int ;354 using P = point<T> ;355 T max = std : :numeric_limits<T> : :max( ) ;356 P origo(100, 100) ;357 P left_top(100, max) ;358 P right_top(max, max) ;359 P middle(100000, 100000) ;360 P right_bottom(max, 100) ;361 using S = std : :list<P> ;362 S input ;363 input.push_back(left_top) ;364 input.push_back(right_bottom) ;365 input.push_back(origo) ;366 input.push_back(middle) ;367 input.push_back(right_top) ;368 assert(f(input.begin( ) , input.end( ))) ;369 }370

371 template<typename checker>372 void negative_overflow(checker f) {373 std : :cout << ”negative overflow\n”;374 using T = int ;375 using P = point<T> ;376 T min = std : :numeric_limits<T> : :min( ) ;377 P origo ;378 P left_top(min, 0) ;379 P left_bottom(min, min) ;380 P right_bottom(0 , min) ;381 P middle(−10000, −10000) ;382 using S = std : :list<P> ;383 S input ;384 input.push_back(left_top) ;385 input.push_back(right_bottom) ;386 input.push_back(origo) ;387 input.push_back(middle) ;388 input.push_back(left_bottom) ;389 assert(f(input.begin( ) , input.end( ))) ;390 }

Page 93: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

93

391

392 template<typename checker>393 void corners_of_the_universe(checker f) {394 std : :cout << ”corners of the universe\n”;395 using T = int ;396 using P = point<T> ;397 T min = std : :numeric_limits<T> : :min( ) ;398 T max = std : :numeric_limits<T> : :max( ) ;399 P origo ;400 P left_top(min, max) ;401 P left_bottom(min, min) ;402 P right_top(max, max) ;403 P right_bottom(max, min) ;404 using S = std : :list<P> ;405 S input ;406 input.push_back(left_top) ;407 input.push_back(right_bottom) ;408 input.push_back(origo) ;409 input.push_back(right_top) ;410 input.push_back(left_bottom) ;411 assert(f(input.begin( ) , input.end( ))) ;412 }413

414 template<typename checker>415 void negative_coordinates(checker f) {416 std : :cout << ”negative coordinates\n”;417 using P = point<int> ;418 P p1(−3, −3) ;419 P p2(−3, −2) ;420 P p3(0 , 0) ;421 P p4(1 , −1) ;422 using S = std : :list<P> ;423 S input ;424 input.push_back(p1) ;425 input.push_back(p2) ;426 input.push_back(p3) ;427 input.push_back(p4) ;428 assert(f(input.begin( ) , input.end( ))) ;429 }430

431 template<typename checker>432 void degenerate_coordinates(checker f) {433 std : :cout << ”degenerate coordinates\n”;434 using P = point<int> ;435 P p1(0 , 0) ;436 P p2(1 , 0) ;437 P p3(2 , 0) ;438 P p4(3 , 0) ;439 P p5(3 , 1) ;440 P p6(3 , 2) ;441 P p7(3 , 3) ;442 P p8(2 , 3) ;

Page 94: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

94

443 P p9(1 , 3) ;444 P p10(0 , 3) ;445 using S = std : :list<P> ;446 S input ;447 input.push_back(p1) ;448 input.push_back(p2) ;449 input.push_back(p3) ;450 input.push_back(p4) ;451 input.push_back(p5) ;452 input.push_back(p6) ;453 input.push_back(p7) ;454 input.push_back(p8) ;455 input.push_back(p9) ;456 input.push_back(p10) ;457 assert(f(input.begin( ) , input.end( ))) ;458 }459

460 int main( ) {461 using P = point<int> ;462 using S = std : :list<P> ;463 using I = typename S : :iterator ;464 using R = checker<I> ;465 using T = testcase<R> ;466

467 T suite[ ] = {468 empty_set,469 one_point,470 two_points,471 three_points_on_a_vertical_line,472 three_points_on_a_horizontal_line,473 ten_equal_points,474 four_poles_and_many_duplicates_inside,475 four_poles_with_duplicates,476 quadrilateral_with_duplicates,477 duplicates_on_the_periphery,478 many_east_pole_candidates,479 line_quadrilateral_line,480 many_big_numbers,481 noisy_box,482 random_points_on_a_parabola,483 random_points_in_a_square,484 positive_overflow,485 negative_overflow,486 corners_of_the_universe,487 negative_coordinates,488 degenerate_coordinates489 };490

491 R program = NAME : :check ;492 for (T test : suite) {493 try {494 test(program) ;

Page 95: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

95

495 }496 catch(std : :exception& e) {497 std : :cerr << e.what( ) << std : :endl ;498 }499 }500 return 0;501 }

E.3 driver.c++

1 /∗2 Performance Engineering Laboratory © 2017−−20193 ∗/4

5 unsigned long maxsize = 128 ∗ 1024 ∗ 1024; // 32 for PARABOLA6 // 1 << 30 = 1073741824 there is space , but things become very slow7

8 #if defined(MEASURE_TURNS)9

10 long long turns = 0;11

12 #endif13

14 #if defined(MEASURE_COMPS) or defined(MEASURE_MOVES)15

16 long long comps = 0;17 long long moves = 0;18

19 #endif20

21 #if defined(PRUNING)22

23 long long pruning_efficiency = 0;24

25 #endif26

27 #include <iostream> // std : : cout std : : cerr28

29 #include <cassert> // assert macro30 #include <cstdlib> // std : : atoi std : : s ize t31 #include <cmath> // std : : sqrt32 #include ”cphstl/integers .h++” // cphstl integers33 #include <ctime> // std : : clock t std : : clock CLOCKSPERSEC34 #include <iterator> // std : : iterator traits std : : distance35 #include <limits> // std : : numeric limits36 #include <random> // std : : linear congruential engine37

38 #include ”algorithm.h++” // NAME: : solve39 #include ”point .h++” // point40

41 using linear_congruential_engine = std : :linear_congruential_engine<

Page 96: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

96

42 unsigned long long, 6364136223846793005U , 1442695040888963407U , 0U> ;43 constexpr unsigned long long seed = 10164167376618180197U ;44 linear_congruential_engine random_number_generator{seed};45

46 #if defined(DISC)47

48 template<typename I>49 void generate(I p , I r) {50 using P = typename std : :iterator_traits<I> : :value_type ;51 using T = typename P : :coordinate ;52 T t = std : :numeric_limits<T> : :max( ) ;53 std : :uniform_int_distribution<T> distribution(−t , t) ;54 for (I q = p ; q =6== r ; ++q) {55 T x = 0;56 T y = 0;57 using R = double;58 R radius = R(t) ;59 R root = 0. 0;60 do {61 x = distribution(random_number_generator) ;62 y = distribution(random_number_generator) ;63 R dx = R(x) ∗ R(x) ;64 R dy = R(y) ∗ R(y) ;65 root = std : :sqrt(dx + dy) ;66 } while (root > radius) ;67 ∗q = P(x , y) ;68 }69 }70

71 #elif defined(UNIVERSE)72

73 template<typename I>74 void generate(I p , I r) {75 std : :size_t n = r − p ;76 using P = typename std : :iterator_traits<I> : :value_type ;77 using T = typename P : :coordinate ;78 T t = std : :sqrt(n) ;79 std : :uniform_int_distribution<T> distribution(−t , +t) ;80 for (I q = p ; q =6== r ; ++q) {81 T x = distribution(random_number_generator) ;82 T y = distribution(random_number_generator) ;83 ∗q = P(x , y) ;84 }85 }86

87 #elif defined(SPECIAL)88

89 template<typename I>90 void generate(I p , I r) {91 assert(std : :distance(p , r) ≥ 4) ;92 using P = typename std : :iterator_traits<I> : :value_type ;93 P origin(0 , 0) ;

Page 97: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

97

94 P west(−1, 0) ;95 P north(0 , 1) ;96 P east(1 , 0) ;97 P south(0 , −1) ;98 ∗p = west ;99 ++p ;

100 ∗p = north ;101 ++p ;102 ∗p = east ;103 ++p ;104 ∗p = south ;105 ++p ;106 for (I q = p ; q =6== r ; ++q) {107 ∗q = origin ;108 }109 }110

111 #elif defined(LINE)112

113 template<typename I>114 void generate(I p , I r) {115 using P = typename std : :iterator_traits<I> : :value_type ;116 using T = typename P : :coordinate ;117 T t = std : :numeric_limits<T> : :max( ) ;118 std : :uniform_int_distribution<T> distribution(−t , t) ;119 for (I q = p ; q =6== r ; ++q) {120 T x = distribution(random_number_generator) ;121 ∗q = P(x , x) ;122 }123 }124

125 #elif defined(PARABOLA)126

127 template<typename I>128 void generate(I p , I r) {129 using P = typename std : :iterator_traits<I> : :value_type ;130 using T = int ; // typename P: : coordinate ;131 T t = 1 << 15;132 std : :uniform_int_distribution<T> distribution(−t , t) ;133 for (I q = p ; q =6== r ; ++q) {134 T x = distribution(random_number_generator) ;135 ∗q = P(x , x ∗ x) ;136 }137 }138

139 #elif defined(SORTED)140

141 template<typename I>142 void generate(I p , I r) {143 using P = typename std : :iterator_traits<I> : :value_type ;144 using T = int ;145 T min = std : :numeric_limits<T> : :min( ) ;

Page 98: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

98

146 T max = std : :numeric_limits<T> : :max( ) ;147 std : :uniform_int_distribution<T> distribution(min, max) ;148 for (I q = p ; q =6== r ; ++q) {149 T x = distribution(random_number_generator) ;150 T y = distribution(random_number_generator) ;151 ∗q = P(x , y) ;152 }153 std : :sort(p , r ,154 [ ](P const& p , P const& q) → bool {155 return p.x < q.x ;156 }) ;157 }158

159 #elif defined(BELL)160

161 template<typename I>162 void generate(I p , I r) {163 using P = typename std : :iterator_traits<I> : :value_type ;164 using T = typename P : :coordinate ;165 using D = typename std : :iterator_traits<I> : :difference_type ;166 D n = std : :distance(p , r) ;167 using R = double;168 R radius = R(std : :numeric_limits<T> : :max( )) ;169 R mean = 0. 0;170 R stddev = radius / (2 + std : :log(n)) ;171 std : :normal_distribution<R> distribution(mean, stddev) ;172 for (I q = p ; q =6== r ; ++q) {173 T x = std : :round(distribution(random_number_generator)) ;174 T y = std : :round(distribution(random_number_generator)) ;175 ∗q = P(x , y) ;176 }177 }178

179 #else // default SQUARE180

181 template<typename I>182 void generate(I p , I r) {183 using P = typename std : :iterator_traits<I> : :value_type ;184 using T = int ; // typename P: : coordinate ;185 T min = std : :numeric_limits<T> : :min( ) ;186 T max = std : :numeric_limits<T> : :max( ) ;187 std : :uniform_int_distribution<T> distribution(min, max) ;188 for (I q = p ; q =6== r ; ++q) {189 T x = distribution(random_number_generator) ;190 T y = distribution(random_number_generator) ;191 ∗q = P(x , y) ;192 }193 }194

195 #endif196

197 void usage(char const∗ program) {

Page 99: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

99

198 std : :cerr << ”Usage: ” << program << ” <n>\n”;199 exit(1) ;200 }201

202 #if defined(MEASURE_COMPS) or defined(MEASURE_MOVES)203

204 template<typename T>205 class counter {206 private :207

208 T datum ;209

210 public :211

212 static constexpr bool is_signed = true ;213 static constexpr bool is_integer = true ;214 static constexpr bool is_exact = true ;215 static constexpr bool is_bounded = true ;216 static constexpr bool is_modulo = not is_signed ;217 static constexpr std : :size_t radix = 2;218 static constexpr std : :size_t length = 1;219 static constexpr std : :size_t width = 8 ∗ sizeof(T) ;220 static constexpr T min = std : :numeric_limits<T> : :min( ) ;221 static constexpr T max = std : :numeric_limits<T> : :max( ) ;222

223 explicit counter( )224 : datum(0) {225 moves += 1;226 }227

228 counter(int x)229 : datum(x) {230 moves += 1;231 }232

233 counter(counter const& other) :234 datum(other.datum) {235 moves += 1;236 }237

238 template<typename number>239 explicit counter(number x = 0)240 : datum(x) {241 moves += 1;242 }243

244 counter(counter&& other) {245 datum = std : :move(other.datum) ;246 moves += 1;247 }248

249 counter& operator=(counter const& other) {

Page 100: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

100

250 datum = other.datum ;251 moves += 1;252 return ∗this ;253 }254

255 counter& operator=(counter&& other) {256 datum = std : :move(other.datum) ;257 moves += 1;258 return ∗this ;259 }260

261 operator T( ) const {262 return datum ;263 }264

265 template<unsigned long int b>266 requires b ≥ width267 operator cphstl : :Z<b>( ) const {268 return cphstl : :Z<b>(datum) ;269 }270

271 template<typename U>272 friend bool operator==(counter<U> const& , counter<U> const&) ;273

274 template<typename U>275 friend bool operator=6== (counter<U> const& , counter<U> const&) ;276

277 template<typename U>278 friend bool operator<(counter<U> const& , counter<U> const&) ;279

280 template<typename U>281 friend bool operator>(counter<U> const& , counter<U> const&) ;282

283 template<typename U>284 friend bool operator≤(counter<U> const& , counter<U> const&) ;285

286 template<typename U>287 friend bool operator≥(counter<U> const& , counter<U> const&) ;288 };289

290 template<typename T>291 bool operator==(counter<T> const& x , counter<T> const& y) {292 ++comps ;293 return x.datum == y.datum ;294 }295

296 template<typename T>297 bool operator=6== (counter<T> const& x , counter<T> const& y) {298 ++comps ;299 return x.datum =6== y.datum ;300 }301

Page 101: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

101

302 template<typename T>303 bool operator<(counter<T> const& x , counter<T> const& y) {304 ++comps ;305 return x.datum < y.datum ;306 }307

308 template<typename T>309 bool operator>(counter<T> const& x , counter<T> const& y) {310 ++comps ;311 return x.datum > y.datum ;312 }313

314 template<typename T>315 bool operator≤(counter<T> const& x , counter<T> const& y) {316 ++comps ;317 return x.datum ≤ y.datum ;318 }319

320 template<typename T>321 bool operator≥(counter<T> const& x , counter<T> const& y) {322 ++comps ;323 return x.datum ≥ y.datum ;324 }325

326 #endif327

328 int main(int argc, char∗∗ argv) {329 unsigned long n = 15;330 i f (argc == 2) {331 n = std : :atoi(argv [1 ] ) ;332 }333 else {334 usage(argv [0 ] ) ;335 }336

337 unsigned long repetitions = maxsize / n ;338 i f (n > maxsize) {339 repetitions = 1;340 maxsize = repetitions ∗ n ;341 }342

343 #if defined(MEASURE_MOVES) or defined(MEASURE_COMPS)344

345 using P = point<counter<int>>;346

347 #else348

349 using P = point<int> ;350

351 #endif352

353 using I = P∗;

Page 102: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

102

354 I a = new P [maxsize ] ;355 I b = a ;356 for (volatile unsigned long t = 0; t =6== repetitions ; ++t) {357 generate(b , b + n) ;358 b = b + n ;359 }360

361 b = a ;362

363 #if defined(MEASURE_ARITHMETIC)364

365 constructions = 0;366 comparisons = 0;367 additions = 0;368 subtractions = 0;369 multiplications = 0;370

371 #elif defined(MEASURE_TURNS)372

373 turns = 0;374

375 #elif defined(MEASURE_MOVES)376

377 moves = 0;378

379 #elif defined(MEASURE_COMPS)380

381 comps = 0;382

383 #elif defined(PRUNING)384

385 pruning_efficiency = 0;386

387 #else388

389 std : :clock_t start = std : :clock( ) ;390

391 #endif392

393 for (volatile unsigned long t = 0; t =6== repetitions ; ++t) {394 (void) NAME : :solve(&b [0 ] , &b [n ] ) ;395 b = b + n ;396 }397

398 #if defined(MEASURE_ARITHMETIC)399

400 double t = double(repetitions) ∗ double(n) ;401 std : :cout.precision(3) ;402 std : :cout << n << ”\n”;403 std : :cout << ” structors ” << double(constructions) / t << ”\n”;404 std : :cout << ” < ” << double(comparisons) / t << ”\n”;405 std : :cout << ” + ” << double(additions) / t << ”\n”;

Page 103: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

103

406 std : :cout << ” − ” << double(subtractions) / t << ”\n”;407 std : :cout << ” ∗ ” << double(multiplications) / t << ”\n”;408

409 #elif defined(MEASURE_TURNS)410

411 double t = double(repetitions) ∗ double(n) ;412 std : :cout.precision(3) ;413 std : :cout << n << ”\t” << double(turns) / t << ”\n”;414

415 #elif defined(MEASURE_MOVES)416

417 double t = double(repetitions) ∗ double(n) ;418 std : :cout.precision(3) ;419 std : :cout << n << ”\t” << double(moves) / t << ”\n”;420

421 #elif defined(MEASURE_COMPS)422

423 double t = double(repetitions) ∗ double(n) ;424 std : :cout.precision(3) ;425 std : :cout << n << ”\t” << double(comps) / t << ”\n”;426

427 #elif defined(PRUNING)428

429 double t = double(repetitions) ∗ double(n) ;430 std : :cout.precision(3) ;431 std : :cout << n << ”\tpruning : ” << double(pruning_efficiency) ∗ 100.0 / t << ”\n”;432

433 #else434

435 std : :clock_t stop = std : :clock( ) ;436

437 double t = double(repetitions) ∗ double(n) ;438 double ns = 1000000000.0 ∗ double(stop − start) / double(CLOCKS_PER_SEC) ;439 std : :cout.precision(4) ;440 std : :cout << n << ”\t” << ns / t << ”\n”;441

442 #endif443

444 delete[ ] a ;445 return 0;446 }

Page 104: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

104

F. Makefile

F.1 makefile

1 CXX=g++−92 CXXFLAGS=−O3 −std=c++2a −Wall −Wextra −x c++ −fconcepts −DNDEBUG3 IFLAGS = −I$(CPHSTL)/Report/Integer/4

5 header−files:= $(wildcard *.h++)6 implementations:= $(basename $(header−files))7 square−tests:= $(addsuffix .square, $(implementations))8 disc−tests:= $(addsuffix .disc, $(implementations))9 universe−tests:= $(addsuffix .universe, $(implementations))

10 bell−tests:= $(addsuffix .bell, $(implementations))11 special−tests:= $(addsuffix .special, $(implementations))12 line−tests:= $(addsuffix .line, $(implementations))13 sorted−tests:= $(addsuffix .sorted, $(implementations))14 parabola−tests:= $(addsuffix .parabola, $(implementations))15 turn−tests:= $(addsuffix .turn, $(implementations))16 comp−tests:= $(addsuffix .comp, $(implementations))17 move−tests:= $(addsuffix .move, $(implementations))18 elimsquare−tests:= $(addsuffix .elimsquare, $(implementations))19 elimdisc−tests:= $(addsuffix .elimdisc, $(implementations))20 sanitychecks:= $(addsuffix .check, $(implementations))21 unittests:= $(addsuffix .test, $(implementations))22 benchmarks:= $(addsuffix .benchmark, $(implementations))23 eliminations:= bucketing.elimination throw_away.elimination24

25 .PHONY: all clean find pilot veryclean26

27 N = 1024 32768 1048576 33554432 536870912 # 1073741824 # 536870912 268435456 13421772828

29 $(square−tests): %.square : %.h++30 @cp $*.h++ algorithm.h++31 $(CXX) $(CXXFLAGS) $(IFLAGS) −DNAME=$* driver.c++32 @for n in $(N) ; do \33 ./a.out $$n ; \34 done; \35 rm −f algorithm.h++ ./a.out36

37 $(disc−tests): %.disc : %.h++38 @cp $*.h++ algorithm.h++39 $(CXX) $(CXXFLAGS) $(IFLAGS) −DDISC −DNAME=$* driver.c++40 @for n in $(N) ; do \41 ./a.out $$n ; \42 done; \43 rm −f algorithm.h++ ./a.out44

45 $(bell−tests): %.bell : %.h++46 @cp $*.h++ algorithm.h++47 $(CXX) $(CXXFLAGS) $(IFLAGS) −DBELL −DNAME=$* driver.c++48 @for n in $(N) ; do \49 ./a.out $$n ; \50 done; \51 rm −f algorithm.h++ ./a.out52

53 $(universe−tests): %.universe : %.h++54 @cp $*.h++ algorithm.h++55 $(CXX) $(CXXFLAGS) $(IFLAGS) −DUNIVERSE −DNAME=$* driver.c++56 @for n in $(N) ; do \57 ./a.out $$n ; \58 done; \59 rm −f algorithm.h++ ./a.out60

Page 105: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

105

61 $(special−tests): %.special : %.h++62 @cp $*.h++ algorithm.h++63 $(CXX) $(CXXFLAGS) $(IFLAGS) −DSPECIAL −DNAME=$* driver.c++64 @for n in $(N) ; do \65 ./a.out $$n ; \66 done; \67 rm −f algorithm.h++ ./a.out68

69 $(line−tests): %.line : %.h++70 @cp $*.h++ algorithm.h++71 $(CXX) $(CXXFLAGS) $(IFLAGS) −DLINE −DNAME=$* driver.c++72 @for n in $(N) ; do \73 ./a.out $$n ; \74 done; \75 rm −f algorithm.h++ ./a.out76

77 $(sorted−tests): %.sorted : %.h++78 @cp $*.h++ algorithm.h++79 $(CXX) $(CXXFLAGS) $(IFLAGS) −DSORTED −DNAME=$* driver.c++80 @for n in $(N) ; do \81 ./a.out $$n ; \82 done; \83 rm −f algorithm.h++ ./a.out84

85 $(parabola−tests): %.parabola : %.h++86 @cp $*.h++ algorithm.h++87 $(CXX) $(CXXFLAGS) $(IFLAGS) −DPARABOLA −DNAME=$* driver.c++88 @for n in $(N) ; do \89 ./a.out $$n ; \90 done; \91 rm −f algorithm.h++ ./a.out92

93 $(turn−tests): %.turn : %.h++94 @cp $*.h++ algorithm.h++95 $(CXX) $(CXXFLAGS) $(IFLAGS) −DNAME=$* −DMEASURE_TURNS driver.c++96 @for n in $(N) ; do \97 ./a.out $$n ; \98 done; \99 rm −f algorithm.h++ ./a.out

100

101 $(comp−tests): %.comp : %.h++102 @cp $*.h++ algorithm.h++103 $(CXX) $(CXXFLAGS) $(IFLAGS) −DNAME=$* −DMEASURE_COMPS driver.c++104 @for n in $(N) ; do \105 ./a.out $$n ; \106 done; \107 rm −f algorithm.h++ ./a.out108

109 $(move−tests): %.move : %.h++110 @cp $*.h++ algorithm.h++111 $(CXX) $(CXXFLAGS) $(IFLAGS) −DNAME=$* −DMEASURE_MOVES driver.c++112 @for n in $(N) ; do \113 ./a.out $$n ; \114 done; \115 rm −f algorithm.h++ ./a.out116

117 $(elimsquare−tests): %.elimsquare : %.h++118 @cp $*.h++ algorithm.h++119 $(CXX) $(CXXFLAGS) $(IFLAGS) −DPRUNING −DNAME=$* driver.c++120 @for n in $(N) ; do \121 ./a.out $$n ; \122 done; \123 rm −f algorithm.h++ ./a.out124

125 $(elimdisc−tests): %.elimdisc : %.h++

Page 106: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

106

126 @cp $*.h++ algorithm.h++127 $(CXX) $(CXXFLAGS) $(IFLAGS) −DPRUNING −DDISC −DNAME=$* driver.c++128 @for n in $(N) ; do \129 ./a.out $$n ; \130 done; \131 rm −f algorithm.h++ ./a.out132

133 $(benchmarks): %.benchmark : %.h++134 @date 2>&1 | tee −a $*.log135 # @make −i −−no−print−directory $*.turn 2>&1 | tee −a $*.log136 # @make −i −−no−print−directory $*.comp 2>&1 | tee −a $*.log137 # @make −i −−no−print−directory $*.move 2>&1 | tee −a $*.log138 @make −i −−no−print−directory $*.square 2>&1 | tee −a $*.log139 @make −i −−no−print−directory $*.disc 2>&1 | tee −a $*.log140 # @make −i −−no−print−directory $*.bell 2>&1 | tee −a $*.log141 @date 2>&1 | tee −a $*.log142

143 $(eliminations): %.elimination : %.h++144 @date 2>&1 | tee −a $*.log145 @make −i −−no−print−directory $*.elimsquare 2>&1 | tee −a $*.log146 @make −i −−no−print−directory $*.elimdisc 2>&1 | tee −a $*.log147 @date 2>&1 | tee −a $*.log148

149 Ns = 1048576150 sizes = 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576151

152 fhistogram:153 @for m in $(sizes) ; do \154 echo "m = " $$m ; \155 sed −e "s/TABLESIZE−TAG/$$m/" fhistogram.h++ >algorithm.h++ ; \156 $(CXX) $(CXXFLAGS) $(IFLAGS) −DNAME=fhistogram driver.c++ ; \157 for n in $(Ns) ; do \158 ./a.out $$n ; \159 done ; \160 done ; \161 rm −f algorithm.h++ ./a.out162

163 ihistogram:164 @for m in $(sizes) ; do \165 echo "m = " $$m ; \166 sed −e "s/TABLESIZE−TAG/$$m/" ihistogram.h++ >algorithm.h++ ; \167 $(CXX) $(CXXFLAGS) $(IFLAGS) −DNAME=ihistogram driver.c++ ; \168 for n in $(Ns) ; do \169 ./a.out $$n ; \170 done ; \171 done ; \172 rm −f algorithm.h++ ./a.out173

174 algorithms:175 @date176 @make −i −−no−print−directory sort.benchmark177 @make −i −−no−print−directory plane_sweep.benchmark178 @make −i −−no−print−directory torch.benchmark179 @make −i −−no−print−directory quickhull.benchmark180 @make −i −−no−print−directory throw_away.benchmark181 @date182

183 sea:184 @date185 @make −i −−no−print−directory plane_sweep_with_bucketsort.benchmark186 @make −i −−no−print−directory divide_and_conquer.benchmark187 @make −i −−no−print−directory quickhull.benchmark188 @make −i −−no−print−directory bucketing.benchmark189 @make −i −−no−print−directory throw_away.benchmark190 @date

Page 107: Convex-hull algorithms in C++...4 1. Introduction The problem of computing the convex hull for a multiset of points in the Euclidean plane is well studied in computational geometry

107

191

192 micros:193 @date194 @make −i −−no−print−directory multiple_precision.sorted195 @make −i −−no−print−directory double_precision.sorted196 @make −i −−no−print−directory floating_point_filter.sorted197 @make −i −−no−print−directory minmax_element.square198 @make −i −−no−print−directory partition.square199 @make −i −−no−print−directory copy.square200 @make −i −−no−print−directory sort.square201 @make −i −−no−print−directory bsort.square202 @make −i −−no−print−directory tsort.square203 @date204

205 TESTFLAGS=−O3 −std=c++2a −Wall −Wextra −x c++ −fconcepts −g −DDEBUG206

207 $(sanitychecks): %.check : %.h++208 @cp $*.h++ algorithm.h++209 $(CXX) $(TESTFLAGS) $(IFLAGS) −DNAME=$* check−driver.c++210 ./a.out211 rm −f ./a.out212

213 $(unittests): %.test : %.h++214 @cp $*.h++ algorithm.h++215 $(CXX) $(TESTFLAGS) $(IFLAGS) −DNAME=$* test−driver.c++216 ./a.out217 rm −f algorithm.h++ ./a.out218

219 # Other tools220

221 clean:222 − rm −f a.out temp algorithm.h++ 2>/dev/null223

224 veryclean: clean225 − rm −f *∼ .*∼ */*∼ 2>/dev/null226

227 find:228 find . −type f −print −exec grep $(word) {} \; | less