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>
53 #define _(msgid) gettext (msgid)
55 /* Argument for AGGREGATE function. */
58 double f; /* Numeric. */
59 char *c; /* Short or long string. */
62 /* Specifies how to make an aggregate variable. */
65 struct agr_var *next; /* Next in list. */
67 /* Collected during parsing. */
68 const struct variable *src; /* Source variable. */
69 struct variable *dest; /* Target variable. */
70 int function; /* Function. */
71 enum mv_class exclude; /* Classes of missing values to exclude. */
72 union agr_argument arg[2]; /* Arguments. */
74 /* Accumulated during AGGREGATE execution. */
79 struct moments1 *moments;
82 struct variable *subject;
83 struct variable *weight;
84 struct casewriter *writer;
87 /* Aggregation functions. */
90 NONE, SUM, MEAN, MEDIAN, SD, MAX, MIN, PGT, PLT, PIN, POUT, FGT, FLT, FIN,
91 FOUT, N, NU, NMISS, NUMISS, FIRST, LAST,
92 N_AGR_FUNCS, N_NO_VARS, NU_NO_VARS,
93 FUNC = 0x1f, /* Function mask. */
94 FSTRING = 1<<5, /* String function bit. */
97 /* Attributes of an aggregation function. */
100 const char *name; /* Aggregation function name. */
101 size_t n_args; /* Number of arguments. */
102 enum val_type alpha_type; /* When given ALPHA arguments, output type. */
103 struct fmt_spec format; /* Format spec if alpha_type != ALPHA. */
106 /* Attributes of aggregation functions. */
107 static const struct agr_func agr_func_tab[] =
109 {"<NONE>", 0, -1, {0, 0, 0}},
110 {"SUM", 0, -1, {FMT_F, 8, 2}},
111 {"MEAN", 0, -1, {FMT_F, 8, 2}},
112 {"MEDIAN", 0, -1, {FMT_F, 8, 2}},
113 {"SD", 0, -1, {FMT_F, 8, 2}},
114 {"MAX", 0, VAL_STRING, {-1, -1, -1}},
115 {"MIN", 0, VAL_STRING, {-1, -1, -1}},
116 {"PGT", 1, VAL_NUMERIC, {FMT_F, 5, 1}},
117 {"PLT", 1, VAL_NUMERIC, {FMT_F, 5, 1}},
118 {"PIN", 2, VAL_NUMERIC, {FMT_F, 5, 1}},
119 {"POUT", 2, VAL_NUMERIC, {FMT_F, 5, 1}},
120 {"FGT", 1, VAL_NUMERIC, {FMT_F, 5, 3}},
121 {"FLT", 1, VAL_NUMERIC, {FMT_F, 5, 3}},
122 {"FIN", 2, VAL_NUMERIC, {FMT_F, 5, 3}},
123 {"FOUT", 2, VAL_NUMERIC, {FMT_F, 5, 3}},
124 {"N", 0, VAL_NUMERIC, {FMT_F, 7, 0}},
125 {"NU", 0, VAL_NUMERIC, {FMT_F, 7, 0}},
126 {"NMISS", 0, VAL_NUMERIC, {FMT_F, 7, 0}},
127 {"NUMISS", 0, VAL_NUMERIC, {FMT_F, 7, 0}},
128 {"FIRST", 0, VAL_STRING, {-1, -1, -1}},
129 {"LAST", 0, VAL_STRING, {-1, -1, -1}},
130 {NULL, 0, -1, {-1, -1, -1}},
131 {"N", 0, VAL_NUMERIC, {FMT_F, 7, 0}},
132 {"NU", 0, VAL_NUMERIC, {FMT_F, 7, 0}},
135 /* Missing value types. */
136 enum missing_treatment
138 ITEMWISE, /* Missing values item by item. */
139 COLUMNWISE /* Missing values column by column. */
142 /* An entire AGGREGATE procedure. */
145 /* Break variables. */
146 struct subcase sort; /* Sort criteria (break variables). */
147 const struct variable **break_vars; /* Break variables. */
148 size_t break_var_cnt; /* Number of break variables. */
150 enum missing_treatment missing; /* How to treat missing values. */
151 struct agr_var *agr_vars; /* First aggregate variable. */
152 struct dictionary *dict; /* Aggregate dictionary. */
153 const struct dictionary *src_dict; /* Dict of the source */
154 int case_cnt; /* Counts aggregated cases. */
156 bool add_variables; /* True iff the aggregated variables should
157 be appended to the existing dictionary */
160 static void initialize_aggregate_info (struct agr_proc *);
162 static void accumulate_aggregate_info (struct agr_proc *,
163 const struct ccase *);
165 static bool parse_aggregate_functions (struct lexer *, const struct dictionary *,
167 static void agr_destroy (struct agr_proc *);
168 static void dump_aggregate_info (const struct agr_proc *agr,
169 struct casewriter *output,
170 const struct ccase *break_case);
174 /* Parses and executes the AGGREGATE procedure. */
176 cmd_aggregate (struct lexer *lexer, struct dataset *ds)
178 struct dictionary *dict = dataset_dict (ds);
180 struct file_handle *out_file = NULL;
181 struct casereader *input = NULL, *group;
182 struct casegrouper *grouper;
183 struct casewriter *output = NULL;
185 bool copy_documents = false;
186 bool presorted = false;
190 memset(&agr, 0 , sizeof (agr));
191 agr.missing = ITEMWISE;
193 subcase_init_empty (&agr.sort);
195 /* OUTFILE subcommand must be first. */
196 lex_match (lexer, '/');
197 if (!lex_force_match_id (lexer, "OUTFILE"))
199 lex_match (lexer, '=');
200 if (!lex_match (lexer, '*'))
202 out_file = fh_parse (lexer, FH_REF_FILE | FH_REF_SCRATCH);
203 if (out_file == NULL)
207 if (out_file == NULL && lex_match_id (lexer, "MODE"))
209 lex_match (lexer, '=');
210 if (lex_match_id (lexer, "ADDVARIABLES"))
212 agr.add_variables = true;
214 /* presorted is assumed in ADDVARIABLES mode */
217 else if (lex_match_id (lexer, "REPLACE"))
219 agr.add_variables = false;
225 if ( agr.add_variables )
226 agr.dict = dict_clone (dict);
228 agr.dict = dict_create ();
230 dict_set_label (agr.dict, dict_get_label (dict));
231 dict_set_documents (agr.dict, dict_get_documents (dict));
233 /* Read most of the subcommands. */
236 lex_match (lexer, '/');
238 if (lex_match_id (lexer, "MISSING"))
240 lex_match (lexer, '=');
241 if (!lex_match_id (lexer, "COLUMNWISE"))
243 lex_error (lexer, _("while expecting COLUMNWISE"));
246 agr.missing = COLUMNWISE;
248 else if (lex_match_id (lexer, "DOCUMENT"))
249 copy_documents = true;
250 else if (lex_match_id (lexer, "PRESORTED"))
252 else if (lex_match_id (lexer, "BREAK"))
256 lex_match (lexer, '=');
257 if (!parse_sort_criteria (lexer, dict, &agr.sort, &agr.break_vars,
260 agr.break_var_cnt = subcase_get_n_fields (&agr.sort);
262 if (! agr.add_variables)
263 for (i = 0; i < agr.break_var_cnt; i++)
264 dict_clone_var_assert (agr.dict, agr.break_vars[i]);
266 /* BREAK must follow the options. */
271 lex_error (lexer, _("expecting BREAK"));
275 if (presorted && saw_direction)
276 msg (SW, _("When PRESORTED is specified, specifying sorting directions "
277 "with (A) or (D) has no effect. Output data will be sorted "
278 "the same way as the input data."));
280 /* Read in the aggregate functions. */
281 lex_match (lexer, '/');
282 if (!parse_aggregate_functions (lexer, dict, &agr))
285 /* Delete documents. */
287 dict_clear_documents (agr.dict);
289 /* Cancel SPLIT FILE. */
290 dict_set_split_vars (agr.dict, NULL, 0);
295 if (out_file == NULL)
297 /* The active file will be replaced by the aggregated data,
298 so TEMPORARY is moot. */
299 proc_cancel_temporary_transformations (ds);
300 proc_discard_output (ds);
301 output = autopaging_writer_create (dict_get_proto (agr.dict));
305 output = any_writer_open (out_file, agr.dict);
310 input = proc_open (ds);
311 if (!subcase_is_empty (&agr.sort) && !presorted)
313 input = sort_execute (input, &agr.sort);
314 subcase_clear (&agr.sort);
317 for (grouper = casegrouper_create_vars (input, agr.break_vars,
319 casegrouper_get_next_group (grouper, &group);
320 casereader_destroy (group))
322 struct casereader *placeholder = NULL;
323 struct ccase *c = casereader_peek (group, 0);
327 casereader_destroy (group);
331 initialize_aggregate_info (&agr);
333 if ( agr.add_variables )
334 placeholder = casereader_clone (group);
338 for (; (cg = casereader_read (group)) != NULL; case_unref (cg))
339 accumulate_aggregate_info (&agr, cg);
343 if (agr.add_variables)
346 for (; (cg = casereader_read (placeholder)) != NULL; case_unref (cg))
347 dump_aggregate_info (&agr, output, cg);
349 casereader_destroy (placeholder);
353 dump_aggregate_info (&agr, output, c);
357 if (!casegrouper_destroy (grouper))
360 if (!proc_commit (ds))
367 if (out_file == NULL)
369 struct casereader *next_input = casewriter_make_reader (output);
370 if (next_input == NULL)
373 proc_set_active_file (ds, next_input, agr.dict);
378 ok = casewriter_destroy (output);
391 casewriter_destroy (output);
394 return CMD_CASCADING_FAILURE;
397 /* Parse all the aggregate functions. */
399 parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict,
400 struct agr_proc *agr)
402 struct agr_var *tail; /* Tail of linked list starting at agr->vars. */
404 /* Parse everything. */
411 struct string function_name;
413 enum mv_class exclude;
414 const struct agr_func *function;
417 union agr_argument arg[2];
419 const struct variable **src;
432 ds_init_empty (&function_name);
434 /* Parse the list of target variables. */
435 while (!lex_match (lexer, '='))
437 size_t n_dest_prev = n_dest;
439 if (!parse_DATA_LIST_vars (lexer, &dest, &n_dest,
440 (PV_APPEND | PV_SINGLE | PV_NO_SCRATCH
444 /* Assign empty labels. */
448 dest_label = xnrealloc (dest_label, n_dest, sizeof *dest_label);
449 for (j = n_dest_prev; j < n_dest; j++)
450 dest_label[j] = NULL;
455 if (lex_token (lexer) == T_STRING)
458 ds_init_string (&label, lex_tokstr (lexer));
460 ds_truncate (&label, 255);
461 dest_label[n_dest - 1] = ds_xstrdup (&label);
467 /* Get the name of the aggregation function. */
468 if (lex_token (lexer) != T_ID)
470 lex_error (lexer, _("expecting aggregation function"));
476 ds_assign_string (&function_name, lex_tokstr (lexer));
478 ds_chomp (&function_name, '.');
480 if (lex_tokid(lexer)[strlen (lex_tokid (lexer)) - 1] == '.')
483 for (function = agr_func_tab; function->name; function++)
484 if (!strcasecmp (function->name, ds_cstr (&function_name)))
486 if (NULL == function->name)
488 msg (SE, _("Unknown aggregation function %s."),
489 ds_cstr (&function_name));
492 ds_destroy (&function_name);
493 func_index = function - agr_func_tab;
496 /* Check for leading lparen. */
497 if (!lex_match (lexer, '('))
500 func_index = N_NO_VARS;
501 else if (func_index == NU)
502 func_index = NU_NO_VARS;
505 lex_error (lexer, _("expecting `('"));
511 /* Parse list of source variables. */
513 int pv_opts = PV_NO_SCRATCH;
515 if (func_index == SUM || func_index == MEAN || func_index == SD)
516 pv_opts |= PV_NUMERIC;
517 else if (function->n_args)
518 pv_opts |= PV_SAME_TYPE;
520 if (!parse_variables_const (lexer, dict, &src, &n_src, pv_opts))
524 /* Parse function arguments, for those functions that
525 require arguments. */
526 if (function->n_args != 0)
527 for (i = 0; i < function->n_args; i++)
531 lex_match (lexer, ',');
532 if (lex_token (lexer) == T_STRING)
534 arg[i].c = ds_xstrdup (lex_tokstr (lexer));
537 else if (lex_is_number (lexer))
539 arg[i].f = lex_tokval (lexer);
544 msg (SE, _("Missing argument %zu to %s."),
545 i + 1, function->name);
551 if (type != var_get_type (src[0]))
553 msg (SE, _("Arguments to %s must be of same type as "
554 "source variables."),
560 /* Trailing rparen. */
561 if (!lex_match (lexer, ')'))
563 lex_error (lexer, _("expecting `)'"));
567 /* Now check that the number of source variables match
568 the number of target variables. If we check earlier
569 than this, the user can get very misleading error
570 message, i.e. `AGGREGATE x=SUM(y t).' will get this
571 error message when a proper message would be more
572 like `unknown variable t'. */
575 msg (SE, _("Number of source variables (%zu) does not match "
576 "number of target variables (%zu)."),
581 if ((func_index == PIN || func_index == POUT
582 || func_index == FIN || func_index == FOUT)
583 && (var_is_numeric (src[0])
584 ? arg[0].f > arg[1].f
585 : str_compare_rpad (arg[0].c, arg[1].c) > 0))
587 union agr_argument t = arg[0];
591 msg (SW, _("The value arguments passed to the %s function "
592 "are out-of-order. They will be treated as if "
593 "they had been specified in the correct order."),
598 /* Finally add these to the linked list of aggregation
600 for (i = 0; i < n_dest; i++)
602 struct agr_var *v = xzalloc (sizeof *v);
604 /* Add variable to chain. */
605 if (agr->agr_vars != NULL)
613 /* Create the target variable in the aggregate
616 struct variable *destvar;
618 v->function = func_index;
624 if (var_is_alpha (src[i]))
626 v->function |= FSTRING;
627 v->string = xmalloc (var_get_width (src[i]));
630 if (function->alpha_type == VAL_STRING)
631 destvar = dict_clone_var_as (agr->dict, v->src, dest[i]);
634 assert (var_is_numeric (v->src)
635 || function->alpha_type == VAL_NUMERIC);
636 destvar = dict_create_var (agr->dict, dest[i], 0);
640 if ((func_index == N || func_index == NMISS)
641 && dict_get_weight (dict) != NULL)
642 f = fmt_for_output (FMT_F, 8, 2);
644 f = function->format;
645 var_set_both_formats (destvar, &f);
651 destvar = dict_create_var (agr->dict, dest[i], 0);
652 if (func_index == N_NO_VARS && dict_get_weight (dict) != NULL)
653 f = fmt_for_output (FMT_F, 8, 2);
655 f = function->format;
656 var_set_both_formats (destvar, &f);
661 msg (SE, _("Variable name %s is not unique within the "
662 "aggregate file dictionary, which contains "
663 "the aggregate variables and the break "
671 var_set_label (destvar, dest_label[i]);
676 v->exclude = exclude;
682 if (var_is_numeric (v->src))
683 for (j = 0; j < function->n_args; j++)
684 v->arg[j].f = arg[j].f;
686 for (j = 0; j < function->n_args; j++)
687 v->arg[j].c = xstrdup (arg[j].c);
691 if (src != NULL && var_is_alpha (src[0]))
692 for (i = 0; i < function->n_args; i++)
702 if (!lex_match (lexer, '/'))
704 if (lex_token (lexer) == '.')
707 lex_error (lexer, "expecting end of command");
713 ds_destroy (&function_name);
714 for (i = 0; i < n_dest; i++)
717 free (dest_label[i]);
723 if (src && n_src && var_is_alpha (src[0]))
724 for (i = 0; i < function->n_args; i++)
737 agr_destroy (struct agr_proc *agr)
739 struct agr_var *iter, *next;
741 subcase_destroy (&agr->sort);
742 free (agr->break_vars);
743 for (iter = agr->agr_vars; iter; iter = next)
747 if (iter->function & FSTRING)
752 n_args = agr_func_tab[iter->function & FUNC].n_args;
753 for (i = 0; i < n_args; i++)
754 free (iter->arg[i].c);
757 else if (iter->function == SD)
758 moments1_destroy (iter->moments);
760 dict_destroy_internal_var (iter->subject);
761 dict_destroy_internal_var (iter->weight);
765 if (agr->dict != NULL)
766 dict_destroy (agr->dict);
771 /* Accumulates aggregation data from the case INPUT. */
773 accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input)
775 struct agr_var *iter;
777 bool bad_warn = true;
779 weight = dict_get_case_weight (agr->src_dict, input, &bad_warn);
781 for (iter = agr->agr_vars; iter; iter = iter->next)
784 const union value *v = case_data (input, iter->src);
785 int src_width = var_get_width (iter->src);
787 if (var_is_value_missing (iter->src, v, iter->exclude))
789 switch (iter->function)
792 case NMISS | FSTRING:
793 iter->dbl[0] += weight;
796 case NUMISS | FSTRING:
800 iter->saw_missing = true;
804 /* This is horrible. There are too many possibilities. */
805 switch (iter->function)
808 iter->dbl[0] += v->f * weight;
812 iter->dbl[0] += v->f * weight;
813 iter->dbl[1] += weight;
820 cout = case_create (casewriter_get_proto (iter->writer));
822 case_data_rw (cout, iter->subject)->f
823 = case_data (input, iter->src)->f;
825 wv = dict_get_case_weight (agr->src_dict, input, NULL);
827 case_data_rw (cout, iter->weight)->f = wv;
831 casewriter_write (iter->writer, cout);
835 moments1_add (iter->moments, v->f, weight);
838 iter->dbl[0] = MAX (iter->dbl[0], v->f);
842 if (memcmp (iter->string, value_str (v, src_width), src_width) < 0)
843 memcpy (iter->string, value_str (v, src_width), src_width);
847 iter->dbl[0] = MIN (iter->dbl[0], v->f);
851 if (memcmp (iter->string, value_str (v, src_width), src_width) > 0)
852 memcpy (iter->string, value_str (v, src_width), src_width);
857 if (v->f > iter->arg[0].f)
858 iter->dbl[0] += weight;
859 iter->dbl[1] += weight;
863 if (memcmp (iter->arg[0].c,
864 value_str (v, src_width), src_width) < 0)
865 iter->dbl[0] += weight;
866 iter->dbl[1] += weight;
870 if (v->f < iter->arg[0].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 iter->dbl[0] += weight;
879 iter->dbl[1] += weight;
883 if (iter->arg[0].f <= v->f && v->f <= iter->arg[1].f)
884 iter->dbl[0] += weight;
885 iter->dbl[1] += weight;
889 if (memcmp (iter->arg[0].c,
890 value_str (v, src_width), src_width) <= 0
891 && memcmp (iter->arg[1].c,
892 value_str (v, src_width), src_width) >= 0)
893 iter->dbl[0] += weight;
894 iter->dbl[1] += weight;
898 if (iter->arg[0].f > v->f || v->f > iter->arg[1].f)
899 iter->dbl[0] += weight;
900 iter->dbl[1] += weight;
904 if (memcmp (iter->arg[0].c,
905 value_str (v, src_width), src_width) > 0
906 || memcmp (iter->arg[1].c,
907 value_str (v, src_width), src_width) < 0)
908 iter->dbl[0] += weight;
909 iter->dbl[1] += weight;
913 iter->dbl[0] += weight;
926 case FIRST | FSTRING:
929 memcpy (iter->string, value_str (v, src_width), src_width);
938 memcpy (iter->string, value_str (v, src_width), src_width);
942 case NMISS | FSTRING:
944 case NUMISS | FSTRING:
945 /* Our value is not missing or it would have been
946 caught earlier. Nothing to do. */
952 switch (iter->function)
955 iter->dbl[0] += weight;
966 /* Writes an aggregated record to OUTPUT. */
968 dump_aggregate_info (const struct agr_proc *agr, struct casewriter *output, const struct ccase *break_case)
970 struct ccase *c = case_create (dict_get_proto (agr->dict));
972 if ( agr->add_variables)
974 case_copy (c, 0, break_case, 0, dict_get_var_cnt (agr->src_dict));
981 for (i = 0; i < agr->break_var_cnt; i++)
983 const struct variable *v = agr->break_vars[i];
984 value_copy (case_data_rw_idx (c, value_idx),
985 case_data (break_case, v),
994 for (i = agr->agr_vars; i; i = i->next)
996 union value *v = case_data_rw (c, i->dest);
997 int width = var_get_width (i->dest);
999 if (agr->missing == COLUMNWISE && i->saw_missing
1000 && (i->function & FUNC) != N && (i->function & FUNC) != NU
1001 && (i->function & FUNC) != NMISS && (i->function & FUNC) != NUMISS)
1003 value_set_missing (v, width);
1004 casewriter_destroy (i->writer);
1008 switch (i->function)
1011 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1014 v->f = i->dbl[1] != 0.0 ? i->dbl[0] / i->dbl[1] : SYSMIS;
1018 struct casereader *sorted_reader;
1019 struct percentile *median = percentile_create (0.5, i->cc);
1020 struct order_stats *os = &median->parent;
1022 sorted_reader = casewriter_make_reader (i->writer);
1024 order_stats_accumulate (&os, 1,
1030 v->f = percentile_calculate (median, PC_HAVERAGE);
1032 statistic_destroy (&median->parent.parent);
1039 /* FIXME: we should use two passes. */
1040 moments1_calculate (i->moments, NULL, NULL, &variance,
1042 if (variance != SYSMIS)
1043 v->f = sqrt (variance);
1050 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1055 memcpy (value_str_rw (v, width), i->string, width);
1057 value_set_missing (v, width);
1066 case FOUT | FSTRING:
1067 v->f = i->dbl[1] ? i->dbl[0] / i->dbl[1] : SYSMIS;
1076 case POUT | FSTRING:
1077 v->f = i->dbl[1] ? i->dbl[0] / i->dbl[1] * 100.0 : SYSMIS;
1089 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1091 case FIRST | FSTRING:
1092 case LAST | FSTRING:
1094 memcpy (value_str_rw (v, width), i->string, width);
1096 value_set_missing (v, width);
1105 case NMISS | FSTRING:
1109 case NUMISS | FSTRING:
1118 casewriter_write (output, c);
1121 /* Resets the state for all the aggregate functions. */
1123 initialize_aggregate_info (struct agr_proc *agr)
1125 struct agr_var *iter;
1127 for (iter = agr->agr_vars; iter; iter = iter->next)
1129 iter->saw_missing = false;
1130 iter->dbl[0] = iter->dbl[1] = iter->dbl[2] = 0.0;
1131 iter->int1 = iter->int2 = 0;
1132 switch (iter->function)
1135 iter->dbl[0] = DBL_MAX;
1138 memset (iter->string, 255, var_get_width (iter->src));
1141 iter->dbl[0] = -DBL_MAX;
1144 memset (iter->string, 0, var_get_width (iter->src));
1148 struct caseproto *proto;
1149 struct subcase ordering;
1151 proto = caseproto_create ();
1152 proto = caseproto_add_width (proto, 0);
1153 proto = caseproto_add_width (proto, 0);
1155 if ( ! iter->subject)
1156 iter->subject = dict_create_internal_var (0, 0);
1158 if ( ! iter->weight)
1159 iter->weight = dict_create_internal_var (1, 0);
1161 subcase_init_var (&ordering, iter->subject, SC_ASCEND);
1162 iter->writer = sort_create_writer (&ordering, proto);
1163 subcase_destroy (&ordering);
1164 caseproto_unref (proto);
1170 if (iter->moments == NULL)
1171 iter->moments = moments1_create (MOMENT_VARIANCE);
1173 moments1_clear (iter->moments);