1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 #include <data/any-writer.h>
25 #include <data/case-sink.h>
26 #include <data/case.h>
27 #include <data/casefile.h>
28 #include <data/dictionary.h>
29 #include <data/file-handle-def.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 int 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, ALPHA, {-1, -1, -1}},
108 {"MIN", 0, ALPHA, {-1, -1, -1}},
109 {"PGT", 1, NUMERIC, {FMT_F, 5, 1}},
110 {"PLT", 1, NUMERIC, {FMT_F, 5, 1}},
111 {"PIN", 2, NUMERIC, {FMT_F, 5, 1}},
112 {"POUT", 2, NUMERIC, {FMT_F, 5, 1}},
113 {"FGT", 1, NUMERIC, {FMT_F, 5, 3}},
114 {"FLT", 1, NUMERIC, {FMT_F, 5, 3}},
115 {"FIN", 2, NUMERIC, {FMT_F, 5, 3}},
116 {"FOUT", 2, NUMERIC, {FMT_F, 5, 3}},
117 {"N", 0, NUMERIC, {FMT_F, 7, 0}},
118 {"NU", 0, NUMERIC, {FMT_F, 7, 0}},
119 {"NMISS", 0, NUMERIC, {FMT_F, 7, 0}},
120 {"NUMISS", 0, NUMERIC, {FMT_F, 7, 0}},
121 {"FIRST", 0, ALPHA, {-1, -1, -1}},
122 {"LAST", 0, ALPHA, {-1, -1, -1}},
123 {NULL, 0, -1, {-1, -1, -1}},
124 {"N", 0, NUMERIC, {FMT_F, 7, 0}},
125 {"NU", 0, 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 agr.break_vars[i]->name);
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);
504 msg (SE, _("Missing argument %d to %s."), i + 1,
511 if (type != src[0]->type)
513 msg (SE, _("Arguments to %s must be of same type as "
514 "source variables."),
520 /* Trailing rparen. */
521 if (!lex_match (lexer, ')'))
523 lex_error (lexer, _("expecting `)'"));
527 /* Now check that the number of source variables match
528 the number of target variables. If we check earlier
529 than this, the user can get very misleading error
530 message, i.e. `AGGREGATE x=SUM(y t).' will get this
531 error message when a proper message would be more
532 like `unknown variable t'. */
535 msg (SE, _("Number of source variables (%u) does not match "
536 "number of target variables (%u)."),
537 (unsigned) n_src, (unsigned) n_dest);
541 if ((func_index == PIN || func_index == POUT
542 || func_index == FIN || func_index == FOUT)
543 && ((src[0]->type == NUMERIC && arg[0].f > arg[1].f)
544 || (src[0]->type == ALPHA
545 && str_compare_rpad (arg[0].c, arg[1].c) > 0)))
547 union agr_argument t = arg[0];
551 msg (SW, _("The value arguments passed to the %s function "
552 "are out-of-order. They will be treated as if "
553 "they had been specified in the correct order."),
558 /* Finally add these to the linked list of aggregation
560 for (i = 0; i < n_dest; i++)
562 struct agr_var *v = xmalloc (sizeof *v);
564 /* Add variable to chain. */
565 if (agr->agr_vars != NULL)
573 /* Create the target variable in the aggregate
576 struct variable *destvar;
578 v->function = func_index;
584 if (src[i]->type == ALPHA)
586 v->function |= FSTRING;
587 v->string = xmalloc (src[i]->width);
590 if (function->alpha_type == ALPHA)
591 destvar = dict_clone_var (agr->dict, v->src, dest[i]);
594 assert (v->src->type == NUMERIC
595 || function->alpha_type == NUMERIC);
596 destvar = dict_create_var (agr->dict, dest[i], 0);
600 if ((func_index == N || func_index == NMISS)
601 && dict_get_weight (dict) != NULL)
602 f = fmt_for_output (FMT_F, 8, 2);
604 f = function->format;
605 destvar->print = destvar->write = f;
611 destvar = dict_create_var (agr->dict, dest[i], 0);
612 if (func_index == N_NO_VARS && dict_get_weight (dict) != NULL)
613 f = fmt_for_output (FMT_F, 8, 2);
615 f = function->format;
616 destvar->print = destvar->write = f;
621 msg (SE, _("Variable name %s is not unique within the "
622 "aggregate file dictionary, which contains "
623 "the aggregate variables and the break "
632 destvar->label = dest_label[i];
633 dest_label[i] = NULL;
639 v->include_missing = include_missing;
645 if (v->src->type == NUMERIC)
646 for (j = 0; j < function->n_args; j++)
647 v->arg[j].f = arg[j].f;
649 for (j = 0; j < function->n_args; j++)
650 v->arg[j].c = xstrdup (arg[j].c);
654 if (src != NULL && src[0]->type == ALPHA)
655 for (i = 0; i < function->n_args; i++)
665 if (!lex_match (lexer, '/'))
667 if (lex_token (lexer) == '.')
670 lex_error (lexer, "expecting end of command");
676 ds_destroy (&function_name);
677 for (i = 0; i < n_dest; i++)
680 free (dest_label[i]);
686 if (src && n_src && src[0]->type == ALPHA)
687 for (i = 0; i < function->n_args; i++)
700 agr_destroy (struct agr_proc *agr)
702 struct agr_var *iter, *next;
704 any_writer_close (agr->writer);
705 if (agr->sort != NULL)
706 sort_destroy_criteria (agr->sort);
707 free (agr->break_vars);
708 case_destroy (&agr->break_case);
709 for (iter = agr->agr_vars; iter; iter = next)
713 if (iter->function & FSTRING)
718 n_args = agr_func_tab[iter->function & FUNC].n_args;
719 for (i = 0; i < n_args; i++)
720 free (iter->arg[i].c);
723 else if (iter->function == SD)
724 moments1_destroy (iter->moments);
727 if (agr->dict != NULL)
728 dict_destroy (agr->dict);
730 case_destroy (&agr->agr_case);
735 static void accumulate_aggregate_info (struct agr_proc *,
736 const struct ccase *);
737 static void dump_aggregate_info (struct agr_proc *, struct ccase *);
739 /* Processes a single case INPUT for aggregation. If output is
740 warranted, writes it to OUTPUT and returns true.
741 Otherwise, returns false and OUTPUT is unmodified. */
743 aggregate_single_case (struct agr_proc *agr,
744 const struct ccase *input, struct ccase *output)
746 bool finished_group = false;
748 if (agr->case_cnt++ == 0)
749 initialize_aggregate_info (agr, input);
750 else if (case_compare (&agr->break_case, input,
751 agr->break_vars, agr->break_var_cnt))
753 dump_aggregate_info (agr, output);
754 finished_group = true;
756 initialize_aggregate_info (agr, input);
759 accumulate_aggregate_info (agr, input);
760 return finished_group;
763 /* Accumulates aggregation data from the case INPUT. */
765 accumulate_aggregate_info (struct agr_proc *agr,
766 const struct ccase *input)
768 struct agr_var *iter;
770 bool bad_warn = true;
772 weight = dict_get_case_weight (agr->src_dict, input, &bad_warn);
774 for (iter = agr->agr_vars; iter; iter = iter->next)
777 const union value *v = case_data (input, iter->src->fv);
779 if ((!iter->include_missing
780 && mv_is_value_missing (&iter->src->miss, v))
781 || (iter->include_missing && iter->src->type == NUMERIC
784 switch (iter->function)
787 case NMISS | FSTRING:
788 iter->dbl[0] += weight;
791 case NUMISS | FSTRING:
799 /* This is horrible. There are too many possibilities. */
800 switch (iter->function)
803 iter->dbl[0] += v->f * weight;
807 iter->dbl[0] += v->f * weight;
808 iter->dbl[1] += weight;
811 moments1_add (iter->moments, v->f, weight);
814 iter->dbl[0] = MAX (iter->dbl[0], v->f);
818 if (memcmp (iter->string, v->s, iter->src->width) < 0)
819 memcpy (iter->string, v->s, iter->src->width);
823 iter->dbl[0] = MIN (iter->dbl[0], v->f);
827 if (memcmp (iter->string, v->s, iter->src->width) > 0)
828 memcpy (iter->string, v->s, iter->src->width);
833 if (v->f > iter->arg[0].f)
834 iter->dbl[0] += weight;
835 iter->dbl[1] += weight;
839 if (memcmp (iter->arg[0].c, v->s, iter->src->width) < 0)
840 iter->dbl[0] += weight;
841 iter->dbl[1] += weight;
845 if (v->f < iter->arg[0].f)
846 iter->dbl[0] += weight;
847 iter->dbl[1] += weight;
851 if (memcmp (iter->arg[0].c, v->s, iter->src->width) > 0)
852 iter->dbl[0] += weight;
853 iter->dbl[1] += weight;
857 if (iter->arg[0].f <= v->f && v->f <= iter->arg[1].f)
858 iter->dbl[0] += weight;
859 iter->dbl[1] += weight;
863 if (memcmp (iter->arg[0].c, v->s, iter->src->width) <= 0
864 && memcmp (iter->arg[1].c, v->s, iter->src->width) >= 0)
865 iter->dbl[0] += weight;
866 iter->dbl[1] += weight;
870 if (iter->arg[0].f > v->f || v->f > iter->arg[1].f)
871 iter->dbl[0] += weight;
872 iter->dbl[1] += weight;
876 if (memcmp (iter->arg[0].c, v->s, iter->src->width) > 0
877 || memcmp (iter->arg[1].c, v->s, iter->src->width) < 0)
878 iter->dbl[0] += weight;
879 iter->dbl[1] += weight;
883 iter->dbl[0] += weight;
896 case FIRST | FSTRING:
899 memcpy (iter->string, v->s, iter->src->width);
908 memcpy (iter->string, v->s, iter->src->width);
912 case NMISS | FSTRING:
914 case NUMISS | FSTRING:
915 /* Our value is not missing or it would have been
916 caught earlier. Nothing to do. */
922 switch (iter->function)
925 iter->dbl[0] += weight;
936 /* We've come to a record that differs from the previous in one or
937 more of the break variables. Make an output record from the
938 accumulated statistics in the OUTPUT case. */
940 dump_aggregate_info (struct agr_proc *agr, struct ccase *output)
946 for (i = 0; i < agr->break_var_cnt; i++)
948 struct variable *v = agr->break_vars[i];
949 memcpy (case_data_rw (output, value_idx),
950 case_data (&agr->break_case, v->fv),
951 sizeof (union value) * v->nv);
959 for (i = agr->agr_vars; i; i = i->next)
961 union value *v = case_data_rw (output, i->dest->fv);
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 (i->dest->type == ALPHA)
968 memset (v->s, ' ', i->dest->width);
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, i->dest->width);
1004 memset (v->s, ' ', i->dest->width);
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, i->dest->width);
1043 memset (v->s, ' ', i->dest->width);
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, iter->src->width);
1089 iter->dbl[0] = -DBL_MAX;
1092 memset (iter->string, 0, iter->src->width);
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);