X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fstats%2Faggregate.c;h=640746991c3246209c56efae14df3302d8fccfd9;hb=3d859a4d0fc88efa2f2bd946f621799ef73739bd;hp=cfa9ea66248a2ca0879d5c183f778f72cff2a657;hpb=55e6e7ba37a30570f5a31e2d78c22dfa7b61a36f;p=pspp diff --git a/src/language/stats/aggregate.c b/src/language/stats/aggregate.c index cfa9ea6624..640746991c 100644 --- a/src/language/stats/aggregate.c +++ b/src/language/stats/aggregate.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006, 2008, 2009, 2010 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 2008, 2009, 2010, 2011, 2012, 2014 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -16,40 +16,42 @@ #include +#include "language/stats/aggregate.h" + #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "aggregate.h" - -#include "minmax.h" -#include "xalloc.h" +#include "data/any-writer.h" +#include "data/case.h" +#include "data/casegrouper.h" +#include "data/casereader.h" +#include "data/casewriter.h" +#include "data/dataset.h" +#include "data/dictionary.h" +#include "data/file-handle-def.h" +#include "data/format.h" +#include "data/settings.h" +#include "data/subcase.h" +#include "data/sys-file-writer.h" +#include "data/variable.h" +#include "language/command.h" +#include "language/data-io/file-handle.h" +#include "language/lexer/lexer.h" +#include "language/lexer/variable-parser.h" +#include "language/stats/sort-criteria.h" +#include "libpspp/assertion.h" +#include "libpspp/i18n.h" +#include "libpspp/message.h" +#include "libpspp/misc.h" +#include "libpspp/pool.h" +#include "libpspp/str.h" +#include "math/moments.h" +#include "math/percentiles.h" +#include "math/sort.h" +#include "math/statistic.h" + +#include "gl/c-strcase.h" +#include "gl/minmax.h" +#include "gl/xalloc.h" #include "gettext.h" #define _(msgid) gettext (msgid) @@ -91,27 +93,27 @@ struct agr_var /* Attributes of aggregation functions. */ const struct agr_func agr_func_tab[] = { - {"SUM", N_("Sum of values"), AGR_SV_YES, 0, -1, {FMT_F, 8, 2}}, - {"MEAN", N_("Mean average"), AGR_SV_YES, 0, -1, {FMT_F, 8, 2}}, - {"MEDIAN", N_("Median average"), AGR_SV_YES, 0, -1, {FMT_F, 8, 2}}, - {"SD", N_("Standard deviation"), AGR_SV_YES, 0, -1, {FMT_F, 8, 2}}, - {"MAX", N_("Maximum value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}}, - {"MIN", N_("Minimum value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}}, - {"PGT", N_("Percentage greater than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 1}}, - {"PLT", N_("Percentage less than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 1}}, - {"PIN", N_("Percentage included in range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 1}}, - {"POUT", N_("Percentage excluded from range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 1}}, - {"FGT", N_("Fraction greater than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 3}}, - {"FLT", N_("Fraction less than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 3}}, - {"FIN", N_("Fraction included in range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 3}}, - {"FOUT", N_("Fraction excluded from range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 3}}, - {"N", N_("Number of cases"), AGR_SV_NO, 0, VAL_NUMERIC, {FMT_F, 7, 0}}, - {"NU", N_("Number of cases (unweighted)"), AGR_SV_OPT, 0, VAL_NUMERIC, {FMT_F, 7, 0}}, - {"NMISS", N_("Number of missing values"), AGR_SV_YES, 0, VAL_NUMERIC, {FMT_F, 7, 0}}, - {"NUMISS", N_("Number of missing values (unweighted)"), AGR_SV_YES, 0, VAL_NUMERIC, {FMT_F, 7, 0}}, - {"FIRST", N_("First non-missing value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}}, - {"LAST", N_("Last non-missing value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}}, - {NULL, NULL, AGR_SV_NO, 0, -1, {-1, -1, -1}}, + {"SUM", N_("Sum of values"), AGR_SV_YES, 0, -1, { .type = FMT_F, .w = 8, .d = 2 }}, + {"MEAN", N_("Mean average"), AGR_SV_YES, 0, -1, { .type = FMT_F, .w = 8, .d = 2 }}, + {"MEDIAN", N_("Median average"), AGR_SV_YES, 0, -1, { .type = FMT_F, .w = 8, .d = 2 }}, + {"SD", N_("Standard deviation"), AGR_SV_YES, 0, -1, { .type = FMT_F, .w = 8, .d = 2 }}, + {"MAX", N_("Maximum value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}}, + {"MIN", N_("Minimum value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}}, + {"PGT", N_("Percentage greater than"), AGR_SV_YES, 1, VAL_NUMERIC, { .type = FMT_F, .w = 5, .d = 1 }}, + {"PLT", N_("Percentage less than"), AGR_SV_YES, 1, VAL_NUMERIC, { .type = FMT_F, .w = 5, .d = 1 }}, + {"PIN", N_("Percentage included in range"), AGR_SV_YES, 2, VAL_NUMERIC, { .type = FMT_F, .w = 5, .d = 1 }}, + {"POUT", N_("Percentage excluded from range"), AGR_SV_YES, 2, VAL_NUMERIC, { .type = FMT_F, .w = 5, .d = 1 }}, + {"FGT", N_("Fraction greater than"), AGR_SV_YES, 1, VAL_NUMERIC, { .type = FMT_F, .w = 5, .d = 3 }}, + {"FLT", N_("Fraction less than"), AGR_SV_YES, 1, VAL_NUMERIC, { .type = FMT_F, .w = 5, .d = 3 }}, + {"FIN", N_("Fraction included in range"), AGR_SV_YES, 2, VAL_NUMERIC, { .type = FMT_F, .w = 5, .d = 3 }}, + {"FOUT", N_("Fraction excluded from range"), AGR_SV_YES, 2, VAL_NUMERIC, { .type = FMT_F, .w = 5, .d = 3 }}, + {"N", N_("Number of cases"), AGR_SV_NO, 0, VAL_NUMERIC, { .type = FMT_F, .w = 7, .d = 0 }}, + {"NU", N_("Number of cases (unweighted)"), AGR_SV_OPT, 0, VAL_NUMERIC, { .type = FMT_F, .w = 7, .d = 0 }}, + {"NMISS", N_("Number of missing values"), AGR_SV_YES, 0, VAL_NUMERIC, { .type = FMT_F, .w = 7, .d = 0 }}, + {"NUMISS", N_("Number of missing values (unweighted)"), AGR_SV_YES, 0, VAL_NUMERIC, { .type = FMT_F, .w = 7, .d = 0 }}, + {"FIRST", N_("First non-missing value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}}, + {"LAST", N_("Last non-missing value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}}, + {NULL, NULL, AGR_SV_NO, 0, -1, {-1, -1, -1}}, }; /* Missing value types. */ @@ -127,13 +129,13 @@ struct agr_proc /* Break variables. */ struct subcase sort; /* Sort criteria (break variables). */ const struct variable **break_vars; /* Break variables. */ - size_t break_var_cnt; /* Number of break variables. */ + size_t break_n_vars; /* Number of break variables. */ enum missing_treatment missing; /* How to treat missing values. */ struct agr_var *agr_vars; /* First aggregate variable. */ struct dictionary *dict; /* Aggregate dictionary. */ const struct dictionary *src_dict; /* Dict of the source */ - int case_cnt; /* Counts aggregated cases. */ + int n_cases; /* Counts aggregated cases. */ bool add_variables; /* True iff the aggregated variables should be appended to the existing dictionary */ @@ -181,7 +183,7 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) lex_match (lexer, T_EQUALS); if (!lex_match (lexer, T_ASTERISK)) { - out_file = fh_parse (lexer, FH_REF_FILE | FH_REF_SCRATCH); + out_file = fh_parse (lexer, FH_REF_FILE, dataset_session (ds)); if (out_file == NULL) goto error; } @@ -204,10 +206,10 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) goto error; } - if ( agr.add_variables ) + if (agr.add_variables) agr.dict = dict_clone (dict); else - agr.dict = dict_create (); + agr.dict = dict_create (dict_get_encoding (dict)); dict_set_label (agr.dict, dict_get_label (dict)); dict_set_documents (agr.dict, dict_get_documents (dict)); @@ -222,7 +224,7 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) lex_match (lexer, T_EQUALS); if (!lex_match_id (lexer, "COLUMNWISE")) { - lex_error (lexer, _("expecting %s"), "COLUMNWISE"); + lex_error_expecting (lexer, "COLUMNWISE"); goto error; } agr.missing = COLUMNWISE; @@ -239,10 +241,10 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) if (!parse_sort_criteria (lexer, dict, &agr.sort, &agr.break_vars, &saw_direction)) goto error; - agr.break_var_cnt = subcase_get_n_fields (&agr.sort); + agr.break_n_vars = subcase_get_n_fields (&agr.sort); if (! agr.add_variables) - for (i = 0; i < agr.break_var_cnt; i++) + for (i = 0; i < agr.break_n_vars; i++) dict_clone_var_assert (agr.dict, agr.break_vars[i]); /* BREAK must follow the options. */ @@ -270,11 +272,11 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) dict_set_split_vars (agr.dict, NULL, 0); /* Initialize. */ - agr.case_cnt = 0; + agr.n_cases = 0; if (out_file == NULL) { - /* The active file will be replaced by the aggregated data, + /* The active dataset will be replaced by the aggregated data, so TEMPORARY is moot. */ proc_cancel_temporary_transformations (ds); proc_discard_output (ds); @@ -295,7 +297,7 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) } for (grouper = casegrouper_create_vars (input, agr.break_vars, - agr.break_var_cnt); + agr.break_n_vars); casegrouper_get_next_group (grouper, &group); casereader_destroy (group)) { @@ -310,7 +312,7 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) initialize_aggregate_info (&agr); - if ( agr.add_variables ) + if (agr.add_variables) placeholder = casereader_clone (group); { @@ -331,8 +333,8 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) else { dump_aggregate_info (&agr, output, c); - case_unref (c); } + case_unref (c); } if (!casegrouper_destroy (grouper)) goto error; @@ -350,7 +352,8 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) if (next_input == NULL) goto error; - proc_set_active_file (ds, next_input, agr.dict); + dataset_set_dict (ds, agr.dict); + dataset_set_source (ds, next_input); agr.dict = NULL; } else @@ -416,7 +419,7 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, { size_t n_dest_prev = n_dest; - if (!parse_DATA_LIST_vars (lexer, &dest, &n_dest, + if (!parse_DATA_LIST_vars (lexer, dict, &dest, &n_dest, (PV_APPEND | PV_SINGLE | PV_NO_SCRATCH | PV_NO_DUPLICATE))) goto error; @@ -434,13 +437,8 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, if (lex_is_string (lexer)) { - struct string label; - ds_init_substring (&label, lex_tokss (lexer)); - - ds_truncate (&label, 255); - dest_label[n_dest - 1] = ds_xstrdup (&label); + dest_label[n_dest - 1] = xstrdup (lex_tokcstr (lexer)); lex_get (lexer); - ds_destroy (&label); } } @@ -452,10 +450,10 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, } ds_assign_substring (&function_name, lex_tokss (lexer)); - exclude = ds_chomp (&function_name, '.') ? MV_SYSTEM : MV_ANY; + exclude = ds_chomp_byte (&function_name, '.') ? MV_SYSTEM : MV_ANY; for (function = agr_func_tab; function->name; function++) - if (!strcasecmp (function->name, ds_cstr (&function_name))) + if (!c_strcasecmp (function->name, ds_cstr (&function_name))) break; if (NULL == function->name) { @@ -472,7 +470,6 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, { if (function->src_vars == AGR_SV_YES) { - lex_force_match (lexer, T_LPAREN); goto error; } } @@ -501,7 +498,9 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, lex_match (lexer, T_COMMA); if (lex_is_string (lexer)) { - arg[i].c = ss_xstrdup (lex_tokss (lexer)); + arg[i].c = recode_string (dict_get_encoding (agr->dict), + "UTF-8", lex_tokcstr (lexer), + -1); type = VAL_STRING; } else if (lex_is_number (lexer)) @@ -566,7 +565,7 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, variables. */ for (i = 0; i < n_dest; i++) { - struct agr_var *v = xzalloc (sizeof *v); + struct agr_var *v = XZALLOC (struct agr_var); /* Add variable to chain. */ if (agr->agr_vars != NULL) @@ -709,7 +708,7 @@ agr_destroy (struct agr_proc *agr) { struct agr_var *iter, *next; - subcase_destroy (&agr->sort); + subcase_uninit (&agr->sort); free (agr->break_vars); for (iter = agr->agr_vars; iter; iter = next) { @@ -734,7 +733,7 @@ agr_destroy (struct agr_proc *agr) free (iter); } if (agr->dict != NULL) - dict_destroy (agr->dict); + dict_unref (agr->dict); } /* Execution. */ @@ -755,7 +754,7 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) const union value *v = case_data (input, iter->src); int src_width = var_get_width (iter->src); - if (var_is_value_missing (iter->src, v, iter->exclude)) + if (var_is_value_missing (iter->src, v) & iter->exclude) { switch (iter->function) { @@ -790,12 +789,11 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) cout = case_create (casewriter_get_proto (iter->writer)); - case_data_rw (cout, iter->subject)->f - = case_data (input, iter->src)->f; + *case_num_rw (cout, iter->subject) = case_num (input, iter->src); wv = dict_get_case_weight (agr->src_dict, input, NULL); - case_data_rw (cout, iter->weight)->f = wv; + *case_num_rw (cout, iter->weight) = wv; iter->cc += wv; @@ -810,8 +808,9 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) iter->int1 = 1; break; case MAX | FSTRING: - if (memcmp (iter->string, value_str (v, src_width), src_width) < 0) - memcpy (iter->string, value_str (v, src_width), src_width); + /* Need to do some kind of Unicode collation thingy here */ + if (memcmp (iter->string, v->s, src_width) < 0) + memcpy (iter->string, v->s, src_width); iter->int1 = 1; break; case MIN: @@ -819,8 +818,8 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) iter->int1 = 1; break; case MIN | FSTRING: - if (memcmp (iter->string, value_str (v, src_width), src_width) > 0) - memcpy (iter->string, value_str (v, src_width), src_width); + if (memcmp (iter->string, v->s, src_width) > 0) + memcpy (iter->string, v->s, src_width); iter->int1 = 1; break; case FGT: @@ -831,8 +830,7 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) break; case FGT | FSTRING: case PGT | FSTRING: - if (memcmp (iter->arg[0].c, - value_str (v, src_width), src_width) < 0) + if (memcmp (iter->arg[0].c, v->s, src_width) < 0) iter->dbl[0] += weight; iter->dbl[1] += weight; break; @@ -844,8 +842,7 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) break; case FLT | FSTRING: case PLT | FSTRING: - if (memcmp (iter->arg[0].c, - value_str (v, src_width), src_width) > 0) + if (memcmp (iter->arg[0].c, v->s, src_width) > 0) iter->dbl[0] += weight; iter->dbl[1] += weight; break; @@ -857,10 +854,8 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) break; case FIN | FSTRING: case PIN | FSTRING: - if (memcmp (iter->arg[0].c, - value_str (v, src_width), src_width) <= 0 - && memcmp (iter->arg[1].c, - value_str (v, src_width), src_width) >= 0) + if (memcmp (iter->arg[0].c, v->s, src_width) <= 0 + && memcmp (iter->arg[1].c, v->s, src_width) >= 0) iter->dbl[0] += weight; iter->dbl[1] += weight; break; @@ -872,10 +867,8 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) break; case FOUT | FSTRING: case POUT | FSTRING: - if (memcmp (iter->arg[0].c, - value_str (v, src_width), src_width) > 0 - || memcmp (iter->arg[1].c, - value_str (v, src_width), src_width) < 0) + if (memcmp (iter->arg[0].c, v->s, src_width) > 0 + || memcmp (iter->arg[1].c, v->s, src_width) < 0) iter->dbl[0] += weight; iter->dbl[1] += weight; break; @@ -897,7 +890,7 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) case FIRST | FSTRING: if (iter->int1 == 0) { - memcpy (iter->string, value_str (v, src_width), src_width); + memcpy (iter->string, v->s, src_width); iter->int1 = 1; } break; @@ -906,7 +899,7 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) iter->int1 = 1; break; case LAST | FSTRING: - memcpy (iter->string, value_str (v, src_width), src_width); + memcpy (iter->string, v->s, src_width); iter->int1 = 1; break; case NMISS: @@ -940,16 +933,16 @@ dump_aggregate_info (const struct agr_proc *agr, struct casewriter *output, cons { struct ccase *c = case_create (dict_get_proto (agr->dict)); - if ( agr->add_variables) + if (agr->add_variables) { - case_copy (c, 0, break_case, 0, dict_get_var_cnt (agr->src_dict)); + case_copy (c, 0, break_case, 0, dict_get_n_vars (agr->src_dict)); } else { int value_idx = 0; int i; - for (i = 0; i < agr->break_var_cnt; i++) + for (i = 0; i < agr->break_n_vars; i++) { const struct variable *v = agr->break_vars[i]; value_copy (case_data_rw_idx (c, value_idx), @@ -986,7 +979,7 @@ dump_aggregate_info (const struct agr_proc *agr, struct casewriter *output, cons break; case MEDIAN: { - if ( i->writer) + if (i->writer) { struct percentile *median = percentile_create (0.5, i->cc); struct order_stats *os = &median->parent; @@ -1024,7 +1017,7 @@ dump_aggregate_info (const struct agr_proc *agr, struct casewriter *output, cons case MAX | FSTRING: case MIN | FSTRING: if (i->int1) - memcpy (value_str_rw (v, width), i->string, width); + memcpy (v->s, i->string, width); else value_set_missing (v, width); break; @@ -1063,7 +1056,7 @@ dump_aggregate_info (const struct agr_proc *agr, struct casewriter *output, cons case FIRST | FSTRING: case LAST | FSTRING: if (i->int1) - memcpy (value_str_rw (v, width), i->string, width); + memcpy (v->s, i->string, width); else value_set_missing (v, width); break; @@ -1118,15 +1111,15 @@ initialize_aggregate_info (struct agr_proc *agr) proto = caseproto_add_width (proto, 0); proto = caseproto_add_width (proto, 0); - if ( ! iter->subject) + if (! iter->subject) iter->subject = dict_create_internal_var (0, 0); - if ( ! iter->weight) + if (! iter->weight) iter->weight = dict_create_internal_var (1, 0); subcase_init_var (&ordering, iter->subject, SC_ASCEND); iter->writer = sort_create_writer (&ordering, proto); - subcase_destroy (&ordering); + subcase_uninit (&ordering); caseproto_unref (proto); iter->cc = 0;