/*   r.c         assorted minor subroutines library          release 1.1    

     Copyright   (c) 2002   David J.C. MacKay

    This library 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 2.1 of the License, or (at your option) any later version.

    This library 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 this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    GNU licenses are here :
    http://www.gnu.org/licenses/licenses.html

    Author contact details are here :
    http://www.inference.phy.cam.ac.uk/mackay/c/macopt.html       mackay@mrao.cam.ac.uk
*/
/* My routines */

#include "r.h"
#include "rand.h"

/* input */

void inputf( float *pointer )
{
  int junk ;
  scanf( "%f" , pointer ) ;
  junk = getchar( ) ;
}
void inputd( double *pointer )
{
  int junk ;
  scanf( "%lf" , pointer ) ;
  junk = getchar( ) ;
}
void inputc( unsigned char *pointer )
{
  int junk ;
  scanf( "%c" , pointer ) ;
  junk = getchar( ) ;
}
void inputi( int *pointer )
{
  int junk ;
  scanf( "%d" , pointer ) ;
  junk = getchar( ) ;
}

void inputrf( float *pointer )
{
  int junk ;
  scanf( "%f" , pointer ) ;
  do{}while( ( junk = getchar( ) ) != 10 ) ;
}
void inputrd( double *pointer )
{
  int junk ;
  scanf( "%lf" , pointer ) ;
  do{}while( ( junk = getchar( ) ) != 10 ) ;
}
void inputrc( unsigned char *pointer )
{
  int junk ;
  scanf( "%c" , pointer ) ;
  do{}while( ( junk = getchar( ) ) != 10 ) ;
}
void inputri( int *pointer )
{
  int junk ;
  scanf( "%d" , pointer ) ;
  do{}while( ( junk = getchar( ) ) != 10 ) ;
}

void clearscan( )
{
  int junk ;
  do{}while( ( junk = getchar( ) ) != 10 ) ;
}

void typeindvector( double *w , int l , int h )
{
  int i ;
  
  printf( "Please enter %d components \n" , h-l+1 ) ;
  for ( i = l ;i<= h ;i++ )
    scanf( "%lf" , &w[i] ) ;
  clearscan( ) ;
}

void constantdmatrix ( double **w , int l1 , int h1 , int l2, int h2 , 
		      double c )
{
  int i , j ;
  
  for ( i = l1 ; i <= h1 ; i++ )
    for ( j = l2 ; j <= h2 ; j++ )
      w[i][j] = c ;
}

void set_dvector_const( double *w , int l , int h , double c )
{
  int i ;
  
  for ( i = l ; i<= h ;i++ )
    w[i] = c ;
}

void set_dvector_c_dvector( double *w , int l , int h , double c , double *v )
{
  int i ;
  
  for ( i = l ; i<= h ;i++ )
    w[i] = c * v[i] ;
}

void set_ivector_const( int *w , int l , int h , int c )
{
  int i ;
  
  for ( i = l ; i<= h ;i++ )
    w[i] = c ;
}

void typeindmatrix ( double **b , int l1 , int h1 , int l2 , int h2 )
{
  int	i , j ;
  
  printf( "please type matrix\n" ) ;
  for ( i = l1 ; i<= h1-1 ; i++ )
    for ( j = l2 ; j<= h2 ; j++ )
      inputd( &b[i][j] ) ; /* This is all a trick to obtain clearscan at the last read-in */
  for ( j = l2 ; j<= h2-1 ; j++ )
    inputd( &b[i][j] ) ;
  inputrd( &b[i][j] ) ;
}

void typeincmatrix ( unsigned char **b , int l1 , int h1 , int l2 , int h2 )
{
  int	i , j , t ;
  
  printf( "please type matrix\n" ) ;
  for ( i = l1 ; i<= h1-1 ; i++ )
    for ( j = l2 ; j<= h2 ; j++ ) {
      inputi( &t ) ; b[i][j] = (unsigned char) t ; 
    }
  for ( j = l2 ; j<= h2-1 ; j++ ) {
    inputi( &t ) ; b[i][j] = (unsigned char) t ; 
  }
  inputri( &t ) ; b[i][j] = (unsigned char) t ; 
}

