1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006, 2008, 2009, 2010, 2011, 2012, 2014 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/c-strcase.h"
53 #include "gl/minmax.h"
54 #include "gl/xalloc.h"
57 #define _(msgid) gettext (msgid)
58 #define N_(msgid) msgid
60 /* Argument for AGGREGATE function. */
63 double f; /* Numeric. */
64 char *c; /* Short or long string. */
67 /* Specifies how to make an aggregate variable. */
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. */
79 double W; /* Total non-missing weight. */
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, { .type = FMT_F, .w = 8, .d = 2 }},
96 {"MEAN", N_("Mean average"), AGR_SV_YES, 0, -1, { .type = FMT_F, .w = 8, .d = 2 }},
97 {"MEDIAN", N_("Median average"), AGR_SV_YES, 0, -1, { .type = FMT_F, .w = 8, .d = 2 }},
98 {"SD", N_("Standard deviation"), AGR_SV_YES, 0, -1, { .type = FMT_F, .w = 8, .d = 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, { .type = FMT_F, .w = 5, .d = 1 }},
102 {"PLT", N_("Percentage less than"), AGR_SV_YES, 1, VAL_NUMERIC, { .type = FMT_F, .w = 5, .d = 1 }},
103 {"PIN", N_("Percentage included in range"), AGR_SV_YES, 2, VAL_NUMERIC, { .type = FMT_F, .w = 5, .d = 1 }},
104 {"POUT", N_("Percentage excluded from range"), AGR_SV_YES, 2, VAL_NUMERIC, { .type = FMT_F, .w = 5, .d = 1 }},
105 {"FGT", N_("Fraction greater than"), AGR_SV_YES, 1, VAL_NUMERIC, { .type = FMT_F, .w = 5, .d = 3 }},
106 {"FLT", N_("Fraction less than"), AGR_SV_YES, 1, VAL_NUMERIC, { .type = FMT_F, .w = 5, .d = 3 }},
107 {"FIN", N_("Fraction included in range"), AGR_SV_YES, 2, VAL_NUMERIC, { .type = FMT_F, .w = 5, .d = 3 }},
108 {"FOUT", N_("Fraction excluded from range"), AGR_SV_YES, 2, VAL_NUMERIC, { .type = FMT_F, .w = 5, .d = 3 }},
109 {"N", N_("Number of cases"), AGR_SV_NO, 0, VAL_NUMERIC, { .type = FMT_F, .w = 7, .d = 0 }},
110 {"NU", N_("Number of cases (unweighted)"), AGR_SV_OPT, 0, VAL_NUMERIC, { .type = FMT_F, .w = 7, .d = 0 }},
111 {"NMISS", N_("Number of missing values"), AGR_SV_YES, 0, VAL_NUMERIC, { .type = FMT_F, .w = 7, .d = 0 }},
112 {"NUMISS", N_("Number of missing values (unweighted)"), AGR_SV_YES, 0, VAL_NUMERIC, { .type = FMT_F, .w = 7, .d = 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_n_vars; /* Number of break variables. */
133 enum missing_treatment missing; /* How to treat missing values. */
134 struct agr_var *agr_vars; /* Aggregate variables. */
136 struct dictionary *dict; /* Aggregate dictionary. */
137 const struct dictionary *src_dict; /* Dict of the source */
138 int n_cases; /* Counts aggregated cases. */
140 bool add_variables; /* True iff the aggregated variables should
141 be appended to the existing dictionary */
144 static void initialize_aggregate_info (struct agr_proc *);
146 static void accumulate_aggregate_info (struct agr_proc *,
147 const struct ccase *);
149 static bool parse_aggregate_functions (struct lexer *, const struct dictionary *,
151 static void agr_destroy (struct agr_proc *);
152 static void dump_aggregate_info (const struct agr_proc *agr,
153 struct casewriter *output,
154 const struct ccase *break_case);
158 /* Parses and executes the AGGREGATE procedure. */
160 cmd_aggregate (struct lexer *lexer, struct dataset *ds)
162 struct dictionary *dict = dataset_dict (ds);
164 struct file_handle *out_file = NULL;
165 struct casereader *input = NULL, *group;
166 struct casegrouper *grouper;
167 struct casewriter *output = NULL;
169 bool copy_documents = false;
170 bool presorted = false;
174 memset(&agr, 0 , sizeof (agr));
175 agr.missing = ITEMWISE;
177 subcase_init_empty (&agr.sort);
179 /* OUTFILE subcommand must be first. */
180 lex_match (lexer, T_SLASH);
181 if (!lex_force_match_id (lexer, "OUTFILE"))
183 lex_match (lexer, T_EQUALS);
184 if (!lex_match (lexer, T_ASTERISK))
186 out_file = fh_parse (lexer, FH_REF_FILE, dataset_session (ds));
187 if (out_file == NULL)
191 if (out_file == NULL && lex_match_id (lexer, "MODE"))
193 lex_match (lexer, T_EQUALS);
194 if (lex_match_id (lexer, "ADDVARIABLES"))
196 agr.add_variables = true;
198 /* presorted is assumed in ADDVARIABLES mode */
201 else if (lex_match_id (lexer, "REPLACE"))
203 agr.add_variables = false;
209 if (agr.add_variables)
210 agr.dict = dict_clone (dict);
212 agr.dict = dict_create (dict_get_encoding (dict));
214 dict_set_label (agr.dict, dict_get_label (dict));
215 dict_set_documents (agr.dict, dict_get_documents (dict));
217 /* Read most of the subcommands. */
220 lex_match (lexer, T_SLASH);
222 if (lex_match_id (lexer, "MISSING"))
224 lex_match (lexer, T_EQUALS);
225 if (!lex_match_id (lexer, "COLUMNWISE"))
227 lex_error_expecting (lexer, "COLUMNWISE");
230 agr.missing = COLUMNWISE;
232 else if (lex_match_id (lexer, "DOCUMENT"))
233 copy_documents = true;
234 else if (lex_match_id (lexer, "PRESORTED"))
236 else if (lex_force_match_id (lexer, "BREAK"))
240 lex_match (lexer, T_EQUALS);
241 if (!parse_sort_criteria (lexer, dict, &agr.sort, &agr.break_vars,
244 agr.break_n_vars = subcase_get_n_fields (&agr.sort);
246 if (! agr.add_variables)
247 for (i = 0; i < agr.break_n_vars; i++)
248 dict_clone_var_assert (agr.dict, agr.break_vars[i]);
250 /* BREAK must follow the options. */
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, T_SLASH);
264 if (!parse_aggregate_functions (lexer, dict, &agr))
267 /* Delete documents. */
269 dict_clear_documents (agr.dict);
271 /* Cancel SPLIT FILE. */
272 dict_clear_split_vars (agr.dict);
277 if (out_file == NULL)
279 /* The active dataset 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 dataset_set_dict (ds, agr.dict);
356 dataset_set_source (ds, next_input);
361 ok = casewriter_destroy (output);
374 casewriter_destroy (output);
377 return CMD_CASCADING_FAILURE;
380 /* Parse all the aggregate functions. */
382 parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict,
383 struct agr_proc *agr)
385 size_t allocated_agr_vars = 0;
387 /* 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, T_EQUALS))
419 size_t n_dest_prev = n_dest;
421 if (!parse_DATA_LIST_vars (lexer, dict, &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_is_string (lexer))
439 dest_label[n_dest - 1] = xstrdup (lex_tokcstr (lexer));
444 /* Get the name of the aggregation function. */
445 if (lex_token (lexer) != T_ID)
447 lex_error (lexer, _("Syntax error expecting aggregation function."));
451 ds_assign_substring (&function_name, lex_tokss (lexer));
452 exclude = ds_chomp_byte (&function_name, '.') ? MV_SYSTEM : MV_ANY;
454 for (function = agr_func_tab; function->name; function++)
455 if (!c_strcasecmp (function->name, ds_cstr (&function_name)))
457 if (NULL == function->name)
459 lex_error (lexer, _("Unknown aggregation function %s."),
460 ds_cstr (&function_name));
463 ds_destroy (&function_name);
464 func_index = function - agr_func_tab;
467 /* Check for leading lparen. */
468 if (!lex_match (lexer, T_LPAREN))
470 if (function->src_vars == AGR_SV_YES)
477 /* Parse list of source variables. */
478 int pv_opts = PV_NO_SCRATCH;
479 if (func_index == SUM || func_index == MEAN || func_index == SD)
480 pv_opts |= PV_NUMERIC;
481 else if (function->n_args)
482 pv_opts |= PV_SAME_TYPE;
484 int vars_start_ofs = lex_ofs (lexer);
485 if (!parse_variables_const (lexer, dict, &src, &n_src, pv_opts))
487 int vars_end_ofs = lex_ofs (lexer) - 1;
489 /* Parse function arguments, for those functions that
490 require arguments. */
491 int args_start_ofs = 0;
492 if (function->n_args != 0)
493 for (i = 0; i < function->n_args; i++)
497 lex_match (lexer, T_COMMA);
499 args_start_ofs = lex_ofs (lexer);
500 if (lex_is_string (lexer))
502 arg[i].c = recode_string (dict_get_encoding (agr->dict),
503 "UTF-8", lex_tokcstr (lexer),
507 else if (lex_is_number (lexer))
509 arg[i].f = lex_tokval (lexer);
514 lex_error (lexer, _("Missing argument %zu to %s."),
515 i + 1, function->name);
518 if (type != var_get_type (src[0]))
520 msg (SE, _("Arguments to %s must be of same type as "
521 "source variables."),
523 if (type == VAL_NUMERIC)
525 lex_next_msg (lexer, SN, 0, 0,
526 _("The argument is numeric."));
527 lex_ofs_msg (lexer, SN, vars_start_ofs, vars_end_ofs,
528 _("The variables have string type."));
532 lex_next_msg (lexer, SN, 0, 0,
533 _("The argument is a string."));
534 lex_ofs_msg (lexer, SN, vars_start_ofs, vars_end_ofs,
535 _("The variables are numeric."));
542 int args_end_ofs = lex_ofs (lexer) - 1;
544 /* Trailing rparen. */
545 if (!lex_force_match (lexer, T_RPAREN))
548 /* Now check that the number of source variables match
549 the number of target variables. If we check earlier
550 than this, the user can get very misleading error
551 message, i.e. `AGGREGATE x=SUM(y t).' will get this
552 error message when a proper message would be more
553 like `unknown variable t'. */
556 msg (SE, _("Number of source variables (%zu) does not match "
557 "number of target variables (%zu)."),
562 if ((func_index == PIN || func_index == POUT
563 || func_index == FIN || func_index == FOUT)
564 && (var_is_numeric (src[0])
565 ? arg[0].f > arg[1].f
566 : str_compare_rpad (arg[0].c, arg[1].c) > 0))
568 union agr_argument t = arg[0];
572 lex_ofs_msg (lexer, SW, args_start_ofs, args_end_ofs,
573 _("The value arguments passed to the %s function "
574 "are out of order. They will be treated as if "
575 "they had been specified in the correct order."),
580 /* Finally add these to the linked list of aggregation
582 for (i = 0; i < n_dest; i++)
584 if (agr->n_agr_vars >= allocated_agr_vars)
585 agr->agr_vars = x2nrealloc (agr->agr_vars, &allocated_agr_vars,
586 sizeof *agr->agr_vars);
587 struct agr_var *v = &agr->agr_vars[agr->n_agr_vars++];
588 *v = (struct agr_var) {
590 .src = src ? src[i] : NULL,
594 /* Create the target variable in the aggregate
597 struct variable *destvar;
599 v->function = func_index;
603 if (var_is_alpha (src[i]))
605 v->function |= FSTRING;
606 v->string = xmalloc (var_get_width (src[i]));
609 if (function->alpha_type == VAL_STRING)
610 destvar = dict_clone_var_as (agr->dict, v->src, dest[i]);
613 assert (var_is_numeric (v->src)
614 || function->alpha_type == VAL_NUMERIC);
615 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);
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]);
662 if (var_is_numeric (v->src))
663 for (j = 0; j < function->n_args; j++)
664 v->arg[j].f = arg[j].f;
666 for (j = 0; j < function->n_args; j++)
667 v->arg[j].c = xstrdup (arg[j].c);
671 if (src != NULL && var_is_alpha (src[0]))
672 for (i = 0; i < function->n_args; i++)
682 if (!lex_match (lexer, T_SLASH))
684 if (lex_token (lexer) == T_ENDCMD)
687 lex_error (lexer, "Syntax error expecting end of command.");
693 ds_destroy (&function_name);
694 for (i = 0; i < n_dest; i++)
697 free (dest_label[i]);
703 if (src && n_src && var_is_alpha (src[0]))
704 for (i = 0; i < function->n_args; i++)
717 agr_destroy (struct agr_proc *agr)
719 subcase_uninit (&agr->sort);
720 free (agr->break_vars);
721 for (size_t i = 0; i < agr->n_agr_vars; i++)
723 struct agr_var *av = &agr->agr_vars[i];
725 if (av->function & FSTRING)
727 size_t n_args = agr_func_tab[av->function & FUNC].n_args;
728 for (size_t i = 0; i < n_args; i++)
732 else if (av->function == SD)
733 moments1_destroy (av->moments);
735 dict_destroy_internal_var (av->subject);
736 dict_destroy_internal_var (av->weight);
738 free (agr->agr_vars);
739 if (agr->dict != NULL)
740 dict_unref (agr->dict);
745 /* Accumulates aggregation data from the case INPUT. */
747 accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input)
750 bool bad_warn = true;
752 weight = dict_get_case_weight (agr->src_dict, input, &bad_warn);
754 for (size_t i = 0; i < agr->n_agr_vars; i++)
756 struct agr_var *av = &agr->agr_vars[i];
759 const union value *v = case_data (input, av->src);
760 int src_width = var_get_width (av->src);
762 if (var_is_value_missing (av->src, v) & av->exclude)
764 switch (av->function)
767 case NMISS | FSTRING:
771 case NUMISS | FSTRING:
775 av->saw_missing = true;
779 /* This is horrible. There are too many possibilities. */
781 switch (av->function)
784 av->dbl += v->f * weight;
788 av->dbl += v->f * weight;
795 cout = case_create (casewriter_get_proto (av->writer));
797 *case_num_rw (cout, av->subject) = case_num (input, av->src);
799 wv = dict_get_case_weight (agr->src_dict, input, NULL);
801 *case_num_rw (cout, av->weight) = wv;
805 casewriter_write (av->writer, cout);
809 moments1_add (av->moments, v->f, weight);
812 av->dbl = MAX (av->dbl, v->f);
816 /* Need to do some kind of Unicode collation thingy here */
817 if (memcmp (av->string, v->s, src_width) < 0)
818 memcpy (av->string, v->s, src_width);
822 av->dbl = MIN (av->dbl, v->f);
826 if (memcmp (av->string, v->s, src_width) > 0)
827 memcpy (av->string, v->s, src_width);
832 if (v->f > av->arg[0].f)
837 if (memcmp (av->arg[0].c, v->s, src_width) < 0)
842 if (v->f < av->arg[0].f)
847 if (memcmp (av->arg[0].c, v->s, src_width) > 0)
852 if (av->arg[0].f <= v->f && v->f <= av->arg[1].f)
857 if (memcmp (av->arg[0].c, v->s, src_width) <= 0
858 && memcmp (av->arg[1].c, v->s, src_width) >= 0)
863 if (av->arg[0].f > v->f || v->f > av->arg[1].f)
868 if (memcmp (av->arg[0].c, v->s, src_width) > 0
869 || memcmp (av->arg[1].c, v->s, src_width) < 0)
887 case FIRST | FSTRING:
890 memcpy (av->string, v->s, src_width);
899 memcpy (av->string, v->s, src_width);
903 case NMISS | FSTRING:
905 case NUMISS | FSTRING:
906 /* Our value is not missing or it would have been
907 caught earlier. Nothing to do. */
915 switch (av->function)
930 /* Writes an aggregated record to OUTPUT. */
932 dump_aggregate_info (const struct agr_proc *agr, struct casewriter *output, const struct ccase *break_case)
934 struct ccase *c = case_create (dict_get_proto (agr->dict));
936 if (agr->add_variables)
938 case_copy (c, 0, break_case, 0, dict_get_n_vars (agr->src_dict));
945 for (i = 0; i < agr->break_n_vars; i++)
947 const struct variable *v = agr->break_vars[i];
948 value_copy (case_data_rw_idx (c, value_idx),
949 case_data (break_case, v),
955 for (size_t i = 0; i < agr->n_agr_vars; i++)
957 struct agr_var *av = &agr->agr_vars[i];
958 union value *v = case_data_rw (c, av->dest);
959 int width = var_get_width (av->dest);
961 if (agr->missing == COLUMNWISE && av->saw_missing
962 && (av->function & FUNC) != N && (av->function & FUNC) != NU
963 && (av->function & FUNC) != NMISS && (av->function & FUNC) != NUMISS)
965 value_set_missing (v, width);
966 casewriter_destroy (av->writer);
970 switch (av->function)
973 v->f = av->int1 ? av->dbl : SYSMIS;
976 v->f = av->W != 0.0 ? av->dbl / av->W : SYSMIS;
982 struct percentile *median = percentile_create (0.5, av->cc);
983 struct order_stats *os = &median->parent;
984 struct casereader *sorted_reader = casewriter_make_reader (av->writer);
987 order_stats_accumulate (&os, 1,
992 av->dbl = percentile_calculate (median, PC_HAVERAGE);
993 statistic_destroy (&median->parent.parent);
1002 /* FIXME: we should use two passes. */
1003 moments1_calculate (av->moments, NULL, NULL, &variance,
1005 if (variance != SYSMIS)
1006 v->f = sqrt (variance);
1013 v->f = av->int1 ? av->dbl : SYSMIS;
1018 memcpy (v->s, av->string, width);
1020 value_set_missing (v, width);
1029 case FOUT | FSTRING:
1030 v->f = av->W ? av->dbl / av->W : SYSMIS;
1039 case POUT | FSTRING:
1040 v->f = av->W ? av->dbl / av->W * 100.0 : SYSMIS;
1052 v->f = av->int1 ? av->dbl : SYSMIS;
1054 case FIRST | FSTRING:
1055 case LAST | FSTRING:
1057 memcpy (v->s, av->string, width);
1059 value_set_missing (v, width);
1062 case NMISS | FSTRING:
1066 case NUMISS | FSTRING:
1074 casewriter_write (output, c);
1077 /* Resets the state for all the aggregate functions. */
1079 initialize_aggregate_info (struct agr_proc *agr)
1081 for (size_t i = 0; i < agr->n_agr_vars; i++)
1083 struct agr_var *av = &agr->agr_vars[i];
1084 av->saw_missing = false;
1085 av->dbl = av->W = 0.0;
1087 switch (av->function)
1093 memset (av->string, 255, var_get_width (av->src));
1099 memset (av->string, 0, var_get_width (av->src));
1103 struct caseproto *proto;
1104 struct subcase ordering;
1106 proto = caseproto_create ();
1107 proto = caseproto_add_width (proto, 0);
1108 proto = caseproto_add_width (proto, 0);
1111 av->subject = dict_create_internal_var (0, 0);
1114 av->weight = dict_create_internal_var (1, 0);
1116 subcase_init_var (&ordering, av->subject, SC_ASCEND);
1117 av->writer = sort_create_writer (&ordering, proto);
1118 subcase_uninit (&ordering);
1119 caseproto_unref (proto);
1125 if (av->moments == NULL)
1126 av->moments = moments1_create (MOMENT_VARIANCE);
1128 moments1_clear (av->moments);