prime_sieve.cpp
1 #include <symengine/prime_sieve.h>
2 #if __cplusplus <= 201703L
3 #include <ciso646>
4 #else
5 #include <version>
6 #endif
7 #include <cmath>
8 #include <valarray>
9 #include <algorithm>
10 #include <vector>
11 #include <iterator>
12 #ifdef HAVE_SYMENGINE_PRIMESIEVE
13 #include <primesieve.hpp>
14 #endif
15 
16 namespace SymEngine
17 {
18 
19 static std::vector<unsigned> &sieve_primes()
20 {
21  static std::vector<unsigned> primes = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
22  return primes;
23 }
24 
25 bool Sieve::_clear = true;
26 unsigned Sieve::_sieve_size = 32 * 1024 * 8; // 32K in bits
27 
28 void Sieve::set_clear(bool clear)
29 {
30  _clear = clear;
31 }
32 
33 void Sieve::clear()
34 {
35  std::vector<unsigned> &_primes = sieve_primes();
36  _primes.erase(_primes.begin() + 10, _primes.end());
37 }
38 
39 void Sieve::set_sieve_size(unsigned size)
40 {
41 #ifdef HAVE_SYMENGINE_PRIMESIEVE
42  primesieve::set_sieve_size(size);
43 #else
44  _sieve_size = size * 1024 * 8; // size in bits
45 #endif
46 }
47 
48 void Sieve::_extend(unsigned limit)
49 {
50  std::vector<unsigned> &_primes = sieve_primes();
51 #ifdef HAVE_SYMENGINE_PRIMESIEVE
52  if (_primes.back() < limit)
53  primesieve::generate_primes(_primes.back() + 1, limit, &_primes);
54 #else
55  const unsigned sqrt_limit
56  = static_cast<unsigned>(std::floor(std::sqrt(limit)));
57  unsigned start = _primes.back() + 1;
58  if (limit <= start)
59  return;
60  if (sqrt_limit >= start) {
61  _extend(sqrt_limit);
62  start = _primes.back() + 1;
63  }
64 
65  unsigned segment = _sieve_size;
66  std::valarray<bool> is_prime(segment);
67  for (; start <= limit; start += 2 * segment) {
68  unsigned finish = std::min(start + segment * 2 + 1, limit);
69  is_prime[std::slice(0, segment, 1)] = true;
70  // considering only odd integers. An odd number n corresponds to
71  // n-start/2 in the array.
72  for (unsigned index = 1; index < _primes.size()
73  and _primes[index] * _primes[index] <= finish;
74  ++index) {
75  unsigned n = _primes[index];
76  unsigned multiple = (start / n + 1) * n;
77  if (multiple % 2 == 0)
78  multiple += n;
79  if (multiple > finish)
80  continue;
81  std::slice sl = std::slice((multiple - start) / 2,
82  1 + (finish - multiple) / (2 * n), n);
83  // starting from n*n, all the odd multiples of n are marked not
84  // prime.
85  is_prime[sl] = false;
86  }
87  for (unsigned n = start + 1; n <= finish; n += 2) {
88  if (is_prime[(n - start) / 2])
89  _primes.push_back(n);
90  }
91  }
92 #endif
93 }
94 
95 void Sieve::generate_primes(std::vector<unsigned> &primes, unsigned limit)
96 {
97  _extend(limit);
98  std::vector<unsigned> &_primes = sieve_primes();
99  auto it = std::upper_bound(_primes.begin(), _primes.end(), limit);
100  // find the first position greater than limit and reserve space for the
101  // primes
102  primes.reserve(it - _primes.begin());
103  std::copy(_primes.begin(), it, std::back_inserter(primes));
104  if (_clear)
105  clear();
106 }
107 
108 Sieve::iterator::iterator(unsigned max)
109 {
110  _limit = max;
111  _index = 0;
112 }
113 
114 Sieve::iterator::iterator()
115 {
116  _limit = 0;
117  _index = 0;
118 }
119 
120 Sieve::iterator::~iterator()
121 {
122  if (_clear)
123  Sieve::clear();
124 }
125 
126 unsigned Sieve::iterator::next_prime()
127 {
128  std::vector<unsigned> &_primes = sieve_primes();
129  if (_index >= _primes.size()) {
130  unsigned extend_to = _primes[_index - 1] * 2;
131  if (_limit > 0 and _limit < extend_to) {
132  extend_to = _limit;
133  }
134  _extend(extend_to);
135  if (_index >= _primes.size()) { // the next prime is greater than _limit
136  return _limit + 1;
137  }
138  }
139  return _primes[_index++];
140 }
141 
142 }; // namespace SymEngine
static void generate_primes(std::vector< unsigned > &primes, unsigned limit)
Definition: prime_sieve.cpp:95
Main namespace for SymEngine package.
Definition: add.cpp:19
RCP< const Basic > max(const vec_basic &arg)
Canonicalize Max:
Definition: functions.cpp:3555
RCP< const Basic > sqrt(const RCP< const Basic > &arg)
Definition: pow.h:61