1 /*
2 
3 Copyright (C) 2008-2021 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  *
28  * Implementation of the interface functions.
29  * \internal
30  *
31  * */
32 /* TODO: introduce RSB_MSG_BADARGS_ERROR(ERRVAL,MSG,BAN) */
33 #include "rsb_common.h"
34 #include "rsb_util.h"
35 #include "rsb.h"
36 #include "rsb_unroll.h"
37 #ifdef RSB_HAVE_SYS_UTSNAME_H
38 #include <sys/utsname.h>	/* uname */
39 #endif /* RSB_HAVE_SYS_UTSNAME_H */
40 #include "rsb_do.h"
41 extern struct rsb_session_handle_t rsb_global_session_handle;
42 
43 RSB_INTERNALS_COMMON_HEAD_DECLS
44 
rsb_do_prec_build(struct rsb_mtx_t ** mtxLpp,struct rsb_mtx_t ** mtxUpp,const struct rsb_mtx_t * mtxAp)45 rsb_err_t rsb_do_prec_build(struct rsb_mtx_t ** mtxLpp, struct rsb_mtx_t ** mtxUpp, const struct rsb_mtx_t * mtxAp)
46 {
47 	/*
48 	 * FIXME: UNFINISHED, UNTESTED
49 	 * */
50 	rsb_err_t errval = RSB_ERR_NO_ERROR;
51 	struct rsb_mtx_t *L=NULL,*U=NULL;
52 	struct rsb_coo_matrix_t csr,lcoo,ucoo;
53 	rsb_flags_t flags = RSB_FLAG_DEFAULT_MATRIX_FLAGS;
54 
55 	csr.VA=NULL; csr.IA=NULL; csr.JA=NULL;
56 	if(!mtxLpp)
57 		goto err;
58 	if(!mtxUpp)
59 		goto err;
60 	if(!mtxAp)
61 		goto err;
62 	if(mtxAp->nr != mtxAp->nc)
63 		goto err;
64 	csr.nr=mtxAp->nr;
65 	csr.nc=mtxAp->nc;
66 	csr.nnz = RSB_MAX(mtxAp->nnz,RSB_MAX(csr.nr,csr.nc)+1);
67 	csr.typecode=mtxAp->typecode;
68 	ucoo=csr; lcoo=csr;
69 	if(rsb__allocate_coo_matrix_t(&csr)!=&csr)
70 	{
71 		errval = RSB_ERR_ENOMEM;
72 		RSB_PERR_GOTO(err,RSB_ERRM_ES);
73 	}
74 	csr.nnz=mtxAp->nnz;
75 /* a reasonably efficient routine would: */
76 	/* build a fullword CSR clone (using a RSB-to-CSR constructor) */
77 	/* perform ILU on the CSR struct */
78 	/* build RSB clones for the L and U CSR parts  (using a modified CSR-to-RSB constructor, eventually building them together, in one shot) */
79 	/* FIXME: TODO */
80 	/* a reasonable quick hack routine would: */
81 	/* build a fullword CSR clone (using a RSB-to-CSR constructor) */
82 	if((errval = rsb__do_get_csr(mtxAp->typecode,mtxAp,csr.VA,csr.IA,csr.JA,RSB_FLAG_DEFAULT_CSR_MATRIX_FLAGS))!=RSB_ERR_NO_ERROR)
83 		goto err;
84 	/* perform ILU on the CSR struct */
85 	if((errval = rsb__prec_csr_ilu0(&csr))!=RSB_ERR_NO_ERROR)
86 		goto err;
87 	/* perform CSR to COO conversion */
88 	rsb__do_count_tri_in_csr(&csr,&lcoo.nnz,&ucoo.nnz);
89 
90 	ucoo.nnz=RSB_MAX(ucoo.nnz,ucoo.nr+1);
91 	if(rsb__allocate_coo_matrix_t(&ucoo)!=&ucoo) { errval = RSB_ERR_ENOMEM; goto err; }
92 
93 	lcoo.nnz=RSB_MAX(lcoo.nnz,lcoo.nr+1);
94 
95 	if(rsb__allocate_coo_matrix_t(&lcoo)!=&lcoo) { errval = RSB_ERR_ENOMEM; goto err; }
96 	rsb__do_count_tri_in_csr(&csr,&lcoo.nnz,&ucoo.nnz);
97 
98 	rsb__do_copy_tri_from_csr_to_coo(&csr,&lcoo,&ucoo);
99 
100 	/* allocating L and U */
101 	L = rsb__do_mtx_alloc_from_coo_const(lcoo.VA,lcoo.IA,lcoo.JA,lcoo.nnz,lcoo.typecode,lcoo.nr,lcoo.nc,RSB_DEFAULT_ROW_BLOCKING,RSB_DEFAULT_COL_BLOCKING,flags|RSB_FLAG_LOWER_TRIANGULAR,&errval);
102 	if(!L)
103 	{
104 		rsb__destroy_coo_matrix_t(&lcoo);
105 		RSB_BZERO_P(&lcoo);
106 		goto err;
107 	}
108 	U = rsb__do_mtx_alloc_from_coo_const(ucoo.VA,ucoo.IA,ucoo.JA,ucoo.nnz,ucoo.typecode,ucoo.nr,ucoo.nc,RSB_DEFAULT_ROW_BLOCKING,RSB_DEFAULT_COL_BLOCKING,flags|RSB_FLAG_UPPER_TRIANGULAR,&errval);
109 	if(!U)
110 	{
111 		rsb__destroy_coo_matrix_t(&ucoo);
112 		RSB_BZERO_P(&ucoo);
113 		goto err;
114 	}
115 	/*RSB_ERROR(RSB_ERRM_WUF);*/
116 
117 	*mtxLpp=L;
118 	*mtxUpp=U;
119        	rsb__destroy_coo_matrix_t(&csr);
120 	rsb__destroy_coo_matrix_t(&lcoo); rsb__destroy_coo_matrix_t(&ucoo);
121 
122 	return errval;
123 err:
124 	rsb__destroy_coo_matrix_t(&lcoo); rsb__destroy_coo_matrix_t(&ucoo);
125 	rsb__destroy_coo_matrix_t(&csr);
126 	rsb__do_perror(NULL,errval);
127 	RSB_MTX_FREE(L);
128 	RSB_MTX_FREE(U);
129 	errval = RSB_ERR_BADARGS;
130 	return errval;
131 }
132 
rsb__do_get_preconditioner(void * opd,const struct rsb_mtx_t * mtxAp,rsb_precf_t prec_flags,const void * ipd)133 rsb_err_t rsb__do_get_preconditioner(void *opd, const struct rsb_mtx_t * mtxAp, rsb_precf_t prec_flags, const void *ipd)/* FIXME: temporary interface */
134 {
135 	// FIXME: UNFINISHED, UNTESTED
136 	rsb_err_t errval = RSB_ERR_GENERIC_ERROR;
137 	struct rsb_mtx_t * LU[2]={NULL,NULL};
138 
139 	if(!opd || !mtxAp)
140 	{
141 		RSB_PERR_GOTO(err,RSB_ERRM_ES);
142 	}
143 	errval = rsb_do_prec_build(&LU[0],&LU[1],mtxAp);
144 	rsb__memcpy(opd,LU,sizeof(LU));
145 err:
146 	return errval;
147 }
148 #if 0
149 rsb_err_t rsb_do_prec_apply(const struct rsb_prec_t * precp, const void *r)
150 {
151 	/*
152 	 * given the preconditioner P, computes \f$ r \leftarrow {P}^{-1} r.\f$
153 	 * \f$ r' = {P}^{-1} r \f$
154 	 * \f$ r' = {L \cdot U}^{-1} r \f$
155 	 * \f$ r' = {U}^{-1} {L}^{-1} r \f$
156 	 * \f$ r' = ({U}^{-1} ({L}^{-1} r)) \f$
157 	 * */
158 	//rsb__debug_print_vector(r,precp->L->nr,precp->L->typecode,1);
159 	double one=1.0;
160 	rsb_err_t errval = RSB_ERR_NO_ERROR;
161 	RSB_DO_ERROR_CUMULATE(errval,rsb__do_spsv(RSB_TRANSPOSITION_N,&one,precp->L,r,1,r,1));
162 	if(RSB_SOME_ERROR(errval))
163 		goto err;
164 	RSB_DO_ERROR_CUMULATE(errval,rsb__do_spsv(RSB_TRANSPOSITION_N,&one,precp->U,r,1,r,1));
165 	if(RSB_SOME_ERROR(errval))
166 		goto err;
167 
168 	//rsb__debug_print_vector(r,precp->L->nr,precp->L->typecode,1);
169 err:
170 	if(RSB_SOME_ERROR(errval))
171 		rsb__do_perror(NULL,errval);
172 	return errval;
173 }
174 #endif
175 
rsb__do_get_rows_sparse(rsb_trans_t transA,const void * alphap,const struct rsb_mtx_t * mtxAp,void * VA,rsb_coo_idx_t * IA,rsb_coo_idx_t * JA,rsb_coo_idx_t frA,rsb_coo_idx_t lrA,rsb_nnz_idx_t * rnzp,rsb_flags_t flags)176 rsb_err_t rsb__do_get_rows_sparse(rsb_trans_t transA, const void * alphap, const struct rsb_mtx_t * mtxAp, void* VA, rsb_coo_idx_t * IA, rsb_coo_idx_t * JA, rsb_coo_idx_t frA, rsb_coo_idx_t lrA, rsb_nnz_idx_t *rnzp, rsb_flags_t flags)
177 {
178 	/* TODO: having a return scaled rows would be an efficient feature. */
179 	rsb_err_t errval = RSB_ERR_NO_ERROR;
180 	rsb_coo_idx_t off = 0;
181 
182 #if RSB_ALLOW_ZERO_DIM
183 	if(RSB_ANY_MTX_DIM_ZERO(mtxAp))
184 	{
185 		goto err; /* FIXME: skipping checks on ldB, ldC, op_flags*/
186 	}
187 #endif
188 
189 	if(VA == NULL && JA == NULL && IA == NULL && rnzp != NULL)
190 	{
191 		*rnzp = rsb__dodo_get_rows_nnz(mtxAp, frA, lrA,flags,&errval);
192 		goto err;
193 	}
194 
195 	if(!mtxAp)
196 	{
197 		errval = RSB_ERR_BADARGS;
198 		RSB_PERR_GOTO(err,RSB_ERRM_E_MTXAP);
199 	}
200 
201 	if(!rnzp)
202 	{
203 		errval = RSB_ERR_BADARGS;
204 		RSB_PERR_GOTO(err,"user did not supply a results nonzeroes pointer\n");
205 	}
206 
207 	if(RSB_DO_FLAG_HAS(flags,RSB_FLAG_FORTRAN_INDICES_INTERFACE))
208 	{
209 		off=1;
210 		lrA--;
211 		frA--;
212 		RSB_DO_FLAG_DEL(flags,RSB_FLAG_FORTRAN_INDICES_INTERFACE);
213 	}
214 
215 	if(frA<0 || lrA>mtxAp->nr)
216 	{
217 		errval = RSB_ERR_BADARGS;
218 		RSB_PERR_GOTO(err,RSB_ERRM_EM);
219 	}
220 
221 	if(!VA)
222 	{
223 		errval = RSB_ERR_BADARGS;
224 		RSB_PERR_GOTO(err,RSB_ERRM_NULL_VA);
225 	}
226 
227 	if(frA>lrA)
228 	{
229 		errval = RSB_ERR_BADARGS;
230 		RSB_PERR_GOTO(err,RSB_ERRM_EM);
231 	}
232 
233 	if(RSB_DOES_TRANSPOSE(transA))
234 		RSB_SWAP(rsb_coo_idx_t*,IA,JA);
235 
236 	*rnzp=0;
237 #if 0
238         errval = rsb__do_get_rows_sparse_rec(mtxAp,VA,frA,lrA,IA,JA,rnzp,off,off);
239 	if(flags & RSB_FLAG_SORT_INPUT)
240 		errval = rsb__util_sort_row_major_inner(VA,IA,JA,*rnzp,mtxAp->nr+off,mtxAp->nc+off,mtxAp->typecode,flags|RSB_FLAG_EXPERIMENTAL_IN_PLACE_CSR);
241 #if 0
242 	if( flags & RSB_FLAG_FORTRAN_INDICES_INTERFACE )
243 		rsb__util_nnz_array_to_fortran_indices(IA,*rnzp),
244 		rsb__util_nnz_array_to_fortran_indices(JA,*rnzp);
245 #endif
246 #else
247 #if 1
248 	{
249 		rsb_coo_idx_t i;
250 		for(i=frA;i<=lrA;++i)
251 		        RSB_DO_ERROR_CUMULATE(errval,rsb__do_get_rows_sparse_rec(mtxAp,VA,i,i,IA,JA,rnzp,off,off));
252 	}
253 #else
254 	{
255 		/* this is too slow for many leaf matrices */
256 		rsb_submatrix_idx_t si;
257 		rsb_coo_idx_t i;
258 		for(i=frA;i<=lrA;++i)
259 		for(si=0;si<mtxAp->all_leaf_matrices_n;++si)
260 		        RSB_DO_ERROR_CUMULATE(errval,rsb__do_get_rows_sparse_rec(mtxAp->all_leaf_matrices[si].mtxlp,VA,i,i,IA,JA,rnzp,off,off));
261 	}
262 #endif
263 #endif
264 	RSB_DEBUG_ASSERT(rsb__dodo_get_rows_nnz(mtxAp,frA,lrA,flags,NULL)==*rnzp);
265 	if(RSB_DOES_TRANSPOSE(transA))
266 	{
267 		RSB_SWAP(rsb_coo_idx_t*,IA,JA);
268 		/* swapping back and ready for sorting. if now, would get column major. */
269 		if(RSB_SOME_ERROR(errval = rsb__util_sort_row_major_inner(VA,IA,JA,*rnzp,mtxAp->nr,mtxAp->nc,mtxAp->typecode,flags)))
270 		{
271 			RSB_PERR_GOTO(err,RSB_ERRM_EM);
272 		}
273 	}
274 
275 	if(RSB_DOES_CONJUGATE(transA))
276 	{
277 		RSB_DO_ERROR_CUMULATE(errval,rsb__util_do_conjugate(VA,mtxAp->typecode,*rnzp));
278 	}
279 
280 	if(alphap)
281 	{
282 		RSB_DO_ERROR_CUMULATE(errval,rsb__cblas_Xscal(mtxAp->typecode,*rnzp,alphap,VA,1));
283 	}
284 err:
285 	if(RSB_SOME_ERROR(errval))
286 	RSB_ERROR(RSB_ERRM_NL);
287 	return errval;
288 }
289 
rsb__do_scal(struct rsb_mtx_t * mtxAp,const void * d,rsb_trans_t trans)290 rsb_err_t rsb__do_scal(struct rsb_mtx_t * mtxAp, const void * d, rsb_trans_t trans)
291 {
292 	/* TODO : what should be the semantics of scaling a symmetric matrix ? */
293 	/* FIXME : and error handling ? **/
294 	rsb_err_t errval = RSB_ERR_UNSUPPORTED_OPERATION;
295 
296 #ifdef RSB_HAVE_OPTYPE_SCALE
297 
298 #if RSB_ALLOW_ZERO_DIM
299 	if(RSB_ANY_MTX_DIM_ZERO(mtxAp))
300 	{
301 		errval = RSB_ERR_NO_ERROR;
302 		goto err; /* FIXME: skipping checks on ldB, ldC, op_flags*/
303 	}
304 #endif
305 
306 	if(!mtxAp)
307 	//	return RSB_ERR_NO_ERROR;
308 	{
309 		errval = RSB_ERR_BADARGS;
310 		RSB_PERR_GOTO(err,RSB_ERRM_EM);
311 	}
312 
313 	if( rsb__is_recursive_matrix(mtxAp->flags))
314 	{
315 		rsb_submatrix_idx_t i,j;
316 		struct rsb_mtx_t * submatrix=NULL;
317 
318 		RSB_SUBMATRIX_FOREACH(mtxAp,submatrix,i,j)
319 		if(submatrix)
320 		{
321 			rsb_coo_idx_t off;
322 			if(RSB_DOES_NOT_TRANSPOSE(trans))
323 				off=submatrix->roff-mtxAp->roff;
324 			else
325 				off=submatrix->coff-mtxAp->coff;
326 
327 			rsb__do_scal(submatrix,((rsb_byte_t*)d)+mtxAp->el_size*off,trans);
328 		}
329 		//return RSB_ERR_NO_ERROR;
330 		{
331 			errval = RSB_ERR_NO_ERROR;
332 			goto err;
333 		}
334 	}
335 	else
336 		errval = rsb__do_scale(mtxAp,trans,d);
337 #else /* RSB_HAVE_OPTYPE_SCALE */
338 #endif /* RSB_HAVE_OPTYPE_SCALE */
339 err:
340 	return errval;
341 }
342 
rsb__dodo_getdiag(const struct rsb_mtx_t * mtxAp,void * diagonal)343 rsb_err_t rsb__dodo_getdiag( const struct rsb_mtx_t * mtxAp, void * diagonal )
344 {
345   	// FIXME : missing documentation and error checks!
346 	rsb_err_t errval = RSB_ERR_NO_ERROR;
347 
348 	if(!mtxAp)
349 	{
350 		errval = RSB_ERR_BADARGS;
351 		RSB_PERR_GOTO(err,RSB_ERRM_E_MTXAP);
352 	}
353 	if(!RSB_BLOCK_CROSSED_BY_DIAGONAL(0,0,mtxAp->nr,mtxAp->nc))
354 	{
355 		errval = RSB_ERR_BADARGS;
356 		goto err;
357 	}
358 
359 	if(1)
360 	//if( mtxAp->flags & RSB_FLAG_USE_HALFWORD_INDICES_COO )
361 	{
362 		// FIXME: THIS IS SLOW, TEMPORARY
363 		rsb_coo_idx_t i;
364 		long nt = rsb_get_num_threads();
365 		const int gdc = RSB_DIVIDE_IN_CHUNKS(mtxAp->nr,nt);
366 		#pragma omp parallel for schedule(static,gdc) reduction(|:errval)  RSB_NTC
367 		for(i=0;i<mtxAp->nr;++i)
368 			RSB_DO_ERROR_CUMULATE(errval,rsb__do_get_coo_element(mtxAp,((rsb_char_t*)diagonal)+mtxAp->el_size*(i),i,i));
369 		errval = RSB_ERR_NO_ERROR;
370 	}
371 #if 0
372 	else
373 	{
374 		RSB_BZERO(diagonal,mtxAp->el_size*RSB_MTX_DIAG_SIZE(mtxAp));
375 		errval = rsb_do_getdiag(mtxAp,diagonal);
376 	}
377 #endif
378 err:
379 	return errval;
380 }
381 
rsb_do_elemental_scale(struct rsb_mtx_t * mtxAp,const void * alphap)382 static rsb_err_t rsb_do_elemental_scale(struct rsb_mtx_t * mtxAp, const void * alphap)
383 {
384 	/*!
385 	   \ingroup rsb_doc_matrix_handling
386 
387 	   Computes \f$ A \leftarrow \alpha A \f$.
388 
389 	   \param \rsb_mtxt_inp_param_msg
390 	   \param \rsb_alpha_inp_param_msg
391 	   \return \rsberrcodemsg
392 	 */
393 	rsb_err_t errval = RSB_ERR_NO_ERROR;
394 	struct rsb_mtx_t * submatrix=NULL;
395 
396 	if(!mtxAp)
397        	{
398 		errval = RSB_ERR_BADARGS;
399 	       	goto err;
400 	}
401 #if RSB_WANT_PARALLEL_ELEMENTAL_OPS
402 	if(1)
403 		errval = rsb__do_elemental_scale_parallel(mtxAp,alphap);
404 #else /* RSB_WANT_PARALLEL_ELEMENTAL_OPS */
405 	if(rsb__is_recursive_matrix(mtxAp->flags))
406 	{
407 		rsb_submatrix_idx_t smi;
408 		//#pragma omp parallel for schedule(static,1) reduction(|:errval)  shared(mtxAp) RSB_NTC
409 		RSB_SUBMATRIX_FOREACH_LEAF(mtxAp,submatrix,smi)
410 			RSB_DO_ERROR_CUMULATE(errval,rsb__cblas_Xscal(submatrix->typecode,submatrix->nnz,alphap,submatrix->VA,1));
411 	}
412 #endif /* RSB_WANT_PARALLEL_ELEMENTAL_OPS */
413 	else
414 		RSB_DO_ERROR_CUMULATE(errval,rsb__cblas_Xscal(mtxAp->typecode,mtxAp->nnz,alphap,mtxAp->VA,1));
415 err:
416 	return errval;
417 }
418 
rsb_do_elemental_scale_inv(struct rsb_mtx_t * mtxAp,const void * alphap)419 static rsb_err_t rsb_do_elemental_scale_inv(struct rsb_mtx_t * mtxAp, const void * alphap)
420 {
421 	/*!
422 	   \ingroup rsb_doc_matrix_handling
423 
424 	   Computes \f$ A \leftarrow \frac{1}{\alpha} A \f$.
425 
426 	   \param \rsb_mtxt_inp_param_msg
427 	   \param \rsb_alpha_inp_param_msg
428 	   \return \rsberrcodemsg
429 	 */
430 	rsb_err_t errval = RSB_ERR_NO_ERROR;
431 	struct rsb_mtx_t * submatrix=NULL;
432 
433 	if(!mtxAp)
434        	{
435 		errval = RSB_ERR_BADARGS;
436 	       	goto err;
437 	}
438 
439 	if(rsb__is_recursive_matrix(mtxAp->flags))
440 	{
441 		rsb_submatrix_idx_t smi;
442 		//#pragma omp parallel for schedule(static,1) reduction(|:errval)  shared(mtxAp) RSB_NTC
443 		RSB_SUBMATRIX_FOREACH_LEAF(mtxAp,submatrix,smi)
444 			RSB_DO_ERROR_CUMULATE(errval,rsb__vector_scale_inv(submatrix->VA,alphap,submatrix->typecode,submatrix->nnz));
445 	}
446 	else
447 		RSB_DO_ERROR_CUMULATE(errval,rsb__vector_scale_inv(mtxAp->VA,alphap,mtxAp->typecode,mtxAp->nnz));
448 err:
449 	return errval;
450 }
451 
rsb_do_elemental_pow(struct rsb_mtx_t * mtxAp,const void * alphap)452 static rsb_err_t rsb_do_elemental_pow(struct rsb_mtx_t * mtxAp, const void * alphap)
453 {
454 	/*!
455 	   \ingroup rsb_doc_matrix_handling
456 
457 	   Raises each matrix element to the given power.
458 
459 	   \param \rsb_mtxt_inp_param_msg
460 	   \param \rsb_alpha_inp_param_msg
461 	   \return \rsberrcodemsg
462 	 */
463 	rsb_err_t errval = RSB_ERR_NO_ERROR;
464 	struct rsb_mtx_t * submatrix=NULL;
465 
466 	if(!mtxAp)
467        	{
468 		errval = RSB_ERR_BADARGS;
469 	       	goto err;
470 	}
471 	if(rsb__is_recursive_matrix(mtxAp->flags))
472 	{
473 		rsb_submatrix_idx_t smi;
474 		//#pragma omp parallel for schedule(static,1) reduction(|:errval)  shared(mtxAp) RSB_NTC
475 		RSB_SUBMATRIX_FOREACH_LEAF(mtxAp,submatrix,smi)
476 			RSB_DO_ERROR_CUMULATE(errval,rsb__util_vector_pow(submatrix->VA,submatrix->typecode,alphap,submatrix->nnz));
477 	}
478 	else
479 		RSB_DO_ERROR_CUMULATE(errval,rsb__util_vector_pow(mtxAp->VA,mtxAp->typecode,alphap,mtxAp->nnz));
480 err:
481 	return errval;
482 }
483 
rsb_dodo_negation(struct rsb_mtx_t * mtxAp)484 static rsb_err_t rsb_dodo_negation(struct rsb_mtx_t * mtxAp)
485 {
486 #ifdef RSB_HAVE_OPTYPE_NEGATION
487 	rsb_err_t errval = RSB_ERR_NO_ERROR;
488 
489 	if(!mtxAp)
490 		{errval = RSB_ERR_BADARGS;goto err;}
491 
492 	if(rsb__is_recursive_matrix(mtxAp->flags))
493 	{
494 		rsb_submatrix_idx_t i,j;
495 		struct rsb_mtx_t * submatrix=NULL;
496 
497 		RSB_SUBMATRIX_FOREACH(mtxAp,submatrix,i,j)
498 		if(submatrix)
499 			RSB_DO_ERROR_CUMULATE(errval,rsb_dodo_negation(submatrix));
500 	}
501 	else
502 		errval = rsb_do_negation(mtxAp,0xf1c57415,RSB_DEFAULT_TRANSPOSITION);
503 #else /* RSB_HAVE_OPTYPE_NEGATION */
504 	/* FIXME : eliminate negation as mop ! */
505 //	return RSB_ERR_UNSUPPORTED_OPERATION;
506 	rsb_err_t errval = RSB_ERR_NO_ERROR;
507 	if(!mtxAp)
508 		{errval = RSB_ERR_BADARGS;goto err;}
509 
510 	if(rsb__is_recursive_matrix(mtxAp->flags))
511 	{
512 		rsb_submatrix_idx_t i,j;
513 		struct rsb_mtx_t * submatrix=NULL;
514 
515 		RSB_SUBMATRIX_FOREACH(mtxAp,submatrix,i,j)
516 		if(submatrix)
517 			RSB_DO_ERROR_CUMULATE(errval,rsb_dodo_negation(submatrix));
518 	}
519 	else
520 		/* FIXME : assuming elements are contiguous ! */
521 		errval = rsb__util_do_negate(mtxAp->VA,mtxAp->typecode,mtxAp->element_count);
522 #endif /* RSB_HAVE_OPTYPE_NEGATION */
523 err:
524 	return errval;
525 }
526 
rsb__do_elemental_unop(struct rsb_mtx_t * mtxAp,enum rsb_elopf_t elop_flags)527 rsb_err_t rsb__do_elemental_unop(struct rsb_mtx_t * mtxAp, enum rsb_elopf_t elop_flags)
528 {
529 	// FIXME: untested
530 	rsb_err_t errval = RSB_ERR_NO_ERROR;
531 
532 	if(!mtxAp) {errval = RSB_ERR_BADARGS; goto err;}
533 	switch(elop_flags)
534 	{
535 		case(RSB_ELOPF_NEG):
536 		errval = rsb_dodo_negation(mtxAp);
537 		break;
538 		//#define RSB_ELOPF_SQRT		0x00000010		/*!< Elemental square root (usable with rsb_mtx_elemental_unop). */
539 		/*
540 		case(RSB_ELOPF_SQRT):
541 		errval=....(mtxAp);
542 		break;
543 		*/
544 	/*	case(RSB_ELOPF_TRANS):
545 		errval = rsb_transpose(&mtxAp);
546 		break;
547 		case(RSB_ELOPF_HTRANS):
548 		errval = rsb_htranspose(&mtxAp);
549 		break;*/
550 		default:
551 		{errval = RSB_ERR_BADARGS; goto err;}
552 	}
553 err:
554 	return errval;
555 }
556 
rsb__do_elemental_binop(struct rsb_mtx_t * mtxAp,enum rsb_elopf_t elop_flags,const void * opp)557 rsb_err_t rsb__do_elemental_binop(struct rsb_mtx_t * mtxAp, enum rsb_elopf_t elop_flags, const void * opp)
558 {
559 	// FIXME: untested
560 	rsb_err_t errval = RSB_ERR_NO_ERROR;
561 	rsb_trans_t transA = RSB_TRANSPOSITION_N;
562 	void * topp=NULL;
563 
564 	if(!mtxAp) {errval = RSB_ERR_BADARGS; goto err;}
565 	if(!opp) {errval = RSB_ERR_BADARGS; goto err;}
566 
567 	switch(elop_flags)
568 	{
569 		case(RSB_ELOPF_SCALE_COLS_REAL):
570 		case(RSB_ELOPF_SCALE_COLS):
571 		transA = RSB_TRANSPOSITION_T;
572 		break;
573 		default: RSB_NULL_STATEMENT_FOR_COMPILER_HAPPINESS;
574 	}
575 
576 	switch(elop_flags)
577 	{
578 		case(RSB_ELOPF_SCALE_COLS_REAL):
579 		case(RSB_ELOPF_SCALE_ROWS_REAL):
580 		if( RSB_IS_MATRIX_TYPE_COMPLEX(mtxAp->typecode) )
581 		{
582 			/* FIXME: this is inefficient */
583 			rsb_type_t typecode = RSB_NUMERICAL_TYPE_REAL_TYPE(mtxAp->typecode);
584 			if( NULL == (topp = rsb__calloc_vector(mtxAp->nr,mtxAp->typecode)) )
585 			{
586 				errval = RSB_ERR_ENOMEM;
587 				goto err;
588 			}
589 			errval = rsb__cblas_Xcopy(typecode,mtxAp->nr,opp,1,topp,2);
590 		}
591 		case(RSB_ELOPF_SCALE_COLS):
592 		case(RSB_ELOPF_SCALE_ROWS):
593 		errval = rsb__do_scal(mtxAp,topp?topp:opp,transA);
594 		break;
595 		case(RSB_ELOPF_MUL):
596 		errval = rsb_do_elemental_scale(mtxAp,opp);
597 		break;
598 		case(RSB_ELOPF_DIV):
599 		errval = rsb_do_elemental_scale_inv(mtxAp,opp);
600 		break;
601 		case(RSB_ELOPF_POW):
602 		errval = rsb_do_elemental_pow(mtxAp,opp);
603 		break;
604 		default:
605 		{
606 			errval = RSB_ERR_BADARGS;
607 		       	goto err;
608 		}
609 	}
610 err:
611 	RSB_CONDITIONAL_FREE(topp);
612 	return errval;
613 }
614 
rsb__dodo_get_rows_nnz(const struct rsb_mtx_t * mtxAp,rsb_blk_idx_t fr,rsb_blk_idx_t lr,rsb_flags_t flags,rsb_err_t * errvalp)615 rsb_nnz_idx_t rsb__dodo_get_rows_nnz(const struct rsb_mtx_t *mtxAp, rsb_blk_idx_t fr, rsb_blk_idx_t lr, rsb_flags_t flags, rsb_err_t * errvalp)
616 {
617 	rsb_err_t errval = RSB_ERR_NO_ERROR;
618 	rsb_nnz_idx_t rnz = 0;
619 
620 	RSB_DEBUG_ASSERT(fr <= lr);
621 
622 	if(RSB_DO_FLAG_HAS(flags,RSB_FLAG_FORTRAN_INDICES_INTERFACE))
623 		lr--,fr--;
624 	errval = rsb_do_get_rows_nnz(mtxAp,fr,lr,&rnz);
625 	RSB_CONDITIONAL_ERRPSET(errvalp,errval);
626 	if(RSB_SOME_ERROR(errval))
627 		rnz=0;
628 	return rnz;
629 }
630 
631 #if RSB_WANT_PARALLEL_ELEMENTAL_OPS
632 rsb_err_t rsb__do_elemental_scale_parallel(struct rsb_mtx_t * mtxAp, const void * alphap);
633 {
634 	/**
635 		\ingroup gr_internals
636 		TODO: move to somewhere else
637 	 */
638 	rsb_err_t errval = RSB_ERR_NO_ERROR;
639 	const rsb_thread_t wet = rsb_get_num_threads();
640 
641 	if(RSB_UNLIKELY(mtxAp->nnz<wet*RSB_MIN_THREAD_MEMCPY_NNZ))
642 	{
643 		RSB_DO_ERROR_CUMULATE(errval,rsb__cblas_Xscal(mtxAp->typecode,mtxAp->nnz,alphap,((rsb_byte_t*)mtxAp->VA),1));
644 	}
645 	else
646 	{
647 		rsb_nnz_idx_t wi;
648 		size_t cnz=(mtxAp->nnz+wet-1)/wet;	/* chunk size */
649 		#pragma omp parallel for schedule(static,1) RSB_NTC
650 		for(wi=0;wi<wet;++wi)
651 		{
652 			size_t coff=wi*cnz;
653 			size_t cnnz=(wi<wet-1)?cnz:mtxAp->nnz-((wet-1)*cnz);
654 			printf("%d nz on %d\n",cnnz,wi);
655 			RSB_DO_ERROR_CUMULATE(errval,rsb__cblas_Xscal(mtxAp->typecode,cnnz,alphap,((rsb_byte_t*)mtxAp->VA)+RSB_SIZEOF(mtxAp->typecode)*mtxAp->coff,1));
656 		}
657 	}
658 }
659 #endif /* RSB_WANT_PARALLEL_ELEMENTAL_OPS */
660 
rsb__do_matrix_add_to_dense(const void * alphap,const struct rsb_mtx_t * mtxAp,rsb_nnz_idx_t ldB,rsb_nnz_idx_t nr,rsb_nnz_idx_t nc,rsb_bool_t rowmajor,void * Bp)661 rsb_err_t rsb__do_matrix_add_to_dense(const void *alphap, const struct rsb_mtx_t * mtxAp, rsb_nnz_idx_t ldB, rsb_nnz_idx_t nr, rsb_nnz_idx_t nc, rsb_bool_t rowmajor, void * Bp)
662 {
663 	//  FIXME: could this be documented in two groups (mops and unfinished) at the same time ?
664 	//  TODO: what about supporting transA ?
665 	rsb_err_t errval = RSB_ERR_NO_ERROR;
666 	struct rsb_mtx_t * submatrix = NULL;
667 	rsb_aligned_t pone[RSB_CONST_ENOUGH_ALIGNED_FOR_ANY_TYPE];
668 
669 	if(!mtxAp)
670 	{
671 		errval = RSB_ERR_BADARGS;
672 		goto err;
673 	}
674 
675 	if(!alphap)
676 	{
677 		rsb__util_set_area_to_converted_integer(&pone[0],mtxAp->typecode,+1);
678 		alphap = &pone[0];
679 	}
680 
681 	if(rsb__is_recursive_matrix(mtxAp->flags))
682 	{
683 		rsb_submatrix_idx_t smi;
684 		//#pragma omp parallel for schedule(static,1) reduction(|:errval)  shared(mtxAp) RSB_NTC
685 		RSB_SUBMATRIX_FOREACH_LEAF(mtxAp,submatrix,smi)
686 			RSB_DO_ERROR_CUMULATE(errval,rsb__do_add_submatrix_to_dense(submatrix,alphap,Bp,ldB,nr,nc,rowmajor));
687 	}
688 	else
689 		RSB_DO_ERROR_CUMULATE(errval,rsb__do_add_submatrix_to_dense(mtxAp,alphap,Bp,ldB,nr,nc,rowmajor));
690 err:
691 	return errval;
692 }
693 
rsb__do_switch_rsb_mtx_to_csr_sorted(struct rsb_mtx_t * mtxAp,void ** VAP,rsb_coo_idx_t ** IAP,rsb_coo_idx_t ** JAP,rsb_flags_t flags)694 rsb_err_t rsb__do_switch_rsb_mtx_to_csr_sorted(struct rsb_mtx_t * mtxAp, void ** VAP, rsb_coo_idx_t ** IAP, rsb_coo_idx_t ** JAP, rsb_flags_t flags)
695 {
696 	rsb_err_t errval = RSB_ERR_NO_ERROR;
697 	struct rsb_coo_matrix_t coo;
698 	const rsb_nnz_idx_t nnz=mtxAp?mtxAp->nnz:0;
699 	const rsb_coo_idx_t m=mtxAp?mtxAp->nr:0;
700 	//const rsb_coo_idx_t k=mtxAp?mtxAp->nc:0;
701 	const rsb_flags_t mflags=mtxAp?mtxAp->flags:RSB_FLAG_NOFLAGS;
702 
703 	if(!mtxAp)
704        	{
705 	       	errval = RSB_ERR_BADARGS;
706 	       	goto err;
707        	}
708 
709 	if(!RSB_DO_FLAG_HAS(mtxAp->flags,RSB_FLAG_EXTERNALLY_ALLOCATED_ARRAYS))
710 	{
711 	       	errval = RSB_ERR_BADARGS;
712 	       	goto err;
713        	}
714 
715 	if(!IAP || !JAP || !VAP)
716 	{
717 		errval = RSB_ERR_BADARGS;
718 		RSB_PERR_GOTO(err,RSB_ERRM_E_VIJP);
719 	}
720 	errval = rsb__do_switch_recursive_in_place_matrix_to_in_place_coo_sorted(mtxAp,&coo);
721 	if(RSB_SOME_ERROR(errval))
722 		goto err;
723 	errval = rsb__util_compress_to_row_pointers_array(NULL,nnz,m,mflags,flags,coo.IA);
724 	if(RSB_SOME_ERROR(errval))
725 		goto err;
726 	if(RSB_DO_FLAG_HAS(flags,RSB_FLAG_FORTRAN_INDICES_INTERFACE))
727 		rsb__util_nnz_array_to_fortran_indices(coo.JA,nnz);
728 	*JAP=coo.JA;
729 	*IAP=coo.IA;
730 	*VAP=coo.VA;
731 err:
732 	return errval;
733 }
734 
rsb__do_get_csr(rsb_type_t typecode,const struct rsb_mtx_t * mtxAp,rsb_byte_t * VA,rsb_nnz_idx_t * RP,rsb_coo_idx_t * JA,rsb_flags_t flags)735 rsb_err_t rsb__do_get_csr(rsb_type_t typecode, const struct rsb_mtx_t *mtxAp, rsb_byte_t * VA, rsb_nnz_idx_t * RP, rsb_coo_idx_t * JA, rsb_flags_t flags)
736 {
737 	/* NOTE this writes more than mtxAp->nnz elements! */
738 	rsb_err_t errval = RSB_ERR_NO_ERROR;
739 
740 	if(!mtxAp)
741 	{
742 	       	errval = RSB_ERR_BADARGS;
743 		RSB_PERR_GOTO(err,RSB_ERRM_ES);
744        	}
745 
746 #define RSB_WANT_OLD_TO_CSR_SEMANTICS 0
747 
748 	if((mtxAp->typecode != typecode && typecode != RSB_NUMERICAL_TYPE_SAME_TYPE) || (mtxAp->flags != flags))/* FIXME: condition on cflags is unnecessarily restrictive */
749 	{
750 		const rsb_flags_t flagsC = flags | (mtxAp->flags & RSB_FLAG_ALL_STRUCTURAL_FLAGS);
751 		struct rsb_mtx_t * mtxCp = NULL;
752 		errval = rsb__mtx_clone(&mtxCp, typecode, RSB_TRANSPOSITION_N, NULL, mtxAp, flagsC );
753 		if(RSB_SOME_ERROR(errval))
754 			RSB_PERR_GOTO(err,RSB_ERRM_ES);
755 		errval = rsb__dodo_get_csr(mtxCp,&VA,&RP,&JA);
756 		RSB_MTX_FREE(mtxCp);
757 	}
758 	else
759 		errval = rsb__dodo_get_csr(mtxAp,&VA,&RP,&JA);
760 
761 	if(RSB_SOME_ERROR(errval))
762 	{
763 		RSB_PERR_GOTO(err,RSB_ERRM_ES);
764        	}
765 //#if RSB_WANT_OLD_TO_CSR_SEMANTICS
766 	/* FIXME: shall move C -> Fortran indices semantics to rsb__dodo_get_csr */
767 	if(flags & RSB_FLAG_FORTRAN_INDICES_INTERFACE)
768 		rsb__util_nnz_array_to_fortran_indices(RP,mtxAp->nr+1),
769 		rsb__util_nnz_array_to_fortran_indices(JA,mtxAp->nnz);
770 //#endif
771 err:
772 	return errval;
773 }
774 
rsb__do_get_matrix_info(const struct rsb_mtx_t * mtxAp,enum rsb_mif_t miflags,void * info,size_t buflen)775 rsb_err_t rsb__do_get_matrix_info(const struct rsb_mtx_t *mtxAp, enum rsb_mif_t miflags, void* info, size_t buflen)
776 {
777 	/*!
778 	   \ingroup FIXME
779 	   \warning \rsb_warn_unfinished_msg
780 		FIXME: UNFINISHED, UNTESTED
781 	*/
782 	rsb_err_t errval = RSB_ERR_NO_ERROR;
783 	rsb_real_t rrv=0;
784 	size_t szv=0;
785 	rsb_coo_idx_t civ=0;
786 	rsb_nnz_idx_t niv=0;
787 	rsb_flags_t fiv=0;
788 	rsb_type_t tiv=0;
789 	rsb_blk_idx_t biv=0;
790 	char*cis=(char*)info;
791 
792 	if(!mtxAp || !info)
793 	{
794 	       	errval = RSB_ERR_BADARGS;
795 	       	goto err;
796 	}
797 	switch(miflags)
798 	{
799 		case RSB_MIF_INDEX_STORAGE_IN_BYTES__TO__SIZE_T:
800 		{
801 		       	szv = rsb__get_index_storage_amount(mtxAp);
802 		       	if(buflen<=0) *(size_t*)info = szv;
803 		        else snprintf(cis,buflen,"%zd",szv);
804 	       	}
805 		break;
806 		case RSB_MIF_INDEX_STORAGE_IN_BYTES_PER_NNZ__TO__RSB_REAL_T:
807 		{
808 			const size_t isa = rsb__get_index_storage_amount(mtxAp);
809 			if ( mtxAp->nnz > 0 )
810 				rrv = ((rsb_real_t)isa) / ((rsb_real_t)mtxAp->nnz);
811 			else
812 				rrv = 2 * sizeof(rsb_coo_idx_t);
813 			if(buflen<=0)
814 				*(rsb_real_t*) info=rrv;
815 			else
816 				snprintf(cis,buflen,"%lg",rrv);
817 		}
818 		break;
819 		case RSB_MIF_MATRIX_ROWS__TO__RSB_COO_INDEX_T:
820 		{
821 		       	civ = (mtxAp->nr);
822 	                if(buflen<=0) *(rsb_coo_idx_t*)info = civ;
823 		        else snprintf(cis,buflen,"%d",civ);
824 	       	}
825 		break;
826 		case RSB_MIF_MATRIX_COLS__TO__RSB_COO_INDEX_T:
827 		{
828 		       	civ = (mtxAp->nc);
829 	                if(buflen<=0) *(rsb_coo_idx_t*)info = civ;
830 		        else snprintf(cis,buflen,"%d",civ);
831 	       	}
832 		break;
833 		case RSB_MIF_MATRIX_NNZ__TO__RSB_NNZ_INDEX_T:
834 		{
835 		       	niv = (mtxAp->nnz);
836 	                if(buflen<=0) *(rsb_nnz_idx_t*)info = niv;
837 		        else snprintf(cis,buflen,"%d",niv);
838 	       	}
839 		break;
840 		case RSB_MIF_TOTAL_SIZE__TO__SIZE_T:
841 		{
842 		       	szv = rsb__get_sizeof(mtxAp);
843 		       	if(buflen<=0) *(size_t*)info = szv;
844 		        else snprintf(cis,buflen,"%zd",szv);
845 	       	}
846 		break;
847 		case RSB_MIF_MATRIX_FLAGS__TO__RSB_FLAGS_T:
848 		{
849 		       	fiv = (mtxAp->flags);
850 		       	if(buflen<=0) *(rsb_flags_t*)info = fiv;
851 		        else snprintf(cis,buflen,"%d",fiv);
852 	       	}
853 		break;
854 		case RSB_MIF_MATRIX_TYPECODE__TO__RSB_TYPE_T:
855 		{
856 		       	tiv = (mtxAp->typecode);
857 		       	if(buflen<=0) *(rsb_type_t*)info = tiv;
858 		        else snprintf(cis,buflen,"%d",tiv);
859 	       	}
860 		break;
861 		case RSB_MIF_MATRIX_INFO__TO__CHAR_P:
862 		{
863 		       	tiv = (mtxAp->typecode);
864 		       	if(buflen<=0) { errval = RSB_ERR_BADARGS; goto err; }
865 		        else snprintf(cis,buflen,RSB_PRINTF_MTX_SUMMARY_ARGS(mtxAp));
866 
867 	       	}
868 		break;
869 		case RSB_MIF_LEAVES_COUNT__TO__RSB_BLK_INDEX_T:
870 		{
871 		       	biv = (mtxAp->all_leaf_matrices_n);
872 		       	if(buflen<=0) *(rsb_blk_idx_t*)info = biv;
873 		        else snprintf(cis,buflen,"%d",biv);
874 	       	}
875 		break;
876 		default:
877 		errval = RSB_ERR_GENERIC_ERROR;
878 	}
879 err:
880 	return errval;
881 }
882 
rsb__do_check_leak(void)883 rsb_err_t rsb__do_check_leak(void)
884 {
885 	/*!
886 	   \ingroup rsb_doc_library
887 
888 	   Called after \ref rsb_lib_exit(), will report on the standard output stream
889 	   (see #RSB_IO_WANT_OUTPUT_STREAM) whether some previously allocated
890 	   memory area was not freed by librsb.
891 	   \n
892 	   Will report leak information only if built with the #RSB_DISABLE_ALLOCATOR_WRAPPER symbol undefined.
893 	   \n
894 	   Will return #RSB_ERR_NO_ERROR on no leak; an error otherwise.
895 	   \n
896 
897 	   \warning \rsb_warn_soon_to_be_deprecated_msg
898 	   \return \rsberrcodemsg
899 	 */
900 	rsb_err_t errval = RSB_ERR_NO_ERROR;
901 
902 	if(rsb__get_g_rsb_memory_count())
903 	{
904 		RSB_INFO("WARNING: allocated memory  : %zu : POSSIBLE MEMORY LEAK\n",rsb__get_g_rsb_memory_count());
905 		RSB_DO_ERROR_CUMULATE(errval,RSB_ERR_INTERNAL_ERROR);
906 	}
907 
908 	if(rsb__get_g_rsb_allocations_count())
909 	{
910 		RSB_INFO("WARNING: allocations count : %zu : POSSIBLE MEMORY LEAK\n",rsb__get_g_rsb_allocations_count());
911 		RSB_DO_ERROR_CUMULATE(errval,RSB_ERR_INTERNAL_ERROR);
912 	}
913 	return errval;
914 }
915 
rsb__do_matrix_norm(const struct rsb_mtx_t * mtxAp,void * np,enum rsb_extff_t flags)916 rsb_err_t rsb__do_matrix_norm(const struct rsb_mtx_t * mtxAp , void * np, enum rsb_extff_t flags)
917 {
918 	rsb_err_t errval = RSB_ERR_BADARGS;
919 
920 	switch(flags)
921 	{
922 		case RSB_EXTF_NORM_ONE:
923 		errval = rsb__do_infinity_norm(mtxAp,np,RSB_BOOL_FALSE,RSB_TRANSPOSITION_T);
924 		break;
925 		case RSB_EXTF_NORM_TWO:/* FIXME: UNTESTED ! */
926 		errval = rsb__cblas_Xnrm2(mtxAp->typecode,mtxAp->nnz,rsb__do_get_first_submatrix(mtxAp)->VA,1,np);
927 		break;
928 		case RSB_EXTF_NORM_INF:
929 		errval = rsb__do_infinity_norm(mtxAp,np,RSB_BOOL_FALSE,RSB_TRANSPOSITION_N);
930 		break;
931 		default:
932 		break;
933 	}
934 	return errval;
935 }
936 
rsb__do_matrix_compute(const struct rsb_mtx_t * mtxAp,void * dp,enum rsb_extff_t flags)937 rsb_err_t rsb__do_matrix_compute(const struct rsb_mtx_t * mtxAp , void * dp, enum rsb_extff_t flags)
938 {
939 	rsb_err_t errval = RSB_ERR_BADARGS;
940 
941 #if RSB_ALLOW_ZERO_DIM
942 	if(RSB_ANY_MTX_DIM_ZERO(mtxAp))
943 	{
944 		errval = RSB_ERR_NO_ERROR;
945 		goto ret; /* FIXME: skipping further error checks */
946 	}
947 #endif
948 
949 	if( mtxAp == NULL || ( mtxAp->nnz > 0 && dp == NULL ) )
950 		goto ret;
951 
952 	switch(flags)
953 	{
954 		case RSB_EXTF_SUMS_ROW:
955 		errval = rsb__do_rows_sums_inner(mtxAp,dp,RSB_BOOL_FALSE,RSB_TRANSPOSITION_N);
956 		break;
957 		case RSB_EXTF_SUMS_COL:
958 		errval = rsb__do_rows_sums_inner(mtxAp,dp,RSB_BOOL_FALSE,RSB_TRANSPOSITION_T);
959 		break;
960 		case RSB_EXTF_ASUMS_ROW:
961 		errval = rsb__do_absolute_rows_sums( mtxAp , dp);
962 		break;
963 		case RSB_EXTF_ASUMS_COL:
964 		errval = rsb__do_absolute_columns_sums(mtxAp,dp);
965 		break;
966 		case RSB_EXTF_DIAG:
967 		errval = rsb__dodo_getdiag(mtxAp,dp);
968 		break;
969 		default:
970 		break;
971 	}
972 ret:
973 	return errval;
974 }
975 
rsb__do_load_vector_file_as_matrix_market(const rsb_char_t * filename,rsb_type_t typecode,void * yp,rsb_coo_idx_t * yvlp)976 rsb_err_t rsb__do_load_vector_file_as_matrix_market(const rsb_char_t * filename, rsb_type_t typecode, void * yp, rsb_coo_idx_t *yvlp)
977 {
978 	rsb_err_t errval = RSB_ERR_NO_ERROR;
979 
980 	if(!filename || ((!yvlp) && (!yp)))
981 	{
982 		errval = RSB_ERR_BADARGS;
983 		RSB_PERR_GOTO(err,RSB_ERRM_EM);
984 	}
985 	if(yvlp)
986 	{
987 		/* FIXME: temporarily ignoring second dimension! */
988 		rsb_coo_idx_t yvk=0, yvm=0;
989 		rsb_bool_t is_vector = RSB_BOOL_FALSE;
990 
991 		if(RSB_SOME_ERROR(errval = rsb__util_mm_info_matrix_f(filename,&yvm,&yvk,NULL,NULL,NULL,NULL,NULL,NULL,NULL,&is_vector)) )
992 		{
993 			RSB_PERR_GOTO(err,RSB_ERRM_EM);
994 		}
995 		*yvlp=yvm;
996 	}
997 	if(yp)
998 	{
999 		/* printf("stub: reading in %s...\n",filename); */
1000 		rsb_nnz_idx_t vnz=0;
1001 
1002 		errval = rsb__util_mm_load_vector_f(filename,&yp,&vnz,typecode);
1003 	}
1004 err:
1005 	return errval;
1006 }
1007 
rsb__dodo_load_matrix_file_as_matrix_market(const rsb_char_t * filename,rsb_flags_t flags,rsb_type_t typecode,rsb_err_t * errvalp)1008 struct rsb_mtx_t * rsb__dodo_load_matrix_file_as_matrix_market(const rsb_char_t * filename, rsb_flags_t flags, rsb_type_t typecode, rsb_err_t *errvalp)
1009 {
1010 	// FIXME
1011 	struct rsb_mtx_t * mtxAp = NULL;
1012 	rsb_err_t errval = RSB_ERR_NO_ERROR;
1013 
1014        	errval = rsb__do_load_matrix_file_as_matrix_market(&mtxAp,filename,flags,typecode);
1015 	RSB_CONDITIONAL_ERRPSET(errvalp,errval);
1016 	return mtxAp;
1017 }
1018 
rsb__do_was_initialized(void)1019 rsb_bool_t rsb__do_was_initialized(void)
1020 {
1021 	/*!
1022 	   \ingroup rsb_doc_library
1023 
1024 	   Call this function to know whether the library had already been initialized or not.
1025 	   \n
1026 	   This function is mainly intended to be used in between \ref rsb_lib_exit() and \ref rsb_lib_init() calls,
1027 	   or generally after one or more calls to \ref rsb_lib_init() were already been done.
1028 	   \n
1029 	   It is not meant to be called before the 'first' initialization ever, unless
1030 	   the user is sure this library was built on a system which supports default
1031 	   initialization to zero of static variables (which indeed is supported by most standards;
1032 	   e.g.: ANSI C: http://flash-gordon.me.uk/ansi.c.txt ).
1033 
1034 	   \return #RSB_BOOL_TRUE if it was initialized, #RSB_BOOL_FALSE otherwise.
1035 	 */
1036 	/* TODO: redocument elsewhere! redundant function! */
1037 	return (rsb_global_session_handle.rsb_g_initialized == RSB_BOOL_TRUE) ? RSB_BOOL_TRUE : RSB_BOOL_FALSE;
1038 }
1039 
rsb__do_switch_rsb_mtx_to_coo_unsorted(struct rsb_mtx_t * mtxAp,void ** VAP,rsb_coo_idx_t ** IAP,rsb_coo_idx_t ** JAP,rsb_flags_t flags)1040 static rsb_err_t rsb__do_switch_rsb_mtx_to_coo_unsorted(struct rsb_mtx_t * mtxAp, void ** VAP, rsb_coo_idx_t ** IAP, rsb_coo_idx_t ** JAP, rsb_flags_t flags)
1041 {
1042 	struct rsb_coo_matrix_t coo;
1043 	rsb_err_t errval = RSB_ERR_NO_ERROR;
1044 
1045 	RSB_ASSERT( RSB_DO_FLAG_HAS(mtxAp->flags, RSB_FLAG_EXTERNALLY_ALLOCATED_ARRAYS) );
1046 
1047 	if(!IAP || !JAP || !VAP)
1048 	{
1049 		errval = RSB_ERR_BADARGS;
1050 		RSB_PERR_GOTO(err,RSB_ERRM_EM);
1051 	}
1052 
1053 	errval = rsb__do_switch_recursive_in_place_matrix_to_in_place_coo_unsorted(mtxAp,&coo);
1054 	if(RSB_DO_FLAG_HAS(flags,RSB_FLAG_FORTRAN_INDICES_INTERFACE))
1055 		rsb__util_nnz_array_to_fortran_indices(coo.IA,coo.nnz),
1056 		rsb__util_nnz_array_to_fortran_indices(coo.JA,coo.nnz);
1057 	*JAP = coo.JA;
1058 	*IAP = coo.IA;
1059 	*VAP = coo.VA;
1060 err:
1061 	return errval;
1062 }
1063 
rsb__do_switch_rsb_mtx_to_coo_sorted(struct rsb_mtx_t * mtxAp,void ** VAP,rsb_coo_idx_t ** IAP,rsb_coo_idx_t ** JAP,rsb_flags_t flags)1064 static rsb_err_t rsb__do_switch_rsb_mtx_to_coo_sorted(struct rsb_mtx_t * mtxAp, void ** VAP, rsb_coo_idx_t ** IAP, rsb_coo_idx_t ** JAP, rsb_flags_t flags)
1065 {
1066 	rsb_err_t errval = RSB_ERR_NO_ERROR;
1067 	struct rsb_coo_matrix_t coo;
1068 	const rsb_nnz_idx_t nnz = mtxAp ? mtxAp-> nnz:0;
1069 
1070 	RSB_ASSERT( RSB_DO_FLAG_HAS(mtxAp->flags, RSB_FLAG_EXTERNALLY_ALLOCATED_ARRAYS) );
1071 
1072 	if(!IAP || !JAP || !VAP)
1073 	{
1074 		errval = RSB_ERR_BADARGS;
1075 		RSB_PERR_GOTO(err, RSB_ERRM_EM);
1076 	}
1077 
1078 	RSB_BZERO_P(&coo);
1079 	errval = rsb__do_switch_recursive_in_place_matrix_to_in_place_coo_sorted(mtxAp, &coo);
1080 	if(RSB_SOME_ERROR(errval))
1081 	{
1082 		RSB_PERR_GOTO(err, RSB_ERRM_EM);
1083 	}
1084 	if(RSB_DO_FLAG_HAS(flags,RSB_FLAG_FORTRAN_INDICES_INTERFACE))
1085 		rsb__util_nnz_array_to_fortran_indices(coo.IA, nnz),
1086 		rsb__util_nnz_array_to_fortran_indices(coo.JA, nnz);
1087 	*JAP = coo.JA;
1088 	*IAP = coo.IA;
1089 	*VAP = coo.VA;
1090 err:
1091 	return errval;
1092 }
1093 
rsb__do_switch_rsb_mtx_to_coo(struct rsb_mtx_t * mtxAp,void ** VAP,rsb_coo_idx_t ** IAP,rsb_coo_idx_t ** JAP,rsb_flags_t flags)1094 rsb_err_t rsb__do_switch_rsb_mtx_to_coo(struct rsb_mtx_t * mtxAp, void ** VAP, rsb_coo_idx_t ** IAP, rsb_coo_idx_t ** JAP, rsb_flags_t flags)
1095 {
1096 	rsb_err_t errval = RSB_ERR_NO_ERROR;
1097 
1098 	if(!mtxAp)
1099        	{
1100 	       	errval = RSB_ERR_BADARGS;
1101 		RSB_PERR_GOTO(err, RSB_ERRM_E_MTXAP"\n");
1102        	}
1103 
1104 	/* Purpose of the following is avoidance of internally allocated memory leakage. */
1105 	/* TODO: As an improvement, one may relax this constraint when the allocation wrapper is off. */
1106 	if(!RSB_DO_FLAG_HAS(mtxAp->flags, RSB_FLAG_EXTERNALLY_ALLOCATED_ARRAYS))
1107        	{
1108 	       	errval = RSB_ERR_BADARGS;
1109 		RSB_PERR_GOTO(err, RSB_ERRM_IMNIP);
1110        	}
1111 
1112 	if(RSB_DO_FLAG_HAS(flags, RSB_FLAG_SORTED_INPUT))
1113 		errval = rsb__do_switch_rsb_mtx_to_coo_sorted(mtxAp, VAP, IAP, JAP, flags);
1114 	else
1115 		errval = rsb__do_switch_rsb_mtx_to_coo_unsorted(mtxAp, VAP, IAP, JAP, flags);
1116 err:
1117 	return errval;
1118 }
1119 
1120 #if RSB_WANT_COO_BEGIN
rsb__do_mtx_alloc_from_coo_begin(rsb_nnz_idx_t nnzA,rsb_type_t typecode,rsb_coo_idx_t nrA,rsb_coo_idx_t ncA,rsb_flags_t flags,rsb_err_t * errvalp)1121 struct rsb_mtx_t * rsb__do_mtx_alloc_from_coo_begin(rsb_nnz_idx_t nnzA, rsb_type_t typecode, rsb_coo_idx_t nrA, rsb_coo_idx_t ncA, rsb_flags_t flags, rsb_err_t * errvalp)
1122 {
1123 	rsb_err_t errval = RSB_ERR_NO_ERROR;
1124 	struct rsb_mtx_t * mtxAp = NULL;
1125 	blas_sparse_matrix bmtxA = RSB_BLAS_INVALID_VAL;
1126 
1127 	rsb__init_struct(mtxAp = rsb__calloc(sizeof(struct rsb_mtx_t)));
1128 	if(!mtxAp)
1129 	{
1130 		errval = RSB_ERR_BADARGS;
1131 		RSB_PERR_GOTO(err,RSB_ERRM_E_MTXAP"\n");
1132 	}
1133 	mtxAp->RSB_MTX_BMF = RSB_MTX_BMV;
1134 	bmtxA = mtxAp->RSB_MTX_BDF = rsb__BLAS_Xuscr_begin(nrA,ncA,typecode);
1135 	if( mtxAp->RSB_MTX_BDF == RSB_BLAS_INVALID_VAL )
1136 	{
1137 		errval = RSB_ERR_GENERIC_ERROR;
1138 		RSB_CONDITIONAL_FREE(mtxAp);
1139 		RSB_PERR_GOTO(err,RSB_ERRM_IPEWIEM);
1140 	}
1141 	/* FIXME : the following need an improvement  */
1142 	if(RSB_DO_FLAG_HAS(flags,RSB_FLAG_FORTRAN_INDICES_INTERFACE)) rsb__BLAS_ussp( bmtxA, blas_one_base);
1143 	if(RSB_DO_FLAG_HAS(flags,RSB_FLAG_UNIT_DIAG_IMPLICIT)) rsb__BLAS_ussp( bmtxA, blas_unit_diag );
1144 	if(RSB_DO_FLAG_HAS(flags,RSB_FLAG_LOWER_TRIANGULAR)) rsb__BLAS_ussp( bmtxA, blas_lower_triangular);
1145 	if(RSB_DO_FLAG_HAS(flags,RSB_FLAG_UPPER_TRIANGULAR)) rsb__BLAS_ussp( bmtxA, blas_upper_triangular);
1146 	if(RSB_DO_FLAG_HAS(flags,RSB_FLAG_LOWER_SYMMETRIC)) rsb__BLAS_ussp( bmtxA, blas_lower_symmetric);
1147 	if(RSB_DO_FLAG_HAS(flags,RSB_FLAG_UPPER_SYMMETRIC)) rsb__BLAS_ussp( bmtxA, blas_upper_symmetric);
1148 	if(RSB_DO_FLAG_HAS(flags,RSB_FLAG_LOWER_HERMITIAN)) rsb__BLAS_ussp( bmtxA, blas_lower_hermitian);
1149 	if(RSB_DO_FLAG_HAS(flags,RSB_FLAG_UPPER_HERMITIAN)) rsb__BLAS_ussp( bmtxA, blas_upper_hermitian);
1150 err:
1151 	RSB_CONDITIONAL_ERRPSET(errvalp,errval);
1152 	return mtxAp;
1153 }
1154 
rsb__do_mtx_alloc_from_coo_end(struct rsb_mtx_t ** mtxApp)1155 rsb_err_t rsb__do_mtx_alloc_from_coo_end(struct rsb_mtx_t ** mtxApp)
1156 {
1157 	rsb_err_t errval = RSB_ERR_NO_ERROR;
1158 	blas_sparse_matrix bmtxA = RSB_BLAS_INVALID_VAL;
1159 	struct rsb_mtx_t * mtxBp = NULL;
1160 	struct rsb_mtx_t * mtxAp = NULL;
1161 
1162 	if(!mtxApp || !*mtxApp)
1163 	{
1164 		errval = RSB_ERR_BADARGS;
1165 		RSB_PERR_GOTO(err,RSB_ERRM_E_MTXAPP);
1166 	}
1167 
1168 	mtxAp = *mtxApp ;
1169 
1170 	if( !RSB_MTX_HBDF( mtxAp ) )
1171 	{
1172 		/* errval = RSB_ERR_NO_ERROR; */
1173 		errval = RSB_ERR_BADARGS;
1174 		RSB_PERR_GOTO(err,RSB_ERRM_DNSAMIWAFCB);
1175 	}
1176 
1177 	bmtxA = RSB_MTX_HBDFH(mtxAp);
1178 	/* FIXME: missing serious check on mtxAp->flags ! */
1179 	if( rsb__BLAS_Xuscr_end_flagged(bmtxA,NULL) == RSB_BLAS_INVALID_VAL )
1180 	{
1181 	       	errval = RSB_ERR_BADARGS;
1182 		RSB_PERR_GOTO(err,RSB_ERRM_PFTM);
1183 		/* FIXME: insufficient cleanup */
1184 	}
1185 	mtxBp = rsb__BLAS_inner_matrix_retrieve(bmtxA);
1186 	*mtxApp = mtxBp;
1187 	rsb__free(mtxAp);
1188 	rsb__BLAS_handle_free(bmtxA); /* ignoring return value ... */
1189 err:
1190 	return errval;
1191 }
1192 #endif /* RSB_WANT_COO_BEGIN */
1193 
rsb__do_upd_vals(struct rsb_mtx_t * mtxAp,enum rsb_elopf_t elop_flags,const void * omegap)1194 rsb_err_t rsb__do_upd_vals(struct rsb_mtx_t * mtxAp, enum rsb_elopf_t elop_flags, const void * omegap)
1195 {
1196 	rsb_err_t errval = RSB_ERR_NO_ERROR;
1197 
1198 	switch(elop_flags)
1199 	{
1200 		case(RSB_ELOPF_MUL):
1201 		case(RSB_ELOPF_DIV):
1202 		case(RSB_ELOPF_POW):
1203 		case(RSB_ELOPF_SCALE_ROWS):
1204 		case(RSB_ELOPF_SCALE_COLS):
1205 		case(RSB_ELOPF_SCALE_ROWS_REAL):
1206 		case(RSB_ELOPF_SCALE_COLS_REAL):
1207 		RSB_DO_ERROR_CUMULATE(errval,rsb__do_elemental_binop(mtxAp,elop_flags,omegap));
1208 		break;
1209 		case(RSB_ELOPF_NEG):
1210 		RSB_DO_ERROR_CUMULATE(errval,rsb__do_elemental_unop(mtxAp,elop_flags));
1211 		break;
1212 		default: {errval = RSB_ERR_BADARGS; goto err;}
1213 	}
1214 err:
1215 	return errval;
1216 }
1217 
rsb__do_mtx_get_info(const struct rsb_mtx_t * mtxAp,enum rsb_mif_t miflags,void * minfop)1218 rsb_err_t rsb__do_mtx_get_info(const struct rsb_mtx_t *mtxAp, enum rsb_mif_t miflags, void* minfop)
1219 {
1220 	rsb_err_t errval = RSB_ERR_UNIMPLEMENTED_YET;
1221 	errval = rsb__do_get_matrix_info(mtxAp,miflags,minfop,0);
1222 	return errval;
1223 }
1224 
rsb__do_file_mtx_save(const struct rsb_mtx_t * mtxAp,const rsb_char_t * filename)1225 rsb_err_t rsb__do_file_mtx_save(const struct rsb_mtx_t * mtxAp, const rsb_char_t * filename)
1226 {
1227 	rsb_err_t errval = RSB_ERR_NO_ERROR;
1228 	errval = rsb__do_print_matrix_stats(mtxAp,RSB_CONST_DUMP_MATRIX_MARKET,filename);
1229 	return errval;
1230 }
1231 
rsb__do_vec_save(const rsb_char_t * filename,rsb_type_t typecode,const void * Yp,rsb_coo_idx_t yvl)1232 rsb_err_t rsb__do_vec_save(const rsb_char_t * filename, rsb_type_t typecode, const void * Yp, rsb_coo_idx_t yvl)
1233 {
1234 	rsb_err_t errval = RSB_ERR_NO_ERROR;
1235 	FILE*stream = NULL;
1236 	const int incX = 1;
1237 
1238        	if(filename == NULL)
1239 		stream = stdout;
1240 	else
1241 		stream = fopen(filename,"w");
1242 
1243 	errval = rsb__debug_print_vector_extra(Yp,yvl,typecode,incX,0x1,stream);
1244 
1245        	if(filename == NULL)
1246 		;
1247 	else
1248 		fclose(stream);
1249 
1250 	return errval;
1251 }
1252 
rsb__do_mtx_alloc_from_csr_inplace(void * VA,rsb_coo_idx_t * RP,rsb_coo_idx_t * JA,rsb_nnz_idx_t nnzA,rsb_type_t typecode,rsb_coo_idx_t nrA,rsb_coo_idx_t ncA,rsb_blk_idx_t brA,rsb_blk_idx_t bcA,rsb_flags_t flagsA,rsb_err_t * errvalp)1253 struct rsb_mtx_t * rsb__do_mtx_alloc_from_csr_inplace (void *VA, rsb_coo_idx_t * RP, rsb_coo_idx_t * JA, rsb_nnz_idx_t nnzA, rsb_type_t typecode, rsb_coo_idx_t nrA, rsb_coo_idx_t ncA, rsb_blk_idx_t brA, rsb_blk_idx_t bcA, rsb_flags_t flagsA, rsb_err_t * errvalp )
1254 {
1255 	struct rsb_mtx_t * mtxAp = NULL;
1256 	rsb_err_t errval = RSB_ERR_NO_ERROR;
1257 
1258 #if RSB_ALLOW_EMPTY_MATRICES
1259 	if( nnzA > 0 )
1260 #endif /* RSB_ALLOW_EMPTY_MATRICES */
1261 		errval = rsb__util_uncompress_row_pointers_array(RP,nrA,flagsA,flagsA,RP);
1262 
1263 	if(RSB_SOME_ERROR(errval))
1264 		RSB_CONDITIONAL_ERRPSET(errvalp,errval);
1265 	if( RSB_DO_FLAG_HAS(flagsA,RSB_FLAG_FORTRAN_INDICES_INTERFACE))
1266 		rsb__util_coo_array_sub(RP,nnzA,1),
1267 		rsb__util_coo_array_sub(JA,nnzA,1),
1268 		RSB_DO_FLAG_DEL(flagsA,RSB_FLAG_FORTRAN_INDICES_INTERFACE);
1269 	RSB_DO_FLAG_ADD(flagsA,RSB_FLAG_SORTED_INPUT);
1270 	if(errval == RSB_ERR_NO_ERROR)
1271 		mtxAp = rsb__do_mtx_alloc_from_coo_inplace(VA,RP,JA,nnzA,typecode,nrA,ncA,brA,bcA,flagsA,&errval);
1272 	return mtxAp;
1273 }
1274 
rsb__do_file_mtx_rndr(void * pmp,const char * filename,rsb_coo_idx_t pmlWidth,rsb_coo_idx_t pmWidth,rsb_coo_idx_t pmHeight,rsb_marf_t rflags)1275 rsb_err_t rsb__do_file_mtx_rndr(void * pmp, const char * filename, rsb_coo_idx_t pmlWidth, rsb_coo_idx_t pmWidth, rsb_coo_idx_t pmHeight, rsb_marf_t rflags)
1276 {
1277 	rsb_err_t errval = RSB_ERR_NO_ERROR;
1278 
1279 	if( pmlWidth != pmHeight )
1280 	{
1281 		errval = RSB_ERR_BADARGS;
1282 		goto err;
1283 	}
1284 
1285 	switch(rflags)
1286 	{
1287 		case(RSB_MARF_RGB):
1288 		RSB_DO_ERROR_CUMULATE(errval,rsb__do_get_pixmap_RGB_from_matrix(filename,pmp,pmWidth,pmHeight));
1289 		break;
1290 		case(RSB_MARF_EPS):
1291 		// rsb_dump_postscript_from_mtx_t(fd,mtxAp,1,1,pmWidth,pmHeight,0);
1292 		// RSB_DO_ERROR_CUMULATE(errval,rsb__dump_postscript_from_matrix(filename,1,1,pmWidth,pmHeight,0));
1293 		RSB_DO_ERROR_CUMULATE(errval,RSB_ERR_UNIMPLEMENTED_YET);
1294 		//RSB_DO_ERROR_CUMULATE(errval,rsb__dump_postscript_recursion_from_matrix(filename,1,1,pmWidth,pmHeight,RSB_FLAG_NOFLAGS,1,1,0,RSB_NUMERICAL_TYPE_DEFAULT));
1295 		break;
1296 		default: {errval = RSB_ERR_UNIMPLEMENTED_YET; goto err;}
1297 	}
1298 err:
1299 	return errval;
1300 }
1301 
1302 
1303 /* @endcond */
1304