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;
90 /* Aggregation functions. */
93 SUM, MEAN, MEDIAN, SD, MAX, MIN, PGT, PLT, PIN, POUT, FGT, FLT, FIN,
94 FOUT, N, NU, NMISS, NUMISS, FIRST, LAST,
96 FUNC = 0x1f, /* Function mask. */
97 FSTRING = 1<<5, /* String function bit. */
101 /* Attributes of aggregation functions. */
102 const struct agr_func agr_func_tab[] =
104 {"SUM", N_("Sum of values"), AGR_SV_YES, 0, -1, {FMT_F, 8, 2}},
105 {"MEAN", N_("Mean average"), AGR_SV_YES, 0, -1, {FMT_F, 8, 2}},
106 {"MEDIAN", N_("Median average"), AGR_SV_YES, 0, -1, {FMT_F, 8, 2}},
107 {"SD", N_("Standard deviation"), AGR_SV_YES, 0, -1, {FMT_F, 8, 2}},
108 {"MAX", N_("Maximum value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}},
109 {"MIN", N_("Minimum value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}},
110 {"PGT", N_("Percentage greater than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 1}},
111 {"PLT", N_("Percentage less than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 1}},
112 {"PIN", N_("Percentage included in range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 1}},
113 {"POUT", N_("Percentage excluded from range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 1}},
114 {"FGT", N_("Fraction greater than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 3}},
115 {"FLT", N_("Fraction less than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 3}},
116 {"FIN", N_("Fraction included in range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 3}},
117 {"FOUT", N_("Fraction excluded from range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 3}},
118 {"N", N_("Number of cases"), AGR_SV_NO, 0, VAL_NUMERIC, {FMT_F, 7, 0}},
119 {"NU", N_("Number of cases (unweighted)"), AGR_SV_OPT, 0, VAL_NUMERIC, {FMT_F, 7, 0}},
120 {"NMISS", N_("Number of missing values"), AGR_SV_YES, 0, VAL_NUMERIC, {FMT_F, 7, 0}},
121 {"NUMISS", N_("Number of missing values (unweighted)"), AGR_SV_YES, 0, VAL_NUMERIC, {FMT_F, 7, 0}},
122 {"FIRST", N_("First non-missing value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}},
123 {"LAST", N_("Last non-missing value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}},
124 {NULL, NULL, AGR_SV_NO, 0, -1, {-1, -1, -1}},
127 /* Missing value types. */
128 enum missing_treatment
130 ITEMWISE, /* Missing values item by item. */
131 COLUMNWISE /* Missing values column by column. */
134 /* An entire AGGREGATE procedure. */
137 /* Break variables. */
138 struct subcase sort; /* Sort criteria (break variables). */
139 const struct variable **break_vars; /* Break variables. */
140 size_t break_var_cnt; /* Number of break variables. */
142 enum missing_treatment missing; /* How to treat missing values. */
143 struct agr_var *agr_vars; /* First aggregate variable. */
144 struct dictionary *dict; /* Aggregate dictionary. */
145 const struct dictionary *src_dict; /* Dict of the source */
146 int case_cnt; /* Counts aggregated cases. */
148 bool add_variables; /* True iff the aggregated variables should
149 be appended to the existing dictionary */
152 static void initialize_aggregate_info (struct agr_proc *);
154 static void accumulate_aggregate_info (struct agr_proc *,
155 const struct ccase *);
157 static bool parse_aggregate_functions (struct lexer *, const struct dictionary *,
159 static void agr_destroy (struct agr_proc *);
160 static void dump_aggregate_info (const struct agr_proc *agr,
161 struct casewriter *output,
162 const struct ccase *break_case);
166 /* Parses and executes the AGGREGATE procedure. */
168 cmd_aggregate (struct lexer *lexer, struct dataset *ds)
170 struct dictionary *dict = dataset_dict (ds);
172 struct file_handle *out_file = NULL;
173 struct casereader *input = NULL, *group;
174 struct casegrouper *grouper;
175 struct casewriter *output = NULL;
177 bool copy_documents = false;
178 bool presorted = false;
182 memset(&agr, 0 , sizeof (agr));
183 agr.missing = ITEMWISE;
185 subcase_init_empty (&agr.sort);
187 /* OUTFILE subcommand must be first. */
188 lex_match (lexer, '/');
189 if (!lex_force_match_id (lexer, "OUTFILE"))
191 lex_match (lexer, '=');
192 if (!lex_match (lexer, '*'))
194 out_file = fh_parse (lexer, FH_REF_FILE | FH_REF_SCRATCH);
195 if (out_file == NULL)
199 if (out_file == NULL && lex_match_id (lexer, "MODE"))
201 lex_match (lexer, '=');
202 if (lex_match_id (lexer, "ADDVARIABLES"))
204 agr.add_variables = true;
206 /* presorted is assumed in ADDVARIABLES mode */
209 else if (lex_match_id (lexer, "REPLACE"))
211 agr.add_variables = false;
217 if ( agr.add_variables )
218 agr.dict = dict_clone (dict);
220 agr.dict = dict_create ();
222 dict_set_label (agr.dict, dict_get_label (dict));
223 dict_set_documents (agr.dict, dict_get_documents (dict));
225 /* Read most of the subcommands. */
228 lex_match (lexer, '/');
230 if (lex_match_id (lexer, "MISSING"))
232 lex_match (lexer, '=');
233 if (!lex_match_id (lexer, "COLUMNWISE"))
235 lex_error (lexer, _("while expecting COLUMNWISE"));
238 agr.missing = COLUMNWISE;
240 else if (lex_match_id (lexer, "DOCUMENT"))
241 copy_documents = true;
242 else if (lex_match_id (lexer, "PRESORTED"))
244 else if (lex_match_id (lexer, "BREAK"))
248 lex_match (lexer, '=');
249 if (!parse_sort_criteria (lexer, dict, &agr.sort, &agr.break_vars,
252 agr.break_var_cnt = subcase_get_n_fields (&agr.sort);
254 if (! agr.add_variables)
255 for (i = 0; i < agr.break_var_cnt; i++)
256 dict_clone_var_assert (agr.dict, agr.break_vars[i]);
258 /* BREAK must follow the options. */
263 lex_error (lexer, _("expecting BREAK"));
267 if (presorted && saw_direction)
268 msg (SW, _("When PRESORTED is specified, specifying sorting directions "
269 "with (A) or (D) has no effect. Output data will be sorted "
270 "the same way as the input data."));
272 /* Read in the aggregate functions. */
273 lex_match (lexer, '/');
274 if (!parse_aggregate_functions (lexer, dict, &agr))
277 /* Delete documents. */
279 dict_clear_documents (agr.dict);
281 /* Cancel SPLIT FILE. */
282 dict_set_split_vars (agr.dict, NULL, 0);
287 if (out_file == NULL)
289 /* The active file will be replaced by the aggregated data,
290 so TEMPORARY is moot. */
291 proc_cancel_temporary_transformations (ds);
292 proc_discard_output (ds);
293 output = autopaging_writer_create (dict_get_proto (agr.dict));
297 output = any_writer_open (out_file, agr.dict);
302 input = proc_open (ds);
303 if (!subcase_is_empty (&agr.sort) && !presorted)
305 input = sort_execute (input, &agr.sort);
306 subcase_clear (&agr.sort);
309 for (grouper = casegrouper_create_vars (input, agr.break_vars,
311 casegrouper_get_next_group (grouper, &group);
312 casereader_destroy (group))
314 struct casereader *placeholder = NULL;
315 struct ccase *c = casereader_peek (group, 0);
319 casereader_destroy (group);
323 initialize_aggregate_info (&agr);
325 if ( agr.add_variables )
326 placeholder = casereader_clone (group);
330 for (; (cg = casereader_read (group)) != NULL; case_unref (cg))
331 accumulate_aggregate_info (&agr, cg);
335 if (agr.add_variables)
338 for (; (cg = casereader_read (placeholder)) != NULL; case_unref (cg))
339 dump_aggregate_info (&agr, output, cg);
341 casereader_destroy (placeholder);
345 dump_aggregate_info (&agr, output, c);
349 if (!casegrouper_destroy (grouper))
352 if (!proc_commit (ds))
359 if (out_file == NULL)
361 struct casereader *next_input = casewriter_make_reader (output);
362 if (next_input == NULL)
365 proc_set_active_file (ds, next_input, agr.dict);
370 ok = casewriter_destroy (output);
383 casewriter_destroy (output);
386 return CMD_CASCADING_FAILURE;
389 /* Parse all the aggregate functions. */
391 parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict,
392 struct agr_proc *agr)
394 struct agr_var *tail; /* Tail of linked list starting at agr->vars. */
396 /* Parse everything. */
403 struct string function_name;
405 enum mv_class exclude;
406 const struct agr_func *function;
409 union agr_argument arg[2];
411 const struct variable **src;
424 ds_init_empty (&function_name);
426 /* Parse the list of target variables. */
427 while (!lex_match (lexer, '='))
429 size_t n_dest_prev = n_dest;
431 if (!parse_DATA_LIST_vars (lexer, &dest, &n_dest,
432 (PV_APPEND | PV_SINGLE | PV_NO_SCRATCH
436 /* Assign empty labels. */
440 dest_label = xnrealloc (dest_label, n_dest, sizeof *dest_label);
441 for (j = n_dest_prev; j < n_dest; j++)
442 dest_label[j] = NULL;
447 if (lex_token (lexer) == T_STRING)
450 ds_init_string (&label, lex_tokstr (lexer));
452 ds_truncate (&label, 255);
453 dest_label[n_dest - 1] = ds_xstrdup (&label);
459 /* Get the name of the aggregation function. */
460 if (lex_token (lexer) != T_ID)
462 lex_error (lexer, _("expecting aggregation function"));
468 ds_assign_string (&function_name, lex_tokstr (lexer));
470 ds_chomp (&function_name, '.');
472 if (lex_tokid(lexer)[strlen (lex_tokid (lexer)) - 1] == '.')
475 for (function = agr_func_tab; function->name; function++)
476 if (!strcasecmp (function->name, ds_cstr (&function_name)))
478 if (NULL == function->name)
480 msg (SE, _("Unknown aggregation function %s."),
481 ds_cstr (&function_name));
484 ds_destroy (&function_name);
485 func_index = function - agr_func_tab;
488 /* Check for leading lparen. */
489 if (!lex_match (lexer, '('))
491 if (function->src_vars == AGR_SV_YES)
493 lex_error (lexer, _("expecting `('"));
499 /* Parse list of source variables. */
501 int pv_opts = PV_NO_SCRATCH;
503 if (func_index == SUM || func_index == MEAN || func_index == SD)
504 pv_opts |= PV_NUMERIC;
505 else if (function->n_args)
506 pv_opts |= PV_SAME_TYPE;
508 if (!parse_variables_const (lexer, dict, &src, &n_src, pv_opts))
512 /* Parse function arguments, for those functions that
513 require arguments. */
514 if (function->n_args != 0)
515 for (i = 0; i < function->n_args; i++)
519 lex_match (lexer, ',');
520 if (lex_token (lexer) == T_STRING)
522 arg[i].c = ds_xstrdup (lex_tokstr (lexer));
525 else if (lex_is_number (lexer))
527 arg[i].f = lex_tokval (lexer);
532 msg (SE, _("Missing argument %zu to %s."),
533 i + 1, function->name);
539 if (type != var_get_type (src[0]))
541 msg (SE, _("Arguments to %s must be of same type as "
542 "source variables."),
548 /* Trailing rparen. */
549 if (!lex_match (lexer, ')'))
551 lex_error (lexer, _("expecting `)'"));
555 /* Now check that the number of source variables match
556 the number of target variables. If we check earlier
557 than this, the user can get very misleading error
558 message, i.e. `AGGREGATE x=SUM(y t).' will get this
559 error message when a proper message would be more
560 like `unknown variable t'. */
563 msg (SE, _("Number of source variables (%zu) does not match "
564 "number of target variables (%zu)."),
569 if ((func_index == PIN || func_index == POUT
570 || func_index == FIN || func_index == FOUT)
571 && (var_is_numeric (src[0])
572 ? arg[0].f > arg[1].f
573 : str_compare_rpad (arg[0].c, arg[1].c) > 0))
575 union agr_argument t = arg[0];
579 msg (SW, _("The value arguments passed to the %s function "
580 "are out-of-order. They will be treated as if "
581 "they had been specified in the correct order."),
586 /* Finally add these to the linked list of aggregation
588 for (i = 0; i < n_dest; i++)
590 struct agr_var *v = xzalloc (sizeof *v);
592 /* Add variable to chain. */
593 if (agr->agr_vars != NULL)
601 /* Create the target variable in the aggregate
604 struct variable *destvar;
606 v->function = func_index;
612 if (var_is_alpha (src[i]))
614 v->function |= FSTRING;
615 v->string = xmalloc (var_get_width (src[i]));
618 if (function->alpha_type == VAL_STRING)
619 destvar = dict_clone_var_as (agr->dict, v->src, dest[i]);
622 assert (var_is_numeric (v->src)
623 || function->alpha_type == VAL_NUMERIC);
624 destvar = dict_create_var (agr->dict, dest[i], 0);
628 if ((func_index == N || func_index == NMISS)
629 && dict_get_weight (dict) != NULL)
630 f = fmt_for_output (FMT_F, 8, 2);
632 f = function->format;
633 var_set_both_formats (destvar, &f);
639 destvar = dict_create_var (agr->dict, dest[i], 0);
640 if (func_index == N && dict_get_weight (dict) != NULL)
641 f = fmt_for_output (FMT_F, 8, 2);
643 f = function->format;
644 var_set_both_formats (destvar, &f);
649 msg (SE, _("Variable name %s is not unique within the "
650 "aggregate file dictionary, which contains "
651 "the aggregate variables and the break "
659 var_set_label (destvar, dest_label[i]);
664 v->exclude = exclude;
670 if (var_is_numeric (v->src))
671 for (j = 0; j < function->n_args; j++)
672 v->arg[j].f = arg[j].f;
674 for (j = 0; j < function->n_args; j++)
675 v->arg[j].c = xstrdup (arg[j].c);
679 if (src != NULL && var_is_alpha (src[0]))
680 for (i = 0; i < function->n_args; i++)
690 if (!lex_match (lexer, '/'))
692 if (lex_token (lexer) == '.')
695 lex_error (lexer, "expecting end of command");
701 ds_destroy (&function_name);
702 for (i = 0; i < n_dest; i++)
705 free (dest_label[i]);
711 if (src && n_src && var_is_alpha (src[0]))
712 for (i = 0; i < function->n_args; i++)
725 agr_destroy (struct agr_proc *agr)
727 struct agr_var *iter, *next;
729 subcase_destroy (&agr->sort);
730 free (agr->break_vars);
731 for (iter = agr->agr_vars; iter; iter = next)
735 if (iter->function & FSTRING)
740 n_args = agr_func_tab[iter->function & FUNC].n_args;
741 for (i = 0; i < n_args; i++)
742 free (iter->arg[i].c);
745 else if (iter->function == SD)
746 moments1_destroy (iter->moments);
748 dict_destroy_internal_var (iter->subject);
749 dict_destroy_internal_var (iter->weight);
753 if (agr->dict != NULL)
754 dict_destroy (agr->dict);
759 /* Accumulates aggregation data from the case INPUT. */
761 accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input)
763 struct agr_var *iter;
765 bool bad_warn = true;
767 weight = dict_get_case_weight (agr->src_dict, input, &bad_warn);
769 for (iter = agr->agr_vars; iter; iter = iter->next)
772 const union value *v = case_data (input, iter->src);
773 int src_width = var_get_width (iter->src);
775 if (var_is_value_missing (iter->src, v, iter->exclude))
777 switch (iter->function)
780 case NMISS | FSTRING:
781 iter->dbl[0] += weight;
784 case NUMISS | FSTRING:
788 iter->saw_missing = true;
792 /* This is horrible. There are too many possibilities. */
793 switch (iter->function)
796 iter->dbl[0] += v->f * weight;
800 iter->dbl[0] += v->f * weight;
801 iter->dbl[1] += weight;
808 cout = case_create (casewriter_get_proto (iter->writer));
810 case_data_rw (cout, iter->subject)->f
811 = case_data (input, iter->src)->f;
813 wv = dict_get_case_weight (agr->src_dict, input, NULL);
815 case_data_rw (cout, iter->weight)->f = wv;
819 casewriter_write (iter->writer, cout);
823 moments1_add (iter->moments, v->f, weight);
826 iter->dbl[0] = MAX (iter->dbl[0], v->f);
830 if (memcmp (iter->string, value_str (v, src_width), src_width) < 0)
831 memcpy (iter->string, value_str (v, src_width), src_width);
835 iter->dbl[0] = MIN (iter->dbl[0], v->f);
839 if (memcmp (iter->string, value_str (v, src_width), src_width) > 0)
840 memcpy (iter->string, value_str (v, src_width), src_width);
845 if (v->f > iter->arg[0].f)
846 iter->dbl[0] += weight;
847 iter->dbl[1] += weight;
851 if (memcmp (iter->arg[0].c,
852 value_str (v, src_width), src_width) < 0)
853 iter->dbl[0] += weight;
854 iter->dbl[1] += weight;
858 if (v->f < iter->arg[0].f)
859 iter->dbl[0] += weight;
860 iter->dbl[1] += weight;
864 if (memcmp (iter->arg[0].c,
865 value_str (v, src_width), src_width) > 0)
866 iter->dbl[0] += weight;
867 iter->dbl[1] += weight;
871 if (iter->arg[0].f <= v->f && v->f <= iter->arg[1].f)
872 iter->dbl[0] += weight;
873 iter->dbl[1] += weight;
877 if (memcmp (iter->arg[0].c,
878 value_str (v, src_width), src_width) <= 0
879 && memcmp (iter->arg[1].c,
880 value_str (v, src_width), src_width) >= 0)
881 iter->dbl[0] += weight;
882 iter->dbl[1] += weight;
886 if (iter->arg[0].f > v->f || v->f > iter->arg[1].f)
887 iter->dbl[0] += weight;
888 iter->dbl[1] += weight;
892 if (memcmp (iter->arg[0].c,
893 value_str (v, src_width), src_width) > 0
894 || memcmp (iter->arg[1].c,
895 value_str (v, src_width), src_width) < 0)
896 iter->dbl[0] += weight;
897 iter->dbl[1] += weight;
901 iter->dbl[0] += weight;
914 case FIRST | FSTRING:
917 memcpy (iter->string, value_str (v, src_width), src_width);
926 memcpy (iter->string, value_str (v, src_width), src_width);
930 case NMISS | FSTRING:
932 case NUMISS | FSTRING:
933 /* Our value is not missing or it would have been
934 caught earlier. Nothing to do. */
940 switch (iter->function)
943 iter->dbl[0] += weight;
954 /* Writes an aggregated record to OUTPUT. */
956 dump_aggregate_info (const struct agr_proc *agr, struct casewriter *output, const struct ccase *break_case)
958 struct ccase *c = case_create (dict_get_proto (agr->dict));
960 if ( agr->add_variables)
962 case_copy (c, 0, break_case, 0, dict_get_var_cnt (agr->src_dict));
969 for (i = 0; i < agr->break_var_cnt; i++)
971 const struct variable *v = agr->break_vars[i];
972 value_copy (case_data_rw_idx (c, value_idx),
973 case_data (break_case, v),
982 for (i = agr->agr_vars; i; i = i->next)
984 union value *v = case_data_rw (c, i->dest);
985 int width = var_get_width (i->dest);
987 if (agr->missing == COLUMNWISE && i->saw_missing
988 && (i->function & FUNC) != N && (i->function & FUNC) != NU
989 && (i->function & FUNC) != NMISS && (i->function & FUNC) != NUMISS)
991 value_set_missing (v, width);
992 casewriter_destroy (i->writer);
999 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1002 v->f = i->dbl[1] != 0.0 ? i->dbl[0] / i->dbl[1] : SYSMIS;
1008 struct percentile *median = percentile_create (0.5, i->cc);
1009 struct order_stats *os = &median->parent;
1010 struct casereader *sorted_reader = casewriter_make_reader (i->writer);
1013 order_stats_accumulate (&os, 1,
1018 i->dbl[0] = percentile_calculate (median, PC_HAVERAGE);
1019 statistic_destroy (&median->parent.parent);
1028 /* FIXME: we should use two passes. */
1029 moments1_calculate (i->moments, NULL, NULL, &variance,
1031 if (variance != SYSMIS)
1032 v->f = sqrt (variance);
1039 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1044 memcpy (value_str_rw (v, width), i->string, width);
1046 value_set_missing (v, width);
1055 case FOUT | FSTRING:
1056 v->f = i->dbl[1] ? i->dbl[0] / i->dbl[1] : SYSMIS;
1065 case POUT | FSTRING:
1066 v->f = i->dbl[1] ? i->dbl[0] / i->dbl[1] * 100.0 : SYSMIS;
1078 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1080 case FIRST | FSTRING:
1081 case LAST | FSTRING:
1083 memcpy (value_str_rw (v, width), i->string, width);
1085 value_set_missing (v, width);
1088 case NMISS | FSTRING:
1092 case NUMISS | FSTRING:
1101 casewriter_write (output, c);
1104 /* Resets the state for all the aggregate functions. */
1106 initialize_aggregate_info (struct agr_proc *agr)
1108 struct agr_var *iter;
1110 for (iter = agr->agr_vars; iter; iter = iter->next)
1112 iter->saw_missing = false;
1113 iter->dbl[0] = iter->dbl[1] = iter->dbl[2] = 0.0;
1114 iter->int1 = iter->int2 = 0;
1115 switch (iter->function)
1118 iter->dbl[0] = DBL_MAX;
1121 memset (iter->string, 255, var_get_width (iter->src));
1124 iter->dbl[0] = -DBL_MAX;
1127 memset (iter->string, 0, var_get_width (iter->src));
1131 struct caseproto *proto;
1132 struct subcase ordering;
1134 proto = caseproto_create ();
1135 proto = caseproto_add_width (proto, 0);
1136 proto = caseproto_add_width (proto, 0);
1138 if ( ! iter->subject)
1139 iter->subject = dict_create_internal_var (0, 0);
1141 if ( ! iter->weight)
1142 iter->weight = dict_create_internal_var (1, 0);
1144 subcase_init_var (&ordering, iter->subject, SC_ASCEND);
1145 iter->writer = sort_create_writer (&ordering, proto);
1146 subcase_destroy (&ordering);
1147 caseproto_unref (proto);
1153 if (iter->moments == NULL)
1154 iter->moments = moments1_create (MOMENT_VARIANCE);
1156 moments1_clear (iter->moments);