int ***imatrix3( int l1 , int h1 , int l2 , int h2 , int l3 , int h3 )
{
  int ***c ;
  int s1 , i ;
  
  s1 = h1-l1+1 ;
  
  c = ( int *** )malloc( ( unsigned ) s1*sizeof( int ** ) ) - l1 ;
  for ( i = l1 ;i<= h1 ;i++ )
    c[i] = imatrix( l2 , h2 , l3 , h3 ) ;
  return c ;
}

double ***dmatrix3( int l1 , int h1 , int l2 , int h2 , int l3 , int h3 )
{
  double ***c;
  int s1,i;
  
  s1=h1-l1+1;
  
  c=(double ***) malloc((unsigned) s1*sizeof(double **)) - l1;
  for (i=l1;i<=h1;i++)
    c[i]=dmatrix(l2,h2,l3,h3);
  return c;
}

long int ***limatrix3( int l1 , int h1 , int l2 , int h2 , int l3 , int h3 )
{
  long int ***c ;
  int s1 , i ;
  
  s1 = h1-l1+1 ;
  
  c = ( long int *** )malloc( ( unsigned ) s1*sizeof( long int ** ) ) - l1 ;
  for ( i = l1 ;i<= h1 ;i++ )
    c[i] = limatrix( l2 , h2 , l3 , h3 ) ;
  return c ;
}

long int **limatrix( int nrl , int nrh , int ncl , int nch )
{
  int i ;
  long int **m ;
  
  m=( long int ** )malloc( ( unsigned ) ( nrh-nrl+1 )*sizeof( long int* ) ) ;
  if ( !m ) nrerror( "allocation failure 1 in limatrix( )" ) ;
  m -= nrl ;
  
  for( i=nrl ;i<=nrh ;i++ ) {
    m[i]=( long int * )malloc( ( unsigned ) ( nch-ncl+1 )*sizeof( long int ) ) ;
    if ( !m[i] ) nrerror( "allocation failure 2 in limatrix( )" ) ;
    m[i] -= ncl ;
  }
  return m ;
}

int ipower( int a , int b )
{
  int     i=1;
  
  for(;b>0;b--)
    i*=a;
  return(i);
}

double readindmatrix 
(
 double **b ,
 int l1,
 int h1,
 int l2,
 int h2,
 char *file
)
{
	int	i, j;
	FILE    *fp;
	double	sumd=0.0;

	fp = fopen( file, "r" );
	if( !fp )   fprintf( stderr, "No such file: %s\n", file ), exit(0);

	printf( "reading in matrix from %s\n",file );
	for (i=l1; i<=h1; i++){
		for (j=l2; j<=h2; j++){
			fscanf(fp,"%lf ",&b[i][j]);
			sumd += b[i][j];
		}
	}
	fclose( fp );
	printf( "matrix in\n" );
	return(sumd);
}

int readinimatrix 
(
 int **b ,
 int l1,
 int h1,
 int l2,
 int h2,
 char *file
)
{
  int	status = 0;
  FILE    *fp;

  fp = fopen( file, "r" );
  if( !fp )   fprintf( stderr, "No such file: %s\n", file ), exit(0);

  printf( "reading in matrix from %s\n",file );
  status = fread_imatrix ( b , l1 , h1 , l2 , h2 , fp ) ; 

  fclose( fp );
  return status ;
}

int fread_imatrix 
(
 int **b ,
 int l1,
 int h1,
 int l2,
 int h2,
 FILE *fp 
)
{
  int	i, j , status = 0;

  for (i=l1; i<=h1; i++){
    for (j=l2; j<=h2; j++){
      if ( fscanf(fp,"%d ",&b[i][j]) == EOF ) {
	status -- ;
	break;
      }
    }
    if ( status < 0 ) break ;
  }
  if ( status == 0 ) fprintf( stderr , "%d * %d int matrix in\n" , h1 , h2 );
  else fprintf( stderr, 
		  "Warning: readinimatrix failed at component %d\n",i);
  return status ;
}

