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/dictionary.h"
29 #include "data/file-handle-def.h"
30 #include "data/format.h"
31 #include "data/procedure.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/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"
48 #include "math/statistic.h"
49 #include "math/percentiles.h"
51 #include "gl/minmax.h"
52 #include "gl/xalloc.h"
55 #define _(msgid) gettext (msgid)
56 #define N_(msgid) msgid
58 /* Argument for AGGREGATE function. */
61 double f; /* Numeric. */
62 char *c; /* Short or long string. */
65 /* Specifies how to make an aggregate variable. */
68 struct agr_var *next; /* Next in list. */
70 /* Collected during parsing. */
71 const struct variable *src; /* Source variable. */
72 struct variable *dest; /* Target variable. */
73 int function; /* Function. */
74 enum mv_class exclude; /* Classes of missing values to exclude. */
75 union agr_argument arg[2]; /* Arguments. */
77 /* Accumulated during AGGREGATE execution. */
82 struct moments1 *moments;
85 struct variable *subject;
86 struct variable *weight;
87 struct casewriter *writer;
91 /* Attributes of aggregation functions. */
92 const struct agr_func agr_func_tab[] =
94 {"SUM", N_("Sum of values"), AGR_SV_YES, 0, -1, {FMT_F, 8, 2}},
95 {"MEAN", N_("Mean average"), AGR_SV_YES, 0, -1, {FMT_F, 8, 2}},
96 {"MEDIAN", N_("Median average"), AGR_SV_YES, 0, -1, {FMT_F, 8, 2}},
97 {"SD", N_("Standard deviation"), AGR_SV_YES, 0, -1, {FMT_F, 8, 2}},
98 {"MAX", N_("Maximum value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}},
99 {"MIN", N_("Minimum value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}},
100 {"PGT", N_("Percentage greater than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 1}},
101 {"PLT", N_("Percentage less than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 1}},
102 {"PIN", N_("Percentage included in range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 1}},
103 {"POUT", N_("Percentage excluded from range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 1}},
104 {"FGT", N_("Fraction greater than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 3}},
105 {"FLT", N_("Fraction less than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 3}},
106 {"FIN", N_("Fraction included in range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 3}},
107 {"FOUT", N_("Fraction excluded from range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 3}},
108 {"N", N_("Number of cases"), AGR_SV_NO, 0, VAL_NUMERIC, {FMT_F, 7, 0}},
109 {"NU", N_("Number of cases (unweighted)"), AGR_SV_OPT, 0, VAL_NUMERIC, {FMT_F, 7, 0}},
110 {"NMISS", N_("Number of missing values"), AGR_SV_YES, 0, VAL_NUMERIC, {FMT_F, 7, 0}},
111 {"NUMISS", N_("Number of missing values (unweighted)"), AGR_SV_YES, 0, VAL_NUMERIC, {FMT_F, 7, 0}},
112 {"FIRST", N_("First non-missing value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}},
113 {"LAST", N_("Last non-missing value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}},
114 {NULL, NULL, AGR_SV_NO, 0, -1, {-1, -1, -1}},
117 /* Missing value types. */
118 enum missing_treatment
120 ITEMWISE, /* Missing values item by item. */
121 COLUMNWISE /* Missing values column by column. */
124 /* An entire AGGREGATE procedure. */
127 /* Break variables. */
128 struct subcase sort; /* Sort criteria (break variables). */
129 const struct variable **break_vars; /* Break variables. */
130 size_t break_var_cnt; /* Number of break variables. */
132 enum missing_treatment missing; /* How to treat missing values. */
133 struct agr_var *agr_vars; /* First aggregate variable. */
134 struct dictionary *dict; /* Aggregate dictionary. */
135 const struct dictionary *src_dict; /* Dict of the source */
136 int case_cnt; /* Counts aggregated cases. */
138 bool add_variables; /* True iff the aggregated variables should
139 be appended to the existing dictionary */
142 static void initialize_aggregate_info (struct agr_proc *);
144 static void accumulate_aggregate_info (struct agr_proc *,
145 const struct ccase *);
147 static bool parse_aggregate_functions (struct lexer *, const struct dictionary *,
149 static void agr_destroy (struct agr_proc *);
150 static void dump_aggregate_info (const struct agr_proc *agr,
151 struct casewriter *output,
152 const struct ccase *break_case);
156 /* Parses and executes the AGGREGATE procedure. */
158 cmd_aggregate (struct lexer *lexer, struct dataset *ds)
160 struct dictionary *dict = dataset_dict (ds);
162 struct file_handle *out_file = NULL;
163 struct casereader *input = NULL, *group;
164 struct casegrouper *grouper;
165 struct casewriter *output = NULL;
167 bool copy_documents = false;
168 bool presorted = false;
172 memset(&agr, 0 , sizeof (agr));
173 agr.missing = ITEMWISE;
175 subcase_init_empty (&agr.sort);
177 /* OUTFILE subcommand must be first. */
178 lex_match (lexer, T_SLASH);
179 if (!lex_force_match_id (lexer, "OUTFILE"))
181 lex_match (lexer, T_EQUALS);
182 if (!lex_match (lexer, T_ASTERISK))
184 out_file = fh_parse (lexer, FH_REF_FILE | FH_REF_SCRATCH);
185 if (out_file == NULL)
189 if (out_file == NULL && lex_match_id (lexer, "MODE"))
191 lex_match (lexer, T_EQUALS);
192 if (lex_match_id (lexer, "ADDVARIABLES"))
194 agr.add_variables = true;
196 /* presorted is assumed in ADDVARIABLES mode */
199 else if (lex_match_id (lexer, "REPLACE"))
201 agr.add_variables = false;
207 if ( agr.add_variables )
208 agr.dict = dict_clone (dict);
210 agr.dict = dict_create ();
212 dict_set_label (agr.dict, dict_get_label (dict));
213 dict_set_documents (agr.dict, dict_get_documents (dict));
215 /* Read most of the subcommands. */
218 lex_match (lexer, T_SLASH);
220 if (lex_match_id (lexer, "MISSING"))
222 lex_match (lexer, T_EQUALS);
223 if (!lex_match_id (lexer, "COLUMNWISE"))
225 lex_error (lexer, _("expecting %s"), "COLUMNWISE");
228 agr.missing = COLUMNWISE;
230 else if (lex_match_id (lexer, "DOCUMENT"))
231 copy_documents = true;
232 else if (lex_match_id (lexer, "PRESORTED"))
234 else if (lex_force_match_id (lexer, "BREAK"))
238 lex_match (lexer, T_EQUALS);
239 if (!parse_sort_criteria (lexer, dict, &agr.sort, &agr.break_vars,
242 agr.break_var_cnt = subcase_get_n_fields (&agr.sort);
244 if (! agr.add_variables)
245 for (i = 0; i < agr.break_var_cnt; i++)
246 dict_clone_var_assert (agr.dict, agr.break_vars[i]);
248 /* BREAK must follow the options. */
255 if (presorted && saw_direction)
256 msg (SW, _("When PRESORTED is specified, specifying sorting directions "
257 "with (A) or (D) has no effect. Output data will be sorted "
258 "the same way as the input data."));
260 /* Read in the aggregate functions. */
261 lex_match (lexer, T_SLASH);
262 if (!parse_aggregate_functions (lexer, dict, &agr))
265 /* Delete documents. */
267 dict_clear_documents (agr.dict);
269 /* Cancel SPLIT FILE. */
270 dict_set_split_vars (agr.dict, NULL, 0);
275 if (out_file == NULL)
277 /* The active file will be replaced by the aggregated data,
278 so TEMPORARY is moot. */
279 proc_cancel_temporary_transformations (ds);
280 proc_discard_output (ds);
281 output = autopaging_writer_create (dict_get_proto (agr.dict));
285 output = any_writer_open (out_file, agr.dict);
290 input = proc_open (ds);
291 if (!subcase_is_empty (&agr.sort) && !presorted)
293 input = sort_execute (input, &agr.sort);
294 subcase_clear (&agr.sort);
297 for (grouper = casegrouper_create_vars (input, agr.break_vars,
299 casegrouper_get_next_group (grouper, &group);
300 casereader_destroy (group))
302 struct casereader *placeholder = NULL;
303 struct ccase *c = casereader_peek (group, 0);
307 casereader_destroy (group);
311 initialize_aggregate_info (&agr);
313 if ( agr.add_variables )
314 placeholder = casereader_clone (group);
318 for (; (cg = casereader_read (group)) != NULL; case_unref (cg))
319 accumulate_aggregate_info (&agr, cg);
323 if (agr.add_variables)
326 for (; (cg = casereader_read (placeholder)) != NULL; case_unref (cg))
327 dump_aggregate_info (&agr, output, cg);
329 casereader_destroy (placeholder);
333 dump_aggregate_info (&agr, output, c);
337 if (!casegrouper_destroy (grouper))
340 if (!proc_commit (ds))
347 if (out_file == NULL)
349 struct casereader *next_input = casewriter_make_reader (output);
350 if (next_input == NULL)
353 proc_set_active_file (ds, next_input, agr.dict);
358 ok = casewriter_destroy (output);
371 casewriter_destroy (output);
374 return CMD_CASCADING_FAILURE;
377 /* Parse all the aggregate functions. */
379 parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict,
380 struct agr_proc *agr)
382 struct agr_var *tail; /* Tail of linked list starting at agr->vars. */
384 /* Parse everything. */
391 struct string function_name;
393 enum mv_class exclude;
394 const struct agr_func *function;
397 union agr_argument arg[2];
399 const struct variable **src;
412 ds_init_empty (&function_name);
414 /* Parse the list of target variables. */
415 while (!lex_match (lexer, T_EQUALS))
417 size_t n_dest_prev = n_dest;
419 if (!parse_DATA_LIST_vars (lexer, &dest, &n_dest,
420 (PV_APPEND | PV_SINGLE | PV_NO_SCRATCH
424 /* Assign empty labels. */
428 dest_label = xnrealloc (dest_label, n_dest, sizeof *dest_label);
429 for (j = n_dest_prev; j < n_dest; j++)
430 dest_label[j] = NULL;
435 if (lex_is_string (lexer))
437 /* XXX check re-encoded length */
439 ds_init_substring (&label, lex_tokss (lexer));
441 ds_truncate (&label, 255);
442 dest_label[n_dest - 1] = ds_xstrdup (&label);
448 /* Get the name of the aggregation function. */
449 if (lex_token (lexer) != T_ID)
451 lex_error (lexer, _("expecting aggregation function"));
455 ds_assign_substring (&function_name, lex_tokss (lexer));
456 exclude = ds_chomp (&function_name, '.') ? MV_SYSTEM : MV_ANY;
458 for (function = agr_func_tab; function->name; function++)
459 if (!strcasecmp (function->name, ds_cstr (&function_name)))
461 if (NULL == function->name)
463 msg (SE, _("Unknown aggregation function %s."),
464 ds_cstr (&function_name));
467 ds_destroy (&function_name);
468 func_index = function - agr_func_tab;
471 /* Check for leading lparen. */
472 if (!lex_match (lexer, T_LPAREN))
474 if (function->src_vars == AGR_SV_YES)
476 lex_force_match (lexer, T_LPAREN);
482 /* Parse list of source variables. */
484 int pv_opts = PV_NO_SCRATCH;
486 if (func_index == SUM || func_index == MEAN || func_index == SD)
487 pv_opts |= PV_NUMERIC;
488 else if (function->n_args)
489 pv_opts |= PV_SAME_TYPE;
491 if (!parse_variables_const (lexer, dict, &src, &n_src, pv_opts))
495 /* Parse function arguments, for those functions that
496 require arguments. */
497 if (function->n_args != 0)
498 for (i = 0; i < function->n_args; i++)
502 lex_match (lexer, T_COMMA);
503 if (lex_is_string (lexer))
505 arg[i].c = ss_xstrdup (lex_tokss (lexer));
508 else if (lex_is_number (lexer))
510 arg[i].f = lex_tokval (lexer);
515 msg (SE, _("Missing argument %zu to %s."),
516 i + 1, function->name);
522 if (type != var_get_type (src[0]))
524 msg (SE, _("Arguments to %s must be of same type as "
525 "source variables."),
531 /* Trailing rparen. */
532 if (!lex_force_match (lexer, T_RPAREN))
535 /* Now check that the number of source variables match
536 the number of target variables. If we check earlier
537 than this, the user can get very misleading error
538 message, i.e. `AGGREGATE x=SUM(y t).' will get this
539 error message when a proper message would be more
540 like `unknown variable t'. */
543 msg (SE, _("Number of source variables (%zu) does not match "
544 "number of target variables (%zu)."),
549 if ((func_index == PIN || func_index == POUT
550 || func_index == FIN || func_index == FOUT)
551 && (var_is_numeric (src[0])
552 ? arg[0].f > arg[1].f
553 : str_compare_rpad (arg[0].c, arg[1].c) > 0))
555 union agr_argument t = arg[0];
559 msg (SW, _("The value arguments passed to the %s function "
560 "are out-of-order. They will be treated as if "
561 "they had been specified in the correct order."),
566 /* Finally add these to the linked list of aggregation
568 for (i = 0; i < n_dest; i++)
570 struct agr_var *v = xzalloc (sizeof *v);
572 /* Add variable to chain. */
573 if (agr->agr_vars != NULL)
581 /* Create the target variable in the aggregate
584 struct variable *destvar;
586 v->function = func_index;
592 if (var_is_alpha (src[i]))
594 v->function |= FSTRING;
595 v->string = xmalloc (var_get_width (src[i]));
598 if (function->alpha_type == VAL_STRING)
599 destvar = dict_clone_var_as (agr->dict, v->src, dest[i]);
602 assert (var_is_numeric (v->src)
603 || function->alpha_type == VAL_NUMERIC);
604 destvar = dict_create_var (agr->dict, dest[i], 0);
608 if ((func_index == N || func_index == NMISS)
609 && dict_get_weight (dict) != NULL)
610 f = fmt_for_output (FMT_F, 8, 2);
612 f = function->format;
613 var_set_both_formats (destvar, &f);
619 destvar = dict_create_var (agr->dict, dest[i], 0);
622 if ((func_index == N || func_index == NMISS)
623 && dict_get_weight (dict) != NULL)
624 f = fmt_for_output (FMT_F, 8, 2);
626 f = function->format;
627 var_set_both_formats (destvar, &f);
633 msg (SE, _("Variable name %s is not unique within the "
634 "aggregate file dictionary, which contains "
635 "the aggregate variables and the break "
643 var_set_label (destvar, dest_label[i]);
648 v->exclude = exclude;
654 if (var_is_numeric (v->src))
655 for (j = 0; j < function->n_args; j++)
656 v->arg[j].f = arg[j].f;
658 for (j = 0; j < function->n_args; j++)
659 v->arg[j].c = xstrdup (arg[j].c);
663 if (src != NULL && var_is_alpha (src[0]))
664 for (i = 0; i < function->n_args; i++)
674 if (!lex_match (lexer, T_SLASH))
676 if (lex_token (lexer) == T_ENDCMD)
679 lex_error (lexer, "expecting end of command");
685 ds_destroy (&function_name);
686 for (i = 0; i < n_dest; i++)
689 free (dest_label[i]);
695 if (src && n_src && var_is_alpha (src[0]))
696 for (i = 0; i < function->n_args; i++)
709 agr_destroy (struct agr_proc *agr)
711 struct agr_var *iter, *next;
713 subcase_destroy (&agr->sort);
714 free (agr->break_vars);
715 for (iter = agr->agr_vars; iter; iter = next)
719 if (iter->function & FSTRING)
724 n_args = agr_func_tab[iter->function & FUNC].n_args;
725 for (i = 0; i < n_args; i++)
726 free (iter->arg[i].c);
729 else if (iter->function == SD)
730 moments1_destroy (iter->moments);
732 dict_destroy_internal_var (iter->subject);
733 dict_destroy_internal_var (iter->weight);
737 if (agr->dict != NULL)
738 dict_destroy (agr->dict);
743 /* Accumulates aggregation data from the case INPUT. */
745 accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input)
747 struct agr_var *iter;
749 bool bad_warn = true;
751 weight = dict_get_case_weight (agr->src_dict, input, &bad_warn);
753 for (iter = agr->agr_vars; iter; iter = iter->next)
756 const union value *v = case_data (input, iter->src);
757 int src_width = var_get_width (iter->src);
759 if (var_is_value_missing (iter->src, v, iter->exclude))
761 switch (iter->function)
764 case NMISS | FSTRING:
765 iter->dbl[0] += weight;
768 case NUMISS | FSTRING:
772 iter->saw_missing = true;
776 /* This is horrible. There are too many possibilities. */
777 switch (iter->function)
780 iter->dbl[0] += v->f * weight;
784 iter->dbl[0] += v->f * weight;
785 iter->dbl[1] += weight;
792 cout = case_create (casewriter_get_proto (iter->writer));
794 case_data_rw (cout, iter->subject)->f
795 = case_data (input, iter->src)->f;
797 wv = dict_get_case_weight (agr->src_dict, input, NULL);
799 case_data_rw (cout, iter->weight)->f = wv;
803 casewriter_write (iter->writer, cout);
807 moments1_add (iter->moments, v->f, weight);
810 iter->dbl[0] = MAX (iter->dbl[0], v->f);
814 if (memcmp (iter->string, value_str (v, src_width), src_width) < 0)
815 memcpy (iter->string, value_str (v, src_width), src_width);
819 iter->dbl[0] = MIN (iter->dbl[0], v->f);
823 if (memcmp (iter->string, value_str (v, src_width), src_width) > 0)
824 memcpy (iter->string, value_str (v, src_width), src_width);
829 if (v->f > iter->arg[0].f)
830 iter->dbl[0] += weight;
831 iter->dbl[1] += weight;
835 if (memcmp (iter->arg[0].c,
836 value_str (v, src_width), 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,
849 value_str (v, src_width), src_width) > 0)
850 iter->dbl[0] += weight;
851 iter->dbl[1] += weight;
855 if (iter->arg[0].f <= v->f && v->f <= iter->arg[1].f)
856 iter->dbl[0] += weight;
857 iter->dbl[1] += weight;
861 if (memcmp (iter->arg[0].c,
862 value_str (v, src_width), src_width) <= 0
863 && memcmp (iter->arg[1].c,
864 value_str (v, src_width), 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,
877 value_str (v, src_width), src_width) > 0
878 || memcmp (iter->arg[1].c,
879 value_str (v, src_width), src_width) < 0)
880 iter->dbl[0] += weight;
881 iter->dbl[1] += weight;
885 iter->dbl[0] += weight;
898 case FIRST | FSTRING:
901 memcpy (iter->string, value_str (v, src_width), src_width);
910 memcpy (iter->string, value_str (v, src_width), src_width);
914 case NMISS | FSTRING:
916 case NUMISS | FSTRING:
917 /* Our value is not missing or it would have been
918 caught earlier. Nothing to do. */
924 switch (iter->function)
927 iter->dbl[0] += weight;
938 /* Writes an aggregated record to OUTPUT. */
940 dump_aggregate_info (const struct agr_proc *agr, struct casewriter *output, const struct ccase *break_case)
942 struct ccase *c = case_create (dict_get_proto (agr->dict));
944 if ( agr->add_variables)
946 case_copy (c, 0, break_case, 0, dict_get_var_cnt (agr->src_dict));
953 for (i = 0; i < agr->break_var_cnt; i++)
955 const struct variable *v = agr->break_vars[i];
956 value_copy (case_data_rw_idx (c, value_idx),
957 case_data (break_case, v),
966 for (i = agr->agr_vars; i; i = i->next)
968 union value *v = case_data_rw (c, i->dest);
969 int width = var_get_width (i->dest);
971 if (agr->missing == COLUMNWISE && i->saw_missing
972 && (i->function & FUNC) != N && (i->function & FUNC) != NU
973 && (i->function & FUNC) != NMISS && (i->function & FUNC) != NUMISS)
975 value_set_missing (v, width);
976 casewriter_destroy (i->writer);
983 v->f = i->int1 ? i->dbl[0] : SYSMIS;
986 v->f = i->dbl[1] != 0.0 ? i->dbl[0] / i->dbl[1] : SYSMIS;
992 struct percentile *median = percentile_create (0.5, i->cc);
993 struct order_stats *os = &median->parent;
994 struct casereader *sorted_reader = casewriter_make_reader (i->writer);
997 order_stats_accumulate (&os, 1,
1002 i->dbl[0] = percentile_calculate (median, PC_HAVERAGE);
1003 statistic_destroy (&median->parent.parent);
1012 /* FIXME: we should use two passes. */
1013 moments1_calculate (i->moments, NULL, NULL, &variance,
1015 if (variance != SYSMIS)
1016 v->f = sqrt (variance);
1023 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1028 memcpy (value_str_rw (v, width), i->string, width);
1030 value_set_missing (v, width);
1039 case FOUT | FSTRING:
1040 v->f = i->dbl[1] ? i->dbl[0] / i->dbl[1] : SYSMIS;
1049 case POUT | FSTRING:
1050 v->f = i->dbl[1] ? i->dbl[0] / i->dbl[1] * 100.0 : SYSMIS;
1062 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1064 case FIRST | FSTRING:
1065 case LAST | FSTRING:
1067 memcpy (value_str_rw (v, width), i->string, width);
1069 value_set_missing (v, width);
1072 case NMISS | FSTRING:
1076 case NUMISS | FSTRING:
1085 casewriter_write (output, c);
1088 /* Resets the state for all the aggregate functions. */
1090 initialize_aggregate_info (struct agr_proc *agr)
1092 struct agr_var *iter;
1094 for (iter = agr->agr_vars; iter; iter = iter->next)
1096 iter->saw_missing = false;
1097 iter->dbl[0] = iter->dbl[1] = iter->dbl[2] = 0.0;
1098 iter->int1 = iter->int2 = 0;
1099 switch (iter->function)
1102 iter->dbl[0] = DBL_MAX;
1105 memset (iter->string, 255, var_get_width (iter->src));
1108 iter->dbl[0] = -DBL_MAX;
1111 memset (iter->string, 0, var_get_width (iter->src));
1115 struct caseproto *proto;
1116 struct subcase ordering;
1118 proto = caseproto_create ();
1119 proto = caseproto_add_width (proto, 0);
1120 proto = caseproto_add_width (proto, 0);
1122 if ( ! iter->subject)
1123 iter->subject = dict_create_internal_var (0, 0);
1125 if ( ! iter->weight)
1126 iter->weight = dict_create_internal_var (1, 0);
1128 subcase_init_var (&ordering, iter->subject, SC_ASCEND);
1129 iter->writer = sort_create_writer (&ordering, proto);
1130 subcase_destroy (&ordering);
1131 caseproto_unref (proto);
1137 if (iter->moments == NULL)
1138 iter->moments = moments1_create (MOMENT_VARIANCE);
1140 moments1_clear (iter->moments);