diff options
author | Paul Duncan <pabs@pablotron.org> | 2019-02-05 00:50:28 -0500 |
---|---|---|
committer | Paul Duncan <pabs@pablotron.org> | 2019-02-05 00:50:28 -0500 |
commit | e63a88ea567744d890d923d1d7aa46e583cbb0ec (patch) | |
tree | cc76b02e39dea66cd8a9c92e77dede1ea07ced4a | |
parent | f2b6c7ea5884b65ef93ab999e4edf460ec86a1d1 (diff) | |
download | kmeans-e63a88ea567744d890d923d1d7aa46e583cbb0ec.tar.bz2 kmeans-e63a88ea567744d890d923d1d7aa46e583cbb0ec.zip |
add km_set_print(), refactor main.c
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | src/km-set-print.c | 41 | ||||
-rw-r--r-- | src/km-set.c | 12 | ||||
-rw-r--r-- | src/km.h | 10 | ||||
-rw-r--r-- | src/main.c | 119 |
5 files changed, 113 insertions, 72 deletions
@@ -3,7 +3,8 @@ CFLAGS=-W -Wall -Wextra -Werror -pedantic -std=c11 -O2 OBJS=src/km-set.o src/km-draw.o src/km-load.o src/km-find.o \ src/km-rand.o src/km-solve.o src/km-init-rand.o src/main.o \ src/km-init-forgy.o src/km-init-kmeans.o src/km-init.o \ - src/km-rand-libc.o src/km-rand-path.o src/km-rand-erand48.o + src/km-rand-libc.o src/km-rand-path.o src/km-rand-erand48.o \ + src/km-set-print.o LIBS=-lm .PHONY=all clean diff --git a/src/km-set-print.c b/src/km-set-print.c new file mode 100644 index 0000000..aa93f96 --- /dev/null +++ b/src/km-set-print.c @@ -0,0 +1,41 @@ +#include <stdbool.h> // bool +#include <stdio.h> // fprintf() +#include "util.h" +#include "km.h" + +bool +km_set_print( + const km_set_t * const set, + FILE * const fh +) { + // print shape + fprintf(fh, "%zu %zu\n", set->shape.num_floats, set->shape.num_ints); + + // print rows + for (size_t i = 0; i < set->num_rows; i++) { + if (set->shape.num_floats > 0) { + const float * const vals = km_set_get_row(set, i); + + // print floats + for (size_t j = 0; j < set->shape.num_floats; j++) { + fprintf(fh, "%s%f", (j > 0) ? " ": "", vals[j]); + } + } + + // print ints + if (set->shape.num_ints > 0) { + const int * const vals = km_set_get_row_ints(set, i); + + for (size_t j = 0; j < set->shape.num_ints; j++) { + const bool need_space = (set->shape.num_floats > 0) || (j > 0); + fprintf(fh, "%s%d", need_space ? " ": "", vals[j]); + } + } + + // end row + fprintf(fh, "\n"); + } + + // return success + return true; +} diff --git a/src/km-set.c b/src/km-set.c index 69ae6c0..fcf1054 100644 --- a/src/km-set.c +++ b/src/km-set.c @@ -263,5 +263,15 @@ km_set_get_row( const size_t i ) { const size_t num_floats = set->shape.num_floats; - return set->floats + i * num_floats; + return (num_floats) ? (set->floats + i * num_floats) : NULL; +} + +// get row from data set +int * +km_set_get_row_ints( + const km_set_t * const set, + const size_t i +) { + const size_t num_ints = set->shape.num_ints; + return (num_ints) ? (set->ints + i * num_ints) : NULL; } @@ -83,6 +83,9 @@ _Bool km_set_normalize(km_set_t * const); // get pointer to data set row float *km_set_get_row(const km_set_t *, const size_t); +// get pointer to data set row ints +int *km_set_get_row_ints(const km_set_t *, const size_t); + typedef struct { float d2, d2_near; @@ -196,6 +199,13 @@ km_load( void * const cb_data ); +// print set to file handle +_Bool +km_set_print( + const km_set_t * const, + FILE * const fh +); + // load set from path _Bool km_load_path( const char * const path, @@ -44,6 +44,13 @@ typedef struct { size_t num_best; } ctx_t; +static inline size_t +ctx_get_max_best( + const ctx_t * const ctx +) { + return MIN(ctx->num_best, MAX_BEST); +} + static int best_score_cmp( const void * const ap, @@ -62,7 +69,7 @@ ctx_best_sort( // sort best sets by ascending score (worst to best) qsort( ctx->best, - MIN(ctx->num_best, MAX_BEST), + ctx_get_max_best(ctx), sizeof(best_item_t), best_score_cmp ); @@ -76,7 +83,7 @@ ctx_best_walk( ) { if (on_best) { // walk best sets and emit each one - for (size_t i = 0; i < MIN(ctx->num_best, MAX_BEST); i++) { + for (size_t i = 0; i < ctx_get_max_best(ctx); i++) { on_best(&(ctx->best[i].set), i, ctx->best[i].score, cb_data); } } @@ -213,42 +220,6 @@ FIND_CBS = { .on_best = find_on_best, }; -static void -ctx_csv_print_row( - const ctx_t * const ctx, - FILE * const fh, - const size_t i -) { - const size_t num_clusters = i + 2; - const float mean_distance = ctx->rows[i].distance / NUM_TESTS, - mean_cluster_size = ctx->rows[i].cluster_size / NUM_TESTS, - mean_empty = 1.0 * ctx->rows[i].num_empty / NUM_TESTS, - score = ctx->rows[i].silouette / NUM_TESTS; - - // print result - fprintf(fh, "%zu,%0.3f,%0.3f,%0.3f,%0.3f\n", - num_clusters, - score, - mean_distance, - mean_cluster_size, - mean_empty - ); -} - -static void -ctx_csv_print( - const ctx_t * const ctx, - FILE * const fh -) { - // print headers - fprintf(fh, "#,score,distance,size,empty\n"); - - // print rows - for (size_t i = 0; i < MAX_CLUSTERS - 2; i++) { - ctx_csv_print_row(ctx, fh, i); - } -} - // static image data buffer static uint8_t im_data[3 * IM_WIDTH * IM_HEIGHT]; @@ -260,17 +231,21 @@ save_on_best( void * const cb_data ) { const ctx_t * const ctx = cb_data; + const bool is_best = (rank == ctx_get_max_best(ctx) - 1); UNUSED(score); // convert rank to channel brightness - const uint8_t ch = 0x33 + (0xff - 0x33) * (1.0 * rank + 1) / (MAX_BEST); - const uint8_t shift = (rank == MIN(ctx->num_best, MAX_BEST) - 1) ? 8 : 16; - const uint32_t color = (ch & 0xff) << shift; - // const uint32_t color = 0xff0000; - // D("rank = %zu, score = %0.3f, size = %zu, color = %06x", rank, score, set->num_rows, color); - - // draw clusters - km_set_draw(set, im_data, IM_WIDTH, IM_HEIGHT, 3, color); + if (is_best) { + // draw best in green + km_set_draw(set, im_data, IM_WIDTH, IM_HEIGHT, 3, 0x00ff00); + } else if (false) { + // draw lower-ranked "best" results + const uint8_t ch = 0x33 + (0xff - 0x33) * (1.0 * rank + 1) / (MAX_BEST); + const uint32_t color = (ch & 0xff) << 16; + + // draw clusters + km_set_draw(set, im_data, IM_WIDTH, IM_HEIGHT, 2, color); + } } static void @@ -297,35 +272,39 @@ ctx_save_png( } } -static void -ctx_best_print_on_best( - const km_set_t * const set, - const size_t rank, - const float score, - void * const cb_data -) { - FILE * const fh = cb_data; - - fprintf(fh, "rank = %zu, score = %0.3f, num_clusters = %zu: [\n", rank, score, set->num_rows); - for (size_t i = 0; i < set->num_rows; i++) { - const float * const vals = km_set_get_row(set, i); - fprintf(fh, " ["); - - for (size_t j = 0; j < set->shape.num_floats; j++) { - fprintf(fh, "%s%0.3f", (j > 0) ? ", " : "", vals[j]); - } - - fprintf(fh, "], (%d rows)\n", set->ints[i]); - } - fprintf(fh, "]\n"); -} +/* + * static void + * ctx_best_print_on_best( + * const km_set_t * const set, + * const size_t rank, + * const float score, + * void * const cb_data + * ) { + * FILE * const fh = cb_data; + * + * fprintf(fh, "rank = %zu, score = %0.3f, num_clusters = %zu: [\n", rank, score, set->num_rows); + * for (size_t i = 0; i < set->num_rows; i++) { + * const float * const vals = km_set_get_row(set, i); + * fprintf(fh, " ["); + * + * for (size_t j = 0; j < set->shape.num_floats; j++) { + * fprintf(fh, "%s%0.3f", (j > 0) ? ", " : "", vals[j]); + * } + * + * fprintf(fh, "], (%d rows)\n", set->ints[i]); + * } + * fprintf(fh, "]\n"); + * } + */ static void ctx_best_print( const ctx_t * const ctx, FILE * const fh ) { - ctx_best_walk(ctx, ctx_best_print_on_best, fh); + if (!km_set_print(&(ctx->best[ctx_get_max_best(ctx) - 1].set), fh)) { + die("km_set_print()"); + } } static const char USAGE_FORMAT[] = @@ -377,7 +356,7 @@ int main(int argc, char *argv[]) { } // print csv - ctx_csv_print(&ctx, stdout); + // ctx_csv_print(&ctx, stdout); // sort best results from lowest to highest ctx_best_sort(&ctx); |