2 PSPP - a program for statistical analysis.
3 Copyright (C) 2012, 2013, 2016, 2019 Free Software Foundation, Inc.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include <gsl/gsl_cdf.h>
24 #include "data/casegrouper.h"
25 #include "data/caseproto.h"
26 #include "data/casereader.h"
27 #include "data/casewriter.h"
28 #include "data/dataset.h"
29 #include "data/dictionary.h"
30 #include "data/format.h"
31 #include "data/subcase.h"
32 #include "language/command.h"
33 #include "language/lexer/lexer.h"
34 #include "language/lexer/value-parser.h"
35 #include "language/lexer/variable-parser.h"
36 #include "libpspp/assertion.h"
37 #include "libpspp/message.h"
38 #include "libpspp/pool.h"
39 #include "math/box-whisker.h"
40 #include "math/categoricals.h"
41 #include "math/chart-geometry.h"
42 #include "math/histogram.h"
43 #include "math/interaction.h"
44 #include "math/moments.h"
46 #include "math/order-stats.h"
47 #include "math/percentiles.h"
48 #include "math/shapiro-wilk.h"
49 #include "math/sort.h"
50 #include "math/trimmed-mean.h"
51 #include "math/tukey-hinges.h"
52 #include "output/charts/boxplot.h"
53 #include "output/charts/np-plot.h"
54 #include "output/charts/plot-hist.h"
55 #include "output/charts/spreadlevel-plot.h"
56 #include "output/pivot-table.h"
59 #define _(msgid) gettext (msgid)
60 #define N_(msgid) msgid
63 append_value_name (const struct variable *var, const union value *val, struct string *str)
65 var_append_value_name (var, val, str);
66 if (var_is_value_missing (var, val))
67 ds_put_cstr (str, _(" (missing)"));
76 /* Indices for the ex_proto member (below) */
89 /* A caseproto used to contain the data subsets under examination,
91 struct caseproto *ex_proto;
94 const struct variable **dep_vars;
97 struct interaction **iacts;
99 enum mv_class dep_excl;
100 enum mv_class fctr_excl;
102 const struct dictionary *dict;
104 struct categoricals *cats;
106 /* how many extremities to display */
115 /* The case index of the ID value (or -1) if not applicable */
121 size_t n_percentiles;
126 bool plot_spreadlevel;
129 enum bp_mode boxplot_mode;
131 const struct variable *id_var;
133 const struct variable *wv;
138 /* The value of this extremity */
141 /* Either the casenumber or the value of the variable specified
142 by the /ID subcommand which corresponds to this extremity */
143 union value identity;
146 struct exploratory_stats
153 /* Most operations need a sorted reader/writer */
154 struct casewriter *sorted_writer;
155 struct casereader *sorted_reader;
157 struct extremity *minima;
158 struct extremity *maxima;
161 Minimum should alway equal mimima[0].val.
162 Likewise, maximum should alway equal maxima[0].val.
163 This redundancy exists as an optimisation effort.
164 Some statistics (eg histogram) require early calculation
170 struct trimmed_mean *trimmed_mean;
171 struct percentile *quartiles[3];
172 struct percentile **percentiles;
173 struct shapiro_wilk *shapiro_wilk;
175 struct tukey_hinges *hinges;
177 /* The data for the NP Plots */
180 struct histogram *histogram;
182 /* The data for the box plots */
183 struct box_whisker *box_whisker;
188 /* The minimum weight */
193 show_boxplot_grouped (const struct examine *cmd, int iact_idx)
197 const struct interaction *iact = cmd->iacts[iact_idx];
198 const size_t n_cats = categoricals_n_count (cmd->cats, iact_idx);
200 for (v = 0; v < cmd->n_dep_vars; ++v)
202 double y_min = DBL_MAX;
203 double y_max = -DBL_MAX;
205 struct boxplot *boxplot;
207 ds_init_empty (&title);
209 if (iact->n_vars > 0)
212 ds_init_empty (&istr);
213 interaction_to_string (iact, &istr);
214 ds_put_format (&title, _("Boxplot of %s vs. %s"),
215 var_to_string (cmd->dep_vars[v]),
220 ds_put_format (&title, _("Boxplot of %s"), var_to_string (cmd->dep_vars[v]));
222 for (grp = 0; grp < n_cats; ++grp)
224 const struct exploratory_stats *es =
225 categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, grp);
227 if (y_min > es[v].minimum)
228 y_min = es[v].minimum;
230 if (y_max < es[v].maximum)
231 y_max = es[v].maximum;
234 boxplot = boxplot_create (y_min, y_max, ds_cstr (&title));
238 for (grp = 0; grp < n_cats; ++grp)
243 const struct ccase *c =
244 categoricals_get_case_by_category_real (cmd->cats, iact_idx, grp);
246 struct exploratory_stats *es =
247 categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, grp);
249 ds_init_empty (&label);
250 for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx)
253 const struct variable *ivar = iact->vars[ivar_idx];
254 const union value *val = case_data (c, ivar);
257 append_value_name (ivar, val, &l);
258 ds_ltrim (&l, ss_cstr (" "));
260 ds_put_substring (&label, l.ss);
261 if (ivar_idx < iact->n_vars - 1)
262 ds_put_cstr (&label, "; ");
267 boxplot_add_box (boxplot, es[v].box_whisker, ds_cstr (&label));
268 es[v].box_whisker = NULL;
273 boxplot_submit (boxplot);
278 show_boxplot_variabled (const struct examine *cmd, int iact_idx)
281 const struct interaction *iact = cmd->iacts[iact_idx];
282 const size_t n_cats = categoricals_n_count (cmd->cats, iact_idx);
284 for (grp = 0; grp < n_cats; ++grp)
286 struct boxplot *boxplot;
288 double y_min = DBL_MAX;
289 double y_max = -DBL_MAX;
291 const struct ccase *c =
292 categoricals_get_case_by_category_real (cmd->cats, iact_idx, grp);
295 ds_init_empty (&title);
297 for (v = 0; v < cmd->n_dep_vars; ++v)
299 const struct exploratory_stats *es =
300 categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, grp);
302 if (y_min > es[v].minimum)
303 y_min = es[v].minimum;
305 if (y_max < es[v].maximum)
306 y_max = es[v].maximum;
309 if (iact->n_vars == 0)
310 ds_put_format (&title, _("Boxplot"));
315 ds_init_empty (&label);
316 for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx)
318 const struct variable *ivar = iact->vars[ivar_idx];
319 const union value *val = case_data (c, ivar);
321 ds_put_cstr (&label, var_to_string (ivar));
322 ds_put_cstr (&label, " = ");
323 append_value_name (ivar, val, &label);
324 ds_put_cstr (&label, "; ");
327 ds_put_format (&title, _("Boxplot of %s"),
333 boxplot = boxplot_create (y_min, y_max, ds_cstr (&title));
337 for (v = 0; v < cmd->n_dep_vars; ++v)
339 struct exploratory_stats *es =
340 categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, grp);
342 boxplot_add_box (boxplot, es[v].box_whisker,
343 var_to_string (cmd->dep_vars[v]));
344 es[v].box_whisker = NULL;
347 boxplot_submit (boxplot);
353 show_npplot (const struct examine *cmd, int iact_idx)
355 const struct interaction *iact = cmd->iacts[iact_idx];
356 const size_t n_cats = categoricals_n_count (cmd->cats, iact_idx);
360 for (v = 0; v < cmd->n_dep_vars; ++v)
363 for (grp = 0; grp < n_cats; ++grp)
365 struct chart *npp, *dnpp;
366 struct casereader *reader;
370 const struct ccase *c =
371 categoricals_get_case_by_category_real (cmd->cats,
374 const struct exploratory_stats *es =
375 categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, grp);
378 ds_init_cstr (&label,
379 var_to_string (cmd->dep_vars[v]));
381 if (iact->n_vars > 0)
383 ds_put_cstr (&label, " (");
384 for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx)
386 const struct variable *ivar = iact->vars[ivar_idx];
387 const union value *val = case_data (c, ivar);
389 ds_put_cstr (&label, var_to_string (ivar));
390 ds_put_cstr (&label, " = ");
391 append_value_name (ivar, val, &label);
392 ds_put_cstr (&label, "; ");
395 ds_put_cstr (&label, ")");
399 reader = casewriter_make_reader (np->writer);
402 npp = np_plot_create (np, reader, ds_cstr (&label));
403 dnpp = dnp_plot_create (np, reader, ds_cstr (&label));
405 if (npp == NULL || dnpp == NULL)
407 msg (MW, _("Not creating NP plot because data set is empty."));
416 casereader_destroy (reader);
424 show_spreadlevel (const struct examine *cmd, int iact_idx)
426 const struct interaction *iact = cmd->iacts[iact_idx];
427 const size_t n_cats = categoricals_n_count (cmd->cats, iact_idx);
431 /* Spreadlevel when there are no levels is not useful */
432 if (iact->n_vars == 0)
435 for (v = 0; v < cmd->n_dep_vars; ++v)
441 ds_init_cstr (&label,
442 var_to_string (cmd->dep_vars[v]));
444 if (iact->n_vars > 0)
446 ds_put_cstr (&label, " (");
447 interaction_to_string (iact, &label);
448 ds_put_cstr (&label, ")");
451 sl = spreadlevel_plot_create (ds_cstr (&label), cmd->sl_power);
453 for (grp = 0; grp < n_cats; ++grp)
455 const struct exploratory_stats *es =
456 categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, grp);
458 double median = percentile_calculate (es[v].quartiles[1], cmd->pc_alg);
460 double iqr = percentile_calculate (es[v].quartiles[2], cmd->pc_alg) -
461 percentile_calculate (es[v].quartiles[0], cmd->pc_alg);
463 spreadlevel_plot_add (sl, iqr, median);
467 msg (MW, _("Not creating spreadlevel chart for %s"), ds_cstr (&label));
477 show_histogram (const struct examine *cmd, int iact_idx)
479 const struct interaction *iact = cmd->iacts[iact_idx];
480 const size_t n_cats = categoricals_n_count (cmd->cats, iact_idx);
484 for (v = 0; v < cmd->n_dep_vars; ++v)
487 for (grp = 0; grp < n_cats; ++grp)
491 const struct ccase *c =
492 categoricals_get_case_by_category_real (cmd->cats,
495 const struct exploratory_stats *es =
496 categoricals_get_user_data_by_category_real (cmd->cats, iact_idx, grp);
500 if (es[v].histogram == NULL)
503 ds_init_cstr (&label,
504 var_to_string (cmd->dep_vars[v]));
506 if (iact->n_vars > 0)
508 ds_put_cstr (&label, " (");
509 for (ivar_idx = 0; ivar_idx < iact->n_vars; ++ivar_idx)
511 const struct variable *ivar = iact->vars[ivar_idx];
512 const union value *val = case_data (c, ivar);
514 ds_put_cstr (&label, var_to_string (ivar));
515 ds_put_cstr (&label, " = ");
516 append_value_name (ivar, val, &label);
517 ds_put_cstr (&label, "; ");
520 ds_put_cstr (&label, ")");
524 moments_calculate (es[v].mom, &n, &mean, &var, NULL, NULL);
527 (histogram_chart_create (es[v].histogram->gsl_hist,
528 ds_cstr (&label), n, mean,
537 static struct pivot_value *
538 new_value_with_missing_footnote (const struct variable *var,
539 const union value *value,
540 struct pivot_footnote *missing_footnote)
542 struct pivot_value *pv = pivot_value_new_var_value (var, value);
543 if (var_is_value_missing (var, value) == MV_USER)
544 pivot_value_add_footnote (pv, missing_footnote);
549 create_interaction_dimensions (struct pivot_table *table,
550 const struct categoricals *cats,
551 const struct interaction *iact,
552 struct pivot_footnote *missing_footnote)
554 for (size_t i = iact->n_vars; i-- > 0;)
556 const struct variable *var = iact->vars[i];
557 struct pivot_dimension *d = pivot_dimension_create__ (
558 table, PIVOT_AXIS_ROW, pivot_value_new_variable (var));
559 d->root->show_label = true;
562 union value *values = categoricals_get_var_values (cats, var, &n);
563 for (size_t j = 0; j < n; j++)
564 pivot_category_create_leaf (
565 d->root, new_value_with_missing_footnote (var, &values[j],
570 static struct pivot_footnote *
571 create_missing_footnote (struct pivot_table *table)
573 return pivot_table_create_footnote (
574 table, pivot_value_new_text (N_("User-missing value.")));
578 percentiles_report (const struct examine *cmd, int iact_idx)
580 struct pivot_table *table = pivot_table_create (N_("Percentiles"));
582 struct pivot_dimension *percentiles = pivot_dimension_create (
583 table, PIVOT_AXIS_COLUMN, N_("Percentiles"));
584 percentiles->root->show_label = true;
585 for (int i = 0; i < cmd->n_percentiles; ++i)
586 pivot_category_create_leaf (
588 pivot_value_new_user_text_nocopy (xasprintf ("%g", cmd->ptiles[i])));
590 pivot_dimension_create (table, PIVOT_AXIS_ROW, N_("Statistics"),
591 N_("Weighted Average"), N_("Tukey's Hinges"));
593 const struct interaction *iact = cmd->iacts[iact_idx];
594 struct pivot_footnote *missing_footnote = create_missing_footnote (table);
595 create_interaction_dimensions (table, cmd->cats, iact, missing_footnote);
597 struct pivot_dimension *dep_dim = pivot_dimension_create (
598 table, PIVOT_AXIS_ROW, N_("Dependent Variables"));
600 size_t *indexes = xnmalloc (table->n_dimensions, sizeof *indexes);
602 size_t n_cats = categoricals_n_count (cmd->cats, iact_idx);
603 for (size_t v = 0; v < cmd->n_dep_vars; ++v)
605 indexes[table->n_dimensions - 1] = pivot_category_create_leaf (
606 dep_dim->root, pivot_value_new_variable (cmd->dep_vars[v]));
608 for (size_t i = 0; i < n_cats; ++i)
610 for (size_t j = 0; j < iact->n_vars; j++)
612 int idx = categoricals_get_value_index_by_category_real (
613 cmd->cats, iact_idx, i, j);
614 indexes[table->n_dimensions - 2 - j] = idx;
617 const struct exploratory_stats *ess
618 = categoricals_get_user_data_by_category_real (
619 cmd->cats, iact_idx, i);
620 const struct exploratory_stats *es = ess + v;
623 tukey_hinges_calculate (es->hinges, hinges);
625 for (size_t pc_idx = 0; pc_idx < cmd->n_percentiles; ++pc_idx)
630 double value = percentile_calculate (es->percentiles[pc_idx],
632 pivot_table_put (table, indexes, table->n_dimensions,
633 pivot_value_new_number (value));
635 double hinge = (cmd->ptiles[pc_idx] == 25.0 ? hinges[0]
636 : cmd->ptiles[pc_idx] == 50.0 ? hinges[1]
637 : cmd->ptiles[pc_idx] == 75.0 ? hinges[2]
642 pivot_table_put (table, indexes, table->n_dimensions,
643 pivot_value_new_number (hinge));
651 pivot_table_submit (table);
655 normality_report (const struct examine *cmd, int iact_idx)
657 struct pivot_table *table = pivot_table_create (N_("Tests of Normality"));
659 struct pivot_dimension *test =
660 pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Shapiro-Wilk"),
662 N_("df"), PIVOT_RC_COUNT,
665 test->root->show_label = true;
667 const struct interaction *iact = cmd->iacts[iact_idx];
668 struct pivot_footnote *missing_footnote = create_missing_footnote (table);
669 create_interaction_dimensions (table, cmd->cats, iact, missing_footnote);
671 struct pivot_dimension *dep_dim = pivot_dimension_create (
672 table, PIVOT_AXIS_ROW, N_("Dependent Variables"));
674 size_t *indexes = xnmalloc (table->n_dimensions, sizeof *indexes);
676 size_t n_cats = categoricals_n_count (cmd->cats, iact_idx);
677 for (size_t v = 0; v < cmd->n_dep_vars; ++v)
679 indexes[table->n_dimensions - 1] =
680 pivot_category_create_leaf (dep_dim->root, pivot_value_new_variable (cmd->dep_vars[v]));
682 for (size_t i = 0; i < n_cats; ++i)
686 const struct exploratory_stats *es
687 = categoricals_get_user_data_by_category_real (
688 cmd->cats, iact_idx, i);
690 struct shapiro_wilk *sw = es[v].shapiro_wilk;
695 double w = shapiro_wilk_calculate (sw);
700 pivot_table_put (table, indexes, table->n_dimensions,
701 pivot_value_new_number (w));
704 pivot_table_put (table, indexes, table->n_dimensions,
705 pivot_value_new_number (sw->n));
708 pivot_table_put (table, indexes, table->n_dimensions,
709 pivot_value_new_number (shapiro_wilk_significance (sw->n, w)));
715 pivot_table_submit (table);
720 descriptives_report (const struct examine *cmd, int iact_idx)
722 struct pivot_table *table = pivot_table_create (N_("Descriptives"));
724 pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Aspect"),
725 N_("Statistic"), N_("Std. Error"));
727 struct pivot_dimension *statistics = pivot_dimension_create (
728 table, PIVOT_AXIS_ROW, N_("Statistics"), N_("Mean"));
729 struct pivot_category *interval = pivot_category_create_group__ (
731 pivot_value_new_text_format (N_("%g%% Confidence Interval for Mean"),
733 pivot_category_create_leaves (interval, N_("Lower Bound"),
735 pivot_category_create_leaves (
736 statistics->root, N_("5% Trimmed Mean"), N_("Median"), N_("Variance"),
737 N_("Std. Deviation"), N_("Minimum"), N_("Maximum"), N_("Range"),
738 N_("Interquartile Range"), N_("Skewness"), N_("Kurtosis"));
740 const struct interaction *iact = cmd->iacts[iact_idx];
741 struct pivot_footnote *missing_footnote = create_missing_footnote (table);
742 create_interaction_dimensions (table, cmd->cats, iact, missing_footnote);
744 struct pivot_dimension *dep_dim = pivot_dimension_create (
745 table, PIVOT_AXIS_ROW, N_("Dependent Variables"));
747 size_t *indexes = xnmalloc (table->n_dimensions, sizeof *indexes);
749 size_t n_cats = categoricals_n_count (cmd->cats, iact_idx);
750 for (size_t v = 0; v < cmd->n_dep_vars; ++v)
752 indexes[table->n_dimensions - 1] = pivot_category_create_leaf (
753 dep_dim->root, pivot_value_new_variable (cmd->dep_vars[v]));
755 for (size_t i = 0; i < n_cats; ++i)
757 for (size_t j = 0; j < iact->n_vars; j++)
759 int idx = categoricals_get_value_index_by_category_real (
760 cmd->cats, iact_idx, i, j);
761 indexes[table->n_dimensions - 2 - j] = idx;
764 const struct exploratory_stats *ess
765 = categoricals_get_user_data_by_category_real (cmd->cats,
767 const struct exploratory_stats *es = ess + v;
769 double m0, m1, m2, m3, m4;
770 moments_calculate (es->mom, &m0, &m1, &m2, &m3, &m4);
771 double tval = gsl_cdf_tdist_Qinv ((1.0 - cmd->conf) / 2.0, m0 - 1.0);
781 { 0, 1, calc_semean (m2, m0) },
782 { 1, 0, m1 - tval * calc_semean (m2, m0) },
783 { 2, 0, m1 + tval * calc_semean (m2, m0) },
784 { 3, 0, trimmed_mean_calculate (es->trimmed_mean) },
785 { 4, 0, percentile_calculate (es->quartiles[1], cmd->pc_alg) },
788 { 7, 0, es->minima[0].val },
789 { 8, 0, es->maxima[0].val },
790 { 9, 0, es->maxima[0].val - es->minima[0].val },
791 { 10, 0, (percentile_calculate (es->quartiles[2], cmd->pc_alg) -
792 percentile_calculate (es->quartiles[0], cmd->pc_alg)) },
794 { 11, 1, calc_seskew (m0) },
796 { 12, 1, calc_sekurt (m0) },
798 for (size_t j = 0; j < sizeof entries / sizeof *entries; j++)
800 const struct entry *e = &entries[j];
801 indexes[0] = e->aspect_idx;
802 indexes[1] = e->stat_idx;
803 pivot_table_put (table, indexes, table->n_dimensions,
804 pivot_value_new_number (e->x));
811 pivot_table_submit (table);
816 extremes_report (const struct examine *cmd, int iact_idx)
818 struct pivot_table *table = pivot_table_create (N_("Extreme Values"));
820 struct pivot_dimension *statistics = pivot_dimension_create (
821 table, PIVOT_AXIS_COLUMN, N_("Statistics"));
822 pivot_category_create_leaf (statistics->root,
824 ? pivot_value_new_variable (cmd->id_var)
825 : pivot_value_new_text (N_("Case Number"))));
826 pivot_category_create_leaves (statistics->root, N_("Value"));
828 struct pivot_dimension *order = pivot_dimension_create (
829 table, PIVOT_AXIS_ROW, N_("Order"));
830 for (size_t i = 0; i < cmd->disp_extremes; i++)
831 pivot_category_create_leaf (order->root, pivot_value_new_integer (i + 1));
833 pivot_dimension_create (table, PIVOT_AXIS_ROW,
834 /* TRANSLATORS: This is a noun, not an adjective. */
836 N_("Highest"), N_("Lowest"));
838 const struct interaction *iact = cmd->iacts[iact_idx];
839 struct pivot_footnote *missing_footnote = create_missing_footnote (table);
840 create_interaction_dimensions (table, cmd->cats, iact, missing_footnote);
842 struct pivot_dimension *dep_dim = pivot_dimension_create (
843 table, PIVOT_AXIS_ROW, N_("Dependent Variables"));
845 size_t *indexes = xnmalloc (table->n_dimensions, sizeof *indexes);
847 size_t n_cats = categoricals_n_count (cmd->cats, iact_idx);
848 for (size_t v = 0; v < cmd->n_dep_vars; ++v)
850 indexes[table->n_dimensions - 1] = pivot_category_create_leaf (
851 dep_dim->root, pivot_value_new_variable (cmd->dep_vars[v]));
853 for (size_t i = 0; i < n_cats; ++i)
855 for (size_t j = 0; j < iact->n_vars; j++)
857 int idx = categoricals_get_value_index_by_category_real (
858 cmd->cats, iact_idx, i, j);
859 indexes[table->n_dimensions - 2 - j] = idx;
862 const struct exploratory_stats *ess
863 = categoricals_get_user_data_by_category_real (cmd->cats,
865 const struct exploratory_stats *es = ess + v;
867 for (int e = 0; e < cmd->disp_extremes; ++e)
871 for (size_t j = 0; j < 2; j++)
873 const struct extremity *extremity
874 = j ? &es->minima[e] : &es->maxima[e];
879 table, indexes, table->n_dimensions,
881 ? new_value_with_missing_footnote (cmd->id_var,
882 &extremity->identity,
884 : pivot_value_new_integer (extremity->identity.f)));
887 union value val = { .f = extremity->val };
889 table, indexes, table->n_dimensions,
890 new_value_with_missing_footnote (cmd->dep_vars[v], &val,
898 pivot_table_submit (table);
903 summary_report (const struct examine *cmd, int iact_idx)
905 struct pivot_table *table = pivot_table_create (
906 N_("Case Processing Summary"));
907 pivot_table_set_weight_var (table, dict_get_weight (cmd->dict));
909 pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
910 N_("N"), PIVOT_RC_COUNT,
911 N_("Percent"), PIVOT_RC_PERCENT);
912 struct pivot_dimension *cases = pivot_dimension_create (
913 table, PIVOT_AXIS_COLUMN, N_("Cases"), N_("Valid"), N_("Missing"),
915 cases->root->show_label = true;
917 const struct interaction *iact = cmd->iacts[iact_idx];
918 struct pivot_footnote *missing_footnote = create_missing_footnote (table);
919 create_interaction_dimensions (table, cmd->cats, iact, missing_footnote);
921 struct pivot_dimension *dep_dim = pivot_dimension_create (
922 table, PIVOT_AXIS_ROW, N_("Dependent Variables"));
924 size_t *indexes = xnmalloc (table->n_dimensions, sizeof *indexes);
926 size_t n_cats = categoricals_n_count (cmd->cats, iact_idx);
927 for (size_t v = 0; v < cmd->n_dep_vars; ++v)
929 indexes[table->n_dimensions - 1] = pivot_category_create_leaf (
930 dep_dim->root, pivot_value_new_variable (cmd->dep_vars[v]));
932 for (size_t i = 0; i < n_cats; ++i)
934 for (size_t j = 0; j < iact->n_vars; j++)
936 int idx = categoricals_get_value_index_by_category_real (
937 cmd->cats, iact_idx, i, j);
938 indexes[table->n_dimensions - 2 - j] = idx;
941 const struct exploratory_stats *es
942 = categoricals_get_user_data_by_category_real (
943 cmd->cats, iact_idx, i);
945 double total = es[v].missing + es[v].non_missing;
953 { 0, 0, es[v].non_missing },
954 { 1, 0, 100.0 * es[v].non_missing / total },
955 { 0, 1, es[v].missing },
956 { 1, 1, 100.0 * es[v].missing / total },
960 for (size_t j = 0; j < sizeof entries / sizeof *entries; j++)
962 const struct entry *e = &entries[j];
963 indexes[0] = e->stat_idx;
964 indexes[1] = e->case_idx;
965 pivot_table_put (table, indexes, table->n_dimensions,
966 pivot_value_new_number (e->x));
973 pivot_table_submit (table);
976 /* Attempt to parse an interaction from LEXER */
977 static struct interaction *
978 parse_interaction (struct lexer *lexer, struct examine *ex)
980 const struct variable *v;
981 if (!lex_match_variable (lexer, ex->dict, &v))
984 struct interaction *iact = interaction_create (v);
985 while (lex_match (lexer, T_BY))
987 if (!lex_match_variable (lexer, ex->dict, &v))
989 interaction_destroy (iact);
992 interaction_add_variable (iact, v);
994 lex_match (lexer, T_COMMA);
1000 create_n (const void *aux1, void *aux2 UNUSED)
1004 const struct examine *examine = aux1;
1005 struct exploratory_stats *es = pool_calloc (examine->pool, examine->n_dep_vars, sizeof (*es));
1006 struct subcase ordering;
1007 subcase_init (&ordering, 0, 0, SC_ASCEND);
1009 for (v = 0; v < examine->n_dep_vars; v++)
1011 es[v].sorted_writer = sort_create_writer (&ordering, examine->ex_proto);
1012 es[v].sorted_reader = NULL;
1014 es[v].mom = moments_create (MOMENT_KURTOSIS);
1015 es[v].cmin = DBL_MAX;
1017 es[v].maximum = -DBL_MAX;
1018 es[v].minimum = DBL_MAX;
1021 subcase_uninit (&ordering);
1026 update_n (const void *aux1, void *aux2 UNUSED, void *user_data,
1027 const struct ccase *c, double weight)
1030 const struct examine *examine = aux1;
1031 struct exploratory_stats *es = user_data;
1033 bool this_case_is_missing = false;
1034 /* LISTWISE missing must be dealt with here */
1035 if (!examine->missing_pw)
1037 for (v = 0; v < examine->n_dep_vars; v++)
1039 const struct variable *var = examine->dep_vars[v];
1041 if (var_is_value_missing (var, case_data (c, var))
1042 & examine->dep_excl)
1044 es[v].missing += weight;
1045 this_case_is_missing = true;
1050 if (this_case_is_missing)
1053 for (v = 0; v < examine->n_dep_vars; v++)
1055 struct ccase *outcase;
1056 const struct variable *var = examine->dep_vars[v];
1057 const double x = case_num (c, var);
1059 if (var_is_value_missing (var, case_data (c, var)) & examine->dep_excl)
1061 es[v].missing += weight;
1065 outcase = case_create (examine->ex_proto);
1067 if (x > es[v].maximum)
1070 if (x < es[v].minimum)
1073 es[v].non_missing += weight;
1075 moments_pass_one (es[v].mom, x, weight);
1077 /* Save the value and the ID to the writer */
1078 assert (examine->id_idx != -1);
1079 *case_num_rw_idx (outcase, EX_VAL) = x;
1080 value_copy (case_data_rw_idx (outcase, EX_ID),
1081 case_data_idx (c, examine->id_idx), examine->id_width);
1083 *case_num_rw_idx (outcase, EX_WT) = weight;
1087 if (es[v].cmin > weight)
1088 es[v].cmin = weight;
1090 casewriter_write (es[v].sorted_writer, outcase);
1095 calculate_n (const void *aux1, void *aux2 UNUSED, void *user_data)
1098 const struct examine *examine = aux1;
1099 struct exploratory_stats *es = user_data;
1101 for (v = 0; v < examine->n_dep_vars; v++)
1104 casenumber imin = 0;
1106 struct casereader *reader;
1109 if (examine->plot_histogram && es[v].non_missing > 0)
1112 double bin_width = fabs (es[v].minimum - es[v].maximum)
1113 / (1 + log2 (es[v].cc));
1116 histogram_create (bin_width, es[v].minimum, es[v].maximum);
1119 es[v].sorted_reader = casewriter_make_reader (es[v].sorted_writer);
1120 es[v].sorted_writer = NULL;
1122 imax = casereader_get_n_cases (es[v].sorted_reader);
1124 es[v].maxima = pool_calloc (examine->pool, examine->calc_extremes, sizeof (*es[v].maxima));
1125 es[v].minima = pool_calloc (examine->pool, examine->calc_extremes, sizeof (*es[v].minima));
1126 for (i = 0; i < examine->calc_extremes; ++i)
1128 value_init_pool (examine->pool, &es[v].maxima[i].identity, examine->id_width);
1129 value_init_pool (examine->pool, &es[v].minima[i].identity, examine->id_width);
1133 for (reader = casereader_clone (es[v].sorted_reader);
1134 (c = casereader_read (reader)) != NULL; case_unref (c))
1136 const double val = case_num_idx (c, EX_VAL);
1137 double wt = case_num_idx (c, EX_WT);
1138 wt = var_force_valid_weight (examine->wv, wt, &warn);
1140 moments_pass_two (es[v].mom, val, wt);
1142 if (es[v].histogram)
1143 histogram_add (es[v].histogram, val, wt);
1145 if (imin < examine->calc_extremes)
1148 for (x = imin; x < examine->calc_extremes; ++x)
1150 struct extremity *min = &es[v].minima[x];
1152 value_copy (&min->identity, case_data_idx (c, EX_ID), examine->id_width);
1158 if (imax < examine->calc_extremes)
1162 for (x = imax; x < imax + 1; ++x)
1164 struct extremity *max;
1166 if (x >= examine->calc_extremes)
1169 max = &es[v].maxima[x];
1171 value_copy (&max->identity, case_data_idx (c, EX_ID), examine->id_width);
1175 casereader_destroy (reader);
1177 if (examine->calc_extremes > 0 && es[v].non_missing > 0)
1179 assert (es[v].minima[0].val == es[v].minimum);
1180 assert (es[v].maxima[0].val == es[v].maximum);
1184 const int n_os = 5 + examine->n_percentiles;
1185 es[v].percentiles = pool_calloc (examine->pool, examine->n_percentiles, sizeof (*es[v].percentiles));
1187 es[v].trimmed_mean = trimmed_mean_create (es[v].cc, 0.05);
1188 es[v].shapiro_wilk = NULL;
1190 struct order_stats **os = XCALLOC (n_os, struct order_stats *);
1191 os[0] = &es[v].trimmed_mean->parent;
1193 es[v].quartiles[0] = percentile_create (0.25, es[v].cc);
1194 es[v].quartiles[1] = percentile_create (0.5, es[v].cc);
1195 es[v].quartiles[2] = percentile_create (0.75, es[v].cc);
1197 os[1] = &es[v].quartiles[0]->parent;
1198 os[2] = &es[v].quartiles[1]->parent;
1199 os[3] = &es[v].quartiles[2]->parent;
1201 es[v].hinges = tukey_hinges_create (es[v].cc, es[v].cmin);
1202 os[4] = &es[v].hinges->parent;
1204 for (i = 0; i < examine->n_percentiles; ++i)
1206 es[v].percentiles[i] = percentile_create (examine->ptiles[i] / 100.00, es[v].cc);
1207 os[5 + i] = &es[v].percentiles[i]->parent;
1210 order_stats_accumulate_idx (os, n_os,
1211 casereader_clone (es[v].sorted_reader),
1217 if (examine->plot_boxplot)
1219 struct order_stats *os;
1221 es[v].box_whisker = box_whisker_create (es[v].hinges,
1222 EX_ID, examine->id_var);
1224 os = &es[v].box_whisker->parent;
1225 order_stats_accumulate_idx (&os, 1,
1226 casereader_clone (es[v].sorted_reader),
1230 if (examine->plot_boxplot || examine->plot_histogram
1231 || examine->plot_npplot || examine->plot_spreadlevel)
1235 moments_calculate (es[v].mom, NULL, &mean, NULL, NULL, NULL);
1237 es[v].shapiro_wilk = shapiro_wilk_create (es[v].non_missing, mean);
1239 if (es[v].shapiro_wilk)
1241 struct order_stats *os = &es[v].shapiro_wilk->parent;
1242 order_stats_accumulate_idx (&os, 1,
1243 casereader_clone (es[v].sorted_reader),
1248 if (examine->plot_npplot)
1250 double n, mean, var;
1251 struct order_stats *os;
1253 moments_calculate (es[v].mom, &n, &mean, &var, NULL, NULL);
1255 es[v].np = np_create (n, mean, var);
1257 os = &es[v].np->parent;
1259 order_stats_accumulate_idx (&os, 1,
1260 casereader_clone (es[v].sorted_reader),
1268 cleanup_exploratory_stats (struct examine *cmd)
1271 for (i = 0; i < cmd->n_iacts; ++i)
1274 const size_t n_cats = categoricals_n_count (cmd->cats, i);
1276 for (v = 0; v < cmd->n_dep_vars; ++v)
1279 for (grp = 0; grp < n_cats; ++grp)
1282 const struct exploratory_stats *es =
1283 categoricals_get_user_data_by_category_real (cmd->cats, i, grp);
1285 struct order_stats *os = &es[v].hinges->parent;
1286 struct statistic *stat = &os->parent;
1287 stat->destroy (stat);
1289 for (q = 0; q < 3; q++)
1291 os = &es[v].quartiles[q]->parent;
1293 stat->destroy (stat);
1296 for (q = 0; q < cmd->n_percentiles; q++)
1298 os = &es[v].percentiles[q]->parent;
1300 stat->destroy (stat);
1303 if (es[v].shapiro_wilk)
1305 stat = &es[v].shapiro_wilk->parent.parent;
1306 stat->destroy (stat);
1309 os = &es[v].trimmed_mean->parent;
1311 stat->destroy (stat);
1313 os = &es[v].np->parent;
1317 stat->destroy (stat);
1320 statistic_destroy (&es[v].histogram->parent);
1321 moments_destroy (es[v].mom);
1323 if (es[v].box_whisker)
1325 stat = &es[v].box_whisker->parent.parent;
1326 stat->destroy (stat);
1329 casereader_destroy (es[v].sorted_reader);
1337 run_examine (struct examine *cmd, struct casereader *input)
1341 struct casereader *reader;
1343 struct payload payload;
1344 payload.create = create_n;
1345 payload.update = update_n;
1346 payload.calculate = calculate_n;
1347 payload.destroy = NULL;
1349 cmd->wv = dict_get_weight (cmd->dict);
1352 = categoricals_create (cmd->iacts, cmd->n_iacts, cmd->wv, cmd->fctr_excl);
1354 categoricals_set_payload (cmd->cats, &payload, cmd, NULL);
1356 if (cmd->id_var == NULL)
1358 struct ccase *c = casereader_peek (input, 0);
1360 cmd->id_idx = case_get_n_values (c);
1361 input = casereader_create_arithmetic_sequence (input, 1.0, 1.0);
1366 for (reader = input;
1367 (c = casereader_read (reader)) != NULL; case_unref (c))
1369 categoricals_update (cmd->cats, c);
1371 casereader_destroy (reader);
1372 categoricals_done (cmd->cats);
1374 for (i = 0; i < cmd->n_iacts; ++i)
1376 summary_report (cmd, i);
1378 const size_t n_cats = categoricals_n_count (cmd->cats, i);
1382 if (cmd->disp_extremes > 0)
1383 extremes_report (cmd, i);
1385 if (cmd->n_percentiles > 0)
1386 percentiles_report (cmd, i);
1388 if (cmd->plot_boxplot)
1390 switch (cmd->boxplot_mode)
1393 show_boxplot_grouped (cmd, i);
1396 show_boxplot_variabled (cmd, i);
1404 if (cmd->plot_histogram)
1405 show_histogram (cmd, i);
1407 if (cmd->plot_npplot)
1408 show_npplot (cmd, i);
1410 if (cmd->plot_spreadlevel)
1411 show_spreadlevel (cmd, i);
1413 if (cmd->descriptives)
1414 descriptives_report (cmd, i);
1416 if (cmd->plot_histogram || cmd->plot_npplot
1417 || cmd->plot_spreadlevel || cmd->plot_boxplot)
1418 normality_report (cmd, i);
1421 cleanup_exploratory_stats (cmd);
1422 categoricals_destroy (cmd->cats);
1426 add_interaction (struct examine *examine, struct interaction *iact,
1427 size_t *allocated_iacts)
1429 if (examine->n_iacts >= *allocated_iacts)
1430 examine->iacts = pool_2nrealloc (examine->pool, examine->iacts,
1431 allocated_iacts, sizeof *examine->iacts);
1432 examine->iacts[examine->n_iacts++] = iact;
1436 cmd_examine (struct lexer *lexer, struct dataset *ds)
1438 bool nototals_seen = false;
1439 bool totals_seen = false;
1441 bool percentiles_seen = false;
1443 size_t allocated_iacts = 0;
1444 struct examine examine = {
1445 .pool = pool_create (),
1446 .dict = dataset_dict (ds),
1449 .pc_alg = PC_HAVERAGE,
1451 .boxplot_mode = BP_GROUPS,
1453 .ex_proto = caseproto_create (),
1456 .fctr_excl = MV_ANY,
1459 /* Allocate space for the first interaction.
1460 This is interaction is an empty one (for the totals).
1461 If no totals are requested, we will simply ignore this
1464 add_interaction (&examine, interaction_create (NULL), &allocated_iacts);
1466 /* Accept an optional, completely pointless "/VARIABLES=" */
1467 lex_match (lexer, T_SLASH);
1468 if (lex_match_id (lexer, "VARIABLES") && !lex_force_match (lexer, T_EQUALS))
1471 if (!parse_variables_const (lexer, examine.dict,
1472 &examine.dep_vars, &examine.n_dep_vars,
1473 PV_NO_DUPLICATE | PV_NUMERIC))
1476 if (lex_match (lexer, T_BY))
1480 struct interaction *iact = parse_interaction (lexer, &examine);
1484 add_interaction (&examine, iact, &allocated_iacts);
1488 int nototals_ofs = 0;
1489 while (lex_token (lexer) != T_ENDCMD)
1491 lex_match (lexer, T_SLASH);
1493 if (lex_match_id (lexer, "STATISTICS"))
1495 lex_match (lexer, T_EQUALS);
1497 while (lex_token (lexer) != T_ENDCMD
1498 && lex_token (lexer) != T_SLASH)
1500 if (lex_match_id (lexer, "DESCRIPTIVES"))
1501 examine.descriptives = true;
1502 else if (lex_match_id (lexer, "EXTREME"))
1505 if (lex_match (lexer, T_LPAREN))
1507 if (!lex_force_int_range (lexer, "EXTREME", 0, INT_MAX))
1509 extr = lex_integer (lexer);
1512 if (!lex_force_match (lexer, T_RPAREN))
1515 examine.disp_extremes = extr;
1517 else if (lex_match_id (lexer, "NONE"))
1520 else if (lex_match (lexer, T_ALL))
1522 if (examine.disp_extremes == 0)
1523 examine.disp_extremes = 5;
1527 lex_error_expecting (lexer, "DESCRIPTIVES", "EXTREME",
1533 else if (lex_match_id (lexer, "PERCENTILES"))
1535 percentiles_seen = true;
1536 if (lex_match (lexer, T_LPAREN))
1538 size_t allocated_percentiles = examine.n_percentiles;
1539 while (lex_is_number (lexer))
1541 if (!lex_force_num_range_open (lexer, "PERCENTILES", 0, 100))
1543 double p = lex_number (lexer);
1545 if (examine.n_percentiles >= allocated_percentiles)
1546 examine.ptiles = x2nrealloc (examine.ptiles,
1547 &allocated_percentiles,
1548 sizeof *examine.ptiles);
1549 examine.ptiles[examine.n_percentiles++] = p;
1552 lex_match (lexer, T_COMMA);
1554 if (!lex_force_match (lexer, T_RPAREN))
1558 lex_match (lexer, T_EQUALS);
1560 while (lex_token (lexer) != T_ENDCMD
1561 && lex_token (lexer) != T_SLASH)
1563 if (lex_match_id (lexer, "HAVERAGE"))
1564 examine.pc_alg = PC_HAVERAGE;
1565 else if (lex_match_id (lexer, "WAVERAGE"))
1566 examine.pc_alg = PC_WAVERAGE;
1567 else if (lex_match_id (lexer, "ROUND"))
1568 examine.pc_alg = PC_ROUND;
1569 else if (lex_match_id (lexer, "EMPIRICAL"))
1570 examine.pc_alg = PC_EMPIRICAL;
1571 else if (lex_match_id (lexer, "AEMPIRICAL"))
1572 examine.pc_alg = PC_AEMPIRICAL;
1573 else if (lex_match_id (lexer, "NONE"))
1574 examine.pc_alg = PC_NONE;
1577 lex_error_expecting (lexer, "HAVERAGE", "WAVERAGE",
1578 "ROUND", "EMPIRICAL", "AEMPIRICAL",
1584 else if (lex_match_id (lexer, "TOTAL"))
1586 else if (lex_match_id (lexer, "NOTOTAL"))
1588 nototals_seen = true;
1589 nototals_ofs = lex_ofs (lexer) - 1;
1591 else if (lex_match_id (lexer, "MISSING"))
1593 lex_match (lexer, T_EQUALS);
1595 while (lex_token (lexer) != T_ENDCMD
1596 && lex_token (lexer) != T_SLASH)
1598 if (lex_match_id (lexer, "LISTWISE"))
1599 examine.missing_pw = false;
1600 else if (lex_match_id (lexer, "PAIRWISE"))
1601 examine.missing_pw = true;
1602 else if (lex_match_id (lexer, "EXCLUDE"))
1603 examine.dep_excl = MV_ANY;
1604 else if (lex_match_id (lexer, "INCLUDE"))
1605 examine.dep_excl = MV_SYSTEM;
1606 else if (lex_match_id (lexer, "REPORT"))
1607 examine.fctr_excl = 0;
1608 else if (lex_match_id (lexer, "NOREPORT"))
1609 examine.fctr_excl = MV_ANY;
1612 lex_error_expecting (lexer, "LISTWISE", "PAIRWISE",
1613 "EXCLUDE", "INCLUDE", "REPORT",
1619 else if (lex_match_id (lexer, "COMPARE"))
1621 lex_match (lexer, T_EQUALS);
1622 if (lex_match_id (lexer, "VARIABLES"))
1623 examine.boxplot_mode = BP_VARIABLES;
1624 else if (lex_match_id (lexer, "GROUPS"))
1625 examine.boxplot_mode = BP_GROUPS;
1628 lex_error_expecting (lexer, "VARIABLES", "GROUPS");
1632 else if (lex_match_id (lexer, "PLOT"))
1634 lex_match (lexer, T_EQUALS);
1636 while (lex_token (lexer) != T_ENDCMD
1637 && lex_token (lexer) != T_SLASH)
1639 if (lex_match_id (lexer, "BOXPLOT"))
1640 examine.plot_boxplot = true;
1641 else if (lex_match_id (lexer, "NPPLOT"))
1642 examine.plot_npplot = true;
1643 else if (lex_match_id (lexer, "HISTOGRAM"))
1644 examine.plot_histogram = true;
1645 else if (lex_match_id (lexer, "SPREADLEVEL"))
1647 examine.plot_spreadlevel = true;
1648 examine.sl_power = 0;
1649 if (lex_match (lexer, T_LPAREN) && lex_force_num (lexer))
1651 examine.sl_power = lex_number (lexer);
1654 if (!lex_force_match (lexer, T_RPAREN))
1658 else if (lex_match_id (lexer, "NONE"))
1659 examine.plot_boxplot = examine.plot_npplot
1660 = examine.plot_histogram = examine.plot_spreadlevel = false;
1661 else if (lex_match (lexer, T_ALL))
1662 examine.plot_boxplot = examine.plot_npplot
1663 = examine.plot_histogram = examine.plot_spreadlevel = true;
1666 lex_error_expecting (lexer, "BOXPLOT", "NPPLOT",
1667 "HISTOGRAM", "SPREADLEVEL",
1671 lex_match (lexer, T_COMMA);
1674 else if (lex_match_id (lexer, "CINTERVAL"))
1676 if (!lex_force_num (lexer))
1679 examine.conf = lex_number (lexer);
1682 else if (lex_match_id (lexer, "ID"))
1684 lex_match (lexer, T_EQUALS);
1686 examine.id_var = parse_variable_const (lexer, examine.dict);
1687 if (!examine.id_var)
1692 lex_error_expecting (lexer, "STATISTICS", "PERCENTILES",
1693 "TOTAL", "NOTOTAL", "MISSING", "COMPARE",
1694 "PLOT", "CINTERVAL", "ID");
1700 if (totals_seen && nototals_seen)
1702 lex_ofs_error (lexer, nototals_ofs, nototals_ofs,
1703 _("%s and %s are mutually exclusive."),
1704 "TOTAL", "NOTOTAL");
1708 /* If totals have been requested or if there are no factors
1709 in this analysis, then the totals need to be included. */
1710 if (nototals_seen && examine.n_iacts > 1)
1712 interaction_destroy (examine.iacts[0]);
1719 examine.id_idx = var_get_case_index (examine.id_var);
1720 examine.id_width = var_get_width (examine.id_var);
1723 examine.ex_proto = caseproto_add_width (examine.ex_proto, 0); /* value */
1724 examine.ex_proto = caseproto_add_width (examine.ex_proto, examine.id_width); /* id */
1725 examine.ex_proto = caseproto_add_width (examine.ex_proto, 0); /* weight */
1727 if (examine.disp_extremes > 0)
1728 examine.calc_extremes = examine.disp_extremes;
1730 if (examine.descriptives && examine.calc_extremes == 0)
1732 /* Descriptives always displays the max and min */
1733 examine.calc_extremes = 1;
1736 if (percentiles_seen && examine.n_percentiles == 0)
1738 examine.n_percentiles = 7;
1739 examine.ptiles = xmalloc (examine.n_percentiles * sizeof *examine.ptiles);
1741 examine.ptiles[0] = 5;
1742 examine.ptiles[1] = 10;
1743 examine.ptiles[2] = 25;
1744 examine.ptiles[3] = 50;
1745 examine.ptiles[4] = 75;
1746 examine.ptiles[5] = 90;
1747 examine.ptiles[6] = 95;
1750 assert (examine.calc_extremes >= examine.disp_extremes);
1752 struct casegrouper *grouper = casegrouper_create_splits (proc_open (ds), examine.dict);
1753 struct casereader *group;
1754 while (casegrouper_get_next_group (grouper, &group))
1755 run_examine (&examine, group);
1756 bool ok = casegrouper_destroy (grouper);
1757 ok = proc_commit (ds) && ok;
1759 caseproto_unref (examine.ex_proto);
1761 for (size_t i = 0; i < examine.n_iacts; ++i)
1762 interaction_destroy (examine.iacts[i]);
1763 free (examine.ptiles);
1764 free (examine.dep_vars);
1765 pool_destroy (examine.pool);
1770 caseproto_unref (examine.ex_proto);
1771 for (size_t i = 0; i < examine.n_iacts; ++i)
1772 interaction_destroy (examine.iacts[i]);
1773 free (examine.dep_vars);
1774 free (examine.ptiles);
1775 pool_destroy (examine.pool);