void readinlumatrix 
(
 double **b,
 int *indx,
 int n,
 char *file
)
{
  int	i, j , status = 0 ;
  FILE    *fp;
  
  fp = fopen( file, "r" );
  if( !fp )   fprintf( stderr, "No such file: %s\n", file ), exit(0);
  
  printf( "reading in matrix\n" );
  for (i=1; i<=n; i++){
    for (j=1; j<=n; j++){
      if ( fscanf(fp,"%lf ",&b[i][j]) == EOF ) {
	status = -1 ;
	break ;
      }
    }
  }
  if ( status == 0 ) {
    for (i=1; i<=n; i++){
      if ( fscanf(fp,"%d ",&indx[i]) == EOF ) {
	status = -1 ;
	break ; 
      }
    }
  }
  fclose( fp );
  if ( status == 0 ) printf( "lu matrix in\n" );
  else fprintf( stderr, 
		  "Warning: readinlumatrix failed at component %d\n",i);
}

void readindvector(double *w, int lo, int hi, char *file)
{
	int i, status = 0 ;
	FILE    *fp;
	
	fp = fopen( file, "r" );
	if( !fp )   fprintf( stderr, "No such file: %s\n", file ), exit(0);

	for (i=lo;i<=hi;i++) {
	  if ( fscanf(fp,"%lf ",&w[i]) == EOF ) {
	    status = -1 ; 
	    break ;
	  }
	}
	fclose( fp );
	if ( status < 0 ) 
	  fprintf( stderr, 
		  "Warning: readindvector failed at component %d\n",i);
}

int readdvector(double *w, int lo, int hi, char *file)
{
  int i, status = 0 ;
  FILE    *fp;
  
  fp = fopen( file, "r" );
  if( !fp ) {
    fprintf( stderr, "No such file: %s\n", file ) ;
    status -- ;
  } 
  else {
    for ( i = lo ; i <= hi ; i ++ ) {
      if ( fscanf ( fp , "%lf " , &w[i] ) == EOF ) {
	status = -1 ; 
	break ;
      }
    }
    fclose( fp );
    if ( status < 0 ) 
      fprintf( stderr, 
	      "Warning: readdvector failed at component %d\n",i);
  }
  return status ; 
}

int writedvector ( double *w, int lo, int hi, char *file)
{
  int i, status = 0 ;
  FILE    *fp;
  
  fp = fopen( file, "w" );
  if( !fp ) {
    fprintf( stderr, "writedvector---No such file: %s\n", file ) ;
    status -- ;
  } 
  else {
    for ( i = lo ; i <= hi ; i ++ ) {
      fprintf ( fp , "%g " , w[i] ) ;
    }
    fclose( fp );
  }
  return status ; 
}

int writedmatrix ( 
 double **m,
 int l1,
 int h1,
 int l2,
 int h2,
 char *file
)
{
  int status = 0 ;
  FILE    *fp;
  int i,j;
	
  fp = fopen( file, "w" );
  if( !fp ) {
    fprintf( stderr, "writedmatrix---No such file: %s\n", file ) ;
    status -- ;
  } 
  else {
    for (i=l1; i<=h1; i++){
      for (j=l2; j<=h2; j++)
	fprintf ( fp , "%g " , m[i][j] ) ;

      fprintf ( fp , "\n" ) ;
    }
    fclose( fp );
  }
  return status ; 
}

void readinivector(int *w, int lo, int hi, char *file)
{
  int status = 0 ;
  FILE    *fp;
  
  fp = fopen( file, "r" );
  if( !fp )   fprintf( stderr, "No such file: %s\n", file ), exit(0);

  status = fread_ivector ( w , lo , hi , fp ) ; 

  fclose( fp );
}

int fread_ivector(int *w, int lo, int hi, FILE *fp )
{
  int i, status = 0 ;
  
  for (i=lo;i<=hi;i++) {
    if ( fscanf(fp,"%d ",&w[i]) == EOF ) {
      status = -1 ; 
      break ;
    }
  }

/*  if ( status < 0 ) 
    fprintf( stderr, 
	    "Warning: fread_ivector failed at component %d\n",i);
*/
  return status ; 
}

