c217310910271f2639830eb09d44b2fcdffd69db
[pspp-builds.git] / src / language / stats / aggregate.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2006, 2008, 2009 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include <stdlib.h>
20
21 #include <data/any-writer.h>
22 #include <data/case.h>
23 #include <data/casegrouper.h>
24 #include <data/casereader.h>
25 #include <data/casewriter.h>
26 #include <data/dictionary.h>
27 #include <data/file-handle-def.h>
28 #include <data/format.h>
29 #include <data/procedure.h>
30 #include <data/settings.h>
31 #include <data/subcase.h>
32 #include <data/sys-file-writer.h>
33 #include <data/variable.h>
34 #include <language/command.h>
35 #include <language/data-io/file-handle.h>
36 #include <language/lexer/lexer.h>
37 #include <language/lexer/variable-parser.h>
38 #include <language/stats/sort-criteria.h>
39 #include <libpspp/assertion.h>
40 #include <libpspp/message.h>
41 #include <libpspp/misc.h>
42 #include <libpspp/pool.h>
43 #include <libpspp/str.h>
44 #include <math/moments.h>
45 #include <math/sort.h>
46 #include <math/statistic.h>
47 #include <math/percentiles.h>
48
49 #include "minmax.h"
50 #include "xalloc.h"
51
52 #include "gettext.h"
53 #define _(msgid) gettext (msgid)
54
55 /* Argument for AGGREGATE function. */
56 union agr_argument
57   {
58     double f;                           /* Numeric. */
59     char *c;                            /* Short or long string. */
60   };
61
62 /* Specifies how to make an aggregate variable. */
63 struct agr_var
64   {
65     struct agr_var *next;               /* Next in list. */
66
67     /* Collected during parsing. */
68     const struct variable *src; /* Source variable. */
69     struct variable *dest;      /* Target variable. */
70     int function;               /* Function. */
71     enum mv_class exclude;      /* Classes of missing values to exclude. */
72     union agr_argument arg[2];  /* Arguments. */
73
74     /* Accumulated during AGGREGATE execution. */
75     double dbl[3];
76     int int1, int2;
77     char *string;
78     bool saw_missing;
79     struct moments1 *moments;
80     double cc;
81
82     struct variable *subject;
83     struct variable *weight;
84     struct casewriter *writer;
85   };
86
87 /* Aggregation functions. */
88 enum
89   {
90     NONE, SUM, MEAN, MEDIAN, SD, MAX, MIN, PGT, PLT, PIN, POUT, FGT, FLT, FIN,
91     FOUT, N, NU, NMISS, NUMISS, FIRST, LAST,
92     N_AGR_FUNCS, N_NO_VARS, NU_NO_VARS,
93     FUNC = 0x1f, /* Function mask. */
94     FSTRING = 1<<5, /* String function bit. */
95   };
96
97 /* Attributes of an aggregation function. */
98 struct agr_func
99   {
100     const char *name;           /* Aggregation function name. */
101     size_t n_args;              /* Number of arguments. */
102     enum val_type alpha_type;   /* When given ALPHA arguments, output type. */
103     struct fmt_spec format;     /* Format spec if alpha_type != ALPHA. */
104   };
105
106 /* Attributes of aggregation functions. */
107 static const struct agr_func agr_func_tab[] =
108   {
109     {"<NONE>",  0, -1,          {0, 0, 0}},
110     {"SUM",     0, -1,          {FMT_F, 8, 2}},
111     {"MEAN",    0, -1,          {FMT_F, 8, 2}},
112     {"MEDIAN",  0, -1,          {FMT_F, 8, 2}},
113     {"SD",      0, -1,          {FMT_F, 8, 2}},
114     {"MAX",     0, VAL_STRING,  {-1, -1, -1}},
115     {"MIN",     0, VAL_STRING,  {-1, -1, -1}},
116     {"PGT",     1, VAL_NUMERIC, {FMT_F, 5, 1}},
117     {"PLT",     1, VAL_NUMERIC, {FMT_F, 5, 1}},
118     {"PIN",     2, VAL_NUMERIC, {FMT_F, 5, 1}},
119     {"POUT",    2, VAL_NUMERIC, {FMT_F, 5, 1}},
120     {"FGT",     1, VAL_NUMERIC, {FMT_F, 5, 3}},
121     {"FLT",     1, VAL_NUMERIC, {FMT_F, 5, 3}},
122     {"FIN",     2, VAL_NUMERIC, {FMT_F, 5, 3}},
123     {"FOUT",    2, VAL_NUMERIC, {FMT_F, 5, 3}},
124     {"N",       0, VAL_NUMERIC, {FMT_F, 7, 0}},
125     {"NU",      0, VAL_NUMERIC, {FMT_F, 7, 0}},
126     {"NMISS",   0, VAL_NUMERIC, {FMT_F, 7, 0}},
127     {"NUMISS",  0, VAL_NUMERIC, {FMT_F, 7, 0}},
128     {"FIRST",   0, VAL_STRING,  {-1, -1, -1}},
129     {"LAST",    0, VAL_STRING,  {-1, -1, -1}},
130     {NULL,      0, -1,          {-1, -1, -1}},
131     {"N",       0, VAL_NUMERIC, {FMT_F, 7, 0}},
132     {"NU",      0, VAL_NUMERIC, {FMT_F, 7, 0}},
133   };
134
135 /* Missing value types. */
136 enum missing_treatment
137   {
138     ITEMWISE,           /* Missing values item by item. */
139     COLUMNWISE          /* Missing values column by column. */
140   };
141
142 /* An entire AGGREGATE procedure. */
143 struct agr_proc
144   {
145     /* Break variables. */
146     struct subcase sort;                /* Sort criteria (break variables). */
147     const struct variable **break_vars;       /* Break variables. */
148     size_t break_var_cnt;               /* Number of break variables. */
149     struct ccase *break_case;           /* Last values of break variables. */
150
151     enum missing_treatment missing;     /* How to treat missing values. */
152     struct agr_var *agr_vars;           /* First aggregate variable. */
153     struct dictionary *dict;            /* Aggregate dictionary. */
154     const struct dictionary *src_dict;  /* Dict of the source */
155     int case_cnt;                       /* Counts aggregated cases. */
156   };
157
158 static void initialize_aggregate_info (struct agr_proc *,
159                                        const struct ccase *);
160
161 static void accumulate_aggregate_info (struct agr_proc *,
162                                        const struct ccase *);
163 /* Prototypes. */
164 static bool parse_aggregate_functions (struct lexer *, const struct dictionary *,
165                                        struct agr_proc *);
166 static void agr_destroy (struct agr_proc *);
167 static void dump_aggregate_info (struct agr_proc *agr,
168                                  struct casewriter *output);
169 \f
170 /* Parsing. */
171
172 /* Parses and executes the AGGREGATE procedure. */
173 int
174 cmd_aggregate (struct lexer *lexer, struct dataset *ds)
175 {
176   struct dictionary *dict = dataset_dict (ds);
177   struct agr_proc agr;
178   struct file_handle *out_file = NULL;
179   struct casereader *input = NULL, *group;
180   struct casegrouper *grouper;
181   struct casewriter *output = NULL;
182
183   bool copy_documents = false;
184   bool presorted = false;
185   bool saw_direction;
186   bool ok;
187
188   memset(&agr, 0 , sizeof (agr));
189   agr.missing = ITEMWISE;
190   agr.break_case = NULL;
191
192   agr.dict = dict_create ();
193   agr.src_dict = dict;
194   subcase_init_empty (&agr.sort);
195   dict_set_label (agr.dict, dict_get_label (dict));
196   dict_set_documents (agr.dict, dict_get_documents (dict));
197
198   /* OUTFILE subcommand must be first. */
199   if (!lex_force_match_id (lexer, "OUTFILE"))
200     goto error;
201   lex_match (lexer, '=');
202   if (!lex_match (lexer, '*'))
203     {
204       out_file = fh_parse (lexer, FH_REF_FILE | FH_REF_SCRATCH);
205       if (out_file == NULL)
206         goto error;
207     }
208
209   /* Read most of the subcommands. */
210   for (;;)
211     {
212       lex_match (lexer, '/');
213
214       if (lex_match_id (lexer, "MISSING"))
215         {
216           lex_match (lexer, '=');
217           if (!lex_match_id (lexer, "COLUMNWISE"))
218             {
219               lex_error (lexer, _("while expecting COLUMNWISE"));
220               goto error;
221             }
222           agr.missing = COLUMNWISE;
223         }
224       else if (lex_match_id (lexer, "DOCUMENT"))
225         copy_documents = true;
226       else if (lex_match_id (lexer, "PRESORTED"))
227         presorted = true;
228       else if (lex_match_id (lexer, "BREAK"))
229         {
230           int i;
231
232           lex_match (lexer, '=');
233           if (!parse_sort_criteria (lexer, dict, &agr.sort, &agr.break_vars,
234                                     &saw_direction))
235             goto error;
236           agr.break_var_cnt = subcase_get_n_fields (&agr.sort);
237
238           for (i = 0; i < agr.break_var_cnt; i++)
239             dict_clone_var_assert (agr.dict, agr.break_vars[i],
240                                    var_get_name (agr.break_vars[i]));
241
242           /* BREAK must follow the options. */
243           break;
244         }
245       else
246         {
247           lex_error (lexer, _("expecting BREAK"));
248           goto error;
249         }
250     }
251   if (presorted && saw_direction)
252     msg (SW, _("When PRESORTED is specified, specifying sorting directions "
253                "with (A) or (D) has no effect.  Output data will be sorted "
254                "the same way as the input data."));
255
256   /* Read in the aggregate functions. */
257   lex_match (lexer, '/');
258   if (!parse_aggregate_functions (lexer, dict, &agr))
259     goto error;
260
261   /* Delete documents. */
262   if (!copy_documents)
263     dict_clear_documents (agr.dict);
264
265   /* Cancel SPLIT FILE. */
266   dict_set_split_vars (agr.dict, NULL, 0);
267
268   /* Initialize. */
269   agr.case_cnt = 0;
270
271   if (out_file == NULL)
272     {
273       /* The active file will be replaced by the aggregated data,
274          so TEMPORARY is moot. */
275       proc_cancel_temporary_transformations (ds);
276       proc_discard_output (ds);
277       output = autopaging_writer_create (dict_get_next_value_idx (agr.dict));
278     }
279   else
280     {
281       output = any_writer_open (out_file, agr.dict);
282       if (output == NULL)
283         goto error;
284     }
285
286   input = proc_open (ds);
287   if (!subcase_is_empty (&agr.sort) && !presorted)
288     {
289       input = sort_execute (input, &agr.sort);
290       subcase_clear (&agr.sort);
291     }
292
293   for (grouper = casegrouper_create_vars (input, agr.break_vars,
294                                           agr.break_var_cnt);
295        casegrouper_get_next_group (grouper, &group);
296        casereader_destroy (group))
297     {
298       struct ccase *c = casereader_peek (group, 0);
299       if (c == NULL)
300         {
301           casereader_destroy (group);
302           continue;
303         }
304       initialize_aggregate_info (&agr, c);
305       case_unref (c);
306
307       for (; (c = casereader_read (group)) != NULL; case_unref (c))
308         accumulate_aggregate_info (&agr, c);
309       dump_aggregate_info (&agr, output);
310     }
311   if (!casegrouper_destroy (grouper))
312     goto error;
313
314   if (!proc_commit (ds))
315     {
316       input = NULL;
317       goto error;
318     }
319   input = NULL;
320
321   if (out_file == NULL)
322     {
323       struct casereader *next_input = casewriter_make_reader (output);
324       if (next_input == NULL)
325         goto error;
326
327       proc_set_active_file (ds, next_input, agr.dict);
328       agr.dict = NULL;
329     }
330   else
331     {
332       ok = casewriter_destroy (output);
333       output = NULL;
334       if (!ok)
335         goto error;
336     }
337
338   agr_destroy (&agr);
339   fh_unref (out_file);
340   return CMD_SUCCESS;
341
342 error:
343   if (input != NULL)
344     proc_commit (ds);
345   casewriter_destroy (output);
346   agr_destroy (&agr);
347   fh_unref (out_file);
348   return CMD_CASCADING_FAILURE;
349 }
350
351 /* Parse all the aggregate functions. */
352 static bool
353 parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict,
354                            struct agr_proc *agr)
355 {
356   struct agr_var *tail; /* Tail of linked list starting at agr->vars. */
357
358   /* Parse everything. */
359   tail = NULL;
360   for (;;)
361     {
362       char **dest;
363       char **dest_label;
364       size_t n_dest;
365       struct string function_name;
366
367       enum mv_class exclude;
368       const struct agr_func *function;
369       int func_index;
370
371       union agr_argument arg[2];
372
373       const struct variable **src;
374       size_t n_src;
375
376       size_t i;
377
378       dest = NULL;
379       dest_label = NULL;
380       n_dest = 0;
381       src = NULL;
382       function = NULL;
383       n_src = 0;
384       arg[0].c = NULL;
385       arg[1].c = NULL;
386       ds_init_empty (&function_name);
387
388       /* Parse the list of target variables. */
389       while (!lex_match (lexer, '='))
390         {
391           size_t n_dest_prev = n_dest;
392
393           if (!parse_DATA_LIST_vars (lexer, &dest, &n_dest,
394                                      PV_APPEND | PV_SINGLE | PV_NO_SCRATCH))
395             goto error;
396
397           /* Assign empty labels. */
398           {
399             int j;
400
401             dest_label = xnrealloc (dest_label, n_dest, sizeof *dest_label);
402             for (j = n_dest_prev; j < n_dest; j++)
403               dest_label[j] = NULL;
404           }
405
406
407
408           if (lex_token (lexer) == T_STRING)
409             {
410               struct string label;
411               ds_init_string (&label, lex_tokstr (lexer));
412
413               ds_truncate (&label, 255);
414               dest_label[n_dest - 1] = ds_xstrdup (&label);
415               lex_get (lexer);
416               ds_destroy (&label);
417             }
418         }
419
420       /* Get the name of the aggregation function. */
421       if (lex_token (lexer) != T_ID)
422         {
423           lex_error (lexer, _("expecting aggregation function"));
424           goto error;
425         }
426
427       exclude = MV_ANY;
428
429       ds_assign_string (&function_name, lex_tokstr (lexer));
430
431       ds_chomp (&function_name, '.');
432
433       if (lex_tokid(lexer)[strlen (lex_tokid (lexer)) - 1] == '.')
434         exclude = MV_SYSTEM;
435
436       for (function = agr_func_tab; function->name; function++)
437         if (!strcasecmp (function->name, ds_cstr (&function_name)))
438           break;
439       if (NULL == function->name)
440         {
441           msg (SE, _("Unknown aggregation function %s."),
442                ds_cstr (&function_name));
443           goto error;
444         }
445       ds_destroy (&function_name);
446       func_index = function - agr_func_tab;
447       lex_get (lexer);
448
449       /* Check for leading lparen. */
450       if (!lex_match (lexer, '('))
451         {
452           if (func_index == N)
453             func_index = N_NO_VARS;
454           else if (func_index == NU)
455             func_index = NU_NO_VARS;
456           else
457             {
458               lex_error (lexer, _("expecting `('"));
459               goto error;
460             }
461         }
462       else
463         {
464           /* Parse list of source variables. */
465           {
466             int pv_opts = PV_NO_SCRATCH;
467
468             if (func_index == SUM || func_index == MEAN || func_index == SD)
469               pv_opts |= PV_NUMERIC;
470             else if (function->n_args)
471               pv_opts |= PV_SAME_TYPE;
472
473             if (!parse_variables_const (lexer, dict, &src, &n_src, pv_opts))
474               goto error;
475           }
476
477           /* Parse function arguments, for those functions that
478              require arguments. */
479           if (function->n_args != 0)
480             for (i = 0; i < function->n_args; i++)
481               {
482                 int type;
483
484                 lex_match (lexer, ',');
485                 if (lex_token (lexer) == T_STRING)
486                   {
487                     arg[i].c = ds_xstrdup (lex_tokstr (lexer));
488                     type = VAL_STRING;
489                   }
490                 else if (lex_is_number (lexer))
491                   {
492                     arg[i].f = lex_tokval (lexer);
493                     type = VAL_NUMERIC;
494                   }
495                 else
496                   {
497                     msg (SE, _("Missing argument %zu to %s."),
498                          i + 1, function->name);
499                     goto error;
500                   }
501
502                 lex_get (lexer);
503
504                 if (type != var_get_type (src[0]))
505                   {
506                     msg (SE, _("Arguments to %s must be of same type as "
507                                "source variables."),
508                          function->name);
509                     goto error;
510                   }
511               }
512
513           /* Trailing rparen. */
514           if (!lex_match (lexer, ')'))
515             {
516               lex_error (lexer, _("expecting `)'"));
517               goto error;
518             }
519
520           /* Now check that the number of source variables match
521              the number of target variables.  If we check earlier
522              than this, the user can get very misleading error
523              message, i.e. `AGGREGATE x=SUM(y t).' will get this
524              error message when a proper message would be more
525              like `unknown variable t'. */
526           if (n_src != n_dest)
527             {
528               msg (SE, _("Number of source variables (%zu) does not match "
529                          "number of target variables (%zu)."),
530                     n_src, n_dest);
531               goto error;
532             }
533
534           if ((func_index == PIN || func_index == POUT
535               || func_index == FIN || func_index == FOUT)
536               && (var_is_numeric (src[0])
537                   ? arg[0].f > arg[1].f
538                   : str_compare_rpad (arg[0].c, arg[1].c) > 0))
539             {
540               union agr_argument t = arg[0];
541               arg[0] = arg[1];
542               arg[1] = t;
543
544               msg (SW, _("The value arguments passed to the %s function "
545                          "are out-of-order.  They will be treated as if "
546                          "they had been specified in the correct order."),
547                    function->name);
548             }
549         }
550
551       /* Finally add these to the linked list of aggregation
552          variables. */
553       for (i = 0; i < n_dest; i++)
554         {
555           struct agr_var *v = xzalloc (sizeof *v);
556
557           /* Add variable to chain. */
558           if (agr->agr_vars != NULL)
559             tail->next = v;
560           else
561             agr->agr_vars = v;
562           tail = v;
563           tail->next = NULL;
564           v->moments = NULL;
565
566           /* Create the target variable in the aggregate
567              dictionary. */
568           {
569             struct variable *destvar;
570
571             v->function = func_index;
572
573             if (src)
574               {
575                 v->src = src[i];
576
577                 if (var_is_alpha (src[i]))
578                   {
579                     v->function |= FSTRING;
580                     v->string = xmalloc (var_get_width (src[i]));
581                   }
582
583                 if (function->alpha_type == VAL_STRING)
584                   destvar = dict_clone_var (agr->dict, v->src, dest[i]);
585                 else
586                   {
587                     assert (var_is_numeric (v->src)
588                             || function->alpha_type == VAL_NUMERIC);
589                     destvar = dict_create_var (agr->dict, dest[i], 0);
590                     if (destvar != NULL)
591                       {
592                         struct fmt_spec f;
593                         if ((func_index == N || func_index == NMISS)
594                             && dict_get_weight (dict) != NULL)
595                           f = fmt_for_output (FMT_F, 8, 2);
596                         else
597                           f = function->format;
598                         var_set_both_formats (destvar, &f);
599                       }
600                   }
601               } else {
602                 struct fmt_spec f;
603                 v->src = NULL;
604                 destvar = dict_create_var (agr->dict, dest[i], 0);
605                 if (func_index == N_NO_VARS && dict_get_weight (dict) != NULL)
606                   f = fmt_for_output (FMT_F, 8, 2);
607                 else
608                   f = function->format;
609                 var_set_both_formats (destvar, &f);
610               }
611
612             if (!destvar)
613               {
614                 msg (SE, _("Variable name %s is not unique within the "
615                            "aggregate file dictionary, which contains "
616                            "the aggregate variables and the break "
617                            "variables."),
618                      dest[i]);
619                 goto error;
620               }
621
622             free (dest[i]);
623             if (dest_label[i])
624               var_set_label (destvar, dest_label[i]);
625
626             v->dest = destvar;
627           }
628
629           v->exclude = exclude;
630
631           if (v->src != NULL)
632             {
633               int j;
634
635               if (var_is_numeric (v->src))
636                 for (j = 0; j < function->n_args; j++)
637                   v->arg[j].f = arg[j].f;
638               else
639                 for (j = 0; j < function->n_args; j++)
640                   v->arg[j].c = xstrdup (arg[j].c);
641             }
642         }
643
644       if (src != NULL && var_is_alpha (src[0]))
645         for (i = 0; i < function->n_args; i++)
646           {
647             free (arg[i].c);
648             arg[i].c = NULL;
649           }
650
651       free (src);
652       free (dest);
653       free (dest_label);
654
655       if (!lex_match (lexer, '/'))
656         {
657           if (lex_token (lexer) == '.')
658             return true;
659
660           lex_error (lexer, "expecting end of command");
661           return false;
662         }
663       continue;
664
665     error:
666       ds_destroy (&function_name);
667       for (i = 0; i < n_dest; i++)
668         {
669           free (dest[i]);
670           free (dest_label[i]);
671         }
672       free (dest);
673       free (dest_label);
674       free (arg[0].c);
675       free (arg[1].c);
676       if (src && n_src && var_is_alpha (src[0]))
677         for (i = 0; i < function->n_args; i++)
678           {
679             free (arg[i].c);
680             arg[i].c = NULL;
681           }
682       free (src);
683
684       return false;
685     }
686 }
687
688 /* Destroys AGR. */
689 static void
690 agr_destroy (struct agr_proc *agr)
691 {
692   struct agr_var *iter, *next;
693
694   subcase_destroy (&agr->sort);
695   free (agr->break_vars);
696   case_unref (agr->break_case);
697   for (iter = agr->agr_vars; iter; iter = next)
698     {
699       next = iter->next;
700
701       if (iter->function & FSTRING)
702         {
703           size_t n_args;
704           size_t i;
705
706           n_args = agr_func_tab[iter->function & FUNC].n_args;
707           for (i = 0; i < n_args; i++)
708             free (iter->arg[i].c);
709           free (iter->string);
710         }
711       else if (iter->function == SD)
712         moments1_destroy (iter->moments);
713
714       var_destroy (iter->subject);
715       var_destroy (iter->weight);
716
717       free (iter);
718     }
719   if (agr->dict != NULL)
720     dict_destroy (agr->dict);
721 }
722 \f
723 /* Execution. */
724
725 /* Accumulates aggregation data from the case INPUT. */
726 static void
727 accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input)
728 {
729   struct agr_var *iter;
730   double weight;
731   bool bad_warn = true;
732
733   weight = dict_get_case_weight (agr->src_dict, input, &bad_warn);
734
735   for (iter = agr->agr_vars; iter; iter = iter->next)
736     if (iter->src)
737       {
738         const union value *v = case_data (input, iter->src);
739         int src_width = var_get_width (iter->src);
740
741         if (var_is_value_missing (iter->src, v, iter->exclude))
742           {
743             switch (iter->function)
744               {
745               case NMISS:
746               case NMISS | FSTRING:
747                 iter->dbl[0] += weight;
748                 break;
749               case NUMISS:
750               case NUMISS | FSTRING:
751                 iter->int1++;
752                 break;
753               }
754             iter->saw_missing = true;
755             continue;
756           }
757
758         /* This is horrible.  There are too many possibilities. */
759         switch (iter->function)
760           {
761           case SUM:
762             iter->dbl[0] += v->f * weight;
763             iter->int1 = 1;
764             break;
765           case MEAN:
766             iter->dbl[0] += v->f * weight;
767             iter->dbl[1] += weight;
768             break;
769           case MEDIAN:
770             {
771               double wv ;
772               struct ccase *cout = case_create (2);
773
774               case_data_rw (cout, iter->subject)->f
775                 = case_data (input, iter->src)->f;
776
777               wv = dict_get_case_weight (agr->src_dict, input, NULL);
778
779               case_data_rw (cout, iter->weight)->f = wv;
780
781               iter->cc += wv;
782
783               casewriter_write (iter->writer, cout);
784             }
785             break;
786           case SD:
787             moments1_add (iter->moments, v->f, weight);
788             break;
789           case MAX:
790             iter->dbl[0] = MAX (iter->dbl[0], v->f);
791             iter->int1 = 1;
792             break;
793           case MAX | FSTRING:
794             if (memcmp (iter->string, v->s, src_width) < 0)
795               memcpy (iter->string, v->s, src_width);
796             iter->int1 = 1;
797             break;
798           case MIN:
799             iter->dbl[0] = MIN (iter->dbl[0], v->f);
800             iter->int1 = 1;
801             break;
802           case MIN | FSTRING:
803             if (memcmp (iter->string, v->s, src_width) > 0)
804               memcpy (iter->string, v->s, src_width);
805             iter->int1 = 1;
806             break;
807           case FGT:
808           case PGT:
809             if (v->f > iter->arg[0].f)
810               iter->dbl[0] += weight;
811             iter->dbl[1] += weight;
812             break;
813           case FGT | FSTRING:
814           case PGT | FSTRING:
815             if (memcmp (iter->arg[0].c, v->s, src_width) < 0)
816               iter->dbl[0] += weight;
817             iter->dbl[1] += weight;
818             break;
819           case FLT:
820           case PLT:
821             if (v->f < iter->arg[0].f)
822               iter->dbl[0] += weight;
823             iter->dbl[1] += weight;
824             break;
825           case FLT | FSTRING:
826           case PLT | FSTRING:
827             if (memcmp (iter->arg[0].c, v->s, src_width) > 0)
828               iter->dbl[0] += weight;
829             iter->dbl[1] += weight;
830             break;
831           case FIN:
832           case PIN:
833             if (iter->arg[0].f <= v->f && v->f <= iter->arg[1].f)
834               iter->dbl[0] += weight;
835             iter->dbl[1] += weight;
836             break;
837           case FIN | FSTRING:
838           case PIN | FSTRING:
839             if (memcmp (iter->arg[0].c, v->s, src_width) <= 0
840                 && memcmp (iter->arg[1].c, v->s, src_width) >= 0)
841               iter->dbl[0] += weight;
842             iter->dbl[1] += weight;
843             break;
844           case FOUT:
845           case POUT:
846             if (iter->arg[0].f > v->f || v->f > iter->arg[1].f)
847               iter->dbl[0] += weight;
848             iter->dbl[1] += weight;
849             break;
850           case FOUT | FSTRING:
851           case POUT | FSTRING:
852             if (memcmp (iter->arg[0].c, v->s, src_width) > 0
853                 || memcmp (iter->arg[1].c, v->s, src_width) < 0)
854               iter->dbl[0] += weight;
855             iter->dbl[1] += weight;
856             break;
857           case N:
858           case N | FSTRING:
859             iter->dbl[0] += weight;
860             break;
861           case NU:
862           case NU | FSTRING:
863             iter->int1++;
864             break;
865           case FIRST:
866             if (iter->int1 == 0)
867               {
868                 iter->dbl[0] = v->f;
869                 iter->int1 = 1;
870               }
871             break;
872           case FIRST | FSTRING:
873             if (iter->int1 == 0)
874               {
875                 memcpy (iter->string, v->s, src_width);
876                 iter->int1 = 1;
877               }
878             break;
879           case LAST:
880             iter->dbl[0] = v->f;
881             iter->int1 = 1;
882             break;
883           case LAST | FSTRING:
884             memcpy (iter->string, v->s, src_width);
885             iter->int1 = 1;
886             break;
887           case NMISS:
888           case NMISS | FSTRING:
889           case NUMISS:
890           case NUMISS | FSTRING:
891             /* Our value is not missing or it would have been
892                caught earlier.  Nothing to do. */
893             break;
894           default:
895             NOT_REACHED ();
896           }
897     } else {
898       switch (iter->function)
899         {
900         case N_NO_VARS:
901           iter->dbl[0] += weight;
902           break;
903         case NU_NO_VARS:
904           iter->int1++;
905           break;
906         default:
907           NOT_REACHED ();
908         }
909     }
910 }
911
912 /* Writes an aggregated record to OUTPUT. */
913 static void
914 dump_aggregate_info (struct agr_proc *agr, struct casewriter *output)
915 {
916   struct ccase *c = case_create (dict_get_next_value_idx (agr->dict));
917
918   {
919     int value_idx = 0;
920     int i;
921
922     for (i = 0; i < agr->break_var_cnt; i++)
923       {
924         const struct variable *v = agr->break_vars[i];
925         size_t value_cnt = var_get_value_cnt (v);
926         memcpy (case_data_rw_idx (c, value_idx),
927                 case_data (agr->break_case, v),
928                 sizeof (union value) * value_cnt);
929         value_idx += value_cnt;
930       }
931   }
932
933   {
934     struct agr_var *i;
935
936     for (i = agr->agr_vars; i; i = i->next)
937       {
938         union value *v = case_data_rw (c, i->dest);
939
940
941         if (agr->missing == COLUMNWISE && i->saw_missing
942             && (i->function & FUNC) != N && (i->function & FUNC) != NU
943             && (i->function & FUNC) != NMISS && (i->function & FUNC) != NUMISS)
944           {
945             if (var_is_alpha (i->dest))
946               memset (v->s, ' ', var_get_width (i->dest));
947             else
948               v->f = SYSMIS;
949
950             casewriter_destroy (i->writer);
951
952             continue;
953           }
954
955         switch (i->function)
956           {
957           case SUM:
958             v->f = i->int1 ? i->dbl[0] : SYSMIS;
959             break;
960           case MEAN:
961             v->f = i->dbl[1] != 0.0 ? i->dbl[0] / i->dbl[1] : SYSMIS;
962             break;
963           case MEDIAN:
964             {
965               struct casereader *sorted_reader;
966               struct order_stats *median = percentile_create (0.5, i->cc);
967
968               sorted_reader = casewriter_make_reader (i->writer);
969
970               order_stats_accumulate (&median, 1,
971                                       sorted_reader,
972                                       i->weight,
973                                       i->subject,
974                                       i->exclude);
975
976               v->f = percentile_calculate ((struct percentile *) median,
977                                            PC_HAVERAGE);
978
979               statistic_destroy ((struct statistic *) median);
980             }
981             break;
982           case SD:
983             {
984               double variance;
985
986               /* FIXME: we should use two passes. */
987               moments1_calculate (i->moments, NULL, NULL, &variance,
988                                  NULL, NULL);
989               if (variance != SYSMIS)
990                 v->f = sqrt (variance);
991               else
992                 v->f = SYSMIS;
993             }
994             break;
995           case MAX:
996           case MIN:
997             v->f = i->int1 ? i->dbl[0] : SYSMIS;
998             break;
999           case MAX | FSTRING:
1000           case MIN | FSTRING:
1001             if (i->int1)
1002               memcpy (v->s, i->string, var_get_width (i->dest));
1003             else
1004               memset (v->s, ' ', var_get_width (i->dest));
1005             break;
1006           case FGT:
1007           case FGT | FSTRING:
1008           case FLT:
1009           case FLT | FSTRING:
1010           case FIN:
1011           case FIN | FSTRING:
1012           case FOUT:
1013           case FOUT | FSTRING:
1014             v->f = i->dbl[1] ? i->dbl[0] / i->dbl[1] : SYSMIS;
1015             break;
1016           case PGT:
1017           case PGT | FSTRING:
1018           case PLT:
1019           case PLT | FSTRING:
1020           case PIN:
1021           case PIN | FSTRING:
1022           case POUT:
1023           case POUT | FSTRING:
1024             v->f = i->dbl[1] ? i->dbl[0] / i->dbl[1] * 100.0 : SYSMIS;
1025             break;
1026           case N:
1027           case N | FSTRING:
1028             v->f = i->dbl[0];
1029             break;
1030           case NU:
1031           case NU | FSTRING:
1032             v->f = i->int1;
1033             break;
1034           case FIRST:
1035           case LAST:
1036             v->f = i->int1 ? i->dbl[0] : SYSMIS;
1037             break;
1038           case FIRST | FSTRING:
1039           case LAST | FSTRING:
1040             if (i->int1)
1041               memcpy (v->s, i->string, var_get_width (i->dest));
1042             else
1043               memset (v->s, ' ', var_get_width (i->dest));
1044             break;
1045           case N_NO_VARS:
1046             v->f = i->dbl[0];
1047             break;
1048           case NU_NO_VARS:
1049             v->f = i->int1;
1050             break;
1051           case NMISS:
1052           case NMISS | FSTRING:
1053             v->f = i->dbl[0];
1054             break;
1055           case NUMISS:
1056           case NUMISS | FSTRING:
1057             v->f = i->int1;
1058             break;
1059           default:
1060             NOT_REACHED ();
1061           }
1062       }
1063   }
1064
1065   casewriter_write (output, c);
1066 }
1067
1068 /* Resets the state for all the aggregate functions. */
1069 static void
1070 initialize_aggregate_info (struct agr_proc *agr, const struct ccase *input)
1071 {
1072   struct agr_var *iter;
1073
1074   case_unref (agr->break_case);
1075   agr->break_case = case_ref (input);
1076
1077   for (iter = agr->agr_vars; iter; iter = iter->next)
1078     {
1079       iter->saw_missing = false;
1080       iter->dbl[0] = iter->dbl[1] = iter->dbl[2] = 0.0;
1081       iter->int1 = iter->int2 = 0;
1082       switch (iter->function)
1083         {
1084         case MIN:
1085           iter->dbl[0] = DBL_MAX;
1086           break;
1087         case MIN | FSTRING:
1088           memset (iter->string, 255, var_get_width (iter->src));
1089           break;
1090         case MAX:
1091           iter->dbl[0] = -DBL_MAX;
1092           break;
1093         case MAX | FSTRING:
1094           memset (iter->string, 0, var_get_width (iter->src));
1095           break;
1096         case MEDIAN:
1097           {
1098             struct subcase ordering;
1099
1100             if ( ! iter->subject)
1101               iter->subject = var_create_internal (0);
1102
1103             if ( ! iter->weight)
1104               iter->weight = var_create_internal (1);
1105
1106             subcase_init_var (&ordering, iter->subject, SC_ASCEND);
1107             iter->writer = sort_create_writer (&ordering, 2);
1108             subcase_destroy (&ordering);
1109
1110             iter->cc = 0;
1111           }
1112           break;
1113         case SD:
1114           if (iter->moments == NULL)
1115             iter->moments = moments1_create (MOMENT_VARIANCE);
1116           else
1117             moments1_clear (iter->moments);
1118           break;
1119         default:
1120           break;
1121         }
1122     }
1123 }