1 /*
2
3 Copyright (C) 2008-2020 Michele Martone
4
5 This file is part of librsb.
6
7 librsb is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 librsb is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with librsb; see the file COPYING.
19 If not, see <http://www.gnu.org/licenses/>.
20
21 */
22 /* @cond INNERDOC */
23 /*!
24 * @file
25 * @author Michele Martone
26 * @brief
27 * This source file contains functions for COO handling and check.
28 * */
29
30 #include "rsb_internals.h"
31
32 #define RSB_LIKELY_OMP(EXP) EXP
33
34 RSB_INTERNALS_COMMON_HEAD_DECLS
35
rsb__util_nnz_array_set_sequence(rsb_nnz_idx_t * p,rsb_nnz_idx_t n,rsb_nnz_idx_t o,rsb_nnz_idx_t i)36 void rsb__util_nnz_array_set_sequence(rsb_nnz_idx_t * p, rsb_nnz_idx_t n, rsb_nnz_idx_t o, rsb_nnz_idx_t i)
37 {
38 /*!
39 \ingroup gr_internals
40 TODO: rsb__util_nnz_array_set_sequence -> rsb__nnz_idx_set_sequence
41 */
42 register rsb_nnz_idx_t k;
43
44 RSB_DEBUG_ASSERT(p || n==0);
45 RSB_DEBUG_ASSERT(o>=0);
46 RSB_DEBUG_ASSERT(RSB_IS_VALID_NNZ_INDEX(n));
47 RSB_DEBUG_ASSERT(RSB_IS_VALID_COO_INDEX(o));
48
49 for(k=0;RSB_LIKELY(k<n);++k)
50 {
51 p[k] = o+k*i;
52 }
53 }
54
rsb__util_coo_array_set_sequence(rsb_coo_idx_t * p,rsb_nnz_idx_t n,rsb_coo_idx_t o,rsb_coo_idx_t i)55 void rsb__util_coo_array_set_sequence(rsb_coo_idx_t * p, rsb_nnz_idx_t n, rsb_coo_idx_t o, rsb_coo_idx_t i)
56 {
57 /*!
58 \ingroup gr_internals
59 TODO: rsb__util_coo_array_set_sequence -> rsb__coo_idx_set_sequence
60 */
61 register rsb_nnz_idx_t k;
62
63 RSB_DEBUG_ASSERT(p || n==0);
64 RSB_DEBUG_ASSERT(o>=0);
65 RSB_DEBUG_ASSERT(RSB_IS_VALID_NNZ_INDEX(n));
66 RSB_DEBUG_ASSERT(RSB_IS_VALID_COO_INDEX(o));
67
68 for(k=0;RSB_LIKELY(k<n);++k)
69 {
70 p[k] = o+k*i;
71 }
72 }
73
rsb__util_nnz_array_set(rsb_nnz_idx_t * p,rsb_nnz_idx_t n,rsb_nnz_idx_t a)74 void rsb__util_nnz_array_set(rsb_nnz_idx_t * p, rsb_nnz_idx_t n, rsb_nnz_idx_t a)
75 {
76 /*!
77 \ingroup gr_internals
78 Adds s from the given matrix coordinate indices array.
79 */
80 register rsb_nnz_idx_t k;
81
82 RSB_DEBUG_ASSERT(p || n==0);
83 RSB_DEBUG_ASSERT(a>=0);
84 RSB_DEBUG_ASSERT(RSB_IS_VALID_NNZ_INDEX(n));
85 RSB_DEBUG_ASSERT(RSB_IS_VALID_COO_INDEX(a));
86
87 for(k=0;RSB_LIKELY(k<n);++k)
88 {
89 p[k] = a;
90 }
91 }
92
rsb__util_coo_array_set(rsb_coo_idx_t * p,rsb_nnz_idx_t n,rsb_coo_idx_t a)93 void rsb__util_coo_array_set(rsb_coo_idx_t * p, rsb_nnz_idx_t n, rsb_coo_idx_t a)
94 {
95 /*!
96 \ingroup gr_internals
97 Adds s from the given matrix coordinate indices array.
98 */
99 register rsb_nnz_idx_t k;
100
101 RSB_DEBUG_ASSERT(p || n==0);
102 RSB_DEBUG_ASSERT(a>=0);
103 RSB_DEBUG_ASSERT(RSB_IS_VALID_NNZ_INDEX(n));
104 RSB_DEBUG_ASSERT(RSB_IS_VALID_COO_INDEX(a) || a==RSB_MARKER_COO_VALUE);
105
106 for(k=0;RSB_LIKELY(k<n);++k)
107 {
108 p[k] = a;
109 }
110 }
111
rsb__util_hcoo_array_copy_trans_add(rsb_coo_idx_t * d,const rsb_half_idx_t * s,rsb_nnz_idx_t n,rsb_coo_idx_t a)112 void rsb__util_hcoo_array_copy_trans_add(rsb_coo_idx_t * d, const rsb_half_idx_t * s, rsb_nnz_idx_t n, rsb_coo_idx_t a)
113 {
114 /*!
115 \ingroup gr_internals
116 Adds s from the given matrix coordinate indices array.
117 */
118 register rsb_nnz_idx_t k;
119
120 RSB_DEBUG_ASSERT(s);
121 RSB_DEBUG_ASSERT(d);
122 RSB_DEBUG_ASSERT(a>=0);
123 RSB_DEBUG_ASSERT(RSB_IS_VALID_NNZ_INDEX(n));
124
125 for(k=0;RSB_LIKELY(k+3<n);k+=4)
126 {
127 /* RSB_DEBUG_ASSERT(RSB_IS_VALID_COO_INDEX(d[k])); */
128 RSB_DEBUG_ASSERT(RSB_IS_VALID_COO_INDEX(a+s[k]));
129 d[k+0] = a+s[k+0];
130 d[k+1] = a+s[k+1];
131 d[k+2] = a+s[k+2];
132 d[k+3] = a+s[k+3];
133 RSB_DEBUG_ASSERT(RSB_IS_VALID_COO_INDEX(d[k]));
134 }
135 for(;(k<n);k+=1)
136 d[k] = s[k]+a;
137 }
138
rsb__util_coo_array_copy_trans_add(rsb_coo_idx_t * d,const rsb_coo_idx_t * s,rsb_nnz_idx_t n,rsb_coo_idx_t a)139 void rsb__util_coo_array_copy_trans_add(rsb_coo_idx_t * d, const rsb_coo_idx_t * s, rsb_nnz_idx_t n, rsb_coo_idx_t a)
140 {
141 /*!
142 \ingroup gr_internals
143 Adds s from the given matrix coordinate indices array.
144 */
145 register rsb_nnz_idx_t k;
146
147 RSB_DEBUG_ASSERT(s);
148 RSB_DEBUG_ASSERT(d);
149 RSB_DEBUG_ASSERT(a>=0);
150 RSB_DEBUG_ASSERT(RSB_IS_VALID_NNZ_INDEX(n));
151
152 for(k=0;RSB_LIKELY(k+3<n);k+=4)
153 {
154 /* RSB_DEBUG_ASSERT(RSB_IS_VALID_COO_INDEX(d[k])); */
155 RSB_DEBUG_ASSERT(RSB_IS_VALID_COO_INDEX(a+s[k]));
156 d[k+0] = a+s[k+0];
157 d[k+1] = a+s[k+1];
158 d[k+2] = a+s[k+2];
159 d[k+3] = a+s[k+3];
160 RSB_DEBUG_ASSERT(RSB_IS_VALID_COO_INDEX(d[k]));
161 }
162 for(;(k<n);k+=1)
163 d[k] = s[k]+a;
164 }
165
rsb__util_coo_array_mul(rsb_coo_idx_t * p,rsb_nnz_idx_t n,rsb_coo_idx_t a)166 void rsb__util_coo_array_mul(rsb_coo_idx_t * p, rsb_nnz_idx_t n, rsb_coo_idx_t a)
167 {
168 /*!
169 \ingroup gr_internals
170 */
171 register rsb_nnz_idx_t k;
172
173 RSB_DEBUG_ASSERT(p || n==0);
174 RSB_DEBUG_ASSERT(a>=0);
175 RSB_DEBUG_ASSERT(RSB_IS_VALID_NNZ_INDEX(n));
176
177 if(a)
178 for(k=0;RSB_LIKELY(k<n);++k)
179 {
180 RSB_DEBUG_ASSERT(RSB_IS_VALID_COO_INDEX(p[k]));
181 p[k] *= a;
182 RSB_DEBUG_ASSERT(RSB_IS_VALID_COO_INDEX(p[k]));
183 }
184 }
185
rsb__util_coo_arrays_mul(rsb_coo_idx_t * p,rsb_coo_idx_t * q,rsb_coo_idx_t a,rsb_coo_idx_t b,rsb_nnz_idx_t n)186 void rsb__util_coo_arrays_mul(rsb_coo_idx_t * p, rsb_coo_idx_t * q, rsb_coo_idx_t a, rsb_coo_idx_t b, rsb_nnz_idx_t n)
187 {
188 /*!
189 TODO : document this.
190 */
191 rsb__util_coo_array_mul(p,n,a);
192 rsb__util_coo_array_mul(q,n,b);
193 }
194
rsb__util_coo_array_add(rsb_coo_idx_t * p,rsb_nnz_idx_t n,rsb_coo_idx_t a)195 void rsb__util_coo_array_add(rsb_coo_idx_t * p, rsb_nnz_idx_t n, rsb_coo_idx_t a)
196 {
197 /*!
198 \ingroup gr_internals
199 Adds s from the given matrix coordinate indices array.
200 */
201 register rsb_nnz_idx_t k;
202
203 RSB_DEBUG_ASSERT(p || n==0);
204 /* RSB_DEBUG_ASSERT(a>=0); */
205 RSB_DEBUG_ASSERT(a>=-1); /* FIXME: -1 is sometimes necessary for Fortran cases ... */
206 RSB_DEBUG_ASSERT(RSB_IS_VALID_NNZ_INDEX(n));
207
208 if(a)
209 for(k=0;RSB_LIKELY(k<n);++k)
210 {
211 RSB_DEBUG_ASSERT(RSB_IS_VALID_COO_INDEX(p[k]));
212 p[k] += a;
213 RSB_DEBUG_ASSERT(RSB_IS_VALID_COO_INDEX(p[k]));
214 }
215 }
216
rsb__util_hcoo_array_add(rsb_half_idx_t * p,rsb_nnz_idx_t n,rsb_coo_idx_t a)217 void rsb__util_hcoo_array_add(rsb_half_idx_t * p, rsb_nnz_idx_t n, rsb_coo_idx_t a)
218 {
219 /*!
220 \ingroup gr_internals
221 Adds s from the given matrix coordinate indices array.
222 */
223 register rsb_nnz_idx_t k;
224
225 RSB_DEBUG_ASSERT(p || n==0);
226 RSB_DEBUG_ASSERT(a>=0);
227 RSB_DEBUG_ASSERT(RSB_IS_VALID_NNZ_INDEX(n));
228
229 if(a)
230 for(k=0;RSB_LIKELY(k<n);++k)
231 {
232 RSB_DEBUG_ASSERT(RSB_IS_VALID_COO_INDEX(p[k]));
233 p[k] += a;
234 RSB_DEBUG_ASSERT(RSB_IS_VALID_COO_INDEX(p[k]));
235 }
236 }
237
rsb__util_coo_arrays_add(rsb_coo_idx_t * p,rsb_coo_idx_t * q,rsb_coo_idx_t a,rsb_coo_idx_t b,rsb_nnz_idx_t n)238 void rsb__util_coo_arrays_add(rsb_coo_idx_t * p, rsb_coo_idx_t * q, rsb_coo_idx_t a, rsb_coo_idx_t b, rsb_nnz_idx_t n)
239 {
240 /*!
241 TODO : document
242 */
243 rsb__util_coo_array_add(p,n,a);
244 rsb__util_coo_array_add(q,n,b);
245 }
246
247 #if 0
248 void rsb_util_coo_arrays_sub(rsb_coo_idx_t * p, rsb_coo_idx_t * q, rsb_coo_idx_t a, rsb_coo_idx_t b, rsb_nnz_idx_t n)
249 {
250 /*!
251 TODO : document
252 */
253 rsb__util_coo_array_sub(p,n,a);
254 rsb__util_coo_array_sub(q,n,b);
255 }
256 #endif
257
rsb_util_nnz_array_add(rsb_nnz_idx_t * p,rsb_nnz_idx_t n,rsb_nnz_idx_t a)258 void rsb_util_nnz_array_add(rsb_nnz_idx_t * p, rsb_nnz_idx_t n, rsb_nnz_idx_t a)
259 {
260 /*!
261 \ingroup gr_internals
262 Subtracts s from the given matrix coordinate indices array.
263 */
264 register rsb_nnz_idx_t k;
265
266 RSB_DEBUG_ASSERT(p || n==0);
267 RSB_DEBUG_ASSERT(a>=0);
268 RSB_DEBUG_ASSERT(RSB_IS_VALID_NNZ_INDEX(n));
269
270 if(a)
271 for(k=0;RSB_LIKELY(k<n);++k)
272 {
273 p[k] += a;
274 RSB_DEBUG_ASSERT(RSB_IS_VALID_NNZ_INDEX(p[k]));
275 }
276 }
277
rsb_util_nnz_array_sub(rsb_nnz_idx_t * p,rsb_nnz_idx_t n,rsb_nnz_idx_t s)278 void rsb_util_nnz_array_sub(rsb_nnz_idx_t * p, rsb_nnz_idx_t n, rsb_nnz_idx_t s)
279 {
280 /*!
281 \ingroup gr_internals
282 Subtracts s from the given matrix coordinate indices array.
283 */
284 register rsb_nnz_idx_t k;
285
286 RSB_DEBUG_ASSERT(p || n==0);
287 RSB_DEBUG_ASSERT(s>=0);
288 RSB_DEBUG_ASSERT(RSB_IS_VALID_NNZ_INDEX(n));
289
290 if(s)
291 for(k=0;RSB_LIKELY(k<n);++k)
292 {
293 p[k] -= s;
294 RSB_DEBUG_ASSERT(RSB_IS_VALID_NNZ_INDEX(p[k]));
295 }
296 }
297
rsb__util_coo_array_sub(rsb_coo_idx_t * p,rsb_nnz_idx_t n,rsb_coo_idx_t s)298 void rsb__util_coo_array_sub(rsb_coo_idx_t * p, rsb_nnz_idx_t n, rsb_coo_idx_t s)
299 {
300 /*!
301 \ingroup gr_internals
302 Subtracts s from the given matrix coordinate indices array.
303 */
304 register rsb_nnz_idx_t k;
305
306 RSB_DEBUG_ASSERT(p || n==0);
307 RSB_DEBUG_ASSERT(s>=0);
308 RSB_DEBUG_ASSERT(RSB_IS_VALID_NNZ_INDEX(n));
309
310 if(s)
311 for(k=0;RSB_LIKELY(k<n);++k)
312 {
313 p[k] -= s;
314 RSB_DEBUG_ASSERT(RSB_IS_VALID_COO_INDEX(p[k]));
315 }
316 }
317
rsb__util_nnz_array_to_fortran_indices(rsb_nnz_idx_t * p,rsb_nnz_idx_t n)318 void rsb__util_nnz_array_to_fortran_indices(rsb_nnz_idx_t * p, rsb_nnz_idx_t n)
319 {
320 /*!
321 \ingroup gr_internals
322 Adds 1 to the given matrix coordinate indices array.
323 */
324 rsb_util_nnz_array_add(p, n, 1);
325 }
326
rsb__util_coo_array_to_fortran_indices(rsb_coo_idx_t * p,rsb_nnz_idx_t n)327 void rsb__util_coo_array_to_fortran_indices(rsb_coo_idx_t * p, rsb_nnz_idx_t n)
328 {
329 /*!
330 \ingroup gr_internals
331 Adds 1 to the given matrix coordinate indices array.
332 */
333 rsb__util_coo_array_add(p, n, 1);
334 }
335
rsb__util_coo_array_to_fortran_indices_parallel(rsb_coo_idx_t * p,rsb_nnz_idx_t n)336 void rsb__util_coo_array_to_fortran_indices_parallel(rsb_coo_idx_t * p, rsb_nnz_idx_t n)
337 {
338 /*!
339 \ingroup gr_internals
340 Adds 1 to the given matrix coordinate indices array.
341 */
342 register rsb_nnz_idx_t k;
343 const rsb_nnz_idx_t mcs = RSB_MINIMUM_VECOP_OMP_CHUNK;
344
345 RSB_DEBUG_ASSERT(p || n==0);
346 RSB_DEBUG_ASSERT(p>=0);
347 RSB_DEBUG_ASSERT(RSB_IS_VALID_NNZ_INDEX(n));
348
349 if(p)
350 {
351 #pragma omp parallel for schedule(guided,mcs) shared(p) RSB_NTC
352 for(k=0;RSB_LIKELY_OMP(k<n);++k)
353 {
354 RSB_DEBUG_ASSERT(RSB_IS_VALID_COO_INDEX(p[k]));
355 ++p[k];
356 RSB_DEBUG_ASSERT(RSB_IS_VALID_COO_INDEX(p[k]));
357 }
358 }
359 }
360
rsb__util_nnz_array_from_fortran_indices(rsb_nnz_idx_t * p,rsb_nnz_idx_t n)361 void rsb__util_nnz_array_from_fortran_indices(rsb_nnz_idx_t * p, rsb_nnz_idx_t n)
362 {
363 /*!
364 \ingroup gr_internals
365 Subtracts 1 from the given matrix coordinate indices array.
366 */
367 rsb_util_nnz_array_sub(p, n, 1);
368 }
369
rsb__util_coo_array_from_fortran_indices(rsb_coo_idx_t * p,rsb_nnz_idx_t n,rsb_bool_t want_parallel)370 void rsb__util_coo_array_from_fortran_indices(rsb_coo_idx_t * p, rsb_nnz_idx_t n, rsb_bool_t want_parallel)
371 {
372 /*!
373 \ingroup gr_internals
374 Subtracts 1 from the given matrix coordinate indices array.
375 TODO: parallelize
376 */
377 register rsb_nnz_idx_t k;
378 const rsb_nnz_idx_t mcs = RSB_MINIMUM_VECOP_OMP_CHUNK;
379
380 RSB_DEBUG_ASSERT(p || n==0);
381 RSB_DEBUG_ASSERT(p>=0);
382 RSB_DEBUG_ASSERT(RSB_IS_VALID_NNZ_INDEX(n));
383
384 if(!p)
385 return;
386
387 if(want_parallel)
388 {
389 #pragma omp parallel for schedule(guided,mcs) shared(p) RSB_NTC
390 for(k=0;RSB_LIKELY_OMP(k<n);++k)
391 {
392 RSB_DEBUG_ASSERT(RSB_IS_VALID_COO_INDEX(p[k]));
393 --p[k];
394 RSB_DEBUG_ASSERT(RSB_IS_VALID_COO_INDEX(p[k]));
395 }
396 }
397 else
398 rsb__util_coo_array_sub(p, n, 1);
399 }
400
rsb__util_coo_determine_uplo_flags(const rsb_coo_idx_t * RSB_RESTRICT IA,const rsb_coo_idx_t * RSB_RESTRICT JA,rsb_nnz_idx_t nnz)401 rsb_flags_t rsb__util_coo_determine_uplo_flags(const rsb_coo_idx_t * RSB_RESTRICT IA, const rsb_coo_idx_t * RSB_RESTRICT JA, rsb_nnz_idx_t nnz)
402 {
403 /*!
404 \ingroup gr_internals
405 */
406 rsb_nnz_idx_t n;
407 const rsb_flags_t tflags = RSB_FLAG_UPPER_TRIANGULAR|RSB_FLAG_LOWER_TRIANGULAR;
408 rsb_flags_t flags = tflags;
409
410 for(n=0;n<nnz ;++n)
411 if(IA[n]<JA[n])
412 {
413 RSB_DO_FLAG_DEL(flags,RSB_FLAG_LOWER);
414 for(;RSB_LIKELY(n<nnz) ;++n)
415 if(IA[n]>JA[n])
416 {
417 RSB_DO_FLAG_DEL(flags,RSB_FLAG_UPPER);
418 goto done;
419 }
420 }
421 else
422 if(IA[n]>JA[n])
423 {
424 RSB_DO_FLAG_DEL(flags,RSB_FLAG_UPPER);
425 for(;RSB_LIKELY(n<nnz) ;++n)
426 if(IA[n]<JA[n])
427 {
428 RSB_DO_FLAG_DEL(flags,RSB_FLAG_LOWER);
429 goto done;
430 }
431 }
432 done:
433 if((flags&tflags)==RSB_FLAG_TRIANGULAR )
434 RSB_DO_FLAG_DEL(flags,RSB_FLAG_TRIANGULAR);
435 return flags;
436 }
437
rsb__util_coo_check_if_triangle_non_empty(const rsb_coo_idx_t * RSB_RESTRICT IA,const rsb_coo_idx_t * RSB_RESTRICT JA,rsb_nnz_idx_t nnz,rsb_flags_t flags)438 rsb_bool_t rsb__util_coo_check_if_triangle_non_empty(const rsb_coo_idx_t * RSB_RESTRICT IA, const rsb_coo_idx_t * RSB_RESTRICT JA, rsb_nnz_idx_t nnz, rsb_flags_t flags)
439 {
440 /*!
441 \ingroup gr_internals
442 */
443 rsb_nnz_idx_t n;
444
445 if(RSB_DO_FLAG_HAS(flags,RSB_FLAG_UPPER))
446 for(n=0;RSB_LIKELY(n<nnz);++n)
447 if(IA[n]<JA[n])
448 return RSB_BOOL_TRUE;
449
450 if(RSB_DO_FLAG_HAS(flags,RSB_FLAG_LOWER))
451 for(n=0;RSB_LIKELY(n<nnz);++n)
452 if(IA[n]>JA[n])
453 return RSB_BOOL_TRUE;
454
455 return RSB_BOOL_FALSE;
456 }
457
rsb__util_coo_upper_to_lower_symmetric(rsb_coo_idx_t * IA,rsb_coo_idx_t * JA,rsb_nnz_idx_t nnz)458 void rsb__util_coo_upper_to_lower_symmetric(rsb_coo_idx_t * IA, rsb_coo_idx_t * JA, rsb_nnz_idx_t nnz)
459 {
460 /*!
461 \ingroup gr_internals
462 A transpose function.
463 */
464 rsb_nnz_idx_t n;
465
466 for(n=0;n<nnz;++n)
467 if(IA[n]<JA[n])
468 RSB_SWAP(rsb_coo_idx_t,IA[n],JA[n]);
469 }
470
rsb__util_coo_lower_to_upper_symmetric(rsb_coo_idx_t * IA,rsb_coo_idx_t * JA,rsb_nnz_idx_t nnz)471 void rsb__util_coo_lower_to_upper_symmetric(rsb_coo_idx_t * IA, rsb_coo_idx_t * JA, rsb_nnz_idx_t nnz)
472 {
473 /*!
474 \ingroup gr_internals
475 */
476 rsb__util_coo_upper_to_lower_symmetric(JA, IA, nnz);
477 }
478
rsb__util_coo_check_if_has_diagonal_elements(const rsb_coo_idx_t * IA,const rsb_coo_idx_t * JA,rsb_nnz_idx_t nnz,rsb_coo_idx_t m,rsb_bool_t * has_diagonal_elements)479 rsb_err_t rsb__util_coo_check_if_has_diagonal_elements(const rsb_coo_idx_t * IA, const rsb_coo_idx_t * JA, rsb_nnz_idx_t nnz, rsb_coo_idx_t m, rsb_bool_t *has_diagonal_elements)
480 {
481 /*!
482 \ingroup gr_internals
483 */
484 rsb_bitmap_data_t * bmap = NULL;
485 rsb_nnz_idx_t n,cnnz = 0;
486
487 if(RSB_INVALID_NNZ_INDEX(nnz) || RSB_INVALID_COO_INDEX(m) || !IA || !JA || !has_diagonal_elements)
488 return RSB_ERR_BADARGS;
489
490 if(m>nnz)
491 goto missing_diagonal_element; /* trivially */
492 /* we allow for duplicates, though (instead a count would be enough) */
493
494 bmap = rsb__allocate_bitmap(1,m);
495
496 if(!bmap)
497 return RSB_ERR_ENOMEM;
498
499 for(n=0;RSB_LIKELY(n<nnz);++n)
500 {
501 if(RSB_UNLIKELY(IA[n]==JA[n]))
502 {
503 if( IA[n]<0 || IA[n]>m || JA[n]<0 || JA[n]>m)
504 {
505 RSB_ERROR(RSB_ERRMSG_BADCOO"\n");
506 goto badinput;
507 }
508 RSB_BITMAP_SET(bmap,1,nnz,0,IA[n]);
509 ++cnnz;
510 }
511 }
512 #if 1
513 if(cnnz<m)
514 {
515 RSB_STDERR("missing %zd diagonal elements\n",(size_t)(m-cnnz));
516 }
517 #endif
518 for(n=0;RSB_LIKELY(n<m);++n)
519 if(!RSB_BITMAP_GET(bmap,1,nnz,0,n))
520 {
521 #if 1
522 RSB_STDERR("missing element %zd\n",(size_t)n);
523 #endif
524 goto missing_diagonal_element;
525 }
526 goto ok;
527
528 ok:
529 RSB_CONDITIONAL_FREE(bmap);
530 *has_diagonal_elements = RSB_BOOL_TRUE;
531 return RSB_ERR_NO_ERROR;
532
533 missing_diagonal_element:
534 RSB_CONDITIONAL_FREE(bmap);
535 *has_diagonal_elements = RSB_BOOL_FALSE;
536 return RSB_ERR_NO_ERROR;
537
538 badinput:
539 RSB_CONDITIONAL_FREE(bmap);
540 return RSB_ERR_BADARGS;
541 }
542
rsb__util_is_halfword_coo_array_sorted_up(const rsb_half_idx_t * p,const rsb_nnz_idx_t n)543 rsb_bool_t rsb__util_is_halfword_coo_array_sorted_up(const rsb_half_idx_t* p, const rsb_nnz_idx_t n)
544 {
545 /*!
546 \ingroup gr_internals
547 */
548 rsb_nnz_idx_t i;
549 if(n<2)
550 return RSB_BOOL_TRUE;
551 for(i=1;RSB_LIKELY(i<n);++i)
552 if(RSB_UNLIKELY(p[i-1]>=p[i]))
553 return RSB_BOOL_FALSE;
554 return RSB_BOOL_TRUE;
555 }
556
rsb__util_is_halfword_coo_array_sorted_up_partial_order(const rsb_half_idx_t * p,const rsb_nnz_idx_t n)557 rsb_bool_t rsb__util_is_halfword_coo_array_sorted_up_partial_order(const rsb_half_idx_t * p, const rsb_nnz_idx_t n)
558 {
559 /*!
560 \ingroup gr_internals
561 */
562 rsb_nnz_idx_t i;
563 if(n<2)
564 return RSB_BOOL_TRUE;
565 for(i=1;RSB_LIKELY(i<n);++i)
566 if(RSB_UNLIKELY(p[i-1]>p[i]))
567 {
568 /* RSB_STDOUT("n=%d, p[%d-1]>p[%d] -- %d > %d\n",n,i,i,p[i-1],p[i]); */
569 return RSB_BOOL_FALSE;
570 }
571 return RSB_BOOL_TRUE;
572 }
573
rsb__util_is_nnz_array_sorted_up_partial_order(const rsb_nnz_idx_t * p,const rsb_nnz_idx_t n)574 rsb_bool_t rsb__util_is_nnz_array_sorted_up_partial_order(const rsb_nnz_idx_t * p, const rsb_nnz_idx_t n)
575 {
576 /*!
577 \ingroup gr_internals
578 */
579 rsb_nnz_idx_t i;
580 if(n<2)
581 goto yes;
582 for(i=1;RSB_LIKELY(i<n);++i)
583 if(RSB_UNLIKELY(p[i-1]>p[i]))
584 {
585 /* RSB_STDOUT("n=%d, p[%d-1]>p[%d] -- %d > %d\n",n,i,i,p[i-1],p[i]); */
586 goto no;
587 }
588 yes:
589 return RSB_BOOL_TRUE;
590 no:
591 /* RSB_STDOUT("%d=p[%d]>=p[%d]=%d\n",p[i-1],i-1,i,p[i]); */
592 return RSB_BOOL_FALSE;
593 }
594
rsb__util_is_coo_array_sorted_up_partial_order(const rsb_nnz_idx_t * p,const rsb_nnz_idx_t n)595 rsb_bool_t rsb__util_is_coo_array_sorted_up_partial_order(const rsb_nnz_idx_t * p, const rsb_nnz_idx_t n)
596 {
597 return rsb__util_is_nnz_array_sorted_up_partial_order(p, n);
598 }
599
rsb__util_is_coo_array_sorted_up(const rsb_coo_idx_t * p,const rsb_nnz_idx_t n)600 rsb_bool_t rsb__util_is_coo_array_sorted_up(const rsb_coo_idx_t * p, const rsb_nnz_idx_t n)
601 {
602 /*!
603 \ingroup gr_internals
604 */
605 rsb_nnz_idx_t i;
606 if(n<2)
607 goto yes;
608 for(i=1;RSB_LIKELY(i<n);++i)
609 if(RSB_UNLIKELY(p[i-1]>=p[i]))
610 goto no;
611 yes:
612 return RSB_BOOL_TRUE;
613 no:
614 /* TODO: if this becomes a debugging function, one can use a RSB_ERROR printout instead */
615 /* RSB_STDOUT("%d=p[%d]>=p[%d]=%d\n",p[i-1],i-1,i,p[i]); */
616 return RSB_BOOL_FALSE;
617 }
618
rsb__util_is_nnz_array_sorted_up(const rsb_nnz_idx_t * p,const rsb_nnz_idx_t n)619 rsb_bool_t rsb__util_is_nnz_array_sorted_up(const rsb_nnz_idx_t * p, const rsb_nnz_idx_t n)
620 {
621 /*!
622 \ingroup gr_internals
623 */
624 rsb_nnz_idx_t i;
625 if(n<2)
626 goto yes;
627 for(i=1;RSB_LIKELY(i<n);++i)
628 if(RSB_UNLIKELY(p[i-1]>=p[i]))
629 goto no;
630 yes:
631 return RSB_BOOL_TRUE;
632 no:
633 return RSB_BOOL_FALSE;
634 }
635
rsb__util_nnz_array_add_array(rsb_nnz_idx_t * p,const rsb_nnz_idx_t * q,rsb_nnz_idx_t n)636 void rsb__util_nnz_array_add_array(rsb_nnz_idx_t * p, const rsb_nnz_idx_t * q, rsb_nnz_idx_t n)
637 {
638 /*!
639 \ingroup gr_internals
640 Adds s from the given matrix coordinate indices array.
641 */
642 register rsb_nnz_idx_t k;
643
644 RSB_DEBUG_ASSERT(p || n==0);
645 RSB_DEBUG_ASSERT(q || n==0);
646 RSB_DEBUG_ASSERT(n>=0);
647 RSB_DEBUG_ASSERT(RSB_IS_VALID_NNZ_INDEX(n));
648
649 for(k=0;RSB_LIKELY(k<n);++k)
650 {
651 p[k] += q[k];
652 }
653 }
654
rsb__util_find_max_index(const rsb_nnz_idx_t * p,rsb_nnz_idx_t n)655 rsb_coo_idx_t rsb__util_find_max_index(const rsb_nnz_idx_t * p, rsb_nnz_idx_t n)
656 {
657 /*!
658 \ingroup gr_internals
659 */
660 rsb_nnz_idx_t i,l=0;
661 rsb_coo_idx_t m;
662 if(n<1)
663 goto ret;
664 m = p[l];
665 for(i=1;RSB_LIKELY(i<n);++i)
666 if(p[i]>m)
667 m = p[i], l = i;
668 ret:
669 return l;
670 }
671
rsb__util_find_min_index(const rsb_nnz_idx_t * p,rsb_nnz_idx_t n)672 rsb_coo_idx_t rsb__util_find_min_index(const rsb_nnz_idx_t * p, rsb_nnz_idx_t n)
673 {
674 /*!
675 \ingroup gr_internals
676 */
677 rsb_nnz_idx_t i,l=0;
678 rsb_coo_idx_t m;
679 if(n<1)
680 goto ret;
681 m = p[l];
682 for(i=1;RSB_LIKELY(i<n);++i)
683 if(p[i]<m)
684 m = p[i], l = i;
685 ret:
686 return l;
687 }
688
rsb__util_find_max_index_val(const rsb_nnz_idx_t * p,rsb_nnz_idx_t n)689 rsb_coo_idx_t rsb__util_find_max_index_val(const rsb_nnz_idx_t * p, rsb_nnz_idx_t n)
690 {
691 /*!
692 \ingroup gr_internals
693 */
694 rsb_nnz_idx_t i;
695 rsb_coo_idx_t m;
696 if(n<1)
697 return RSB_MARKER_COO_VALUE;
698 m = p[0];
699 for(i=1;RSB_LIKELY(i<n);++i)
700 if(p[i]>m)
701 m = p[i];
702 return m;
703 }
704
rsb__util_find_min_index_val(const rsb_nnz_idx_t * p,rsb_nnz_idx_t n)705 rsb_coo_idx_t rsb__util_find_min_index_val(const rsb_nnz_idx_t * p, rsb_nnz_idx_t n)
706 {
707 /*!
708 \ingroup gr_internals
709 */
710 rsb_nnz_idx_t i;
711 rsb_coo_idx_t m;
712 if(n<1)
713 return RSB_MARKER_COO_VALUE;
714 m = p[0];
715 for(i=1;RSB_LIKELY(i<n);++i)
716 if(p[i]<m)
717 m = p[i];
718 return m;
719 }
720
rsb__util_coo_array_renumber(rsb_coo_idx_t * a,const rsb_coo_idx_t * iren,rsb_nnz_idx_t n,rsb_flags_t aflags,rsb_flags_t pflags,rsb_flags_t oflags)721 void rsb__util_coo_array_renumber(rsb_coo_idx_t * a, const rsb_coo_idx_t * iren, rsb_nnz_idx_t n, rsb_flags_t aflags, rsb_flags_t pflags, rsb_flags_t oflags)
722 {
723 /*!
724 \ingroup gr_internals
725 */
726 rsb_nnz_idx_t i = 0;
727 rsb_coo_idx_t ioff = 0,ooff = 0,oooff = 0;
728
729 if( aflags & RSB_FLAG_FORTRAN_INDICES_INTERFACE )
730 ioff = 1;
731 if( pflags & RSB_FLAG_FORTRAN_INDICES_INTERFACE )
732 ooff = 1;
733 if( oflags & RSB_FLAG_FORTRAN_INDICES_INTERFACE )
734 oooff = 1;
735
736 for(i=0;RSB_LIKELY(i<n);++i)
737 a[i] = iren[a[i]-ioff]-ooff+oooff;
738 }
739
rsb__util_compress_to_row_pointers_array(rsb_coo_idx_t * RSB_RESTRICT pa,rsb_nnz_idx_t nz,rsb_coo_idx_t m,rsb_flags_t iflags,rsb_flags_t oflags,rsb_coo_idx_t * ta)740 rsb_err_t rsb__util_compress_to_row_pointers_array(rsb_coo_idx_t * RSB_RESTRICT pa, rsb_nnz_idx_t nz, rsb_coo_idx_t m, rsb_flags_t iflags, rsb_flags_t oflags, rsb_coo_idx_t * ta)
741 {
742 /*
743 * Note that this routine invokes OpenMP.
744 * Requires m+1 temporary space.
745 * TODO: rsb__util_compress_to_row_pointers_array -> rsb__idx_fia2fpa
746 * */
747 rsb_nnz_idx_t i;
748 rsb_bool_t sa = RSB_BOOL_TRUE;
749 rsb_nnz_idx_t ifo = ( iflags & RSB_FLAG_FORTRAN_INDICES_INTERFACE )?1:0;
750 rsb_nnz_idx_t ofo = ( oflags & RSB_FLAG_FORTRAN_INDICES_INTERFACE )?1:0;
751
752 if(!ta)
753 return RSB_ERR_BADARGS;
754 if(!pa)
755 pa = rsb__calloc((m+1)*sizeof(rsb_coo_idx_t));
756 else
757 sa = RSB_BOOL_FALSE,
758 RSB_BZERO(pa,(m+1)*sizeof(rsb_coo_idx_t));
759 if(!pa)
760 goto err;
761 for(i=0;RSB_LIKELY(i<nz);++i)
762 pa[1+ta[i]-ifo]++;
763 for(i=0;RSB_LIKELY(i<m );++i)
764 pa[i+1] += pa[i]; /* TODO: need a prefix sum routine */
765 if(ofo)
766 for(i=0;RSB_LIKELY(i<m+1);++i)
767 pa[i]++;
768
769 RSB_COA_MEMCPY_parallel(ta,pa,0,0,m+1);
770 if(sa)
771 RSB_CONDITIONAL_FREE(pa);
772 return RSB_ERR_NO_ERROR;
773 err:
774 return RSB_ERR_ENOMEM;
775 }
776
rsb__util_uncompress_row_pointers_array(const rsb_coo_idx_t * pa,rsb_nnz_idx_t n,rsb_flags_t iflags,rsb_flags_t oflags,rsb_coo_idx_t * ta)777 rsb_err_t rsb__util_uncompress_row_pointers_array(const rsb_coo_idx_t * pa, rsb_nnz_idx_t n, rsb_flags_t iflags, rsb_flags_t oflags, rsb_coo_idx_t * ta)
778 {
779 /*
780 TODO: write a version to exploit no-pointer-aliasing (if available)
781 */
782 rsb_nnz_idx_t i,nz;
783 rsb_bool_t sa = RSB_BOOL_TRUE; /* same array */
784 rsb_nnz_idx_t ifo = ( iflags & RSB_FLAG_FORTRAN_INDICES_INTERFACE )?1:0;
785 rsb_nnz_idx_t ofo = ( oflags & RSB_FLAG_FORTRAN_INDICES_INTERFACE )?1:0;
786 rsb_coo_idx_t * ota = ta, *tmp = NULL;
787
788 if(!pa || !ta)
789 {
790 RSB_ERROR(RSB_ERRM_ES);
791 return RSB_ERR_BADARGS;
792 }
793 nz = pa[n]-ifo;
794 if(nz==0)
795 goto ret;
796 if(ta==pa)
797 {
798 if(RSB_LIKELY(n+1<nz))
799 pa = tmp = rsb__clone_area(pa,sizeof(rsb_coo_idx_t)*(n+1));
800 else
801 tmp = ta = rsb__clone_area(pa,sizeof(rsb_coo_idx_t)* nz );
802 }
803 else
804 sa = RSB_BOOL_FALSE;
805 if((!ta) || (!pa))
806 goto err;
807 /* TODO: this shall be parallel! */
808 for(i=0;RSB_LIKELY(i<n);++i)
809 rsb__util_coo_array_set(ta+(pa[i]-ifo),(pa[i+1]-pa[i]),i+ofo);
810 if(sa && !(n+1<nz))
811 RSB_COA_MEMCPY_parallel(ota,ta,0,0,nz);
812 RSB_CONDITIONAL_FREE(tmp);
813 ret:
814 return RSB_ERR_NO_ERROR;
815 err:
816 return RSB_ERR_ENOMEM;
817 }
818
rsb__debug_print_index_vector(const rsb_coo_idx_t * v1,size_t n)819 rsb_err_t rsb__debug_print_index_vector(const rsb_coo_idx_t * v1, size_t n){
820 /*!
821 **/
822 #if RSB_ALLOW_STDOUT
823 size_t i = 0;
824 int ioff = 1,voff = 1;
825 if(!v1)
826 return RSB_ERR_BADARGS;
827
828 for(i=0;i<n ;++i)
829 RSB_STDOUT("%zd : %d \n",(rsb_printf_int_t)(i+ioff),v1[i]+voff);
830 return RSB_ERR_NO_ERROR;
831 #else
832 return RSB_ERR_UNSUPPORTED_FEATURE;
833 #endif /* RSB_ALLOW_STDOUT */
834 }
835
rsb__debug_print_index_vectors_diff(const rsb_coo_idx_t * v1,const rsb_coo_idx_t * v2,size_t n,int onlyfirst)836 rsb_err_t rsb__debug_print_index_vectors_diff(const rsb_coo_idx_t * v1, const rsb_coo_idx_t * v2, size_t n, int onlyfirst){
837 /*!
838 **/
839 #if RSB_ALLOW_STDOUT
840 size_t i,differing = 0;
841 if(!v1 || !v2)return RSB_ERR_BADARGS;
842
843 RSB_STDERR("\t indices vectors diff :\n");
844
845 for(i=0;i<n ;++i)
846 if(v1[i]!=v2[i]){
847 differing++;
848 if((onlyfirst==0)||(onlyfirst>differing))
849 RSB_STDOUT("%zd : %d %d \n",(rsb_printf_int_t)i, v1[i],v2[i] );
850 }
851 if(differing>onlyfirst)RSB_STDOUT("...and %zd more ...\n",(rsb_printf_int_t)(differing-onlyfirst));
852 return RSB_ERR_NO_ERROR;
853 #else
854 return RSB_ERR_UNSUPPORTED_FEATURE;
855 #endif /* RSB_ALLOW_STDOUT */
856 }
857
rsb__util_find_extremal_half_index_val(const rsb_half_idx_t * RSB_RESTRICT p,rsb_nnz_idx_t n,rsb_coo_idx_t lb,rsb_coo_idx_t ub,rsb_half_idx_t * lf,rsb_half_idx_t * RSB_RESTRICT uf)858 rsb_err_t rsb__util_find_extremal_half_index_val(const rsb_half_idx_t * RSB_RESTRICT p, rsb_nnz_idx_t n, rsb_coo_idx_t lb, rsb_coo_idx_t ub, rsb_half_idx_t *lf, rsb_half_idx_t * RSB_RESTRICT uf)
859 {
860 /* TODO: remove the useless 'ub' argument */
861 /* TODO: this is a naive implementation; need a better one */
862 rsb_half_idx_t vm = RSB_MAX_VALUE_FOR_TYPE(rsb_half_idx_t),vM = 0;
863 rsb_nnz_idx_t i = 0;
864
865 for(i=0;i<n;++i)
866 vm = RSB_MIN(vm,p[i]), vM = RSB_MAX(vM,p[i]);
867 if(lf)*lf = vm;
868 if(uf)*uf = vM;
869 return RSB_ERR_NO_ERROR;
870 }
871
rsb__util_find_extremal_full_index_val(const rsb_coo_idx_t * RSB_RESTRICT p,rsb_nnz_idx_t n,rsb_coo_idx_t lb,rsb_coo_idx_t ub,rsb_coo_idx_t * RSB_RESTRICT lf,rsb_coo_idx_t * RSB_RESTRICT uf)872 rsb_err_t rsb__util_find_extremal_full_index_val(const rsb_coo_idx_t * RSB_RESTRICT p, rsb_nnz_idx_t n, rsb_coo_idx_t lb, rsb_coo_idx_t ub, rsb_coo_idx_t * RSB_RESTRICT lf, rsb_coo_idx_t * RSB_RESTRICT uf)
873 {
874 /* TODO: remove the useless 'ub' argument */
875 /* TODO: this is a naive implementation; need a better one */
876 rsb_coo_idx_t vm = RSB_MAX_VALUE_FOR_TYPE(rsb_coo_idx_t),vM = 0;
877 rsb_nnz_idx_t i = 0;
878
879 for(i=0;i<n;++i)
880 vm = RSB_MIN(vm,p[i]), vM = RSB_MAX(vM,p[i]);
881 RSB_ASSIGN_IF_DP(lf,vm);
882 RSB_ASSIGN_IF_DP(uf,vM);
883 return RSB_ERR_NO_ERROR;
884
885 }
886
rsb__util_reverse_halfword_coo_array(rsb_half_idx_t * p,rsb_nnz_idx_t n)887 rsb_bool_t rsb__util_reverse_halfword_coo_array(rsb_half_idx_t* p, rsb_nnz_idx_t n)
888 {
889 rsb_nnz_idx_t nzi;
890 --n;
891 for(nzi=0;nzi<(n+1)/2;++nzi)
892 RSB_SWAP(rsb_half_idx_t,p[n-nzi],p[nzi]);
893 return RSB_BOOL_TRUE;
894 }
895
rsb__util_reverse_fullword_coo_array(rsb_coo_idx_t * p,rsb_nnz_idx_t n)896 rsb_bool_t rsb__util_reverse_fullword_coo_array(rsb_coo_idx_t* p, rsb_nnz_idx_t n)
897 {
898 rsb_nnz_idx_t nzi;
899 --n;
900 for(nzi=0;nzi<(n+1)/2;++nzi)
901 RSB_SWAP(rsb_coo_idx_t,p[n-nzi],p[nzi]);
902 return RSB_BOOL_TRUE;
903 }
904
905 /* @endcond */
906