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 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);
504 msg (SE, _("Missing argument %d to %s."), i + 1,
511 if (type != var_get_type (src[0]))
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 && (var_is_numeric (src[0])
544 ? arg[0].f > arg[1].f
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 (var_is_alpha (src[i]))
586 v->function |= FSTRING;
587 v->string = xmalloc (var_get_width (src[i]));
590 if (function->alpha_type == ALPHA)
591 destvar = dict_clone_var (agr->dict, v->src, dest[i]);
594 assert (var_is_numeric (v->src)
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 var_set_both_formats (destvar, &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 var_set_both_formats (destvar, &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 "
631 var_set_label (destvar, dest_label[i]);
636 v->include_missing = include_missing;
642 if (var_is_numeric (v->src))
643 for (j = 0; j < function->n_args; j++)
644 v->arg[j].f = arg[j].f;
646 for (j = 0; j < function->n_args; j++)
647 v->arg[j].c = xstrdup (arg[j].c);
651 if (src != NULL && var_is_alpha (src[0]))
652 for (i = 0; i < function->n_args; i++)
662 if (!lex_match (lexer, '/'))
664 if (lex_token (lexer) == '.')
667 lex_error (lexer, "expecting end of command");
673 ds_destroy (&function_name);
674 for (i = 0; i < n_dest; i++)
677 free (dest_label[i]);
683 if (src && n_src && var_is_alpha (src[0]))
684 for (i = 0; i < function->n_args; i++)
697 agr_destroy (struct agr_proc *agr)
699 struct agr_var *iter, *next;
701 any_writer_close (agr->writer);
702 if (agr->sort != NULL)
703 sort_destroy_criteria (agr->sort);
704 free (agr->break_vars);
705 case_destroy (&agr->break_case);
706 for (iter = agr->agr_vars; iter; iter = next)
710 if (iter->function & FSTRING)
715 n_args = agr_func_tab[iter->function & FUNC].n_args;
716 for (i = 0; i < n_args; i++)
717 free (iter->arg[i].c);
720 else if (iter->function == SD)
721 moments1_destroy (iter->moments);
724 if (agr->dict != NULL)
725 dict_destroy (agr->dict);
727 case_destroy (&agr->agr_case);
732 static void accumulate_aggregate_info (struct agr_proc *,
733 const struct ccase *);
734 static void dump_aggregate_info (struct agr_proc *, struct ccase *);
736 /* Processes a single case INPUT for aggregation. If output is
737 warranted, writes it to OUTPUT and returns true.
738 Otherwise, returns false and OUTPUT is unmodified. */
740 aggregate_single_case (struct agr_proc *agr,
741 const struct ccase *input, struct ccase *output)
743 bool finished_group = false;
745 if (agr->case_cnt++ == 0)
746 initialize_aggregate_info (agr, input);
747 else if (case_compare (&agr->break_case, input,
748 agr->break_vars, agr->break_var_cnt))
750 dump_aggregate_info (agr, output);
751 finished_group = true;
753 initialize_aggregate_info (agr, input);
756 accumulate_aggregate_info (agr, input);
757 return finished_group;
760 /* Accumulates aggregation data from the case INPUT. */
762 accumulate_aggregate_info (struct agr_proc *agr,
763 const struct ccase *input)
765 struct agr_var *iter;
767 bool bad_warn = true;
769 weight = dict_get_case_weight (agr->src_dict, input, &bad_warn);
771 for (iter = agr->agr_vars; iter; iter = iter->next)
774 const union value *v = case_data (input, iter->src->fv);
775 int src_width = var_get_width (iter->src);
777 if (iter->include_missing
778 ? var_is_numeric (iter->src) && v->f == SYSMIS
779 : var_is_value_missing (iter->src, v))
781 switch (iter->function)
784 case NMISS | FSTRING:
785 iter->dbl[0] += weight;
788 case NUMISS | FSTRING:
796 /* This is horrible. There are too many possibilities. */
797 switch (iter->function)
800 iter->dbl[0] += v->f * weight;
804 iter->dbl[0] += v->f * weight;
805 iter->dbl[1] += weight;
808 moments1_add (iter->moments, v->f, weight);
811 iter->dbl[0] = MAX (iter->dbl[0], v->f);
815 if (memcmp (iter->string, v->s, src_width) < 0)
816 memcpy (iter->string, v->s, src_width);
820 iter->dbl[0] = MIN (iter->dbl[0], v->f);
824 if (memcmp (iter->string, v->s, src_width) > 0)
825 memcpy (iter->string, v->s, src_width);
830 if (v->f > iter->arg[0].f)
831 iter->dbl[0] += weight;
832 iter->dbl[1] += weight;
836 if (memcmp (iter->arg[0].c, v->s, src_width) < 0)
837 iter->dbl[0] += weight;
838 iter->dbl[1] += weight;
842 if (v->f < iter->arg[0].f)
843 iter->dbl[0] += weight;
844 iter->dbl[1] += weight;
848 if (memcmp (iter->arg[0].c, v->s, src_width) > 0)
849 iter->dbl[0] += weight;
850 iter->dbl[1] += weight;
854 if (iter->arg[0].f <= v->f && v->f <= iter->arg[1].f)
855 iter->dbl[0] += weight;
856 iter->dbl[1] += weight;
860 if (memcmp (iter->arg[0].c, v->s, src_width) <= 0
861 && memcmp (iter->arg[1].c, v->s, src_width) >= 0)
862 iter->dbl[0] += weight;
863 iter->dbl[1] += weight;
867 if (iter->arg[0].f > v->f || v->f > iter->arg[1].f)
868 iter->dbl[0] += weight;
869 iter->dbl[1] += weight;
873 if (memcmp (iter->arg[0].c, v->s, src_width) > 0
874 || memcmp (iter->arg[1].c, v->s, src_width) < 0)
875 iter->dbl[0] += weight;
876 iter->dbl[1] += weight;
880 iter->dbl[0] += weight;
893 case FIRST | FSTRING:
896 memcpy (iter->string, v->s, src_width);
905 memcpy (iter->string, v->s, src_width);
909 case NMISS | FSTRING:
911 case NUMISS | FSTRING:
912 /* Our value is not missing or it would have been
913 caught earlier. Nothing to do. */
919 switch (iter->function)
922 iter->dbl[0] += weight;
933 /* We've come to a record that differs from the previous in one or
934 more of the break variables. Make an output record from the
935 accumulated statistics in the OUTPUT case. */
937 dump_aggregate_info (struct agr_proc *agr, struct ccase *output)
943 for (i = 0; i < agr->break_var_cnt; i++)
945 struct variable *v = agr->break_vars[i];
946 size_t value_cnt = var_get_value_cnt (v);
947 memcpy (case_data_rw (output, value_idx),
948 case_data (&agr->break_case, v->fv),
949 sizeof (union value) * value_cnt);
950 value_idx += value_cnt;
957 for (i = agr->agr_vars; i; i = i->next)
959 union value *v = case_data_rw (output, i->dest->fv);
961 if (agr->missing == COLUMNWISE && i->missing != 0
962 && (i->function & FUNC) != N && (i->function & FUNC) != NU
963 && (i->function & FUNC) != NMISS && (i->function & FUNC) != NUMISS)
965 if (var_is_alpha (i->dest))
966 memset (v->s, ' ', var_get_width (i->dest));
975 v->f = i->int1 ? i->dbl[0] : SYSMIS;
978 v->f = i->dbl[1] != 0.0 ? i->dbl[0] / i->dbl[1] : SYSMIS;
984 /* FIXME: we should use two passes. */
985 moments1_calculate (i->moments, NULL, NULL, &variance,
987 if (variance != SYSMIS)
988 v->f = sqrt (variance);
995 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1000 memcpy (v->s, i->string, var_get_width (i->dest));
1002 memset (v->s, ' ', var_get_width (i->dest));
1011 case FOUT | FSTRING:
1012 v->f = i->dbl[1] ? i->dbl[0] / i->dbl[1] : SYSMIS;
1021 case POUT | FSTRING:
1022 v->f = i->dbl[1] ? i->dbl[0] / i->dbl[1] * 100.0 : SYSMIS;
1034 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1036 case FIRST | FSTRING:
1037 case LAST | FSTRING:
1039 memcpy (v->s, i->string, var_get_width (i->dest));
1041 memset (v->s, ' ', var_get_width (i->dest));
1050 case NMISS | FSTRING:
1054 case NUMISS | FSTRING:
1064 /* Resets the state for all the aggregate functions. */
1066 initialize_aggregate_info (struct agr_proc *agr, const struct ccase *input)
1068 struct agr_var *iter;
1070 case_destroy (&agr->break_case);
1071 case_clone (&agr->break_case, input);
1073 for (iter = agr->agr_vars; iter; iter = iter->next)
1076 iter->dbl[0] = iter->dbl[1] = iter->dbl[2] = 0.0;
1077 iter->int1 = iter->int2 = 0;
1078 switch (iter->function)
1081 iter->dbl[0] = DBL_MAX;
1084 memset (iter->string, 255, var_get_width (iter->src));
1087 iter->dbl[0] = -DBL_MAX;
1090 memset (iter->string, 0, var_get_width (iter->src));
1093 if (iter->moments == NULL)
1094 iter->moments = moments1_create (MOMENT_VARIANCE);
1096 moments1_clear (iter->moments);
1104 /* Aggregate each case as it comes through. Cases which aren't needed
1106 Returns true if successful, false if an I/O error occurred. */
1108 agr_to_active_file (const struct ccase *c, void *agr_, const struct dataset *ds UNUSED)
1110 struct agr_proc *agr = agr_;
1112 if (aggregate_single_case (agr, c, &agr->agr_case))
1113 return agr->sink->class->write (agr->sink, &agr->agr_case);
1118 /* Aggregate the current case and output it if we passed a
1121 presorted_agr_to_sysfile (const struct ccase *c, void *agr_,
1122 const struct dataset *ds UNUSED)
1124 struct agr_proc *agr = agr_;
1126 if (aggregate_single_case (agr, c, &agr->agr_case))
1127 return any_writer_write (agr->writer, &agr->agr_case);