/*
 *  $Id: benchmark.c 29416 2026-01-30 16:49:54Z yeti-dn $
 *  Copyright (C) 2026 David Nečas (Yeti).
 *  E-mail: yeti@gwyddion.net.
 *
 *  This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public
 *  License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any
 *  later version.
 *
 *  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
 *  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 *  details.
 *
 *  You should have received a copy of the GNU General Public License along with this program; if not, write to the
 *  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include "gwy.h"

static void benchmark_rank_filter(void);

int
main(gint argc, gchar *argv[])
{
    for (gint i = 1; i < argc; i++) {
        if (gwy_stramong(argv[i], "-h", "--help", NULL)) {
            printf("benchmark WHAT...\n");
            printf("Available targets: rank-filter\n");
        }
        if (gwy_strequal(argv[i], "rank-filter"))
            benchmark_rank_filter();
        else {
            fprintf(stderr, "Do not know %s.\n", argv[i]);
        }
    }

    return 0;
}

static void
add_noise_to_field(GwyField *field)
{
    gint n = gwy_field_get_xres(field)*gwy_field_get_yres(field);
    gdouble *d = gwy_field_get_data(field);
    gdouble s = exp(2*g_random_double() - 1);
    for (gint k = 0; k < n; k++)
        d[k] = s*(0.1*d[k] + g_random_double());
}

static void
fill_kernel(GwyNield *nield)
{
    gint n = gwy_nield_get_xres(nield)*gwy_nield_get_yres(nield);
    gwy_nield_fill(nield, 1);
    gint *d = gwy_nield_get_data(nield);
    for (gint k = 0; k < n/3; k++)
        d[g_random_int_range(0, n)] = 0;
}

static void
benchmark_rank_filter(void)
{
    GTimer *timer = g_timer_new();

    for (gint size = 5; size < 1200; size = MAX(16*size/15, size + 1)) {
        GwyField *field = gwy_field_new(size, size, size, size, TRUE);
        add_noise_to_field(field);
        GwyField *workspace = gwy_field_new_alike(field, FALSE);
        gint nrep = 100000/(size*size) + 3;

        for (gint ksize = 2; ksize < MIN(3*size/4, 30); ksize = MAX(16*ksize/15, ksize + 1)) {
            GwyNield *kernel = gwy_nield_new(ksize, ksize);
            fill_kernel(kernel);
            gint k = 2*gwy_nield_count(kernel)/5;

            gwy_tune_algorithms("rank-filter-method", "direct");
            g_timer_start(timer);
            g_timer_stop(timer);
            for (gint itr = 0; itr < nrep; itr++) {
                gwy_field_copy_data(field, workspace);
                g_timer_continue(timer);
                gwy_field_area_filter_kth_rank(workspace, kernel, 0, 0, size, size, k, NULL);
                g_timer_stop(timer);
            }
            gdouble t_direct = g_timer_elapsed(timer, NULL);

            gwy_tune_algorithms("rank-filter-method", "radix-tree");
            g_timer_start(timer);
            g_timer_stop(timer);
            for (gint itr = 0; itr < nrep; itr++) {
                gwy_field_copy_data(field, workspace);
                g_timer_continue(timer);
                gwy_field_area_filter_kth_rank(workspace, kernel, 0, 0, size, size, k, NULL);
                g_timer_stop(timer);
            }
            gdouble t_radixtree = g_timer_elapsed(timer, NULL);

            printf("%d %d %.3f %.3f\n", size, ksize, 1e3*t_direct/nrep, 1e3*t_radixtree/nrep);
            fflush(stdout);

            g_object_unref(kernel);
        }
        g_object_unref(workspace);
        g_object_unref(field);
    }

    g_timer_destroy(timer);
}

/* vim: set cin columns=120 tw=118 et ts=4 sw=4 cino=>1s,e0,n0,f0,{0,}0,^0,\:1s,=0,g1s,h0,t0,+1s,c3,(0,u0 : */
