/* Last changed Time-stamp: <2009-04-24 11:48:38 ivo> */ /* minimum free energy folding for a set of aligned sequences c Ivo Hofacker Vienna RNA package */ #include #include #include #include #include #include #include "fold.h" #include "utils.h" #include "energy_par.h" #include "fold_vars.h" #include "pair_mat.h" #include "params.h" #include "ribo.h" /*@unused@*/ static char rcsid[] UNUSED = "$Id: alifold.c,v 1.18 2009/02/27 16:25:54 ivo Exp $"; #define PAREN #define PUBLIC #define PRIVATE static #define STACK_BULGE1 1 /* stacking energies for bulges of size 1 */ #define NEW_NINIO 1 /* new asymetry penalty */ PUBLIC float alifold(char **strings, char *structure); PRIVATE void init_alifold(int length); PUBLIC void free_alifold_arrays(void); PUBLIC double cv_fact=1.; PUBLIC double nc_fact=1.; PRIVATE void parenthesis_structure(char *structure, int length); PRIVATE void get_arrays(unsigned int size); PRIVATE void make_pscores(const short *const *S, const char *const *AS, int n_seq, const char *structure); PRIVATE short *encode_seq(const char *sequence, short *s5, short *s3, char *ss, unsigned short *as); PRIVATE int fill_arrays(const char **strings); PRIVATE void backtrack(const char **strings, int s); PRIVATE int ML_Energy(int i, int is_extloop,int n_seq); PRIVATE double stack_energy(int i, char **sequences, int n_seq, float *energy); PRIVATE void arrays_for_energyofstruct(int n_seq, char **sequences); PRIVATE void free_arrays_for_energyofstruct(int n_seq); PRIVATE double energy_of_alistruct_pt(char **sequences,short * ptable, int n_seq, float *CVenergy); /*@unused@*/ extern int LoopEnergy(int n1, int n2, int type, int type_2, int si1, int sj1, int sp1, int sq1); extern int HairpinE(int size, int type, int si1, int sj1, const char *string); #define MAXSECTORS 500 /* dimension for a backtrack array */ #define LOCALITY 0. /* locality parameter for base-pairs */ #define MIN2(A, B) ((A) < (B) ? (A) : (B)) PRIVATE const paramT *P; PRIVATE int *indx; /* index for moving in the triangle matrices c[] and fMl[]*/ PRIVATE int *c; /* energy array, given that i-j pair */ PRIVATE int *cc; /* linear array for calculating canonical structures */ PRIVATE int *cc1; /* " " */ PRIVATE int *f5; /* energy of 5' end */ PRIVATE int *fML; /* multi-loop auxiliary energy array */ PRIVATE int *Fmi; /* holds row i of fML (avoids jumps in memory) */ PRIVATE int *DMLi; /* DMLi[j] holds MIN(fML[i,k]+fML[k+1,j]) */ PRIVATE int *DMLi1; /* MIN(fML[i+1,k]+fML[k+1,j]) */ PRIVATE int *DMLi2; /* MIN(fML[i+2,k]+fML[k+1,j]) */ PRIVATE int *pscore; /* precomputed array of pair types */ PRIVATE int init_length=-1; PUBLIC float **readribosum(char *name); /*--------------------------------------------------------------------------*/ PRIVATE void init_alifold(int length) { unsigned int n; if (length<1) nrerror("initialize_fold: argument must be greater 0"); if (init_length>0) free_alifold_arrays(); get_arrays((unsigned) length); make_pair_matrix(); init_length=length; for (n = 1; n <= (unsigned) length; n++) indx[n] = (n*(n-1)) >> 1; /* n(n-1)/2 */ update_fold_params(); } /*--------------------------------------------------------------------------*/ PRIVATE void get_arrays(unsigned int size) { indx = (int *) space(sizeof(int)*(size+1)); c = (int *) space(sizeof(int)*((size*(size+1))/2+2)); fML = (int *) space(sizeof(int)*((size*(size+1))/2+2)); pscore = (int *) space(sizeof(int)*((size*(size+1))/2+2)); f5 = (int *) space(sizeof(int)*(size+2)); cc = (int *) space(sizeof(int)*(size+2)); cc1 = (int *) space(sizeof(int)*(size+2)); Fmi = (int *) space(sizeof(int)*(size+1)); DMLi = (int *) space(sizeof(int)*(size+1)); DMLi1 = (int *) space(sizeof(int)*(size+1)); DMLi2 = (int *) space(sizeof(int)*(size+1)); if (base_pair) free(base_pair); base_pair = (struct bond *) space(sizeof(struct bond)*(1+size/2)); } /*--------------------------------------------------------------------------*/ void free_alifold_arrays(void) { free(indx); free(c); free(fML); free(f5); free(cc); free(cc1); free(pscore); free(base_pair); base_pair=NULL; free(Fmi); free(DMLi); free(DMLi1);free(DMLi2); init_length=0; } static short **S; static short **S5; /*S5[s][i] holds next base 5' of i in sequence s*/ static short **S3; /*Sl[s][i] holds next base 3' of i in sequence s*/ static char **Ss; static unsigned short **a2s; /*--------------------------------------------------------------------------*/ #define UNIT 100 #define MINPSCORE -2 * UNIT float alifold(char **strings, char *structure) { int length, energy, s, n_seq; length = (int) strlen(strings[0]); if (length>init_length) init_alifold(length); if ((P==NULL)||(fabs(P->temperature - temperature)>1e-6)) { update_fold_params(); P = scale_parameters(); } for (s=0; strings[s]!=NULL; s++); n_seq = s; S = (short **) space(n_seq*sizeof(short *)); S5 = (short **) space(n_seq*sizeof(short *)); S3 = (short **) space(n_seq*sizeof(short *)); a2s= (unsigned short **)space(n_seq*sizeof(unsigned short *)); Ss = (char **)space(n_seq*sizeof(char *)); for (s=0; sTURN?(j-TURN):1); i= 1; i--) { /* i,j in [1..length] */ for (j = i+TURN+1; j <= length; j++) { int ij, psc; ij = indx[j]+i; for (s=0; s=MINPSCORE) { /* a pair to consider */ int stackEnergy = INF; /* hairpin ----------------------------------------------*/ for (new_c=s=0; sdangle3[tt][S3[s][i]]; d5 = P->dangle5[tt][S5[s][j]]; decomp += d5 + d3; } } MLenergy = decomp + n_seq*P->MLclosing; for (s=0; sMLintern[type[s]]; new_c = MLenergy < new_c ? MLenergy : new_c; new_c = MIN2(new_c, cc1[j-1]+stackEnergy); cc[j] = new_c - psc; /* add covariance bonnus/penalty */ if (noLonelyPairs) c[ij] = cc1[j-1]+stackEnergy-psc; else c[ij] = cc[j]; } /* end >> if (pair) << */ else c[ij] = INF; /* done with c[i,j], now compute fML[i,j] */ /* free ends ? -----------------------------------------*/ new_fML = fML[ij+1]+n_seq*P->MLbase; new_fML = MIN2(fML[indx[j-1]+i]+n_seq*P->MLbase, new_fML); energy = c[ij]; for (s=0; sMLintern[type[s]]; if (dangles) { /* double dangles */ energy += (i==1) ? /* works also for circfold */ P->dangle5[type[s]][S5[s][1]] : P->dangle5[type[s]][S5[s][i]]; /* if (jdangle3[type[s]][S3[s][j]]; } } new_fML = MIN2(energy, new_fML); /* modular decomposition -------------------------------*/ for (decomp = INF, k = i+1+TURN; k <= j-2-TURN; k++) decomp = MIN2(decomp, Fmi[k]+fML[indx[j]+k+1]); DMLi[j] = decomp; /* store for use in ML decompositon */ new_fML = MIN2(new_fML,decomp); /* coaxial stacking deleted */ fML[ij] = Fmi[j] = new_fML; /* substring energy */ } { int *FF; /* rotate the auxilliary arrays */ FF = DMLi2; DMLi2 = DMLi1; DMLi1 = DMLi; DMLi = FF; FF = cc1; cc1=cc; cc=FF; for (j=1; j<=length; j++) {cc[j]=Fmi[j]=DMLi[j]=INF; } } } /* calculate energies of 5' and 3' fragments */ f5[TURN+1]=0; for (j=TURN+2; j<=length; j++) { f5[j] = f5[j-1]; if (c[indx[j]+1]2) energy += TerminalAU; if ((dangles)&&(jdangle3[type][S3[s][j]]; } f5[j] = MIN2(f5[j], energy); } for (i=j-TURN-1; i>1; i--) { if (c[indx[j]+i]2) energy += TerminalAU; if (dangles) { energy += P->dangle5[type][S5[s][i]]; if (jdangle3[type][S3[s][j]]; } } f5[j] = MIN2(f5[j], energy); } } } free(type); return(f5[length]); } struct sect { int i; int j; int ml; } static sector[MAXSECTORS]; /* stack of partial structures for backtracking */ #include "alicircfold.inc" void backtrack(const char **strings, int s) { /*------------------------------------------------------------------ trace back through the "c", "f5" and "fML" arrays to get the base pairing list. No search for equivalent structures is done. This inverts the folding procedure, hence it's very fast. ------------------------------------------------------------------*/ /* normally s=0. If s>0 then s items have been already pushed onto the sector stack */ int i, j, k, p, q, length, energy; int type_2, tt, mm; int b=0, cov_en = 0; int n_seq; int *type; length = strlen(strings[0]); for (n_seq=0; strings[n_seq]!=NULL; n_seq++); type = (int *) space(n_seq*sizeof(int)); if (s==0) { sector[++s].i = 1; sector[s].j = length; sector[s].ml = (backtrack_type=='M') ? 1 : ((backtrack_type=='C')?2:0); } while (s>0) { int ss, ml, fij, fi, cij, traced, i1, j1, d3, d5, jj=0; int canonical = 1; /* (i,j) closes a canonical structure */ i = sector[s].i; j = sector[s].j; ml = sector[s--].ml; /* ml is a flag indicating if backtracking is to occur in the fML- (1) or in the f-array (0) */ if (ml==2) { base_pair[++b].i = i; base_pair[b].j = j; cov_en += pscore[indx[j]+i]; goto repeat1; } if (j < i+TURN+1) continue; /* no more pairs in this interval */ fij = (ml)? fML[indx[j]+i] : f5[j]; fi = (ml)?(fML[indx[j-1]+i]+n_seq*P->MLbase):f5[j-1]; if (fij == fi) { /* 3' end is unpaired */ sector[++s].i = i; sector[s].j = j-1; sector[s].ml = ml; continue; } if (ml == 0) { /* backtrack in f5 */ /* j or j-1 is paired. Find pairing partner */ for (i=j-TURN-1,traced=0; i>=1; i--) { int cc, en; jj = i-1; if (c[indx[j]+i]2) cc += TerminalAU; } en = cc + f5[i-1]; if (dangles) { for (ss=0; ss1) en += P->dangle5[type[ss]][S5[ss][i]]; if (jdangle3[type[ss]][S3[ss][j]]; } } if (fij == en) traced=j; } if (traced) break; } if (!traced) nrerror("backtrack failed in f5"); sector[++s].i = 1; sector[s].j = jj; sector[s].ml = ml; j=traced; base_pair[++b].i = i; base_pair[b].j = j; cov_en += pscore[indx[j]+i]; goto repeat1; } else { /* trace back in fML array */ int cij1=INF, ci1j=INF, ci1j1=INF; if (fML[indx[j]+i+1]+n_seq*P->MLbase == fij) { /* 5' end is unpaired */ sector[++s].i = i+1; sector[s].j = j; sector[s].ml = ml; continue; } cij = c[indx[j]+i]; for (ss=0; ssMLintern[tt]; if (dangles) { /* double dangles */ cij += (i==1) ? P->dangle5[tt][S5[ss][1]] : P->dangle5[tt][S5[ss][i]]; /* if (jdangle3[tt][S3[ss][j]]; } } if ((fij==cij)||(fij==ci1j)||(fij==cij1)||(fij==ci1j1)) { /* found a pair */ if (fij==ci1j) i++; else if (fij==cij1) j--; else if (fij==ci1j1) {i++; j--;} base_pair[++b].i = i; base_pair[b].j = j; cov_en += pscore[indx[j]+i]; goto repeat1; } for (k = i+1+TURN; k <= j-2-TURN; k++) if (fij == (fML[indx[k]+i]+fML[indx[j]+k+1])) break; sector[++s].i = i; sector[s].j = k; sector[s].ml = ml; sector[++s].i = k+1; sector[s].j = j; sector[s].ml = ml; if (k>j-2-TURN) nrerror("backtrack failed in fML"); continue; } repeat1: /*----- begin of "repeat:" -----*/ if (canonical) cij = c[indx[j]+i]; for (ss=0; ssstack[type[ss]][type_2]; } cij += pscore[indx[j]+i]; base_pair[++b].i = i+1; base_pair[b].j = j-1; cov_en += pscore[indx[j-1]+i+1]; i++; j--; canonical=0; goto repeat1; } canonical = 1; cij += pscore[indx[j]+i]; {int cc=0; for (ss=0; ss= minq; q--) { if (c[indx[q]+p]>=INF) continue; for (ss=energy=0; ssMLclosing; for (ss=d3=d5=0; ssMLintern[tt]; d5 += P->dangle5[tt][S5[ss][j]]; d3 += P->dangle3[tt][S3[ss][i]]; } i1 = i+1; j1 = j-1; sector[s+1].ml = sector[s+2].ml = 1; for (k = i+2+TURN; k < j-2-TURN; k++) { int en; en = fML[indx[k]+i+1]+fML[indx[j-1]+k+1]+mm; if (dangles) /* double dangles */ en += d5+d3; if (cij == en) break; } if (k<=j-3-TURN) { /* found the decomposition */ sector[++s].i = i1; sector[s].j = k; sector[++s].i = k+1; sector[s].j = j1; } else { nrerror("backtracking failed in repeat"); } } /* fprintf(stderr, "covariance energy %6.2f\n", cov_en/100.); */ base_pair[0].i = b; /* save the total number of base pairs */ free(type); } /*---------------------------------------------------------------------------*/ PRIVATE short * encode_seq(const char *sequence, short *s5, short *s3, char *ss, unsigned short *as) { unsigned int i,l; short *S; unsigned short p; l = strlen(sequence); S = (short *) space(sizeof(short)*(l+2)); S[0] = (short) l; s5[0]=s5[1]=0; /* make numerical encoding of sequence */ for (i=1; i<=l; i++) { short ctemp; ctemp=(short) encode_char(toupper(sequence[i-1])); S[i]= ctemp ; } if (oldAliEn) { /*use alignment sequences in all energy evaluations*/ ss[0]=sequence[0]; for (i=1; i0; i--) { char c5; c5=sequence[i-1]; if ((c5=='-')||(c5=='_')||(c5=='~')||(c5=='.')) continue; s5[1] = S[i]; break; } for (i=1; i<=l; i++) { char c3; c3 = sequence[i-1]; if ((c3=='-')||(c3=='_')||(c3=='~')||(c3=='.')) continue; s3[l] = S[i]; break; } } else s5[1]=s3[l]=0; for (i=1,p=0; i<=l; i++) { char c5; c5=sequence[i-1]; if ((c5=='-')||(c5=='_')||(c5=='~')||(c5=='.')) s5[i+1]=s5[i]; else { /* no gap */ ss[p++]=sequence[i-1]; /*start at 0!!*/ s5[i+1]=S[i]; } as[i]=p; } for (i=l; i>=1; i--) { char c3; c3=sequence[i-1]; if ((c3=='-')||(c3=='_')||(c3=='~')||(c3=='.')) s3[i-1]=s3[i]; else s3[i-1]=S[i]; } } return S; } /*---------------------------------------------------------------------------*/ PRIVATE void parenthesis_structure(char *structure, int length) { int n, k; for (n = 0; n <= length-1; structure[n++] = '.') ; structure[length] = '\0'; for (k = 1; k <= base_pair[0].i; k++) { structure[base_pair[k].i-1] = '('; structure[base_pair[k].j-1] = ')'; } } /*---------------------------------------------------------------------------*/ PRIVATE void make_pscores(const short *const* S, const char *const* AS, int n_seq, const char *structure) { /* calculate co-variance bonus for each pair depending on */ /* compensatory/consistent mutations and incompatible seqs */ /* should be 0 for conserved pairs, >0 for good pairs */ #define NONE -10000 /* score for forbidden pairs */ int n,i,j,k,l,s; int olddm[7][7]={{0,0,0,0,0,0,0}, /* hamming distance between pairs */ {0,0,2,2,1,2,2} /* CG */, {0,2,0,1,2,2,2} /* GC */, {0,2,1,0,2,1,2} /* GU */, {0,1,2,2,0,2,1} /* UG */, {0,2,2,1,2,0,2} /* AU */, {0,2,2,2,1,2,0} /* UA */}; float **dm; n=S[0][0]; /* length of seqs */ if (ribo) { if (RibosumFile !=NULL) dm=readribosum(RibosumFile); else dm=get_ribosum(AS,n_seq,n); } else { /*use usual matrix*/ dm=(float **)space(7*sizeof(float*)); for (i=0; i<7;i++) { dm[i]=(float *)space(7*sizeof(float)); for (j=0; j<7; j++) dm[i][j] = (float) olddm[i][j]; } } n=S[0][0]; /* length of seqs */ for (i=1; in_seq) { pscore[indx[j]+i] = NONE; continue;} for (k=1,score=0; k<=6; k++) /* ignore pairtype 7 (gap-gap) */ for (l=k; l<=6; l++) score += pfreq[k]*pfreq[l]*dm[k][l]; /* counter examples score -1, gap-gap scores -0.25 */ pscore[indx[j]+i] = cv_fact * ((UNIT*score)/n_seq - nc_fact*UNIT*(pfreq[0] + pfreq[7]*0.25)); } } if (noLonelyPairs) /* remove unwanted pairs */ for (k=1; k=1)&&(j<=n)) { if ((i>1)&&(j0) ? psij : 0; /* fallthrough */ case '>': /* pairs downstream */ for (l=j+TURN+1; l<=n; l++) pscore[indx[l]+j] = NONE; break; } } if (hx!=0) { fprintf(stderr, "%s\n", structure); nrerror("unbalanced brackets in constraint string"); } free(stack); free(stack2); } /*free dm */ for (i=0; i<7;i++) { free(dm[i]); } free(dm); } /*--------New scoring part-----------------------------------*/ /*Get the mean pairwise identity in steps from ?to?(ident)*/ PUBLIC int get_mpi(char *Alseq[], int n_seq, int length, int *mini) { int i, j,k; float ident=0; int pairnum=0; int sumident=0; float minimum=1.; for(j=0; j0) return (int) (sumident*100/pairnum); else return 0; } /* how to chose a ribosum matrix: ribosum matrices exist for starlike clusters of X=45 55 60 65 70 75 80 85 90 95 100 they are further seperated by only regarding sequences with a minimal pairwise idensity of Y=25-95, step 5, not all are present. now the question is, which matrix to use when. the suggestion of the dr. will: with a mpi of Z X~Z and Y > Z ?? if we say the minimum of the pis is M, then we may be able to use: X~Z and Y ~ M? I'd say we do a default matrix (e.g. 85/60) but better is try out (all 170??) and then we use the best in average. actually, it would be preferrable to make a very big testset and simply check it out. (create a function to derive the best matrix) furthermore: default, function or user defined. ntscd: fijklmn pijpklpmn */ PUBLIC float **readribosum(char *name) { float **dm; char *line; FILE *fp; int i=0; int who=0; float a,b,c,d,e,f; int translator[7]={0,5,1,2,3,6,4}; fp=fopen(name,"r"); dm=(float **)space(7*sizeof(float*)); for (i=0; i<7;i++) { dm[i]=(float *)space(7*sizeof(float)); } while(1) { /*bisma hoit fertisch san*/ line=get_line(fp); if (*line=='#') continue; i=0; i=sscanf(line,"%f %f %f %f %f %f",&a,&b,&c,&d,&e,&f); if (i==0) break; dm[translator[++who]][translator[1]]=a; dm[translator[who]][translator[2]]=b; dm[translator[who]][translator[3]]=c; dm[translator[who]][translator[4]]=d; dm[translator[who]][translator[5]]=e; dm[translator[who]][translator[6]]=f; free(line); if (who==6) break; } fclose(fp); return dm; } /*------------------ENERGY OF STRUCT----------------------------------*/ PRIVATE short *pair_table; /*write another "call function" including all the allocation, seq2num etc if needed*/ static int *type; PUBLIC float energy_of_alistruct(char **sequences, const char *structure, int n_seq, float *CVenergy) { double energy; int new=0; short **tempS; short **tempS5; /*S5[s][i] holds next base 5' of i in sequence s*/ short **tempS3; /*Sl[s][i] holds next base 3' of i in sequence s*/ char **tempSs; unsigned short **tempa2s; int *temptype, *tempindx, *temppscore; if (P==NULL) P = scale_parameters(); /*save old memory*/ tempS=S; tempS3=S3; tempS5=S5; tempSs=Ss; tempa2s=a2s; temptype=type; tempindx=indx; temppscore=pscore; arrays_for_energyofstruct(n_seq, sequences); make_pscores((const short *const*)S, (const char *const *)sequences, n_seq, NULL); make_pair_matrix(); new=1; pair_table = make_pair_table(structure); energy = energy_of_alistruct_pt(sequences,pair_table, n_seq, CVenergy); free(pair_table); energy /= (100.*n_seq); *CVenergy /= (100.*n_seq); free_arrays_for_energyofstruct(n_seq); S=tempS;S3=tempS3; S5=tempS5; Ss=tempSs; a2s=tempa2s; type=temptype; indx=tempindx; pscore=temppscore; return energy ; } /*------------------------------------------------------------------*/ PRIVATE double energy_of_alistruct_pt(char **sequences,short * ptable, int n_seq, float *CVenergy) { int i, length; double energy=0; *CVenergy = 0; pair_table = ptable; length = S[0][0]; energy = backtrack_type=='M' ? (float) ML_Energy(0, 0,n_seq) : (float) ML_Energy(0, 1,n_seq); for (i=1; i<=length; i++) { if (pair_table[i]==0) continue; energy += stack_energy(i, sequences, n_seq, CVenergy); i=pair_table[i]; } return energy; } /*---------------------------------------------------------------------------*/ PRIVATE double stack_energy(int i, char **sequences, int n_seq, float *CVenergy) { /* calculate energy of substructure enclosed by (i,j) */ int ee= 0; int j, p, q, s; int numberofcomponents; double energy = 0; j=pair_table[i]; for (s=0; sq)) break; ee=0; for (s=0; sq) { ee=0;/* hair pin */ for (s=0; s< n_seq; s++) { if ((a2s[s][j-1]-a2s[s][i])<3) ee+=600; else ee += HairpinE(a2s[s][j-1]-a2s[s][i], type[s], S3[s][i], S5[s][j], Ss[s]+(a2s[s][i-1])); } energy += ee; *CVenergy += pscore[indx[j]+i]; return energy; } numberofcomponents=0; /* (i,j) is exterior pair of multiloop */ *CVenergy += pscore[indx[j]+i]; while (pTerminalAU; /* 0 or TerminalAU */ mlclosing = mlbase = 0; } else { for (x = 0; x <= NBPAIRS; x++) mlintern[x] = P->MLintern[x]; mlclosing =P->MLclosing*n_seq; mlbase = P->MLbase*n_seq; } if ( i==0 ) { j = pair_table[0]+1; stype = 0; /* no pair */ } else { j = pair_table[i]; for (s=0; sq */ tt = pair[S[s][p]][S[s][q]]; if (tt==0) tt=7; } energy += mlintern[tt]; if (dangles) { int dang5=0, dang3=0, dang; if ((a2s[s][p]>1) && (tt!=0)) dang5= P->dangle5[tt][S5[s][p]]; if ((i1>0) && a2s[s][i1]dangle3[type[s]][S3[s][i1]]; switch (p-i1-1) { case 0: /* adjacent helices */ if (dangles==2) energy += dang3+dang5; break; case 1: /* 1 unpaired base between helices */ dang = (dangles==2)?(dang3+dang5):MIN2(dang3, dang5); energy += dang; break; default: /* many unpaired base between helices */ energy += dang5 +dang3; } type[s] = tt; } } i1 = q; p=q+1; } while (q!=i); energy += mlclosing; energy += mlbase*u; return energy; } /*---------------------------------------------------------------------------*/ PRIVATE void arrays_for_energyofstruct(int n_seq, char **sequences){ int s,n; n = (int) strlen(sequences[0]); S = (short **) space(sizeof(short *)*(n_seq+1)); S5 = (short **) space(n_seq*sizeof(short *)); S3 = (short **) space(n_seq*sizeof(short *)); a2s= (unsigned short **)space(n_seq*sizeof(unsigned short *)); Ss = (char **)space(n_seq*sizeof(char *)); type = (int *) space(n_seq*sizeof(int)); pscore = (int *) space(sizeof(int)*((n+1)*(n+2)/2)); indx = (int *) space(sizeof(int)*(n+1)); for (s = 1; s <= (unsigned) n; s++){ indx[s] = (s*(s-1)) >> 1; } for (s=0; s