/* * ===================================================================================== * * Filename: RuniqueCombs.c * * Description: The routines are copied from the R package mgcv * which is downloaded from * http://cran.r-project.org/web/packages/mgcv/ * * Copyright (C) 2000-2005 Simon N. Wood simon.wood@r-project.org * * Created: 30/04/2011 06:22:46 * Revision: none * Compiler: gcc * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * This program 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 General Public License for more details. * (www.gnu.org/copyleft/gpl.html) * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * * * * ===================================================================================== */ #ifdef WINDOWS #include /* For easy self window porting, without neading everything R.h needs */ #include #else #include #endif #include #include #include #include #include #include "RuniqueCombs.h" #define RANGECHECK #define PAD 1L #define ROUND(a) ((a)-(int)floor(a)>0.5) ? ((int)floor(a)+1):((int)floor(a)) matrix null_mat; /* matrix for passing when you don't actually need to */ #define PADCON (-1.234565433647588392902028934e270) /* counter for memory used */ long memused=0L,matrallocd=0L; /* the routines */ struct mrec { matrix mat; struct mrec *fp,*bp; }; typedef struct mrec MREC; void ErrorMessage(char *msg,int fatal) { #ifdef WINDOWS MessageBox(HWND_DESKTOP,msg,"Info!",MB_ICONEXCLAMATION|MB_OK); #else if (fatal) error("%s",msg);else warning("%s",msg); #endif } matrix null_mat; MREC *top,*bottom; matrix Rmatrix(double *A,long r,long c) /* produces a matrix from the array containing a (default) R matrix stored: A[0,0], A[1,0], A[2,0] .... etc */ { int i,j; matrix M; M=initmat(r,c); for (i=0;i0L)) { ErrorMessage("Failed to initialize memory for matrix.",1);} if (pad) /* This lot is debugging code that checks out matrix errors on allocation and release */ { if (A.vec) { A.V=A.M[0];for (i=0;imat=top->mat=A;top->bp=bottom;bottom->fp=top; } else /* expanding the linked list by one */ { top->fp=(MREC *)calloc(1,sizeof(MREC)); top->fp->mat=A;top->fp->bp=top;top=top->fp; /* crystal clear, no? */ } } A.V=A.M[0];/* This allows vectors to be accessed using A.V[i] */ return(A); } void mcopy(matrix *A,matrix *B) /* copies A into B */ { long Ac; double *pA,*pB,**AM,**BM; if (A->r>B->r||A->c>B->c) ErrorMessage("Target matrix too small in mcopy",1); BM=B->M;Ac=A->c; for (AM=A->M;AMM+A->r;AM++) { pB= *BM; for (pA= *AM;pA< *AM+Ac; pA++) *(pB++) = *pA; BM++; } } void freemat(A) matrix A; { long i,j,pad;int ok=1; MREC *delet; #ifdef RANGECHECK pad=PAD; #else pad=0L; #endif /* if (A.original_r*A.original_c!=0L) */ { if (pad) { if (A.vec) { for (i=-pad;i<0;i++) if ((A.V[i]!=PADCON)||(A.V[i+A.original_r*A.original_c+pad]!=PADCON)) ok=0; } else { for (i=-pad;imat.M!=A.M)) { i++;delet=delet->fp;} if (i==matrallocd) { ErrorMessage("INTEGRITY PROBLEM in the extant matrix list.",1); } else { if (i) delet->bp->fp=delet->fp; else bottom=delet->fp; if (i!=matrallocd-1) delet->fp->bp=delet->bp; else top=delet->bp; free(delet); } /* repositioning pointers so that what was allocated gets freed */ if (!A.vec) for (i=0;ir;i++) for (j=0;jc;j++) a[i+r*j]=M->M[i][j]; } int *Xd_strip(matrix *Xd) /* The rows of Xd (excluding last col) contain the covariate values for a set of data to which a thin plate spline is to be fitted. The purpose of this routine is to locate co-incident points, and strip out redundant copies of these points. At the same time a record is kept of what has been done, so that the function returns an array yxindex, such that yxindex[i] contains the row of the stripped down Xd that corresponds to the ith response datum. Note that the identification of ties involves sorting Xd - even if there are no ties. Note that this routine assumes that the final column of Xd consists of the integers 0 to Xd->r-1. These are vital for constructing the index. On exit Xd->r will contain the number of unique covariate points. */ { int *yxindex,start,stop,ok,i; /* long Xdor;*/ double xi,**dum; yxindex = (int *)calloc((size_t)Xd->r,sizeof(int)); dum = (double **)calloc((size_t)Xd->r,sizeof(double *)); msort(*Xd); /* Xdor=Xd->r; keep record of original length of Xd */ start=stop=0;ok=1; while(ok) { /* look for start of run of equal rows ..... */ while(startr-1&&!Xd_row_comp(Xd->M[start],Xd->M[start+1],(int)Xd->c-1)) { /* Xd->M[start] not tied with anything, nothing to erase.... */ xi=Xd->M[start][Xd->c-1]; yxindex[ROUND(xi)]=start; start++; } if (start==Xd->r-1) { ok=0; /* reached end with no more ties */ xi=Xd->M[start][Xd->c-1]; yxindex[ROUND(xi)]=start; /* final index entry needed */ } if (ok) /* search for end of run */ { stop=start+1; while(stopr-1&&Xd_row_comp(Xd->M[stop],Xd->M[stop+1],(int)Xd->c-1)) stop++; for (i=start;i<=stop;i++) /* fill out the index array */ { xi=Xd->M[i][Xd->c-1]; yxindex[ROUND(xi)]=start; dum[i-start]=Xd->M[i]; /* Rows stored to copy back onto end, so matrix can be freed properly */ } for (i=stop+1;ir;i++) { Xd->M[i-stop+start]=Xd->M[i];} Xd->r -= stop-start; for (i=1;i<=stop-start;i++) { Xd->M[Xd->r-1+i]=dum[i];} } } free(dum); return(yxindex); } int Xd_row_comp(double *a,double *b,int k) /* service routine for Xd_strip(), compares k elements of two rows for equality */ { int i; for (i=0;i=0) { k=el;return(0);} na=(*(double **)a);nb=(*(double **)b); for (i=0;inb[i]) return(1); } return(0); } int melemcmp(const void *a,const void *b) { return(real_elemcmp(a,b,-1)); } void msort(matrix a) /* sorts a matrix, in situ, using standard routine qsort so that its first col is in ascending order, its second col is in ascending order for any ties in the first col, and so on..... */ { double z=0.0; real_elemcmp(&z,&z,(int)a.c); qsort(a.M,(size_t)a.r,sizeof(a.M[0]),melemcmp); } void RuniqueCombs(double *X,int *ind,int *r, int *c) /* X is a matrix. This routine finds its unique rows and strips out the duplicates. This is useful for finding out the number of unique covariate combinations present in a set of data. */ { matrix B,Xd; int i,*ind1; B=Rmatrix(X,(long)(*r),(long)(*c)); Xd=initmat(B.r,B.c+1); Xd.c--;mcopy(&B,&Xd);freemat(B);Xd.c++; for (i=0;i