1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 #include <data/any-writer.h>
24 #include <data/case-sink.h>
25 #include <data/case.h>
26 #include <data/casefile.h>
27 #include <data/dictionary.h>
28 #include <data/file-handle-def.h>
29 #include <data/format.h>
30 #include <data/procedure.h>
31 #include <data/settings.h>
32 #include <data/storage-stream.h>
33 #include <data/sys-file-writer.h>
34 #include <data/variable.h>
35 #include <language/command.h>
36 #include <language/data-io/file-handle.h>
37 #include <language/lexer/lexer.h>
38 #include <language/lexer/variable-parser.h>
39 #include <language/stats/sort-criteria.h>
40 #include <libpspp/alloc.h>
41 #include <libpspp/assertion.h>
42 #include <libpspp/message.h>
43 #include <libpspp/misc.h>
44 #include <libpspp/pool.h>
45 #include <libpspp/str.h>
46 #include <math/moments.h>
47 #include <math/sort.h>
52 #define _(msgid) gettext (msgid)
54 /* Argument for AGGREGATE function. */
57 double f; /* Numeric. */
58 char *c; /* Short or long string. */
61 /* Specifies how to make an aggregate variable. */
64 struct agr_var *next; /* Next in list. */
66 /* Collected during parsing. */
67 struct variable *src; /* Source variable. */
68 struct variable *dest; /* Target variable. */
69 int function; /* Function. */
70 int include_missing; /* 1=Include user-missing values. */
71 union agr_argument arg[2]; /* Arguments. */
73 /* Accumulated during AGGREGATE execution. */
78 struct moments1 *moments;
81 /* Aggregation functions. */
84 NONE, SUM, MEAN, SD, MAX, MIN, PGT, PLT, PIN, POUT, FGT, FLT, FIN,
85 FOUT, N, NU, NMISS, NUMISS, FIRST, LAST,
86 N_AGR_FUNCS, N_NO_VARS, NU_NO_VARS,
87 FUNC = 0x1f, /* Function mask. */
88 FSTRING = 1<<5, /* String function bit. */
91 /* Attributes of an aggregation function. */
94 const char *name; /* Aggregation function name. */
95 size_t n_args; /* Number of arguments. */
96 enum var_type alpha_type; /* When given ALPHA arguments, output type. */
97 struct fmt_spec format; /* Format spec if alpha_type != ALPHA. */
100 /* Attributes of aggregation functions. */
101 static const struct agr_func agr_func_tab[] =
103 {"<NONE>", 0, -1, {0, 0, 0}},
104 {"SUM", 0, -1, {FMT_F, 8, 2}},
105 {"MEAN", 0, -1, {FMT_F, 8, 2}},
106 {"SD", 0, -1, {FMT_F, 8, 2}},
107 {"MAX", 0, VAR_STRING, {-1, -1, -1}},
108 {"MIN", 0, VAR_STRING, {-1, -1, -1}},
109 {"PGT", 1, VAR_NUMERIC, {FMT_F, 5, 1}},
110 {"PLT", 1, VAR_NUMERIC, {FMT_F, 5, 1}},
111 {"PIN", 2, VAR_NUMERIC, {FMT_F, 5, 1}},
112 {"POUT", 2, VAR_NUMERIC, {FMT_F, 5, 1}},
113 {"FGT", 1, VAR_NUMERIC, {FMT_F, 5, 3}},
114 {"FLT", 1, VAR_NUMERIC, {FMT_F, 5, 3}},
115 {"FIN", 2, VAR_NUMERIC, {FMT_F, 5, 3}},
116 {"FOUT", 2, VAR_NUMERIC, {FMT_F, 5, 3}},
117 {"N", 0, VAR_NUMERIC, {FMT_F, 7, 0}},
118 {"NU", 0, VAR_NUMERIC, {FMT_F, 7, 0}},
119 {"NMISS", 0, VAR_NUMERIC, {FMT_F, 7, 0}},
120 {"NUMISS", 0, VAR_NUMERIC, {FMT_F, 7, 0}},
121 {"FIRST", 0, VAR_STRING, {-1, -1, -1}},
122 {"LAST", 0, VAR_STRING, {-1, -1, -1}},
123 {NULL, 0, -1, {-1, -1, -1}},
124 {"N", 0, VAR_NUMERIC, {FMT_F, 7, 0}},
125 {"NU", 0, VAR_NUMERIC, {FMT_F, 7, 0}},
128 /* Missing value types. */
129 enum missing_treatment
131 ITEMWISE, /* Missing values item by item. */
132 COLUMNWISE /* Missing values column by column. */
135 /* An entire AGGREGATE procedure. */
138 /* We have either an output file or a sink. */
139 struct any_writer *writer; /* Output file, or null if none. */
140 struct case_sink *sink; /* Sink, or null if none. */
142 /* Break variables. */
143 struct sort_criteria *sort; /* Sort criteria. */
144 struct variable **break_vars; /* Break variables. */
145 size_t break_var_cnt; /* Number of break variables. */
146 struct ccase break_case; /* Last values of break variables. */
148 enum missing_treatment missing; /* How to treat missing values. */
149 struct agr_var *agr_vars; /* First aggregate variable. */
150 struct dictionary *dict; /* Aggregate dictionary. */
151 const struct dictionary *src_dict; /* Dict of the source */
152 int case_cnt; /* Counts aggregated cases. */
153 struct ccase agr_case; /* Aggregate case for output. */
156 static void initialize_aggregate_info (struct agr_proc *,
157 const struct ccase *);
160 static bool parse_aggregate_functions (struct lexer *, const struct dictionary *,
162 static void agr_destroy (struct agr_proc *);
163 static bool aggregate_single_case (struct agr_proc *agr,
164 const struct ccase *input,
165 struct ccase *output);
166 static void dump_aggregate_info (struct agr_proc *agr, struct ccase *output);
168 /* Aggregating to the active file. */
169 static bool agr_to_active_file (const struct ccase *, void *aux, const struct dataset *);
171 /* Aggregating to a system file. */
172 static bool presorted_agr_to_sysfile (const struct ccase *, void *aux, const struct dataset *);
176 /* Parses and executes the AGGREGATE procedure. */
178 cmd_aggregate (struct lexer *lexer, struct dataset *ds)
180 struct dictionary *dict = dataset_dict (ds);
182 struct file_handle *out_file = NULL;
184 bool copy_documents = false;
185 bool presorted = false;
188 memset(&agr, 0 , sizeof (agr));
189 agr.missing = ITEMWISE;
190 case_nullify (&agr.break_case);
192 agr.dict = dict_create ();
194 dict_set_label (agr.dict, dict_get_label (dict));
195 dict_set_documents (agr.dict, dict_get_documents (dict));
197 /* OUTFILE subcommand must be first. */
198 if (!lex_force_match_id (lexer, "OUTFILE"))
200 lex_match (lexer, '=');
201 if (!lex_match (lexer, '*'))
203 out_file = fh_parse (lexer, FH_REF_FILE | FH_REF_SCRATCH);
204 if (out_file == NULL)
208 /* Read most of the subcommands. */
211 lex_match (lexer, '/');
213 if (lex_match_id (lexer, "MISSING"))
215 lex_match (lexer, '=');
216 if (!lex_match_id (lexer, "COLUMNWISE"))
218 lex_error (lexer, _("while expecting COLUMNWISE"));
221 agr.missing = COLUMNWISE;
223 else if (lex_match_id (lexer, "DOCUMENT"))
224 copy_documents = true;
225 else if (lex_match_id (lexer, "PRESORTED"))
227 else if (lex_match_id (lexer, "BREAK"))
231 lex_match (lexer, '=');
232 agr.sort = sort_parse_criteria (lexer, dict,
233 &agr.break_vars, &agr.break_var_cnt,
234 &saw_direction, NULL);
235 if (agr.sort == NULL)
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]));
242 /* BREAK must follow the options. */
247 lex_error (lexer, _("expecting BREAK"));
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."));
256 /* Read in the aggregate functions. */
257 lex_match (lexer, '/');
258 if (!parse_aggregate_functions (lexer, dict, &agr))
261 /* Delete documents. */
263 dict_set_documents (agr.dict, NULL);
265 /* Cancel SPLIT FILE. */
266 dict_set_split_vars (agr.dict, NULL, 0);
270 case_create (&agr.agr_case, dict_get_next_value_idx (agr.dict));
272 /* Output to active file or external file? */
273 if (out_file == NULL)
275 /* The active file will be replaced by the aggregated data,
276 so TEMPORARY is moot. */
277 proc_cancel_temporary_transformations (ds);
279 if (agr.sort != NULL && !presorted)
281 if (!sort_active_file_in_place (ds, agr.sort))
285 agr.sink = create_case_sink (&storage_sink_class, agr.dict, NULL);
286 if (agr.sink->class->open != NULL)
287 agr.sink->class->open (agr.sink);
289 create_case_sink (&null_sink_class,
291 if (!procedure (ds, agr_to_active_file, &agr))
293 if (agr.case_cnt > 0)
295 dump_aggregate_info (&agr, &agr.agr_case);
296 if (!agr.sink->class->write (agr.sink, &agr.agr_case))
299 discard_variables (ds);
301 dataset_set_dict (ds, agr.dict);
304 agr.sink->class->make_source (agr.sink));
305 free_case_sink (agr.sink);
309 agr.writer = any_writer_open (out_file, agr.dict);
310 if (agr.writer == NULL)
313 if (agr.sort != NULL && !presorted)
315 /* Sorting is needed. */
316 struct casefile *dst;
317 struct casereader *reader;
321 dst = sort_active_file_to_casefile (ds, agr.sort);
324 reader = casefile_get_destructive_reader (dst);
325 while (ok && casereader_read_xfer (reader, &c))
327 if (aggregate_single_case (&agr, &c, &agr.agr_case))
328 ok = any_writer_write (agr.writer, &agr.agr_case);
331 casereader_destroy (reader);
333 ok = !casefile_error (dst);
334 casefile_destroy (dst);
340 /* Active file is already sorted. */
341 if (!procedure (ds, presorted_agr_to_sysfile, &agr))
345 if (agr.case_cnt > 0)
347 dump_aggregate_info (&agr, &agr.agr_case);
348 any_writer_write (agr.writer, &agr.agr_case);
350 if (any_writer_error (agr.writer))
359 return CMD_CASCADING_FAILURE;
362 /* Parse all the aggregate functions. */
364 parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, struct agr_proc *agr)
366 struct agr_var *tail; /* Tail of linked list starting at agr->vars. */
368 /* Parse everything. */
375 struct string function_name;
378 const struct agr_func *function;
381 union agr_argument arg[2];
383 struct variable **src;
397 /* Parse the list of target variables. */
398 while (!lex_match (lexer, '='))
400 size_t n_dest_prev = n_dest;
402 if (!parse_DATA_LIST_vars (lexer, &dest, &n_dest,
403 PV_APPEND | PV_SINGLE | PV_NO_SCRATCH))
406 /* Assign empty labels. */
410 dest_label = xnrealloc (dest_label, n_dest, sizeof *dest_label);
411 for (j = n_dest_prev; j < n_dest; j++)
412 dest_label[j] = NULL;
417 if (lex_token (lexer) == T_STRING)
420 ds_init_string (&label, lex_tokstr (lexer));
422 ds_truncate (&label, 255);
423 dest_label[n_dest - 1] = ds_xstrdup (&label);
429 /* Get the name of the aggregation function. */
430 if (lex_token (lexer) != T_ID)
432 lex_error (lexer, _("expecting aggregation function"));
438 ds_init_string (&function_name, lex_tokstr (lexer));
440 ds_chomp (&function_name, '.');
442 if (lex_tokid(lexer)[strlen (lex_tokid (lexer)) - 1] == '.')
445 for (function = agr_func_tab; function->name; function++)
446 if (!strcasecmp (function->name, ds_cstr (&function_name)))
448 if (NULL == function->name)
450 msg (SE, _("Unknown aggregation function %s."),
451 ds_cstr (&function_name));
454 ds_destroy (&function_name);
455 func_index = function - agr_func_tab;
458 /* Check for leading lparen. */
459 if (!lex_match (lexer, '('))
462 func_index = N_NO_VARS;
463 else if (func_index == NU)
464 func_index = NU_NO_VARS;
467 lex_error (lexer, _("expecting `('"));
473 /* Parse list of source variables. */
475 int pv_opts = PV_NO_SCRATCH;
477 if (func_index == SUM || func_index == MEAN || func_index == SD)
478 pv_opts |= PV_NUMERIC;
479 else if (function->n_args)
480 pv_opts |= PV_SAME_TYPE;
482 if (!parse_variables (lexer, dict, &src, &n_src, pv_opts))
486 /* Parse function arguments, for those functions that
487 require arguments. */
488 if (function->n_args != 0)
489 for (i = 0; i < function->n_args; i++)
493 lex_match (lexer, ',');
494 if (lex_token (lexer) == T_STRING)
496 arg[i].c = ds_xstrdup (lex_tokstr (lexer));
499 else if (lex_is_number (lexer))
501 arg[i].f = lex_tokval (lexer);
506 msg (SE, _("Missing argument %d to %s."), i + 1,
513 if (type != var_get_type (src[0]))
515 msg (SE, _("Arguments to %s must be of same type as "
516 "source variables."),
522 /* Trailing rparen. */
523 if (!lex_match (lexer, ')'))
525 lex_error (lexer, _("expecting `)'"));
529 /* Now check that the number of source variables match
530 the number of target variables. If we check earlier
531 than this, the user can get very misleading error
532 message, i.e. `AGGREGATE x=SUM(y t).' will get this
533 error message when a proper message would be more
534 like `unknown variable t'. */
537 msg (SE, _("Number of source variables (%u) does not match "
538 "number of target variables (%u)."),
539 (unsigned) n_src, (unsigned) n_dest);
543 if ((func_index == PIN || func_index == POUT
544 || func_index == FIN || func_index == FOUT)
545 && (var_is_numeric (src[0])
546 ? arg[0].f > arg[1].f
547 : str_compare_rpad (arg[0].c, arg[1].c) > 0))
549 union agr_argument t = arg[0];
553 msg (SW, _("The value arguments passed to the %s function "
554 "are out-of-order. They will be treated as if "
555 "they had been specified in the correct order."),
560 /* Finally add these to the linked list of aggregation
562 for (i = 0; i < n_dest; i++)
564 struct agr_var *v = xmalloc (sizeof *v);
566 /* Add variable to chain. */
567 if (agr->agr_vars != NULL)
575 /* Create the target variable in the aggregate
578 struct variable *destvar;
580 v->function = func_index;
586 if (var_is_alpha (src[i]))
588 v->function |= FSTRING;
589 v->string = xmalloc (var_get_width (src[i]));
592 if (function->alpha_type == VAR_STRING)
593 destvar = dict_clone_var (agr->dict, v->src, dest[i]);
596 assert (var_is_numeric (v->src)
597 || function->alpha_type == VAR_NUMERIC);
598 destvar = dict_create_var (agr->dict, dest[i], 0);
602 if ((func_index == N || func_index == NMISS)
603 && dict_get_weight (dict) != NULL)
604 f = fmt_for_output (FMT_F, 8, 2);
606 f = function->format;
607 var_set_both_formats (destvar, &f);
613 destvar = dict_create_var (agr->dict, dest[i], 0);
614 if (func_index == N_NO_VARS && dict_get_weight (dict) != NULL)
615 f = fmt_for_output (FMT_F, 8, 2);
617 f = function->format;
618 var_set_both_formats (destvar, &f);
623 msg (SE, _("Variable name %s is not unique within the "
624 "aggregate file dictionary, which contains "
625 "the aggregate variables and the break "
633 var_set_label (destvar, dest_label[i]);
638 v->include_missing = include_missing;
644 if (var_is_numeric (v->src))
645 for (j = 0; j < function->n_args; j++)
646 v->arg[j].f = arg[j].f;
648 for (j = 0; j < function->n_args; j++)
649 v->arg[j].c = xstrdup (arg[j].c);
653 if (src != NULL && var_is_alpha (src[0]))
654 for (i = 0; i < function->n_args; i++)
664 if (!lex_match (lexer, '/'))
666 if (lex_token (lexer) == '.')
669 lex_error (lexer, "expecting end of command");
675 ds_destroy (&function_name);
676 for (i = 0; i < n_dest; i++)
679 free (dest_label[i]);
685 if (src && n_src && var_is_alpha (src[0]))
686 for (i = 0; i < function->n_args; i++)
699 agr_destroy (struct agr_proc *agr)
701 struct agr_var *iter, *next;
703 any_writer_close (agr->writer);
704 if (agr->sort != NULL)
705 sort_destroy_criteria (agr->sort);
706 free (agr->break_vars);
707 case_destroy (&agr->break_case);
708 for (iter = agr->agr_vars; iter; iter = next)
712 if (iter->function & FSTRING)
717 n_args = agr_func_tab[iter->function & FUNC].n_args;
718 for (i = 0; i < n_args; i++)
719 free (iter->arg[i].c);
722 else if (iter->function == SD)
723 moments1_destroy (iter->moments);
726 if (agr->dict != NULL)
727 dict_destroy (agr->dict);
729 case_destroy (&agr->agr_case);
734 static void accumulate_aggregate_info (struct agr_proc *,
735 const struct ccase *);
736 static void dump_aggregate_info (struct agr_proc *, struct ccase *);
738 /* Processes a single case INPUT for aggregation. If output is
739 warranted, writes it to OUTPUT and returns true.
740 Otherwise, returns false and OUTPUT is unmodified. */
742 aggregate_single_case (struct agr_proc *agr,
743 const struct ccase *input, struct ccase *output)
745 bool finished_group = false;
747 if (agr->case_cnt++ == 0)
748 initialize_aggregate_info (agr, input);
749 else if (case_compare (&agr->break_case, input,
750 agr->break_vars, agr->break_var_cnt))
752 dump_aggregate_info (agr, output);
753 finished_group = true;
755 initialize_aggregate_info (agr, input);
758 accumulate_aggregate_info (agr, input);
759 return finished_group;
762 /* Accumulates aggregation data from the case INPUT. */
764 accumulate_aggregate_info (struct agr_proc *agr,
765 const struct ccase *input)
767 struct agr_var *iter;
769 bool bad_warn = true;
771 weight = dict_get_case_weight (agr->src_dict, input, &bad_warn);
773 for (iter = agr->agr_vars; iter; iter = iter->next)
776 const union value *v = case_data (input, iter->src);
777 int src_width = var_get_width (iter->src);
779 if (iter->include_missing
780 ? var_is_numeric (iter->src) && v->f == SYSMIS
781 : var_is_value_missing (iter->src, v))
783 switch (iter->function)
786 case NMISS | FSTRING:
787 iter->dbl[0] += weight;
790 case NUMISS | FSTRING:
798 /* This is horrible. There are too many possibilities. */
799 switch (iter->function)
802 iter->dbl[0] += v->f * weight;
806 iter->dbl[0] += v->f * weight;
807 iter->dbl[1] += weight;
810 moments1_add (iter->moments, v->f, weight);
813 iter->dbl[0] = MAX (iter->dbl[0], v->f);
817 if (memcmp (iter->string, v->s, src_width) < 0)
818 memcpy (iter->string, v->s, src_width);
822 iter->dbl[0] = MIN (iter->dbl[0], v->f);
826 if (memcmp (iter->string, v->s, src_width) > 0)
827 memcpy (iter->string, v->s, src_width);
832 if (v->f > iter->arg[0].f)
833 iter->dbl[0] += weight;
834 iter->dbl[1] += weight;
838 if (memcmp (iter->arg[0].c, v->s, src_width) < 0)
839 iter->dbl[0] += weight;
840 iter->dbl[1] += weight;
844 if (v->f < iter->arg[0].f)
845 iter->dbl[0] += weight;
846 iter->dbl[1] += weight;
850 if (memcmp (iter->arg[0].c, v->s, src_width) > 0)
851 iter->dbl[0] += weight;
852 iter->dbl[1] += weight;
856 if (iter->arg[0].f <= v->f && v->f <= iter->arg[1].f)
857 iter->dbl[0] += weight;
858 iter->dbl[1] += weight;
862 if (memcmp (iter->arg[0].c, v->s, src_width) <= 0
863 && memcmp (iter->arg[1].c, v->s, src_width) >= 0)
864 iter->dbl[0] += weight;
865 iter->dbl[1] += weight;
869 if (iter->arg[0].f > v->f || v->f > iter->arg[1].f)
870 iter->dbl[0] += weight;
871 iter->dbl[1] += weight;
875 if (memcmp (iter->arg[0].c, v->s, src_width) > 0
876 || memcmp (iter->arg[1].c, v->s, src_width) < 0)
877 iter->dbl[0] += weight;
878 iter->dbl[1] += weight;
882 iter->dbl[0] += weight;
895 case FIRST | FSTRING:
898 memcpy (iter->string, v->s, src_width);
907 memcpy (iter->string, v->s, src_width);
911 case NMISS | FSTRING:
913 case NUMISS | FSTRING:
914 /* Our value is not missing or it would have been
915 caught earlier. Nothing to do. */
921 switch (iter->function)
924 iter->dbl[0] += weight;
935 /* We've come to a record that differs from the previous in one or
936 more of the break variables. Make an output record from the
937 accumulated statistics in the OUTPUT case. */
939 dump_aggregate_info (struct agr_proc *agr, struct ccase *output)
945 for (i = 0; i < agr->break_var_cnt; i++)
947 struct variable *v = agr->break_vars[i];
948 size_t value_cnt = var_get_value_cnt (v);
949 memcpy (case_data_rw_idx (output, value_idx),
950 case_data (&agr->break_case, v),
951 sizeof (union value) * value_cnt);
952 value_idx += value_cnt;
959 for (i = agr->agr_vars; i; i = i->next)
961 union value *v = case_data_rw (output, i->dest);
963 if (agr->missing == COLUMNWISE && i->missing != 0
964 && (i->function & FUNC) != N && (i->function & FUNC) != NU
965 && (i->function & FUNC) != NMISS && (i->function & FUNC) != NUMISS)
967 if (var_is_alpha (i->dest))
968 memset (v->s, ' ', var_get_width (i->dest));
977 v->f = i->int1 ? i->dbl[0] : SYSMIS;
980 v->f = i->dbl[1] != 0.0 ? i->dbl[0] / i->dbl[1] : SYSMIS;
986 /* FIXME: we should use two passes. */
987 moments1_calculate (i->moments, NULL, NULL, &variance,
989 if (variance != SYSMIS)
990 v->f = sqrt (variance);
997 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1002 memcpy (v->s, i->string, var_get_width (i->dest));
1004 memset (v->s, ' ', var_get_width (i->dest));
1013 case FOUT | FSTRING:
1014 v->f = i->dbl[1] ? i->dbl[0] / i->dbl[1] : SYSMIS;
1023 case POUT | FSTRING:
1024 v->f = i->dbl[1] ? i->dbl[0] / i->dbl[1] * 100.0 : SYSMIS;
1036 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1038 case FIRST | FSTRING:
1039 case LAST | FSTRING:
1041 memcpy (v->s, i->string, var_get_width (i->dest));
1043 memset (v->s, ' ', var_get_width (i->dest));
1052 case NMISS | FSTRING:
1056 case NUMISS | FSTRING:
1066 /* Resets the state for all the aggregate functions. */
1068 initialize_aggregate_info (struct agr_proc *agr, const struct ccase *input)
1070 struct agr_var *iter;
1072 case_destroy (&agr->break_case);
1073 case_clone (&agr->break_case, input);
1075 for (iter = agr->agr_vars; iter; iter = iter->next)
1078 iter->dbl[0] = iter->dbl[1] = iter->dbl[2] = 0.0;
1079 iter->int1 = iter->int2 = 0;
1080 switch (iter->function)
1083 iter->dbl[0] = DBL_MAX;
1086 memset (iter->string, 255, var_get_width (iter->src));
1089 iter->dbl[0] = -DBL_MAX;
1092 memset (iter->string, 0, var_get_width (iter->src));
1095 if (iter->moments == NULL)
1096 iter->moments = moments1_create (MOMENT_VARIANCE);
1098 moments1_clear (iter->moments);
1106 /* Aggregate each case as it comes through. Cases which aren't needed
1108 Returns true if successful, false if an I/O error occurred. */
1110 agr_to_active_file (const struct ccase *c, void *agr_, const struct dataset *ds UNUSED)
1112 struct agr_proc *agr = agr_;
1114 if (aggregate_single_case (agr, c, &agr->agr_case))
1115 return agr->sink->class->write (agr->sink, &agr->agr_case);
1120 /* Aggregate the current case and output it if we passed a
1123 presorted_agr_to_sysfile (const struct ccase *c, void *agr_,
1124 const struct dataset *ds UNUSED)
1126 struct agr_proc *agr = agr_;
1128 if (aggregate_single_case (agr, c, &agr->agr_case))
1129 return any_writer_write (agr->writer, &agr->agr_case);