X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fstats%2Fexamine.c;h=46863cad9724f3b7899ab637ec8f3100a06df548;hb=912833f9331784d692ade66c76bffb5497b890e0;hp=d2d4987d27f8e51999421f78d27e16ac7109d27e;hpb=00473f96a19f9b4fc8b9dbe54dc165f2742b1140;p=pspp diff --git a/src/language/stats/examine.c b/src/language/stats/examine.c index d2d4987d27..46863cad97 100644 --- a/src/language/stats/examine.c +++ b/src/language/stats/examine.c @@ -1,6 +1,6 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2012 Free Software Foundation, Inc. + Copyright (C) 2012, 2013 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 @@ -23,6 +23,7 @@ #include "libpspp/assertion.h" #include "libpspp/message.h" +#include "libpspp/pool.h" #include "data/dataset.h" @@ -39,6 +40,7 @@ #include "math/interaction.h" #include "math/box-whisker.h" #include "math/categoricals.h" +#include "math/chart-geometry.h" #include "math/histogram.h" #include "math/moments.h" #include "math/np.h" @@ -50,6 +52,7 @@ #include "output/charts/boxplot.h" #include "output/charts/np-plot.h" +#include "output/charts/spreadlevel-plot.h" #include "output/charts/plot-hist.h" #include "language/command.h" @@ -63,21 +66,46 @@ #define _(msgid) gettext (msgid) #define N_(msgid) msgid +static void +append_value_name (const struct variable *var, const union value *val, struct string *str) +{ + var_append_value_name (var, val, str); + if ( var_is_value_missing (var, val, MV_ANY)) + ds_put_cstr (str, _(" (missing)")); +} + enum bp_mode { BP_GROUPS, BP_VARIABLES }; + +/* Indices for the ex_proto member (below) */ +enum + { + EX_VAL, /* value */ + EX_ID, /* identity */ + EX_WT /* weight */ + }; + + struct examine { + struct pool *pool; + + /* A caseproto used to contain the data subsets under examination, + see (enum above) */ + struct caseproto *ex_proto; + size_t n_dep_vars; const struct variable **dep_vars; size_t n_iacts; struct interaction **iacts; - enum mv_class exclude; + enum mv_class dep_excl; + enum mv_class fctr_excl; const struct dictionary *dict; @@ -92,19 +120,19 @@ struct examine bool missing_pw; - /* Test options require that casenumbers are known */ - bool casenumbers; - /* The case index of the ID value (or -1) if not applicable */ size_t id_idx; + int id_width; enum pc_alg pc_alg; double *ptiles; size_t n_percentiles; bool npplot; - bool histogram; + bool histogramplot; bool boxplot; + bool spreadlevelplot; + int sl_power; enum bp_mode boxplot_mode; @@ -120,16 +148,9 @@ struct extremity /* Either the casenumber or the value of the variable specified by the /ID subcommand which corresponds to this extremity */ - double identity; + union value identity; }; -enum - { - EX_VAL, /* value */ - EX_ID, /* identity */ - EX_WT /* weight */ - }; - struct exploratory_stats { double missing; @@ -176,25 +197,28 @@ struct exploratory_stats }; -static -const union value ** -xxx0 (const struct interaction *iact) +/* Returns an array of (iact->n_vars) pointers to union value initialised to NULL. + The caller must free this array when no longer required. */ +static const union value ** +previous_value_alloc (const struct interaction *iact) { int ivar_idx; const union value **prev_val = xcalloc (iact->n_vars, sizeof (*prev_val)); - + for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx) prev_val[ivar_idx] = NULL; return prev_val; } +/* Set the contents of PREV_VAL to the values of C indexed by the variables of IACT */ static int -xxx1 (const struct interaction *iact, const struct ccase *c, const union value **prev_val) +previous_value_record (const struct interaction *iact, const struct ccase *c, const union value **prev_val) { int ivar_idx; int diff_idx = -1; + for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx) { const struct variable *ivar = iact->vars[ivar_idx]; @@ -280,13 +304,19 @@ show_boxplot_grouped (const struct examine *cmd, int iact_idx) ds_init_empty (&label); for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx) { + struct string l; const struct variable *ivar = iact->vars[ivar_idx]; const union value *val = case_data (c, ivar); - - ds_put_cstr (&label, var_to_string (ivar)); - ds_put_cstr (&label, " = "); - var_append_value_name (ivar, val, &label); - ds_put_cstr (&label, "; "); + ds_init_empty (&l); + + append_value_name (ivar, val, &l); + ds_ltrim (&l, ss_cstr (" ")); + + ds_put_substring (&label, l.ss); + if (ivar_idx < iact->n_vars - 1) + ds_put_cstr (&label, "; "); + + ds_destroy (&l); } boxplot_add_box (boxplot, es[v].box_whisker, ds_cstr (&label)); @@ -313,7 +343,7 @@ show_boxplot_variabled (const struct examine *cmd, int iact_idx) double y_max = -DBL_MAX; const struct ccase *c = - categoricals_get_case_by_category_real (cmd->cats, iact_idx, grp); + categoricals_get_case_by_category_real (cmd->cats, iact_idx, grp); struct string title; ds_init_empty (&title); @@ -344,7 +374,7 @@ show_boxplot_variabled (const struct examine *cmd, int iact_idx) ds_put_cstr (&label, var_to_string (ivar)); ds_put_cstr (&label, " = "); - var_append_value_name (ivar, val, &label); + append_value_name (ivar, val, &label); ds_put_cstr (&label, "; "); } @@ -411,7 +441,7 @@ show_npplot (const struct examine *cmd, int iact_idx) ds_put_cstr (&label, var_to_string (ivar)); ds_put_cstr (&label, " = "); - var_append_value_name (ivar, val, &label); + append_value_name (ivar, val, &label); ds_put_cstr (&label, "; "); } @@ -436,12 +466,65 @@ show_npplot (const struct examine *cmd, int iact_idx) chart_item_submit (npp); chart_item_submit (dnpp); } + casereader_destroy (reader); ds_destroy (&label); } } } +static void +show_spreadlevel (const struct examine *cmd, int iact_idx) +{ + const struct interaction *iact = cmd->iacts[iact_idx]; + const size_t n_cats = categoricals_n_count (cmd->cats, iact_idx); + + int v; + + /* Spreadlevel when there are no levels is not useful */ + if (iact->n_vars == 0) + return; + + for (v = 0; v < cmd->n_dep_vars; ++v) + { + int grp; + struct chart_item *sl; + + struct string label; + ds_init_cstr (&label, + var_to_string (cmd->dep_vars[v])); + + if (iact->n_vars > 0) + { + ds_put_cstr (&label, " ("); + interaction_to_string (iact, &label); + ds_put_cstr (&label, ")"); + } + + sl = spreadlevel_plot_create (ds_cstr (&label), cmd->sl_power); + + for (grp = 0; grp < n_cats; ++grp) + { + const struct exploratory_stats *es = + categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, grp); + + double median = percentile_calculate (es[v].quartiles[1], cmd->pc_alg); + + double iqr = percentile_calculate (es[v].quartiles[2], cmd->pc_alg) - + percentile_calculate (es[v].quartiles[0], cmd->pc_alg); + + spreadlevel_plot_add (sl, iqr, median); + } + + if (sl == NULL) + msg (MW, _("Not creating spreadlevel chart for %s"), ds_cstr (&label)); + else + chart_item_submit (sl); + + ds_destroy (&label); + } +} + static void show_histogram (const struct examine *cmd, int iact_idx) @@ -466,6 +549,10 @@ show_histogram (const struct examine *cmd, int iact_idx) categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, grp); struct string label; + + if (es[v].histogram == NULL) + continue; + ds_init_cstr (&label, var_to_string (cmd->dep_vars[v])); @@ -479,7 +566,7 @@ show_histogram (const struct examine *cmd, int iact_idx) ds_put_cstr (&label, var_to_string (ivar)); ds_put_cstr (&label, " = "); - var_append_value_name (ivar, val, &label); + append_value_name (ivar, val, &label); ds_put_cstr (&label, "; "); } @@ -518,6 +605,7 @@ percentiles_report (const struct examine *cmd, int iact_idx) const int nc = heading_columns + cmd->n_percentiles; t = tab_create (nc, nr); + tab_title (t, _("Percentiles")); tab_headers (t, heading_columns, 0, heading_rows, 0); @@ -558,119 +646,124 @@ percentiles_report (const struct examine *cmd, int iact_idx) ); } - tab_vline (t, TAL_1, heading_columns - 1, heading_rows, nr - 1); - for (v = 0; v < cmd->n_dep_vars; ++v) + if (n_cats > 0) { - const union value **prev_val = xxx0 (iact); + tab_vline (t, TAL_1, heading_columns - 1, heading_rows, nr - 1); - int ivar_idx; - if ( v > 0 ) - tab_hline (t, TAL_1, 0, nc - 1, heading_rows + v * rows_per_var); + for (v = 0; v < cmd->n_dep_vars; ++v) + { + const union value **prev_vals = previous_value_alloc (iact); + + int ivar_idx; + if ( v > 0 ) + tab_hline (t, TAL_1, 0, nc - 1, heading_rows + v * rows_per_var); - tab_text (t, - 0, heading_rows + v * rows_per_var, - TAT_TITLE | TAB_LEFT, - var_to_string (cmd->dep_vars[v]) - ); + tab_text (t, + 0, heading_rows + v * rows_per_var, + TAT_TITLE | TAB_LEFT, + var_to_string (cmd->dep_vars[v]) + ); - for (i = 0; i < n_cats; ++i) - { - const struct ccase *c = - categoricals_get_case_by_category_real (cmd->cats, - iact_idx, i); + for (i = 0; i < n_cats; ++i) + { + const struct ccase *c = + categoricals_get_case_by_category_real (cmd->cats, + iact_idx, i); - const struct exploratory_stats *ess = - categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, i); + const struct exploratory_stats *ess = + categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, i); - const struct exploratory_stats *es = ess + v; + const struct exploratory_stats *es = ess + v; - int diff_idx = xxx1 (iact, c, prev_val); + int diff_idx = previous_value_record (iact, c, prev_vals); - double hinges[3]; - int p; + double hinges[3]; + int p; - for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx) - { - const struct variable *ivar = iact->vars[ivar_idx]; - const union value *val = case_data (c, ivar); + for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx) + { + const struct variable *ivar = iact->vars[ivar_idx]; + const union value *val = case_data (c, ivar); - if (( diff_idx != -1 && diff_idx <= ivar_idx) - || i == 0) - { - struct string str; - ds_init_empty (&str); - var_append_value_name (ivar, val, &str); + if (( diff_idx != -1 && diff_idx <= ivar_idx) + || i == 0) + { + struct string str; + ds_init_empty (&str); + append_value_name (ivar, val, &str); - tab_text (t, - 1 + ivar_idx, - heading_rows + v * rows_per_var + i * rows_per_cat, - TAT_TITLE | TAB_LEFT, - ds_cstr (&str) - ); + tab_text (t, + 1 + ivar_idx, + heading_rows + v * rows_per_var + i * rows_per_cat, + TAT_TITLE | TAB_LEFT, + ds_cstr (&str) + ); - ds_destroy (&str); - } - } - - if ( diff_idx != -1 && diff_idx < iact->n_vars) - { - tab_hline (t, TAL_1, 1 + diff_idx, nc - 1, - heading_rows + v * rows_per_var + i * rows_per_cat - ); - } - - tab_text (t, heading_columns - 1, - heading_rows + v * rows_per_var + i * rows_per_cat, - TAT_TITLE | TAB_LEFT, - gettext (ptile_alg_desc [cmd->pc_alg])); - - tukey_hinges_calculate (es->hinges, hinges); - - for (p = 0; p < cmd->n_percentiles; ++p) - { - tab_double (t, heading_columns + p, - heading_rows + v * rows_per_var + i * rows_per_cat, - 0, - percentile_calculate (es->percentiles[p], cmd->pc_alg), - 0); + ds_destroy (&str); + } + } + + if ( diff_idx != -1 && diff_idx < iact->n_vars) + { + tab_hline (t, TAL_1, 1 + diff_idx, nc - 1, + heading_rows + v * rows_per_var + i * rows_per_cat + ); + } + + tab_text (t, heading_columns - 1, + heading_rows + v * rows_per_var + i * rows_per_cat, + TAT_TITLE | TAB_LEFT, + gettext (ptile_alg_desc [cmd->pc_alg])); + + tukey_hinges_calculate (es->hinges, hinges); + + for (p = 0; p < cmd->n_percentiles; ++p) + { + tab_double (t, heading_columns + p, + heading_rows + v * rows_per_var + i * rows_per_cat, + 0, + percentile_calculate (es->percentiles[p], cmd->pc_alg), + NULL, RC_OTHER); - if (cmd->ptiles[p] == 25.0) - { - tab_double (t, heading_columns + p, - heading_rows + v * rows_per_var + i * rows_per_cat + 1, - 0, - hinges[0], - 0); - } - else if (cmd->ptiles[p] == 50.0) - { - tab_double (t, heading_columns + p, - heading_rows + v * rows_per_var + i * rows_per_cat + 1, - 0, - hinges[1], - 0); - } - else if (cmd->ptiles[p] == 75.0) - { - tab_double (t, heading_columns + p, - heading_rows + v * rows_per_var + i * rows_per_cat + 1, - 0, - hinges[2], - 0); - } - } - - - tab_text (t, heading_columns - 1, - heading_rows + v * rows_per_var + i * rows_per_cat + 1, - TAT_TITLE | TAB_LEFT, - _("Tukey's Hinges")); + if (cmd->ptiles[p] == 25.0) + { + tab_double (t, heading_columns + p, + heading_rows + v * rows_per_var + i * rows_per_cat + 1, + 0, + hinges[0], + NULL, RC_OTHER); + } + else if (cmd->ptiles[p] == 50.0) + { + tab_double (t, heading_columns + p, + heading_rows + v * rows_per_var + i * rows_per_cat + 1, + 0, + hinges[1], + NULL, RC_OTHER); + } + else if (cmd->ptiles[p] == 75.0) + { + tab_double (t, heading_columns + p, + heading_rows + v * rows_per_var + i * rows_per_cat + 1, + 0, + hinges[2], + NULL, RC_OTHER); + } + } + + + tab_text (t, heading_columns - 1, + heading_rows + v * rows_per_var + i * rows_per_cat + 1, + TAT_TITLE | TAB_LEFT, + _("Tukey's Hinges")); - } - } + } + free (prev_vals); + } + } tab_submit (t); } @@ -692,6 +785,7 @@ descriptives_report (const struct examine *cmd, int iact_idx) const int nc = 2 + heading_columns; t = tab_create (nc, nr); + tab_title (t, _("Descriptives")); tab_headers (t, heading_columns, 0, heading_rows, 0); @@ -725,7 +819,7 @@ descriptives_report (const struct examine *cmd, int iact_idx) for (v = 0; v < cmd->n_dep_vars; ++v) { - const union value **prev_val = xxx0 (iact); + const union value **prev_val = previous_value_alloc (iact); int ivar_idx; if ( v > 0 ) @@ -748,7 +842,7 @@ descriptives_report (const struct examine *cmd, int iact_idx) const struct exploratory_stats *es = ess + v; - const int diff_idx = xxx1 (iact, c, prev_val); + const int diff_idx = previous_value_record (iact, c, prev_val); double m0, m1, m2, m3, m4; double tval; @@ -767,7 +861,7 @@ descriptives_report (const struct examine *cmd, int iact_idx) { struct string str; ds_init_empty (&str); - var_append_value_name (ivar, val, &str); + append_value_name (ivar, val, &str); tab_text (t, 1 + ivar_idx, @@ -797,12 +891,12 @@ descriptives_report (const struct examine *cmd, int iact_idx) tab_double (t, 1 + iact->n_vars + 2, heading_rows + v * rows_per_var + i * rows_per_cat, - 0, m1, 0); + 0, m1, NULL, RC_OTHER); tab_double (t, 1 + iact->n_vars + 3, heading_rows + v * rows_per_var + i * rows_per_cat, - 0, calc_semean (m2, m0), 0); + 0, calc_semean (m2, m0), NULL, RC_OTHER); tab_text_format (t, 1 + iact->n_vars, @@ -822,7 +916,7 @@ descriptives_report (const struct examine *cmd, int iact_idx) tab_double (t, 1 + iact->n_vars + 2, heading_rows + v * rows_per_var + i * rows_per_cat + 1, - 0, m1 - tval * calc_semean (m2, m0), 0); + 0, m1 - tval * calc_semean (m2, m0), NULL, RC_OTHER); tab_text (t, @@ -835,7 +929,7 @@ descriptives_report (const struct examine *cmd, int iact_idx) tab_double (t, 1 + iact->n_vars + 2, heading_rows + v * rows_per_var + i * rows_per_cat + 2, - 0, m1 + tval * calc_semean (m2, m0), 0); + 0, m1 + tval * calc_semean (m2, m0), NULL, RC_OTHER); tab_text (t, @@ -850,7 +944,7 @@ descriptives_report (const struct examine *cmd, int iact_idx) heading_rows + v * rows_per_var + i * rows_per_cat + 3, 0, trimmed_mean_calculate (es->trimmed_mean), - 0); + NULL, RC_OTHER); tab_text (t, 1 + iact->n_vars, @@ -864,7 +958,7 @@ descriptives_report (const struct examine *cmd, int iact_idx) heading_rows + v * rows_per_var + i * rows_per_cat + 4, 0, percentile_calculate (es->quartiles[1], cmd->pc_alg), - 0); + NULL, RC_OTHER); tab_text (t, @@ -877,7 +971,7 @@ descriptives_report (const struct examine *cmd, int iact_idx) tab_double (t, 1 + iact->n_vars + 2, heading_rows + v * rows_per_var + i * rows_per_cat + 5, - 0, m2, 0); + 0, m2, NULL, RC_OTHER); tab_text (t, 1 + iact->n_vars, @@ -889,7 +983,7 @@ descriptives_report (const struct examine *cmd, int iact_idx) tab_double (t, 1 + iact->n_vars + 2, heading_rows + v * rows_per_var + i * rows_per_cat + 6, - 0, sqrt (m2), 0); + 0, sqrt (m2), NULL, RC_OTHER); tab_text (t, 1 + iact->n_vars, @@ -903,7 +997,7 @@ descriptives_report (const struct examine *cmd, int iact_idx) heading_rows + v * rows_per_var + i * rows_per_cat + 7, 0, es->minima[0].val, - 0); + NULL, RC_OTHER); tab_text (t, 1 + iact->n_vars, @@ -917,7 +1011,7 @@ descriptives_report (const struct examine *cmd, int iact_idx) heading_rows + v * rows_per_var + i * rows_per_cat + 8, 0, es->maxima[0].val, - 0); + NULL, RC_OTHER); tab_text (t, 1 + iact->n_vars, @@ -931,7 +1025,7 @@ descriptives_report (const struct examine *cmd, int iact_idx) heading_rows + v * rows_per_var + i * rows_per_cat + 9, 0, es->maxima[0].val - es->minima[0].val, - 0); + NULL, RC_OTHER); tab_text (t, 1 + iact->n_vars, @@ -947,7 +1041,7 @@ descriptives_report (const struct examine *cmd, int iact_idx) 0, percentile_calculate (es->quartiles[2], cmd->pc_alg) - percentile_calculate (es->quartiles[0], cmd->pc_alg), - 0); + NULL, RC_OTHER); @@ -962,12 +1056,12 @@ descriptives_report (const struct examine *cmd, int iact_idx) tab_double (t, 1 + iact->n_vars + 2, heading_rows + v * rows_per_var + i * rows_per_cat + 11, - 0, m3, 0); + 0, m3, NULL, RC_OTHER); tab_double (t, 1 + iact->n_vars + 3, heading_rows + v * rows_per_var + i * rows_per_cat + 11, - 0, calc_seskew (m0), 0); + 0, calc_seskew (m0), NULL, RC_OTHER); tab_text (t, 1 + iact->n_vars, @@ -979,13 +1073,15 @@ descriptives_report (const struct examine *cmd, int iact_idx) tab_double (t, 1 + iact->n_vars + 2, heading_rows + v * rows_per_var + i * rows_per_cat + 12, - 0, m4, 0); + 0, m4, NULL, RC_OTHER); tab_double (t, 1 + iact->n_vars + 3, heading_rows + v * rows_per_var + i * rows_per_cat + 12, - 0, calc_sekurt (m0), 0); + 0, calc_sekurt (m0), NULL, RC_OTHER); } + + free (prev_val); } tab_submit (t); } @@ -1009,6 +1105,7 @@ extremes_report (const struct examine *cmd, int iact_idx) const int nc = 2 + heading_columns; t = tab_create (nc, nr); + tab_title (t, _("Extreme Values")); tab_headers (t, heading_columns, 0, heading_rows, 0); @@ -1046,7 +1143,7 @@ extremes_report (const struct examine *cmd, int iact_idx) for (v = 0; v < cmd->n_dep_vars; ++v) { - const union value **prev_val = xxx0 (iact); + const union value **prev_val = previous_value_alloc (iact); int ivar_idx; if ( v > 0 ) @@ -1069,7 +1166,7 @@ extremes_report (const struct examine *cmd, int iact_idx) const struct exploratory_stats *es = ess + v; - int diff_idx = xxx1 (iact, c, prev_val); + int diff_idx = previous_value_record (iact, c, prev_val); for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx) { @@ -1081,7 +1178,7 @@ extremes_report (const struct examine *cmd, int iact_idx) { struct string str; ds_init_empty (&str); - var_append_value_name (ivar, val, &str); + append_value_name (ivar, val, &str); tab_text (t, 1 + ivar_idx, @@ -1125,49 +1222,66 @@ extremes_report (const struct examine *cmd, int iact_idx) heading_rows + v * rows_per_var + i * rows_per_cat + e, TAB_RIGHT, e + 1, - &F_8_0); + NULL, RC_INTEGER); /* The casenumber */ - tab_double (t, + if (cmd->id_var) + tab_value (t, + heading_columns, + heading_rows + v * rows_per_var + i * rows_per_cat + e, + TAB_RIGHT, + &es->maxima[e].identity, + cmd->id_var, + NULL); + else + tab_double (t, heading_columns, - heading_rows + v * rows_per_var + i * rows_per_cat + e, - 0, - es->maxima[e].identity, - &F_8_0); - + heading_rows + v * rows_per_var + i * rows_per_cat + e, + TAB_RIGHT, + es->maxima[e].identity.f, + NULL, RC_INTEGER); tab_double (t, - heading_columns + 1, - heading_rows + v * rows_per_var + i * rows_per_cat + e, - 0, - es->maxima[e].val, - 0); - - + heading_columns + 1, + heading_rows + v * rows_per_var + i * rows_per_cat + e, + 0, + es->maxima[e].val, + var_get_print_format (cmd->dep_vars[v]), RC_OTHER); + tab_double (t, heading_columns - 1, heading_rows + v * rows_per_var + i * rows_per_cat + cmd->disp_extremes + e, TAB_RIGHT, e + 1, - &F_8_0); + NULL, RC_INTEGER); /* The casenumber */ - tab_double (t, - heading_columns, - heading_rows + v * rows_per_var + i * rows_per_cat + cmd->disp_extremes + e, - 0, - es->minima[e].identity, - &F_8_0); + if (cmd->id_var) + tab_value (t, + heading_columns, + heading_rows + v * rows_per_var + i * rows_per_cat + cmd->disp_extremes + e, + TAB_RIGHT, + &es->minima[e].identity, + cmd->id_var, + NULL); + else + tab_double (t, + heading_columns, + heading_rows + v * rows_per_var + i * rows_per_cat + cmd->disp_extremes + e, + TAB_RIGHT, + es->minima[e].identity.f, + NULL, RC_INTEGER); tab_double (t, heading_columns + 1, heading_rows + v * rows_per_var + i * rows_per_cat + cmd->disp_extremes + e, 0, es->minima[e].val, - 0); + var_get_print_format (cmd->dep_vars[v]), RC_OTHER); } } + free (prev_val); } tab_submit (t); @@ -1191,6 +1305,7 @@ summary_report (const struct examine *cmd, int iact_idx) const int nc = 6 + heading_columns; t = tab_create (nc, nr); + tab_set_format (t, RC_WEIGHT, wfmt); tab_title (t, _("Case Processing Summary")); tab_headers (t, heading_columns, 0, heading_rows, 0); @@ -1241,113 +1356,114 @@ summary_report (const struct examine *cmd, int iact_idx) } if (n_cats > 0) - for (v = 0; v < cmd->n_dep_vars; ++v) - { - int ivar_idx; - const union value **prev_val = xxx0 (iact); - - if ( v > 0 ) - tab_hline (t, TAL_1, 0, nc - 1, heading_rows + v * n_cats); - - tab_text (t, - 0, heading_rows + n_cats * v, - TAT_TITLE, - var_to_string (cmd->dep_vars[v]) - ); - - - for (i = 0; i < n_cats; ++i) - { - double total; - const struct exploratory_stats *es; - - const struct ccase *c = - categoricals_get_case_by_category_real (cmd->cats, - iact_idx, i); - if (c) - { - int diff_idx = xxx1 (iact, c, prev_val); - - if ( diff_idx != -1 && diff_idx < iact->n_vars - 1) - tab_hline (t, TAL_1, 1 + diff_idx, nc - 1, - heading_rows + n_cats * v + i - ); - - for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx) - { - const struct variable *ivar = iact->vars[ivar_idx]; - const union value *val = case_data (c, ivar); - - if (( diff_idx != -1 && diff_idx <= ivar_idx) - || i == 0) - { - struct string str; - ds_init_empty (&str); - var_append_value_name (ivar, val, &str); + for (v = 0; v < cmd->n_dep_vars; ++v) + { + int ivar_idx; + const union value **prev_values = previous_value_alloc (iact); + + if ( v > 0 ) + tab_hline (t, TAL_1, 0, nc - 1, heading_rows + v * n_cats); + + tab_text (t, + 0, heading_rows + n_cats * v, + TAT_TITLE, + var_to_string (cmd->dep_vars[v]) + ); + + + for (i = 0; i < n_cats; ++i) + { + double total; + const struct exploratory_stats *es; + + const struct ccase *c = + categoricals_get_case_by_category_real (cmd->cats, + iact_idx, i); + if (c) + { + int diff_idx = previous_value_record (iact, c, prev_values); + + if ( diff_idx != -1 && diff_idx < iact->n_vars - 1) + tab_hline (t, TAL_1, 1 + diff_idx, nc - 1, + heading_rows + n_cats * v + i ); + + for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx) + { + const struct variable *ivar = iact->vars[ivar_idx]; + const union value *val = case_data (c, ivar); + + if (( diff_idx != -1 && diff_idx <= ivar_idx) + || i == 0) + { + struct string str; + ds_init_empty (&str); + append_value_name (ivar, val, &str); - tab_text (t, - 1 + ivar_idx, heading_rows + n_cats * v + i, - TAT_TITLE | TAB_LEFT, - ds_cstr (&str) - ); + tab_text (t, + 1 + ivar_idx, heading_rows + n_cats * v + i, + TAT_TITLE | TAB_LEFT, + ds_cstr (&str) + ); - ds_destroy (&str); - } - } - } + ds_destroy (&str); + } + } + } - es = categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, i); + + es = categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, i); - total = es[v].missing + es[v].non_missing; - tab_double (t, - heading_columns + 0, - heading_rows + n_cats * v + i, - 0, - es[v].non_missing, - wfmt); - - - tab_text_format (t, - heading_columns + 1, - heading_rows + n_cats * v + i, - 0, - "%g%%", - 100.0 * es[v].non_missing / total - ); - - - tab_double (t, - heading_columns + 2, - heading_rows + n_cats * v + i, - 0, - es[v].missing, - wfmt); - - tab_text_format (t, - heading_columns + 3, - heading_rows + n_cats * v + i, - 0, - "%g%%", - 100.0 * es[v].missing / total - ); - tab_double (t, - heading_columns + 4, - heading_rows + n_cats * v + i, - 0, - total, - wfmt); - - /* This can only be 100% can't it? */ - tab_text_format (t, - heading_columns + 5, - heading_rows + n_cats * v + i, - 0, - "%g%%", - 100.0 * (es[v].missing + es[v].non_missing)/ total - ); - } - } + total = es[v].missing + es[v].non_missing; + tab_double (t, + heading_columns + 0, + heading_rows + n_cats * v + i, + 0, + es[v].non_missing, + NULL, RC_WEIGHT); + + + tab_text_format (t, + heading_columns + 1, + heading_rows + n_cats * v + i, + 0, + "%g%%", + 100.0 * es[v].non_missing / total + ); + + + tab_double (t, + heading_columns + 2, + heading_rows + n_cats * v + i, + 0, + es[v].missing, + NULL, RC_WEIGHT); + + tab_text_format (t, + heading_columns + 3, + heading_rows + n_cats * v + i, + 0, + "%g%%", + 100.0 * es[v].missing / total + ); + tab_double (t, + heading_columns + 4, + heading_rows + n_cats * v + i, + 0, + total, + NULL, RC_WEIGHT); + + /* This can only be 100% can't it? */ + tab_text_format (t, + heading_columns + 5, + heading_rows + n_cats * v + i, + 0, + "%g%%", + 100.0 * (es[v].missing + es[v].non_missing)/ total + ); + } + free (prev_values); + } tab_hline (t, TAL_1, heading_columns, nc - 1, 1); tab_hline (t, TAL_1, heading_columns, nc - 1, 2); @@ -1355,25 +1471,6 @@ summary_report (const struct examine *cmd, int iact_idx) tab_submit (t); } - -/* Match a variable. - If the match succeeds, the variable will be placed in VAR. - Returns true if successful */ -static bool -lex_match_variable (struct lexer *lexer, - const struct dictionary *dict, const struct variable **var) -{ - if (lex_token (lexer) != T_ID) - - return false; - - *var = parse_variable_const (lexer, dict); - - if ( *var == NULL) - return false; - return true; -} - /* Attempt to parse an interaction from LEXER */ static struct interaction * parse_interaction (struct lexer *lexer, struct examine *ex) @@ -1407,20 +1504,13 @@ create_n (const void *aux1, void *aux2 UNUSED) int v; const struct examine *examine = aux1; - struct exploratory_stats *es = xcalloc (examine->n_dep_vars, sizeof (*es)); - - struct caseproto *proto = caseproto_create (); - proto = caseproto_add_width (proto, 0); /* value */ - proto = caseproto_add_width (proto, 0); /* id */ - proto = caseproto_add_width (proto, 0); /* weight */ + struct exploratory_stats *es = pool_calloc (examine->pool, examine->n_dep_vars, sizeof (*es)); + struct subcase ordering; + subcase_init (&ordering, 0, 0, SC_ASCEND); for (v = 0; v < examine->n_dep_vars; v++) { - struct subcase ordering; - - subcase_init (&ordering, 0, 0, SC_ASCEND); - - es[v].sorted_writer = sort_create_writer (&ordering, proto); + es[v].sorted_writer = sort_create_writer (&ordering, examine->ex_proto); es[v].sorted_reader = NULL; es[v].mom = moments_create (MOMENT_KURTOSIS); @@ -1429,6 +1519,8 @@ create_n (const void *aux1, void *aux2 UNUSED) es[v].maximum = -DBL_MAX; es[v].minimum = DBL_MAX; } + + subcase_destroy (&ordering); return es; } @@ -1439,24 +1531,21 @@ update_n (const void *aux1, void *aux2 UNUSED, void *user_data, int v; const struct examine *examine = aux1; struct exploratory_stats *es = user_data; - - struct caseproto *proto = caseproto_create (); - proto = caseproto_add_width (proto, 0); /* value */ - proto = caseproto_add_width (proto, 0); /* id */ - proto = caseproto_add_width (proto, 0); /* weight */ - + for (v = 0; v < examine->n_dep_vars; v++) { - struct ccase *outcase = case_create (proto); + struct ccase *outcase ; const struct variable *var = examine->dep_vars[v]; const double x = case_data (c, var)->f; - if (var_is_value_missing (var, case_data (c, var), examine->exclude)) + if (var_is_value_missing (var, case_data (c, var), examine->dep_excl)) { es[v].missing += weight; continue; } + outcase = case_create (examine->ex_proto); + if (x > es[v].maximum) es[v].maximum = x; @@ -1467,10 +1556,11 @@ update_n (const void *aux1, void *aux2 UNUSED, void *user_data, moments_pass_one (es[v].mom, x, weight); - /* Save the value and the casenumber to the writer */ + /* Save the value and the ID to the writer */ + assert (examine->id_idx != -1); case_data_rw_idx (outcase, EX_VAL)->f = x; - if ( examine->id_idx != -1) - case_data_rw_idx (outcase, EX_ID)->f = case_data_idx (c, examine->id_idx)->f; + value_copy (case_data_rw_idx (outcase, EX_ID), + case_data_idx (c, examine->id_idx), examine->id_width); case_data_rw_idx (outcase, EX_WT)->f = weight; @@ -1494,29 +1584,39 @@ calculate_n (const void *aux1, void *aux2 UNUSED, void *user_data) { int i; casenumber imin = 0; - double imax = es[v].cc; + casenumber imax; struct casereader *reader; struct ccase *c; - casenumber total_cases; - if (examine->histogram) + if (examine->histogramplot) { + /* Sturges Rule */ + double bin_width = fabs (es[v].minimum - es[v].maximum) + / (1 + log2 (es[v].cc)) + ; + es[v].histogram = - histogram_create (10, es[v].minimum, es[v].maximum); + histogram_create (bin_width, es[v].minimum, es[v].maximum); } es[v].sorted_reader = casewriter_make_reader (es[v].sorted_writer); - total_cases = casereader_count_cases (casereader_clone (es[v].sorted_reader)); es[v].sorted_writer = NULL; - es[v].maxima = xcalloc (examine->calc_extremes, sizeof (*es[v].maxima)); - es[v].minima = xcalloc (examine->calc_extremes, sizeof (*es[v].minima)); + imax = casereader_get_case_cnt (es[v].sorted_reader); + + es[v].maxima = pool_calloc (examine->pool, examine->calc_extremes, sizeof (*es[v].maxima)); + es[v].minima = pool_calloc (examine->pool, examine->calc_extremes, sizeof (*es[v].minima)); + for (i = 0; i < examine->calc_extremes; ++i) + { + value_init_pool (examine->pool, &es[v].maxima[i].identity, examine->id_width) ; + value_init_pool (examine->pool, &es[v].minima[i].identity, examine->id_width) ; + } for (reader = casereader_clone (es[v].sorted_reader); (c = casereader_read (reader)) != NULL; case_unref (c)) { const double val = case_data_idx (c, EX_VAL)->f; - const double wt = case_data_idx (c, EX_WT)->f; /* FIXME: What about fractional weights ??? */ + const double wt = case_data_idx (c, EX_WT)->f; moments_pass_two (es[v].mom, val, wt); @@ -1530,17 +1630,17 @@ calculate_n (const void *aux1, void *aux2 UNUSED, void *user_data) { struct extremity *min = &es[v].minima[x]; min->val = val; - min->identity = case_data_idx (c, EX_ID)->f; + value_copy (&min->identity, case_data_idx (c, EX_ID), examine->id_width); } - imin += wt; + imin ++; } - imax -= wt; + imax --; if (imax < examine->calc_extremes) { int x; - for (x = imax; x < imax + wt; ++x) + for (x = imax; x < imax + 1; ++x) { struct extremity *max; @@ -1549,7 +1649,7 @@ calculate_n (const void *aux1, void *aux2 UNUSED, void *user_data) max = &es[v].maxima[x]; max->val = val; - max->identity = case_data_idx (c, EX_ID)->f; + value_copy (&max->identity, case_data_idx (c, EX_ID), examine->id_width); } } } @@ -1558,39 +1658,41 @@ calculate_n (const void *aux1, void *aux2 UNUSED, void *user_data) if (examine->calc_extremes > 0) { assert (es[v].minima[0].val == es[v].minimum); - assert (es[v].maxima[0].val == es[v].maximum); + assert (es[v].maxima[0].val == es[v].maximum); } { - const int n_os = 5 + examine->n_percentiles; - struct order_stats **os ; - es[v].percentiles = xcalloc (examine->n_percentiles, sizeof (*es[v].percentiles)); + const int n_os = 5 + examine->n_percentiles; + struct order_stats **os ; + es[v].percentiles = pool_calloc (examine->pool, examine->n_percentiles, sizeof (*es[v].percentiles)); - es[v].trimmed_mean = trimmed_mean_create (es[v].cc, 0.05); + es[v].trimmed_mean = trimmed_mean_create (es[v].cc, 0.05); - os = xcalloc (n_os, sizeof *os); - os[0] = &es[v].trimmed_mean->parent; + os = xcalloc (n_os, sizeof *os); + os[0] = &es[v].trimmed_mean->parent; - es[v].quartiles[0] = percentile_create (0.25, es[v].cc); - es[v].quartiles[1] = percentile_create (0.5, es[v].cc); - es[v].quartiles[2] = percentile_create (0.75, es[v].cc); + es[v].quartiles[0] = percentile_create (0.25, es[v].cc); + es[v].quartiles[1] = percentile_create (0.5, es[v].cc); + es[v].quartiles[2] = percentile_create (0.75, es[v].cc); - os[1] = &es[v].quartiles[0]->parent; - os[2] = &es[v].quartiles[1]->parent; - os[3] = &es[v].quartiles[2]->parent; + os[1] = &es[v].quartiles[0]->parent; + os[2] = &es[v].quartiles[1]->parent; + os[3] = &es[v].quartiles[2]->parent; - es[v].hinges = tukey_hinges_create (es[v].cc, es[v].cmin); - os[4] = &es[v].hinges->parent; + es[v].hinges = tukey_hinges_create (es[v].cc, es[v].cmin); + os[4] = &es[v].hinges->parent; - for (i = 0; i < examine->n_percentiles; ++i) - { - es[v].percentiles[i] = percentile_create (examine->ptiles[i] / 100.00, es[v].cc); - os[5 + i] = &es[v].percentiles[i]->parent; - } + for (i = 0; i < examine->n_percentiles; ++i) + { + es[v].percentiles[i] = percentile_create (examine->ptiles[i] / 100.00, es[v].cc); + os[5 + i] = &es[v].percentiles[i]->parent; + } - order_stats_accumulate_idx (os, n_os, - casereader_clone (es[v].sorted_reader), - EX_WT, EX_VAL); + order_stats_accumulate_idx (os, n_os, + casereader_clone (es[v].sorted_reader), + EX_WT, EX_VAL); + + free (os); } if (examine->boxplot) @@ -1598,12 +1700,12 @@ calculate_n (const void *aux1, void *aux2 UNUSED, void *user_data) struct order_stats *os; es[v].box_whisker = box_whisker_create (es[v].hinges, - EX_ID); + EX_ID, examine->id_var); os = &es[v].box_whisker->parent; order_stats_accumulate_idx (&os, 1, - casereader_clone (es[v].sorted_reader), - EX_WT, EX_VAL); + casereader_clone (es[v].sorted_reader), + EX_WT, EX_VAL); } if (examine->npplot) @@ -1618,13 +1720,70 @@ calculate_n (const void *aux1, void *aux2 UNUSED, void *user_data) os = &es[v].np->parent; order_stats_accumulate_idx (&os, 1, - casereader_clone (es[v].sorted_reader), - EX_WT, EX_VAL); + casereader_clone (es[v].sorted_reader), + EX_WT, EX_VAL); } } } +static void +cleanup_exploratory_stats (struct examine *cmd) +{ + int i; + for (i = 0; i < cmd->n_iacts; ++i) + { + int v; + const size_t n_cats = categoricals_n_count (cmd->cats, i); + + for (v = 0; v < cmd->n_dep_vars; ++v) + { + int grp; + for (grp = 0; grp < n_cats; ++grp) + { + int q; + const struct exploratory_stats *es = + categoricals_get_user_data_by_category_real (cmd->cats, i, grp); + + struct order_stats *os = &es[v].hinges->parent; + struct statistic *stat = &os->parent; + stat->destroy (stat); + + for (q = 0; q < 3 ; q++) + { + os = &es[v].quartiles[q]->parent; + stat = &os->parent; + stat->destroy (stat); + } + + for (q = 0; q < cmd->n_percentiles ; q++) + { + os = &es[v].percentiles[q]->parent; + stat = &os->parent; + stat->destroy (stat); + } + + os = &es[v].trimmed_mean->parent; + stat = &os->parent; + stat->destroy (stat); + + os = &es[v].np->parent; + if (os) + { + stat = &os->parent; + stat->destroy (stat); + } + + statistic_destroy (&es[v].histogram->parent); + moments_destroy (es[v].mom); + + casereader_destroy (es[v].sorted_reader); + } + } + } +} + + static void run_examine (struct examine *cmd, struct casereader *input) { @@ -1635,44 +1794,37 @@ run_examine (struct examine *cmd, struct casereader *input) struct payload payload; payload.create = create_n; payload.update = update_n; - payload.destroy = calculate_n; + payload.calculate = calculate_n; + payload.destroy = NULL; cmd->wv = dict_get_weight (cmd->dict); - cmd->id_idx = -1; cmd->cats = categoricals_create (cmd->iacts, cmd->n_iacts, - cmd->wv, cmd->exclude); + cmd->wv, cmd->dep_excl, cmd->fctr_excl); categoricals_set_payload (cmd->cats, &payload, cmd, NULL); - if (cmd->casenumbers) + if (cmd->id_var == NULL) { struct ccase *c = casereader_peek (input, 0); - if (cmd->id_var) - cmd->id_idx = var_get_case_index (cmd->id_var); - else - { - cmd->id_idx = case_get_value_cnt (c); - input = casereader_create_arithmetic_sequence (input, 1.0, 1.0); - } + cmd->id_idx = case_get_value_cnt (c); + input = casereader_create_arithmetic_sequence (input, 1.0, 1.0); case_unref (c); } - /* FIXME: Filter out missing factor variables */ - /* Remove cases on a listwise basis if requested */ if ( cmd->missing_pw == false) input = casereader_create_filter_missing (input, cmd->dep_vars, cmd->n_dep_vars, - cmd->exclude, + cmd->dep_excl, NULL, NULL); - for (reader = casereader_clone (input); + for (reader = input; (c = casereader_read (reader)) != NULL; case_unref (c)) { categoricals_update (cmd->cats, c); @@ -1706,20 +1858,28 @@ run_examine (struct examine *cmd, struct casereader *input) } } - if (cmd->histogram) + if (cmd->histogramplot) show_histogram (cmd, i); if (cmd->npplot) show_npplot (cmd, i); + if (cmd->spreadlevelplot) + show_spreadlevel (cmd, i); + if (cmd->descriptives) descriptives_report (cmd, i); } + + cleanup_exploratory_stats (cmd); + categoricals_destroy (cmd->cats); } + int cmd_examine (struct lexer *lexer, struct dataset *ds) { + int i; bool nototals_seen = false; bool totals_seen = false; @@ -1727,7 +1887,6 @@ cmd_examine (struct lexer *lexer, struct dataset *ds) struct examine examine; bool percentiles_seen = false; - examine.casenumbers = false; examine.missing_pw = false; examine.disp_extremes = 0; examine.calc_extremes = 0; @@ -1736,9 +1895,14 @@ cmd_examine (struct lexer *lexer, struct dataset *ds) examine.pc_alg = PC_HAVERAGE; examine.ptiles = NULL; examine.n_percentiles = 0; - examine.id_var = 0; + examine.id_idx = -1; + examine.id_width = 0; + examine.id_var = NULL; examine.boxplot_mode = BP_GROUPS; + examine.ex_proto = caseproto_create (); + + examine.pool = pool_create (); /* Allocate space for the first interaction. This is interaction is an empty one (for the totals). @@ -1746,13 +1910,16 @@ cmd_examine (struct lexer *lexer, struct dataset *ds) interaction. */ examine.n_iacts = 1; - examine.iacts = iacts_mem = xzalloc (sizeof (struct interaction *)); + examine.iacts = iacts_mem = pool_zalloc (examine.pool, sizeof (struct interaction *)); examine.iacts[0] = interaction_create (NULL); - examine.exclude = MV_ANY; - examine.histogram = false; + examine.dep_excl = MV_ANY; + examine.fctr_excl = MV_ANY; + examine.histogramplot = false; examine.npplot = false; examine.boxplot = false; + examine.spreadlevelplot = false; + examine.sl_power = 0; examine.dict = dataset_dict (ds); @@ -1779,8 +1946,9 @@ cmd_examine (struct lexer *lexer, struct dataset *ds) { examine.n_iacts++; iacts_mem = - xrealloc (iacts_mem, - sizeof (*iacts_mem) * examine.n_iacts); + pool_nrealloc (examine.pool, iacts_mem, + examine.n_iacts, + sizeof (*iacts_mem)); iacts_mem[examine.n_iacts - 1] = iact; } @@ -1930,11 +2098,19 @@ cmd_examine (struct lexer *lexer, struct dataset *ds) } else if (lex_match_id (lexer, "EXCLUDE")) { - examine.exclude = MV_ANY; + examine.dep_excl = MV_ANY; } else if (lex_match_id (lexer, "INCLUDE")) { - examine.exclude = MV_SYSTEM; + examine.dep_excl = MV_SYSTEM; + } + else if (lex_match_id (lexer, "REPORT")) + { + examine.fctr_excl = MV_NEVER; + } + else if (lex_match_id (lexer, "NOREPORT")) + { + examine.fctr_excl = MV_ANY; } else { @@ -1977,17 +2153,30 @@ cmd_examine (struct lexer *lexer, struct dataset *ds) } else if (lex_match_id (lexer, "HISTOGRAM")) { - examine.histogram = true; + examine.histogramplot = true; + } + else if (lex_match_id (lexer, "SPREADLEVEL")) + { + examine.spreadlevelplot = true; + examine.sl_power = 0; + if (lex_match (lexer, T_LPAREN) && lex_force_int (lexer)) + { + examine.sl_power = lex_integer (lexer); + + lex_get (lexer); + if (! lex_force_match (lexer, T_RPAREN)) + goto error; + } } else if (lex_match_id (lexer, "NONE")) { - examine.histogram = false; + examine.histogramplot = false; examine.npplot = false; examine.boxplot = false; } else if (lex_match (lexer, T_ALL)) { - examine.histogram = true; + examine.histogramplot = true; examine.npplot = true; examine.boxplot = true; } @@ -2020,6 +2209,7 @@ cmd_examine (struct lexer *lexer, struct dataset *ds) } } + if ( totals_seen && nototals_seen) { msg (SE, _("%s and %s are mutually exclusive"),"TOTAL","NOTOTAL"); @@ -2036,21 +2226,26 @@ cmd_examine (struct lexer *lexer, struct dataset *ds) { examine.n_iacts--; examine.iacts = &iacts_mem[1]; + interaction_destroy (iacts_mem[0]); } - if (examine.disp_extremes > 0) + if ( examine.id_var ) { - examine.calc_extremes = examine.disp_extremes; - examine.casenumbers = true; + examine.id_idx = var_get_case_index (examine.id_var); + examine.id_width = var_get_width (examine.id_var); } - if (examine.boxplot) + examine.ex_proto = caseproto_add_width (examine.ex_proto, 0); /* value */ + examine.ex_proto = caseproto_add_width (examine.ex_proto, examine.id_width); /* id */ + examine.ex_proto = caseproto_add_width (examine.ex_proto, 0); /* weight */ + + + if (examine.disp_extremes > 0) { - examine.casenumbers = true; + examine.calc_extremes = examine.disp_extremes; } - if (examine.descriptives && examine.calc_extremes == 0) { /* Descriptives always displays the max and min */ @@ -2085,8 +2280,24 @@ cmd_examine (struct lexer *lexer, struct dataset *ds) ok = proc_commit (ds) && ok; } + caseproto_unref (examine.ex_proto); + + for (i = 0; i < examine.n_iacts; ++i) + interaction_destroy (examine.iacts[i]); + free (examine.ptiles); + free (examine.dep_vars); + pool_destroy (examine.pool); + return CMD_SUCCESS; error: + caseproto_unref (examine.ex_proto); + examine.iacts = iacts_mem; + for (i = 0; i < examine.n_iacts; ++i) + interaction_destroy (examine.iacts[i]); + free (examine.dep_vars); + free (examine.ptiles); + pool_destroy (examine.pool); + return CMD_FAILURE; }