Loading [MathJax]/extensions/tex2jax.js
Parallel numerical verification of the σ_odd problem  October 6, 2018
All Classes Namespaces Files Functions Variables Typedefs Macros
threads.cpp
Go to the documentation of this file.
1 /* -*- coding: latin-1 -*- */
2 /** \file threads/threads/threads.cpp (January 6, 2018)
3  *
4  * GPLv3 --- Copyright (C) 2017, 2018 Olivier Pirson
5  * http://www.opimedia.be/
6  */
7 
8 // \cond
9 #include <cassert>
10 
11 #include <algorithm>
12 #include <thread>
13 // \endcond
14 
15 #include "../../sequential/sequential/sequential.hpp"
16 
17 #include "threads.hpp"
18 
19 
20 namespace threads {
21 
22  /* ***********
23  * Functions *
24  *************/
25 
26  std::set<nat_type>
28  nat_type first_n, nat_type last_n,
29  const std::set<nat_type> &previous_bad_table,
30  bool print_bad,
31  unsigned int range_size) {
32  assert(nb_thread >= 1);
33  assert(sigmaodd::is_odd(first_n));
34  assert(3 <= first_n);
35  assert(first_n <= last_n);
36  assert(last_n <= sigmaodd::MAX_POSSIBLE_N);
37  assert(sigmaodd::is_even(range_size));
38 #ifdef PRIME16
39  assert(n < 65536);
40 #endif
41 
42  const nat_type bad_first_n = (previous_bad_table.empty()
43  ? first_n
44  : 0);
45 
46  std::set<nat_type> bad_table(previous_bad_table);
47 
48  std::set<nat_type>* new_bad_tables = new std::set<nat_type>[nb_thread](); // empty-initialized
49  std::thread* threads = new std::thread[nb_thread]; // threads[0] never used
50 
51  for (nat_type n = first_n; n <= last_n; ) {
52  const nat_type bad_last_n = n - 1;
53 
54  // Start each slave thread on a range
55  const nat_type master_n = n;
56  unsigned int nb_slave_required = 0;
57 
58  n += range_size; // reserve range for master thread
59 
60  for (unsigned int i = 1; (i < nb_thread) && (n <= last_n); ++i, n += range_size) {
61  ++nb_slave_required;
62  threads[i] = std::thread
63  ([bad_first_n, bad_last_n, i, last_n, n, range_size,
64  &bad_table, &new_bad_tables] {
65  new_bad_tables[i]
67  (n, std::min(n + range_size - 1, last_n),
68  bad_table,
69  bad_first_n, bad_last_n,
70  false);
71  });
72  }
73 
74  // Run on master thread
75  new_bad_tables[0]
77  (master_n, std::min(master_n + range_size - 1, last_n),
78  bad_table,
79  bad_first_n, bad_last_n,
80  false);
81 
82  // Wait end of each slave thread
83  for (unsigned int i = 1; i <= nb_slave_required; ++i) {
84  threads[i].join();
85  }
86 
87  // Update bad_table
88  for (unsigned int i = 0; i < nb_thread; ++i) {
89  if (!new_bad_tables[i].empty()) { // new bad numbers identified
90  bad_table.insert(new_bad_tables[i].cbegin(), new_bad_tables[i].cend());
91  if (print_bad) {
92  sequential::sequential_print_in_order(new_bad_tables[i]);
93  }
94  new_bad_tables[i].clear();
95  }
96  }
97  }
98 
99  delete[] new_bad_tables;
100  delete[] threads;
101 
102  return bad_table;
103  }
104 
105 
106  std::set<nat_type>
108  nat_type first_n, nat_type last_n,
109  const std::set<nat_type> &previous_bad_table,
110  bool print_bad,
111  unsigned int range_size,
112  unsigned int master_range_size) {
113  assert(nb_thread >= 1);
114  assert(sigmaodd::is_odd(first_n));
115  assert(3 <= first_n);
116  assert(first_n <= last_n);
117  assert(last_n <= sigmaodd::MAX_POSSIBLE_N);
118  assert(sigmaodd::is_even(range_size));
119  assert(sigmaodd::is_even(master_range_size));
120 #ifdef PRIME16
121  assert(n < 65536);
122 #endif
123 
124  const nat_type bad_first_n = (previous_bad_table.empty()
125  ? first_n
126  : 0);
127 
128  std::set<nat_type> bad_table(previous_bad_table);
129 
130  nat_type* first_ns = new nat_type[nb_thread];
131  std::set<nat_type>* new_bad_tables = new std::set<nat_type>[nb_thread](); // empty-initialized
132 
133  std::set<nat_type>* current_bad_tables = new std::set<nat_type>[nb_thread](); // current_bad_tables[0] never used
134  bool* is_finisheds = new bool[nb_thread]; // is_finisheds[0] never used
135  std::thread* threads = new std::thread[nb_thread]; // threads[0] never used
136 
137  // Starts empty slave threads to simplify following code (all slave threads are used)
138  for (unsigned int i = 1; i < nb_thread; ++i) {
139  threads[i] = std::thread([] {});
140  is_finisheds[i] = true;
141  first_ns[i] = first_n;
142  }
143 
144  for (nat_type n = first_n; n <= last_n; ) {
145  // Start each slave thread on a range
146  first_ns[0] = n;
147 
148  // Update the last known possible bad number
149  nat_type bad_last_n = sequential::sequential_min_array(first_ns, nb_thread) - 1;
150 
151  n += master_range_size; // reserve range for master thread
152 
153  for (unsigned int i = 1; (i < nb_thread) && (n <= last_n); ++i) {
154  if (is_finisheds[i]) { // if slave thread i is free
155  is_finisheds[i] = false;
156  first_ns[i] = n;
157 
158  // Update the last known possible bad number
159  bad_last_n = sequential::sequential_min_array(first_ns, nb_thread) - 1;
160 
161  // Update bad_table
162  bad_table.insert(new_bad_tables[i].cbegin(), new_bad_tables[i].cend());
163  if (print_bad) {
164  sequential::sequential_print_in_order(new_bad_tables[i]);
165  }
166  current_bad_tables[i] = bad_table;
167 
168  // Start this slave thread on its range
169  threads[i].join();
170  threads[i] = std::thread
171  ([bad_first_n, bad_last_n, i, range_size, last_n, n,
172  &current_bad_tables, &first_ns, &is_finisheds, &new_bad_tables] {
173  new_bad_tables[i]
175  (first_ns[i],
176  std::min(n + range_size - 1, last_n),
177  current_bad_tables[i],
178  bad_first_n, bad_last_n,
179  false);
180  current_bad_tables[i].clear();
181  is_finisheds[i] = true;
182  });
183 
184  // Next range
185  n += range_size;
186  }
187  }
188 
189  // Run on master thread
190  new_bad_tables[0]
192  (first_ns[0],
193  std::min(first_ns[0] + master_range_size - 1, last_n),
194  bad_table,
195  bad_first_n, bad_last_n,
196  false);
197 
198  // Update bad_table
199  bad_table.insert(new_bad_tables[0].cbegin(), new_bad_tables[0].cend());
200  if (print_bad) {
201  sequential::sequential_print_in_order(new_bad_tables[0]);
202  }
203  new_bad_tables[0].clear();
204  }
205 
206  // Wait end of each slave thread
207  for (unsigned int i = 1; i < nb_thread; ++i) {
208  threads[i].join();
209 
210  // Update bad_table
211  bad_table.insert(new_bad_tables[i].cbegin(), new_bad_tables[i].cend());
212  if (print_bad) {
213  sequential::sequential_print_in_order(new_bad_tables[i]);
214  }
215  }
216 
217  delete[] first_ns;
218  delete[] is_finisheds;
219  delete[] new_bad_tables;
220  delete[] threads;
221 
222  return bad_table;
223  }
224 
225 
226  std::set<nat_type>
228  nat_type first_n, nat_type last_n,
229  const std::set<nat_type> &previous_bad_table,
230  bool print_bad) {
231  assert(nb_thread >= 1);
232  assert(sigmaodd::is_odd(first_n));
233  assert(3 <= first_n);
234  assert(first_n <= last_n);
235  assert(last_n <= sigmaodd::MAX_POSSIBLE_N);
236 #ifdef PRIME16
237  assert(n < 65536);
238 #endif
239 
240  const nat_type bad_first_n = (previous_bad_table.empty()
241  ? first_n
242  : 0);
243 
244  std::set<nat_type> bad_table(previous_bad_table);
245 
246  bool* is_lowers = new bool[nb_thread];
247  nat_type* ns = new nat_type[nb_thread];
248  std::thread* threads = new std::thread[nb_thread]; // threads[0] never used
249 
250  for (nat_type n = first_n; n <= last_n; ) {
251  unsigned int nb_thread_required = 0;
252 
253  // Assign one number for each thread
254  // and start each slave thread
255  for ( ; (nb_thread_required < nb_thread) && (n <= last_n); n += 2) {
257  ns[nb_thread_required] = n;
258 
259  if (nb_thread_required > 0) { // if not master thread
260  threads[nb_thread_required] = std::thread
261  ([bad_first_n, nb_thread_required, is_lowers, ns,
262  &bad_table] {
263  is_lowers[nb_thread_required]
264  = sequential::sequential_is_varsigma_odd_lower(ns[nb_thread_required],
265  bad_table,
266  bad_first_n, ns[0] - 1);
267  });
268  }
269 
270  ++nb_thread_required;
271  }
272  }
273 
274  // Run on master thread
275  is_lowers[0]
277  bad_table,
278  bad_first_n, ns[0] - 1);
279 
280  // Wait end of each slave thread
281  for (unsigned int i = 1; i < nb_thread_required; ++i) {
282  threads[i].join();
283  }
284 
285  // Update bad_table
286  for (unsigned int i = 0; i < nb_thread_required; ++i) {
287  if (!is_lowers[i]) { // new bad number identified
288  bad_table.insert(ns[i]);
289  if (print_bad) {
290  std::cout << ns[i] << std::endl;
291  }
292  }
293  }
294  if (print_bad) {
295  std::cout.flush();
296  }
297  }
298 
299  delete[] is_lowers;
300  delete[] ns;
301  delete[] threads;
302 
303  return bad_table;
304  }
305 
306 } // namespace threads
std::vector< nat_type > sequential_print_in_order(const std::set< nat_type > &ns)
Print number from ns, in increasing order and return a list of these number in the same order...
Definition: sequential.cpp:480
std::set< nat_type > sequential_check_gentle_varsigma_odd(nat_type first_n, nat_type last_n, bool print_bad)
Check in the order all odd gentle numbers between first_n and last_n, and if print_bad then print all...
Definition: sequential.cpp:29
constexpr bool is_odd(nat_type n)
Return true iff n is odd.
constexpr bool is_even(nat_type n)
Return true iff n is even.
bool sequential_is_varsigma_odd_lower(nat_type n, const std::set< nat_type > &bad_table, nat_type bad_first_n)
Return true iff varsigma_odd(n) < n.
Definition: sequential.cpp:202
std::set< nat_type > threads_check_gentle_varsigma_odd__dynamic(unsigned int nb_thread, nat_type first_n, nat_type last_n, const std::set< nat_type > &previous_bad_table, bool print_bad, unsigned int range_size, unsigned int master_range_size)
Check in the order all odd gentle numbers between first_n and last_n, and if print_bad then print all...
Definition: threads.cpp:107
Implementation of the threads parallel algorithms presented in the report.
constexpr nat_type MAX_POSSIBLE_N
Lower bound of the bigger number such that it is possible to compute the result of the sigma function...
Definition: helper.hpp:54
std::set< nat_type > threads_check_gentle_varsigma_odd__by_range(unsigned int nb_thread, nat_type first_n, nat_type last_n, const std::set< nat_type > &previous_bad_table, bool print_bad, unsigned int range_size)
Definition: threads.cpp:27
constexpr nat_type sequential_min_array(const nat_type ns[], size_t size)
Return the minimum of the first size values of ns.
sigmaodd::nat_type nat_type
Definition: threads.hpp:25
std::set< nat_type > threads_check_gentle_varsigma_odd__one_by_one(unsigned int nb_thread, nat_type first_n, nat_type last_n, const std::set< nat_type > &previous_bad_table, bool print_bad)
Definition: threads.cpp:227
constexpr bool is_first_mersenne_prime_unitary_divide_or_square(nat_type n)
Return true iff is_first_mersenne_prime_unitary_divide(n) or is_square(n).