Change how checking for missing values works.
[pspp] / src / language / stats / frequencies.c
1 /*
2   PSPP - a program for statistical analysis.
3   Copyright (C) 1997-9, 2000, 2007, 2009, 2010, 2011, 2014, 2015 Free Software Foundation, Inc.
4
5   This program is free software: you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation, either version 3 of the License, or
8   (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <config.h>
20 #include <stdlib.h>
21 #include <gsl/gsl_histogram.h>
22
23
24 #include "data/case.h"
25 #include "data/casegrouper.h"
26 #include "data/casereader.h"
27 #include "data/dataset.h"
28 #include "data/dictionary.h"
29 #include "data/format.h"
30 #include "data/missing-values.h"
31 #include "data/settings.h"
32 #include "data/value-labels.h"
33 #include "data/variable.h"
34
35 #include "language/dictionary/split-file.h"
36
37 #include "language/command.h"
38 #include "language/lexer/lexer.h"
39 #include "language/lexer/variable-parser.h"
40 #include "language/stats/freq.h"
41
42 #include "libpspp/array.h"
43 #include "libpspp/bit-vector.h"
44 #include "libpspp/compiler.h"
45 #include "libpspp/hmap.h"
46 #include "libpspp/message.h"
47 #include "libpspp/misc.h"
48 #include "libpspp/pool.h"
49
50 #include "math/histogram.h"
51 #include "math/moments.h"
52 #include "math/chart-geometry.h"
53
54
55 #include "output/charts/barchart.h"
56 #include "output/charts/piechart.h"
57 #include "output/charts/plot-hist.h"
58 #include "output/pivot-table.h"
59
60 #include "gl/minmax.h"
61 #include "gl/xalloc.h"
62
63 #include "gettext.h"
64 #define _(msgid) gettext (msgid)
65 #define N_(msgid) msgid
66
67 /* Percentiles to calculate. */
68
69 struct percentile
70 {
71   double p;        /* the %ile to be calculated */
72   double value;    /* the %ile's value */
73   bool show;       /* True to show this percentile in the statistics box. */
74 };
75
76 static int
77 ptile_3way (const void *_p1, const void *_p2)
78 {
79   const struct percentile *p1 = _p1;
80   const struct percentile *p2 = _p2;
81
82   if (p1->p < p2->p)
83     return -1;
84
85   if (p1->p == p2->p)
86     {
87       if (p1->show > p2->show)
88         return -1;
89
90       return (p1->show < p2->show);
91     }
92
93   return (p1->p > p2->p);
94 }
95
96
97 enum
98   {
99     FRQ_NONORMAL,
100     FRQ_NORMAL
101   };
102
103 enum
104   {
105     FRQ_FREQ,
106     FRQ_PERCENT
107   };
108
109 enum sortprops
110   {
111     FRQ_AFREQ,
112     FRQ_DFREQ,
113     FRQ_AVALUE,
114     FRQ_DVALUE
115   };
116
117 /* Array indices for STATISTICS subcommand. */
118 enum
119   {
120     FRQ_ST_MEAN,
121     FRQ_ST_SEMEAN,
122     FRQ_ST_MEDIAN,
123     FRQ_ST_MODE,
124     FRQ_ST_STDDEV,
125     FRQ_ST_VARIANCE,
126     FRQ_ST_KURTOSIS,
127     FRQ_ST_SEKURTOSIS,
128     FRQ_ST_SKEWNESS,
129     FRQ_ST_SESKEWNESS,
130     FRQ_ST_RANGE,
131     FRQ_ST_MINIMUM,
132     FRQ_ST_MAXIMUM,
133     FRQ_ST_SUM,
134     FRQ_ST_count
135   };
136
137 /* Description of statistics. */
138 static const char *st_name[FRQ_ST_count] =
139 {
140    N_("Mean"),
141    N_("S.E. Mean"),
142    N_("Median"),
143    N_("Mode"),
144    N_("Std Dev"),
145    N_("Variance"),
146    N_("Kurtosis"),
147    N_("S.E. Kurt"),
148    N_("Skewness"),
149    N_("S.E. Skew"),
150    N_("Range"),
151    N_("Minimum"),
152    N_("Maximum"),
153    N_("Sum")
154 };
155
156 struct freq_tab
157   {
158     struct hmap data;           /* Hash table for accumulating counts. */
159     struct freq *valid;         /* Valid freqs. */
160     int n_valid;                /* Number of total freqs. */
161     const struct dictionary *dict; /* Source of entries in the table. */
162
163     struct freq *missing;       /* Missing freqs. */
164     int n_missing;              /* Number of missing freqs. */
165
166     /* Statistics. */
167     double total_cases;         /* Sum of weights of all cases. */
168     double valid_cases;         /* Sum of weights of valid cases. */
169   };
170
171 struct frq_chart
172   {
173     double x_min;               /* X axis minimum value. */
174     double x_max;               /* X axis maximum value. */
175     int y_scale;                /* Y axis scale: FRQ_FREQ or FRQ_PERCENT. */
176
177     /* Histograms only. */
178     double y_max;               /* Y axis maximum value. */
179     bool draw_normal;           /* Whether to draw normal curve. */
180
181     /* Pie charts only. */
182     bool include_missing;       /* Whether to include missing values. */
183   };
184
185 /* Per-variable frequency data. */
186 struct var_freqs
187   {
188     const struct variable *var;
189
190     /* Freqency table. */
191     struct freq_tab tab;        /* Frequencies table to use. */
192
193     /* Percentiles. */
194     int n_groups;               /* Number of groups. */
195     double *groups;             /* Groups. */
196
197     /* Statistics. */
198     double stat[FRQ_ST_count];
199
200     /* Variable attributes. */
201     int width;
202   };
203
204 struct frq_proc
205   {
206     struct pool *pool;
207
208     struct var_freqs *vars;
209     size_t n_vars;
210
211     /* Percentiles to calculate and possibly display. */
212     struct percentile *percentiles;
213     const struct percentile *median;
214     int n_percentiles;
215
216     /* Frequency table display. */
217     long int max_categories;         /* Maximum categories to show. */
218     int sort;                   /* FRQ_AVALUE or FRQ_DVALUE
219                                    or FRQ_AFREQ or FRQ_DFREQ. */
220
221     /* Statistics; number of statistics. */
222     unsigned long stats;
223     int n_stats;
224
225     /* Histogram and pie chart settings. */
226     struct frq_chart *hist, *pie, *bar;
227
228     bool warn;
229   };
230
231
232 struct freq_compare_aux
233   {
234     bool by_freq;
235     bool ascending_freq;
236
237     int width;
238     bool ascending_value;
239   };
240
241 static void calc_stats (const struct frq_proc *,
242                         const struct var_freqs *, double d[FRQ_ST_count]);
243
244 static void do_piechart(const struct frq_chart *pie,
245                         const struct variable *var,
246                         const struct freq_tab *frq_tab);
247
248 static void do_barchart(const struct frq_chart *bar,
249                         const struct variable **var,
250                         const struct freq_tab *frq_tab);
251
252 static void dump_statistics (const struct frq_proc *frq,
253                              const struct variable *wv);
254
255 static int
256 compare_freq (const void *a_, const void *b_, const void *aux_)
257 {
258   const struct freq_compare_aux *aux = aux_;
259   const struct freq *a = a_;
260   const struct freq *b = b_;
261
262   if (aux->by_freq && a->count != b->count)
263     {
264       int cmp = a->count > b->count ? 1 : -1;
265       return aux->ascending_freq ? cmp : -cmp;
266     }
267   else
268     {
269       int cmp = value_compare_3way (a->values, b->values, aux->width);
270       return aux->ascending_value ? cmp : -cmp;
271     }
272 }
273
274 /* Create a gsl_histogram from a freq_tab */
275 static struct histogram *
276 freq_tab_to_hist (const struct frq_proc *frq, const struct freq_tab *ft,
277                   const struct variable *var);
278
279 static void
280 put_freq_row (struct pivot_table *table, int var_idx,
281               double frequency, double percent,
282               double valid_percent, double cum_percent)
283 {
284   double entries[] = { frequency, percent, valid_percent, cum_percent };
285   for (size_t i = 0; i < sizeof entries / sizeof *entries; i++)
286     if (entries[i] != SYSMIS)
287       pivot_table_put2 (table, i, var_idx,
288                         pivot_value_new_number (entries[i]));
289 }
290
291 /* Displays a full frequency table for variable V. */
292 static void
293 dump_freq_table (const struct var_freqs *vf, const struct variable *wv)
294 {
295   const struct freq_tab *ft = &vf->tab;
296
297   struct pivot_table *table = pivot_table_create__ (pivot_value_new_variable (
298                                                       vf->var), "Frequencies");
299   pivot_table_set_weight_var (table, wv);
300
301   pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
302                           N_("Frequency"), PIVOT_RC_COUNT,
303                           N_("Percent"), PIVOT_RC_PERCENT,
304                           N_("Valid Percent"), PIVOT_RC_PERCENT,
305                           N_("Cumulative Percent"), PIVOT_RC_PERCENT);
306
307   struct pivot_dimension *variable = pivot_dimension_create__ (
308     table, PIVOT_AXIS_ROW, pivot_value_new_variable (vf->var));
309
310   double cum_freq = 0.0;
311   double cum_percent = 0.0;
312   struct pivot_category *valid = NULL;
313   for (const struct freq *f = ft->valid; f < ft->missing; f++)
314     {
315       cum_freq += f->count;
316       double valid_percent = f->count / ft->valid_cases * 100.0;
317       cum_percent += valid_percent;
318
319       if (!valid)
320         valid = pivot_category_create_group (variable->root, N_("Valid"));
321       int var_idx = pivot_category_create_leaf (
322         valid, pivot_value_new_var_value (vf->var, &f->values[0]));
323       put_freq_row (table, var_idx, f->count,
324                     f->count / ft->total_cases * 100.0,
325                     valid_percent, cum_percent);
326     }
327
328   struct pivot_category *missing = NULL;
329   size_t n_categories = ft->n_valid + ft->n_missing;
330   for (const struct freq *f = ft->missing; f < &ft->valid[n_categories]; f++)
331     {
332       cum_freq += f->count;
333
334       if (!missing)
335         missing = pivot_category_create_group (variable->root, N_("Missing"));
336       int var_idx = pivot_category_create_leaf (
337         missing, pivot_value_new_var_value (vf->var, &f->values[0]));
338       put_freq_row (table, var_idx, f->count,
339                     f->count / ft->total_cases * 100.0, SYSMIS, SYSMIS);
340     }
341
342   int var_idx = pivot_category_create_leaf (
343     variable->root, pivot_value_new_text (N_("Total")));
344   put_freq_row (table, var_idx, cum_freq, cum_percent, SYSMIS, SYSMIS);
345
346   pivot_table_submit (table);
347 }
348 \f
349 /* Statistical display. */
350
351 static double
352 calc_percentile (double p, double valid_cases, double x1, double x2)
353 {
354   double s, dummy;
355
356   s = (settings_get_algorithm () != COMPATIBLE
357        ? modf ((valid_cases - 1) * p, &dummy)
358        : modf ((valid_cases + 1) * p - 1, &dummy));
359
360   return x1 + (x2 - x1) * s;
361 }
362
363 /* Calculates all of the percentiles for VF within FRQ. */
364 static void
365 calc_percentiles (const struct frq_proc *frq, const struct var_freqs *vf)
366 {
367   const struct freq_tab *ft = &vf->tab;
368   double W = ft->valid_cases;
369   const struct freq *f;
370   int percentile_idx = 0;
371   double  rank = 0;
372
373   for (f = ft->valid; f < ft->missing; f++)
374     {
375       rank += f->count;
376       for (; percentile_idx < frq->n_percentiles; percentile_idx++)
377         {
378           struct percentile *pc = &frq->percentiles[percentile_idx];
379           double tp;
380
381           tp = (settings_get_algorithm () == ENHANCED
382                 ? (W - 1) * pc->p
383                 : (W + 1) * pc->p - 1);
384
385           if (rank <= tp)
386             break;
387
388           if (tp + 1 < rank || f + 1 >= ft->missing)
389             pc->value = f->values[0].f;
390           else
391             pc->value = calc_percentile (pc->p, W, f->values[0].f, f[1].values[0].f);
392         }
393     }
394   for (; percentile_idx < frq->n_percentiles; percentile_idx++)
395     {
396       struct percentile *pc = &frq->percentiles[percentile_idx];
397       pc->value = (ft->n_valid > 0
398                    ? ft->valid[ft->n_valid - 1].values[0].f
399                    : SYSMIS);
400     }
401 }
402
403 /* Returns true iff the value in struct freq F is non-missing
404    for variable V. */
405 static bool
406 not_missing (const void *f_, const void *v_)
407 {
408   const struct freq *f = f_;
409   const struct variable *v = v_;
410
411   return !var_is_value_missing (v, f->values);
412 }
413
414
415 /* Summarizes the frequency table data for variable V. */
416 static void
417 postprocess_freq_tab (const struct frq_proc *frq, struct var_freqs *vf)
418 {
419   struct freq_tab *ft = &vf->tab;
420   struct freq_compare_aux aux;
421   size_t count;
422   struct freq *freqs, *f;
423   size_t i;
424
425   /* Extract data from hash table. */
426   count = hmap_count (&ft->data);
427   freqs = freq_hmap_extract (&ft->data);
428
429   /* Put data into ft. */
430   ft->valid = freqs;
431   ft->n_valid = partition (freqs, count, sizeof *freqs, not_missing, vf->var);
432   ft->missing = freqs + ft->n_valid;
433   ft->n_missing = count - ft->n_valid;
434
435   /* Sort data. */
436   aux.by_freq = frq->sort == FRQ_AFREQ || frq->sort == FRQ_DFREQ;
437   aux.ascending_freq = frq->sort != FRQ_DFREQ;
438   aux.width = vf->width;
439   aux.ascending_value = frq->sort != FRQ_DVALUE;
440   sort (ft->valid, ft->n_valid, sizeof *ft->valid, compare_freq, &aux);
441   sort (ft->missing, ft->n_missing, sizeof *ft->missing, compare_freq, &aux);
442
443   /* Summary statistics. */
444   ft->valid_cases = 0.0;
445   for(i = 0 ;  i < ft->n_valid ; ++i)
446     {
447       f = &ft->valid[i];
448       ft->valid_cases += f->count;
449
450     }
451
452   ft->total_cases = ft->valid_cases ;
453   for(i = 0 ;  i < ft->n_missing ; ++i)
454     {
455       f = &ft->missing[i];
456       ft->total_cases += f->count;
457     }
458
459 }
460
461 /* Frees the frequency table for variable V. */
462 static void
463 cleanup_freq_tab (struct var_freqs *vf)
464 {
465   free (vf->tab.valid);
466   freq_hmap_destroy (&vf->tab.data, vf->width);
467 }
468
469 /* Add data from case C to the frequency table. */
470 static void
471 calc (struct frq_proc *frq, const struct ccase *c, const struct dataset *ds)
472 {
473   double weight = dict_get_case_weight (dataset_dict (ds), c, &frq->warn);
474   size_t i;
475
476   for (i = 0; i < frq->n_vars; i++)
477     {
478       struct var_freqs *vf = &frq->vars[i];
479       const union value *value = case_data (c, vf->var);
480       size_t hash = value_hash (value, vf->width, 0);
481       struct freq *f;
482
483       f = freq_hmap_search (&vf->tab.data, value, vf->width, hash);
484       if (f == NULL)
485         f = freq_hmap_insert (&vf->tab.data, value, vf->width, hash);
486
487       f->count += weight;
488     }
489 }
490
491 /* Prepares each variable that is the target of FREQUENCIES by setting
492    up its hash table. */
493 static void
494 precalc (struct frq_proc *frq, struct casereader *input, struct dataset *ds)
495 {
496   struct ccase *c;
497   size_t i;
498
499   c = casereader_peek (input, 0);
500   if (c != NULL)
501     {
502       output_split_file_values (ds, c);
503       case_unref (c);
504     }
505
506   for (i = 0; i < frq->n_vars; i++)
507     hmap_init (&frq->vars[i].tab.data);
508 }
509
510 /* Finishes up with the variables after frequencies have been
511    calculated.  Displays statistics, percentiles, ... */
512 static void
513 postcalc (struct frq_proc *frq, const struct dataset *ds)
514 {
515   const struct dictionary *dict = dataset_dict (ds);
516   const struct variable *wv = dict_get_weight (dict);
517   size_t i;
518
519   for (i = 0; i < frq->n_vars; i++)
520     {
521       struct var_freqs *vf = &frq->vars[i];
522       postprocess_freq_tab (frq, vf);
523       calc_percentiles (frq, vf);
524     }
525
526   if (frq->n_stats)
527     dump_statistics (frq, wv);
528
529   for (i = 0; i < frq->n_vars; i++)
530     {
531       struct var_freqs *vf = &frq->vars[i];
532
533       /* Frequencies tables. */
534       if (vf->tab.n_valid + vf->tab.n_missing <= frq->max_categories)
535         dump_freq_table (vf, wv);
536
537
538       if (frq->hist && var_is_numeric (vf->var) && vf->tab.n_valid > 0)
539         {
540           double d[FRQ_ST_count];
541           struct histogram *histogram;
542
543           calc_stats (frq, vf, d);
544
545           histogram = freq_tab_to_hist (frq, &vf->tab, vf->var);
546
547           if (histogram)
548             {
549               chart_submit (histogram_chart_create (
550                               histogram->gsl_hist, var_to_string(vf->var),
551                               vf->tab.valid_cases,
552                               d[FRQ_ST_MEAN],
553                               d[FRQ_ST_STDDEV],
554                               frq->hist->draw_normal));
555
556               statistic_destroy (&histogram->parent);
557             }
558         }
559
560       if (frq->pie)
561         do_piechart(frq->pie, vf->var, &vf->tab);
562
563       if (frq->bar)
564         do_barchart(frq->bar, &vf->var, &vf->tab);
565
566       cleanup_freq_tab (vf);
567     }
568 }
569
570 int
571 cmd_frequencies (struct lexer *lexer, struct dataset *ds)
572 {
573   int i;
574   struct frq_proc frq;
575   const struct variable **vars = NULL;
576
577   bool sbc_barchart = false;
578   bool sbc_piechart = false;
579   bool sbc_histogram = false;
580
581   double pie_min = -DBL_MAX;
582   double pie_max = DBL_MAX;
583   bool pie_missing = true;
584
585   double bar_min = -DBL_MAX;
586   double bar_max = DBL_MAX;
587   bool bar_freq = true;
588
589   double hi_min = -DBL_MAX;
590   double hi_max = DBL_MAX;
591   int hi_scale = FRQ_FREQ;
592   int hi_freq = INT_MIN;
593   int hi_pcnt = INT_MIN;
594   int hi_norm = FRQ_NONORMAL;
595
596   frq.pool = pool_create ();
597   frq.sort = FRQ_AVALUE;
598
599   frq.vars = NULL;
600   frq.n_vars = 0;
601
602   frq.stats = BIT_INDEX (FRQ_ST_MEAN)
603     | BIT_INDEX (FRQ_ST_STDDEV)
604     | BIT_INDEX (FRQ_ST_MINIMUM)
605     | BIT_INDEX (FRQ_ST_MAXIMUM);
606
607   frq.n_stats = 4;
608
609   frq.max_categories = LONG_MAX;
610
611   frq.percentiles = NULL;
612   frq.n_percentiles = 0;
613
614   frq.hist = NULL;
615   frq.pie = NULL;
616   frq.bar = NULL;
617   frq.warn = true;
618
619
620   /* Accept an optional, completely pointless "/VARIABLES=" */
621   lex_match (lexer, T_SLASH);
622   if (lex_match_id  (lexer, "VARIABLES"))
623     {
624       if (! lex_force_match (lexer, T_EQUALS))
625         goto error;
626     }
627
628   if (!parse_variables_const (lexer, dataset_dict (ds),
629                               &vars,
630                               &frq.n_vars,
631                               PV_NO_DUPLICATE))
632     goto error;
633
634   frq.vars = xcalloc (frq.n_vars, sizeof (*frq.vars));
635   for (i = 0; i < frq.n_vars; ++i)
636     {
637       frq.vars[i].var = vars[i];
638       frq.vars[i].width = var_get_width (vars[i]);
639     }
640
641   while (lex_token (lexer) != T_ENDCMD)
642     {
643       lex_match (lexer, T_SLASH);
644
645       if (lex_match_id (lexer, "STATISTICS"))
646         {
647           frq.stats = BIT_INDEX (FRQ_ST_MEAN)
648             | BIT_INDEX (FRQ_ST_STDDEV)
649             | BIT_INDEX (FRQ_ST_MINIMUM)
650             | BIT_INDEX (FRQ_ST_MAXIMUM);
651
652           frq.n_stats = 4;
653
654           if (lex_match (lexer, T_EQUALS))
655             {
656               frq.n_stats = 0;
657               frq.stats = 0;
658             }
659
660           while (lex_token (lexer) != T_ENDCMD
661                  && lex_token (lexer) != T_SLASH)
662             {
663               if (lex_match_id (lexer, "DEFAULT"))
664                 {
665                   frq.stats = BIT_INDEX (FRQ_ST_MEAN)
666                     | BIT_INDEX (FRQ_ST_STDDEV)
667                     | BIT_INDEX (FRQ_ST_MINIMUM)
668                     | BIT_INDEX (FRQ_ST_MAXIMUM);
669
670                   frq.n_stats = 4;
671                 }
672               else if (lex_match_id (lexer, "MEAN"))
673                 {
674                   frq.stats |= BIT_INDEX (FRQ_ST_MEAN);
675                   frq.n_stats++;
676                 }
677               else if (lex_match_id (lexer, "SEMEAN"))
678                 {
679                   frq.stats |= BIT_INDEX (FRQ_ST_SEMEAN);
680                   frq.n_stats++;
681                 }
682               else if (lex_match_id (lexer, "MEDIAN"))
683                 {
684                   frq.stats |= BIT_INDEX (FRQ_ST_MEDIAN);
685                   frq.n_stats++;
686                 }
687               else if (lex_match_id (lexer, "MODE"))
688                 {
689                   frq.stats |= BIT_INDEX (FRQ_ST_MODE);
690                   frq.n_stats++;
691                 }
692               else if (lex_match_id (lexer, "STDDEV"))
693                 {
694                   frq.stats |= BIT_INDEX (FRQ_ST_STDDEV);
695                   frq.n_stats++;
696                 }
697               else if (lex_match_id (lexer, "VARIANCE"))
698                 {
699                   frq.stats |= BIT_INDEX (FRQ_ST_VARIANCE);
700                   frq.n_stats++;
701                 }
702               else if (lex_match_id (lexer, "KURTOSIS"))
703                 {
704                   frq.stats |= BIT_INDEX (FRQ_ST_KURTOSIS);
705                   frq.n_stats++;
706                 }
707               else if (lex_match_id (lexer, "SKEWNESS"))
708                 {
709                   frq.stats |= BIT_INDEX (FRQ_ST_SKEWNESS);
710                   frq.n_stats++;
711                 }
712               else if (lex_match_id (lexer, "RANGE"))
713                 {
714                   frq.stats |= BIT_INDEX (FRQ_ST_RANGE);
715                   frq.n_stats++;
716                 }
717               else if (lex_match_id (lexer, "MINIMUM"))
718                 {
719                   frq.stats |= BIT_INDEX (FRQ_ST_MINIMUM);
720                   frq.n_stats++;
721                 }
722               else if (lex_match_id (lexer, "MAXIMUM"))
723                 {
724                   frq.stats |= BIT_INDEX (FRQ_ST_MAXIMUM);
725                   frq.n_stats++;
726                 }
727               else if (lex_match_id (lexer, "SUM"))
728                 {
729                   frq.stats |= BIT_INDEX (FRQ_ST_SUM);
730                   frq.n_stats++;
731                 }
732               else if (lex_match_id (lexer, "SESKEWNESS"))
733                 {
734                   frq.stats |= BIT_INDEX (FRQ_ST_SESKEWNESS);
735                   frq.n_stats++;
736                 }
737               else if (lex_match_id (lexer, "SEKURTOSIS"))
738                 {
739                   frq.stats |= BIT_INDEX (FRQ_ST_SEKURTOSIS);
740                   frq.n_stats++;
741                 }
742               else if (lex_match_id (lexer, "NONE"))
743                 {
744                   frq.stats = 0;
745                   frq.n_stats = 0;
746                 }
747               else if (lex_match (lexer, T_ALL))
748                 {
749                   frq.stats = ~0;
750                   frq.n_stats = FRQ_ST_count;
751                 }
752               else
753                 {
754                   lex_error (lexer, NULL);
755                   goto error;
756                 }
757             }
758         }
759       else if (lex_match_id (lexer, "PERCENTILES"))
760         {
761           lex_match (lexer, T_EQUALS);
762           while (lex_token (lexer) != T_ENDCMD
763                  && lex_token (lexer) != T_SLASH)
764             {
765               if (lex_force_num (lexer))
766                 {
767                   frq.percentiles =
768                     xrealloc (frq.percentiles,
769                               (frq.n_percentiles + 1)
770                               * sizeof (*frq.percentiles));
771                   frq.percentiles[frq.n_percentiles].p = lex_number (lexer)  / 100.0;
772                   frq.percentiles[frq.n_percentiles].show = true;
773                   lex_get (lexer);
774                   frq.n_percentiles++;
775                 }
776               else
777                 {
778                   lex_error (lexer, NULL);
779                   goto error;
780                 }
781               lex_match (lexer, T_COMMA);
782             }
783         }
784       else if (lex_match_id (lexer, "FORMAT"))
785         {
786           lex_match (lexer, T_EQUALS);
787           while (lex_token (lexer) != T_ENDCMD
788                  && lex_token (lexer) != T_SLASH)
789             {
790               if (lex_match_id (lexer, "TABLE"))
791                 {
792                 }
793               else if (lex_match_id (lexer, "NOTABLE"))
794                 {
795                   frq.max_categories = 0;
796                 }
797               else if (lex_match_id (lexer, "LIMIT"))
798                 {
799                   if (!lex_force_match (lexer, T_LPAREN)
800                       || !lex_force_int_range (lexer, "LIMIT", 0, INT_MAX))
801                     goto error;
802
803                   frq.max_categories = lex_integer (lexer);
804                   lex_get (lexer);
805
806                   if (!lex_force_match (lexer, T_RPAREN))
807                     goto error;
808                 }
809               else if (lex_match_id (lexer, "AVALUE"))
810                 {
811                   frq.sort = FRQ_AVALUE;
812                 }
813               else if (lex_match_id (lexer, "DVALUE"))
814                 {
815                   frq.sort = FRQ_DVALUE;
816                 }
817               else if (lex_match_id (lexer, "AFREQ"))
818                 {
819                   frq.sort = FRQ_AFREQ;
820                 }
821               else if (lex_match_id (lexer, "DFREQ"))
822                 {
823                   frq.sort = FRQ_DFREQ;
824                 }
825               else
826                 {
827                   lex_error (lexer, NULL);
828                   goto error;
829                 }
830             }
831         }
832       else if (lex_match_id (lexer, "NTILES"))
833         {
834           lex_match (lexer, T_EQUALS);
835
836           if (lex_force_int_range (lexer, "NTILES", 0, INT_MAX))
837             {
838               int n = lex_integer (lexer);
839               lex_get (lexer);
840               for (int i = 0; i < n + 1; ++i)
841                 {
842                   frq.percentiles =
843                     xrealloc (frq.percentiles,
844                               (frq.n_percentiles + 1)
845                               * sizeof (*frq.percentiles));
846                   frq.percentiles[frq.n_percentiles].p =
847                     i / (double) n ;
848                   frq.percentiles[frq.n_percentiles].show = true;
849
850                   frq.n_percentiles++;
851                 }
852             }
853           else
854             {
855               lex_error (lexer, NULL);
856               goto error;
857             }
858         }
859       else if (lex_match_id (lexer, "ALGORITHM"))
860         {
861           lex_match (lexer, T_EQUALS);
862
863           if (lex_match_id (lexer, "COMPATIBLE"))
864             {
865               settings_set_cmd_algorithm (COMPATIBLE);
866             }
867           else if (lex_match_id (lexer, "ENHANCED"))
868             {
869               settings_set_cmd_algorithm (ENHANCED);
870             }
871           else
872             {
873               lex_error (lexer, NULL);
874               goto error;
875             }
876         }
877       else if (lex_match_id (lexer, "HISTOGRAM"))
878         {
879           lex_match (lexer, T_EQUALS);
880           sbc_histogram = true;
881
882           while (lex_token (lexer) != T_ENDCMD
883                  && lex_token (lexer) != T_SLASH)
884             {
885               if (lex_match_id (lexer, "NORMAL"))
886                 {
887                   hi_norm = FRQ_NORMAL;
888                 }
889               else if (lex_match_id (lexer, "NONORMAL"))
890                 {
891                   hi_norm = FRQ_NONORMAL;
892                 }
893               else if (lex_match_id (lexer, "FREQ"))
894                 {
895                   hi_scale = FRQ_FREQ;
896                   if (lex_match (lexer, T_LPAREN))
897                     {
898                       if (lex_force_int_range (lexer, "FREQ", 1, INT_MAX))
899                         {
900                           hi_freq = lex_integer (lexer);
901                           lex_get (lexer);
902                           if (! lex_force_match (lexer, T_RPAREN))
903                             goto error;
904                         }
905                     }
906                 }
907               else if (lex_match_id (lexer, "PERCENT"))
908                 {
909                   hi_scale = FRQ_PERCENT;
910                   if (lex_match (lexer, T_LPAREN))
911                     {
912                       if (lex_force_int_range (lexer, "PERCENT", 1, INT_MAX))
913                         {
914                           hi_pcnt = lex_integer (lexer);
915                           lex_get (lexer);
916                           if (! lex_force_match (lexer, T_RPAREN))
917                             goto error;
918                         }
919                     }
920                 }
921               else if (lex_match_id (lexer, "MINIMUM"))
922                 {
923                   if (! lex_force_match (lexer, T_LPAREN))
924                     goto error;
925                   if (lex_force_num (lexer))
926                     {
927                       hi_min = lex_number (lexer);
928                       lex_get (lexer);
929                     }
930                   if (! lex_force_match (lexer, T_RPAREN))
931                     goto error;
932                 }
933               else if (lex_match_id (lexer, "MAXIMUM"))
934                 {
935                   if (! lex_force_match (lexer, T_LPAREN))
936                     goto error;
937                   if (lex_force_num (lexer))
938                     {
939                       hi_max = lex_number (lexer);
940                       lex_get (lexer);
941                     }
942                   if (! lex_force_match (lexer, T_RPAREN))
943                     goto error;
944                 }
945               else
946                 {
947                   lex_error (lexer, NULL);
948                   goto error;
949                 }
950             }
951         }
952       else if (lex_match_id (lexer, "PIECHART"))
953         {
954           lex_match (lexer, T_EQUALS);
955           while (lex_token (lexer) != T_ENDCMD
956                  && lex_token (lexer) != T_SLASH)
957             {
958               if (lex_match_id (lexer, "MINIMUM"))
959                 {
960                   if (! lex_force_match (lexer, T_LPAREN))
961                     goto error;
962                   if (lex_force_num (lexer))
963                     {
964                       pie_min = lex_number (lexer);
965                       lex_get (lexer);
966                     }
967                   if (! lex_force_match (lexer, T_RPAREN))
968                     goto error;
969                 }
970               else if (lex_match_id (lexer, "MAXIMUM"))
971                 {
972                   if (! lex_force_match (lexer, T_LPAREN))
973                     goto error;
974                   if (lex_force_num (lexer))
975                     {
976                       pie_max = lex_number (lexer);
977                       lex_get (lexer);
978                     }
979                   if (! lex_force_match (lexer, T_RPAREN))
980                     goto error;
981                 }
982               else if (lex_match_id (lexer, "MISSING"))
983                 {
984                   pie_missing = true;
985                 }
986               else if (lex_match_id (lexer, "NOMISSING"))
987                 {
988                   pie_missing = false;
989                 }
990               else
991                 {
992                   lex_error (lexer, NULL);
993                   goto error;
994                 }
995             }
996           sbc_piechart = true;
997         }
998       else if (lex_match_id (lexer, "BARCHART"))
999         {
1000           lex_match (lexer, T_EQUALS);
1001           while (lex_token (lexer) != T_ENDCMD
1002                  && lex_token (lexer) != T_SLASH)
1003             {
1004               if (lex_match_id (lexer, "MINIMUM"))
1005                 {
1006                   if (! lex_force_match (lexer, T_LPAREN))
1007                     goto error;
1008                   if (lex_force_num (lexer))
1009                     {
1010                       bar_min = lex_number (lexer);
1011                       lex_get (lexer);
1012                     }
1013                   if (! lex_force_match (lexer, T_RPAREN))
1014                     goto error;
1015                 }
1016               else if (lex_match_id (lexer, "MAXIMUM"))
1017                 {
1018                   if (! lex_force_match (lexer, T_LPAREN))
1019                     goto error;
1020                   if (lex_force_num (lexer))
1021                     {
1022                       bar_max = lex_number (lexer);
1023                       lex_get (lexer);
1024                     }
1025                   if (! lex_force_match (lexer, T_RPAREN))
1026                     goto error;
1027                 }
1028               else if (lex_match_id (lexer, "FREQ"))
1029                 {
1030                   if (lex_match (lexer, T_LPAREN))
1031                     {
1032                       if (lex_force_num (lexer))
1033                         {
1034                           lex_number (lexer);
1035                           lex_get (lexer);
1036                         }
1037                       if (! lex_force_match (lexer, T_RPAREN))
1038                         goto error;
1039                     }
1040                   bar_freq = true;
1041                 }
1042               else if (lex_match_id (lexer, "PERCENT"))
1043                 {
1044                   if (lex_match (lexer, T_LPAREN))
1045                     {
1046                       if (lex_force_num (lexer))
1047                         {
1048                           lex_number (lexer);
1049                           lex_get (lexer);
1050                         }
1051                       if (! lex_force_match (lexer, T_RPAREN))
1052                         goto error;
1053                     }
1054                   bar_freq = false;
1055                 }
1056               else
1057                 {
1058                   lex_error (lexer, NULL);
1059                   goto error;
1060                 }
1061             }
1062           sbc_barchart = true;
1063         }
1064       else if (lex_match_id (lexer, "MISSING"))
1065         {
1066           lex_match (lexer, T_EQUALS);
1067
1068           while (lex_token (lexer) != T_ENDCMD
1069                  && lex_token (lexer) != T_SLASH)
1070             {
1071               if (lex_match_id (lexer, "EXCLUDE"))
1072                 {
1073                 }
1074               else if (lex_match_id (lexer, "INCLUDE"))
1075                 {
1076                 }
1077               else
1078                 {
1079                   lex_error (lexer, NULL);
1080                   goto error;
1081                 }
1082             }
1083         }
1084       else if (lex_match_id (lexer, "ORDER"))
1085         {
1086           lex_match (lexer, T_EQUALS);
1087           if (!lex_match_id (lexer, "ANALYSIS"))
1088             lex_match_id (lexer, "VARIABLE");
1089         }
1090       else
1091         {
1092           lex_error (lexer, NULL);
1093           goto error;
1094         }
1095     }
1096
1097   if (frq.stats & BIT_INDEX (FRQ_ST_MEDIAN))
1098     {
1099         frq.percentiles =
1100           xrealloc (frq.percentiles,
1101                     (frq.n_percentiles + 1)
1102                     * sizeof (*frq.percentiles));
1103
1104         frq.percentiles[frq.n_percentiles].p = 0.50;
1105         frq.percentiles[frq.n_percentiles].show = false;
1106
1107         frq.n_percentiles++;
1108     }
1109
1110
1111 /* Figure out which charts the user requested.  */
1112
1113   {
1114     if (sbc_histogram)
1115       {
1116         struct frq_chart *hist;
1117
1118         hist = frq.hist = xmalloc (sizeof *frq.hist);
1119         hist->x_min = hi_min;
1120         hist->x_max = hi_max;
1121         hist->y_scale = hi_scale;
1122         hist->y_max = hi_scale == FRQ_FREQ ? hi_freq : hi_pcnt;
1123         hist->draw_normal = hi_norm != FRQ_NONORMAL;
1124         hist->include_missing = false;
1125
1126         if (hist->x_min != SYSMIS && hist->x_max != SYSMIS
1127             && hist->x_min >= hist->x_max)
1128           {
1129             msg (SE, _("%s for histogram must be greater than or equal to %s, "
1130                        "but %s was specified as %.15g and %s as %.15g.  "
1131                        "%s and %s will be ignored."),
1132                  "MAX", "MIN",
1133                  "MIN", hist->x_min,
1134                  "MAX", hist->x_max,
1135                  "MIN", "MAX");
1136             hist->x_min = hist->x_max = SYSMIS;
1137           }
1138
1139         frq.percentiles =
1140           xrealloc (frq.percentiles,
1141                     (frq.n_percentiles + 2)
1142                     * sizeof (*frq.percentiles));
1143
1144         frq.percentiles[frq.n_percentiles].p = 0.25;
1145         frq.percentiles[frq.n_percentiles].show = false;
1146
1147         frq.percentiles[frq.n_percentiles + 1].p = 0.75;
1148         frq.percentiles[frq.n_percentiles + 1].show = false;
1149
1150         frq.n_percentiles+=2;
1151       }
1152
1153     if (sbc_barchart)
1154       {
1155         frq.bar = xmalloc (sizeof *frq.bar);
1156         frq.bar->x_min = bar_min;
1157         frq.bar->x_max = bar_max;
1158         frq.bar->include_missing = false;
1159         frq.bar->y_scale = bar_freq ? FRQ_FREQ : FRQ_PERCENT;
1160       }
1161
1162     if (sbc_piechart)
1163       {
1164         struct frq_chart *pie;
1165
1166         pie = frq.pie = xmalloc (sizeof *frq.pie);
1167         pie->x_min = pie_min;
1168         pie->x_max = pie_max;
1169         pie->include_missing = pie_missing;
1170
1171         if (pie->x_min != SYSMIS && pie->x_max != SYSMIS
1172             && pie->x_min >= pie->x_max)
1173           {
1174             msg (SE, _("%s for pie chart must be greater than or equal to %s, "
1175                        "but %s was specified as %.15g and %s as %.15g.  "
1176                        "%s and %s will be ignored."),
1177                  "MAX", "MIN",
1178                  "MIN", pie->x_min,
1179                  "MAX", pie->x_max,
1180                  "MIN", "MAX");
1181             pie->x_min = pie->x_max = SYSMIS;
1182           }
1183       }
1184   }
1185
1186   {
1187     int i,o;
1188     double previous_p = -1;
1189     qsort (frq.percentiles, frq.n_percentiles,
1190            sizeof (*frq.percentiles),
1191            ptile_3way);
1192
1193     for (i = o = 0; i < frq.n_percentiles; ++i)
1194       {
1195         if (frq.percentiles[i].p != previous_p)
1196           {
1197             frq.percentiles[o].p = frq.percentiles[i].p;
1198             frq.percentiles[o].show = frq.percentiles[i].show;
1199             o++;
1200           }
1201         else if (frq.percentiles[i].show &&
1202                  !frq.percentiles[o].show)
1203           {
1204             frq.percentiles[o].show = true;
1205           }
1206         previous_p = frq.percentiles[i].p;
1207       }
1208
1209     frq.n_percentiles = o;
1210
1211     frq.median = NULL;
1212     for (i = 0; i < frq.n_percentiles; i++)
1213       if (frq.percentiles[i].p == 0.5)
1214         {
1215           frq.median = &frq.percentiles[i];
1216           break;
1217         }
1218   }
1219
1220   {
1221     struct casegrouper *grouper;
1222     struct casereader *group;
1223     bool ok;
1224
1225     grouper = casegrouper_create_splits (proc_open (ds), dataset_dict (ds));
1226     while (casegrouper_get_next_group (grouper, &group))
1227       {
1228         struct ccase *c;
1229         precalc (&frq, group, ds);
1230
1231         for (; (c = casereader_read (group)) != NULL; case_unref (c))
1232           calc (&frq, c, ds);
1233         postcalc (&frq, ds);
1234         casereader_destroy (group);
1235       }
1236     ok = casegrouper_destroy (grouper);
1237     ok = proc_commit (ds) && ok;
1238   }
1239
1240
1241   free (vars);
1242   free (frq.vars);
1243   free (frq.bar);
1244   free (frq.pie);
1245   free (frq.hist);
1246   free (frq.percentiles);
1247   pool_destroy (frq.pool);
1248
1249   return CMD_SUCCESS;
1250
1251  error:
1252
1253   free (vars);
1254   free (frq.vars);
1255   free (frq.bar);
1256   free (frq.pie);
1257   free (frq.hist);
1258   free (frq.percentiles);
1259   pool_destroy (frq.pool);
1260
1261   return CMD_FAILURE;
1262 }
1263
1264 static double
1265 calculate_iqr (const struct frq_proc *frq)
1266 {
1267   double q1 = SYSMIS;
1268   double q3 = SYSMIS;
1269   int i;
1270
1271   /* This cannot work unless the 25th and 75th percentile are calculated */
1272   assert (frq->n_percentiles >= 2);
1273   for (i = 0; i < frq->n_percentiles; i++)
1274     {
1275       struct percentile *pc = &frq->percentiles[i];
1276
1277       if (fabs (0.25 - pc->p) < DBL_EPSILON)
1278         q1 = pc->value;
1279       else if (fabs (0.75 - pc->p) < DBL_EPSILON)
1280         q3 = pc->value;
1281     }
1282
1283   return q1 == SYSMIS || q3 == SYSMIS ? SYSMIS : q3 - q1;
1284 }
1285
1286 static bool
1287 chart_includes_value (const struct frq_chart *chart,
1288                       const struct variable *var,
1289                       const union value *value)
1290 {
1291   if (!chart->include_missing && var_is_value_missing (var, value))
1292     return false;
1293
1294   if (var_is_numeric (var)
1295       && ((chart->x_min != SYSMIS && value->f < chart->x_min)
1296           || (chart->x_max != SYSMIS && value->f > chart->x_max)))
1297     return false;
1298
1299   return true;
1300 }
1301
1302 /* Create a gsl_histogram from a freq_tab */
1303 static struct histogram *
1304 freq_tab_to_hist (const struct frq_proc *frq, const struct freq_tab *ft,
1305                   const struct variable *var)
1306 {
1307   double x_min, x_max, valid_freq;
1308   int i;
1309   double bin_width;
1310   struct histogram *histogram;
1311   double iqr;
1312
1313   /* Find out the extremes of the x value, within the range to be included in
1314      the histogram, and sum the total frequency of those values. */
1315   x_min = DBL_MAX;
1316   x_max = -DBL_MAX;
1317   valid_freq = 0;
1318   for (i = 0; i < ft->n_valid; i++)
1319     {
1320       const struct freq *f = &ft->valid[i];
1321       if (chart_includes_value (frq->hist, var, f->values))
1322         {
1323           x_min = MIN (x_min, f->values[0].f);
1324           x_max = MAX (x_max, f->values[0].f);
1325           valid_freq += f->count;
1326         }
1327     }
1328
1329   if (valid_freq <= 0)
1330     return NULL;
1331
1332   iqr = calculate_iqr (frq);
1333
1334   if (iqr > 0)
1335     /* Freedman-Diaconis' choice of bin width. */
1336     bin_width = 2 * iqr / pow (valid_freq, 1.0 / 3.0);
1337
1338   else
1339     /* Sturges Rule */
1340     bin_width = (x_max - x_min) / (1 + log2 (valid_freq));
1341
1342   histogram = histogram_create (bin_width, x_min, x_max);
1343
1344   if (histogram == NULL)
1345     return NULL;
1346
1347   for (i = 0; i < ft->n_valid; i++)
1348     {
1349       const struct freq *f = &ft->valid[i];
1350       if (chart_includes_value (frq->hist, var, f->values))
1351         histogram_add (histogram, f->values[0].f, f->count);
1352     }
1353
1354   return histogram;
1355 }
1356
1357
1358 /* Allocate an array of struct freqs and fill them from the data in FRQ_TAB,
1359    according to the parameters of CATCHART
1360    N_SLICES will contain the number of slices allocated.
1361    The caller is responsible for freeing slices
1362 */
1363 static struct freq *
1364 pick_cat_counts (const struct frq_chart *catchart,
1365                  const struct freq_tab *frq_tab,
1366                  int *n_slicesp)
1367 {
1368   int n_slices = 0;
1369   int i;
1370   struct freq *slices = xnmalloc (frq_tab->n_valid + frq_tab->n_missing, sizeof *slices);
1371
1372   for (i = 0; i < frq_tab->n_valid; i++)
1373     {
1374       const struct freq *f = &frq_tab->valid[i];
1375       if (f->count > catchart->x_max)
1376         continue;
1377
1378       if (f->count < catchart->x_min)
1379         continue;
1380
1381       slices[n_slices] = *f;
1382
1383       n_slices++;
1384     }
1385
1386   if (catchart->include_missing)
1387     {
1388       for (i = 0; i < frq_tab->n_missing; i++)
1389         {
1390           const struct freq *f = &frq_tab->missing[i];
1391           slices[n_slices].count += f->count;
1392
1393           if (i == 0)
1394             slices[n_slices].values[0] = f->values[0];
1395         }
1396
1397       if (frq_tab->n_missing > 0)
1398         n_slices++;
1399     }
1400
1401   *n_slicesp = n_slices;
1402   return slices;
1403 }
1404
1405
1406 /* Allocate an array of struct freqs and fill them from the data in FRQ_TAB,
1407    according to the parameters of CATCHART
1408    N_SLICES will contain the number of slices allocated.
1409    The caller is responsible for freeing slices
1410 */
1411 static struct freq **
1412 pick_cat_counts_ptr (const struct frq_chart *catchart,
1413                      const struct freq_tab *frq_tab,
1414                      int *n_slicesp)
1415 {
1416   int n_slices = 0;
1417   int i;
1418   struct freq **slices = xnmalloc (frq_tab->n_valid + frq_tab->n_missing, sizeof *slices);
1419
1420   for (i = 0; i < frq_tab->n_valid; i++)
1421     {
1422       struct freq *f = &frq_tab->valid[i];
1423       if (f->count > catchart->x_max)
1424         continue;
1425
1426       if (f->count < catchart->x_min)
1427         continue;
1428
1429       slices[n_slices] = f;
1430
1431       n_slices++;
1432     }
1433
1434   if (catchart->include_missing)
1435     {
1436       for (i = 0; i < frq_tab->n_missing; i++)
1437         {
1438           const struct freq *f = &frq_tab->missing[i];
1439           if (i == 0)
1440             {
1441               slices[n_slices] = xmalloc (sizeof (struct freq));
1442               slices[n_slices]->values[0] = f->values[0];
1443             }
1444
1445           slices[n_slices]->count += f->count;
1446
1447         }
1448     }
1449
1450   *n_slicesp = n_slices;
1451   return slices;
1452 }
1453
1454
1455
1456 static void
1457 do_piechart(const struct frq_chart *pie, const struct variable *var,
1458             const struct freq_tab *frq_tab)
1459 {
1460   int n_slices;
1461   struct freq *slices = pick_cat_counts (pie, frq_tab, &n_slices);
1462
1463   if (n_slices < 2)
1464     msg (SW, _("Omitting pie chart for %s, which has only %d unique values."),
1465          var_get_name (var), n_slices);
1466   else if (n_slices > 50)
1467     msg (SW, _("Omitting pie chart for %s, which has over 50 unique values."),
1468          var_get_name (var));
1469   else
1470     chart_submit (piechart_create (var, slices, n_slices));
1471
1472   free (slices);
1473 }
1474
1475
1476 static void
1477 do_barchart(const struct frq_chart *bar, const struct variable **var,
1478             const struct freq_tab *frq_tab)
1479 {
1480   int n_slices;
1481   struct freq **slices = pick_cat_counts_ptr (bar, frq_tab, &n_slices);
1482
1483   if (n_slices < 1)
1484     msg (SW, _("Omitting bar chart, which has no values."));
1485   else
1486     chart_submit (barchart_create (var, 1,
1487                                    (bar->y_scale == FRQ_FREQ) ? _("Count") : _("Percent"),
1488                                    (bar->y_scale == FRQ_PERCENT),
1489                                    slices, n_slices));
1490   free (slices);
1491 }
1492
1493
1494 /* Calculates all the pertinent statistics for VF, putting them in array
1495    D[]. */
1496 static void
1497 calc_stats (const struct frq_proc *frq, const struct var_freqs *vf,
1498             double d[FRQ_ST_count])
1499 {
1500   const struct freq_tab *ft = &vf->tab;
1501   double W = ft->valid_cases;
1502   const struct freq *f;
1503   struct moments *m;
1504   int most_often = -1;
1505   double X_mode = SYSMIS;
1506
1507   /* Calculate the mode. */
1508   for (f = ft->valid; f < ft->missing; f++)
1509     {
1510       if (most_often < f->count)
1511         {
1512           most_often = f->count;
1513           X_mode = f->values[0].f;
1514         }
1515       else if (most_often == f->count)
1516         {
1517           /* A duplicate mode is undefined.
1518              FIXME: keep track of *all* the modes. */
1519           X_mode = SYSMIS;
1520         }
1521     }
1522
1523   /* Calculate moments. */
1524   m = moments_create (MOMENT_KURTOSIS);
1525   for (f = ft->valid; f < ft->missing; f++)
1526     moments_pass_one (m, f->values[0].f, f->count);
1527   for (f = ft->valid; f < ft->missing; f++)
1528     moments_pass_two (m, f->values[0].f, f->count);
1529   moments_calculate (m, NULL, &d[FRQ_ST_MEAN], &d[FRQ_ST_VARIANCE],
1530                      &d[FRQ_ST_SKEWNESS], &d[FRQ_ST_KURTOSIS]);
1531   moments_destroy (m);
1532
1533   /* Formulae below are taken from _SPSS Statistical Algorithms_. */
1534   if (ft->n_valid > 0)
1535     {
1536       d[FRQ_ST_MINIMUM] = ft->valid[0].values[0].f;
1537       d[FRQ_ST_MAXIMUM] = ft->valid[ft->n_valid - 1].values[0].f;
1538       d[FRQ_ST_RANGE] = d[FRQ_ST_MAXIMUM] - d[FRQ_ST_MINIMUM];
1539     }
1540   else
1541     {
1542       d[FRQ_ST_MINIMUM] = SYSMIS;
1543       d[FRQ_ST_MAXIMUM] = SYSMIS;
1544       d[FRQ_ST_RANGE] = SYSMIS;
1545     }
1546   d[FRQ_ST_MODE] = X_mode;
1547   d[FRQ_ST_SUM] = d[FRQ_ST_MEAN] * W;
1548   d[FRQ_ST_STDDEV] = sqrt (d[FRQ_ST_VARIANCE]);
1549   d[FRQ_ST_SEMEAN] = d[FRQ_ST_STDDEV] / sqrt (W);
1550   d[FRQ_ST_SESKEWNESS] = calc_seskew (W);
1551   d[FRQ_ST_SEKURTOSIS] = calc_sekurt (W);
1552   d[FRQ_ST_MEDIAN] = frq->median ? frq->median->value : SYSMIS;
1553 }
1554
1555 static bool
1556 all_string_variables (const struct frq_proc *frq)
1557 {
1558   for (size_t i = 0; i < frq->n_vars; i++)
1559     if (var_is_numeric (frq->vars[i].var))
1560       return false;
1561
1562   return true;
1563 }
1564
1565 /* Displays a table of all the statistics requested. */
1566 static void
1567 dump_statistics (const struct frq_proc *frq, const struct variable *wv)
1568 {
1569   if (all_string_variables (frq))
1570     return;
1571
1572   struct pivot_table *table = pivot_table_create (N_("Statistics"));
1573   pivot_table_set_weight_var (table, wv);
1574
1575   struct pivot_dimension *variables
1576     = pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Variables"));
1577
1578   struct pivot_dimension *statistics = pivot_dimension_create (
1579     table, PIVOT_AXIS_ROW, N_("Statistics"));
1580   struct pivot_category *n = pivot_category_create_group (
1581     statistics->root, N_("N"));
1582   pivot_category_create_leaves (n,
1583                                 N_("Valid"), PIVOT_RC_COUNT,
1584                                 N_("Missing"), PIVOT_RC_COUNT);
1585   for (int i = 0; i < FRQ_ST_count; i++)
1586     if (frq->stats & BIT_INDEX (i))
1587       pivot_category_create_leaf (statistics->root,
1588                                   pivot_value_new_text (st_name[i]));
1589   struct pivot_category *percentiles = NULL;
1590   for (size_t i = 0; i < frq->n_percentiles; i++)
1591     {
1592       const struct percentile *pc = &frq->percentiles[i];
1593
1594       if (!pc->show)
1595         continue;
1596
1597       if (!percentiles)
1598         percentiles = pivot_category_create_group (
1599           statistics->root, N_("Percentiles"));
1600       pivot_category_create_leaf (percentiles, pivot_value_new_integer (
1601                                     pc->p * 100.0));
1602     }
1603
1604   for (size_t i = 0; i < frq->n_vars; i++)
1605     {
1606       struct var_freqs *vf = &frq->vars[i];
1607       if (var_is_alpha (vf->var))
1608         continue;
1609
1610       const struct freq_tab *ft = &vf->tab;
1611
1612       int var_idx = pivot_category_create_leaf (
1613         variables->root, pivot_value_new_variable (vf->var));
1614
1615       int row = 0;
1616       pivot_table_put2 (table, var_idx, row++,
1617                         pivot_value_new_number (ft->valid_cases));
1618       pivot_table_put2 (table, var_idx, row++,
1619                         pivot_value_new_number (
1620                           ft->total_cases - ft->valid_cases));
1621
1622       double stat_values[FRQ_ST_count];
1623       calc_stats (frq, vf, stat_values);
1624       for (int j = 0; j < FRQ_ST_count; j++)
1625         {
1626           if (!(frq->stats & BIT_INDEX (j)))
1627             continue;
1628
1629           union value v = { .f = vf->tab.n_valid ? stat_values[j] : SYSMIS };
1630           struct pivot_value *pv
1631             = (j == FRQ_ST_MODE || j == FRQ_ST_MINIMUM || j == FRQ_ST_MAXIMUM
1632                ? pivot_value_new_var_value (vf->var, &v)
1633                : pivot_value_new_number (v.f));
1634           pivot_table_put2 (table, var_idx, row++, pv);
1635         }
1636
1637       for (size_t j = 0; j < frq->n_percentiles; j++)
1638         {
1639           const struct percentile *pc = &frq->percentiles[j];
1640           if (!pc->show)
1641             continue;
1642
1643           union value v = { .f = vf->tab.n_valid ? pc->value : SYSMIS };
1644           pivot_table_put2 (table, var_idx, row++,
1645                             pivot_value_new_var_value (vf->var, &v));
1646         }
1647     }
1648
1649   pivot_table_submit (table);
1650 }