#include "mrilib.h"

#define MAX_NCODE 666

int main( int argc , char *argv[] )
{
   THD_3dim_dataset *inset=NULL , *jnset=NULL , *outset , *wset=NULL;
   int ncode=0 , code[MAX_NCODE] , iarg=1 , ii ;
   MCW_cluster *nbhd=NULL ;
   byte *mask=NULL ; int mask_nx=0,mask_ny=0,mask_nz=0 , automask=0 ;
   char *prefix="./localstat" ;
   int ntype=0 ; float na=0.0f,nb=0.0f,nc=0.0f ;
   double hist_pow=0.3333333 ; int hist_nbin=0 ;
   float hbot1=1.0f , htop1=-1.0f ; int hbot1_perc=0, htop1_perc=0 ;
   float hbot2=1.0f , htop2=-1.0f ; int hbot2_perc=0, htop2_perc=0 ;

   /*---- for the clueless who wish to become clued-in ----*/

   if( argc < 2 || strcmp(argv[1],"-help") == 0 ){
     printf(
      "Usage: 3dLocalBistat [options] dataset1 dataset2\n"
      "\n"
      "This program computes statistics between 2 datasets,\n"
      "at each voxel, based on a local neighborhood of that voxel.\n"
      " - The neighborhood is defined by the '-nbhd' option.\n"
      " - Statistics to be calculated are defined by the '-stat' option(s).\n"
      " - The 2 input datasets should have the same number of sub-bricks.\n"
      " - OR dataset1 should have 1 sub-brick and dataset2 can have more than 1:\n"
      "   - In which case, the statistics of dataset2 against dataset1 are\n"
      "     calculated for the #0 sub-brick of dataset1 against each sub-brick\n"
      "     of dataset2.\n"
      "\n"
      "OPTIONS\n"
      "-------\n"
      " -nbhd 'nnn' = The string 'nnn' defines the region around each\n"
      "               voxel that will be extracted for the statistics\n"
      "               calculation.  The format of the 'nnn' string are:\n"
      "               * 'SPHERE(r)' where 'r' is the radius in mm;\n"
      "                 the neighborhood is all voxels whose center-to-\n"
      "                 center distance is less than or equal to 'r'.\n"
      "                 ** A negative value for 'r' means that the region\n"
      "                    is calculated using voxel indexes rather than\n"
      "                    voxel dimensions; that is, the neighborhood\n"
      "                    region is a \"sphere\" in voxel indexes of\n"
      "                    \"radius\" abs(r).\n"
      "               * 'RECT(a,b,c)' is a rectangular block which\n"
      "                 proceeds plus-or-minus 'a' mm in the x-direction,\n"
      "                 'b' mm in the y-direction, and 'c' mm in the\n"
      "                 z-direction.  The correspondence between the\n"
      "                 dataset xyz axes and the actual spatial orientation\n"
      "                 can be determined by using program 3dinfo.\n"
      "                 ** A negative value for 'a' means that the region\n"
      "                    extends plus-and-minus abs(a) voxels in the\n"
      "                    x-direction, rather than plus-and-minus a mm.\n"
      "                    Mutatis mutandum for negative 'b' and/or 'c'.\n"
      "               * 'RHDD(r)' is a rhombic dodecahedron of 'radius' r.\n"
      "               * 'TOHD(r)' is a truncated octahedron of 'radius' r.\n"
      "\n"
      " -stat sss   = Compute the statistic named 'sss' on the values\n"
      "               extracted from the region around each voxel:\n"
      "               * pearson  = Pearson correlation coefficient\n"
      "               * spearman = Spearman correlation coefficient\n"
      "               * quadrant = Quadrant correlation coefficient\n"
      "               * mutinfo  = Mutual Information\n"
      "               * normuti  = Normalized Mutual Information\n"
      "               * jointent = Joint entropy\n"
      "               * hellinger= Hellinger metric\n"
      "               * crU      = Correlation ratio (Unsymmetric)\n"
      "               * crM      = Correlation ratio (symmetrized by Multiplication)\n"
      "               * crA      = Correlation ratio (symmetrized by Addition)\n"
      "               * L2slope  = slope of least-squares (L2) linear regression of\n"
      "                            the data from dataset1 vs. the dataset2\n"
      "                            (i.e., d2 = a + b*d1 ==> this is 'b')\n"
      "               * L1slope  = slope of least-absolute-sum (L1) linear regression\n"
      "                            of the data from dataset1 vs. the dataset2\n"
      "               * num      = number of the values in the region:\n"
      "                            with the use of -mask or -automask,\n"
      "                            the size of the region around any given\n"
      "                            voxel will vary; this option lets you\n"
      "                            map that size.\n"
#if 0
      "               * ncd      = Normalized Compression Distance (zlib; very slow)\n"
#endif
#if 0 /* activate after testing */
      "               * euclidean = Euclidean distance.\n"
      "               * cityblock = City Block distance.\n"
#endif
      "               * ALL      = all of the above, in that order\n"
      "               More than one '-stat' option can be used.\n"
      "\n"
      " -mask mset  = Read in dataset 'mset' and use the nonzero voxels\n"
      "               therein as a mask.  Voxels NOT in the mask will\n"
      "               not be used in the neighborhood of any voxel. Also,\n"
      "               a voxel NOT in the mask will have its statistic(s)\n"
      "               computed as zero (0).\n"
      " -automask   = Compute the mask as in program 3dAutomask.\n"
      "               -mask and -automask are mutually exclusive: that is,\n"
      "               you can only specify one mask.\n"
      " -weight ws  = Use dataset 'ws' as a weight.  Only applies to 'pearson'.\n"
      "\n"
      " -prefix ppp = Use string 'ppp' as the prefix for the output dataset.\n"
      "               The output dataset is always stored as floats.\n"
      "\n"
      "ADVANCED OPTIONS\n"
      "----------------\n"
      " -histpow pp   = By default, the number of bins in the histogram used\n"
      "                 for calculating the Hellinger, Mutual Information,\n"
      "                 and Correlation Ratio statistics is n^(1/3), where n\n"
      "                 is the number of data points in the -nbhd mask.  You\n"
      "                 can change that exponent to 'pp' with this option.\n"
      " -histbin nn   = Or you can just set the number of bins directly to 'nn'.\n"
      " -hclip1 a b   = Clip dataset1 to lie between values 'a' and 'b'.  If 'a'\n"
      "                 and 'b' end in '%%', then these values are percentage\n"
      "                 points on the cumulative histogram.\n"
      " -hclip2 a b   = Similar to '-hclip1' for dataset2.\n"
      "\n"
      "-----------------------------\n"
      "Author: RWCox - October 2006.\n"
     ) ;
     PRINT_COMPILE_DATE ; exit(0) ;
   }

   /*---- official startup ---*/

   PRINT_VERSION("3dLocalBistat"); mainENTRY("3dLocalBistat main"); machdep();
   AFNI_logger("3dLocalBistat",argc,argv) ;

   /*---- loop over options ----*/

   while( iarg < argc && argv[iarg][0] == '-' ){

     if( strcmp(argv[iarg],"-hclip1") == 0 ){
       char *cpt1, *cpt2 ;
       if( ++iarg >= argc-1 ) ERROR_exit("need 2 arguments after -hclip1") ;
       hbot1 = (float)strtod(argv[iarg],&cpt1) ; iarg++ ;
       htop1 = (float)strtod(argv[iarg],&cpt2) ;
       if( hbot1 >= htop1 ) ERROR_exit("illegal values after -hclip1") ;
       if( *cpt1 == '%' ){
         hbot1_perc = 1 ; hbot1 = (int)rint((double)hbot1) ;
         if( hbot1 < 0 || hbot1 > 99 ) ERROR_exit("illegal bot percentage after -hclip1") ;
       }
       if( *cpt2 == '%' ){
         htop1_perc = 1 ; htop1 = (int)rint((double)htop1) ;
         if( htop1 < 1 || htop1 > 100 ) ERROR_exit("illegal top percentage after -hclip1") ;
       }
       iarg++ ; continue ;
     }

     if( strcmp(argv[iarg],"-hclip2") == 0 ){
       char *cpt1, *cpt2 ;
       if( ++iarg >= argc-1 ) ERROR_exit("need 2 arguments after -hclip2") ;
       hbot2 = (float)strtod(argv[iarg],&cpt1) ; iarg++ ;
       htop2 = (float)strtod(argv[iarg],&cpt2) ;
       if( hbot2 >= htop2 ) ERROR_exit("illegal values after -hclip2") ;
       if( *cpt1 == '%' ){
         hbot2_perc = 1 ; hbot2 = (int)rint((double)hbot2) ;
         if( hbot2 < 0 || hbot2 > 99 ) ERROR_exit("illegal bot percentage after -hclip2") ;
       }
       if( *cpt2 == '%' ){
         htop2_perc = 1 ; htop2 = (int)rint((double)htop2) ;
         if( htop2 < 1 || htop2 > 100 ) ERROR_exit("illegal top percentage after -hclip2") ;
       }
       iarg++ ; continue ;
     }

     if( strcmp(argv[iarg],"-histpow") == 0 ){
       if( ++iarg >= argc ) ERROR_exit("no argument after '%s'!",argv[iarg-1]) ;
       hist_pow = strtod(argv[iarg],NULL) ;
       if( hist_pow <= 0.0 || hist_pow > 0.5 ){
         WARNING_message("Illegal value after -histpow"); hist_pow = 0.33333;
       }
       iarg++ ; continue ;
     }

     if( strcmp(argv[iarg],"-histbin") == 0 ){
       if( ++iarg >= argc ) ERROR_exit("no argument after '%s'!",argv[iarg-1]) ;
       hist_nbin = (int)strtod(argv[iarg],NULL) ;
       if( hist_nbin <= 1 ) WARNING_message("Illegal value after -histbin");
       iarg++ ; continue ;
     }

     if( strcmp(argv[iarg],"-prefix") == 0 ){
       if( ++iarg >= argc ) ERROR_exit("Need argument after '-prefix'") ;
       prefix = strdup(argv[iarg]) ;
       if( !THD_filename_ok(prefix) ) ERROR_exit("Bad name after '-prefix'") ;
       iarg++ ; continue ;
     }

     if( strcmp(argv[iarg],"-mask") == 0 ){
       THD_3dim_dataset *mset ; int mmm ;
       if( ++iarg >= argc ) ERROR_exit("Need argument after '-mask'") ;
       if( mask != NULL || automask ) ERROR_exit("Can't have two mask inputs") ;
       mset = THD_open_dataset( argv[iarg] ) ;
       CHECK_OPEN_ERROR(mset,argv[iarg]) ;
       DSET_load(mset) ; CHECK_LOAD_ERROR(mset) ;
       mask_nx = DSET_NX(mset); mask_ny = DSET_NY(mset); mask_nz = DSET_NZ(mset);
       mask = THD_makemask( mset , 0 , 0.5f, 0.0f ) ; DSET_delete(mset) ;
       if( mask == NULL ) ERROR_exit("Can't make mask from dataset '%s'",argv[iarg]) ;
       mmm = THD_countmask( mask_nx*mask_ny*mask_nz , mask ) ;
       INFO_message("Number of voxels in mask = %d",mmm) ;
       if( mmm < 2 ) ERROR_exit("Mask is too small to process") ;
       iarg++ ; continue ;
     }

     if( strcmp(argv[iarg],"-weight") == 0 ){  /* 14 Aug 2007 */
       if( ++iarg >= argc ) ERROR_exit("Need argument after '-weight'") ;
       if( wset != NULL ) ERROR_exit("Can't have two weight inputs") ;
       wset = THD_open_dataset( argv[iarg] ) ;
       CHECK_OPEN_ERROR(wset,argv[iarg]) ;
       DSET_load(wset) ; CHECK_LOAD_ERROR(wset) ;
       iarg++ ; continue ;
     }

     if( strcmp(argv[iarg],"-automask") == 0 ){
       if( mask != NULL ) ERROR_exit("Can't have -automask and -mask") ;
       automask = 1 ;
       iarg++ ; continue ;
     }

     if( strcmp(argv[iarg],"-stat") == 0 ){
       char *cpt ;
       if( ++iarg >= argc ) ERROR_exit("Need argument after '-stat'") ;
       cpt = argv[iarg] ; if( *cpt == '-' ) cpt++ ;
            if( strcasecmp(cpt,"pearson")  == 0 ) code[ncode++] = NBISTAT_PEARSON_CORR ;
       else if( strcasecmp(cpt,"spearman") == 0 ) code[ncode++] = NBISTAT_SPEARMAN_CORR;
       else if( strcasecmp(cpt,"quadrant") == 0 ) code[ncode++] = NBISTAT_QUADRANT_CORR;
       else if( strcasecmp(cpt,"mutinfo")  == 0 ) code[ncode++] = NBISTAT_MUTUAL_INFO  ;
       else if( strcasecmp(cpt,"normuti")  == 0 ) code[ncode++] = NBISTAT_NORMUT_INFO  ;
       else if( strcasecmp(cpt,"jointent") == 0 ) code[ncode++] = NBISTAT_JOINT_ENTROPY;
       else if( strcasecmp(cpt,"hellinger")== 0 ) code[ncode++] = NBISTAT_HELLINGER    ;
       else if( strcasecmp(cpt,"crU")      == 0 ) code[ncode++] = NBISTAT_CORR_RATIO_U ;
       else if( strcasecmp(cpt,"crM")      == 0 ) code[ncode++] = NBISTAT_CORR_RATIO_M ;
       else if( strcasecmp(cpt,"crA")      == 0 ) code[ncode++] = NBISTAT_CORR_RATIO_A ;
       else if( strcasecmp(cpt,"L2slope")  == 0 ) code[ncode++] = NBISTAT_L2SLOPE      ;
       else if( strcasecmp(cpt,"L1slope")  == 0 ) code[ncode++] = NBISTAT_L1SLOPE      ;
       else if( strcasecmp(cpt,"num")      == 0 ) code[ncode++] = NBISTAT_NUM          ;
#if 0
       else if( strcasecmp(cpt,"ncd")      == 0 ) code[ncode++] = NBISTAT_NCD          ;
#endif
#if 0 /* activate after testing */
       else if( strcasecmp(cpt,"euclidean")  == 0 )
                              code[ncode++] = NBISTAT_EUCLIDIAN_DIST      ;
       else if( strcasecmp(cpt,"cityblock")  == 0 )
                              code[ncode++] = NBISTAT_CITYBLOCK_DIST      ;
#endif
       else if( strcasecmp(cpt,"ALL")      == 0 ){
          code[ncode++] = NBISTAT_PEARSON_CORR ; code[ncode++] = NBISTAT_SPEARMAN_CORR;
          code[ncode++] = NBISTAT_QUADRANT_CORR; code[ncode++] = NBISTAT_MUTUAL_INFO  ;
          code[ncode++] = NBISTAT_NORMUT_INFO  ; code[ncode++] = NBISTAT_JOINT_ENTROPY;
          code[ncode++] = NBISTAT_HELLINGER    ; code[ncode++] = NBISTAT_CORR_RATIO_U ;
          code[ncode++] = NBISTAT_CORR_RATIO_M ; code[ncode++] = NBISTAT_CORR_RATIO_A ;
          code[ncode++] = NBISTAT_L2SLOPE      ; code[ncode++] = NBISTAT_L1SLOPE      ;
          code[ncode++] = NBISTAT_NUM          ;
#if 0
          code[ncode++] = NBISTAT_NCD          ;
#endif
#if 0 /* activate after testing */
         code[ncode++] = NBISTAT_EUCLIDIAN_DIST;
         code[ncode++] = NBISTAT_CITYBLOCK_DIST;
#endif
       }
       else
         ERROR_exit("-stat '%s' is an unknown statistic type",argv[iarg]) ;

       iarg++ ; continue ;
     }

     if( strcmp(argv[iarg],"-nbhd") == 0 ){
       char *cpt ;
       if( ntype  >  0    ) ERROR_exit("Can't have 2 '-nbhd' options") ;
       if( ++iarg >= argc ) ERROR_exit("Need argument after '-nbhd'") ;

       cpt = argv[iarg] ;
       if( strncasecmp(cpt,"SPHERE",6) == 0 ){
         sscanf( cpt+7 , "%f" , &na ) ;
         if( na == 0.0f ) ERROR_exit("Can't have a SPHERE of radius 0") ;
         ntype = NTYPE_SPHERE ;
       } else if( strncasecmp(cpt,"RHDD",4) == 0 ){
         sscanf( cpt+5 , "%f" , &na ) ;
         if( na == 0.0f ) ERROR_exit("Can't have a RHDD of radius 0") ;
         ntype = NTYPE_RHDD ;
       } else if( strncasecmp(cpt,"TOHD",4) == 0 ){
         sscanf( cpt+5 , "%f" , &na ) ;
         if( na == 0.0f ) ERROR_exit("Can't have a TOHD of radius 0") ;
         ntype = NTYPE_TOHD ;
       } else if( strncasecmp(cpt,"RECT",4) == 0 ){
         sscanf( cpt+5 , "%f,%f,%f" , &na,&nb,&nc ) ;
         if( na == 0.0f && nb == 0.0f && nc == 0.0f )
           ERROR_exit("'RECT(0,0,0)' is not a legal neighborhood") ;
         ntype = NTYPE_RECT ;
       } else {
           ERROR_exit("Unknown -nbhd shape: '%s'",cpt) ;
       }
       iarg++ ; continue ;
     }

     ERROR_exit("Unknown option '%s'",argv[iarg]) ;

   } /*--- end of loop over options ---*/

   /*---- check for stupid user inputs ----*/

   if( ncode <= 0 ) ERROR_exit("No '-stat' options given?") ;
   if( ntype <= 0 ) ERROR_exit("No '-nbhd' option given?!") ;

   /*---- deal with input datasets ----*/

   if( iarg > argc-1 ) ERROR_exit("No first input dataset on command line?") ;
   inset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(inset,argv[iarg]) ;
   iarg++ ;
   if( iarg > argc-1 ) ERROR_exit("No second input dataset on command line?") ;
   jnset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(jnset,argv[iarg]) ;
   if( jnset == NULL  ) ERROR_exit("Can't open dataset '%s'",argv[iarg]) ;
   if( DSET_NVOX(jnset)  != DSET_NVOX(inset) )
     ERROR_exit("Input datasets have different numbers of voxels!?");

   if( DSET_NVALS(jnset) != DSET_NVALS(inset)  ){
     if( DSET_NVALS(inset) > 1 ){
       ERROR_exit("Input datasets have different numbers of sub-bricks!?");
     } else {
       INFO_message("first input dataset has 1 sub-brick, second has %d",DSET_NVALS(jnset)) ;
     }
   }

   DSET_load(inset) ; CHECK_LOAD_ERROR(inset) ;
   DSET_load(jnset) ; CHECK_LOAD_ERROR(jnset) ;

   if( mask != NULL ){
     if( mask_nx != DSET_NX(inset) ||
         mask_ny != DSET_NY(inset) ||
         mask_nz != DSET_NZ(inset)   )
       ERROR_exit("-mask dataset grid doesn't match input dataset") ;

   } else if( automask ){
     int mmm , nvox ; byte *jask ;
     mask = THD_automask( inset ) ;
     if( mask == NULL )
       ERROR_message("Can't create -automask from input dataset #1?") ;
     jask = THD_automask( jnset ) ;
     if( jask == NULL )
       ERROR_message("Can't create -automask from input dataset #2?") ;
     nvox = DSET_NVOX(inset) ;
     for( ii=0 ; ii < nvox ; ii++ ) mask[ii] = (mask[ii] || jask[ii]) ;
     free(jask) ;
     mmm = THD_countmask( nvox , mask ) ;
     INFO_message("Number of voxels in dual automask = %d",mmm) ;
     if( mmm < 11 ) ERROR_exit("Automask is too small to process") ;
   }

   if( wset != NULL ){ /* 14 Aug 2007 */
     MRI_IMAGE *wim ; float *war ;
     if( DSET_NVOX(wset) != DSET_NVOX(inset) )
       ERROR_exit("-weight dataset mismatch with input datasets!") ;
     wim = mri_scale_to_float( DSET_BRICK_FACTOR(wset,0), DSET_BRICK(wset,0) );
     war = MRI_FLOAT_PTR(wim) ;
     DSET_delete(wset) ;
     if( mask != NULL ){
       int nvox = DSET_NVOX(inset) ;
       for( ii=0 ; ii < nvox ; ii++ ) if( !mask[ii] ) war[ii] = 0.0f ;
     }
     mri_bistat_setweight( wim ) ; mri_free(wim) ;
   }

   /*---- create neighborhood -----*/

   switch( ntype ){
     default:
       ERROR_exit("WTF?  ntype=%d",ntype) ;

     case NTYPE_SPHERE:{
       float dx , dy , dz ;
       if( na < 0.0f ){ dx = dy = dz = 1.0f ; na = -na ; }
       else           { dx = fabsf(DSET_DX(inset)) ;
                        dy = fabsf(DSET_DY(inset)) ;
                        dz = fabsf(DSET_DZ(inset)) ; }
       nbhd = MCW_spheremask( dx,dy,dz , na ) ;
     }
     break ;

     case NTYPE_RHDD:{
       float dx , dy , dz ;
       if( na < 0.0f ){ dx = dy = dz = 1.0f ; na = -na ; }
       else           { dx = fabsf(DSET_DX(inset)) ;
                        dy = fabsf(DSET_DY(inset)) ;
                        dz = fabsf(DSET_DZ(inset)) ; }
       nbhd = MCW_rhddmask( dx,dy,dz , na ) ;
     }
     break ;

     case NTYPE_TOHD:{
       float dx , dy , dz ;
       if( na < 0.0f ){ dx = dy = dz = 1.0f ; na = -na ; }
       else           { dx = fabsf(DSET_DX(inset)) ;
                        dy = fabsf(DSET_DY(inset)) ;
                        dz = fabsf(DSET_DZ(inset)) ; }
       nbhd = MCW_tohdmask( dx,dy,dz , na ) ;
     }
     break ;

     case NTYPE_RECT:{
       float dx , dy , dz ;
       if( na < 0.0f ){ dx = 1.0f; na = -na; } else dx = fabsf(DSET_DX(inset));
       if( nb < 0.0f ){ dy = 1.0f; nb = -nb; } else dy = fabsf(DSET_DY(inset));
       if( nc < 0.0f ){ dz = 1.0f; nc = -nc; } else dz = fabsf(DSET_DZ(inset));
       nbhd = MCW_rectmask( dx,dy,dz , na,nb,nc ) ;
     }
     break ;
   }

   INFO_message("Neighborhood comprises %d voxels",nbhd->num_pt) ;

   if( hist_nbin <= 1 ) hist_nbin = (int)pow((double)nbhd->num_pt,hist_pow) ;
   if( hist_nbin <= 1 ) hist_nbin = 2 ;
   INFO_message("2D histogram size = %d",hist_nbin) ;
   set_2Dhist_hbin( hist_nbin ) ;

   if( hbot1_perc || htop1_perc ){
     MRI_IMAGE *fim ; float perc[101] ;
     fim = THD_median_brick(inset) ;
     mri_percents(fim,100,perc) ; mri_free(fim) ;
     if( hbot1_perc ) hbot1 = perc[(int)hbot1] ;
     if( htop1_perc ) htop1 = perc[(int)htop1] ;
     INFO_message("Clipping dataset '%s' between %g and %g" ,
                  DSET_BRIKNAME(inset),hbot1,htop1 ) ;
   }
   if( hbot2_perc || htop2_perc ){
     MRI_IMAGE *fim ; float perc[101] ;
     fim = THD_median_brick(jnset) ;
     mri_percents(fim,100,perc) ; mri_free(fim) ;
     if( hbot2_perc ) hbot2 = perc[(int)hbot2] ;
     if( htop2_perc ) htop2 = perc[(int)htop2] ;
     INFO_message("Clipping dataset '%s' between %g and %g" ,
                  DSET_BRIKNAME(jnset),hbot2,htop2 ) ;
   }
   mri_nbistat_setclip( hbot1,htop1 , hbot2,htop2 ) ;

   /*---- actually do some work for a change ----*/

   THD_localbistat_verb(1) ;
   outset = THD_localbistat( inset,jnset , mask , nbhd , ncode , code ) ;

   DSET_unload(inset) ; DSET_unload(jnset) ;

   if( outset == NULL ) ERROR_exit("Function THD_localbistat() fails?!") ;

   EDIT_dset_items( outset , ADN_prefix,prefix , ADN_none ) ;

   tross_Copy_History( inset , outset ) ;
   tross_Make_History( "3dLocalBistat" , argc,argv , outset ) ;

#if 1
   { char *lcode[66] , lll[66] ;
     lcode[0] = "Rank cor" ;
     lcode[1] = "Quad cor" ;
     lcode[2] = "Pear cor" ;
     lcode[3] = "MI" ;
     lcode[4] = "NMI" ;
     lcode[5] = "Jnt Entropy" ;
     lcode[6] = "Hlngr metric" ;
     lcode[7] = "CorRat Sym*" ;
     lcode[8] = "CorRat Sym+" ;
     lcode[9] = "CorRatUnsym" ;
     lcode[10]= "Number" ;
     lcode[11]= "NCD" ;
     lcode[12]= "Euclidean Dist";
     lcode[13]= "CityBlock Dist";
     if( DSET_NVALS(inset) == 1 ){
       for( ii=0 ; ii < DSET_NVALS(outset) ; ii++ )
         EDIT_dset_items( outset ,
                            ADN_brick_label_one+ii, lcode[code[ii%ncode]-NBISTAT_BASE],
                          ADN_none ) ;
     } else {
       for( ii=0 ; ii < DSET_NVALS(outset) ; ii++ ){
         sprintf(lll,"%s[%d]",lcode[code[ii%ncode]-NBISTAT_BASE],(ii/ncode)) ;
         EDIT_dset_items( outset , ADN_brick_label_one+ii,lll, ADN_none ) ;
       }
     }
   }
#endif

   DSET_write( outset ) ;
   WROTE_DSET( outset ) ;
   exit(0) ;
}
