/*
 *	File: mcprofile.c
 *
 *      (C) IWTS
 *          KU Nijmegen
 *          The Netherlands
 *
 *      Author: R. Harald Baayen
 *
 *      History:
 *
 *      - feb 1997, version 1.0
 *
 *      Description:
 *
 *	mcprofile   -kK -pP -cC text.zvec
 *
 *	    -kK: K chunks                 (default: 20)
 *	    -pP: P permutations           (default: 0)
 *	    -cC: C\% confidence interval  (default 95)
 *
 *	    text.zvec:  text, one word per line, with Zipf rank
 *	                text.zvec can be made with "zvec text.wflist text.vec"
 *
 *	    output in 4 tables, K rows, 19 colums (measures)
 *	        text.mcm:  Monte Carlo mean
 *	        text.mcl:  Lower confidence interval
 *	        text.mch:  Upper confidence interval
 *	        text.obs:  Observed values
 *
 *	   EXAMPLE:
 *	        mcprofile -p5000 alice.zvec
 *
 *	   CURRENT CONSTRAINTS:
 *	        maximum word length:                   50
 *	        maximum number of input lines:     220000
 *	        maximum number of types:            20000
 *	        maximum number of permutation runs:  5000
 *	        maximum number of text chunks:         40
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "lex_cons.h"


/* EXTERN FUNCTIONS */

/* functions for numerical procedures */

extern double	getD2 ();
extern double	getE2 ();
extern double	getK2 ();
extern double	getZ ();
extern double	getlogMean2 ();
extern double	getlogStdDev2 ();
extern void	lognormal2 ();

extern double	fz ();
extern double	delta ();

extern void	constants ();
extern void	permute ();
extern void	randomize ();
extern double	uniformRandom ();
extern void	qcksrt ();

extern void	tabulate ();
extern void	tabulate2 ();
extern void	print_tabel ();
extern void	spectrum ();
extern void	SichelParam ();

/* argument reading, file manipulation, and help function */

extern int	leesgetal ();
extern void	change_extension ();
extern void	help ();


/* GLOBAL VARIABLES */

double

    /* GLOBAL VARIABLES FOR PARAMETERS OF SICHEL'S MODEL */

       cur_c, cur_b, cur_a1,   

    /* PARAMETERS OF SICHEL'S MODEL, ESTIMATED FROM THE SAMPLE */

       smean, sstdev,
       PVM[MAXTYPES2],

    /* DATA STRUCTURES FOR THE CONSTANTS FOR EACH CHUNK AND PERMUTATION RUN */

       K_CONST[MAXPERM][MAXCHUNKS2],
       D_CONST[MAXPERM][MAXCHUNKS2],
       V_CONST[MAXPERM][MAXCHUNKS2],
       V1_CONST[MAXPERM][MAXCHUNKS2],
       V2_CONST[MAXPERM][MAXCHUNKS2],
       V3_CONST[MAXPERM][MAXCHUNKS2],
       V4_CONST[MAXPERM][MAXCHUNKS2],
       V5_CONST[MAXPERM][MAXCHUNKS2],
       R_CONST[MAXPERM][MAXCHUNKS2],
       W_CONST[MAXPERM][MAXCHUNKS2],
       S_CONST[MAXPERM][MAXCHUNKS2],
       H_CONST[MAXPERM][MAXCHUNKS2],
       C_CONST[MAXPERM][MAXCHUNKS2],
       E_CONST[MAXPERM][MAXCHUNKS2],
       logM_CONST[MAXPERM][MAXCHUNKS2],
       logSt_CONST[MAXPERM][MAXCHUNKS2],
       Sb_CONST[MAXPERM][MAXCHUNKS2],
       Sc_CONST[MAXPERM][MAXCHUNKS2],
       Sa1_CONST[MAXPERM][MAXCHUNKS2],
       Z_CONST[MAXPERM][MAXCHUNKS2],
       A_FREQ[MAXPERM][MAXCHUNKS2],
       THE_FREQ[MAXPERM][MAXCHUNKS2],
       SMEAN_CONST[MAXPERM][MAXCHUNKS2],
       SSTDEV_CONST[MAXPERM][MAXCHUNKS2],
       LABHUB_CONST[MAXPERM][MAXCHUNKS2],

    /* DATA STRUCTURES FOR MEANS, CONFIDENCE INTERVALS, OBSERVED VALUES */

       tabel_means[MAXCHUNKS2+1][NMEASURES+1],
       tabel_orig[MAXCHUNKS2+1][NMEASURES+1],
       tabel_cilow[MAXCHUNKS2+1][NMEASURES+1],
       tabel_cihigh[MAXCHUNKS2+1][NMEASURES+1];

