Mercurial > repos > zzhou > spp_phantompeak
diff spp/src/peaks.cpp @ 6:ce08b0efa3fd draft
Uploaded
author | zzhou |
---|---|
date | Tue, 27 Nov 2012 16:11:40 -0500 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/spp/src/peaks.cpp Tue Nov 27 16:11:40 2012 -0500 @@ -0,0 +1,804 @@ +#include <vector> +#include <string.h> +#include <iostream> +#include <string> +#include <set> + +extern "C" { +#include "R.h" +#include "Rmath.h" +#include "Rinternals.h" +#include "Rdefines.h" +} + +using namespace std; +using namespace __gnu_cxx; + +/** + * Calculate all local peaks + */ + +//#define DEBUG 1 + +extern "C" { + SEXP find_peaks(SEXP x_R,SEXP thr_R,SEXP max_span_R) { + +#ifdef DEBUG + Rprintf("start\n"); +#endif + double* x=REAL(x_R); + int nx=LENGTH(x_R); + int max_span=*INTEGER(max_span_R); + double thr=REAL(thr_R)[0]; +#ifdef DEBUG + Rprintf("n=%d; thr=%f; max_span=%d\n",nx,thr,max_span); +#endif + + vector<int> pos; + + double pv=x[0]; + double ppv=0; // previous peak value + int ppp=-max_span-1; // previous peak position + + for(int i=1;i<(nx-1);i++) { + if(x[i]>pv && x[i]>=thr && x[i]>x[i+1]) { + if(max_span>2) { + //Rprintf("i=%d; ppp=%d\n",i,ppp); + if(i-ppp > max_span) { + if(ppp>=0) { + pos.push_back(ppp); + } + //Rprintf("recorded %d; now %d\n",ppp,i); + ppp=i; ppv=x[i]; + } else { + if(x[i]>ppv) { + //Rprintf("reset from %d to %d\n",ppp,i); + ppp=i; ppv=x[i]; + } + } + } else { + pos.push_back(i); + } + } + if(x[i]!=x[i+1]) { pv=x[i]; } + } + + // add remaining peak + if(max_span>2 && ppp>=0) { + pos.push_back(ppp); + } + + SEXP nv; + PROTECT(nv=allocVector(INTSXP,pos.size())); + int* i_nv=INTEGER(nv); + int i=0; + for(vector<int> ::const_iterator pi=pos.begin();pi!=pos.end();++pi) { + i_nv[i++]=1+(*pi); + } + + UNPROTECT(1); + return(nv); + } + + + + + /************************************************************************/ + // given a data vector d (positive values) and a set of signed center coordinates pos, + // returns coordinates of data points relative to the centers + // size is the size of the region around the centers + // return: vector of relative coordinates (x) and indecies of centers relative the coordinate + // was calculated (i). + SEXP get_relative_coordinates(SEXP d_R, + SEXP pos_R, + SEXP size_R) + { + int *d, *pos; + int npos,nd,size; + + d = INTEGER(d_R); pos = INTEGER(pos_R); + npos=LENGTH(pos_R); nd=LENGTH(d_R); + size = INTEGER(size_R)[0]; +#ifdef DEBUG + Rprintf("|d|=%d, |c|=%d, size=%d\n",nd,npos,size); +#endif + + vector<int> x; vector<int> xi; + int k=0; // current pos index + + for(int i=0;i<nd;i++) { + // increment k until pos[k]+size>=d[i] + while((abs(pos[k])+size) < d[i]) { k++; if(k==npos) { break; }; +#ifdef DEBUG + Rprintf("advancing k to %d\n",k); +#endif + } + if(k==npos) { break; }; + // increment i until d[i]>=pos[k]-size + while((abs(pos[k])-size) > d[i]) { i++; if(i==nd) { break; } +#ifdef DEBUG + Rprintf("advancing i to %d\n",i); +#endif + } + if(i==nd) { break; } + + + int l=k; + while((l<npos) && ((abs(pos[l])-size) <= d[i])) { l++; +#ifdef DEBUG + Rprintf("advancing l to %d\n",l); +#endif + } + for(int j=k;j<l;j++) { + int pd=d[i]-abs(pos[j]); + if(abs(pd)<=size) { + // record + if(pos[j]>0) { + x.push_back(pd); + } else { + x.push_back(-1*pd); + } + xi.push_back(j); +#ifdef DEBUG + Rprintf("recorded i=%d, j=%d\n",i,j); +#endif + } else { + break; + } + } + } + + SEXP xv_R,xiv_R; + PROTECT(xv_R=allocVector(INTSXP,x.size())); + PROTECT(xiv_R=allocVector(INTSXP,x.size())); + int* xv=INTEGER(xv_R); + int* xiv=INTEGER(xiv_R); + + int i=0; + for(vector<int> ::const_iterator pi=x.begin();pi!=x.end();++pi) { + xv[i++]=*pi; + } + i=0; + for(vector<int> ::const_iterator pi=xi.begin();pi!=xi.end();++pi) { + xiv[i++]=1+(*pi); + } + + SEXP ans_R, names_R; + PROTECT(names_R = allocVector(STRSXP, 2)); + SET_STRING_ELT(names_R, 0, mkChar("x")); + SET_STRING_ELT(names_R, 1, mkChar("i")); + + PROTECT(ans_R = allocVector(VECSXP, 2)); + SET_VECTOR_ELT(ans_R, 0, xv_R); + SET_VECTOR_ELT(ans_R, 1, xiv_R); + setAttrib(ans_R, R_NamesSymbol, names_R); + + UNPROTECT(4); + return(ans_R); + } + + + // determines a set of points within a set of fragments + // note: all vectors sorted in ascending order + // note: all vectors are integers + // x_R - vector of point positions + // se_R - vector of start and end positions + // fi_R - vector of signed fragment indecies + // return_list_R - whether a list of fragments should be returned for each point + // return_unique_R - whether points in multiple fragments should be omitted + SEXP points_within(SEXP x_R,SEXP se_R,SEXP fi_R,SEXP return_list_R,SEXP return_unique_R,SEXP return_point_counts_R) { +#ifdef DEBUG + Rprintf("start\n"); +#endif + int* x=INTEGER(x_R); + int nx=LENGTH(x_R); + int* se=INTEGER(se_R); + int* fi=INTEGER(fi_R); + int nf=LENGTH(se_R); + + int return_list=*(INTEGER(return_list_R)); + int return_unique=*(INTEGER(return_unique_R)); + int return_point_counts=*(INTEGER(return_point_counts_R)); + +#ifdef DEBUG + Rprintf("nf=%d; nx=%d, return_list=%d, return_unique=%d, return_point_counts=%d\n",nf/2,nx,return_list,return_unique,return_point_counts); +#endif + set<int> fset; + + + SEXP nv; int *i_nv; + int np=0; + if(return_point_counts) { + PROTECT(nv = allocVector(INTSXP, nf/2)); np++; + i_nv=INTEGER(nv); + for(int i=0;i<nf/2;i++) { i_nv[i]=0; } + } else if(return_list) { + PROTECT(nv = allocVector(VECSXP, nx)); np++; + } else { + PROTECT(nv=allocVector(INTSXP,nx)); np++; + i_nv=INTEGER(nv); + } + + int j=0; + + for(int i=0;i<nx;i++) { + // advance j + while(j<nf && se[j]<x[i]) { + int frag=fi[j]; + if(frag>0) { // insert + fset.insert(frag); +#ifdef DEBUG + Rprintf("inserted frag %d, size=%d\n",frag,fset.size()); +#endif + } else { // remove + fset.erase(-frag); +#ifdef DEBUG + Rprintf("removed frag %d, size=%d\n",-frag,fset.size()); +#endif + } + j++; + } +#ifdef DEBUG + Rprintf("i=%d j=%d\n",i,j); +#endif + if(return_list) { + if(fset.empty() || (return_unique && fset.size()>1)) { + // assign null list? + } else { + SEXP fil_R; + PROTECT(fil_R=allocVector(INTSXP,fset.size())); np++; + int* fil=INTEGER(fil_R); + int k=0; + for(set<int>::const_iterator ki=fset.begin();ki!=fset.end();++ki) { + fil[k]=*ki; k++; + } + SET_VECTOR_ELT(nv, i, fil_R); + UNPROTECT(1); np--; + } + } else { + if(return_point_counts) { + for(set<int>::const_iterator ki=fset.begin();ki!=fset.end();++ki) { + i_nv[*ki-1]++; + } + } else { + if(fset.empty() || (return_unique && fset.size()>1)) { + i_nv[i]=-1; + } else { + i_nv[i]=*fset.begin(); + } + } + } + } + + UNPROTECT(np); + return(nv); + } + + + SEXP expuni_lr(SEXP x_R, // positions and their number (assumed sorted in ascending order) + SEXP mdist_R, // max distance at which points should be considered + SEXP lambda_R, // lambda value + SEXP spos_R, // starting position + SEXP epos_R, // ending position + SEXP step_R, // step size + SEXP return_peaks_R, // whether peak positions should be returned, or entire score vector + SEXP min_peak_lr_R // min peak height (lr) + ) + { + +#ifdef DEBUG + Rprintf("start\n"); +#endif + int* x=INTEGER(x_R); + int nx=LENGTH(x_R); + int mdist=INTEGER(mdist_R)[0]; + double lambda=*(REAL(lambda_R)); + + int return_peaks=*(INTEGER(return_peaks_R)); + double min_peak=*(REAL(min_peak_lr_R)); + + int spos=*(INTEGER(spos_R)); + int epos=*(INTEGER(epos_R)); + int step=*(INTEGER(step_R)); + + int nsteps=(int) (epos-spos)/step; + + +#ifdef DEBUG + Rprintf("n=%d; lambda=%f; mdist=%d; spos=%d; epos=%d; step=%d; nsteps=%d\n",nx,lambda,mdist,spos,epos,step,nsteps); +#endif + + + SEXP nv; + double *d_nv; + if(!return_peaks) { + PROTECT(nv=allocVector(REALSXP,nsteps+1)); + d_nv=REAL(nv); + } + + + int i=0; // current index of the first point being used in the calculations + int j=0; // current index of the last point being used in the calculations + int sx=0; // current sum of all positions + int n=0; + + for(int k=0; k<=nsteps; k++) { + int cpos=spos+k*step; + // increase i until x[i]>=cpos-mdist; remove x from sx; decrement n; + while(i<nx && x[i]<(cpos-mdist)) { + n--; sx-=x[i]; i++; + //Rprintf("incremented i: i=%d; n=%d; sx=%d; cpos-mdist=%d; x[i-1]=%d\n",i,n,sx,cpos-mdist,x[i-1]); + } + //Rprintf("stable i: i=%d; n=%d; sx=%d; cpos-mdist=%d; x[i-1]=%d\n",i,n,sx,cpos-mdist,x[i-1]); + + //if(i>j) { j=i; } + + // increase j until x[j]>cpos + while(j<nx && x[j]<=cpos) { + n++; sx+=x[j]; j++; + //Rprintf("incremented j: j=%d; n=%d; sx=%d; cpos=%d; x[j-1]=%d\n",j,n,sx,cpos,x[j-1]); + } + //Rprintf("stable j: j=%d; n=%d; sx=%d; cpos=%d; x[j-1]=%d\n",j,n,sx,cpos,x[j]); + + // calculate lr + d_nv[k]=((double)(1-n))*log(lambda)-lambda*((double)(n*(cpos+1)-sx)); + //Rprintf("recorded lr[%d]=%f\n",k-1,d_nv[k-1]); + } + UNPROTECT(1); + return(nv); + } + + + SEXP allpdist(SEXP x_R,SEXP max_dist_R) { + +#ifdef DEBUG + Rprintf("start\n"); +#endif + double* x=REAL(x_R); + int nx=LENGTH(x_R); + double max_dist=*REAL(max_dist_R); +#ifdef DEBUG + Rprintf("n=%d; max_dist=%d\n",nx,max_dist); +#endif + + vector<double> dist; + + for(int i=0;i<nx;i++) { + for(int j=i+1;j<nx;j++) { + + double d=x[j]-x[i]; +#ifdef DEBUG + Rprintf("i=%d; j=%d; d=%f\n",i,j,d); +#endif + if(d<=max_dist) { + dist.push_back(d); + } else { + break; + } + } + } + + SEXP nv; + PROTECT(nv=allocVector(REALSXP,dist.size())); + double* i_nv=REAL(nv); + int i=0; + for(vector<double> ::const_iterator pi=dist.begin();pi!=dist.end();++pi) { + i_nv[i++]=*pi; + } + + UNPROTECT(1); + return(nv); + } + + // same as above, but for two different sets + SEXP allxpdist(SEXP x_R,SEXP y_R, SEXP max_dist_R) { + +#ifdef DEBUG + Rprintf("start\n"); +#endif + double* x=REAL(x_R); + double* y=REAL(y_R); + int nx=LENGTH(x_R); + int ny=LENGTH(y_R); + double max_dist=*REAL(max_dist_R); +#ifdef DEBUG + Rprintf("nx=%d; ny=%d; max_dist=%d\n",nx,ny,max_dist); +#endif + + vector<double> dist; + int yi=0; // latest y start index + + for(int i=0;i<nx;i++) { + // adjust yi so that yi>=x[i]-max_dist_R + while(y[yi]<(x[i]-max_dist) && yi<ny) { yi++; } + if(yi==ny) { break; } + + for(int j=yi;j<ny;j++) { + double d=y[j]-x[i]; +#ifdef DEBUG + Rprintf("i=%d; j=%d; d=%f\n",i,j,d); +#endif + if(d<=max_dist) { + dist.push_back(d); + } else { + break; + } + } + } + + SEXP nv; + PROTECT(nv=allocVector(REALSXP,dist.size())); + double* i_nv=REAL(nv); + int i=0; + for(vector<double> ::const_iterator pi=dist.begin();pi!=dist.end();++pi) { + i_nv[i++]=*pi; + } + + UNPROTECT(1); + return(nv); + } + + // returns a vector giving for each point, + // number of points within a given max_dist + SEXP nwithindist(SEXP x_R,SEXP max_dist_R) { + +#ifdef DEBUG + Rprintf("start\n"); +#endif + double* x=REAL(x_R); + int nx=LENGTH(x_R); + double max_dist=*REAL(max_dist_R); + + SEXP nv; + PROTECT(nv=allocVector(REALSXP,nx)); + double* i_nv=REAL(nv); + for(int i=0;i<nx;i++) { i_nv[i]=0; } + +#ifdef DEBUG + Rprintf("n=%d; max_dist=%d\n",nx,max_dist); +#endif + + for(int i=0;i<nx;i++) { + for(int j=i+1;j<nx;j++) { + + double d=x[j]-x[i]; +#ifdef DEBUG + Rprintf("i=%d; j=%d; d=%f\n",i,j,d); +#endif + if(d<=max_dist) { + i_nv[i]++; + i_nv[j]++; + } else { + break; + } + } + } + + UNPROTECT(1); + return(nv); + } + + + + + // given a list of sorted chromosome signal and background vectors (unscaled), determine + // cluster contigs exceeding thr poisson P value, based on a whs window size, + // and satisfying mcs cluster size + SEXP find_poisson_enrichment_clusters(SEXP pos_R,SEXP flag_R,SEXP wsize_R,SEXP thr_R,SEXP mcs_R,SEXP bgm_R,SEXP mintag_R,SEXP either_R) { + +#ifdef DEBUG + Rprintf("start\n"); +#endif + double* pos=REAL(pos_R); + int* flag=INTEGER(flag_R); + int nt=LENGTH(pos_R); + + int mcs=*INTEGER(mcs_R); + int wsize=*INTEGER(wsize_R); + int either=*INTEGER(either_R); + double thr=REAL(thr_R)[0]; + double bgm=REAL(bgm_R)[0]; + double mintag=REAL(mintag_R)[0]; + +#ifdef DEBUG + Rprintf("nt=%d; wsize=%d; thr=%f; mcs=%d; min.tag=%f; bgm=%f\n",nt,wsize,thr,mcs,mintag,bgm); +#endif + + + vector< pair<double,double> > contigs; + + // running indecies (start and end) + int si=0; + int ei=0; + + // current window coordinate + double ws=pos[0]; + + // current window tag counts + int cc[2]={0,0}; + + + if(nt>0) { + cc[flag[si]]++; + // increment window end + while(ei<(nt-1) && (pos[ei+1]-ws) <= wsize) { + ei++; + cc[flag[ei]]++; + } + + + // cluster start,end positions + double cs,ce; + int inclust=0; + + while(si<nt-1) { + + if((pos[si+1]-ws) > (pos[ei+1] - ws - wsize) && ei!=(nt-1)) { + // move end boudnary + ei++; + ws=pos[ei]-wsize; + cc[flag[ei]]++; + while(ei<(nt-1) && pos[ei+1]==ws+wsize) { + ei++; + cc[flag[ei]]++; + } + + // increment window start + while(si<(nt-1) && pos[si] < ws) { + cc[flag[si]]--; + si++; + } + + } else { + // move up start boundary + ws=pos[si+1]; + cc[flag[si]]--; + si++; + while(si<(nt-1) && pos[si+1]==ws) { + cc[flag[si]]--; + si++; + } + + // increment window end + while(ei<(nt-1) && (pos[ei+1] - ws) <= wsize) { + ei++; + cc[flag[ei]]++; + } + + } + + // calculate z score + double dc0=((double)cc[0])+0.5; + double dc1=((double)cc[1])+0.5; + double rte=dc0+dc1-0.25*thr*thr; + double lb; + if(rte<=0) { + lb=0; + } else { + lb=(sqrt(dc1*dc0) - 0.5*thr*sqrt(rte))/(dc0 - 0.25*thr*thr); + if(lb<0) { lb=0; } + lb*=lb; + } + + //Rprintf("%f=f(%f,%f,%f); %f=f(%f,%f,%f)\n",lb,1.0-thr,2.0*dc1,2.0*dc0,ub,thr,2.0*dc1,2.0*dc0); + +#ifdef DEBUG + //double ub=gsl_cdf_fdist_Qinv(thr,2.0*dc1,2.0*dc0)*dc1/dc0; + double ub=(sqrt(dc1*dc0) + 0.5*thr*sqrt(rte))/(dc0 - 0.25*thr*thr); + ub*=ub; + Rprintf("s=%d (%f); e=%d (%f); window: %f-%f; cc=[%d,%d]; lb=%f; ub=%f\n",si,pos[si],ei,pos[ei],ws,ws+wsize,cc[0],cc[1],lb,ub); +#endif + + int bc=lb>=bgm && cc[1]>=mintag; + if(either) { + bc=lb>=bgm || cc[1]>=mintag; + } + if(bc) { + if(inclust) { + double nce=ws+wsize/2.0; + if(nce-ce > wsize/2.0) { + // next point is too far removed, end cluster + if(ce-cs >= mcs) { + contigs.push_back(pair<double,double>(cs,ce)); +#ifdef DEBUG + Rprintf("recorded cluster %f-%f\n",cs,ce); +#endif + } + inclust=0; + } else { + ce=nce; + } + } else { + inclust=1; + cs=ws+wsize/2.0; + ce=cs; + } + } else { + if(inclust) { + if(ce-cs >= mcs) { + contigs.push_back(pair<double,double>(cs,ce)); +#ifdef DEBUG + Rprintf("recorded cluster %f-%f\n",cs,ce); +#endif + } + inclust=0; + } + } + + } + + if(inclust) { + if(ce-cs >= mcs) { + contigs.push_back(pair<double,double>(cs,ce)); +#ifdef DEBUG + Rprintf("recorded cluster %f-%f\n",cs,ce); +#endif + } + inclust=0; + } + } + + SEXP cs_R,ce_R; + PROTECT(cs_R=allocVector(REALSXP,contigs.size())); + PROTECT(ce_R=allocVector(REALSXP,contigs.size())); + double* csa=REAL(cs_R); + double* cea=REAL(ce_R); + + int i=0; + for(vector< pair<double,double> >::const_iterator ci=contigs.begin(); ci!=contigs.end();++ci) { + csa[i]=ci->first; + cea[i]=ci->second; + i++; + } + + SEXP ans_R, names_R; + PROTECT(names_R = allocVector(STRSXP, 2)); + SET_STRING_ELT(names_R, 0, mkChar("s")); + SET_STRING_ELT(names_R, 1, mkChar("e")); + + PROTECT(ans_R = allocVector(VECSXP, 2)); + SET_VECTOR_ELT(ans_R, 0, cs_R); + SET_VECTOR_ELT(ans_R, 1, ce_R); + setAttrib(ans_R, R_NamesSymbol, names_R); + + UNPROTECT(4); + return(ans_R); + + } + + + // finds intersection between a list of regions + // the flag has +n/-n value, corresponding to the start/end of a segment in n-th regionset + // max_val: 1 - report max overlapping value, -1: report min, 0 - don't look at values + // returns: $s, $e, ($v) lists + SEXP region_intersection(SEXP n_R,SEXP pos_R,SEXP flags_R,SEXP vals_R,SEXP max_val_R,SEXP union_R) { + const int max_val=*INTEGER(max_val_R); + const int unionr=*INTEGER(union_R); + const int n=*INTEGER(n_R); + double* pos=REAL(pos_R); + int* flags=INTEGER(flags_R); + double* val=REAL(vals_R); + +#ifdef DEBUG + Rprintf("n=%d; npos=%d; max_val=%d\n",n,LENGTH(pos_R),max_val); +#endif + + int s[n]; // flag status for each set + double mv[n]; // max/min value of current clusters + + for(int i=0;i<n;i++) { s[i]=0; } + + vector<double> starts; + vector<double> ends; + vector<double> values; + + int start=-1; + double mval=0; + for(int i=0;i<LENGTH(pos_R);i++) { + // update flags + int f=flags[i]; + if(f>0) { + s[abs(f)-1]++; + } else { + s[abs(f)-1]--; + } + + if(max_val!=0 && val[i]*max_val > mval*max_val) { mval=val[i]; } + + // joined status + int all; + if(unionr) { + all=0; + for(int j=0;j<n;j++) { if(s[j]>0) { all=1; break;} } + } else { + all=1; + for(int j=0;j<n;j++) { all=all & (s[j]>0); } + } + + + //Rprintf("i=%d; s=[",i); + //for(int j=0;j<n;j++) { Rprintf("%d",s[j]); } + //Rprintf("]; all=%d; start=%d\n",all,start); + + if(start>=0) { + // in fragment + if(!all) { + // end fragment + starts.push_back(pos[start]); + ends.push_back(pos[i]); + start=-1; + if(max_val!=0) { values.push_back(mval); } + +#ifdef DEBUG + Rprintf("recorded new fragment (s=%f,e=%f,v=%f);\n",pos[start],pos[i],mval); +#endif + } + } else { + // should a fragment be started? + if(all) { + start=i; + if(max_val!=0) { mval=val[i]; } +#ifdef DEBUG + Rprintf("starting new fragment (s=%f,i=%d);\n",pos[start],i); +#endif + } + } + } + SEXP cs_R,ce_R,cv_R; + PROTECT(cs_R=allocVector(REALSXP,starts.size())); + PROTECT(ce_R=allocVector(REALSXP,ends.size())); + + double* csa=REAL(cs_R); + int i=0; + for(vector<double>::const_iterator ci=starts.begin(); ci!=starts.end(); ++ci) { + csa[i]=*ci; i++; + } + + csa=REAL(ce_R); + i=0; + for(vector<double>::const_iterator ci=ends.begin(); ci!=ends.end(); ++ci) { + csa[i]=*ci; i++; + } + + if(max_val!=0) { + PROTECT(cv_R=allocVector(REALSXP,values.size())); + csa=REAL(cv_R); + i=0; + for(vector<double>::const_iterator ci=values.begin(); ci!=values.end(); ++ci) { + csa[i]=*ci; i++; + } + } + + SEXP ans_R, names_R; + if(max_val!=0) { + PROTECT(names_R = allocVector(STRSXP, 3)); + SET_STRING_ELT(names_R, 0, mkChar("s")); + SET_STRING_ELT(names_R, 1, mkChar("e")); + SET_STRING_ELT(names_R, 2, mkChar("v")); + + PROTECT(ans_R = allocVector(VECSXP, 3)); + SET_VECTOR_ELT(ans_R, 0, cs_R); + SET_VECTOR_ELT(ans_R, 1, ce_R); + SET_VECTOR_ELT(ans_R, 2, cv_R); + } else { + PROTECT(names_R = allocVector(STRSXP, 2)); + SET_STRING_ELT(names_R, 0, mkChar("s")); + SET_STRING_ELT(names_R, 1, mkChar("e")); + + PROTECT(ans_R = allocVector(VECSXP, 2)); + SET_VECTOR_ELT(ans_R, 0, cs_R); + SET_VECTOR_ELT(ans_R, 1, ce_R); + } + + setAttrib(ans_R, R_NamesSymbol, names_R); + + if(max_val!=0) { + UNPROTECT(5); + } else { + UNPROTECT(4); + } + return(ans_R); + } + +} +