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