FILE   *fdata,                    /* input file: Word z */
       *fmeans,                   /* Monte Carlo means */
       *flow,                     /* lower c.int */
       *fhigh,                    /* upper c.int */
       *forig;                    /* original values */

int

    /* BASIC DATA STRUCTURES */

       TEXT[MAXTOKENS2],          /* TEXT[line]: zipf rank of word at line */
       CHUNKS[MAXCHUNKS2],        /* the K chunksizes */
       WORDFREQ[MAXTYPES2],       /* frequency of types */
       TYPENLIJST[MAXTYPES2],     /* list of types */
       VM[MAXTYPES2],             /* frequency spectrum: V(m) */
       MLIJST[MAXTYPES2],         /* list of frequency ranks m */

    /* SOME COUNTERS */

       i, j, k, l, aantal,        /* counters */

    /* CHUNKS */

       chunk,                     /* variables for determining the chunks */
       nchunks, 
       chunksize, 
       remainDer, 

    /* LEXICAL PARAMETERS */

       V, N,                      /* types, tokens */
       curN, curV,                /* types, tokens up to current chunk size */
       curV1, curV2,              /* hapaxes, disleg. up to current chunk */
       curV3, curV4, curV5,
       mMax, gmMax,               /* maximal (current) frequency rank */
       f_a, f_the,                /* zipf rank specifications for 2 words */
       freq_a, freq_the,          /* current frequencies of these words */
       maantal,                   /* number of frequency ranks */
       nwords,                    /* number of words in text = N */
       typenaantal,               /* number of types up to current chunk */
       getal,                     /* used for reading zipf ranks with scanf */
       header,                    /* boolean for presence of header */
       p,                         /* counter for permutations in permute() */

    /* RANDOMIZATION */

       nperm,                     /* number of permutations */
       ci,                        /* confidence interval */

    /* ZIPF, SICHEL */

       zipfzeros, sichelzeros,    /* counts for fitless runs */
       useGlobalMmax;             /* boolean on use of fmax for Zipf */

char   woord[MAXWORDLENGTH],      /* variable for a word */
       new_name[MAXWORDLENGTH],   /* variables for extension handling */
       base_name[MAXWORDLENGTH],
       *fs;                       /* char for scanning command line */


/* MAIN () */

int main (argc, argv)
int	argc;
char	*argv[];