int fread_dvector( double *w, int lo, int hi, FILE *fp )
{
  int i, status = 0 ;
  
  for (i=lo;i<=hi;i++) {
    if ( fscanf(fp,"%lf ",&w[i]) == EOF ) {
      status = -1 ; 
      break ;
    }
  }

/*  if ( status < 0 ) 
    fprintf( stderr, 
	    "Warning: fread_dvector failed at component %d\n",i);
*/
  return status ; 
}

int fread_cvector(unsigned char *w, int lo, int hi, FILE *fp )
{
  int i, status = 0 , bit ;
  
  for (i=lo;i<=hi;i++) {
    if ( fscanf(fp,"%d", &bit ) == EOF ) {
      status = -1 ; 
      break ;
    }
    w[i] = (unsigned char) bit ;
  }

/*  if ( status < 0 ) 
    fprintf( stderr, 
	    "Warning: fread_cvector failed at component %d\n",i);
*/
  return status ; 
}

void printoutimatrix 
(
 int **m,
 int l1,
 int h1,
 int l2,
 int h2
)
{
  write_imatrix ( stdout , m , l1 , h1 , l2 , h2 ) ; 
}

void write_imatrix 
(
 FILE *fp , 
 int **m,
 int l1,
 int h1,
 int l2,
 int h2
)
{
  int i,j;
  
  for (i=l1; i<=h1; i++){
    for (j=l2; j<=h2; j++)
      fprintf( fp , "%d ",m[i][j]);
    fprintf(fp , "\n");
  }                   
}

void write_imatrix2 
(
 FILE *fp , 
 int **m,
 int l1,
 int h1,
 int l2,
 int h2
)
{
  int i,j;
  
  for (i=l1; i<=h1; i++){
    for (j=l2; j<=h2; j++)
      fprintf( fp , "%+2d ",m[i][j]);
    fprintf(fp , "\n");
  }                   
}


void allocate_cm_inversion 
( unsigned char **mo,
 int l,
 int N,
 unsigned char **mi,
 cm_inversion *p
)
{
  int i,j ; 

  p->l = l ; p->N = N ; p->mo = mo ; p->mi = mi ; 
  p->m = cmatrix ( l , N , l , N ) ; 
  p->mt=(unsigned char **)malloc((unsigned) (N-l+1)*sizeof(unsigned char*));
  p->mt -= l ;
  p->perm = ivector ( l , N ) ; 
  p->iperm = ivector ( l , N ) ; 
  p->i = l ; 
  for (i=l; i<=N; i++){
    p->perm[i] = l-1 ;  /* deliberately off scale */
    p->iperm[i] = l-1 ;
    for (j=l; j<=N; j++) {
      mi[i][j] = 0 ; 
      p->m[i][j] = mo[i][j] ;
    }
    mi[i][i] = 1 ;
  }
}

void print_cm_inversion 
( cm_inversion *p
)
{
/*  printf( "mo:\n" ) ; 
  printoutcmatrix (  p->mo , p->l , p->N , p->l , p->N ) ; */
  printf( "m:\n" ) ; 
  printoutcmatrix (  p->m , p->l , p->N , p->l , p->N ) ; 
  printf( "mi:\n" ) ; 
  printoutcmatrix (  p->mi , p->l , p->N , p->l , p->N ) ; 
  printf( "i = %d\n" , p->i ) ;
  printf( "perm:\n" ) ; 
  printoutivector ( p->perm , p->l , p->N ) ; 
  printf( "iperm:\n" ) ; 
  printoutivector ( p->iperm , p->l , p->N ) ; 
  pause_for_return () ;
}

void free_cm_inversion 
( cm_inversion *p
)
{
  free_ivector ( p->perm , p->l , p->N ) ; 
  free_ivector ( p->iperm , p->l , p->N ) ; 
  free_cmatrix ( p->m , p->l  , p->N , p->l , p->N ) ;
  free( ( char * ) ( p->mt + p->l ) ) ;
}

