1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006, 2008, 2009, 2010 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/>. */
21 #include <data/any-writer.h>
22 #include <data/case.h>
23 #include <data/casegrouper.h>
24 #include <data/casereader.h>
25 #include <data/casewriter.h>
26 #include <data/dictionary.h>
27 #include <data/file-handle-def.h>
28 #include <data/format.h>
29 #include <data/procedure.h>
30 #include <data/settings.h>
31 #include <data/subcase.h>
32 #include <data/sys-file-writer.h>
33 #include <data/variable.h>
34 #include <language/command.h>
35 #include <language/data-io/file-handle.h>
36 #include <language/lexer/lexer.h>
37 #include <language/lexer/variable-parser.h>
38 #include <language/stats/sort-criteria.h>
39 #include <libpspp/assertion.h>
40 #include <libpspp/message.h>
41 #include <libpspp/misc.h>
42 #include <libpspp/pool.h>
43 #include <libpspp/str.h>
44 #include <math/moments.h>
45 #include <math/sort.h>
46 #include <math/statistic.h>
47 #include <math/percentiles.h>
49 #include "aggregate.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, '/');
179 if (!lex_force_match_id (lexer, "OUTFILE"))
181 lex_match (lexer, '=');
182 if (!lex_match (lexer, '*'))
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, '=');
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, '/');
220 if (lex_match_id (lexer, "MISSING"))
222 lex_match (lexer, '=');
223 if (!lex_match_id (lexer, "COLUMNWISE"))
225 lex_error (lexer, _("while expecting 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_match_id (lexer, "BREAK"))
238 lex_match (lexer, '=');
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. */
253 lex_error (lexer, _("expecting BREAK"));
257 if (presorted && saw_direction)
258 msg (SW, _("When PRESORTED is specified, specifying sorting directions "
259 "with (A) or (D) has no effect. Output data will be sorted "
260 "the same way as the input data."));
262 /* Read in the aggregate functions. */
263 lex_match (lexer, '/');
264 if (!parse_aggregate_functions (lexer, dict, &agr))
267 /* Delete documents. */
269 dict_clear_documents (agr.dict);
271 /* Cancel SPLIT FILE. */
272 dict_set_split_vars (agr.dict, NULL, 0);
277 if (out_file == NULL)
279 /* The active file will be replaced by the aggregated data,
280 so TEMPORARY is moot. */
281 proc_cancel_temporary_transformations (ds);
282 proc_discard_output (ds);
283 output = autopaging_writer_create (dict_get_proto (agr.dict));
287 output = any_writer_open (out_file, agr.dict);
292 input = proc_open (ds);
293 if (!subcase_is_empty (&agr.sort) && !presorted)
295 input = sort_execute (input, &agr.sort);
296 subcase_clear (&agr.sort);
299 for (grouper = casegrouper_create_vars (input, agr.break_vars,
301 casegrouper_get_next_group (grouper, &group);
302 casereader_destroy (group))
304 struct casereader *placeholder = NULL;
305 struct ccase *c = casereader_peek (group, 0);
309 casereader_destroy (group);
313 initialize_aggregate_info (&agr);
315 if ( agr.add_variables )
316 placeholder = casereader_clone (group);
320 for (; (cg = casereader_read (group)) != NULL; case_unref (cg))
321 accumulate_aggregate_info (&agr, cg);
325 if (agr.add_variables)
328 for (; (cg = casereader_read (placeholder)) != NULL; case_unref (cg))
329 dump_aggregate_info (&agr, output, cg);
331 casereader_destroy (placeholder);
335 dump_aggregate_info (&agr, output, c);
339 if (!casegrouper_destroy (grouper))
342 if (!proc_commit (ds))
349 if (out_file == NULL)
351 struct casereader *next_input = casewriter_make_reader (output);
352 if (next_input == NULL)
355 proc_set_active_file (ds, next_input, agr.dict);
360 ok = casewriter_destroy (output);
373 casewriter_destroy (output);
376 return CMD_CASCADING_FAILURE;
379 /* Parse all the aggregate functions. */
381 parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict,
382 struct agr_proc *agr)
384 struct agr_var *tail; /* Tail of linked list starting at agr->vars. */
386 /* Parse everything. */
393 struct string function_name;
395 enum mv_class exclude;
396 const struct agr_func *function;
399 union agr_argument arg[2];
401 const struct variable **src;
414 ds_init_empty (&function_name);
416 /* Parse the list of target variables. */
417 while (!lex_match (lexer, '='))
419 size_t n_dest_prev = n_dest;
421 if (!parse_DATA_LIST_vars (lexer, &dest, &n_dest,
422 (PV_APPEND | PV_SINGLE | PV_NO_SCRATCH
426 /* Assign empty labels. */
430 dest_label = xnrealloc (dest_label, n_dest, sizeof *dest_label);
431 for (j = n_dest_prev; j < n_dest; j++)
432 dest_label[j] = NULL;
437 if (lex_token (lexer) == T_STRING)
440 ds_init_string (&label, lex_tokstr (lexer));
442 ds_truncate (&label, 255);
443 dest_label[n_dest - 1] = ds_xstrdup (&label);
449 /* Get the name of the aggregation function. */
450 if (lex_token (lexer) != T_ID)
452 lex_error (lexer, _("expecting aggregation function"));
458 ds_assign_string (&function_name, lex_tokstr (lexer));
460 ds_chomp (&function_name, '.');
462 if (lex_tokid(lexer)[strlen (lex_tokid (lexer)) - 1] == '.')
465 for (function = agr_func_tab; function->name; function++)
466 if (!strcasecmp (function->name, ds_cstr (&function_name)))
468 if (NULL == function->name)
470 msg (SE, _("Unknown aggregation function %s."),
471 ds_cstr (&function_name));
474 ds_destroy (&function_name);
475 func_index = function - agr_func_tab;
478 /* Check for leading lparen. */
479 if (!lex_match (lexer, '('))
481 if (function->src_vars == AGR_SV_YES)
483 lex_error (lexer, _("expecting `('"));
489 /* Parse list of source variables. */
491 int pv_opts = PV_NO_SCRATCH;
493 if (func_index == SUM || func_index == MEAN || func_index == SD)
494 pv_opts |= PV_NUMERIC;
495 else if (function->n_args)
496 pv_opts |= PV_SAME_TYPE;
498 if (!parse_variables_const (lexer, dict, &src, &n_src, pv_opts))
502 /* Parse function arguments, for those functions that
503 require arguments. */
504 if (function->n_args != 0)
505 for (i = 0; i < function->n_args; i++)
509 lex_match (lexer, ',');
510 if (lex_token (lexer) == T_STRING)
512 arg[i].c = ds_xstrdup (lex_tokstr (lexer));
515 else if (lex_is_number (lexer))
517 arg[i].f = lex_tokval (lexer);
522 msg (SE, _("Missing argument %zu to %s."),
523 i + 1, function->name);
529 if (type != var_get_type (src[0]))
531 msg (SE, _("Arguments to %s must be of same type as "
532 "source variables."),
538 /* Trailing rparen. */
539 if (!lex_match (lexer, ')'))
541 lex_error (lexer, _("expecting `)'"));
545 /* Now check that the number of source variables match
546 the number of target variables. If we check earlier
547 than this, the user can get very misleading error
548 message, i.e. `AGGREGATE x=SUM(y t).' will get this
549 error message when a proper message would be more
550 like `unknown variable t'. */
553 msg (SE, _("Number of source variables (%zu) does not match "
554 "number of target variables (%zu)."),
559 if ((func_index == PIN || func_index == POUT
560 || func_index == FIN || func_index == FOUT)
561 && (var_is_numeric (src[0])
562 ? arg[0].f > arg[1].f
563 : str_compare_rpad (arg[0].c, arg[1].c) > 0))
565 union agr_argument t = arg[0];
569 msg (SW, _("The value arguments passed to the %s function "
570 "are out-of-order. They will be treated as if "
571 "they had been specified in the correct order."),
576 /* Finally add these to the linked list of aggregation
578 for (i = 0; i < n_dest; i++)
580 struct agr_var *v = xzalloc (sizeof *v);
582 /* Add variable to chain. */
583 if (agr->agr_vars != NULL)
591 /* Create the target variable in the aggregate
594 struct variable *destvar;
596 v->function = func_index;
602 if (var_is_alpha (src[i]))
604 v->function |= FSTRING;
605 v->string = xmalloc (var_get_width (src[i]));
608 if (function->alpha_type == VAL_STRING)
609 destvar = dict_clone_var_as (agr->dict, v->src, dest[i]);
612 assert (var_is_numeric (v->src)
613 || function->alpha_type == VAL_NUMERIC);
614 destvar = dict_create_var (agr->dict, dest[i], 0);
618 if ((func_index == N || func_index == NMISS)
619 && dict_get_weight (dict) != NULL)
620 f = fmt_for_output (FMT_F, 8, 2);
622 f = function->format;
623 var_set_both_formats (destvar, &f);
629 destvar = dict_create_var (agr->dict, dest[i], 0);
632 if ((func_index == N || func_index == NMISS)
633 && dict_get_weight (dict) != NULL)
634 f = fmt_for_output (FMT_F, 8, 2);
636 f = function->format;
637 var_set_both_formats (destvar, &f);
643 msg (SE, _("Variable name %s is not unique within the "
644 "aggregate file dictionary, which contains "
645 "the aggregate variables and the break "
653 var_set_label (destvar, dest_label[i]);
658 v->exclude = exclude;
664 if (var_is_numeric (v->src))
665 for (j = 0; j < function->n_args; j++)
666 v->arg[j].f = arg[j].f;
668 for (j = 0; j < function->n_args; j++)
669 v->arg[j].c = xstrdup (arg[j].c);
673 if (src != NULL && var_is_alpha (src[0]))
674 for (i = 0; i < function->n_args; i++)
684 if (!lex_match (lexer, '/'))
686 if (lex_token (lexer) == '.')
689 lex_error (lexer, "expecting end of command");
695 ds_destroy (&function_name);
696 for (i = 0; i < n_dest; i++)
699 free (dest_label[i]);
705 if (src && n_src && var_is_alpha (src[0]))
706 for (i = 0; i < function->n_args; i++)
719 agr_destroy (struct agr_proc *agr)
721 struct agr_var *iter, *next;
723 subcase_destroy (&agr->sort);
724 free (agr->break_vars);
725 for (iter = agr->agr_vars; iter; iter = next)
729 if (iter->function & FSTRING)
734 n_args = agr_func_tab[iter->function & FUNC].n_args;
735 for (i = 0; i < n_args; i++)
736 free (iter->arg[i].c);
739 else if (iter->function == SD)
740 moments1_destroy (iter->moments);
742 dict_destroy_internal_var (iter->subject);
743 dict_destroy_internal_var (iter->weight);
747 if (agr->dict != NULL)
748 dict_destroy (agr->dict);
753 /* Accumulates aggregation data from the case INPUT. */
755 accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input)
757 struct agr_var *iter;
759 bool bad_warn = true;
761 weight = dict_get_case_weight (agr->src_dict, input, &bad_warn);
763 for (iter = agr->agr_vars; iter; iter = iter->next)
766 const union value *v = case_data (input, iter->src);
767 int src_width = var_get_width (iter->src);
769 if (var_is_value_missing (iter->src, v, iter->exclude))
771 switch (iter->function)
774 case NMISS | FSTRING:
775 iter->dbl[0] += weight;
778 case NUMISS | FSTRING:
782 iter->saw_missing = true;
786 /* This is horrible. There are too many possibilities. */
787 switch (iter->function)
790 iter->dbl[0] += v->f * weight;
794 iter->dbl[0] += v->f * weight;
795 iter->dbl[1] += weight;
802 cout = case_create (casewriter_get_proto (iter->writer));
804 case_data_rw (cout, iter->subject)->f
805 = case_data (input, iter->src)->f;
807 wv = dict_get_case_weight (agr->src_dict, input, NULL);
809 case_data_rw (cout, iter->weight)->f = wv;
813 casewriter_write (iter->writer, cout);
817 moments1_add (iter->moments, v->f, weight);
820 iter->dbl[0] = MAX (iter->dbl[0], v->f);
824 if (memcmp (iter->string, value_str (v, src_width), src_width) < 0)
825 memcpy (iter->string, value_str (v, src_width), src_width);
829 iter->dbl[0] = MIN (iter->dbl[0], v->f);
833 if (memcmp (iter->string, value_str (v, src_width), src_width) > 0)
834 memcpy (iter->string, value_str (v, src_width), src_width);
839 if (v->f > iter->arg[0].f)
840 iter->dbl[0] += weight;
841 iter->dbl[1] += weight;
845 if (memcmp (iter->arg[0].c,
846 value_str (v, src_width), src_width) < 0)
847 iter->dbl[0] += weight;
848 iter->dbl[1] += weight;
852 if (v->f < iter->arg[0].f)
853 iter->dbl[0] += weight;
854 iter->dbl[1] += weight;
858 if (memcmp (iter->arg[0].c,
859 value_str (v, src_width), src_width) > 0)
860 iter->dbl[0] += weight;
861 iter->dbl[1] += weight;
865 if (iter->arg[0].f <= v->f && v->f <= iter->arg[1].f)
866 iter->dbl[0] += weight;
867 iter->dbl[1] += weight;
871 if (memcmp (iter->arg[0].c,
872 value_str (v, src_width), src_width) <= 0
873 && memcmp (iter->arg[1].c,
874 value_str (v, src_width), src_width) >= 0)
875 iter->dbl[0] += weight;
876 iter->dbl[1] += weight;
880 if (iter->arg[0].f > v->f || v->f > iter->arg[1].f)
881 iter->dbl[0] += weight;
882 iter->dbl[1] += weight;
886 if (memcmp (iter->arg[0].c,
887 value_str (v, src_width), src_width) > 0
888 || memcmp (iter->arg[1].c,
889 value_str (v, src_width), src_width) < 0)
890 iter->dbl[0] += weight;
891 iter->dbl[1] += weight;
895 iter->dbl[0] += weight;
908 case FIRST | FSTRING:
911 memcpy (iter->string, value_str (v, src_width), src_width);
920 memcpy (iter->string, value_str (v, src_width), src_width);
924 case NMISS | FSTRING:
926 case NUMISS | FSTRING:
927 /* Our value is not missing or it would have been
928 caught earlier. Nothing to do. */
934 switch (iter->function)
937 iter->dbl[0] += weight;
948 /* Writes an aggregated record to OUTPUT. */
950 dump_aggregate_info (const struct agr_proc *agr, struct casewriter *output, const struct ccase *break_case)
952 struct ccase *c = case_create (dict_get_proto (agr->dict));
954 if ( agr->add_variables)
956 case_copy (c, 0, break_case, 0, dict_get_var_cnt (agr->src_dict));
963 for (i = 0; i < agr->break_var_cnt; i++)
965 const struct variable *v = agr->break_vars[i];
966 value_copy (case_data_rw_idx (c, value_idx),
967 case_data (break_case, v),
976 for (i = agr->agr_vars; i; i = i->next)
978 union value *v = case_data_rw (c, i->dest);
979 int width = var_get_width (i->dest);
981 if (agr->missing == COLUMNWISE && i->saw_missing
982 && (i->function & FUNC) != N && (i->function & FUNC) != NU
983 && (i->function & FUNC) != NMISS && (i->function & FUNC) != NUMISS)
985 value_set_missing (v, width);
986 casewriter_destroy (i->writer);
993 v->f = i->int1 ? i->dbl[0] : SYSMIS;
996 v->f = i->dbl[1] != 0.0 ? i->dbl[0] / i->dbl[1] : SYSMIS;
1002 struct percentile *median = percentile_create (0.5, i->cc);
1003 struct order_stats *os = &median->parent;
1004 struct casereader *sorted_reader = casewriter_make_reader (i->writer);
1007 order_stats_accumulate (&os, 1,
1012 i->dbl[0] = percentile_calculate (median, PC_HAVERAGE);
1013 statistic_destroy (&median->parent.parent);
1022 /* FIXME: we should use two passes. */
1023 moments1_calculate (i->moments, NULL, NULL, &variance,
1025 if (variance != SYSMIS)
1026 v->f = sqrt (variance);
1033 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1038 memcpy (value_str_rw (v, width), i->string, width);
1040 value_set_missing (v, width);
1049 case FOUT | FSTRING:
1050 v->f = i->dbl[1] ? i->dbl[0] / i->dbl[1] : SYSMIS;
1059 case POUT | FSTRING:
1060 v->f = i->dbl[1] ? i->dbl[0] / i->dbl[1] * 100.0 : SYSMIS;
1072 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1074 case FIRST | FSTRING:
1075 case LAST | FSTRING:
1077 memcpy (value_str_rw (v, width), i->string, width);
1079 value_set_missing (v, width);
1082 case NMISS | FSTRING:
1086 case NUMISS | FSTRING:
1095 casewriter_write (output, c);
1098 /* Resets the state for all the aggregate functions. */
1100 initialize_aggregate_info (struct agr_proc *agr)
1102 struct agr_var *iter;
1104 for (iter = agr->agr_vars; iter; iter = iter->next)
1106 iter->saw_missing = false;
1107 iter->dbl[0] = iter->dbl[1] = iter->dbl[2] = 0.0;
1108 iter->int1 = iter->int2 = 0;
1109 switch (iter->function)
1112 iter->dbl[0] = DBL_MAX;
1115 memset (iter->string, 255, var_get_width (iter->src));
1118 iter->dbl[0] = -DBL_MAX;
1121 memset (iter->string, 0, var_get_width (iter->src));
1125 struct caseproto *proto;
1126 struct subcase ordering;
1128 proto = caseproto_create ();
1129 proto = caseproto_add_width (proto, 0);
1130 proto = caseproto_add_width (proto, 0);
1132 if ( ! iter->subject)
1133 iter->subject = dict_create_internal_var (0, 0);
1135 if ( ! iter->weight)
1136 iter->weight = dict_create_internal_var (1, 0);
1138 subcase_init_var (&ordering, iter->subject, SC_ASCEND);
1139 iter->writer = sort_create_writer (&ordering, proto);
1140 subcase_destroy (&ordering);
1141 caseproto_unref (proto);
1147 if (iter->moments == NULL)
1148 iter->moments = moments1_create (MOMENT_VARIANCE);
1150 moments1_clear (iter->moments);