aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Duncan <pabs@pablotron.org>2019-02-05 00:50:28 -0500
committerPaul Duncan <pabs@pablotron.org>2019-02-05 00:50:28 -0500
commite63a88ea567744d890d923d1d7aa46e583cbb0ec (patch)
treecc76b02e39dea66cd8a9c92e77dede1ea07ced4a
parentf2b6c7ea5884b65ef93ab999e4edf460ec86a1d1 (diff)
downloadkmeans-e63a88ea567744d890d923d1d7aa46e583cbb0ec.tar.bz2
kmeans-e63a88ea567744d890d923d1d7aa46e583cbb0ec.zip
add km_set_print(), refactor main.c
-rw-r--r--Makefile3
-rw-r--r--src/km-set-print.c41
-rw-r--r--src/km-set.c12
-rw-r--r--src/km.h10
-rw-r--r--src/main.c119
5 files changed, 113 insertions, 72 deletions
diff --git a/Makefile b/Makefile
index 19691c7..f69b526 100644
--- a/Makefile
+++ b/Makefile
@@ -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;
}
diff --git a/src/km.h b/src/km.h
index 5a34261..3091685 100644
--- a/src/km.h
+++ b/src/km.h
@@ -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,
diff --git a/src/main.c b/src/main.c
index 55056b7..88e4f94 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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);