/* invert_cmatrix attempts to invert p->m, or to continue to invert it, 
   starting from the state indicated by i,j,perm,etc. 
   if invert_cmatrix succeeds it returns 1, else 0, with p->i 
   recording the row at which non-full-rank was detected . 
*/
int invert_cmatrix
(
 cm_inversion *p
)
{
  int j , done , i2 , k ; 
  unsigned char *irow ;

  for ( ; p->i <= p->N ; p->i ++ ) {
    irow = p->m[p->i] ;
    /* search for a 1 in this row */
    for ( j = p->l , done = 0 ; j <= p->N ; j++ ) {
      if ( irow[j] &&            /* if we find a 1              and */
	  p->perm[j] < p->l ) {  /* if j is not already on the list */
	p->perm[j]  = p->i ; 
	p->iperm[p->i] = j ; 
	done = 1 ;
	break ; /* break out of j loop */
      }
    }
    if ( !done ) {
      return ( 0 ) ;
      break ;
    }
    else { /* search for 1s in subsequent rows. */
      for ( i2 = p->i + 1 ; i2 <= p->N ; i2 ++ ) {
	if ( p->m[i2][j] ) {
	  for ( k = p->l ; k <= p->N ; k ++ ) {
	    p->m[i2][k] ^= irow[k] ;
 	    p->mi[i2][k] ^= p->mi[p->i][k] ; 
	  }
	}
      }
    }
  }      
  /* at this point, if done==1 then m contains a (permuted) upper
     triangular matrix and mi contains a (permuted) lower triangular
     matrix. 
     */
/*  printf ("lu decomposition achieved\n" ) ; */
/*  print_cm_inversion ( p ) ; */
/*  printf ("now working back\n" ) ;  */
  done = invert_utriangularc ( p ) ; 
  /* finally, undo the permutation - make mi[l] = mi[perm[l]] etc. */
  undo_cm_perm ( p ) ; 
  return ( done ) ; 
}

void undo_cm_perm ( cm_inversion *p ) {
  int i , pi ;
  
  for ( i = p->N ; i >= p->l ; i-- ) {
    p->mt[i] = p->mi[i] ;                 /* copy all columns */
  } 
  for ( i = p->N ; i >= p->l ; i-- ) {    /* reallocate them */
    pi = p->perm[i] ;
    if ( ( pi >= p->l ) && ( pi <= p->N ) )
      p->mi[i] = p->mt[pi] ;
    else {
      fprintf ( stderr , "error in undo_cm_perm, perm[%d] = %d\n" , i , 
	       pi ) ; 
      exit ( 0 ) ; 
    }
  } 
}

/* invert_ltriangularc takes p->m and p->mi 
   and applies a series of row sums to both 
   such that p->m becomes the identity.
   If p->mi started out as the identity, it becomes the inverse 
   of p->m; otherwise it becomes (that inverse)*(whatever it was before) */
int invert_utriangularc 
( cm_inversion *p ) {
  int i , vj , j  , k ;
   
  for ( i = p->N ; i >= p->l ; i-- ) {
    for ( vj = i + 1 ; vj <= p->N ; vj++ ) { /* virtual j */
      j = p->iperm[vj] ;
      if (!( ( j >= p->l ) && ( j <= p->N ) ))
      {
	fprintf ( stderr , "error in invert_utriangularc, iperm[%d] = %d\n" ,
		 vj ,  j ) ; 
	exit ( 0 ) ; 
      }
      if ( p->m[i][j] ) {
	for ( k = p->l ; k <= p->N ; k ++ ) {
	  p->m[i][k] ^= p->m[vj][k] ; 
	  p->mi[i][k] ^= p->mi[vj][k] ; 
	} 
/*	printf("%d,%d -> \n",i,j);
	print_cm_inversion ( p ) ; */
      }
    }
  }
  return 1 ; /* inverse has been evaluated */
}


