From 9d50b997eb2a992400e6dd3c242ff6bd0142ab11 Mon Sep 17 00:00:00 2001 From: Carsten Burstedde Date: Fri, 19 Dec 2025 20:17:48 +0100 Subject: [PATCH 01/11] feature sort: begin example boilerplate --- Makefile.am | 1 + example/sort/Makefile.am | 7 +++ example/sort/sort.c | 104 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 example/sort/Makefile.am create mode 100644 example/sort/sort.c diff --git a/Makefile.am b/Makefile.am index 67c597de0..9117f57bb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -82,6 +82,7 @@ include example/v4l2/Makefile.am ## include example/warp/Makefile.am include example/testing/Makefile.am include example/camera/Makefile.am +include example/sort/Makefile.am # revision control and ChangeLog ChangeLog: diff --git a/example/sort/Makefile.am b/example/sort/Makefile.am new file mode 100644 index 000000000..b83e99ff4 --- /dev/null +++ b/example/sort/Makefile.am @@ -0,0 +1,7 @@ + +# This file is part of the SC Library +# Makefile.am in example/sort +# included non-recursively from toplevel directory + +bin_PROGRAMS += example/sort/sc_sort +example_sort_sc_sort_SOURCES = example/sort/sort.c diff --git a/example/sort/sort.c b/example/sort/sort.c new file mode 100644 index 000000000..1d9c659b4 --- /dev/null +++ b/example/sort/sort.c @@ -0,0 +1,104 @@ +/* + This file is part of the SC Library. + The SC Library provides support for parallel scientific applications. + + Copyright (C) 2010 The University of Texas System + Additional copyright (C) 2011 individual authors + + The SC Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The SC Library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the SC Library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +/* + * Demo program to exercise various sorting algorithms + */ + +#include +#include + +typedef struct sc_sort +{ + int mpirank; + int mpisize; + int n; +} +sc_sort_t; + +static void +run_sort (sc_sort_t *s) +{ +} + +int +main (int argc, char **argv) +{ + sc_sort_t sort, *s = &sort; + int fail = 0; + int mpiret; + int help; + int first_arg; + sc_options_t *opt; + + mpiret = sc_MPI_Init (&argc, &argv); + SC_CHECK_MPI (mpiret); + + sc_init (sc_MPI_COMM_WORLD, 1, 1, NULL, SC_LP_DEFAULT); + + mpiret = sc_MPI_Comm_size (sc_MPI_COMM_WORLD, &s->mpisize); + SC_CHECK_MPI (mpiret); + mpiret = sc_MPI_Comm_rank (sc_MPI_COMM_WORLD, &s->mpirank); + SC_CHECK_MPI (mpiret); + + opt = sc_options_new (argv[0]); + sc_options_add_int (opt, 'n', NULL, &s->n, 0, "Total number of items"); + sc_options_add_switch (opt, 'h', "help", &help, "Print help information"); + + /* process command line options */ + first_arg = sc_options_parse (sc_package_id, SC_LP_INFO, opt, argc, argv); + if (!fail && first_arg < 0) { + SC_GLOBAL_LERROR ("Error in option parsing\n"); + fail = 1; + } + if (!fail && first_arg < argc) { + SC_GLOBAL_LERROR ("This program takes no arguments, just options\n"); + fail = 1; + } + if (!fail && s->n < 0) { + SC_GLOBAL_LERROR ("Parameter n must be non-negative\n"); + fail = 1; + } + + /* execute main program action */ + if (fail) { + sc_options_print_usage (sc_package_id, SC_LP_ERROR, opt, NULL); + } + else { + if (help) { + sc_options_print_usage (sc_package_id, SC_LP_PRODUCTION, opt, NULL); + } + else { + sc_options_print_summary (sc_package_id, SC_LP_PRODUCTION, opt); + run_sort (s); + } + } + + sc_options_destroy (opt); + sc_finalize (); + + mpiret = sc_MPI_Finalize (); + SC_CHECK_MPI (mpiret); + + return fail ? EXIT_FAILURE : EXIT_SUCCESS; +} From 0cfa7d25ca3d2295e78c3c3eb84bdb833eef6a1c Mon Sep 17 00:00:00 2001 From: Carsten Burstedde Date: Fri, 19 Dec 2025 20:46:40 +0100 Subject: [PATCH 02/11] Quicksort random array for reference --- example/sort/sort.c | 62 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/example/sort/sort.c b/example/sort/sort.c index 1d9c659b4..c31c46dce 100644 --- a/example/sort/sort.c +++ b/example/sort/sort.c @@ -30,15 +30,65 @@ typedef struct sc_sort { + sc_rand_state_t rstate; int mpirank; int mpisize; int n; + int myself, mynext, myn; + int roundn; + sc_array_t *input; + sc_array_t *tosort; } sc_sort_t; +static void +print_small (sc_sort_t *s, sc_array_t *a, const char *prefi) +{ + int i; + + SC_ASSERT (s != NULL); + SC_ASSERT (a != NULL); + SC_ASSERT (a->elem_size == sizeof (double)); + SC_ASSERT (a->elem_count == (size_t) s->myn); + + if (s->myn <= 10 && s->mpirank == 0) { + for (i = 0; i < s->myn; ++i) { + SC_INFOF ("%8s %d is %8.6f\n", prefi, i, + *(double *) sc_array_index_int (s->input, i)); + } + } +} + static void run_sort (sc_sort_t *s) { + int i; + + /* compute offset and count of elements assigned to rank */ + s->myself = (int) ((s->mpirank * (long) s->n) / s->mpisize); + s->mynext = (int) (((s->mpirank + 1) * (long) s->n) / s->mpisize); + s->myn = s->mynext - s->myself; + + /* initialize storage for items to sort */ + s->input = sc_array_new_count (sizeof (double), s->myn); + for (i = 0; i < s->myn; ++i) { + *(double *) sc_array_index_int (s->input, i) = + floor (s->roundn * sc_rand (&s->rstate)) / s->roundn; + } + + /* print for small output ranges */ + print_small (s, s->input, "Input"); + + /* run quicksort for comparison */ + sc_array_sort (s->input, sc_double_compare); + print_small (s, s->input, "Qsort"); + +#if 0 + s->tosort = sc_array_new_count (sizeof (double), s->myn); + sc_array_destroy (s->tosort); +#endif + + sc_array_destroy (s->input); } int @@ -49,6 +99,7 @@ main (int argc, char **argv) int mpiret; int help; int first_arg; + size_t seed; sc_options_t *opt; mpiret = sc_MPI_Init (&argc, &argv); @@ -62,8 +113,10 @@ main (int argc, char **argv) SC_CHECK_MPI (mpiret); opt = sc_options_new (argv[0]); - sc_options_add_int (opt, 'n', NULL, &s->n, 0, "Total number of items"); - sc_options_add_switch (opt, 'h', "help", &help, "Print help information"); + sc_options_add_int (opt, 'n', NULL, &s->n, 10, "Total number of items"); + sc_options_add_int (opt, 'r', NULL, &s->roundn, 1000, "Random rounded"); + sc_options_add_size_t (opt, 's', "seed", &seed, 0, "Random number seed"); + sc_options_add_switch (opt, 'h', "help", &help, "Show help information"); /* process command line options */ first_arg = sc_options_parse (sc_package_id, SC_LP_INFO, opt, argc, argv); @@ -79,6 +132,11 @@ main (int argc, char **argv) SC_GLOBAL_LERROR ("Parameter n must be non-negative\n"); fail = 1; } + if (!fail && s->roundn <= 0) { + SC_GLOBAL_LERROR ("Parameter r must be positive\n"); + fail = 1; + } + s->rstate = (sc_rand_state_t) (seed ^ (size_t) s->mpirank); /* execute main program action */ if (fail) { From 9d46b779d060fb05da667888ba55dff9a76ac718 Mon Sep 17 00:00:00 2001 From: Carsten Burstedde Date: Fri, 19 Dec 2025 21:01:03 +0100 Subject: [PATCH 03/11] Feature pqueue: invoke existing sort algorithms --- example/sort/sort.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/example/sort/sort.c b/example/sort/sort.c index c31c46dce..03175a65f 100644 --- a/example/sort/sort.c +++ b/example/sort/sort.c @@ -27,6 +27,7 @@ #include #include +#include typedef struct sc_sort { @@ -54,7 +55,7 @@ print_small (sc_sort_t *s, sc_array_t *a, const char *prefi) if (s->myn <= 10 && s->mpirank == 0) { for (i = 0; i < s->myn; ++i) { SC_INFOF ("%8s %d is %8.6f\n", prefi, i, - *(double *) sc_array_index_int (s->input, i)); + *(double *) sc_array_index_int (a, i)); } } } @@ -79,15 +80,23 @@ run_sort (sc_sort_t *s) /* print for small output ranges */ print_small (s, s->input, "Input"); - /* run quicksort for comparison */ - sc_array_sort (s->input, sc_double_compare); - print_small (s, s->input, "Qsort"); + /* initialize output array */ + s->tosort = sc_array_new (sizeof (double)); -#if 0 - s->tosort = sc_array_new_count (sizeof (double), s->myn); + /* run quicksort for comparison */ + sc_array_copy (s->tosort, s->input); + sc_array_sort (s->tosort, sc_double_compare); + print_small (s, s->tosort, "Qsort"); + + /* run parallel sort for comparison */ + sc_array_copy (s->tosort, s->input); + sc_psort (sc_MPI_COMM_SELF, + s->tosort->array, &s->tosort->elem_count, s->tosort->elem_size, + sc_double_compare); + print_small (s, s->tosort, "Psort"); + + /* release memory */ sc_array_destroy (s->tosort); -#endif - sc_array_destroy (s->input); } From ad2c4de3d9ccd28b32ee57380c44e56cafd0f6c4 Mon Sep 17 00:00:00 2001 From: Carsten Burstedde Date: Fri, 19 Dec 2025 21:42:54 +0100 Subject: [PATCH 04/11] Feature pqueue: add pqueue_lessen, upd pqueue_add The sc_array_pqueue_add function was hitherto set do abort. We update the semantics to have it enlarge the queue array by one. New implementation by the new helper function sc_array_pqueue_lessen. --- src/sc_containers.c | 66 ++++++++++++++++++++++++--------------------- src/sc_containers.h | 39 ++++++++++++++++++--------- 2 files changed, 61 insertions(+), 44 deletions(-) diff --git a/src/sc_containers.c b/src/sc_containers.c index 7510d6bac..f87f20cbf 100644 --- a/src/sc_containers.c +++ b/src/sc_containers.c @@ -653,46 +653,50 @@ sc_array_checksum (sc_array_t * array) } size_t -sc_array_pqueue_add (sc_array_t * array, void *temp, - int (*compar) (const void *, const void *)) +sc_array_pqueue_lessen (sc_array_t * array, size_t pos, void *newval, + int (*compar) (const void *, const void *)) { - int comp; - size_t parent, child, swaps; - const size_t size = array->elem_size; - void *p, *c; + size_t esize; + size_t swaps; + size_t parent; + void *Hparent; - /* this works on a pre-allocated array that is not a view */ + SC_ASSERT (array != NULL); SC_ASSERT (SC_ARRAY_IS_OWNER (array)); - SC_ASSERT (array->elem_count > 0); - - /* PQUEUE FUNCTIONS ARE UNTESTED AND CURRENTLY DISABLED. */ - SC_ABORT_NOT_REACHED (); + SC_ASSERT (pos < array->elem_count); + SC_ASSERT (newval != NULL); + SC_ASSERT (compar != NULL); + esize = array->elem_size; swaps = 0; - child = array->elem_count - 1; - c = array->array + (size * child); - while (child > 0) { - parent = (child - 1) / 2; - p = array->array + (size * parent); - - /* compare child to parent */ - comp = compar (p, c); - if (comp <= 0) { - break; + while (pos > 0) { + parent = (pos - 1) >> 1; + Hparent = sc_array_index (array, parent); + if (compar (newval, Hparent) < 0) { + memcpy (sc_array_index (array, pos), Hparent, esize); + pos = parent; + ++swaps; } + else break; + } + memcpy (sc_array_index (array, pos), newval, esize); + return swaps; +} - /* swap child and parent */ - memcpy (temp, c, size); - memcpy (c, p, size); - memcpy (p, temp, size); - ++swaps; +size_t +sc_array_pqueue_add (sc_array_t * array, void *newval, + int (*compar) (const void *, const void *)) +{ + size_t snn; - /* walk up the tree */ - child = parent; - c = p; - } + SC_ASSERT (array != NULL); + SC_ASSERT (SC_ARRAY_IS_OWNER (array)); + SC_ASSERT (newval != NULL); + SC_ASSERT (compar != NULL); - return swaps; + snn = array->elem_count; + sc_array_push (array); + return sc_array_pqueue_lessen (array, snn, newval, compar); } size_t diff --git a/src/sc_containers.h b/src/sc_containers.h index 6eaeb74d5..7357ad554 100644 --- a/src/sc_containers.h +++ b/src/sc_containers.h @@ -452,22 +452,35 @@ void sc_array_permute (sc_array_t * array, */ unsigned int sc_array_checksum (sc_array_t * array); -/** Adds an element to a priority queue. - * \note PQUEUE FUNCTIONS ARE UNTESTED AND CURRENTLY DISABLED. +/** Replace an element in a priority queue with another and sift up. + * The priority queue is implemented as a binary heap in ascending order. + * It is a minimum-heap: The smallest values have highest priority. + * The new element is inserted at a given position and must not + * be greater than the descendants below that position. * This function is not allowed for views. + * \param [in,out] array Valid priority queue, not a view. + * \param [in] pos Valid position in priority queue. + * \param [in] newval Read-only storage of the new value. + * \param [in] compar A comparison function to be used. + * \return The number of swap operations. + */ +size_t sc_array_pqueue_lessen (sc_array_t * array, + size_t pos, void *newval, + int (*compar) (const void *, + const void *)); + +/** Add an element to a priority queue. * The priority queue is implemented as a heap in ascending order. - * A heap is a binary tree where the children are not less than their parent. - * Assumes that elements [0]..[elem_count-2] form a valid heap. - * Then propagates [elem_count-1] upward by swapping if necessary. - * \param [in,out] array Valid priority queue object. - * \param [in] temp Pointer to unused allocated memory of elem_size. - * \param [in] compar The comparison function to be used. - * \return Returns the number of swap operations. - * \note If the return value is zero for all elements in an array, - * the array is sorted linearly and unchanged. + * It is a minimum-heap: The smallest values have highest priority. + * This function augments the priority queue by one element. + * This function is not allowed for views. + * \param [in,out] array Valid priority queue, not a view. + * Enlarged by one element. + * \param [in] newval Read-only storage of the new value. + * \param [in] compar A comparison function to be used. + * \return The number of swap operations. */ -size_t sc_array_pqueue_add (sc_array_t * array, - void *temp, +size_t sc_array_pqueue_add (sc_array_t * array, void *newval, int (*compar) (const void *, const void *)); From ee7b6161229a0a4a5fa00d1af4a075942b47be28 Mon Sep 17 00:00:00 2001 From: Carsten Burstedde Date: Fri, 19 Dec 2025 22:58:02 +0100 Subject: [PATCH 05/11] Feature pqueue: sc_array_pqueue_greaten, upd _pop Add a new helper function to sift down an element in a minimum heap. Update the pqueue_pop function to use the helper function. --- src/sc_containers.c | 116 ++++++++++++++++++++++++-------------------- src/sc_containers.h | 39 +++++++++++---- 2 files changed, 93 insertions(+), 62 deletions(-) diff --git a/src/sc_containers.c b/src/sc_containers.c index f87f20cbf..8f69934e4 100644 --- a/src/sc_containers.c +++ b/src/sc_containers.c @@ -700,71 +700,81 @@ sc_array_pqueue_add (sc_array_t * array, void *newval, } size_t -sc_array_pqueue_pop (sc_array_t * array, void *result, - int (*compar) (const void *, const void *)) +sc_array_pqueue_greaten (sc_array_t * array, size_t snn, + size_t pos, void *newval, + int (*compar) (const void *, const void *)) { - int comp; - size_t new_count, swaps; - size_t parent, child, child1; - const size_t size = array->elem_size; - void *p, *c, *c1; - void *temp; + size_t esize; + size_t swaps; + size_t child, child2; + void *Hchild, *Hchild2; - /* array must not be empty or a view */ + SC_ASSERT (array != NULL); SC_ASSERT (SC_ARRAY_IS_OWNER (array)); - SC_ASSERT (array->elem_count > 0); - - /* PQUEUE FUNCTIONS ARE UNTESTED AND CURRENTLY DISABLED. */ - SC_ABORT_NOT_REACHED (); + SC_ASSERT (snn <= array->elem_count); + SC_ASSERT (pos < snn); + SC_ASSERT (newval != NULL); + SC_ASSERT (compar != NULL); + esize = array->elem_size; swaps = 0; - new_count = array->elem_count - 1; - - /* extract root */ - parent = 0; - p = array->array + (size * parent); - memcpy (result, p, size); - - /* copy the last element to the top and reuse it as temp storage */ - temp = array->array + (size * new_count); - if (new_count > 0) { - memcpy (p, temp, size); - } - - /* sift down the tree */ - while ((child = 2 * parent + 1) < new_count) { - c = array->array + (size * child); - - /* check if child has a sibling and use that one if it is smaller */ - if ((child1 = 2 * parent + 2) < new_count) { - c1 = array->array + (size * child1); - comp = compar (c, c1); - if (comp > 0) { - child = child1; - c = c1; + for (;;) { + child = (pos << 1) + 1; + if (child < snn) { + Hchild = sc_array_index (array, child); + child2 = child + 1; + if (child2 < snn) { + Hchild2 = sc_array_index (array, child2); + if (compar (Hchild, Hchild2) >= 0) { + child = child2; + Hchild = Hchild2; + } + } + if (compar (newval, Hchild) > 0) { + memcpy (sc_array_index (array, pos), Hchild, esize); + pos = child; + ++swaps; } + else break; } + else break; + } + memcpy (sc_array_index (array, pos), newval, esize); + return swaps; +} - /* sift down the parent if it is larger */ - comp = compar (p, c); - if (comp <= 0) { - break; - } +size_t +sc_array_pqueue_pop (sc_array_t * array, void *newval, + int (*compar) (const void *, const void *)) +{ + size_t esize; + size_t snn; + size_t swaps; - /* swap child and parent */ - memcpy (temp, c, size); - memcpy (c, p, size); - memcpy (p, temp, size); - ++swaps; + SC_ASSERT (array != NULL); + SC_ASSERT (SC_ARRAY_IS_OWNER (array)); + SC_ASSERT (array->elem_count > 0); + SC_ASSERT (newval != NULL); + SC_ASSERT (compar != NULL); - /* walk down the tree */ - parent = child; - p = c; - } + esize = array->elem_size; + snn = array->elem_count; + swaps = 0; - /* we can resize down here only since we need the temp element above */ - sc_array_resize (array, new_count); + /* remove root from heap */ + memcpy (newval, sc_array_index (array, 0), esize); + if (snn == 1) { + sc_array_resize (array, 0); + } + else { + /* move last leaf to root and sift down */ + --snn; + swaps = sc_array_pqueue_greaten + (array, snn, 0, sc_array_index (array, snn), compar); + /* circumvent calling sc_array_pop */ + array->elem_count = snn; + } return swaps; } diff --git a/src/sc_containers.h b/src/sc_containers.h index 7357ad554..69cf3ce35 100644 --- a/src/sc_containers.h +++ b/src/sc_containers.h @@ -484,18 +484,39 @@ size_t sc_array_pqueue_add (sc_array_t * array, void *newval, int (*compar) (const void *, const void *)); -/** Pops the smallest element from a priority queue. - * \note PQUEUE FUNCTIONS ARE UNTESTED AND CURRENTLY DISABLED. +/** Replace an element in a priority queue with another and sift down. + * The priority queue is implemented as a binary heap in ascending order. + * It is a minimum-heap: The smallest values have highest priority. + * The new element is inserted at a given position and must not be less + * than its ancestors above that position. + * This function is not allowed for views. + * \param [in,out] array Valid priority queue, not a view. + * \param [in] maxcount Less or equal than \a array's element count. + * Work only with this amount of array elements. + * \param [in] pos Valid position less than \a maxcount. + * \param [in] newval Read-only storage of the new value. + * \param [in] compar A comparison function to be used. + * \return The number of swap operations. + */ +size_t sc_array_pqueue_greaten (sc_array_t * array, + size_t maxcount, + size_t pos, void *newval, + int (*compar) (const void *, + const void *)); + +/** Pop the smallest element from a priority queue. + * The priority queue is implemented as a binary heap in ascending order. + * It is a minimum-heap: The smallest values have highest priority. + * The root of the heap is removed and returned. * This function is not allowed for views. - * This function assumes that the array forms a valid heap in ascending order. - * \param [in,out] array Valid priority queue object. - * \param [out] result Pointer to unused allocated memory of elem_size. - * \param [in] compar The comparison function to be used. - * \return Returns the number of swap operations. - * \note This function resizes the array to elem_count-1. + * \param [in,out] array Valid priority queue, not a view. + * Shrunk by one element. + * \param [in] newval Storage for the minimum value removed. + * \param [in] compar A comparison function to be used. + * \return The number of swap operations. */ size_t sc_array_pqueue_pop (sc_array_t * array, - void *result, + void *newval, int (*compar) (const void *, const void *)); From 0f60529d3a127f54c8ad670ed654832db9c7ff86 Mon Sep 17 00:00:00 2001 From: Carsten Burstedde Date: Fri, 19 Dec 2025 23:01:13 +0100 Subject: [PATCH 06/11] Feature pqueue: implement heapsort in example --- example/sort/sort.c | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/example/sort/sort.c b/example/sort/sort.c index 03175a65f..5828c25e4 100644 --- a/example/sort/sort.c +++ b/example/sort/sort.c @@ -60,6 +60,40 @@ print_small (sc_sort_t *s, sc_array_t *a, const char *prefi) } } +static void +array_heapsort (sc_array_t *a, int (*compar) (const void *, const void *)) +{ + size_t esize; + size_t snn; + size_t sz, szmo; + sc_array_t *heap; + + SC_ASSERT (a != NULL); + esize = a->elem_size; + snn = a->elem_count; + + /* allocate heap as temporary storage */ + heap = sc_array_new_count (a->elem_size, snn); + + /* insert input variables into heap */ + for (sz = 0; sz < snn; ++sz) { + sc_array_pqueue_lessen (heap, sz, sc_array_index (a, sz), compar); + } + + /* remove minimum value one at a time */ + szmo = 0; + for (sz = snn; sz > 0; sz = szmo) { + memcpy (sc_array_index (a, snn - sz), sc_array_index (heap, 0), esize); + if ((szmo = sz - 1) > 0) { + sc_array_pqueue_greaten + (heap, szmo, 0, sc_array_index (heap, szmo), compar); + } + } + + /* release temporary storage */ + sc_array_destroy (heap); +} + static void run_sort (sc_sort_t *s) { @@ -88,13 +122,18 @@ run_sort (sc_sort_t *s) sc_array_sort (s->tosort, sc_double_compare); print_small (s, s->tosort, "Qsort"); - /* run parallel sort for comparison */ + /* run parallel sort in serial for comparison */ sc_array_copy (s->tosort, s->input); sc_psort (sc_MPI_COMM_SELF, s->tosort->array, &s->tosort->elem_count, s->tosort->elem_size, sc_double_compare); print_small (s, s->tosort, "Psort"); + /* run heapsort for comparison */ + sc_array_copy (s->tosort, s->input); + array_heapsort (s->tosort, sc_double_compare); + print_small (s, s->tosort, "Hsort"); + /* release memory */ sc_array_destroy (s->tosort); sc_array_destroy (s->input); From 28d748bb37d56b8a0a3c36d0b66c0e7faba33e2c Mon Sep 17 00:00:00 2001 From: Carsten Burstedde Date: Sun, 21 Dec 2025 16:08:49 +0100 Subject: [PATCH 07/11] sc_camera: mention in release notes --- doc/release_notes.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/release_notes.txt b/doc/release_notes.txt index a860aa400..a59352de9 100644 --- a/doc/release_notes.txt +++ b/doc/release_notes.txt @@ -18,6 +18,8 @@ ### Functionality + - Merge new code to define and modify a camera object for graphics. + ## 2.8.7 We expect this to be a drop-in replacement for most use cases, but there are From 0393257889e7936e2b8d3d6ea33f6bb4c02f5f82 Mon Sep 17 00:00:00 2001 From: Carsten Burstedde Date: Sun, 21 Dec 2025 16:10:01 +0100 Subject: [PATCH 08/11] Feature pqueue: fixup new set of pqueue functions --- doc/release_notes.txt | 1 + example/sort/sort.c | 34 +++++++++++++++--------------- src/sc_containers.c | 22 +++++++++---------- src/sc_containers.h | 49 +++++++++++++++++++++++-------------------- 4 files changed, 55 insertions(+), 51 deletions(-) diff --git a/doc/release_notes.txt b/doc/release_notes.txt index a59352de9..cca1c7bd4 100644 --- a/doc/release_notes.txt +++ b/doc/release_notes.txt @@ -18,6 +18,7 @@ ### Functionality + - Rename, redesign and reactivate the priority queue functions. - Merge new code to define and modify a camera object for graphics. ## 2.8.7 diff --git a/example/sort/sort.c b/example/sort/sort.c index 5828c25e4..53ec45441 100644 --- a/example/sort/sort.c +++ b/example/sort/sort.c @@ -65,33 +65,33 @@ array_heapsort (sc_array_t *a, int (*compar) (const void *, const void *)) { size_t esize; size_t snn; - size_t sz, szmo; - sc_array_t *heap; + size_t sz; + char *temp; SC_ASSERT (a != NULL); + if ((snn = a->elem_count) <= 1) { + return; + } esize = a->elem_size; - snn = a->elem_count; - /* allocate heap as temporary storage */ - heap = sc_array_new_count (a->elem_size, snn); + /* reserve temporary element storage */ + temp = SC_ALLOC (char, esize); /* insert input variables into heap */ - for (sz = 0; sz < snn; ++sz) { - sc_array_pqueue_lessen (heap, sz, sc_array_index (a, sz), compar); + for (sz = 1; sz < snn; ++sz) { + memcpy (temp, sc_array_index (a, sz), esize); + sc_array_pqueue_siftup (a, sz, temp, compar); } - /* remove minimum value one at a time */ - szmo = 0; - for (sz = snn; sz > 0; sz = szmo) { - memcpy (sc_array_index (a, snn - sz), sc_array_index (heap, 0), esize); - if ((szmo = sz - 1) > 0) { - sc_array_pqueue_greaten - (heap, szmo, 0, sc_array_index (heap, szmo), compar); - } + /* remove maximum value one at a time */ + for (sz = snn - 1; sz > 0; --sz) { + memcpy (temp, sc_array_index (a, sz), esize); + memcpy (sc_array_index (a, sz), sc_array_index (a, 0), esize); + sc_array_pqueue_siftdown (a, sz, 0, temp, compar); } - /* release temporary storage */ - sc_array_destroy (heap); + /* free temporary element storage */ + SC_FREE (temp); } static void diff --git a/src/sc_containers.c b/src/sc_containers.c index 8f69934e4..3c785b508 100644 --- a/src/sc_containers.c +++ b/src/sc_containers.c @@ -653,7 +653,7 @@ sc_array_checksum (sc_array_t * array) } size_t -sc_array_pqueue_lessen (sc_array_t * array, size_t pos, void *newval, +sc_array_pqueue_siftup (sc_array_t * array, size_t pos, void *newval, int (*compar) (const void *, const void *)) { size_t esize; @@ -672,7 +672,7 @@ sc_array_pqueue_lessen (sc_array_t * array, size_t pos, void *newval, while (pos > 0) { parent = (pos - 1) >> 1; Hparent = sc_array_index (array, parent); - if (compar (newval, Hparent) < 0) { + if (compar (newval, Hparent) > 0) { memcpy (sc_array_index (array, pos), Hparent, esize); pos = parent; ++swaps; @@ -684,8 +684,8 @@ sc_array_pqueue_lessen (sc_array_t * array, size_t pos, void *newval, } size_t -sc_array_pqueue_add (sc_array_t * array, void *newval, - int (*compar) (const void *, const void *)) +sc_array_pqueue_insert (sc_array_t * array, void *newval, + int (*compar) (const void *, const void *)) { size_t snn; @@ -696,13 +696,13 @@ sc_array_pqueue_add (sc_array_t * array, void *newval, snn = array->elem_count; sc_array_push (array); - return sc_array_pqueue_lessen (array, snn, newval, compar); + return sc_array_pqueue_siftup (array, snn, newval, compar); } size_t -sc_array_pqueue_greaten (sc_array_t * array, size_t snn, - size_t pos, void *newval, - int (*compar) (const void *, const void *)) +sc_array_pqueue_siftdown (sc_array_t * array, size_t snn, + size_t pos, void *newval, + int (*compar) (const void *, const void *)) { size_t esize; size_t swaps; @@ -725,12 +725,12 @@ sc_array_pqueue_greaten (sc_array_t * array, size_t snn, child2 = child + 1; if (child2 < snn) { Hchild2 = sc_array_index (array, child2); - if (compar (Hchild, Hchild2) >= 0) { + if (compar (Hchild, Hchild2) <= 0) { child = child2; Hchild = Hchild2; } } - if (compar (newval, Hchild) > 0) { + if (compar (newval, Hchild) < 0) { memcpy (sc_array_index (array, pos), Hchild, esize); pos = child; ++swaps; @@ -769,7 +769,7 @@ sc_array_pqueue_pop (sc_array_t * array, void *newval, else { /* move last leaf to root and sift down */ --snn; - swaps = sc_array_pqueue_greaten + swaps = sc_array_pqueue_siftdown (array, snn, 0, sc_array_index (array, snn), compar); /* circumvent calling sc_array_pop */ diff --git a/src/sc_containers.h b/src/sc_containers.h index 69cf3ce35..a4dfdb8f2 100644 --- a/src/sc_containers.h +++ b/src/sc_containers.h @@ -111,7 +111,8 @@ typedef int (*sc_hash_foreach_t) (void **v, const void *u); * \ref sc_array_resize and \ref sc_array_rewind. * Elements can be sorted with \ref sc_array_sort. * If the array is sorted, it can be searched with \ref sc_array_bsearch. - * A priority queue is implemented with pqueue_add and pqueue_pop (untested). + * A maximum-first priority queue is implemented with \ref + * sc_array_pqueue_insert, \ref sc_array_pqueue_pop and further helpers. */ typedef struct sc_array { @@ -453,25 +454,26 @@ void sc_array_permute (sc_array_t * array, unsigned int sc_array_checksum (sc_array_t * array); /** Replace an element in a priority queue with another and sift up. - * The priority queue is implemented as a binary heap in ascending order. - * It is a minimum-heap: The smallest values have highest priority. + * The priority queue is implemented as a binary heap in descending order. + * It is a maximum heap: The largest values have highest priority. * The new element is inserted at a given position and must not - * be greater than the descendants below that position. + * be less than the descendants below that position. * This function is not allowed for views. * \param [in,out] array Valid priority queue, not a view. * \param [in] pos Valid position in priority queue. * \param [in] newval Read-only storage of the new value. + * Must reside outside of the array. * \param [in] compar A comparison function to be used. * \return The number of swap operations. */ -size_t sc_array_pqueue_lessen (sc_array_t * array, +size_t sc_array_pqueue_siftup (sc_array_t * array, size_t pos, void *newval, int (*compar) (const void *, const void *)); /** Add an element to a priority queue. - * The priority queue is implemented as a heap in ascending order. - * It is a minimum-heap: The smallest values have highest priority. + * The priority queue is implemented as a heap in descending order. + * It is a maximum heap: The largest values have highest priority. * This function augments the priority queue by one element. * This function is not allowed for views. * \param [in,out] array Valid priority queue, not a view. @@ -480,38 +482,39 @@ size_t sc_array_pqueue_lessen (sc_array_t * array, * \param [in] compar A comparison function to be used. * \return The number of swap operations. */ -size_t sc_array_pqueue_add (sc_array_t * array, void *newval, - int (*compar) (const void *, - const void *)); +size_t sc_array_pqueue_insert (sc_array_t * array, void *newval, + int (*compar) (const void *, + const void *)); /** Replace an element in a priority queue with another and sift down. - * The priority queue is implemented as a binary heap in ascending order. - * It is a minimum-heap: The smallest values have highest priority. - * The new element is inserted at a given position and must not be less + * The priority queue is implemented as a binary heap in descending order. + * It is a maximum heap: The largest values have highest priority. + * The new element is inserted at a given position and must not be greater * than its ancestors above that position. * This function is not allowed for views. * \param [in,out] array Valid priority queue, not a view. * \param [in] maxcount Less or equal than \a array's element count. * Work only with this amount of array elements. * \param [in] pos Valid position less than \a maxcount. - * \param [in] newval Read-only storage of the new value. + * \param [in] newval Read-only storage of the new value. Must reside + * outside of the first maxcount array positions. * \param [in] compar A comparison function to be used. * \return The number of swap operations. */ -size_t sc_array_pqueue_greaten (sc_array_t * array, - size_t maxcount, - size_t pos, void *newval, - int (*compar) (const void *, - const void *)); +size_t sc_array_pqueue_siftdown (sc_array_t * array, + size_t maxcount, + size_t pos, void *newval, + int (*compar) (const void *, + const void *)); -/** Pop the smallest element from a priority queue. - * The priority queue is implemented as a binary heap in ascending order. - * It is a minimum-heap: The smallest values have highest priority. +/** Pop the largest element from a priority queue. + * The priority queue is implemented as a binary heap in descending order. + * It is a maximum heap: The largest values have highest priority. * The root of the heap is removed and returned. * This function is not allowed for views. * \param [in,out] array Valid priority queue, not a view. * Shrunk by one element. - * \param [in] newval Storage for the minimum value removed. + * \param [in] newval Storage for the maximum value removed. * \param [in] compar A comparison function to be used. * \return The number of swap operations. */ From c6ec58e947cbb6c1f97143806c45e4e1ffc21e1e Mon Sep 17 00:00:00 2001 From: Carsten Burstedde Date: Sun, 21 Dec 2025 16:35:52 +0100 Subject: [PATCH 09/11] Feature pqueue: reactivate test --- test/Makefile.am | 7 ++----- test/test_pqueue.c | 36 +++++++++++++++++++----------------- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/test/Makefile.am b/test/Makefile.am index 0ae79a29c..21d7d2762 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -16,14 +16,12 @@ sc_test_programs = \ test/sc_test_search \ test/sc_test_sort \ test/sc_test_sortb \ + test/sc_test_pqueue \ test/sc_test_version \ test/sc_test_helpers \ test/sc_test_mpi_pack \ test/sc_test_scda -## Reenable and properly verify pqueue when it is actually used -## test/sc_test_pqueue \ - check_PROGRAMS += $(sc_test_programs) test_sc_test_allgather_SOURCES = test/test_allgather.c @@ -34,12 +32,11 @@ test_sc_test_io_file_SOURCES = test/test_io_file.c test_sc_test_keyvalue_SOURCES = test/test_keyvalue.c test_sc_test_notify_SOURCES = test/test_notify.c test_sc_test_node_comm_SOURCES = test/test_node_comm.c -## Reenable and properly verify pqueue when it is actually used -## test_sc_test_pqueue_SOURCES = test/test_pqueue.c test_sc_test_reduce_SOURCES = test/test_reduce.c test_sc_test_search_SOURCES = test/test_search.c test_sc_test_sort_SOURCES = test/test_sort.c test_sc_test_sortb_SOURCES = test/test_sortb.c +test_sc_test_pqueue_SOURCES = test/test_pqueue.c test_sc_test_version_SOURCES = test/test_version.c test_sc_test_helpers_SOURCES = test/test_helpers.c test_sc_test_mpi_pack_SOURCES = test/test_mpi_pack.c diff --git a/test/test_pqueue.c b/test/test_pqueue.c index 93b295355..f7cb51281 100644 --- a/test/test_pqueue.c +++ b/test/test_pqueue.c @@ -23,15 +23,17 @@ #include -/* #define THEBIGTEST */ +#if 0 +#define THEBIGTEST +#endif static int -compar (const void *p1, const void *p2) +reverse_compare (const void *v1, const void *v2) { - int i1 = *(int *) p1; - int i2 = *(int *) p2; + const int i1 = *(int *) v1; + const int i2 = *(int *) v2; - return i1 - i2; + return i1 == i2 ? 0 : i1 < i2 ? +1 : -1; } int @@ -67,28 +69,28 @@ main (int argc, char **argv) swaps1 = swaps2 = swaps3 = 0; total1 = total2 = total3 = 0; for (i = 0; i < count; ++i) { - *(int *) sc_array_push (a1) = i; - s = sc_array_pqueue_add (a1, &temp, compar); + i1 = i; + s = sc_array_pqueue_insert (a1, &i1, reverse_compare); swaps1 += ((s > 0) ? 1 : 0); total1 += s; - *(int *) sc_array_push (a2) = count - i - 1; - s = sc_array_pqueue_add (a2, &temp, compar); + i2 = count - i - 1; + s = sc_array_pqueue_insert (a2, &i2, reverse_compare); swaps2 += ((s > 0) ? 1 : 0); total2 += s; - *(int *) sc_array_push (a3) = (15 * i) % 172; - s = sc_array_pqueue_add (a3, &temp, compar); + i3 = (15 * i) % 172; + s = sc_array_pqueue_insert (a3, &i3, reverse_compare); swaps3 += ((s > 0) ? 1 : 0); total3 += s; } - SC_CHECK_ABORT (swaps1 == 0 && total1 == 0, "pqueue_add"); + SC_CHECK_ABORT (swaps1 == 0 && total1 == 0, "pqueue_insert"); SC_VERBOSEF (" Swaps %lld %lld %lld Total %lld %lld %lld\n", (long long) swaps1, (long long) swaps2, (long long) swaps3, (long long) total1, (long long) total2, (long long) total3); temp = 52; - searched = sc_array_bsearch (a1, &temp, compar); + searched = sc_array_bsearch (a1, &temp, sc_int_compare); SC_CHECK_ABORT (searched != -1, "array_bsearch_index"); pi = (int *) sc_array_index_ssize_t (a1, searched); SC_CHECK_ABORT (*pi == temp, "array_bsearch"); @@ -97,15 +99,15 @@ main (int argc, char **argv) swaps1 = swaps2 = swaps3 = 0; total1 = total2 = total3 = 0; for (i = 0; i < count; ++i) { - s = sc_array_pqueue_pop (a1, &i1, compar); + s = sc_array_pqueue_pop (a1, &i1, reverse_compare); swaps1 += ((s > 0) ? 1 : 0); total1 += s; - s = sc_array_pqueue_pop (a2, &i2, compar); + s = sc_array_pqueue_pop (a2, &i2, reverse_compare); swaps2 += ((s > 0) ? 1 : 0); total2 += s; - s = sc_array_pqueue_pop (a3, &i3, compar); + s = sc_array_pqueue_pop (a3, &i3, reverse_compare); swaps3 += ((s > 0) ? 1 : 0); total3 += s; @@ -131,7 +133,7 @@ main (int argc, char **argv) for (i = 0; i < count; ++i) { *(int *) sc_array_push (a4) = (15 * i) % 172; } - sc_array_sort (a4, compar); + sc_array_sort (a4, sc_int_compare); i4last = -1; for (i = 0; i < count; ++i) { From d186a93fead6d16c6d747c4509bb25fe06158db5 Mon Sep 17 00:00:00 2001 From: Carsten Burstedde Date: Sun, 21 Dec 2025 16:37:27 +0100 Subject: [PATCH 10/11] Feature pqueue: run indent on sc_containers --- src/sc_containers.c | 36 ++++++++++++++++++++---------------- src/sc_containers.h | 20 ++++++++++---------- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/src/sc_containers.c b/src/sc_containers.c index 3c785b508..8e92a1e23 100644 --- a/src/sc_containers.c +++ b/src/sc_containers.c @@ -677,7 +677,8 @@ sc_array_pqueue_siftup (sc_array_t * array, size_t pos, void *newval, pos = parent; ++swaps; } - else break; + else + break; } memcpy (sc_array_index (array, pos), newval, esize); return swaps; @@ -735,9 +736,11 @@ sc_array_pqueue_siftdown (sc_array_t * array, size_t snn, pos = child; ++swaps; } - else break; + else + break; } - else break; + else + break; } memcpy (sc_array_index (array, pos), newval, esize); return swaps; @@ -770,7 +773,7 @@ sc_array_pqueue_pop (sc_array_t * array, void *newval, /* move last leaf to root and sift down */ --snn; swaps = sc_array_pqueue_siftdown - (array, snn, 0, sc_array_index (array, snn), compar); + (array, snn, 0, sc_array_index (array, snn), compar); /* circumvent calling sc_array_pop */ array->elem_count = snn; @@ -1801,15 +1804,16 @@ sc_recycle_array_remove (sc_recycle_array_t * rec_array, size_t position) /* definitions for inline functions */ -void *sc_array_index (sc_array_t * array, size_t iz); -void *sc_array_index_null (sc_array_t * array, size_t iz); -void *sc_array_index_int (sc_array_t * array, int i); -void *sc_array_index_long (sc_array_t * array, long l); -void *sc_array_index_ssize_t (sc_array_t * array, ssize_t is); -void *sc_array_index_int16 (sc_array_t * array, int16_t i16); -size_t sc_array_position (sc_array_t * array, void *element); -void *sc_array_pop (sc_array_t * array); -void *sc_array_push_count (sc_array_t * array, size_t add_count); -void *sc_array_push (sc_array_t * array); -void *sc_mempool_alloc (sc_mempool_t * mempool); -void sc_mempool_free (sc_mempool_t * mempool, void *elem); +void *sc_array_index (sc_array_t * array, size_t iz); +void *sc_array_index_null (sc_array_t * array, size_t iz); +void *sc_array_index_int (sc_array_t * array, int i); +void *sc_array_index_long (sc_array_t * array, long l); +void *sc_array_index_ssize_t (sc_array_t * array, ssize_t is); +void *sc_array_index_int16 (sc_array_t * array, int16_t i16); +size_t sc_array_position (sc_array_t * array, void *element); +void *sc_array_pop (sc_array_t * array); +void *sc_array_push_count (sc_array_t * array, + size_t add_count); +void *sc_array_push (sc_array_t * array); +void *sc_mempool_alloc (sc_mempool_t * mempool); +void sc_mempool_free (sc_mempool_t * mempool, void *elem); diff --git a/src/sc_containers.h b/src/sc_containers.h index a4dfdb8f2..1879a034c 100644 --- a/src/sc_containers.h +++ b/src/sc_containers.h @@ -528,7 +528,7 @@ size_t sc_array_pqueue_pop (sc_array_t * array, * \param [in] iz Needs to be in [0]..[elem_count-1]. * \return Pointer to the indexed array element. */ -inline void * +inline void * sc_array_index (sc_array_t * array, size_t iz) { SC_ASSERT (iz < array->elem_count); @@ -542,7 +542,7 @@ sc_array_index (sc_array_t * array, size_t iz) * \return Pointer to the indexed array element or * NULL if the specified index is elem_count. */ -inline void * +inline void * sc_array_index_null (sc_array_t * array, size_t iz) { SC_ASSERT (iz <= array->elem_count); @@ -555,7 +555,7 @@ sc_array_index_null (sc_array_t * array, size_t iz) * \param [in] array Valid array. * \param [in] i Needs to be in [0]..[elem_count-1]. */ -inline void * +inline void * sc_array_index_int (sc_array_t * array, int i) { SC_ASSERT (i >= 0 && (size_t) i < array->elem_count); @@ -567,7 +567,7 @@ sc_array_index_int (sc_array_t * array, int i) * \param [in] array Valid array. * \param [in] l Needs to be in [0]..[elem_count-1]. */ -inline void * +inline void * sc_array_index_long (sc_array_t * array, long l) { SC_ASSERT (l >= 0 && (size_t) l < array->elem_count); @@ -579,7 +579,7 @@ sc_array_index_long (sc_array_t * array, long l) * \param [in] array Valid array. * \param [in] is Needs to be in [0]..[elem_count-1]. */ -inline void * +inline void * sc_array_index_ssize_t (sc_array_t * array, ssize_t is) { SC_ASSERT (is >= 0 && (size_t) is < array->elem_count); @@ -591,7 +591,7 @@ sc_array_index_ssize_t (sc_array_t * array, ssize_t is) * \param [in] array Valid array. * \param [in] i16 Needs to be in [0]..[elem_count-1]. */ -inline void * +inline void * sc_array_index_int16 (sc_array_t * array, int16_t i16) { SC_ASSERT (i16 >= 0 && (size_t) i16 < array->elem_count); @@ -623,7 +623,7 @@ sc_array_position (sc_array_t * array, void *element) * \return The pointer to the removed object. Will be valid * as long as no other function is called on this array. */ -inline void * +inline void * sc_array_pop (sc_array_t * array) { SC_ASSERT (SC_ARRAY_IS_OWNER (array)); @@ -636,7 +636,7 @@ sc_array_pop (sc_array_t * array) * This function is not allowed for views. * \return Returns a pointer to the uninitialized newly added elements. */ -inline void * +inline void * sc_array_push_count (sc_array_t * array, size_t add_count) { const size_t old_count = array->elem_count; @@ -658,7 +658,7 @@ sc_array_push_count (sc_array_t * array, size_t add_count) * This function is not allowed for views. * \return Returns a pointer to the uninitialized newly added element. */ -inline void * +inline void * sc_array_push (sc_array_t * array) { return sc_array_push_count (array, 1); @@ -812,7 +812,7 @@ void sc_mempool_truncate (sc_mempool_t * mempool); * Elements previously returned to the pool are recycled. * \return Returns a new or recycled element pointer. */ -inline void * +inline void * sc_mempool_alloc (sc_mempool_t * mempool) { void *ret; From 276e4bd487382773b964a621a7f406b555d4ee45 Mon Sep 17 00:00:00 2001 From: Hannes Brandt Date: Wed, 11 Mar 2026 10:49:52 +0100 Subject: [PATCH 11/11] Feature pqueue: add example and test to cmake --- example/CMakeLists.txt | 1 + test/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 23e68ce96..2708fb2e6 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -29,6 +29,7 @@ sc_example(function function/function.c) sc_example(logging logging/logging.c) sc_example(test_shmem testing/sc_test_shmem.c) sc_example(camera camera/camera.c) +sc_example(sort sort/sort.c) configure_file(options/sc_options_example.ini sc_options_example.ini COPYONLY) configure_file(options/sc_options_example.json sc_options_example.json COPYONLY) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ba59edbd3..ddd9a20ac 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -7,7 +7,7 @@ if(SC_HAVE_RANDOM AND SC_HAVE_SRANDOM) endif() if(SC_HAVE_UNISTD_H) - list(APPEND sc_tests sort) + list(APPEND sc_tests sort pqueue) endif() list(APPEND sc_tests builtin io_sink helpers)