{
   /* DEFAULT SETTINGS */

   nchunks = DEF_CHUNKS;          /* default number of chunks */
   nperm = 0;                     /* default effecive permuation runs: 1 */
   ci = 95;                       /* 95% confidence interval */
   f_the = 1;                     /* monitor word with Zipf rank 1 (the) */
   f_a = 4;                       /* monitor word with Zipf rank 4 (a) */
   useGlobalMmax = 0;             /* do not recalculate pstar for each run */
   zipfzeros = 0;                 /* count of missing fits Zipf */
   sichelzeros = 0;               /* count of missing fits Sichel */
   header = 1;                    /* text.zvec has header "Word z" */

   /* READ COMMAND LINE OPTIONS */

   while ((--argc > 0) && ((*++argv)[0] == '-')) {
        for (fs = argv[0] + 1; *fs != '\0'; fs++) {
            switch (*fs) {
            case 'h':  /* help */
                help();
                break;
            case 'p':  /* number of permutation runs */
                nperm = leesgetal (fs, &aantal);
                for (; aantal > 0; aantal--){
                   fs++;
                }
                break;
            case 'c':  /* confidence interval */
                ci = leesgetal (fs, &aantal);
                for (; aantal > 0; aantal--){
                   fs++;
                }
                break;
            case 'k':  /* number of chunks */
                nchunks = leesgetal (fs, &aantal);
                for (; aantal > 0; aantal--){
                   fs++;
                }
                break;
            case 'z':  
                useGlobalMmax = 1;  /* do NOT recalculte pstar for each run */
                break;
            case 't':
                f_the = leesgetal (fs, &aantal);
                for (; aantal > 0; aantal--){
                   fs++;
                }
                break;
            case 'a':
                f_a = leesgetal (fs, &aantal);
                for (; aantal > 0; aantal--){
                   fs++;
                }
                break;
            case 'H':
                header = 0;
                break;
            default:
                fprintf(stderr, "mcprofile: illegal option %c\n", *fs);
                exit(1);
                break;
            }
        }
   } /* of while */

   /* FILE HANDLING */
   
   if (argc == 0) {
     help ();
   }

   if ((fdata = fopen(*argv, "r")) == NULL) {
    fprintf(stderr, "mcprofile: can't open textfile %s\n", *argv);
    exit(1);
   }

   /* strip of the input extension .zvec and store result in base_name */
   strncpy(base_name, *argv, strlen(*argv) - 4);

   change_extension (base_name, new_name, ".obs");
   if ((forig = fopen(new_name, "w")) == NULL){
    fprintf(stderr, "mcprofile: can't open textfile %s\n", new_name);
    exit(1);
   }

   if (nperm > 0){
      change_extension (base_name, new_name, ".mcm");
      if ((fmeans = fopen(new_name, "w")) == NULL){
          fprintf(stderr, "mcprofile: can't open textfile %s\n", new_name);
          exit(1);
      }
   
      change_extension (base_name, new_name, ".mch");
      if ((fhigh = fopen(new_name, "w")) == NULL){
          fprintf(stderr, "mcprofile: can't open textfile %s\n", new_name);
          exit(1);
      }
   
      change_extension (base_name, new_name, ".mcl");
      if ((flow = fopen(new_name, "w")) == NULL){
          fprintf(stderr, "mcprofile: can't open textfile %s\n", new_name);
          exit(1);
      }
   }

   /* READ THE INPUT DATA FILE                    */

   /* first skip header, if present (the default) */

   if (header){   
          fscanf(fdata, "%s ", woord);
          fscanf(fdata, "%s ", woord);
   }
 
   N = 1; gmMax = 0;
   while (fscanf(fdata, "%s %d", woord, &getal) != EOF) {
     TEXT[N] = getal;
     if (getal == 1) gmMax++;   /* highest-frequency word has Zipf rank 1 */
     N++;
     if (N > MAXTOKENS2){
       fprintf(stderr, "mcprofile: ERROR: text length exceeds array bounds\n");
       exit(1);
     }
     if (getal > (MAXTYPES2-1)) {  /* Zipf rank is too high! */
       fprintf(stderr, "mcprofile: ERROR: number of types exceeds array bounds\n");
       exit(1);
     }
   }
   N--;
   fclose(fdata);

   /* REPORT BACK TO USER */

   fprintf(stderr, "Loaded %s (%d word tokens)\n", *argv, N);

   /* DETERMINE THE SUCCESSIVE CHUNKS */

   chunksize = (int) floor(N/(nchunks*1.0));
   remainDer = N - (nchunks * chunksize);
   for (k = 1; k <= nchunks; k++) CHUNKS[k] = chunksize;
   for (k = 1; k <= remainDer; k++) CHUNKS[k]++;
   for (k = 2; k <= nchunks; k++) CHUNKS[k] += CHUNKS[k-1];
   CHUNKS[0] = 0;

   /* CALCULATE ORIGINAL DEVELOPMENTAL PROFILE */

   constants(0);

   /* CARRY OUT THE MONTE CARLO PERMUTATION RUNS */

   if (nperm > 0) {
      fprintf(stderr, "Running %d permutations\n", nperm);
      permute(nperm);
      fprintf(stderr, "\nCompleted permutation runs\n");
   }

   /* CALCULATE THE MEANS AND CONFIDENCE INTERVALS FOR THE CONSTANTS */

   tabulate(K_CONST, 1);
   tabulate(D_CONST, 2);
   tabulate(V_CONST, 3);
   tabulate(V1_CONST, 4);
   tabulate(V2_CONST, 5);
   tabulate(V3_CONST, 6);
   tabulate(V4_CONST, 7);
   tabulate(V5_CONST, 8);
   tabulate(R_CONST, 9);
   tabulate(W_CONST, 10);
   tabulate(S_CONST, 11);
   tabulate(H_CONST, 12);
   tabulate(C_CONST, 13);
   tabulate(E_CONST, 14);
   tabulate(logM_CONST, 15);
   tabulate(logSt_CONST, 16);
   tabulate2(Sb_CONST, 17);
   tabulate2(Sc_CONST, 18);
   tabulate2(Sa1_CONST, 19);
   tabulate2(Z_CONST, 20);
   tabulate(A_FREQ, 21);
   tabulate(THE_FREQ, 22);
   tabulate(SMEAN_CONST, 23);
   tabulate(SSTDEV_CONST, 24);

   /* AND PRINT THE RESULTS */

   print_tabel(forig, tabel_orig);
   if (nperm > 0) {
        print_tabel(fmeans, tabel_means);
        print_tabel(flow, tabel_cilow);
        print_tabel(fhigh, tabel_cihigh);
   }

   /* FINALLY, REPORT NUMBER OF RUNS WITHOUT FITS FOR ZIPF AND SICHEL */

   fprintf(stderr, "Number of missing fits for Zipf:   %d\n", zipfzeros);
   fprintf(stderr, "Number of missing fits for Sichel: %d\n", sichelzeros);

   return (0);
}