int modify_cmatrix_row ( cm_inversion *p ) {
  /* proceed along the current row seeking an available j */
  unsigned char *irow ;
  int j , done = 0 ;

  irow = p->m[p->i] ;
  /* search for a 1 in this row */
  for ( j = p->l ; done == 0 && j <= p->N ; j++ ) {
    if ( p->perm[j] < p->l ) {  /* if j is not already on the list */
      irow[j] = 1 ; 
      p->mo[p->i][j] ^= 1 ; /* modify original matrix */
      done = 1 ;
    }
  }
  return ( done ) ; /* if done == 0 then this 
		       routine has failed to
		       find a j; an unexpected
		       outcome */
}

/* 
   pbm format is 
   P1
   30 90
   (30 rows with 90 cols)

   which gives (under xv) a picture 
   with 90 rows and 30 cols.

   So in fact rows and columns are interchanged
*/
void cmatrix2pbm
(
 unsigned char **m,
 int l1,
 int h1,
 int l2,
 int h2,
 FILE *fp 
)
{
  int i,j;
  
  fprintf( fp , "P1\n%d %d\n" , h1 - l1 + 1 , h2 - l2 + 1 ) ;
  for (i=l1; i<=h1; i++){
    for (j=l2; j<=h2; j++)
      fprintf( fp , "%d ",m[i][j]);
    fprintf( fp , "\n");
  }                   
}

void printoutcmatrix 
(
 unsigned char **m,
 int l1,
 int h1,
 int l2,
 int h2
)
{
  int i,j;
  
  for (i=l1; i<=h1; i++){
    if ( !(i%10) ) printf ( "| " ) ; 
    else printf ( "  " ) ; 
  }
  printf("\n");
  for (i=l1; i<=h1; i++){
    for (j=l2; j<=h2; j++)
      printf("%d ",m[i][j]);
    printf("\n");
  }                   
}

void printoutcmatrix1 
(
 unsigned char **m,
 int l1,
 int h1,
 int l2,
 int h2
)
{
  int i,j;
  
  for (i=l1; i<=h1; i++){
    for (j=l2; j<=h2; j++)
      if ( m[i][j] ) printf("1") ; else printf(" ") ;
    printf("\n");
  }                   
}

void printoutivector
(
 int *m,
 int l1,
 int h1
)
{
  int i;
  
  for (i=l1; i<=h1; i++)
    printf( "%d " , m[i] );
  printf("\n");
}

void write_ivector
(
 FILE *fp,
 int *m,
 int l1,
 int h1
)
{
  int i;
  
  for (i=l1; i<=h1; i++)
    fprintf( fp , "%d " , m[i] );
  fprintf( fp , "\n");
}

void write_cvector
(
 FILE *fp ,
 unsigned char *m,
 int l1,
 int h1
)
{
  int i;
  
  for (i=l1; i<=h1; i++)
    fprintf( fp , "%d\n" , m[i] );
/*  fprintf( fp ,"\n"); */
}

void printoutcvector
(
 unsigned char *m,
 int l1,
 int h1
)
{
  int i;
  
  for (i=l1; i<=h1; i++)
    printf( "%d " , m[i] );
  printf("\n");
}

void printoutcvector1
(
 unsigned char *m,
 int l1,
 int h1
)
{
  int i;
  
  printf("|");
  for (i=l1; i<=h1; i++)
    if ( m[i] ) printf( "1" ) ; else printf( " " );
  printf("|\n");
}

void printoutdmatrix 
(
 double **m,
 int l1,
 int h1,
 int l2,
 int h2,
 int style
)
{
	int i,j;
	
	for (i=l1; i<=h1; i++){
		for (j=l2; j<=h2; j++)
        	 	pd(m[i][j],style);
          	printf("\n");
     	}                   
}

void printoutdmatrix3 
(
 double ***m,
 int l1,
 int h1,
 int l2,
 int h2,
 int l3,
 int h3,
 int style
)
{
  int i,j,k;
	
  for (i=l1; i<=h1; i++){
    for (j=l2; j<=h2; j++) {
      for (k=l3; k<=h3; k++)
	pd(m[i][j][k],style);
      printf("\n");
    }                   
    printf("\n");
  }                   
}

