1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
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.
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.
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/>. */
19 #include "language/stats/aggregate.h"
23 #include "data/any-writer.h"
24 #include "data/case.h"
25 #include "data/casegrouper.h"
26 #include "data/casereader.h"
27 #include "data/casewriter.h"
28 #include "data/dataset.h"
29 #include "data/dictionary.h"
30 #include "data/file-handle-def.h"
31 #include "data/format.h"
32 #include "data/settings.h"
33 #include "data/subcase.h"
34 #include "data/sys-file-writer.h"
35 #include "data/variable.h"
36 #include "language/command.h"
37 #include "language/data-io/file-handle.h"
38 #include "language/lexer/lexer.h"
39 #include "language/lexer/variable-parser.h"
40 #include "language/stats/sort-criteria.h"
41 #include "libpspp/assertion.h"
42 #include "libpspp/i18n.h"
43 #include "libpspp/message.h"
44 #include "libpspp/misc.h"
45 #include "libpspp/pool.h"
46 #include "libpspp/str.h"
47 #include "math/moments.h"
48 #include "math/percentiles.h"
49 #include "math/sort.h"
50 #include "math/statistic.h"
52 #include "gl/minmax.h"
53 #include "gl/xalloc.h"
56 #define _(msgid) gettext (msgid)
57 #define N_(msgid) msgid
59 /* Argument for AGGREGATE function. */
62 double f; /* Numeric. */
63 char *c; /* Short or long string. */
66 /* Specifies how to make an aggregate variable. */
69 struct agr_var *next; /* Next in list. */
71 /* Collected during parsing. */
72 const struct variable *src; /* Source variable. */
73 struct variable *dest; /* Target variable. */
74 int function; /* Function. */
75 enum mv_class exclude; /* Classes of missing values to exclude. */
76 union agr_argument arg[2]; /* Arguments. */
78 /* Accumulated during AGGREGATE execution. */
83 struct moments1 *moments;
86 struct variable *subject;
87 struct variable *weight;
88 struct casewriter *writer;
92 /* Attributes of aggregation functions. */
93 const struct agr_func agr_func_tab[] =
95 {"SUM", N_("Sum of values"), AGR_SV_YES, 0, -1, {FMT_F, 8, 2}},
96 {"MEAN", N_("Mean average"), AGR_SV_YES, 0, -1, {FMT_F, 8, 2}},
97 {"MEDIAN", N_("Median average"), AGR_SV_YES, 0, -1, {FMT_F, 8, 2}},
98 {"SD", N_("Standard deviation"), AGR_SV_YES, 0, -1, {FMT_F, 8, 2}},
99 {"MAX", N_("Maximum value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}},
100 {"MIN", N_("Minimum value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}},
101 {"PGT", N_("Percentage greater than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 1}},
102 {"PLT", N_("Percentage less than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 1}},
103 {"PIN", N_("Percentage included in range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 1}},
104 {"POUT", N_("Percentage excluded from range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 1}},
105 {"FGT", N_("Fraction greater than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 3}},
106 {"FLT", N_("Fraction less than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 3}},
107 {"FIN", N_("Fraction included in range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 3}},
108 {"FOUT", N_("Fraction excluded from range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 3}},
109 {"N", N_("Number of cases"), AGR_SV_NO, 0, VAL_NUMERIC, {FMT_F, 7, 0}},
110 {"NU", N_("Number of cases (unweighted)"), AGR_SV_OPT, 0, VAL_NUMERIC, {FMT_F, 7, 0}},
111 {"NMISS", N_("Number of missing values"), AGR_SV_YES, 0, VAL_NUMERIC, {FMT_F, 7, 0}},
112 {"NUMISS", N_("Number of missing values (unweighted)"), AGR_SV_YES, 0, VAL_NUMERIC, {FMT_F, 7, 0}},
113 {"FIRST", N_("First non-missing value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}},
114 {"LAST", N_("Last non-missing value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}},
115 {NULL, NULL, AGR_SV_NO, 0, -1, {-1, -1, -1}},
118 /* Missing value types. */
119 enum missing_treatment
121 ITEMWISE, /* Missing values item by item. */
122 COLUMNWISE /* Missing values column by column. */
125 /* An entire AGGREGATE procedure. */
128 /* Break variables. */
129 struct subcase sort; /* Sort criteria (break variables). */
130 const struct variable **break_vars; /* Break variables. */
131 size_t break_var_cnt; /* Number of break variables. */
133 enum missing_treatment missing; /* How to treat missing values. */
134 struct agr_var *agr_vars; /* First aggregate variable. */
135 struct dictionary *dict; /* Aggregate dictionary. */
136 const struct dictionary *src_dict; /* Dict of the source */
137 int case_cnt; /* Counts aggregated cases. */
139 bool add_variables; /* True iff the aggregated variables should
140 be appended to the existing dictionary */
143 static void initialize_aggregate_info (struct agr_proc *);
145 static void accumulate_aggregate_info (struct agr_proc *,
146 const struct ccase *);
148 static bool parse_aggregate_functions (struct lexer *, const struct dictionary *,
150 static void agr_destroy (struct agr_proc *);
151 static void dump_aggregate_info (const struct agr_proc *agr,
152 struct casewriter *output,
153 const struct ccase *break_case);
157 /* Parses and executes the AGGREGATE procedure. */
159 cmd_aggregate (struct lexer *lexer, struct dataset *ds)
161 struct dictionary *dict = dataset_dict (ds);
163 struct file_handle *out_file = NULL;
164 struct casereader *input = NULL, *group;
165 struct casegrouper *grouper;
166 struct casewriter *output = NULL;
168 bool copy_documents = false;
169 bool presorted = false;
173 memset(&agr, 0 , sizeof (agr));
174 agr.missing = ITEMWISE;
176 subcase_init_empty (&agr.sort);
178 /* OUTFILE subcommand must be first. */
179 lex_match (lexer, T_SLASH);
180 if (!lex_force_match_id (lexer, "OUTFILE"))
182 lex_match (lexer, T_EQUALS);
183 if (!lex_match (lexer, T_ASTERISK))
185 out_file = fh_parse (lexer, FH_REF_FILE | FH_REF_SCRATCH);
186 if (out_file == NULL)
190 if (out_file == NULL && lex_match_id (lexer, "MODE"))
192 lex_match (lexer, T_EQUALS);
193 if (lex_match_id (lexer, "ADDVARIABLES"))
195 agr.add_variables = true;
197 /* presorted is assumed in ADDVARIABLES mode */
200 else if (lex_match_id (lexer, "REPLACE"))
202 agr.add_variables = false;
208 if ( agr.add_variables )
209 agr.dict = dict_clone (dict);
211 agr.dict = dict_create ();
213 dict_set_label (agr.dict, dict_get_label (dict));
214 dict_set_documents (agr.dict, dict_get_documents (dict));
216 /* Read most of the subcommands. */
219 lex_match (lexer, T_SLASH);
221 if (lex_match_id (lexer, "MISSING"))
223 lex_match (lexer, T_EQUALS);
224 if (!lex_match_id (lexer, "COLUMNWISE"))
226 lex_error (lexer, _("expecting %s"), "COLUMNWISE");
229 agr.missing = COLUMNWISE;
231 else if (lex_match_id (lexer, "DOCUMENT"))
232 copy_documents = true;
233 else if (lex_match_id (lexer, "PRESORTED"))
235 else if (lex_force_match_id (lexer, "BREAK"))
239 lex_match (lexer, T_EQUALS);
240 if (!parse_sort_criteria (lexer, dict, &agr.sort, &agr.break_vars,
243 agr.break_var_cnt = subcase_get_n_fields (&agr.sort);
245 if (! agr.add_variables)
246 for (i = 0; i < agr.break_var_cnt; i++)
247 dict_clone_var_assert (agr.dict, agr.break_vars[i]);
249 /* BREAK must follow the options. */
256 if (presorted && saw_direction)
257 msg (SW, _("When PRESORTED is specified, specifying sorting directions "
258 "with (A) or (D) has no effect. Output data will be sorted "
259 "the same way as the input data."));
261 /* Read in the aggregate functions. */
262 lex_match (lexer, T_SLASH);
263 if (!parse_aggregate_functions (lexer, dict, &agr))
266 /* Delete documents. */
268 dict_clear_documents (agr.dict);
270 /* Cancel SPLIT FILE. */
271 dict_set_split_vars (agr.dict, NULL, 0);
276 if (out_file == NULL)
278 /* The active file will be replaced by the aggregated data,
279 so TEMPORARY is moot. */
280 proc_cancel_temporary_transformations (ds);
281 proc_discard_output (ds);
282 output = autopaging_writer_create (dict_get_proto (agr.dict));
286 output = any_writer_open (out_file, agr.dict);
291 input = proc_open (ds);
292 if (!subcase_is_empty (&agr.sort) && !presorted)
294 input = sort_execute (input, &agr.sort);
295 subcase_clear (&agr.sort);
298 for (grouper = casegrouper_create_vars (input, agr.break_vars,
300 casegrouper_get_next_group (grouper, &group);
301 casereader_destroy (group))
303 struct casereader *placeholder = NULL;
304 struct ccase *c = casereader_peek (group, 0);
308 casereader_destroy (group);
312 initialize_aggregate_info (&agr);
314 if ( agr.add_variables )
315 placeholder = casereader_clone (group);
319 for (; (cg = casereader_read (group)) != NULL; case_unref (cg))
320 accumulate_aggregate_info (&agr, cg);
324 if (agr.add_variables)
327 for (; (cg = casereader_read (placeholder)) != NULL; case_unref (cg))
328 dump_aggregate_info (&agr, output, cg);
330 casereader_destroy (placeholder);
334 dump_aggregate_info (&agr, output, c);
338 if (!casegrouper_destroy (grouper))
341 if (!proc_commit (ds))
348 if (out_file == NULL)
350 struct casereader *next_input = casewriter_make_reader (output);
351 if (next_input == NULL)
354 proc_set_active_file (ds, next_input, agr.dict);
359 ok = casewriter_destroy (output);
372 casewriter_destroy (output);
375 return CMD_CASCADING_FAILURE;
378 /* Parse all the aggregate functions. */
380 parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict,
381 struct agr_proc *agr)
383 struct agr_var *tail; /* Tail of linked list starting at agr->vars. */
385 /* Parse everything. */
392 struct string function_name;
394 enum mv_class exclude;
395 const struct agr_func *function;
398 union agr_argument arg[2];
400 const struct variable **src;
413 ds_init_empty (&function_name);
415 /* Parse the list of target variables. */
416 while (!lex_match (lexer, T_EQUALS))
418 size_t n_dest_prev = n_dest;
420 if (!parse_DATA_LIST_vars (lexer, dict, &dest, &n_dest,
421 (PV_APPEND | PV_SINGLE | PV_NO_SCRATCH
425 /* Assign empty labels. */
429 dest_label = xnrealloc (dest_label, n_dest, sizeof *dest_label);
430 for (j = n_dest_prev; j < n_dest; j++)
431 dest_label[j] = NULL;
436 if (lex_is_string (lexer))
438 dest_label[n_dest - 1] = xstrdup (lex_tokcstr (lexer));
443 /* Get the name of the aggregation function. */
444 if (lex_token (lexer) != T_ID)
446 lex_error (lexer, _("expecting aggregation function"));
450 ds_assign_substring (&function_name, lex_tokss (lexer));
451 exclude = ds_chomp_byte (&function_name, '.') ? MV_SYSTEM : MV_ANY;
453 for (function = agr_func_tab; function->name; function++)
454 if (!strcasecmp (function->name, ds_cstr (&function_name)))
456 if (NULL == function->name)
458 msg (SE, _("Unknown aggregation function %s."),
459 ds_cstr (&function_name));
462 ds_destroy (&function_name);
463 func_index = function - agr_func_tab;
466 /* Check for leading lparen. */
467 if (!lex_match (lexer, T_LPAREN))
469 if (function->src_vars == AGR_SV_YES)
471 lex_force_match (lexer, T_LPAREN);
477 /* Parse list of source variables. */
479 int pv_opts = PV_NO_SCRATCH;
481 if (func_index == SUM || func_index == MEAN || func_index == SD)
482 pv_opts |= PV_NUMERIC;
483 else if (function->n_args)
484 pv_opts |= PV_SAME_TYPE;
486 if (!parse_variables_const (lexer, dict, &src, &n_src, pv_opts))
490 /* Parse function arguments, for those functions that
491 require arguments. */
492 if (function->n_args != 0)
493 for (i = 0; i < function->n_args; i++)
497 lex_match (lexer, T_COMMA);
498 if (lex_is_string (lexer))
500 arg[i].c = recode_string (dict_get_encoding (agr->dict),
501 "UTF-8", lex_tokcstr (lexer),
505 else if (lex_is_number (lexer))
507 arg[i].f = lex_tokval (lexer);
512 msg (SE, _("Missing argument %zu to %s."),
513 i + 1, function->name);
519 if (type != var_get_type (src[0]))
521 msg (SE, _("Arguments to %s must be of same type as "
522 "source variables."),
528 /* Trailing rparen. */
529 if (!lex_force_match (lexer, T_RPAREN))
532 /* Now check that the number of source variables match
533 the number of target variables. If we check earlier
534 than this, the user can get very misleading error
535 message, i.e. `AGGREGATE x=SUM(y t).' will get this
536 error message when a proper message would be more
537 like `unknown variable t'. */
540 msg (SE, _("Number of source variables (%zu) does not match "
541 "number of target variables (%zu)."),
546 if ((func_index == PIN || func_index == POUT
547 || func_index == FIN || func_index == FOUT)
548 && (var_is_numeric (src[0])
549 ? arg[0].f > arg[1].f
550 : str_compare_rpad (arg[0].c, arg[1].c) > 0))
552 union agr_argument t = arg[0];
556 msg (SW, _("The value arguments passed to the %s function "
557 "are out-of-order. They will be treated as if "
558 "they had been specified in the correct order."),
563 /* Finally add these to the linked list of aggregation
565 for (i = 0; i < n_dest; i++)
567 struct agr_var *v = xzalloc (sizeof *v);
569 /* Add variable to chain. */
570 if (agr->agr_vars != NULL)
578 /* Create the target variable in the aggregate
581 struct variable *destvar;
583 v->function = func_index;
589 if (var_is_alpha (src[i]))
591 v->function |= FSTRING;
592 v->string = xmalloc (var_get_width (src[i]));
595 if (function->alpha_type == VAL_STRING)
596 destvar = dict_clone_var_as (agr->dict, v->src, dest[i]);
599 assert (var_is_numeric (v->src)
600 || function->alpha_type == VAL_NUMERIC);
601 destvar = dict_create_var (agr->dict, dest[i], 0);
605 if ((func_index == N || func_index == NMISS)
606 && dict_get_weight (dict) != NULL)
607 f = fmt_for_output (FMT_F, 8, 2);
609 f = function->format;
610 var_set_both_formats (destvar, &f);
616 destvar = dict_create_var (agr->dict, dest[i], 0);
619 if ((func_index == N || func_index == NMISS)
620 && dict_get_weight (dict) != NULL)
621 f = fmt_for_output (FMT_F, 8, 2);
623 f = function->format;
624 var_set_both_formats (destvar, &f);
630 msg (SE, _("Variable name %s is not unique within the "
631 "aggregate file dictionary, which contains "
632 "the aggregate variables and the break "
640 var_set_label (destvar, dest_label[i],
641 dict_get_encoding (agr->dict), true);
646 v->exclude = exclude;
652 if (var_is_numeric (v->src))
653 for (j = 0; j < function->n_args; j++)
654 v->arg[j].f = arg[j].f;
656 for (j = 0; j < function->n_args; j++)
657 v->arg[j].c = xstrdup (arg[j].c);
661 if (src != NULL && var_is_alpha (src[0]))
662 for (i = 0; i < function->n_args; i++)
672 if (!lex_match (lexer, T_SLASH))
674 if (lex_token (lexer) == T_ENDCMD)
677 lex_error (lexer, "expecting end of command");
683 ds_destroy (&function_name);
684 for (i = 0; i < n_dest; i++)
687 free (dest_label[i]);
693 if (src && n_src && var_is_alpha (src[0]))
694 for (i = 0; i < function->n_args; i++)
707 agr_destroy (struct agr_proc *agr)
709 struct agr_var *iter, *next;
711 subcase_destroy (&agr->sort);
712 free (agr->break_vars);
713 for (iter = agr->agr_vars; iter; iter = next)
717 if (iter->function & FSTRING)
722 n_args = agr_func_tab[iter->function & FUNC].n_args;
723 for (i = 0; i < n_args; i++)
724 free (iter->arg[i].c);
727 else if (iter->function == SD)
728 moments1_destroy (iter->moments);
730 dict_destroy_internal_var (iter->subject);
731 dict_destroy_internal_var (iter->weight);
735 if (agr->dict != NULL)
736 dict_destroy (agr->dict);
741 /* Accumulates aggregation data from the case INPUT. */
743 accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input)
745 struct agr_var *iter;
747 bool bad_warn = true;
749 weight = dict_get_case_weight (agr->src_dict, input, &bad_warn);
751 for (iter = agr->agr_vars; iter; iter = iter->next)
754 const union value *v = case_data (input, iter->src);
755 int src_width = var_get_width (iter->src);
757 if (var_is_value_missing (iter->src, v, iter->exclude))
759 switch (iter->function)
762 case NMISS | FSTRING:
763 iter->dbl[0] += weight;
766 case NUMISS | FSTRING:
770 iter->saw_missing = true;
774 /* This is horrible. There are too many possibilities. */
775 switch (iter->function)
778 iter->dbl[0] += v->f * weight;
782 iter->dbl[0] += v->f * weight;
783 iter->dbl[1] += weight;
790 cout = case_create (casewriter_get_proto (iter->writer));
792 case_data_rw (cout, iter->subject)->f
793 = case_data (input, iter->src)->f;
795 wv = dict_get_case_weight (agr->src_dict, input, NULL);
797 case_data_rw (cout, iter->weight)->f = wv;
801 casewriter_write (iter->writer, cout);
805 moments1_add (iter->moments, v->f, weight);
808 iter->dbl[0] = MAX (iter->dbl[0], v->f);
812 /* Need to do some kind of Unicode collation thingy here */
813 if (memcmp (iter->string, value_str (v, src_width), src_width) < 0)
814 memcpy (iter->string, value_str (v, src_width), src_width);
818 iter->dbl[0] = MIN (iter->dbl[0], v->f);
822 if (memcmp (iter->string, value_str (v, src_width), src_width) > 0)
823 memcpy (iter->string, value_str (v, src_width), src_width);
828 if (v->f > iter->arg[0].f)
829 iter->dbl[0] += weight;
830 iter->dbl[1] += weight;
834 if (memcmp (iter->arg[0].c,
835 value_str (v, src_width), src_width) < 0)
836 iter->dbl[0] += weight;
837 iter->dbl[1] += weight;
841 if (v->f < iter->arg[0].f)
842 iter->dbl[0] += weight;
843 iter->dbl[1] += weight;
847 if (memcmp (iter->arg[0].c,
848 value_str (v, src_width), 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,
861 value_str (v, src_width), src_width) <= 0
862 && memcmp (iter->arg[1].c,
863 value_str (v, src_width), 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,
876 value_str (v, src_width), src_width) > 0
877 || memcmp (iter->arg[1].c,
878 value_str (v, src_width), src_width) < 0)
879 iter->dbl[0] += weight;
880 iter->dbl[1] += weight;
884 iter->dbl[0] += weight;
897 case FIRST | FSTRING:
900 memcpy (iter->string, value_str (v, src_width), src_width);
909 memcpy (iter->string, value_str (v, src_width), src_width);
913 case NMISS | FSTRING:
915 case NUMISS | FSTRING:
916 /* Our value is not missing or it would have been
917 caught earlier. Nothing to do. */
923 switch (iter->function)
926 iter->dbl[0] += weight;
937 /* Writes an aggregated record to OUTPUT. */
939 dump_aggregate_info (const struct agr_proc *agr, struct casewriter *output, const struct ccase *break_case)
941 struct ccase *c = case_create (dict_get_proto (agr->dict));
943 if ( agr->add_variables)
945 case_copy (c, 0, break_case, 0, dict_get_var_cnt (agr->src_dict));
952 for (i = 0; i < agr->break_var_cnt; i++)
954 const struct variable *v = agr->break_vars[i];
955 value_copy (case_data_rw_idx (c, value_idx),
956 case_data (break_case, v),
965 for (i = agr->agr_vars; i; i = i->next)
967 union value *v = case_data_rw (c, i->dest);
968 int width = var_get_width (i->dest);
970 if (agr->missing == COLUMNWISE && i->saw_missing
971 && (i->function & FUNC) != N && (i->function & FUNC) != NU
972 && (i->function & FUNC) != NMISS && (i->function & FUNC) != NUMISS)
974 value_set_missing (v, width);
975 casewriter_destroy (i->writer);
982 v->f = i->int1 ? i->dbl[0] : SYSMIS;
985 v->f = i->dbl[1] != 0.0 ? i->dbl[0] / i->dbl[1] : SYSMIS;
991 struct percentile *median = percentile_create (0.5, i->cc);
992 struct order_stats *os = &median->parent;
993 struct casereader *sorted_reader = casewriter_make_reader (i->writer);
996 order_stats_accumulate (&os, 1,
1001 i->dbl[0] = percentile_calculate (median, PC_HAVERAGE);
1002 statistic_destroy (&median->parent.parent);
1011 /* FIXME: we should use two passes. */
1012 moments1_calculate (i->moments, NULL, NULL, &variance,
1014 if (variance != SYSMIS)
1015 v->f = sqrt (variance);
1022 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1027 memcpy (value_str_rw (v, width), i->string, width);
1029 value_set_missing (v, width);
1038 case FOUT | FSTRING:
1039 v->f = i->dbl[1] ? i->dbl[0] / i->dbl[1] : SYSMIS;
1048 case POUT | FSTRING:
1049 v->f = i->dbl[1] ? i->dbl[0] / i->dbl[1] * 100.0 : SYSMIS;
1061 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1063 case FIRST | FSTRING:
1064 case LAST | FSTRING:
1066 memcpy (value_str_rw (v, width), i->string, width);
1068 value_set_missing (v, width);
1071 case NMISS | FSTRING:
1075 case NUMISS | FSTRING:
1084 casewriter_write (output, c);
1087 /* Resets the state for all the aggregate functions. */
1089 initialize_aggregate_info (struct agr_proc *agr)
1091 struct agr_var *iter;
1093 for (iter = agr->agr_vars; iter; iter = iter->next)
1095 iter->saw_missing = false;
1096 iter->dbl[0] = iter->dbl[1] = iter->dbl[2] = 0.0;
1097 iter->int1 = iter->int2 = 0;
1098 switch (iter->function)
1101 iter->dbl[0] = DBL_MAX;
1104 memset (iter->string, 255, var_get_width (iter->src));
1107 iter->dbl[0] = -DBL_MAX;
1110 memset (iter->string, 0, var_get_width (iter->src));
1114 struct caseproto *proto;
1115 struct subcase ordering;
1117 proto = caseproto_create ();
1118 proto = caseproto_add_width (proto, 0);
1119 proto = caseproto_add_width (proto, 0);
1121 if ( ! iter->subject)
1122 iter->subject = dict_create_internal_var (0, 0);
1124 if ( ! iter->weight)
1125 iter->weight = dict_create_internal_var (1, 0);
1127 subcase_init_var (&ordering, iter->subject, SC_ASCEND);
1128 iter->writer = sort_create_writer (&ordering, proto);
1129 subcase_destroy (&ordering);
1130 caseproto_unref (proto);
1136 if (iter->moments == NULL)
1137 iter->moments = moments1_create (MOMENT_VARIANCE);
1139 moments1_clear (iter->moments);