void print_tabel (bestand, tabel)
FILE *bestand;
double tabel[MAXCHUNKS2+1][NMEASURES+1];

{
   int i, j;
   
   fprintf(bestand, "N K D V V1 V2 V3 V4 V5 R W S H C E lM lSt b c a1 Z fa fthe sLmean sLstdev\n");
   for (i = 1; i <= nchunks; i++){
         fprintf(bestand, "%d", CHUNKS[i]);
         for (j = 1; j <= NMEASURES; j++){
               fprintf(bestand, " %10.7f", tabel[i][j]);
         }
         fprintf(bestand, "\n");
   }
}


void tabulate2(CTABLE, column_number)   /* ignore cases without fit */
double CTABLE[MAXPERM][MAXCHUNKS2];
int column_number;
{
   double sum, mean; 
   int nnonzero;
   double vektor[MAXPERM];
   double cif;

   /* means for each chunksize */

   for (j = 1; j <= nchunks; j++){ 
 
        /* original text values for each chunksize */
    
        tabel_orig[j][column_number] = CTABLE[0][j];

        if (nperm > 0){
 
            /* means for each chunksize */

            sum = 0; nnonzero = 0;
            for (i = 1; i <= nperm; i++){
              if (CTABLE[i][j] != 0){
                nnonzero++;
                sum += CTABLE[i][j];
                vektor[nnonzero] = (double) CTABLE[i][j];
              }
            }
            mean = sum/((double) nnonzero);
            tabel_means[j][column_number] = mean;
   
            /* confidence interval for each chunksize */

            qcksrt(nnonzero, vektor);  /* vektor indexed: 1 ... nperm */
            cif = 2* (100.0/(100.0 - (double)ci)); /* default: 40 */
            tabel_cilow[j][column_number] = vektor[(int)floor(nnonzero/cif)+1];
            tabel_cihigh[j][column_number] = 
                vektor[(int)(nnonzero-floor(nnonzero/cif))];
        }
   }

}


void tabulate(CTABLE, column_number)
double CTABLE[MAXPERM][MAXCHUNKS2];
int column_number;

{
   double sum, mean;
   double vektor[MAXPERM];
   double cif;

   /* means for each chunksize */

   for (j = 1; j <= nchunks; j++){ 
 
        /* original text values for each chunksize */
    
        tabel_orig[j][column_number] = CTABLE[0][j];

        if (nperm > 0){

            /* means for each chunksize */

            sum = 0;
            for (i = 1; i <= nperm; i++){
                sum += CTABLE[i][j];
                vektor[i] = (double) CTABLE[i][j];
            }
            mean = sum/((double) nperm);
            tabel_means[j][column_number] = mean;
   
            /* confidence interval for each chunksize */

            qcksrt(nperm, vektor);  /* vektor indexed: 1 ... nperm */
            cif = 2* (100.0/(100.0 - (double)ci)); /* default: 40 */
            tabel_cilow[j][column_number] = vektor[(int)floor(nperm/cif)+1];
            tabel_cihigh[j][column_number] = 
                 vektor[(int)(nperm-floor(nperm/cif))];
        }
   }

}


void permute (nperm)
int nperm;

