From 957aa0c0c95335f8f5b962c4c6739b0544710e3b Mon Sep 17 00:00:00 2001 From: Al Date: Mon, 3 Apr 2017 00:15:31 -0400 Subject: [PATCH] [utils] cartesian product iterator for grid search during model selection --- src/cartesian_product.c | 91 +++++++++++++++++++++++++++++++++++++++++ src/cartesian_product.h | 23 +++++++++++ 2 files changed, 114 insertions(+) create mode 100644 src/cartesian_product.c create mode 100644 src/cartesian_product.h diff --git a/src/cartesian_product.c b/src/cartesian_product.c new file mode 100644 index 00000000..fa57e778 --- /dev/null +++ b/src/cartesian_product.c @@ -0,0 +1,91 @@ +#include "cartesian_product.h" +#include + +cartesian_product_iterator_t *cartesian_product_iterator_new_vargs(size_t n, va_list args) { + cartesian_product_iterator_t *iter = malloc(sizeof(cartesian_product_iterator_t)); + if (iter == NULL) return NULL; + + iter->lengths = uint32_array_new_size(n); + if (iter->lengths == NULL) { + goto exit_iter_created; + } + + size_t remaining = 1; + for (size_t i = 0; i < n; i++) { + uint32_t arg = va_arg(args, uint32_t); + uint32_array_push(iter->lengths, arg); + if (arg > 0) { + remaining *= arg; + } + } + iter->remaining = remaining; + + iter->state = uint32_array_new_zeros(n); + if (iter->state == NULL) { + goto exit_iter_created; + } + + return iter; + +exit_iter_created: + cartesian_product_iterator_destroy(iter); + return NULL; +} + +cartesian_product_iterator_t *cartesian_product_iterator_new(size_t n, ...) { + va_list args; + va_start(args, n); + cartesian_product_iterator_t *iter = cartesian_product_iterator_new_vargs(n, args); + va_end(args); + return iter; +} + +uint32_t *cartesian_product_iterator_start(cartesian_product_iterator_t *self) { + return self->state->a; +} + +bool cartesian_product_iterator_done(cartesian_product_iterator_t *self) { + return self->remaining == 0; +} + +uint32_t *cartesian_product_iterator_next(cartesian_product_iterator_t *self) { + if (self == NULL) return NULL; + + uint32_t *lengths = self->lengths->a; + uint32_t *state = self->state->a; + + if (self->remaining > 0) { + ssize_t i; + ssize_t n = self->lengths->n; + for (i = n - 1; i >= 0; i--) { + state[i]++; + if (state[i] == lengths[i]) { + state[i] = 0; + } else { + self->remaining--; + break; + } + } + if (i < 0) { + self->remaining = 0; + } + } else { + return NULL; + } + + return state; +} + +void cartesian_product_iterator_destroy(cartesian_product_iterator_t *self) { + if (self == NULL) return; + + if (self->lengths != NULL) { + uint32_array_destroy(self->lengths); + } + + if (self->state != NULL) { + uint32_array_destroy(self->state); + } + + free(self); +} diff --git a/src/cartesian_product.h b/src/cartesian_product.h new file mode 100644 index 00000000..d38917fd --- /dev/null +++ b/src/cartesian_product.h @@ -0,0 +1,23 @@ +#ifndef CARTESIAN_PRODUCT_H +#define CARTESIAN_PRODUCT_H + +#include +#include + +#include "collections.h" + +typedef struct cartesian_product_iterator { + size_t remaining; + uint32_array *lengths; + uint32_array *state; +} cartesian_product_iterator_t; + +cartesian_product_iterator_t *cartesian_product_iterator_new(size_t n, ...); +cartesian_product_iterator_t *cartesian_product_iterator_new_vargs(size_t n, va_list args); +uint32_t *cartesian_product_iterator_start(cartesian_product_iterator_t *self); +uint32_t *cartesian_product_iterator_next(cartesian_product_iterator_t *self); +bool cartesian_product_iterator_done(cartesian_product_iterator_t *self); + +void cartesian_product_iterator_destroy(cartesian_product_iterator_t *self); + +#endif \ No newline at end of file