void pd
(
 double w,
 int p
) 	/* prints a single double with a specified number of digits */ 
{
	switch(p){
		case(0):		/* Don't print */
			break;
		case(-1):		/* Standard format */
			printf("%g ",w);
			break;
		case(1):
			printf("%1.0f ",w);
			break;
		case(100):
			printf("%1.0f ",w*10);
			break;
		case(11):
			if (w==1.0)printf("%1.0f ",w);
			else printf("  ");
			break;
		case(10): /* 0/1 <- -1/1 */
			printf("%1.0f ",(double)(w+1.0)*0.5);
			break;
		case(2):
			printf("%2.0f ",w);
			break;
		case(29):
			printf("%2f ",w);
			break;
		case(21):
			printf("%2.1f ",w);
			break;
		case(20):
			printf("%2.0f ",w);
			break;
		case(200):
			printf("%2.0f",w*100);
			break;
		case(3):
			printf("%3.1f ",w);
			break;
		case(39):
			printf("%3f ",w);
			break;
		case(30):
			printf("%3.0f ",w);
			break;
		case(300):
			printf("%3.0f ",w*1000);
			break;
		case(31):
			printf("%3.1f ",w);
			break;
		case(32):
			printf("%3.2f ",w);
			break;
		case(4):
			printf("%4.1f ",w);
			break;
		case(49):
			printf("%4f ",w);
			break;
		case(40):
			printf("%4.0f ",w);
			break;
		case(400):
			printf("%4.0f ",w*10000);
			break;
		case(41):
			printf("%4.1f ",w);
			break;
		case(43):
			printf("%4.3f ",w);
			break;
		case(42):
			printf("%4.2f ",w);
			break;
		case(52):
			printf("%5.2f ",w);
			break;
		case(53):
			printf("%5.3f ",w);
			break;
		case(54):
			printf("%5.4f ",w);
			break;
		case(50): 
			printf("%5.0f ",w);
			break;
		case(500): /* for probabilities */
			printf("%5.0f ",w*100000);
			break;
		case(60): 
			printf("%6.0f ",w);
			break;
		case(62):
			printf("%6.2f ",w);
			break;
		case(63):
			printf("%6.3f ",w);
			break;
		case(64):
			printf("%6.4f ",w);
			break;
		case(72):
			printf("%7.2f ",w);
			break;
		case(74):
			printf("%7.4g ",w);
			break;
		case(84):
			printf("%8.4g ",w);
			break;
		case(94):
			printf("%+9.4g ",w);
			break;
		case(76):
			printf("%7.6f ",w);
			break;
		case(5):
			printf("%5g ",w);
			break;
		case(6):
			printf("%6g ",w);
			break;
		case(600):
			printf("%6.0f ",w*1000000);
			break;
		case(7):
			printf("%7g ",w);
			break;
		case(700):
			printf("%7.0f ",w*10000000);
			break;
		default:
			printf("Error in pd rule \n");
			break;
	}
}

void pdv
(
 double *w, int m, int n, int p
 )	/* prints dvector without newline, with specified number of digits */
{
	int i;
	for(i=m;i<=n;i++)
		pd(w[i],p);
}
 

void 	pause_for_return()
{
	int c;

	printf( "press return to continue" );
	do{}while((c=getchar())!=10);
}

double gammln(
	      double xx
)
{
  double x,tmp,ser;
  static double cof[6]={76.18009173,-86.50532033,24.01409822,
                -1.231739516,0.120858003e-2,-0.536382e-5};
  int j;
  
  x=xx-1.0;
  tmp=x+5.5;
  tmp -= (x+0.5)*log(tmp);
  ser=1.0;
  for (j=0;j<=5;j++) {
    x += 1.0;
    ser += cof[j]/x;
  }
  return -tmp+log(2.50662827465*ser);
}

