-
Notifications
You must be signed in to change notification settings - Fork 0
/
gray.h
147 lines (134 loc) · 2.35 KB
/
gray.h
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
137
138
139
140
141
142
143
144
145
146
147
#pragma once
#include <cstdint>
// count number of bits set in x
inline uint32_t count_bits(uint32_t x)
{
uint32_t count = 0;
for (; x; x >>= 1)
{
count += x & 1;
}
return count;
}
// Index of most significant set bit in x
inline int set_bit(uint32_t x)
{
uint32_t r = 0;
while (x >>= 1)
{
++r;
}
return r;
}
// Factorial of x
inline uint32_t fact(uint32_t x)
{
uint32_t f = 1;
for(; x > 1; --x)
{
f *= x;
}
return f;
}
// Generates Gray Code sequences of length size with pick bits set,
// suitable for combinations. Each successive value has a Hamming
// distance of 2 from the previous value which corresponds to replacing
// one item in a combination with a different item.
class gray_generator_t
{
int size_;
int pick_;
bool reversed_;
uint32_t index_;
int combinations_;
public:
gray_generator_t(int size, int pick)
:
size_(size),
pick_(pick),
reversed_(false),
index_(0),
combinations_(fact(size) / (fact(pick) * fact(size-pick)))
{
next();
}
// Binary to Gray Code
static uint32_t gray(uint32_t x)
{
return x ^ (x >> 1);
}
// Advance to the next Code. At the end, the sequence is replayed in reverse.
void next()
{
auto next_index = index_;
if (reversed_)
{
for (;;)
{
--next_index;
if (next_index == 0)
{
reversed_ = false;
break;
}
if (count_bits(gray(next_index)) == pick_)
{
index_ = next_index;
break;
}
}
}
else
{
for (;;)
{
++next_index;
if (next_index == 1 << size_)
{
reversed_ = true;
break;
}
if (count_bits(gray(next_index)) == pick_)
{
index_ = next_index;
break;
}
}
}
}
// The current Gray code
uint32_t value() const
{
return gray(index_);
}
// The size of the set being selected from
int size() const
{
return size_;
}
// Length of the sequence that this will generate
int combinations() const
{
return combinations_;
}
};
// Combines two Gray code combinatorial generators such that only one item
// is replaced from one selection to the next.
class gray_join_t
{
gray_generator_t small_{4, 3};
gray_generator_t large_{7, 4};
int count_ = 0;
public:
uint32_t next()
{
uint32_t ret = small_.value() << large_.size() | large_.value();
count_++;
if (count_ > 0 && count_ % large_.combinations() == 0)
{
small_.next();
}
large_.next();
return ret;
}
};