-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBoundedPrimeSets.cpp
136 lines (117 loc) · 3.92 KB
/
BoundedPrimeSets.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include "BoundedPrimeSets.h"
#include <cstdint>
#include <memory>
#include <vector>
#include "PrimeSieve.h"
// Sets are ordered in lex order, starting at the empty set, and each set is represented in increasing order.
BoundedPrimeSetIterator::BoundedPrimeSetIterator (std::uint64_t upperBound)
: upperBound (upperBound),
primes (std::make_shared<primes_t> ()),
n (1),
isEnd (upperBound <= 1)
{
// The pool will still exist even after 'sieve' has been destroyed.
PrimeSieve<std::uint64_t> sieve (upperBound);
primePool = sieve.Primes ();
}
BoundedPrimeSetIterator::BoundedPrimeSetIterator
(
std::uint64_t upperBound,
std::shared_ptr<const primes_t> primePool
)
: upperBound (upperBound),
primePool (primePool),
primes (std::make_shared<primes_t> ()),
n (1),
isEnd (upperBound <= 1) {}
std::shared_ptr<const primes_t> BoundedPrimeSetIterator::Primes () const
{
return primes;
}
std::uint64_t BoundedPrimeSetIterator::N () const
{
return n;
}
void BoundedPrimeSetIterator::operator++ ()
{
// Try to append to 'primes' the prime in 'primePool' succeeding the last prime in 'primes'.
if (indices.empty ())
{
// The previous prime set was the empty set.
// The next set in lex order is the singleton containing 'primePool.front ()',
// assuming that prime is not larger than 'upperBound'.
if (primePool->front () < upperBound)
{
// The singleton containing 'primePool.front ()' is valid.
indices.emplace_back (0);
primes->emplace_back (primePool->front ());
n = primes->front ();
return;
}
// No non-empty subsets of 'primePool' are valid.
// Enter the end state.
isEnd = true;
return;
}
if (indices.back () < primePool->size () - 1)
{
// There is a prime 'nextPrime' in 'primePool' greater than any prime in 'primes'.
// First try to append 'nextPrime' to 'primes'.
std::uint64_t nextPrime = (*primePool)[indices.back () + 1];
std::uint64_t nextN = n * nextPrime;
if (nextN < upperBound)
{
// Appending 'nextPrime' results in a valid set.
indices.emplace_back (indices.back () + 1);
primes->emplace_back (nextPrime);
n = nextN;
return;
}
// Appending 'nextPrime' results in an invalid set.
// Instead of appending, try replacing the last prime in 'primes' with 'nextPrime'.
nextN = n / primes->back () * nextPrime;
if (nextN < upperBound)
{
// Replacing the last prime in 'primes' with 'nextPrime' results in a valid set.
++indices.back ();
primes->back () = nextPrime;
n = nextN;
return;
}
}
// Repeatedly remove the last prime in 'primes' and replace the new last prime with its successor in 'primePool'.
while (true)
{
// Move up the search tree.
n /= primes->back ();
primes->pop_back ();
indices.pop_back ();
if (indices.empty ())
{
// All valid sets have already been observed.
// Enter the end state.
isEnd = true;
return;
}
// Try to replace the last prime with its successor in 'primePool'.
std::uint64_t nextPrime = (*primePool)[indices.back () + 1];
std::uint64_t nextN = n / primes->back () * nextPrime;
if (nextN < upperBound)
{
// Replacing the last prime in 'primes' with its successor in 'primePool' results in a valid set.
++indices.back ();
primes->back () = nextPrime;
n = nextN;
return;
}
}
}
bool BoundedPrimeSetIterator::IsEnd () const
{
return isEnd;
}
std::int32_t BoundedPrimeSetIterator::MoebiusN () const
{
// Efficient (-1)^n algorithm.
return (-(primes->size () & 1)) | 1;
}