int find_rank ( double act , double *v , int lo , int hi ) {
  /* given an ordered list v[lo] < v[lo+1] < ... < v[hi], 
     and assuming that act > v[lo], the task is to return 
     the ranking of act, i.e. the integer place where it will push 
     in. For example, if we find act < v[lo+1], the answer is lo. 
     If act > v[hi], answer is hi. 
     Note no comparison with v[lo] should occur, we already know it's
     bigger. 
     */

  int query ;

  if ( lo > hi ) { 
    fprintf ( stderr , "Eek, lo > hi ???\n" ) ; 
    exit ( 0 ) ; 
  }
  if ( lo == hi ) { /* we are done */
    return ( lo ) ; 
  } 
  else { 
    query = lo + ( hi + 1 - lo ) / 2 ; 
    if ( query == lo ) { 
      fprintf ( stderr , "Eek, query == lo ???\n" ) ; 
      exit ( 0 ) ; 
    }
    else if ( act > v[query] ) { 
      return ( find_rank ( act , v , query , hi ) ) ;
    }
    else {
      return ( find_rank ( act , v , lo , query - 1 ) ) ;
    }
  }
} 

int dotprod_mod2 ( int *a , int *b , int lo , int hi ) {
  int i , ans = 0 ; 
  for ( i = lo ; i <= hi ; i ++ ) {
    ans ^= a[i] * b[i] ;
  }
  return ans ;
}
int idotprod ( int *a , int *b , int lo , int hi ) {
  int i , ans = 0 ; 
  for ( i = lo ; i <= hi ; i ++ ) {
    ans += a[i] * b[i] ;
  }
  return ans ;
}

unsigned char cdotprod_mod2 ( unsigned char *a , unsigned char *b , int lo , int hi ) {
  unsigned char ans = 0 ; 
  int i ; 
  for ( i = lo ; i <= hi ; i ++ ) {
    ans ^= a[i] & b[i] ;
  }
  return ans ;
}

void mult_cms 
( unsigned char **A , unsigned char **B , unsigned char **C , int l , int N ) {
  int i , j , k ; 
  unsigned char a ;

  for ( i = l ; i <= N ; i ++ ) {
    for ( k = l ; k <= N ; k ++ ) {
      a = 0 ; 
      for ( j = l ; j <= N ; j ++ ) {
	a ^= A[i][j] & B[j][k] ;
      }
      C[i][k] = a ;
    }
  }
}

void mult_cm_cv 
( unsigned char **A , unsigned char *b , unsigned char *c , int l , int N ) {
  int i , j ; 
  unsigned char a ;

  for ( i = l ; i <= N ; i ++ ) {
    a = 0 ; 
    for ( j = l ; j <= N ; j ++ ) {
      a ^= A[i][j] & b[j];
    }
    c[i] = a ;
  }
}

int cdotprod ( unsigned char *a , unsigned char *b , int lo , int hi ) {
  int i , ans = 0 ; 
  for ( i = lo ; i <= hi ; i ++ ) {
    ans += a[i] & b[i] ;
  }
  return ans ;
}

/* For useful routines for dealing with triangular char matrices and 
   with lists of matrices of the form
   U = 10
       11
   (just one off diagonal 1)
   see
   ~/code/old/mnc.c.940106
*/


#define MBIG 1000000000
#define MSEED 161803398
#define MZ 0
#define FAC (1.0/MBIG)

float ran3(
	   int *idum
)
{
	static int inext,inextp;
	static long ma[56];
	static int iff=0;
	long mj,mk;
	int i,ii,k;

	if (*idum < 0 || iff == 0) {
		iff=1;
		mj=MSEED-(*idum < 0 ? -*idum : *idum);
		mj %= MBIG;
		ma[55]=mj;
		mk=1;
		for (i=1;i<=54;i++) {
			ii=(21*i) % 55;
			ma[ii]=mk;
			mk=mj-mk;
			if (mk < MZ) mk += MBIG;
			mj=ma[ii];
		}
		for (k=1;k<=4;k++)
			for (i=1;i<=55;i++) {
				ma[i] -= ma[1+(i+30) % 55];
				if (ma[i] < MZ) ma[i] += MBIG;
			}
		inext=0;
		inextp=31;
		*idum=1;
	}
	if (++inext == 56) inext=1;
	if (++inextp == 56) inextp=1;
	mj=ma[inext]-ma[inextp];
	if (mj < MZ) mj += MBIG;
	ma[inext]=mj;
	return mj*FAC;
}

#undef MBIG
#undef MSEED
#undef MZ
#undef FAC
