/*****************************************************************************
   Major portions of this software are copyrighted by the Medical College
   of Wisconsin, 1994-2000, and are released under the Gnu General Public
   License, Version 2.  See the file README.Copyright for details.
******************************************************************************/
   
#include "mrilib.h"

/*--------------------------------------------------------------------------*/

int equal_bitvector_piece( MRI_IMAGE * b , MRI_IMAGE * c , int aa , int bb )
{
   int ii ; byte * bv=MRI_BYTE_PTR(b) , * cv=MRI_BYTE_PTR(c) ;

   if( aa <  0     ) aa = 0 ;
   if( bb >= b->nx ) bb = b->nx - 1 ;
   for( ii=aa ; ii <= bb ; ii++ ) if( bv[ii] != cv[ii] ) return 0 ;
   return 1;
}

int equal_bitvector( MRI_IMAGE * b , MRI_IMAGE * c )
{
   return equal_bitvector_piece( b , c , 0 , b->nx - 1 ) ;
}

/*--------------------------------------------------------------------------*/

void randomize_bitvector_piece( MRI_IMAGE * b , int aa , int bb )
{
   int ii ; byte * bv=MRI_BYTE_PTR(b) ;

   if( aa <  0     ) aa = 0 ;
   if( bb >= b->nx ) bb = b->nx - 1 ;
   for( ii=aa ; ii <= bb ; ii++ ) bv[ii] = ( drand48() > 0.5 ) ;
   return ;
}

void randomize_bitvector( MRI_IMAGE * b )
{
   randomize_bitvector_piece( b , 0 , b->nx - 1 ) ;
   return ;
}

/*--------------------------------------------------------------------------*/

void zero_bitvector_piece( MRI_IMAGE * b , int aa , int bb )
{
   int ii ; byte * bv=MRI_BYTE_PTR(b) ;

   if( aa <  0     ) aa = 0 ;
   if( bb >= b->nx ) bb = b->nx - 1 ;
   for( ii=aa ; ii <= bb ; ii++ ) bv[ii] = 0 ;
   return ;
}

void zero_bitvector( MRI_IMAGE * b )
{
   zero_bitvector_piece( b , 0 , b->nx - 1 ) ;
   return ;
}

/*--------------------------------------------------------------------------*/

void one_bitvector_piece( MRI_IMAGE * b , int aa , int bb )
{
   int ii ; byte * bv=MRI_BYTE_PTR(b) ;

   if( aa <  0     ) aa = 0 ;
   if( bb >= b->nx ) bb = b->nx - 1 ;
   for( ii=aa ; ii <= bb ; ii++ ) bv[ii] = 1 ;
   return ;
}

void one_bitvector( MRI_IMAGE * b )
{
   one_bitvector_piece( b , 0 , b->nx - 1 ) ;
   return ;
}

/*--------------------------------------------------------------------------*/

void invert_bitvector_piece( MRI_IMAGE * b , int aa , int bb )
{
   int ii ; byte * bv=MRI_BYTE_PTR(b) ;

   if( aa <  0     ) aa = 0 ;
   if( bb >= b->nx ) bb = b->nx - 1 ;
   for( ii=aa ; ii <= bb ; ii++ ) bv[ii] = 1 - bv[ii] ;
   return ;
}

void invert_bitvector( MRI_IMAGE * b )
{
   invert_bitvector_piece( b , 0 , b->nx - 1 ) ;
   return ;
}

/*--------------------------------------------------------------------------*/

MRI_IMAGE * new_bitvector( int n )
{
   MRI_IMAGE * b ;
   b = mri_new( n , 1 , MRI_byte ) ;
   return b ;
}

MRI_IMAGE * copy_bitvector( MRI_IMAGE * b )
{
   int ii ;
   MRI_IMAGE * c = mri_new( b->nx , 1 , MRI_byte ) ;
   memcpy( MRI_BYTE_PTR(c) , MRI_BYTE_PTR(b) , b->nx ) ;
   return c ;
}

/*--------------------------------------------------------------------------*/

int count_bitvector( MRI_IMAGE * b )
{
   int ii,ss , n=b->nx ;
   byte * bv = MRI_BYTE_PTR(b) ;
   for( ii=ss=0 ; ii < n ; ii++ ) if( bv[ii] ) ss++ ;
   return ss ;
}

/*--------------------------------------------------------------------------*/

void normalize_floatvector( MRI_IMAGE * fim )
{
   int ii , n=fim->nx ;
   float ff,gg , * far=MRI_FLOAT_PTR(fim) ;

   for( ff=0.0,ii=0 ; ii < n ; ii++ ) ff += far[ii] ;
   ff /= n ;
   for( gg=0.0,ii=0 ; ii < n ; ii++ ) gg += SQR( (far[ii]-ff) ) ;
   if( gg <= 0.0 ) return ;
   gg = 1.0 / sqrt(gg) ;
   for( ii=0 ; ii < n ; ii++ ) far[ii] = (far[ii]-ff)*gg ;
   return ;
}

/*--------------------------------------------------------------------------*/

float corr_floatbit( MRI_IMAGE * fim , MRI_IMAGE * bim )
{
   int ii , n=fim->nx , ns ;
   float * far=MRI_FLOAT_PTR(fim) , ss ;
   byte  * bar=MRI_BYTE_PTR(bim) ;

   for( ss=0.0,ns=ii=0 ; ii < n ; ii++ )
      if( bar[ii] ){ ns++ ; ss += far[ii] ; }

   if( ns == 0 || ns == n ) return 0.0 ;

   ss *= sqrt( ((float) n) / (float)(ns*(n-ns)) ) ;
   return ss ;
}

/*--------------------------------------------------------------------------*/

