/* Copyright (C) 2008-2016 Michele Martone This file is part of librsb. librsb is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. librsb is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with librsb; see the file COPYING. If not, see . */ /* @cond INNERDOC */ /*! * @file * @author Michele Martone * @brief * This source file contains matrix setter functions. * */ #include "rsb_internals.h" RSB_INTERNALS_COMMON_HEAD_DECLS #define RSB_ALLOW_MTX_UPD 1 static const void * rsb_do_has_coo_element_inner(const struct rsb_mtx_t * mtxAp, rsb_coo_idx_t i, rsb_coo_idx_t j) { /*! * \ingroup gr_internals * * FIXME: unfinished * * Should return a pointer to the value at (i,j), if present, and NULL if not present. * Only for CSR/CSC. * * */ RSB_DEBUG_ASSERT(mtxAp); RSB_DEBUG_ASSERT(!RSB_INVALID_COO_INDEX(i)); RSB_DEBUG_ASSERT(!RSB_INVALID_COO_INDEX(j)); RSB_DEBUG_ASSERT(rsb__is_css_matrix(mtxAp)); if(rsb__is_recursive_matrix(mtxAp->flags)) { const struct rsb_mtx_t * submatrix = RSB_FIND_SUBMATRIX_CONTAINING(mtxAp,i+mtxAp->roff,j+mtxAp->coff); rsb_coo_idx_t moff; rsb_coo_idx_t koff; if(!submatrix) return NULL; moff = submatrix->roff-mtxAp->roff; koff = submatrix->coff-mtxAp->coff; return rsb_do_has_coo_element_inner(submatrix,i-moff,j-koff); } else { rsb_nnz_idx_t si; rsb_coo_idx_t Mi,mi; const rsb_nnz_idx_t * bpntr = mtxAp->bpntr; const rsb_coo_idx_t * bindx = mtxAp->bindx; if( mtxAp->flags & RSB_FLAG_WANT_COLUMN_MAJOR_ORDER ) Mi = j, mi = i; else Mi = i, mi = j; if(rsb__is_coo_matrix(mtxAp)) { rsb_nnz_idx_t nnz1,nnz0,nnz = mtxAp->nnz; if( mtxAp->flags & RSB_FLAG_USE_HALFWORD_INDICES) { // delimit the current row const rsb_half_idx_t *IA = (const rsb_half_idx_t *)mtxAp->bpntr; const rsb_half_idx_t *JA = (const rsb_half_idx_t *)mtxAp->bindx; // we search the beginning of line Mi nnz0 = rsb__nnz_split_hcoo_bsearch(IA,Mi,nnz); // we search the end of line Mi nnz1 = nnz0+rsb__nnz_split_hcoo_bsearch(IA+nnz0,Mi+1,nnz-nnz0); if(nnz1-nnz0<1) return NULL;// no row Mi // in line Mi, we search the index of mi, if any nnz0 += rsb__nnz_split_hcoo_bsearch(JA+nnz0,mi,nnz1-nnz0); if(nnz1-nnz0<1 || JA[nnz0]!=mi) return NULL;// no element mi } else { // delimit the current row const rsb_coo_idx_t *IA = mtxAp->bpntr; const rsb_coo_idx_t *JA = mtxAp->bindx; // we search the beginning of line Mi nnz0 = rsb__nnz_split_coo_bsearch(IA,Mi,nnz); // we search the end of line Mi nnz1 = nnz0+rsb__nnz_split_coo_bsearch(IA+nnz0,Mi+1,nnz-nnz0); if(nnz1-nnz0<1) return NULL;// no row Mi // in line Mi, we search the index of mi, if any nnz0 += rsb__nnz_split_coo_bsearch(JA+nnz0,mi,nnz1-nnz0); if(nnz1-nnz0<1 || JA[nnz0]!=mi) return NULL;// no element mi } return ((const rsb_char_t*)(mtxAp->VA))+mtxAp->el_size*(nnz0); } else { if(mtxAp->flags & RSB_FLAG_USE_HALFWORD_INDICES_CSR) si = rsb__seek_half_idx_t(((rsb_half_idx_t*)bindx)+bpntr[Mi],mi,bpntr[Mi+1]-bpntr[Mi]); else si = rsb__seek_nnz_idx_t(bindx+bpntr[Mi],mi,bpntr[Mi+1]-bpntr[Mi]); } if(si == RSB_MARKER_NNZ_VALUE) return NULL; else return ((const rsb_char_t*)(mtxAp->VA))+mtxAp->el_size*(bpntr[Mi]+si); } } const void * rsb__do_coo_element_inner_address(const struct rsb_mtx_t * mtxAp, rsb_coo_idx_t i, rsb_coo_idx_t j) { return rsb_do_has_coo_element_inner(mtxAp,i,j); } rsb_err_t rsb__do_set_coo_elements(struct rsb_mtx_t * mtxAp, const void * VA, const rsb_coo_idx_t *IA, const rsb_coo_idx_t *JA, rsb_nnz_idx_t nnz) { /*! * \ingroup gr_internals * FIXME: undocumented * FIXME: should parallelize meaningfully * */ rsb_err_t errval = RSB_ERR_NO_ERROR; rsb_nnz_idx_t n; if(nnzel_size*n,IA[n],JA[n])); if(RSB_SOME_ERROR(errval)) { RSB_ERROR("error updating %dth element of %d: %d %d\n",n,nnz,IA[n],JA[n]); RSB_PERR_GOTO(err,RSB_ERRM_ES) } } } else { #pragma omp parallel for schedule(static,1) reduction(|:errval) RSB_NTC for(n=0;nel_size*n,IA[n],JA[n])); if(RSB_SOME_ERROR(errval)) { RSB_ERROR("error updating %dth element of %d: %d %d\n",n,nnz,IA[n],JA[n]); // RSB_PERR_GOTO(err,RSB_ERRM_ES) } } } err: RSB_DO_ERR_RETURN(errval) } rsb_err_t rsb__do_set_coo_element(struct rsb_mtx_t * mtxAp, const void * vp, const rsb_coo_idx_t i, const rsb_coo_idx_t j) { return rsb__do_upd_coo_element(mtxAp, vp, i, j, RSB_FLAG_DUPLICATES_DEFAULT_HANDLE); } rsb_err_t rsb__do_upd_coo_element(struct rsb_mtx_t * mtxAp, const void * vp, const rsb_coo_idx_t i, const rsb_coo_idx_t j, rsb_flags_t flags) { /*! * \ingroup gr_internals * * Overwrites the element at (i,j), if present. * If not present, returns RSB_ERR_GENERIC_ERROR. * */ rsb_err_t errval = RSB_ERR_NO_ERROR; void * OV = NULL; if(!mtxAp || !vp || RSB_INVALID_COO_INDEX(i) || RSB_INVALID_COO_INDEX(j)) { errval = RSB_ERR_BADARGS; RSB_PERR_GOTO(err,RSB_ERRM_ES) } if(!rsb__is_css_matrix(mtxAp)) { errval = RSB_ERR_UNIMPLEMENTED_YET; RSB_PERR_GOTO(err,RSB_ERRM_ES) } if(!RSB_MATRIX_CONTAINS(mtxAp,i,j)) { errval = RSB_ERR_BADARGS; RSB_PERR_GOTO(err,RSB_ERRM_ES) } if( i == j && rsb__get_diagonal_type_flag(mtxAp)==RSB_DIAGONAL_I ) { errval = RSB_ERR_BADARGS; RSB_PERR_GOTO(err,RSB_ERRM_ES) } OV = (void*) rsb_do_has_coo_element_inner(mtxAp,i,j); if(OV) { #if RSB_ALLOW_MTX_UPD rsb_flags_t cflag = ( mtxAp->flags & RSB_FLAG_ALL_DUPLICATE_FLAGS ) | ( flags & RSB_FLAG_ALL_DUPLICATE_FLAGS ); if(RSB_DO_FLAG_HAS(cflag,RSB_FLAG_DUPLICATES_SUM)) { RSB_NUMERICAL_TYPE_SUM_AND_STORE_ELEMENTS(OV,vp,mtxAp->typecode);} else #endif { RSB_NUMERICAL_TYPE_SET_ELEMENT(OV,vp,mtxAp->typecode); } } else errval = RSB_ERR_GENERIC_ERROR; err: RSB_DO_ERR_RETURN(errval) } #if 1 /* rsb_do_locate_nnz_element and rsb_do_get_nnz_element are used (experimentally) by sparsersb */ static rsb_err_t rsb_do_locate_nnz_element(const struct rsb_mtx_t * mtxAp, void ** vpp, rsb_coo_idx_t*ip, rsb_coo_idx_t*jp, rsb_nnz_idx_t nzi) { /* FIXME: * new, unfinished, untested */ rsb_err_t errval = RSB_ERR_BADARGS; rsb_submatrix_idx_t i,j; struct rsb_mtx_t * submatrix = NULL; if(!mtxAp) { RSB_PERR_GOTO(err,RSB_ERRM_ES) } if(rsb__is_terminal_recursive_matrix(mtxAp) && ( nzi >= mtxAp->nzoff ) && ( nzi < mtxAp->nzoff+mtxAp->nnz ) ) { rsb_nnz_idx_t lnz = nzi-mtxAp->nzoff; rsb_byte_t*OV = mtxAp->VA; OV += mtxAp->el_size * lnz; if( (!ip) || (!jp) ) goto noij; if(rsb__is_coo_matrix(mtxAp)) { if(RSB_DO_FLAG_HAS(mtxAp->flags,RSB_FLAG_USE_HALFWORD_INDICES)) { RSB_DECLARE_CONST_HALFCOO_ARRAYS_FROM_MATRIX(mIA,mJA,mtxAp) i = mIA[lnz]; j = mJA[lnz]; } else { RSB_DECLARE_CONST_FULLCOO_ARRAYS_FROM_MATRIX(mIA,mJA,mtxAp) i = mIA[lnz]; j = mJA[lnz]; } } else { if(mtxAp->flags & RSB_FLAG_USE_HALFWORD_INDICES_CSR) { RSB_DECLARE_CONST_HALFCSR_ARRAYS_FROM_MATRIX(mPA,mJA,mtxAp); j = mJA[lnz]; i = rsb__nnz_split_coo_bsearch(mPA,lnz,mtxAp->nnz); } else { RSB_DECLARE_CONST_FULLCSR_ARRAYS_FROM_MATRIX(mPA,mJA,mtxAp); j = mJA[lnz]; i = rsb__nnz_split_coo_bsearch(mPA,lnz,mtxAp->nnz); } } if(ip)*ip = i; if(jp)*jp = j; noij: if(vpp)*vpp = OV; errval = RSB_ERR_NO_ERROR; } else { RSB_SUBMATRIX_FOREACH(mtxAp,submatrix,i,j) if(submatrix && ( nzi >= submatrix->nzoff ) && ( nzi < submatrix->nnz+submatrix->nzoff ) ) { errval = rsb_do_locate_nnz_element(submatrix,vpp,ip,jp,nzi); RSB_PERR_GOTO(err,RSB_ERRM_ES) } } err: RSB_DO_ERR_RETURN(errval) } rsb_err_t rsb_do_get_nnz_element(const struct rsb_mtx_t * mtxAp, void * vp, rsb_coo_idx_t*ip, rsb_coo_idx_t*jp, rsb_nnz_idx_t nzi) { /* FIXME: * new, unfinished (20130331) */ void * OV = NULL; rsb_err_t errval = RSB_ERR_NO_ERROR; errval = rsb_do_locate_nnz_element(mtxAp,&OV,ip,jp,nzi); if((!RSB_SOME_ERROR(errval)) && OV) { RSB_NUMERICAL_TYPE_SET_ELEMENT(vp,OV,mtxAp->typecode); } RSB_DO_ERR_RETURN(errval) } #endif #if 0 rsb_err_t rsb_do_set_nnz_element(const struct rsb_mtx_t * mtxAp, const void * vp, rsb_nnz_idx_t nzi) { /* FIXME: * new, unfinished (20130331) */ void * OV = NULL; rsb_err_t errval = RSB_ERR_NO_ERROR; errval = rsb_do_locate_nnz_element(mtxAp,&OV,NULL,NULL,nzi); if((!RSB_SOME_ERROR(errval)) && OV) { RSB_NUMERICAL_TYPE_SET_ELEMENT(OV,vp,mtxAp->typecode); } RSB_DO_ERR_RETURN(errval) } #endif rsb_err_t rsb__do_get_coo_element(const struct rsb_mtx_t * mtxAp, void * vp, rsb_coo_idx_t i, rsb_coo_idx_t j) { /*! * \ingroup gr_internals * * FIXME: undocumented * Gets the element at (i,j), if present. * If not present, returns RSB_ERR_GENERIC_ERROR and zeros the area. * */ const void * OV = NULL; rsb_err_t errval = RSB_ERR_NO_ERROR; #if RSB_ALLOW_ZERO_DIM if(RSB_ANY_MTX_DIM_ZERO(mtxAp)) goto err; /* FIXME: skipping further error checks */ #endif if(!mtxAp || !vp || RSB_INVALID_COO_INDEX(i) || RSB_INVALID_COO_INDEX(j)) { errval = RSB_ERR_BADARGS; RSB_PERR_GOTO(err,RSB_ERRM_ES) } if(!rsb__is_css_matrix(mtxAp)) { errval = RSB_ERR_UNIMPLEMENTED_YET; RSB_PERR_GOTO(err,RSB_ERRM_ES) } if(!RSB_MATRIX_CONTAINS(mtxAp,i,j)) { errval = RSB_ERR_BADARGS; RSB_PERR_GOTO(err,RSB_ERRM_ES) } if( i == j && rsb__get_diagonal_type_flag(mtxAp)==RSB_DIAGONAL_I ) return rsb__fill_with_ones(vp,mtxAp->typecode,1,1); OV = rsb_do_has_coo_element_inner(mtxAp,i,j); if(!OV) { errval = RSB_ERR_GENERIC_ERROR; rsb__cblas_Xscal(mtxAp->typecode,1,NULL,vp,1); } else {RSB_NUMERICAL_TYPE_SET_ELEMENT(vp,OV,mtxAp->typecode);} err: RSB_DO_ERR_RETURN(errval) } rsb_err_t rsb__do_reverse_odd_rows(struct rsb_mtx_t * mtxAp) { /*! * \ingroup gr_internals * \rsb_warn_unoptimized_msg * \note Works only for csr leaves. * */ RSB_DEBUG_ASSERT(mtxAp); if(rsb__is_recursive_matrix(mtxAp->flags)) { struct rsb_mtx_t * submatrix; rsb_submatrix_idx_t i,j; RSB_SUBMATRIX_FOREACH(mtxAp,submatrix,i,j) rsb__do_reverse_odd_rows(submatrix); } else { if(rsb__is_coo_matrix(mtxAp)) { if( mtxAp->flags & RSB_FLAG_USE_HALFWORD_INDICES) { //RSB_DECLARE_CONST_HALFCOO_ARRAYS_FROM_MATRIX(IA,JA,mtxAp) /* FIXME: not implemented yet for COO */ } else { //RSB_DECLARE_CONST_FULLCOO_ARRAYS_FROM_MATRIX(IA,JA,mtxAp) /* FIXME: not implemented yet for COO */ } } else { rsb_coo_idx_t i; rsb_nnz_idx_t ib,ie; if(mtxAp->flags & RSB_FLAG_USE_HALFWORD_INDICES) { RSB_DECLARE_HALFCSR_ARRAYS_FROM_MATRIX(IA,JA,mtxAp) for(i=1;inr;i+=2) ib = IA[i],ie = IA[i+1], rsb__util_reverse_halfword_coo_array(JA+ib,ie-ib); } else { RSB_DECLARE_FULLCSR_ARRAYS_FROM_MATRIX(IA,JA,mtxAp) for(i=1;inr;i+=2) ib = IA[i],ie = IA[i+1], rsb__util_reverse_fullword_coo_array(JA+ib,ie-ib); } } } return RSB_ERR_NO_ERROR; } rsb_err_t rsb__do_zsort_coo_submatrices(struct rsb_mtx_t * mtxAp) { /*! * \ingroup gr_internals * \rsb_warn_unoptimized_msg * */ RSB_DEBUG_ASSERT(mtxAp); if(rsb__is_recursive_matrix(mtxAp->flags)) { struct rsb_mtx_t * submatrix; rsb_submatrix_idx_t i,j; RSB_SUBMATRIX_FOREACH(mtxAp,submatrix,i,j) if(submatrix) rsb__do_zsort_coo_submatrices(submatrix); } else { if(rsb__is_coo_matrix(mtxAp)) { rsb_err_t errval = RSB_ERR_NO_ERROR; if( mtxAp->flags & RSB_FLAG_USE_HALFWORD_INDICES) { RSB_DECLARE_FULLCOO_ARRAYS_FROM_MATRIX(IA,JA,mtxAp) RSB_DO_ERROR_CUMULATE(errval,rsb__do_switch_to_fullword_coo(mtxAp)); RSB_DO_ERROR_CUMULATE(errval,rsb__do_index_based_z_morton_sort(NULL,NULL,NULL,IA,JA,mtxAp->VA,mtxAp->nr,mtxAp->nc,mtxAp->nnz,mtxAp->typecode,RSB_OP_FLAG_DEFAULT)); RSB_DO_ERROR_CUMULATE(errval,rsb__do_switch_to_halfword_coo(mtxAp)); } else { RSB_DECLARE_FULLCOO_ARRAYS_FROM_MATRIX(IA,JA,mtxAp) RSB_DO_ERROR_CUMULATE(errval,rsb__do_index_based_z_morton_sort(NULL,NULL,NULL,IA,JA,mtxAp->VA,mtxAp->nr,mtxAp->nc,mtxAp->nnz,mtxAp->typecode,RSB_OP_FLAG_DEFAULT)); } return errval; } else { if(mtxAp->flags & RSB_FLAG_USE_HALFWORD_INDICES) { /* nothing to do */ } else { /* nothing to do */ } } } return RSB_ERR_NO_ERROR; } /* @endcond */