{
  int s; 
  if (s == 0) {
    s = -1;
  }
  uniformRandom (&s); 

  for (p = 1; p <= nperm; p++){
    randomize (s, N);
    if (p % 10 == 0) {
      fprintf (stderr, "%d\r", p);
    }
    constants (p);
  }
}


void constants (a)
int a;    /* 0: for original; p for p-th randomization */

{
   freq_a = 0;
   freq_the = 0;
   typenaantal = 0;

   /* build spectra for the k chunks */

   for (j = 1; j <= nchunks; j++){
  
      /* build spectrum */

      spectrum (CHUNKS[j-1] + 1, CHUNKS[j]);
      curN = CHUNKS[j];

      /* calculate constants */

      A_FREQ[a][j] = (double) freq_a;
      THE_FREQ[a][j] = (double) freq_the;
      K_CONST[a][j] = getK2 (maantal, VM, MLIJST, curN);
      D_CONST[a][j] = getD2 (maantal, VM, MLIJST, curN);
      V_CONST[a][j] = (double) curV;
      V1_CONST[a][j] = (double) curV1;
      V2_CONST[a][j] = (double) curV2;
      V3_CONST[a][j] = (double) curV3;
      V4_CONST[a][j] = (double) curV4;
      V5_CONST[a][j] = (double) curV5;
      R_CONST[a][j] = ((double) curV)/sqrt(curN);
      W_CONST[a][j] = exp(exp(-0.17*log(curV))*log(curN));
      S_CONST[a][j] = ((double) curV2)/((double) curV);
      H_CONST[a][j] = 100.0 * log((double)curN)/
                      (1.0 - ((double)curV1/(double)curV));
      C_CONST[a][j] = log (curV) / log (curN);
      E_CONST[a][j] = getE2 (maantal, VM, MLIJST, curN);
      lognormal2 (maantal, PVM, VM, MLIJST, curN, &smean, &sstdev);
      SMEAN_CONST[a][j] = smean;
      SSTDEV_CONST[a][j] = sstdev;
      logM_CONST[a][j] = getlogMean2 (maantal, VM, MLIJST, curV);
      logSt_CONST[a][j] = getlogStdDev2 (logM_CONST[a][j], maantal, VM, MLIJST, curV);
      SichelParam ();  /* calculates the parameters for Sichel */
      Sb_CONST[a][j] = cur_b;
      Sc_CONST[a][j] = cur_c;
      Sa1_CONST[a][j] = cur_a1;
      if (useGlobalMmax == 1) {
         Z_CONST[a][j] = getZ ((double) gmMax / (double) N, curN, curV, &zipfzeros);
      }
      else{
         Z_CONST[a][j] = getZ ((double) mMax / (double) curN, curN, curV, &zipfzeros);
      }
   }

   /* clean out the arrays for future use in new permutation run */   

   for (i = 1; i <= typenaantal; i++){
       WORDFREQ[TYPENLIJST[i]] = 0;
       TYPENLIJST[i] = 0;
   }      
   typenaantal = 0;
}


void spectrum(begin, eind) /* build spectrum for text vector from begin to eind */
int begin, eind;           /* first and last position to take into account */
{
  int i; 
  
  for (i = begin; i <= eind; i++){
      WORDFREQ[TEXT[i]] ++;                       /* word frequencies */
      if (WORDFREQ[TEXT[i]] == 1){                /* this type is new! */
             typenaantal++;                       /* hence increase typecount */
             TYPENLIJST[typenaantal] = TEXT[i];   /* and add to list of types */
      }
      if (TEXT[i] == f_the) freq_the++;           /* check particular words */
      if (TEXT[i] == f_a) freq_a++;
  }

  curV = typenaantal;                             /* current number of types */

  /*
  We now have:
     TYPENLIJST[1..typenaantal]:  list of types by Zipf rank z
     WORDFREQ[z]:                 frequency of type with Zipf rank z
  */

  /* throw out old values from arrays */

  for (i = 1; i <= maantal; i++){    /* maantal: number of ranks previous run */
     VM[MLIJST[i]] = 0;
     MLIJST[i] = 0;
  }
  maantal = 0;   /* number of ranks */
  mMax = 0;      /* maximal frequency rank in current part of the text */

  /* build new spectrum */

  for (i = 1; i <= typenaantal; i++){  /* for all types in typelist */
      VM[ WORDFREQ[ TYPENLIJST[i] ] ] ++;
      if (VM[ WORDFREQ[ TYPENLIJST[i] ] ] == 1) {
         maantal++;
         MLIJST[maantal] = WORDFREQ[ TYPENLIJST[i] ];
      }
      if (WORDFREQ[ TYPENLIJST[i] ] >= mMax){
            mMax = WORDFREQ[ TYPENLIJST[i]];
      }
  }

  curV1 = VM[1];  /* current number of hapaxes */
  curV2 = VM[2];  /* current number of dislegomena */
  curV3 = VM[3]; 
  curV4 = VM[4];
  curV5 = VM[5]; 
}


