RandomLib  1.10
 All Classes Namespaces Files Functions Variables Typedefs Enumerator Friends Macros Pages
RandomThread.cpp
Go to the documentation of this file.
1 /**
2  * \file RandomThread.cpp
3  * \brief Example of parallelization with %RandomLib using threads
4  *
5  * Compile/link with, e.g.,\n
6  * g++ -I../include -O2 -funroll-loops -fopenmp
7  * -o RandomThread RandomThread.cpp ../src/Random.cpp\n
8  * ./RandomThread
9  *
10  * See \ref parallel, for a description of this example.
11  *
12  * Copyright (c) Charles Karney (2011) <charles@karney.com> and licensed under
13  * the MIT/X11 License. For more information, see
14  * http://randomlib.sourceforge.net/
15  **********************************************************************/
16 
17 #include <iostream>
18 #include <iomanip>
19 #include <limits>
20 #include <vector>
21 #include <string>
22 #include <sstream>
23 #include <numeric>
24 
25 #include <RandomLib/Random.hpp>
26 #if HAVE_OPENMP
27 #include <omp.h>
28 #endif
29 
30 using RandomLib::Random;
31 
32 double dotrials(Random& r, int d, long long n) {
33  // Require d > 0, n > 0
34  double w = 0;
35  for ( ; n--; ) { // Iterate n times
36  double h = 0;
37  for (int i = 1; i < d; ++i) { // Iterate d-1 times
38  double x = 2 * r.FixedS(); // x is in (-1, 1)
39  h += x * x; // cumulative radius^2
40  if (h >= 1) break; // Point can't be in sphere; bail out,
41  }
42  // If h < 1 then inside a (d-1) dimensional unit sphere at radius
43  // sqrt(h), so extent of last dimension is +/- sqrt(1 -h)
44  w += h < 1 ? sqrt(1 - h) : 0;
45  }
46  return w;
47 }
48 
49 double result(int d, long long n, double w) {
50  // Volume of (d-1) dimensional box = 2^(d-1).
51  // Multiply by another 2 to account for +/- extent in last dimension.
52  return double(1U << d) * w / double(n);
53 }
54 
55 int usage(const std::string& name, int retval) {
56  ( retval == 0 ? std::cout : std::cerr )
57  << "Usage: \n" << name
58  << " [-d dim] [-n nsamp] [-k ntask] [-l stride] [-s seed] [-h]\n"
59  << "Estimate volume of n-dimensional unit sphere\n";
60  return retval;
61 }
62 
63 int main(int argc, char* argv[]) {
64  int d = 4; // Number of dimensions
65  long long n = 10000000; // Number of trials 10^7
66  int k = 100; // Number of tasks
67  int l = 4; // The leapfrogging stride
68  std::string seedstr;
69  bool seedgiven = false;
70 
71  for (int m = 1; m < argc; ++m) {
72  std::string arg(argv[m]);
73  if (arg == "-d") {
74  if (++m == argc) return usage(argv[0], true);
75  std::istringstream str(argv[m]);
76  char c;
77  if (!(str >> d) || (str >> c) || d <= 0) {
78  std::cerr << "Number of dimensions " << argv[m]
79  << " is not a positive number\n";
80  return 1;
81  }
82  } else if (arg == "-n") {
83  if (++m == argc) return usage(argv[0], true);
84  std::istringstream str(argv[m]);
85  char c;
86  double fn;
87  if (!(str >> fn) || (str >> c) || fn < 1 ||
88  fn > double(std::numeric_limits<long long>::max())) {
89  std::cerr << "Total count " << argv[m] << " is not a positive number\n";
90  return 1;
91  }
92  n = (long long)(fn);
93  } else if (arg == "-k") {
94  if (++m == argc) return usage(argv[0], true);
95  std::istringstream str(argv[m]);
96  char c;
97  if (!(str >> k) || (str >> c) || k <= 0) {
98  std::cerr << "Number of tasks " << argv[m]
99  << " is not a positive number\n";
100  return 1;
101  }
102  } else if (arg == "-l") {
103  if (++m == argc) return usage(argv[0], true);
104  std::istringstream str(argv[m]);
105  char c;
106  if (!(str >> l) || (str >> c) || l <= 0) {
107  std::cerr << "Leapfrog stride " << argv[m]
108  << " is not a positive number\n";
109  return 1;
110  }
111  } else if (arg == "-s") {
112  seedgiven = true;
113  if (++m == argc) return usage(argv[0], 1);
114  seedstr = std::string(argv[m]);
115  } else
116  return usage(argv[0], arg != "-h");
117  }
118 
119  std::vector<unsigned long> master_seed =
120  seedgiven ? Random::StringToVector(seedstr) : Random::SeedVector();
121 
122  std::cout << "Estimate volume of a " << d
123  << "-dimensional sphere;\nsamples = -n " << n
124  << "; tasks = -k " << k
125  << "; leapfrog stride = -l " << l << ";\nusing " << Random::Name()
126  << "\nwith master seed = -s "
127  << Random::VectorToString(master_seed) << ".\n";
128  std::cout << "Estimated volume = "
129  << std::fixed << std::setprecision(8) << std::flush;
130 
131  // Reserve room for a task id at the end of the seed
132  master_seed.push_back(0);
133  // Fill weight vector with NaNs to verify that all tasks have completed
134  std::vector<double> w(k, std::numeric_limits<double>::quiet_NaN());
135 
136 #if HAVE_OPENMP
137 #pragma omp parallel for
138 #endif
139  for (int i = 0; i < k; ++i) { // the main loop over tasks
140  Random r; // task specific Random
141  {
142  std::vector<unsigned long> seed(master_seed); // task specific seed
143  seed.back() = i / l; // include task id in seed
144  r.Reseed(seed);
145  // Turn on leapfrogging with an offset that depends on the task id
146  r.SetStride(l, i % l);
147  }
148  // Do the work; last argument splits n exactly into k pieces
149  w[i] = dotrials(r, d, (n * (i + 1))/k - (n * i)/k);
150  }
151  // Sum up the weights from the individual tasks
152  double weight = accumulate(w.begin(), w.end(), 0.0);
153  // Compute the result
154  std::cout << result(d, n, weight) << "\n";
155 
156  return 0;
157 }
double result(int d, long long n, double w)
Header for Random, RandomGenerator.
int main(int argc, char *argv[])
int usage(const std::string &name, int retval)
RandomCanonical< RandomGenerator > Random
Definition: Random.hpp:135
double dotrials(Random &r, int d, long long n)