Yet Another eXchange Tool  DO_NOT_EDIT_HERE
xt_idxvec.c
Go to the documentation of this file.
1 
12 /*
13  * Keywords:
14  * Maintainer: Jörg Behrens <behrens@dkrz.de>
15  * Moritz Hanke <hanke@dkrz.de>
16  * Thomas Jahns <jahns@dkrz.de>
17  * URL: https://doc.redmine.dkrz.de/yaxt/html/
18  *
19  * Redistribution and use in source and binary forms, with or without
20  * modification, are permitted provided that the following conditions are
21  * met:
22  *
23  * Redistributions of source code must retain the above copyright notice,
24  * this list of conditions and the following disclaimer.
25  *
26  * Redistributions in binary form must reproduce the above copyright
27  * notice, this list of conditions and the following disclaimer in the
28  * documentation and/or other materials provided with the distribution.
29  *
30  * Neither the name of the DKRZ GmbH nor the names of its contributors
31  * may be used to endorse or promote products derived from this software
32  * without specific prior written permission.
33  *
34  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
35  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
36  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
37  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
38  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
39  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
40  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
41  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
42  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
43  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
44  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45  */
46 #ifdef HAVE_CONFIG_H
47 #include <config.h>
48 #endif
49 
50 #include <assert.h>
51 #include <limits.h>
52 #include <stdbool.h>
53 #include <stdlib.h>
54 #include <stdio.h>
55 #include <string.h>
56 
57 #include "xt/xt_core.h"
58 #include "xt/xt_idxlist.h"
59 #include "xt_idxlist_internal.h"
60 #include "xt/xt_idxempty.h"
61 #include "xt/xt_idxvec.h"
62 #include "xt_idxvec_internal.h"
63 #include "xt/xt_idxstripes.h"
64 #include "xt/xt_mpi.h"
65 #include "xt_idxlist_unpack.h"
66 #include "core/ppm_xfuncs.h"
67 #include "core/core.h"
68 #include "xt_stripe_util.h"
69 #include "xt/quicksort.h"
70 #include "instr.h"
71 
72 #define MIN(a,b) (((a)<(b))?(a):(b))
73 
74 static void
76 
77 static size_t
79 
80 static void
81 idxvec_pack(Xt_idxlist data, void *buffer, int buffer_size,
82  int *position, MPI_Comm comm);
83 
84 static Xt_idxlist
85 idxvec_copy(Xt_idxlist idxlist);
86 
87 static void
88 idxvec_get_indices(Xt_idxlist idxlist, Xt_int *indices);
89 
90 static Xt_int const*
92 
93 static void
94 idxvec_get_index_stripes(Xt_idxlist idxlist, struct Xt_stripe ** stripes,
95  int * num_stripes);
96 
97 static int
98 idxvec_get_index_at_position(Xt_idxlist idxlist, int position, Xt_int * index);
99 
100 static int
101 idxvec_get_indices_at_positions(Xt_idxlist idxlist, const int *positions,
102  int num, Xt_int *index, Xt_int undef_idx);
103 
104 static int
105 idxvec_get_position_of_index(Xt_idxlist idxlist, Xt_int index, int * position);
106 
107 static int
109  int * position, int offset);
110 
111 static int
112 idxvec_get_positions_of_indices(Xt_idxlist idxlist, const Xt_int *indices,
113  int num_indices, int *positions,
114  int single_match_only);
115 
116 static Xt_int
118 
119 static Xt_int
121 
122 static const struct xt_idxlist_vtable idxvec_vtable = {
124  .get_pack_size = idxvec_get_pack_size,
125  .pack = idxvec_pack,
126  .copy = idxvec_copy,
127  .get_indices = idxvec_get_indices,
128  .get_indices_const = idxvec_get_indices_const,
129  .get_index_stripes = idxvec_get_index_stripes,
130  .get_index_at_position = idxvec_get_index_at_position,
131  .get_indices_at_positions = idxvec_get_indices_at_positions,
132  .get_position_of_index = idxvec_get_position_of_index,
133  .get_positions_of_indices = idxvec_get_positions_of_indices,
134  .get_position_of_index_off = idxvec_get_position_of_index_off,
135  .get_positions_of_indices_off = NULL,
136  .get_min_index = idxvec_get_min_index,
137  .get_max_index = idxvec_get_max_index,
138  .get_bounding_box = NULL,
139  .idxlist_pack_code = VECTOR,
140 };
141 
142 typedef struct Xt_idxvec_ *Xt_idxvec;
143 
144 // index vector data structure
145 struct Xt_idxvec_ {
146 
148 
149  const Xt_int *vector;
150 
151  // internal array used to optimise access to vector data
152  const Xt_int *sorted_vector; // sorted version of vector
153  int *sorted_vec_positions; // original positions of the
154  // indices in sorted_vector
155  /*
156  we have the following relations:
157  sorted_vector[i-1] <= sorted_vector[i],
158  vector[sorted_vec_positions[i]] = sorted_vector[i]
159  */
160 };
161 
162 
164  INSTR_DEF(t_idxvec_new,"xt_idxvec_new")
165  if (num_indices > 0)
166  ;
167  else if (num_indices == 0)
168  return xt_idxempty_new();
169  else
170  die("number of indices passed to xt_idxvec_new must not be negative!");
171 
172  INSTR_START(t_idxvec_new);
173  size_t vector_size = (size_t)num_indices * sizeof (idxvec[0]),
174  header_size = ((sizeof (struct Xt_idxvec_) + sizeof (Xt_int) - 1)
175  /sizeof (Xt_int)) * sizeof (Xt_int);
176  struct Xt_idxvec_ *restrict idxvec_obj = xmalloc(header_size + vector_size);
177  Xt_idxlist_init(&idxvec_obj->parent, &idxvec_vtable, num_indices);
178 
179  Xt_int *vector_assign = (Xt_int *)(void *)((unsigned char *)idxvec_obj + header_size);
180  idxvec_obj->vector = vector_assign;
181  memcpy(vector_assign, idxvec, vector_size);
182  idxvec_obj->sorted_vector = NULL;
183  idxvec_obj->sorted_vec_positions = NULL;
184 
185  INSTR_STOP(t_idxvec_new);
186  return (void *)idxvec_obj;
187 }
188 
189 Xt_idxlist xt_idxvec_prealloc_new(const Xt_int *idxvec, int num_indices)
190 {
191  if (num_indices > 0)
192  ;
193  else if (num_indices == 0)
194  return xt_idxempty_new();
195  else
196  die("number of indices passed to xt_idxvec_new must not be negative!");
197  struct Xt_idxvec_ *restrict idxvec_obj = xmalloc(sizeof (*idxvec_obj));
198  Xt_idxlist_init(&idxvec_obj->parent, &idxvec_vtable, num_indices);
199  idxvec_obj->vector = idxvec;
200  idxvec_obj->sorted_vector = NULL;
201  idxvec_obj->sorted_vec_positions = NULL;
202  return (void *)idxvec_obj;
203 }
204 
205 static int
207  int * sorted_vec_pos, int pos_offset) {
208 
209  if (stripe.stride >= 0) {
210  for (int i = 0; i < stripe.nstrides; ++i) {
211  sorted_vector[i] = (Xt_int)(stripe.start + i * stripe.stride);
212  sorted_vec_pos[i] = pos_offset + i;
213  }
214  } else {
215  for (int i = 0; i < stripe.nstrides; ++i) {
216  int j = stripe.nstrides - i - 1;
217  sorted_vector[j] = (Xt_int)(stripe.start + i * stripe.stride);
218  sorted_vec_pos[j] = pos_offset + i;
219  }
220  }
221 
222  return stripe.nstrides;
223 }
224 
225 #define MAX(a,b) ((a) >= (b) ? (a) : (b))
226 
227 static void
229  int num_stripes_,
230  Xt_idxvec idxvec) {
231 
232  if (num_stripes_ <= 0) {
233  idxvec->sorted_vector = NULL;
234  idxvec->sorted_vec_positions = NULL;
235  return;
236  }
237 
238  size_t num_stripes = (size_t)num_stripes_;
239  Xt_int *restrict sorted_vector_assign
240  = xmalloc((size_t)idxvec->parent.num_indices
241  * sizeof(*(idxvec->sorted_vector)));
242  idxvec->sorted_vector = sorted_vector_assign;
243  idxvec->sorted_vec_positions
244  = xmalloc((size_t)idxvec->parent.num_indices *
245  sizeof(*(idxvec->sorted_vec_positions)));
246 
247  /* stripe_minmax[0][i] is the minimal index in stripe i at first,
248  * later of sorted stripe i, stripe_minmax[1][i] is the
249  * corresponding maximal index */
250  Xt_int (*restrict stripe_minmax)[num_stripes]
251  = xmalloc(2 * sizeof(*stripe_minmax));
252  int *restrict sorted_stripe_min_pos
253  = xmalloc(num_stripes * 3 * sizeof(*sorted_stripe_min_pos));
254 
255  for(size_t i = 0; i < num_stripes; ++i) {
256  Xt_int ofs = (Xt_int)(stripes[i].stride * (stripes[i].nstrides - 1)),
257  mask = Xt_isign_mask(ofs);
258  stripe_minmax[0][i] = (Xt_int)(stripes[i].start + (ofs & mask));
259  }
260 
261  xt_quicksort_index(stripe_minmax[0], (int)num_stripes,
262  sorted_stripe_min_pos, 1);
263 
264  int *restrict sorted_pos_prefix_sum, *restrict orig_pos_prefix_sum;
265 
266  sorted_pos_prefix_sum
267  = sorted_stripe_min_pos + num_stripes;
268  orig_pos_prefix_sum
269  = xmalloc(num_stripes * sizeof(*orig_pos_prefix_sum));
270 
271  orig_pos_prefix_sum[0] = 0;
272  for (size_t i = 1; i < num_stripes; ++i)
273  orig_pos_prefix_sum[i] = orig_pos_prefix_sum[i-1] + stripes[i-1].nstrides;
274 
275  for (size_t i = 0; i < num_stripes; ++i) {
276  sorted_pos_prefix_sum[i] = orig_pos_prefix_sum[sorted_stripe_min_pos[i]];
277  int sorted_pos = sorted_stripe_min_pos[i];
278  Xt_int ofs = (Xt_int)(stripes[sorted_pos].stride
279  * (stripes[sorted_pos].nstrides - 1)),
280  mask = Xt_isign_mask(ofs);
281  stripe_minmax[1][i] = (Xt_int)(stripes[sorted_pos].start + (ofs & ~mask));
282  }
283 
284  free(orig_pos_prefix_sum);
285 
286  /* i'th stripe overlaps with overlap_count[i] following stripes, or
287  * is part of a stretch of this many overlapping stripes, if
288  * overlap_count[i] is > 0, in case overlap_count[i] <= 0, this many
289  * non-overlapping stripes follow after negation + 1 */
290  int *restrict overlap_count
291  = sorted_stripe_min_pos + 2 * num_stripes;
292  for (size_t i = 0; i < num_stripes - 1; ++i) {
293  bool do_overlap = stripe_minmax[1][i] >= stripe_minmax[0][i + 1];
294  size_t j = i + 1;
295  if (do_overlap) {
296  /* range_max_idx is the maximal index encountered in a rage of
297  * overlapping stripes, only stop when a stripe starting at
298  * index larger than this is encountered */
299  Xt_int range_max_idx = MAX(stripe_minmax[1][i], stripe_minmax[1][i+1]);
300  while (j + 1 < num_stripes
301  && stripe_minmax[0][j + 1] <= range_max_idx) {
302  range_max_idx = MAX(range_max_idx, stripe_minmax[1][j+1]);
303  ++j;
304  }
305  overlap_count[i] = (int)(j - i);
306  i = j;
307  } else {
308  while (j + 1 < num_stripes
309  && stripe_minmax[0][j + 1] > stripe_minmax[1][j])
310  ++j;
311  overlap_count[i] = -(int)(j - i - 1);
312  i = j - 1;
313  }
314  }
315  overlap_count[num_stripes - 1] = 0;
316 
317  Xt_int offset = 0;
318 
319  size_t i = 0;
320  while (i < num_stripes) {
321 
322  bool do_overlap = overlap_count[i] > 0;
323  size_t num_selection = (size_t)(abs(overlap_count[i])) + 1;
324  Xt_int curr_offset = 0;
325 
326  for (size_t j = 0; j < num_selection; ++j)
327  curr_offset
328  = (Xt_int)(curr_offset
329  + decode_stripe(stripes[sorted_stripe_min_pos[i+j]],
330  sorted_vector_assign + offset
331  + curr_offset,
332  idxvec->sorted_vec_positions + offset
333  + curr_offset,
334  sorted_pos_prefix_sum[i+j]));
335 
336  if (do_overlap)
337  xt_quicksort_index(sorted_vector_assign + offset, (int)curr_offset,
338  idxvec->sorted_vec_positions + offset, 0);
339 
340  offset = (Xt_int)(offset + curr_offset);
341  i += num_selection;
342  }
343 
344  free(sorted_stripe_min_pos);
345  free(stripe_minmax);
346 }
347 
349 xt_idxvec_from_stripes_new(const struct Xt_stripe stripes[],
350  int num_stripes) {
351 
352  long long num_indices = 0;
353 
354  for (int i = 0; i < num_stripes; ++i)
355  num_indices += stripes[i].nstrides;
356  assert((sizeof (long long) > sizeof (int)) & (num_indices <= INT_MAX)
357  & (num_indices >= 0));
358 
359  size_t vector_size = (size_t)num_indices * sizeof (Xt_int),
360  header_size = ((sizeof (struct Xt_idxvec_) + sizeof (Xt_int) - 1)
361  /sizeof (Xt_int)) * sizeof (Xt_int);
362  Xt_idxvec idxvec_obj = xmalloc(header_size + vector_size);
363 
364  Xt_int *restrict indices
365  = (Xt_int *)(void *)((unsigned char *)idxvec_obj + header_size);
366  idxvec_obj->vector = indices;
367 
368  size_t k = (size_t)-1;
369  for (int i = 0; i < num_stripes; ++i)
370  for (int j = 0; j < stripes[i].nstrides; ++j)
371  indices[++k] = (Xt_int)(stripes[i].start + j * stripes[i].stride);
372 
373  Xt_idxlist_init(&idxvec_obj->parent, &idxvec_vtable, (int)num_indices);
374 
375  generate_sorted_vector_from_stripes(stripes, num_stripes, idxvec_obj);
376 
377  return (Xt_idxlist)idxvec_obj;
378 }
379 
380 static void idxvec_delete(Xt_idxlist obj) {
381 
382  if (((Xt_idxvec)obj)->sorted_vector !=
383  ((Xt_idxvec)obj)->vector)
384  free((void *)(((Xt_idxvec)obj)->sorted_vector));
385  free(((Xt_idxvec)obj)->sorted_vec_positions);
386  free(obj);
387 }
388 
389 static size_t idxvec_get_pack_size(Xt_idxlist obj, MPI_Comm comm) {
390 
391  Xt_idxvec idxvec = (Xt_idxvec)obj;
392  int size_xt_idx, size_int_type;
393 
394  xt_mpi_call(MPI_Pack_size(2, MPI_INT, comm, &size_int_type), comm);
395  xt_mpi_call(MPI_Pack_size(idxvec->parent.num_indices, Xt_int_dt, comm,
396  &size_xt_idx), comm);
397 
398  return (size_t)size_xt_idx + (size_t)size_int_type;
399 }
400 
401 void idxvec_pack(Xt_idxlist obj, void *buffer, int buffer_size,
402  int *position, MPI_Comm comm) {
403 
404  assert(obj);
405  Xt_idxvec idxvec = (Xt_idxvec)obj;
406  int type = VECTOR;
407 
408  xt_mpi_call(MPI_Pack(&(type), 1, MPI_INT, buffer,
409  buffer_size, position, comm), comm);
410  xt_mpi_call(MPI_Pack(&(idxvec->parent.num_indices), 1, MPI_INT, buffer,
411  buffer_size, position, comm), comm);
412  if (idxvec->parent.num_indices != 0)
413  xt_mpi_call(MPI_Pack((Xt_int *)idxvec->vector, idxvec->parent.num_indices,
414  Xt_int_dt, buffer,
415  buffer_size, position, comm), comm);
416 }
417 
418 Xt_idxlist xt_idxvec_unpack(void *buffer, int buffer_size, int *position,
419  MPI_Comm comm) {
420 
421  int num_indices;
422 
423  xt_mpi_call(MPI_Unpack(buffer, buffer_size, position,
424  &num_indices, 1, MPI_INT, comm), comm);
425 
426  size_t vector_size = (size_t)num_indices * sizeof (Xt_int),
427  header_size = ((sizeof (struct Xt_idxvec_) + sizeof (Xt_int) - 1)
428  /sizeof (Xt_int)) * sizeof (Xt_int);
429  Xt_idxvec idxvec = xmalloc(header_size + vector_size);
430  Xt_idxlist_init(&idxvec->parent, &idxvec_vtable, num_indices);
431 
432  Xt_int *vector_assign = (Xt_int *)(void *)((unsigned char *)idxvec + header_size);
433  idxvec->vector = vector_assign;
434  if (num_indices != 0) {
435  xt_mpi_call(MPI_Unpack(buffer, buffer_size, position,
436  vector_assign, num_indices,
437  Xt_int_dt, comm), comm);
438  } else {
439  fputs("warning: implementation generated empty vector!\n", stderr);
440  idxvec->vector = NULL;
441  }
442 
443  idxvec->sorted_vector = NULL;
444  idxvec->sorted_vec_positions = NULL;
445 
446  return (Xt_idxlist)idxvec;
447 }
448 
449 static const Xt_int *
450 get_sorted_vector(Xt_idxvec idxvec) {
451 
452  if (idxvec->sorted_vector != NULL)
453  return idxvec->sorted_vector;
454 
455  size_t num_indices = (size_t)idxvec->parent.num_indices;
456  idxvec->sorted_vec_positions = xmalloc((size_t)num_indices *
457  sizeof(*(idxvec->sorted_vec_positions)));
458 
459 
460  bool sorted = true;
461  // check if we are already sorted:
462  for (size_t i = 1; i < num_indices; ++i)
463  sorted &= (idxvec->vector[i-1] <= idxvec->vector[i]);
464 
465  /* we are done if vector is already sorted */
466  if (sorted) {
467  // gen id-map:
468  for (size_t i = 0; i < num_indices; ++i)
469  idxvec->sorted_vec_positions[i] = (int)i;
470  return idxvec->sorted_vector = idxvec->vector;
471  }
473  = xmalloc((size_t)num_indices * sizeof(*sorted_vector));
474 
475  memcpy(sorted_vector, idxvec->vector,
476  (size_t)num_indices * sizeof(*sorted_vector));
477 
478  xt_quicksort_index(sorted_vector, (int)num_indices,
479  idxvec->sorted_vec_positions, 1);
480 
481  idxvec->sorted_vector = sorted_vector;
482 
483  return sorted_vector;
484 }
485 
488 
489  // both lists are index vectors:
490 
491  Xt_idxvec idxvec_src = (Xt_idxvec)idxlist_src,
492  idxvec_dst = (Xt_idxvec)idxlist_dst;
493 
494 
495  size_t num_indices_inter = 0,
496  num_indices_src = (size_t)idxvec_src->parent.num_indices,
497  num_indices_dst = (size_t)idxvec_dst->parent.num_indices;
498 
499  size_t vector_size = num_indices_dst * sizeof (idxvec_dst->vector[0]),
500  header_size = ((sizeof (struct Xt_idxvec_) + sizeof (Xt_int) - 1)
501  /sizeof (Xt_int)) * sizeof (Xt_int);
502 
503  Xt_idxvec inter_vector = xmalloc(header_size + vector_size);
504 
505  Xt_int *vector_assign
506  = (Xt_int *)(void *)((unsigned char *)inter_vector + header_size);
507  inter_vector->vector = vector_assign;
508 
509  const Xt_int *restrict sorted_src_vector, *restrict sorted_dst_vector;
510 
511  // get sorted indices of source and destination
512 
513  sorted_src_vector = get_sorted_vector(idxvec_src);
514  sorted_dst_vector = get_sorted_vector(idxvec_dst);
515 
516  // compute the intersection
517 
518  for (size_t i = 0, j = 0; i < num_indices_dst; ++i) {
519 
520  while (j < num_indices_src &&
521  sorted_src_vector[j] < sorted_dst_vector[i]) ++j;
522  if (j >= num_indices_src) break;
523  if (sorted_src_vector[j] == sorted_dst_vector[i])
524  vector_assign[num_indices_inter++] = sorted_dst_vector[i];
525  }
526 
527  if (num_indices_inter) {
528  vector_size = (size_t)num_indices_inter * sizeof (idxvec_dst->vector[0]);
529  inter_vector = xrealloc(inter_vector, header_size + vector_size);
530  inter_vector->vector
531  = (Xt_int *)(void *)((unsigned char *)inter_vector + header_size);
532  } else {
533  free(inter_vector);
534  return xt_idxempty_new();
535  }
536 
537  Xt_idxlist_init(&inter_vector->parent, &idxvec_vtable, (int)num_indices_inter);
538  inter_vector->sorted_vector = NULL;
539  inter_vector->sorted_vec_positions = NULL;
540 
541  return (Xt_idxlist)inter_vector;
542 }
543 
544 static Xt_idxlist
546 
547  Xt_idxvec idxvec_obj = (Xt_idxvec)idxlist;
548 
549  return xt_idxvec_new(idxvec_obj->vector, idxvec_obj->parent.num_indices);
550 }
551 
552 static void
554 
555  Xt_idxvec idxvec_obj = (Xt_idxvec)idxlist;
556 
557  memcpy(indices, idxvec_obj->vector,
558  (size_t)idxvec_obj->parent.num_indices * sizeof(*indices));
559 }
560 
561 static Xt_int const*
563  Xt_idxvec idxvec = (Xt_idxvec)idxlist;
564 
565  return idxvec->vector;
566 }
567 
568 
569 static void
570 idxvec_get_index_stripes(Xt_idxlist idxlist, struct Xt_stripe ** stripes,
571  int * num_stripes) {
572 
573  Xt_idxvec idxvec_obj = (Xt_idxvec)idxlist;
574 
576  idxvec_obj->parent.num_indices,
577  stripes, num_stripes);
578 }
579 
580 static int
581 idxvec_get_index_at_position(Xt_idxlist idxlist, int position, Xt_int * index) {
582 
583  Xt_idxvec idxvec_obj = (Xt_idxvec)idxlist;
584 
585  if (position < 0 || position >= idxvec_obj->parent.num_indices)
586  return 1;
587 
588  *index = idxvec_obj->vector[position];
589 
590  return 0;
591 }
592 
593 static int
595  const int *restrict positions,
596  int num_pos_, Xt_int *index,
597  Xt_int undef_idx) {
598 
599  Xt_idxvec idxvec = (Xt_idxvec)idxlist;
600  size_t num_indices = (size_t)idxvec->parent.num_indices;
601  const Xt_int *restrict v = idxvec->vector;
602 
603  int undef_count = 0;
604  size_t num_pos = num_pos_ >= 0 ? (size_t)num_pos_ : (size_t)0;
605  for (size_t ip = 0; ip < num_pos; ip++) {
606  int p = positions[ip];
607  if (p >= 0 && (size_t)p < num_indices) {
608  index[ip] = v[p];
609  } else {
610  index[ip] = undef_idx;
611  undef_count++;
612  }
613  }
614 
615  return undef_count;
616 }
617 
621 static int
623  int * position, int offset) {
624 
625  Xt_idxvec idxvec_obj = (Xt_idxvec)idxlist;
626 
627  *position = -1;
628 
629  size_t num_indices = (size_t)idxvec_obj->parent.num_indices;
630  if ((offset < 0) || ((size_t)offset >= num_indices))
631  return 1;
632 
633  const Xt_int *sorted_vector = get_sorted_vector(idxvec_obj);
634 
635  if ((index < sorted_vector[0]) ||
636  (index > sorted_vector[num_indices-1]))
637  return 1;
638 
639  // bisection to find one matching position:
640  size_t lb = 0;
641  size_t ub = num_indices - 1;
642 
643  while (sorted_vector[lb] < index) {
644 
645  size_t middle = (ub + lb + 1)/2;
646 
647  if (sorted_vector[middle] <= index)
648  lb = middle;
649  else if (ub == middle)
650  return 1;
651  else
652  ub = middle;
653  }
654 
655  // find left most match:
656  while (lb > 0 && sorted_vector[lb-1] == index) --lb;
657 
658  // go forward until offset condition is satisfied:
659  while (lb < num_indices - 1 && // boundary condition
660  idxvec_obj->sorted_vec_positions[lb] < offset && // ignore postions left of offset
661  sorted_vector[lb] == index) ++lb; // check if index is valid
662 
663  // check if position is invalid:
664  if (lb >= num_indices || sorted_vector[lb] != index)
665  return 1; // failure
666 
667  // result:
668  *position = idxvec_obj->sorted_vec_positions[lb];
669  return 0;
670 }
671 
672 static int
673 idxvec_get_position_of_index(Xt_idxlist idxlist, Xt_int index, int * position) {
674 
675  return idxvec_get_position_of_index_off(idxlist, index, position, 0);
676 }
677 
678 static bool idx_vec_is_sorted(Xt_int const *idx, size_t n) {
679 
680  if (n>=2)
681  for (size_t i = 1; i < n; i++)
682  if (idx[i] < idx[i-1]) return false;
683 
684  return true;
685 }
686 
687 static int
689  const Xt_int *selection_idx,
690  int num_selection, int *positions,
691  int single_match_only) {
692 
693  if (num_selection <= 0) return 0;
694 
695  bool selection_is_ordered = idx_vec_is_sorted(selection_idx, (size_t)num_selection);
697 
698  Xt_int const *sorted_selection;
699  int *sorted_selection_pos = NULL;
700  Xt_int *tmp_idx = NULL;
701 
702  if (selection_is_ordered) {
703  sorted_selection = selection_idx;
704  } else {
705  size_t idx_memsize = (size_t)num_selection * sizeof(*sorted_selection),
706  pos_memsize = (size_t)num_selection * sizeof(*sorted_selection_pos),
707  /* round pos_memsize up to next multiple of sizeof (int) */
708  pos_ofs = ((idx_memsize + sizeof (int) - 1)
709  & ((size_t)-(ssize_t)(sizeof(int)))),
710  /* compute size of merged allocation */
711  alloc_size = pos_ofs + pos_memsize;
712 
713  tmp_idx = xmalloc(alloc_size);
714  memcpy(tmp_idx, selection_idx, idx_memsize);
715 
716  sorted_selection_pos
717  = (void *)((unsigned char *)tmp_idx + pos_ofs);
718  xt_quicksort_index(tmp_idx, num_selection, sorted_selection_pos, 1);
719  sorted_selection = tmp_idx;
720  }
721 
722  /* motivation for usage of single_match_only:
723  * on the target side we want single_match_only,
724  * on the source side we don't
725  */
726  Xt_idxvec body_idxvec = (Xt_idxvec)body_idxlist;
727  const Xt_int *sorted_body = get_sorted_vector(body_idxvec);
728  int *sorted_body_pos = body_idxvec->sorted_vec_positions;
729  size_t search_end = (size_t)body_idxvec->parent.num_indices - 1;
730  int num_unmatched = 0;
731 
732  // after the match we will move on one step in order to avoid matching the same position again
733  size_t post_match_step = single_match_only != 0;
734 
735  size_t i=0;
736  for (size_t search_start = 0, ub_guess_ofs = 1;
737  i < (size_t)num_selection && search_start<=search_end;
738  ++i) {
739  size_t selection_pos = selection_is_ordered ? i : (size_t)sorted_selection_pos[i];
740  Xt_int isel = sorted_selection[i];
741  // bisection to find one matching position:
742  size_t ub = MIN(search_start + ub_guess_ofs, search_end);
743  size_t lb = search_start;
744  /* guess too low? */
745  if (sorted_body[ub] < isel) {
746  lb = MIN(ub + 1, search_end);
747  ub = search_end;
748  }
749  /* dividing (ub-lb) by 2 gives 0 iff (ub-lb) < 2 but uses less
750  * instructions than comparing to literal 1 */
751  while ((ub-lb)/16) {
752  size_t middle = (ub + lb + 1) / 2;
753  /* todo: make branch free with mask/inv mask by predicate */
754  if (sorted_body[middle] <= isel)
755  lb = middle;
756  else
757  ub = middle;
758  }
759  /* use linear scan for last part of search */
760  while (sorted_body[lb] < isel && lb < ub)
761  ++lb;
762  size_t match_pos;
763  // search is now narrowed to two positions, select one of them:
764  if (isel == sorted_body[lb]) {
765  match_pos = lb;
766  } else {
767  num_unmatched++;
768  positions[selection_pos] = -1;
769  continue;
770  }
771 
772  // find left most match >= search_start (bisection can lead to any match >= search_start)
773  while (match_pos > search_start && sorted_body[match_pos-1] == isel)
774  --match_pos;
775 
776  // result:
777  // update positions and prepare next search:
778  positions[selection_pos] = sorted_body_pos[match_pos];
779  ub_guess_ofs = match_pos - search_start;
780  search_start = match_pos + post_match_step;
781  }
782  if (i < (size_t)num_selection) {
783  num_unmatched += (int)((size_t)num_selection - i);
784  if (selection_is_ordered)
785  do {
786  positions[i] = -1;
787  } while (++i < (size_t)num_selection);
788  else
789  do {
790  positions[sorted_selection_pos[i]] = -1;
791  } while (++i < (size_t)num_selection);
792  }
793  if (tmp_idx) free(tmp_idx);
794 
795  return num_unmatched;
796 }
797 
798 static Xt_int
800 
801  Xt_idxvec idxvec_obj = (Xt_idxvec)idxlist;
802 
803  if (!idxvec_obj->parent.num_indices)
804  die("idxvec_get_min_index: empty index vector");
805 
806  return get_sorted_vector(idxvec_obj)[0];
807 }
808 
809 static Xt_int
811 
812  Xt_idxvec idxvec_obj = (Xt_idxvec)idxlist;
813 
814  if (!idxvec_obj->parent.num_indices)
815  die("idxvec_get_max_index: empty index vector");
816 
817  return get_sorted_vector(idxvec_obj)[idxvec_obj->parent.num_indices-1];
818 }
819 
820 /*
821  * Local Variables:
822  * c-basic-offset: 2
823  * coding: utf-8
824  * indent-tabs-mode: nil
825  * show-trailing-whitespace: t
826  * require-trailing-newline: t
827  * End:
828  */
struct Xt_idxlist_ parent
Definition: xt_idxvec.c:147
base definitions header file
#define die(msg)
Definition: core.h:131
static int idxvec_get_position_of_index_off(Xt_idxlist idxlist, Xt_int index, int *position, int offset)
Definition: xt_idxvec.c:622
const Xt_int * sorted_vector
Definition: xt_idxvec.c:152
static void idxvec_delete(Xt_idxlist data)
Definition: xt_idxvec.c:380
#define INSTR_START(T)
Definition: instr.h:68
const Xt_int * vector
Definition: xt_idxvec.c:149
add versions of standard API functions not returning on error
static void idxvec_get_index_stripes(Xt_idxlist idxlist, struct Xt_stripe **stripes, int *num_stripes)
Definition: xt_idxvec.c:570
static size_t idxvec_get_pack_size(Xt_idxlist data, MPI_Comm comm)
Definition: xt_idxvec.c:389
Xt_idxlist xt_idxvec_from_stripes_new(const struct Xt_stripe stripes[], int num_stripes)
Definition: xt_idxvec.c:349
int * sorted_vec_positions
Definition: xt_idxvec.c:153
#define MAX(a, b)
Definition: xt_idxvec.c:225
#define xrealloc(ptr, size)
Definition: ppm_xfuncs.h:67
void xt_convert_indices_to_stripes(const Xt_int *indices, int num_indices, struct Xt_stripe **stripes, int *num_stripes)
#define MIN(a, b)
Definition: xt_idxvec.c:72
int nstrides
Definition: xt_stripe.h:57
static void idxvec_get_indices(Xt_idxlist idxlist, Xt_int *indices)
Definition: xt_idxvec.c:553
static Xt_int idxvec_get_min_index(Xt_idxlist idxlist)
Definition: xt_idxvec.c:799
Xt_idxlist xt_idxempty_new(void)
Definition: xt_idxempty.c:165
static const Xt_int * get_sorted_vector(Xt_idxvec idxvec)
Definition: xt_idxvec.c:450
XT_INT Xt_int
Definition: xt_core.h:68
static bool idx_vec_is_sorted(Xt_int const *idx, size_t n)
Definition: xt_idxvec.c:678
static void generate_sorted_vector_from_stripes(const struct Xt_stripe stripes[], int num_stripes_, Xt_idxvec idxvec)
Definition: xt_idxvec.c:228
Provide non-public declarations common to all index lists.
static Xt_int Xt_isign_mask(Xt_int x)
struct Xt_idxvec_ * Xt_idxvec
Definition: xt_idxvec.c:142
void xt_quicksort_index(Xt_int *v_idx, int n, int *v_pos, int reset_pos)
Definition: quicksort.c:77
static void Xt_idxlist_init(Xt_idxlist idxlist, const struct xt_idxlist_vtable *vtable, int num_indices)
static void idxvec_pack(Xt_idxlist data, void *buffer, int buffer_size, int *position, MPI_Comm comm)
Definition: xt_idxvec.c:401
Xt_int stride
Definition: xt_stripe.h:56
static const struct xt_idxlist_vtable idxvec_vtable
Definition: xt_idxvec.c:122
static int decode_stripe(struct Xt_stripe stripe, Xt_int *sorted_vector, int *sorted_vec_pos, int pos_offset)
Definition: xt_idxvec.c:206
quicksort declaration
static Xt_idxlist idxvec_copy(Xt_idxlist idxlist)
Definition: xt_idxvec.c:545
#define Xt_int_dt
Definition: xt_core.h:69
static int idxvec_get_indices_at_positions(Xt_idxlist idxlist, const int *positions, int num, Xt_int *index, Xt_int undef_idx)
static int idxvec_get_index_at_position(Xt_idxlist idxlist, int position, Xt_int *index)
Definition: xt_idxvec.c:581
#define INSTR_DEF(T, S)
Definition: instr.h:66
void(* delete)(Xt_idxlist)
static int idxvec_get_position_of_index(Xt_idxlist idxlist, Xt_int index, int *position)
Definition: xt_idxvec.c:673
Xt_idxlist xt_idxvec_unpack(void *buffer, int buffer_size, int *position, MPI_Comm comm)
Definition: xt_idxvec.c:418
Xt_int start
Definition: xt_stripe.h:55
Xt_idxlist xt_idxvec_new(const Xt_int *idxvec, int num_indices)
Definition: xt_idxvec.c:163
#define xt_mpi_call(call, comm)
Definition: xt_mpi.h:68
#define INSTR_STOP(T)
Definition: instr.h:69
index list declaration
Xt_idxlist xt_idxvec_prealloc_new(const Xt_int *idxvec, int num_indices)
Definition: xt_idxvec.c:189
Xt_idxlist xt_idxvec_get_intersection(Xt_idxlist idxlist_src, Xt_idxlist idxlist_dst)
Definition: xt_idxvec.c:487
#define xmalloc(size)
Definition: ppm_xfuncs.h:66
int MPI_Comm
Definition: core.h:64
static int idxvec_get_positions_of_indices(Xt_idxlist idxlist, const Xt_int *indices, int num_indices, int *positions, int single_match_only)
Definition: xt_idxvec.c:688
static Xt_int const * idxvec_get_indices_const(Xt_idxlist idxlist)
Definition: xt_idxvec.c:562
utility routines for MPI
static Xt_int idxvec_get_max_index(Xt_idxlist idxlist)
Definition: xt_idxvec.c:810