#include<cmath>
#include<cstring>
#ifdef _OPENMP
#include<omp.h>
#endif
#include "SimpleSparse.h"
double SimpleSparse::logSumExpVal(long st, long en) const{//{{{
if(st<0)st = 0;
if((en == -1) || (en > T)) en = T;
if(st >= en) return 0;
long i;
double sumE = 0, m = val[st];
for(i = st; i < en; i++)if(val[i] > m)m = val[i];
for(i = st; i < en; i++)
sumE += exp(val[i] - m);
return m + log(sumE);
}//}}}
void SimpleSparse::sumRows(double res[]) const{//{{{
long i,r;
for(r=0;r<N;r++){
res[r]=0;
for(i=rowStart[r];i<rowStart[r+1];i++){
res[r]+=val[i];
}
}
}//}}}
void SimpleSparse::sumCols(double res[]) const{//{{{
memset(res,0,M*sizeof(double));
for(long i=0;i<T;i++)res[col[i]]+=val[i];
}//}}}
long SimpleSparse::countAboveDelta(double delta) const{//{{{
long i,count=0;
#pragma omp parallel for reduction(+:count)
for(i=0;i<T;i++){
if(val[i]>delta)count++;
}
return count;
}//}}}
void SimpleSparse::softmaxInplace(SimpleSparse *res){//{{{
double logRowSum = 0;
long i,r;
#pragma omp parallel for private(i,logRowSum)
for(r=0;r<N;r++){
logRowSum = logSumExpVal(rowStart[r],rowStart[r+1]);
for(i=rowStart[r];i<rowStart[r+1];i++){
val[i] = val[i] - logRowSum;
res->val[i] = exp( val[i] );
}
}
}//}}}
void SimpleSparse::softmax(SimpleSparse *res) const{//{{{
double logRowSum = 0;
long i,r;
#pragma omp parallel for private(i,logRowSum)
for(r=0;r<N;r++){
logRowSum = logSumExpVal(rowStart[r],rowStart[r+1]);
for(i=rowStart[r];i<rowStart[r+1];i++){
res->val[i] = exp(val[i] - logRowSum);
}
}
}//}}}
SimpleSparse::SimpleSparse(long n,long m, long t){//{{{
N=n;
M=m;
T=t;
val = new double[T];
base = true; // base matrix with it's own col & rowStart information
col = new int_least32_t[T];
rowStart = new int_least32_t[N+1];
//colStart = new long[M+1];
}//}}}
SimpleSparse::SimpleSparse(SimpleSparse *m0){//{{{
N=m0->N;
M=m0->M;
T=m0->T;
val = new double[T];
base = false; // use col & rowStart information from the base matrix m0
col = m0->col;
rowStart = m0->rowStart;
/*col = new long[T];
rowStart = new long[N+1];
memcpy(col, m0->col, T*sizeof(long));
memcpy(rowStart, m0->rowStart, (N+1)*sizeof(long));
*/
}//}}}
SimpleSparse::~SimpleSparse(){//{{{
delete[] val;
if(base){
// BEWARE there could be other matrices using this data
delete[] col;
delete[] rowStart;
}
}//}}}