11#ifndef RD_LEADERPICKER_H
12#define RD_LEADERPICKER_H
67 unsigned int pickSize)
const;
71 unsigned int pickSize,
double threshold)
const;
75 unsigned int pickSize,
77 double threshold)
const;
81 unsigned int pickSize,
100 double threshold,
int nthreads)
const {
105 if (poolSize < pickSize) {
108 distmatFunctor functor(distMat);
109 return this->
lazyPick(functor, poolSize, pickSize, firstPicks, threshold,
115 unsigned int pickSize)
const override {
122#if defined(RDK_BUILD_THREADSAFE_SSS)
123#if defined(unix) || defined(__unix__) || defined(__unix)
124#define USE_THREADED_LEADERPICKER
128#ifdef USE_THREADED_LEADERPICKER
135void *LeaderPickerWork(
void *arg);
138struct LeaderPickerState {
141 unsigned int capacity;
143 unsigned int next[2];
146 LeaderPickerState<T> *stat;
149 } LeaderPickerThread;
151 std::vector<LeaderPickerThread> threads;
152 std::vector<LeaderPickerBlock> blocks;
153 pthread_barrier_t wait;
154 pthread_barrier_t
done;
156 LeaderPickerBlock *head_block;
157 unsigned int thread_op;
158 unsigned int nthreads;
166 for (
unsigned int i = 0; i < count; i++) {
175 bcount = (count + (bsize - 1)) / bsize;
176 unsigned int tasks = (bcount + 1) / 2;
178 if (nt > (
int)tasks) {
183 bcount = (count + (bsize - 1)) / bsize;
185 blocks.resize(bcount);
186 head_block = &blocks[0];
191 unsigned int len = count;
192 for (
unsigned int i = 0; i < bcount; i++) {
193 LeaderPickerBlock *block = &blocks[i];
196 block->capacity = bsize;
198 block->next[0] = i + 1;
200 block->capacity = len;
209 head_block->capacity = count;
210 head_block->len = count;
211 head_block->next[0] = 0;
212 head_block->next[1] = 0;
213 head_block->ptr = &
v[0];
219 pthread_barrier_init(&wait, NULL, nthreads + 1);
220 pthread_barrier_init(&done, NULL, nthreads + 1);
223 for (
unsigned int i = 0; i < nthreads; i++) {
225 threads[i].stat =
this;
226 pthread_create(&threads[i].tid, NULL, LeaderPickerWork<T>,
227 (
void *)&threads[i]);
234 ~LeaderPickerState() {
237 pthread_barrier_wait(&wait);
238 for (
unsigned int i = 0; i < nthreads; i++) {
239 pthread_join(threads[i].tid, 0);
241 pthread_barrier_destroy(&wait);
242 pthread_barrier_destroy(&done);
248 if (head_block->len) {
251 unsigned int next_tick = head_block->next[tick];
255 head_block = &blocks[next_tick];
260 unsigned int compact(
int *dst,
int *src,
unsigned int len) {
261 unsigned int count = 0;
262 for (
unsigned int i = 0; i < len; i++) {
264 dst[count++] = src[i];
270 void compact_job(
unsigned int cycle) {
273 unsigned int tock = tick ^ 1;
275 LeaderPickerBlock *list = head_block;
277 unsigned int next_tick = list->next[tick];
279 LeaderPickerBlock *next = &blocks[next_tick];
280 unsigned int next_next_tick = next->next[tick];
282 list->len =
compact(list->ptr, list->ptr, list->len);
283 if (list->len + next->len <= list->capacity) {
284 list->len +=
compact(list->ptr + list->len, next->ptr, next->len);
285 list->next[tock] = next_next_tick;
287 next->len =
compact(next->ptr, next->ptr, next->len);
289 list->next[tock] = next_tick;
290 next->next[tock] = next_next_tick;
292 list->next[tock] = next_next_tick;
295 cycle = nthreads - 1;
299 if (next_next_tick) {
300 list = &blocks[next_next_tick];
306 list->len =
compact(list->ptr, list->ptr, list->len);
307 list->next[tock] = 0;
318 pthread_barrier_wait(&wait);
319 pthread_barrier_wait(&done);
334void *LeaderPickerWork(
void *arg) {
335 typename LeaderPickerState<T>::LeaderPickerThread *thread;
336 thread = (
typename LeaderPickerState<T>::LeaderPickerThread *)arg;
337 LeaderPickerState<T> *stat = thread->stat;
340 pthread_barrier_wait(&stat->wait);
341 if (stat->thread_op) {
344 stat->compact_job(thread->id);
345 pthread_barrier_wait(&stat->done);
361 for (
unsigned int i = 0; i < count; i++) {
368 unsigned int compact(
int *dst,
int *src,
unsigned int len) {
369 unsigned int count = 0;
370 for (
unsigned int i = 0; i < len; i++) {
371 double ld = (*func)(
query, src[i]);
374 dst[count++] = src[i];
397 unsigned int pickSize,
399 double threshold,
int nthreads)
const {
404 if (poolSize < pickSize) {
416 stat.threshold = threshold;
419 unsigned int picked = 0;
420 unsigned int pick = 0;
422 if (!firstPicks.empty()) {
423 for (RDKit::INT_VECT::const_iterator pIdx = firstPicks.begin();
424 pIdx != firstPicks.end(); ++pIdx) {
425 pick =
static_cast<unsigned int>(*pIdx);
426 if (
pick >= poolSize) {
429 picks.push_back(
pick);
435 while (picked < pickSize && !stat.empty()) {
436 pick = stat.compact_next();
437 picks.push_back(
pick);
445 unsigned int pickSize)
const {
453 unsigned int pickSize,
454 double threshold)
const {
461 unsigned int pickSize,
463 double threshold)
const {
#define CHECK_INVARIANT(expr, mess)
Abstract base class to do perform item picking (typically molecules) using a distance matrix.
Implements the Leader algorithm for picking a subset of item from a pool.
RDKit::INT_VECT lazyPick(T &func, unsigned int poolSize, unsigned int pickSize) const
Contains the implementation for a lazy Leader diversity picker.
RDKit::INT_VECT pick(const double *distMat, unsigned int poolSize, unsigned int pickSize, const RDKit::INT_VECT &firstPicks, double threshold, int nthreads) const
Contains the implementation for the Leader diversity picker.
LeaderPicker()
Default Constructor.
LeaderPicker(double threshold)
LeaderPicker(double threshold, int nthreads)
RDKit::INT_VECT pick(const double *distMat, unsigned int poolSize, unsigned int pickSize) const override
Class to allow us to throw a ValueError from C++ and have it make it back to Python.
RDKIT_RGROUPDECOMPOSITION_EXPORT const std::string done
std::vector< int > INT_VECT
unsigned int getNumThreadsToUse(int target)
unsigned int compact(int *dst, int *src, unsigned int len)
LeaderPickerState(unsigned int count, int)