home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume10 / cbw / part08 / stats.c next >
Encoding:
C/C++ Source or Header  |  1987-06-17  |  18.4 KB  |  799 lines

  1. /*
  2.  * Statistics routines.
  3.  *
  4.  * Robert W. Baldwin, January 1985.
  5.  * Scoring based on letter pairs added by Bob Baldwin May 1985.
  6.  */
  7.  
  8.  
  9. #include    <stdio.h>
  10. #include    <math.h>
  11. #include    "window.h"
  12. #include    "specs.h"
  13. #include    "cipher.h"
  14.  
  15.  
  16. #define STANDALONE    FALSE
  17.  
  18.  
  19.  
  20. /* Globals */
  21. int        stats1loaded = FALSE;    /* True if letter stats loaded. */
  22. char    *letterstats;            /* Filename to find single letter counts. */
  23. int        stats2loaded = FALSE;    /* True if letter pair stats loaded. */
  24. char    *bigramstats;            /* Filename to find letter pair counts. */
  25.  
  26.  
  27. /* This array contains the single letter frequencies.
  28.  * That is, prob[i] is the probability that a randomly selected
  29.  * plaintext character has ascii value i.
  30.  */
  31. float    prob[MAXCHAR+1];
  32. float    pmean, pvar;            /* Mean and variance of above. */
  33.  
  34.  
  35. /* This array contains the base ten logarithms of the single
  36.  * letter frequencies (probabilities) of ASCII characters.
  37.  * The frequencies are between 0 and 1, so the enteries in the
  38.  * table are between minus infinity and 0.
  39.  * The log of a vanishingly small frequency is represented as
  40.  * zero rather than some large negative number.
  41.  * The expected value of logprob[c] for a randomly selected
  42.  * character, c, is given by logmean.  The variance of logprob[c]
  43.  * is given by logvar.  The standard deviation is in logsd.
  44.  */
  45. float    logprob[MAXCHAR+1];
  46. float    logmean, logvar, logsd;
  47.  
  48.  
  49. /* This array contains the bigram (letter pair) frequencies.
  50.  * That is, biprob[i][j] is the probability that a randomly selected
  51.  * pair of adjacent plaintext characters is Ai, Aj.  Where Ai
  52.  * is the ith letter of the alphabet (0 = 'A' or 'a', and
  53.  * 26 = space or other non-alphabetic).
  54.  * Eventually this will be generalized to include an arbitrary
  55.  * character translation table to handle punctuation and to allow
  56.  * groups of characters such as (, <, {, and [ to be treated the same.
  57.  * 
  58.  * The array slbiprob is the single letter frequencies taken from the
  59.  * same sources as biprob[][].
  60.  */
  61. float    biprob[MXBIINDEX][MXBIINDEX];
  62. float    slbiprob[MXBIINDEX];
  63.  
  64.  
  65. /* The array is used to map from 7-bit ascii to indices in the biprob
  66.  * and related arrays.  The variable nbichars is set to the next index
  67.  * to use in the biprob array.
  68.  */
  69. int        char_bimap[MAXCHAR+1];
  70. int        nbichars;
  71.  
  72.  
  73. /* This array contains the base ten logarithms of the letter pair
  74.  * frequencies (biprob[][]).
  75.  * The frequencies are between 0 and 1, so the enteries in the
  76.  * table are between minus infinity and 0.
  77.  * The log of a vanishingly small frequency is represented as
  78.  * zero rather than some large negative number.
  79.  * The expected value of bilogprob[c] for a randomly selected
  80.  * character, c, is given by bilogmean.  The variance of bilogprob[c]
  81.  * is given by bilogvar.  The standard deviation is in bilogsd.
  82.  */
  83. float    bilogprob[MXBIINDEX][MXBIINDEX];
  84.  
  85.  
  86. /* This vector contains the base ten logarithms of the single letter
  87.  * frequencies which are derived from biprob[][].
  88.  * They are used to compute the log of the conditional probabilities
  89.  * of letter pairs, given a known value for either the first or
  90.  * second character.
  91.  * Specifically: log( prob(XY given X=Ai) ) equals
  92.  *    log( prob(XY) / prob(Ai) ) which equals 
  93.  *    bilogprob[X][Y] - sllogprob[Ai].
  94.  */
  95. float    sllogprob[MXBIINDEX];
  96.  
  97.  
  98. /* The scoring function that uses letter pair frequencies is based
  99.  * on a statistic that has a computable mean and variance (and
  100.  * standard deviation).  The are stored in the following variables.
  101.  */
  102. float    score2_mean, score2_var, score2_sd, score2_scale;
  103. float    score1_mean, score1_var, score1_sd, score1_scale;
  104.  
  105.  
  106. #if STANDALONE
  107. #define    filename        "/usr/baldwin/Ecrypt/mss-bigram.stats"
  108. main()
  109. {
  110.     FILE    *inp;
  111.  
  112.     load_2stats_from(filename);
  113.     print_2stats(stdout);
  114. }
  115. #endif
  116.  
  117.  
  118.  
  119. /* Score the given plaintext block.  Returns a floating point number.
  120.  * For now a stud.
  121.  */
  122. float    score(pblock)
  123. int        pblock[];
  124. {
  125.     int        pchar;
  126.     int        i;
  127.     float    score;
  128.  
  129.     score = 0.0;
  130.     for (i = 0 ; i < BLOCKSIZE ; i++)  {
  131.         pchar = pblock[i];
  132.         if (pchar == -1)  continue;
  133.         if (pchar == ' ')            {score += 0.1;}
  134.         else if (lletter(pchar))    {score += 0.1;}
  135.         else if (uletter(pchar))    {score += 0.05;}
  136.         else if (printable(pchar))    {score += 0.02;}
  137.         else if (pchar == '\t' || pchar == '\n' || pchar == '\f')
  138.                                     {score += 0.05;}
  139.         else if ('0' <= pchar && pchar <= '9')
  140.                                     {score += 0.05;}
  141.         else                         {score -= 0.4;}
  142.         }
  143.     return(score);
  144. }
  145.  
  146.  
  147. /* Score a vector of integers that represent characters.
  148.  * The vector is terminated by a value of NONE.
  149.  * The returned score is the number of standard deviations
  150.  * that the observed statistics differs from its expected value.
  151.  * Scores are positive with low scores being better.
  152.  * A negative score indicates an impossible plaintext value.
  153.  */
  154. float    pvec_1score(pvec)
  155. int    *pvec;
  156. {
  157.     int        i;
  158.     int        c;
  159.     float    tmp, sum, count, score;
  160.  
  161.     if (!stats1loaded)  {
  162.         load_1stats_from(letterstats);
  163.         }
  164.  
  165.     count = 0.0;
  166.     sum = 0.0;
  167.     while (*pvec != NONE)  {
  168.         count += 1.0;
  169.         c = *pvec++;
  170.         if (c != c & CHARMASK)  return(-1.0);
  171.         tmp = logprob[c & CHARMASK];
  172.         if (tmp == 0.0)  return(-1.0);
  173.         sum += tmp;
  174.         }
  175.  
  176.     if (count == 0.0)  return(-1.0);
  177.     tmp = (sum / count) - logmean;
  178.     tmp = tmp > 0 ? tmp : 0.0 - tmp;
  179.     score = tmp / (logsd / sqrt(count));
  180. /*    printf("  dividing by logsd yields %g", score);
  181.     tmp = tmp * tmp;
  182.     tmp = (tmp * count) / logvar;
  183.     tmp = exp(-0.5 * tmp);
  184.     printf("\nThe exponential yields %g", tmp);
  185.     printf("\n");
  186.     score = sqrt(count) * exp((0 - tmp)/2.0);
  187. */
  188.     return(score);
  189. }
  190.  
  191.  
  192. /* Score a vector of integers that represent characters.
  193.  * The vector is terminated by a value of NONE.
  194.  * Scoring is based on ratio of observed and expected variance.
  195.  */
  196. float    var_1score(pvec)
  197. int    *pvec;
  198. {
  199.     int        i;
  200.     int        c;
  201.     float    tmp, sum, count, score;
  202.  
  203.     if (!stats1loaded)  {
  204.         load_1stats_from(letterstats);
  205.         }
  206.  
  207.     count = 0.0;
  208.     sum = 0.0;
  209.     while (*pvec != NONE)  {
  210.         count += 1.0;
  211.         c = *pvec++;
  212.         if (c != c & CHARMASK)  return(0.0);
  213.         tmp = logprob[c & CHARMASK];
  214.         if (tmp == 0.0)  return(0.0);
  215.         tmp = tmp - logmean;
  216.         tmp = tmp * tmp;
  217.         sum += tmp;
  218.         }
  219.  
  220.     if (count == 0.0)  return(0.0);
  221.     score = sum / (count * logvar);
  222.     return(score);
  223. }
  224.  
  225.  
  226. /* Score a vector of integers that represent characters.
  227.  * The vector is terminated by a value of NONE.
  228.  * Score is the probability that the given characters
  229.  * were drawn from english.
  230.  * NOTE: doesn't correctly handle repeated letters.
  231.  */
  232. float    prob_1score(pvec)
  233. int    *pvec;
  234. {
  235.     int        i;
  236.     int        c;
  237.     float    tmp, product, count, score;
  238.  
  239.     if (!stats1loaded)  {
  240.         load_1stats_from(letterstats);
  241.         }
  242.  
  243.     count = 0.0;
  244.     product = 1.0;
  245.     while (*pvec != NONE)  {
  246.         count += 1.0;
  247.         c = *pvec++;
  248.         if (c != c & CHARMASK)  return(0.0);
  249.         product *= prob[c] * count;
  250.         }
  251.  
  252.     if (count == 0.0)  return(0.0);
  253.     score = product;
  254.     return(score);
  255. }
  256.  
  257.  
  258. /* Score a guess based on letter pair frequencies.
  259.  * The returned score is the number of standard deviations
  260.  * that the observed statistics differs from its expected value.
  261.  * Scores are positive with low scores being better.
  262.  * A negative score indicates an impossible plaintext value.
  263.  */
  264. float    gsi_2score(gsi)
  265. reg        gsinfo    *gsi;
  266. {
  267.     float    score;
  268.     float    total;
  269.     float    tmp;
  270.     int        nchars;
  271.     int        i;
  272. reg    int        pos;    
  273. reg    int        c;
  274. reg    int        center_letter;
  275.     int        left_letter, right_letter;
  276.     float    pair_score;
  277.  
  278.     if (!stats2loaded)  {
  279.         load_2stats_from(bigramstats);
  280.         }
  281.  
  282.     nchars = 0;
  283.     total = 0.0;
  284.     for (i = 0 ; (pos = gsi->cpos[i]) != NONE ; i++)  {
  285.         nchars++;
  286.         c = (gsi->cguessed)[pos];
  287.         center_letter = char_bimap[c & CHARMASK];
  288.         if (sllogprob[center_letter] == 0.0)
  289.             return(-1.0);
  290.  
  291.         if (pos == 0) {
  292.             total += sllogprob[center_letter];
  293.             }
  294.         else {
  295.             c = (gsi->cknown)[pos - 1];
  296.             if (c == NONE)  {
  297.                 c = (gsi->cguessed)[pos - 1];
  298.                 }
  299.             if (c == NONE)  {
  300.                 total += sllogprob[center_letter];
  301.                 }
  302.             else {
  303.                 left_letter = char_bimap[c & CHARMASK];
  304.                 pair_score = bilogprob[left_letter][center_letter];
  305.                 if (pair_score == 0.0)
  306.                     return(-1.0);
  307.                 total += pair_score - sllogprob[center_letter];
  308.                 }
  309.             }
  310.  
  311.         if (pos == (BLOCKSIZE - 1)) {
  312.             total += sllogprob[center_letter];
  313.             }
  314.         else {
  315.             c = (gsi->cknown)[pos + 1];
  316.             if (c == NONE)  {
  317.                 c = (gsi->cguessed)[pos + 1];
  318.                 }
  319.             if (c == NONE)  {
  320.                 total += sllogprob[center_letter];
  321.                 }
  322.             else {
  323.                 right_letter = char_bimap[c & CHARMASK];
  324.                 pair_score = bilogprob[center_letter][right_letter];
  325.                 if (pair_score == 0.0)
  326.                     return(-1.0);
  327.                 total += pair_score - sllogprob[center_letter];
  328.                 }
  329.             }
  330.         }
  331.  
  332.     if (nchars == 0)
  333.         return(-1.0);
  334.     tmp = (total / nchars) - score2_mean;
  335.     tmp = tmp > 0.0 ? tmp : 0.0 - tmp;
  336.     score = tmp / (score2_sd / isqrt[nchars]);
  337.     return(score);
  338. }
  339.  
  340.  
  341. /* Score a guess based on single letter frequencies.
  342.  * The returned score is the number of standard deviations
  343.  * that the observed statistics differs from its expected value.
  344.  * Scores are positive with low scores being better.
  345.  * A negative score indicates an impossible plaintext value.
  346.  */
  347. float    gsi_1score(gsi)
  348. reg        gsinfo    *gsi;
  349. {
  350. reg    int        pos;
  351.     int        i;
  352.     int        c;
  353.     int        nchars;
  354.     float    sum, score;
  355. reg    float    tmp;
  356.  
  357.     if (!stats1loaded)  {
  358.         load_1stats_from(letterstats);
  359.         }
  360.  
  361.     nchars = 0;
  362.     sum = 0.0;
  363.     for (i = 0 ; (pos = gsi->cpos[i]) != NONE ; i++)  {
  364.         nchars++;
  365.         c = (gsi->cguessed)[pos];
  366.         tmp = logprob[c & CHARMASK];
  367.         if (tmp == 0.0)
  368.             return(-1.0);
  369.         sum += tmp;
  370.         }
  371.  
  372.     if (nchars == 0)
  373.         return(-1.0);
  374.     tmp = (sum / nchars) - logmean;
  375.     tmp = tmp > 0 ? tmp : 0.0 - tmp;
  376.     score = tmp / (logsd / isqrt[nchars]);
  377.  
  378.     return(score);
  379. }
  380.  
  381.  
  382. /* Compute expected value of a scoring function given
  383.  * a vector of probabilities for values and a vector of
  384.  * scores for each value.
  385.  */
  386. float    vec_mean(probvec, scorevec, maxindex)
  387. float    *probvec;
  388. float    *scorevec;
  389. int        maxindex;
  390. {
  391.     int        i;
  392.     float    mean;
  393.  
  394.     mean = 0.0;
  395.     for (i = 0 ; i <= maxindex ; i++) {
  396.         mean += (*probvec++) * (*scorevec++);
  397.         }
  398.     return(mean);
  399. }
  400.  
  401.  
  402. /* Compute variance of a scoring function given
  403.  * a vector of probabilities for values and a vector of
  404.  * scores for each value.
  405.  */
  406. float    vec_variance(probvec, scorevec, maxindex)
  407. float    *probvec;
  408. float    *scorevec;
  409. int        maxindex;
  410. {
  411.     int        i;
  412.     float    var, mean;
  413.     float    delta;
  414.  
  415.     mean = vec_mean(probvec, scorevec, maxindex);
  416.     var = 0.0;
  417.     for (i = 0 ; i <= maxindex ; i++) {
  418.         delta = (*scorevec++) - mean;
  419.         var += (*probvec++) * (delta * delta);
  420.         }
  421.     return(var);
  422. }
  423.  
  424.  
  425. /* Read from given stream to set up logprob table and constants
  426.  * logmean and logvar.
  427.  *
  428.  * The table format is:
  429.  * <Total count>
  430.  * <Blankline>
  431.  * <Count><space><One or more slashified characters to share that count>
  432.  *  ...
  433.  * <Count><space><One or more slashified characters to share that count>
  434.  * <Blankline>
  435.  * <EOF>
  436.  */
  437. load_1stats(inp)
  438. FILE    *inp;
  439. {
  440.     int        i,n;
  441.     int        tmp;
  442.     int        c;
  443.     float    v, lv, fv;
  444.     float    etotal, ctotal;
  445.  
  446.     stats1loaded = TRUE;
  447.  
  448.     for (i = 0 ; i <= MAXCHAR ; i++)  logprob[i] = 0.0;
  449.  
  450.     if (fscanf(inp, "%d", &tmp) != 1)  {
  451.         printf("Error while getting total");
  452.         return;
  453.         }
  454.     etotal = tmp;
  455.     ctotal = 0.0;
  456.  
  457.     if (fscanf(inp, "\n") != 0)  {
  458.         printf("Error while skipping blank line");
  459.         return;
  460.         }
  461.  
  462.     while (TRUE) {
  463.         if ((n = fscanf(inp, "%d", &tmp)) != 1)  {
  464.             if (n == 0) break;
  465.             if (n == EOF) break;
  466.             printf("Error while getting character count");
  467.             return;
  468.             }
  469.         v = tmp;
  470.         ctotal += v;
  471.         fv = v/etotal;
  472.         if (fv != 0.0)  {lv = log10(fv);}
  473.         else {lv = 0.0;}
  474.  
  475.         c = read_char(inp);        /* Skip the space. */
  476.         while (TRUE) {
  477.             c = read_char(inp);
  478.             if (c == EOL)  break;
  479.             prob[c&CHARMASK] = fv;
  480.             logprob[c&CHARMASK] = lv;
  481.             }
  482.         }
  483.  
  484.     if (etotal != ctotal) {
  485.         printf("Expected total is %f.  Actual total is %f.\n",etotal,ctotal);
  486.         }
  487.  
  488.     logmean = vec_mean(prob, logprob, MAXCHAR);
  489.     logvar  = vec_variance(prob, logprob, MAXCHAR);
  490.     logsd = sqrt(logvar);
  491.     score1_mean = logmean;
  492.     score1_var = logvar;
  493.     score1_sd = logsd;
  494.     score1_scale = sqrt(2 * PI * score1_var);
  495.     pmean = vec_mean(prob, prob, MAXCHAR);
  496.     pvar = vec_variance(prob, prob, MAXCHAR);
  497. }
  498.  
  499.  
  500. /* Load the letter pair statistics from the given file name.
  501.  */
  502. load_2stats_from(statfname)
  503. char    *statfname;        /* Full path name of file with statistics. */
  504. {
  505.     FILE    *inp;
  506.  
  507.     if ((inp = fopen(statfname, "r")) == NULL) {
  508.         printf("\nCan't open %s to read letter statistics\n", statfname);
  509.         exit(0);
  510.         }
  511.     load_2stats(inp);
  512.     fclose(inp);
  513. }
  514.  
  515.  
  516. /* Read from given stream to set up bilogprob table and constants
  517.  * bilogmean, bilogsd, and bilogvar.
  518.  *
  519.  * The format of the statistics file is: [This should be more general.]
  520.  * <Total count>
  521.  * <Blankline>
  522.  * <single letter counts>
  523.  * <line with the chars '***'>
  524.  * <double letter counts>
  525.  * <line with the chars '***'>
  526.  * <mean of matrix>
  527.  * <variance of matrix>
  528.  * <standard deviation of matrix>
  529.  * <Blankline>
  530.  * <EOF>
  531.  *
  532.  * Where single letter counts also define the mapping from ascii chars to
  533.  * distinguished letters (i.e., all open brackets are treated the same).
  534.  * The single letter format is:
  535.  * <Count><space><One or more slashified characters to share that count>
  536.  *  ...
  537.  * <Count><space><One or more slashified characters to share that count>
  538.  * NOTE: the first entry should be for a low probability letter because the
  539.  * default mapping for unknown chars is zero.  See code for details.
  540.  *
  541.  * The double letter format is:
  542.  * <Count><space><Representative of first letter group><Rep of second letter>
  543.  *  ...
  544.  * <Count><space><Representative of first letter group><Rep of second letter>
  545.  *
  546.  * For example if 'T' and 't' are treated the same, a double letter entry
  547.  * might look like: "1247 TT" and count for Tt, tT, tt, and TT.
  548.  */
  549. load_2stats(inp)
  550. FILE    *inp;
  551. {
  552. register    int        i,j;
  553.     int        n;
  554.     int        tmp;
  555.     int        c;
  556.     int        left_index, right_index;
  557.     float    v, lv, fv;
  558.     float    etotal, ctotal;
  559.     char    linebuf[300];
  560.  
  561.     stats2loaded = TRUE;
  562.     nbichars = 0;
  563.  
  564.     for (i = 0 ; i < MXBIINDEX ; i++)  {
  565.         sllogprob[i] = 0.0;
  566.         slbiprob[i] = 0.0;
  567.         for (j = 0 ; j < MXBIINDEX ; j++)  {
  568.              bilogprob[i][j] = 0.0;
  569.             biprob[i][j] = 0.0;
  570.             }
  571.         }
  572.  
  573.     for (i = 0 ; i < MAXCHAR+1 ; i++)
  574.         char_bimap[i] = 0;        /* Default index if char unknown. */
  575.  
  576.     if (fscanf(inp, "%d", &tmp) != 1)  {
  577.         printf("Error while getting total");
  578.         exit(0);
  579.         }
  580.     etotal = tmp;
  581.  
  582.     if (fscanf(inp, "\n") != 0)  {
  583.         printf("Error while skipping blank line before single letters");
  584.         exit(0);
  585.         }
  586.  
  587.     ctotal = 0.0;
  588.     while (TRUE) {
  589.         if ((n = fscanf(inp, "%d", &tmp)) != 1)  {
  590.             if (n == 0) break;
  591.             if (n == EOF) break;
  592.             printf("Error while getting character count (singles)");
  593.             exit(0);
  594.             }
  595.         v = tmp;
  596.         ctotal += v;
  597.         fv = v/etotal;
  598.         if (fv == 0.0)
  599.             lv = 0.0;
  600.         else
  601.             lv = log10(fv);
  602.  
  603.         c = read_char(inp);        /* Skip the space. */
  604.         while (TRUE) {
  605.             c = read_char(inp);
  606.             if (c == EOL)  break;
  607.             char_bimap[c & CHARMASK] = nbichars;
  608.             slbiprob[nbichars] = fv;
  609.             sllogprob[nbichars] = lv;
  610.             }
  611.         nbichars++;
  612.         }
  613.  
  614.     if (etotal != ctotal) {
  615.         printf("Expected total is %f.  Actual total is %f for singles.\n",
  616.                 etotal, ctotal);
  617.         exit(0);
  618.         }
  619.  
  620.  
  621.     if (fscanf(inp, "***\n") != 0)  {
  622.         printf("Error on delimiter before letter pairs");
  623.         exit(0);
  624.         }
  625.  
  626.     ctotal = 0.0;
  627.     while (TRUE) {
  628.         if ((n = fscanf(inp, "%d", &tmp)) != 1)  {
  629.             if (n == 0) break;
  630.             if (n == EOF) break;
  631.             printf("Error while getting character count (pairs)");
  632.             exit(0);
  633.             }
  634.         v = tmp;
  635.         ctotal += v;
  636.         fv = v/etotal;
  637.         if (fv == 0.0)
  638.             lv = 0.0;
  639.         else
  640.             lv = log10(fv);
  641.  
  642.         c = read_char(inp);        /* Skip the space. */
  643.         c = read_char(inp);        /* First letter. */
  644.         if (c == EOL)  {
  645.             printf("Line ends before letter pair");
  646.             exit(0);
  647.             }
  648.         left_index = char_bimap[c & CHARMASK];
  649.         c = read_char(inp);        /* Second letter. */
  650.         if (c == EOL)  {
  651.             printf("Line ends in middle of letter pair");
  652.             exit(0);
  653.             }
  654.         right_index = char_bimap[c & CHARMASK];
  655.  
  656.         biprob[left_index][right_index] = fv;
  657.         bilogprob[left_index][right_index] = lv;
  658.         }
  659.  
  660.     if (etotal != ctotal) {
  661.         printf("Expected total is %f.  Actual total is %f for pairs.\n",
  662.                 etotal, ctotal);
  663.         exit(0);
  664.         }
  665.  
  666.     if (fscanf(inp, "***\n") == 0)  {
  667.         if (fscanf(inp, "%f", &score2_mean) != 1)  {
  668.             printf("Error reading mean.");
  669.             exit(0);
  670.             }
  671.         if (fscanf(inp, "%f", &score2_var) != 1)  {
  672.             printf("Error reading variance.");
  673.             exit(0);
  674.             }
  675.         if (fscanf(inp, "%f", &score2_sd) != 1)  {
  676.             printf("Error reading standard deviations.");
  677.             exit(0);
  678.             }
  679.         score2_scale = sqrt(2 * PI * score2_var);
  680.         approx_init();
  681.         return;
  682.         }
  683.  
  684.     stats2();
  685.     printf("Mean: %f, Var: %f, SD: %f\n", score2_mean, score2_var, score2_sd);
  686. }
  687.  
  688.  
  689. /* Compute scoring statistics for the letter pair frequencies.
  690.  * Uses the globals: biprob[][], sllogbiprob[], and bilogprob[][].
  691.  * Sets gobals: score2_mean, score2_var, score2_sd.
  692.  */
  693. stats2()
  694. {
  695. register    int    i,j,k;
  696.     float    mean, var;
  697.     float    weight, score;
  698.  
  699.     mean = 0.0;
  700.     var = 0.0;
  701.     for (i = 0 ; i < nbichars ; i++)
  702.         for (j = 0 ; j < nbichars ; j++)  {
  703.             if (slbiprob[j] == 0.0)
  704.                 continue;
  705.             for (k = 0 ; k < nbichars ; k++) {
  706.                 weight = biprob[i][j] * biprob[j][k] / slbiprob[j];
  707.                 score = bilogprob[i][j] + bilogprob[j][k] - 2 * sllogprob[j];
  708.                 mean += weight * score;
  709.                 var += weight * score * score;
  710.                 }
  711.             }
  712.     var -= mean * mean;
  713.  
  714.     score2_mean = mean;
  715.     score2_var = var;
  716.     score2_sd = sqrt(score2_var);
  717.     score2_scale = sqrt(2 * PI * score2_var);
  718.  
  719.     approx_init();
  720. }
  721.  
  722.  
  723. /* Print the bigram statistics.
  724.  */
  725. print_2stats(out)
  726. FILE    *out;
  727. {
  728.     float    sllog_mean;
  729.     float    sllog_var;
  730.     float    lev_mean, lev_var;
  731.     float    rev_mean, rev_var;
  732.  
  733.     fprintf(out, "\t\tBigram Statistics\n");
  734.     fprintf(out, "Score2_mean is %f", score2_mean);
  735.     fprintf(out, ", score2_var is %f", score2_var);
  736.     fprintf(out, ", score2_sd is %f", score2_sd);
  737.     fprintf(out, "\nnbichars is %d", nbichars);
  738.     fprintf(out, "\n");
  739.  
  740.     sllog_mean = vec_mean(slbiprob, sllogprob, nbichars);
  741.     sllog_var = vec_variance(slbiprob, sllogprob, nbichars);
  742.     fprintf(out, "sllog_mean is %f", sllog_mean);
  743.     fprintf(out, ", sllog_var is %f", sllog_var);
  744.     fprintf(out, "\n");
  745. }
  746.  
  747.  
  748.  
  749. /* Print the first order log statistics on a stream.
  750.  */
  751. print_1stats(out)
  752. FILE    *out;
  753. {
  754.  
  755.     fprintf(out, "Single letter frequencies\n");
  756.     fprintf(out, "\nExpected value of prob is %f.  Variance is %f.\n",
  757.            pmean, pvar);
  758.     print_stat_tab(out, prob, MAXCHAR);
  759.  
  760.     fprintf(out, "\nExpected value of logprob is %f.  Variance is %f.\n",
  761.            logmean, logvar);
  762.     fprintf(out, "Log of single letter frequencies\n");
  763.     print_stat_tab(out, logprob, MAXCHAR);
  764. }
  765.  
  766.  
  767. /* Dumpa statistics table on to a stream.
  768.  */
  769. print_stat_tab(out, table, maxindex)
  770. FILE    *out;
  771. float    table[];
  772. int        maxindex;
  773. {
  774.     int        i;
  775.  
  776.     for (i = 0 ; i <= maxindex ; i++) {
  777.         if (i % 8 == 0)  fprintf(out, "\n");
  778.         fprintf(out, "%7.4f ", table[i]);
  779.         }
  780.     fprintf(out, "\n");
  781. }
  782.  
  783.  
  784. /* Load the first order statistics from the given file name.
  785.  */
  786. load_1stats_from(statfname)
  787. char    *statfname;
  788. {
  789.     FILE    *inp;
  790.  
  791.     if ((inp = fopen(statfname, "r")) == NULL) {
  792.         printf("\nCan't open %s to read letter statistics\n", statfname);
  793.         exit(0);
  794.         }
  795.     load_1stats(inp);
  796.     fclose(inp);
  797. }
  798.  
  799.