void randomize (s, n)
int	s, n;

{
  int	k, i, regel, tmp, r;

  k = n; r = 1;

  for (i = 1; i < n; i++) {
     regel = ((i-1) + ((int) floor( (k-i+1) * uniformRandom(&r) ) + 1));
     tmp =  TEXT[regel];
     TEXT[regel] = TEXT[i];
     TEXT[i] = tmp;
  }
}


/* Sichel functions */

void SichelParam ()    /* estimates parameters for Gamma fixed at -0.5 */
{
    double upper, lower, stepsize, x, y, z, theta,alpha;
    int slecht, iterations;

    upper = ((double)curN)/((double)curV1);
    lower = NULL_F;
    stepsize = ((double)curN/(double)curV1)/1000.0;

    x = upper; slecht = 0; iterations = 0;
    while (delta (x, (double) curN, (double) curV, (double) curV1) > EPSILON) {
        iterations++;
        upper = x;
        x -= stepsize;
        if (x > NULL_F) {
           if (delta (x, (double) curN, (double) curV, (double) curV1) < NULL_F) {
               x = upper;
               stepsize /= 1000.0;
           }
        }
        if (fz (x, (double) curN, (double) curV, (double) curV1) < NULL_F) {
             x = upper;
             slecht = 1;
             break;
        }
        if (iterations > MAXITERATIONS){
             x = upper;
             slecht = 1;
             break;
        }
    }
    z = x;
    y = ((double)curV1/(double)curN)*z;
    theta = (1.0 - (y*y));
    alpha = ((2.0 * curV1)/(1.0*curV*theta))*
             (((1.0*curN*y)/((double) curV1))-1.0);

    cur_c = theta/((double)curN*(1.0-theta));
    cur_b = alpha/sqrt(1.0 + (cur_c * (double)curN));
    cur_a1 =  (cur_b*(double)curN)/
              ((2.0/cur_c) * sqrt(1.0 + ((double)curN * cur_c)) *
              (exp( cur_b * (sqrt(1.0 + ((double)curN * cur_c))-1.0))-1.0));

    if (slecht){
      cur_c = 0; cur_b = 0; cur_a1 = 0; sichelzeros++;
    }
}


void help ()
{
  fprintf (stderr,"mcprofile -kCHUNKS -pPERM -H -aA -tT -cC -z text.zvc \n");
  fprintf (stderr,"      (k maximally %d, p maximally %d)\n", MAXCHUNKS2-1, MAXPERM-1);
  fprintf (stderr,"      (maximal text size %d)\n", MAXTOKENS2-1);
  fprintf (stderr,"OPTIONS:\n"); 
  fprintf (stderr,"      -a: zipf rank word1 (default: A = 4)\n");
  fprintf (stderr,"      -t: zipf rank word2 (default: T = 1)\n");
  fprintf (stderr,"      -H: text.zvc lacks its header\n");
  fprintf (stderr,"      -z: use global instead of local pstar for Zipf\n");
  fprintf (stderr,"      -c: confidence interval (default: C = 95)\n");
  fprintf (stderr,"      -k: number of chunks (default: 20)\n");
  fprintf (stderr,"      -p: number of permutation runs (default: 0)\n");
  fprintf (stderr,"INPUT:\n");
  fprintf (stderr,"      text.zvc:  Word z\n");
  fprintf (stderr,"OUTPUT:\n"); 
  fprintf (stderr,"  text.mcm: Monte Carlo means\n");
  fprintf (stderr,"  text.mcl: lower 95%% confidence interval\n");
  fprintf (stderr,"  text.mch: upper 95%% confidence interval\n");
  fprintf (stderr,"  text.obs: empirical profile of measures\n");
  exit (1);
}
