-
Notifications
You must be signed in to change notification settings - Fork 1
/
generator.hpp
146 lines (124 loc) · 4.58 KB
/
generator.hpp
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
#ifndef CG_GENERATOR_H
#define CG_GENERATOR_H
#include <iostream>
#include <vector>
#include <string>
#include <chrono>
#include <future>
#include "chord.hpp"
#include "helpers.hpp"
namespace generator {
const auto BUFSIZE = 65536;
const std::chrono::duration<float> TIMEOUT(0.25);
const auto THREADS = 8;
const uint32_t COUNT_PER_THREAD = chord::MAX / THREADS;
void print_table(std::vector<bool> table) {
auto vars = helpers::log2(table.size());
for (size_t i = 0; i < table.size(); ++i) {
for (uint32_t v = 0; v < vars; ++v)
std::cerr << ((char) (v+'A')) << ": " << (i >> (vars-v-1) & 1) << " ";
std::cerr << "= ";
std::cerr << table[i] << std::endl;
}
}
struct Rule {
std::vector<uint32_t> conditions;
std::vector<bool> table;
void print_matching() {
std::vector<std::future<std::pair<uint32_t, uint32_t>>> futures(THREADS);
std::vector<std::vector<uint32_t>> buffers(THREADS, std::vector<uint32_t>(BUFSIZE));
for (auto t = 0; t < THREADS; ++t) {
uint32_t start = COUNT_PER_THREAD * t;
uint32_t stop = start + COUNT_PER_THREAD;
futures[t] = std::async(std::launch::async, &Rule::check_range, this,
start, stop, std::ref(buffers[t]));
}
auto still_running = THREADS;
uint32_t chords_found = 0;
while (still_running) {
for (auto t = 0; t < THREADS; ++t) {
if (!futures[t].valid()) continue;
auto [count, stop_pos] = futures[t].get();
uint32_t all_done = (t+1) * COUNT_PER_THREAD;
chords_found += count;
if (stop_pos == all_done) {
still_running--;
for (uint32_t i = 0; i < count; ++i) {
chord::Chord c(buffers[t][i], 0);
if (c.notes.empty()) continue;
std::cout << c.fmt() << std::endl;
}
continue;
}
for (uint32_t i = 0; i < count; ++i) {
chord::Chord c(buffers[t][i], 0);
if (c.notes.empty()) continue;
std::cout << c.fmt() << std::endl;
}
futures[t] = std::async(std::launch::async, &Rule::check_range, this,
stop_pos, all_done, std::ref(buffers[t]));
}
}
std::cerr << chords_found << " chord types found." << std::endl;
}
// Checks chords starting at [start] and outputting to [out],
// which should already by resized to BUFSIZE. Returns the
// number of chords checked and stopping position when either
// out is filled or stop is reached or more than TIMEOUT seconds
// pass.
std::pair<uint32_t, uint32_t> check_range(uint32_t start, uint32_t stop, std::vector<uint32_t>& out) {
if (out.size() != BUFSIZE) throw;
auto start_time = std::chrono::high_resolution_clock::now();
uint32_t valid = 0;
uint32_t i = start;
// Optimized loops for small numbers of conditions
if (conditions.size() == 1) {
for (; i < stop && valid < BUFSIZE; ++i) {
if (table[(i & conditions[0]) > 0]) out[valid++] = i;
if (i % 32768 == 0 && std::chrono::high_resolution_clock::now() - start_time > TIMEOUT) break;
}
return {valid, i};
} else if (conditions.size() == 2) {
for (; i < stop && valid < BUFSIZE; ++i) {
if (table[((i & conditions[0]) > 0) * 2
+ ((i & conditions[1]) > 0)]) out[valid++] = i;
if (i % 32768 == 0 && std::chrono::high_resolution_clock::now() - start_time > TIMEOUT) break;
}
return {valid, i};
} else if (conditions.size() == 3) {
for (; i < stop && valid < BUFSIZE; ++i) {
if (table[((i & conditions[0]) > 0) * 4
+ ((i & conditions[1]) > 0) * 2
+ ((i & conditions[2]) > 0)]) out[valid++] = i;
if (i % 32768 == 0 && std::chrono::high_resolution_clock::now() - start_time > TIMEOUT) break;
}
return {valid, i};
} else if (conditions.size() == 4) {
for (; i < stop && valid < BUFSIZE; ++i) {
if (table[((i & conditions[0]) > 0) * 8
+ ((i & conditions[1]) > 0) * 4
+ ((i & conditions[2]) > 0) * 2
+ ((i & conditions[3]) > 0)]) out[valid++] = i;
if (i % 32768 == 0 && std::chrono::high_resolution_clock::now() - start_time > TIMEOUT) break;
}
return {valid, i};
}
// General, but slow solution
for (i = start; i < stop && valid < BUFSIZE; ++i) {
auto table_idx = 0;
for (auto cnd : conditions) table_idx = table_idx << 1 | ((i & cnd) > 0);
if (table[table_idx]) out[valid++] = i;
if (i % 32768 == 0 && std::chrono::high_resolution_clock::now() - start_time > TIMEOUT) break;
}
return {valid, i};
}
void print() {
std::cerr << "Conditions:" << std::endl;
for (auto c : conditions) {
std::cerr << chord::fmt_mixed(c) << std::endl;
}
std::cerr << "Truth table has size " << table.size() << std::endl;
}
};
}
#endif // CG_GENERATOR_H