/*
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 */