MRI_IMARR * init_bitvector_array( int nbv , MRI_IMAGE * fim )
{
   MRI_IMARR * imar ;
   MRI_IMAGE * bim ;
   int ii , n=fim->nx ;
   byte * bar ; float * far=MRI_FLOAT_PTR(fim) ;

   INIT_IMARR(imar) ;
   normalize_floatvector( fim ) ;

   for( ii=0 ; ii < nbv ; ii++ ){
      bim = new_bitvector( n ) ;
      randomize_bitvector( bim ) ;
      bim->dx = corr_floatbit( fim , bim ) ;
      if( bim->dx < 0.0 ){ bim->dx = -bim->dx; invert_bitvector( bim ); }
      ADDTO_IMARR(imar,bim) ;
   }

   return imar ;
}

/*--------------------------------------------------------------------------*/

#define IRAN(j) (lrand48() % (j))

void evolve_bitvector_array( MRI_IMARR * bvar , MRI_IMAGE * fim )
{
   static int    nrvec=-1 ;
   static float * rvec=NULL ;

   int ii,nn=fim->nx , nbv=IMARR_COUNT(bvar) , aa,bb , qbv ;
   MRI_IMAGE * bim , * qim ;

   /* create mutants */

   for( ii=0 ; ii < nbv ; ii++ ){

      bim = IMARR_SUBIMAGE(bvar,ii) ;

      aa = IRAN(nn) ; bb = aa + IRAN(5) ; if( bb >= nn ) bb = nn-1 ;

      qim = copy_bitvector(bim) ;
      zero_bitvector_piece( qim , aa , bb ) ;
      if( equal_bitvector_piece(bim,qim,aa,bb) ){
         mri_free(qim) ;
      } else {
         qim->dx = corr_floatbit( fim , qim ) ;
         if( qim->dx < 0.0 ){ qim->dx = -qim->dx; invert_bitvector( qim ); }
         ADDTO_IMARR(bvar,qim) ;
      }

      qim = copy_bitvector(bim) ;
      one_bitvector_piece( qim , aa , bb ) ;
      if( equal_bitvector_piece(bim,qim,aa,bb) ){
         mri_free(qim) ;
      } else {
         qim->dx = corr_floatbit( fim , qim ) ;
         if( qim->dx < 0.0 ){ qim->dx = -qim->dx; invert_bitvector( qim ); }
         ADDTO_IMARR(bvar,qim) ;
      }

      qim = copy_bitvector(bim) ;
      randomize_bitvector_piece( qim , aa , bb ) ;
      if( equal_bitvector_piece(bim,qim,aa,bb) ){
         mri_free(qim) ;
      } else {
         qim->dx = corr_floatbit( fim , qim ) ;
         if( qim->dx < 0.0 ){ qim->dx = -qim->dx; invert_bitvector( qim ); }
         ADDTO_IMARR(bvar,qim) ;
      }

      qim = copy_bitvector(bim) ;
      invert_bitvector_piece( qim , aa , bb ) ;
      if( equal_bitvector_piece(bim,qim,aa,bb) ){
         mri_free(qim) ;
      } else {
         qim->dx = corr_floatbit( fim , qim ) ;
         if( qim->dx < 0.0 ){ qim->dx = -qim->dx; invert_bitvector( qim ); }
         ADDTO_IMARR(bvar,qim) ;
      }
   }

   /* sort everybody */

   qbv = IMARR_COUNT(bvar) ;
   if( nrvec < qbv ){
      if( rvec != NULL ) free(rvec) ;
      rvec = (float *) malloc(sizeof(float)*qbv) ;
      nrvec = qbv ;
   }
   for( ii=0 ; ii < qbv ; ii++ ) rvec[ii] = -fabs(IMARR_SUBIM(bvar,ii)->dx) ;

   qsort_floatstuff( qbv , rvec , (void **) bvar->imarr ) ;

   TRUNCATE_IMARR( bvar , nbv ) ;
   return ;
}

/*--------------------------------------------------------------------------*/

int main( int argc , char * argv[] )
{
   MRI_IMAGE * fim , * bim ;
   MRI_IMARR * bvar ;
   int ii , nv , nite=0 , neq=0 ;
   float fold , fnew ;

   if( argc < 2 ){printf("Usage: bitvec fname.1D > bname.1D\n");exit(0);}

   fim = mri_read_1D( argv[1] ) ;
   if( fim == NULL ){fprintf(stderr,"Can't read %s\n",argv[1]);exit(1);}
   fprintf(stderr,"vector length = %d\n",fim->nx) ;

   srand48((long)time(NULL)) ;

   bvar = init_bitvector_array( 256 , fim ) ;
   fold = fabs(IMARR_SUBIM(bvar,0)->dx) ;
   fprintf(stderr,"fold = %7.4f\n",fold) ;

   while(1){
      evolve_bitvector_array( bvar , fim ) ;
      nv = IMARR_COUNT(bvar) ;
      nite++ ;
#if 0
      fprintf(stderr,"nite=%d\n",nite) ;
      for( ii=0 ; ii < nv ; ii++ )
         fprintf(stderr," %7.4f",IMARR_SUBIM(bvar,ii)->dx) ;
      fprintf(stderr,"\n\n") ;
#endif

      fnew = fabs(IMARR_SUBIM(bvar,0)->dx) ;
      if( fnew <= fold ){
         neq++ ; if( neq == 10 ) break ;
      } else {
         neq  = 0 ;
         fold = fnew ;
         fprintf(stderr,"%d: %7.4f\n",nite,fold) ;
      }
   }

   bim = IMARR_SUBIM(bvar,0) ;
   for( ii=0 ; ii < fim->nx ; ii++ )
      printf(" %d\n",(int)MRI_BYTE_PTR(bim)[ii]) ;

   exit(0) ;
}
