From 1b9ed07d1681f7744552a9e32e8136cffc2ae344 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sat, 2 Jul 2022 17:24:37 -0700 Subject: [PATCH] CTABLES fixes for totals. --- src/language/stats/ctables.c | 121 ++++++++++++++++----- tests/language/stats/ctables.at | 184 +++++++++++++++++++++++++++++++- 2 files changed, 273 insertions(+), 32 deletions(-) diff --git a/src/language/stats/ctables.c b/src/language/stats/ctables.c index 92e7a55fa5..d3a00312a9 100644 --- a/src/language/stats/ctables.c +++ b/src/language/stats/ctables.c @@ -201,7 +201,7 @@ struct ctables_cell struct hmap_node node; /* The domains that contain this cell. */ - bool contributes_to_domains; + uint32_t omit_domains; struct ctables_domain *domains[N_CTDTS]; bool hide; @@ -222,6 +222,8 @@ struct ctables_cell axes[PIVOT_N_AXES]; union ctables_summary *summaries; + + //char *name; }; struct ctables @@ -2705,8 +2707,13 @@ ctables_domain_insert (struct ctables_section *s, struct ctables_cell *cell, for (size_t i = 0; i < nest->n_domains[domain]; i++) { size_t v_idx = nest->domains[domain][i]; - hash = value_hash (&cell->axes[a].cvs[v_idx].value, - var_get_width (nest->vars[v_idx]), hash); + struct ctables_cell_value *cv = &cell->axes[a].cvs[v_idx]; + hash = hash_pointer (cv->category, hash); + if (cv->category->type != CCT_TOTAL + && cv->category->type != CCT_SUBTOTAL + && cv->category->type != CCT_POSTCOMPUTE) + hash = value_hash (&cv->value, + var_get_width (nest->vars[v_idx]), hash); } } @@ -2720,9 +2727,14 @@ ctables_domain_insert (struct ctables_section *s, struct ctables_cell *cell, for (size_t i = 0; i < nest->n_domains[domain]; i++) { size_t v_idx = nest->domains[domain][i]; - if (!value_equal (&df->axes[a].cvs[v_idx].value, - &cell->axes[a].cvs[v_idx].value, - var_get_width (nest->vars[v_idx]))) + struct ctables_cell_value *cv1 = &df->axes[a].cvs[v_idx]; + struct ctables_cell_value *cv2 = &cell->axes[a].cvs[v_idx]; + if (cv1->category != cv2->category + || (cv1->category->type != CCT_TOTAL + && cv1->category->type != CCT_SUBTOTAL + && cv1->category->type != CCT_POSTCOMPUTE + && !value_equal (&cv1->value, &cv2->value, + var_get_width (nest->vars[v_idx])))) goto not_equal; } } @@ -2854,14 +2866,15 @@ ctables_cell_insert__ (struct ctables_section *s, const struct ccase *c, cell = xmalloc (sizeof *cell); cell->hide = false; cell->sv = sv; - cell->contributes_to_domains = true; + cell->omit_domains = 0; cell->postcompute = false; + //struct string name = DS_EMPTY_INITIALIZER; for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++) { const struct ctables_nest *nest = s->nests[a]; cell->axes[a].cvs = (nest->n - ? xnmalloc (nest->n, sizeof *cell->axes[a].cvs) - : NULL); + ? xnmalloc (nest->n, sizeof *cell->axes[a].cvs) + : NULL); for (size_t i = 0; i < nest->n; i++) { const struct ctables_category *cat = cats[a][i]; @@ -2876,15 +2889,59 @@ ctables_cell_insert__ (struct ctables_section *s, const struct ccase *c, if (cat->type == CCT_TOTAL || cat->type == CCT_SUBTOTAL || cat->type == CCT_POSTCOMPUTE) - cell->contributes_to_domains = false; + { + /* XXX these should be more encompassing I think.*/ + + switch (a) + { + case PIVOT_AXIS_COLUMN: + cell->omit_domains |= ((1u << CTDT_TABLE) | + (1u << CTDT_LAYER) | + (1u << CTDT_LAYERCOL) | + (1u << CTDT_SUBTABLE) | + (1u << CTDT_COL)); + break; + case PIVOT_AXIS_ROW: + cell->omit_domains |= ((1u << CTDT_TABLE) | + (1u << CTDT_LAYER) | + (1u << CTDT_LAYERROW) | + (1u << CTDT_SUBTABLE) | + (1u << CTDT_ROW)); + break; + case PIVOT_AXIS_LAYER: + cell->omit_domains |= ((1u << CTDT_TABLE) | + (1u << CTDT_LAYER)); + break; + } + } if (cat->type == CCT_POSTCOMPUTE) cell->postcompute = true; } cell->axes[a].cvs[i].category = cat; value_clone (&cell->axes[a].cvs[i].value, value, var_get_width (var)); + +#if 0 + if (i != nest->scale_idx) + { + if (!ds_is_empty (&name)) + ds_put_cstr (&name, ", "); + char *value_s = data_out (value, var_get_encoding (var), + var_get_print_format (var), + settings_get_fmt_settings ()); + if (cat->type == CCT_TOTAL + || cat->type == CCT_SUBTOTAL + || cat->type == CCT_POSTCOMPUTE) + ds_put_format (&name, "%s=total", var_get_name (var)); + else + ds_put_format (&name, "%s=%s", var_get_name (var), + value_s + strspn (value_s, " ")); + free (value_s); + } +#endif } } + //cell->name = ds_steal_cstr (&name); const struct ctables_nest *ss = s->nests[s->table->summary_axis]; const struct ctables_summary_spec_set *specs = &ss->specs[cell->sv]; @@ -2911,25 +2968,23 @@ ctables_cell_add__ (struct ctables_section *s, const struct ccase *c, ctables_summary_add (&cell->summaries[i], &specs->specs[i], specs->var, case_data (c, specs->var), specs->is_scale, is_missing, excluded_missing, d_weight, e_weight); - if (cell->contributes_to_domains) - { - for (enum ctables_domain_type dt = 0; dt < N_CTDTS; dt++) - { - struct ctables_domain *d = cell->domains[dt]; - d->d_total += d_weight; - d->e_total += e_weight; - if (!excluded_missing) - { - d->d_count += d_weight; - d->e_count += e_weight; - } - if (!is_missing) - { - d->d_valid += d_weight; - d->e_valid += e_weight; - } - } - } + for (enum ctables_domain_type dt = 0; dt < N_CTDTS; dt++) + if (!(cell->omit_domains && (1u << dt))) + { + struct ctables_domain *d = cell->domains[dt]; + d->d_total += d_weight; + d->e_total += e_weight; + if (!excluded_missing) + { + d->d_count += d_weight; + d->e_count += e_weight; + } + if (!is_missing) + { + d->d_valid += d_weight; + d->e_valid += e_weight; + } + } } static void @@ -3522,6 +3577,14 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t) struct ctables_cell_sort_aux aux = { .nest = nest, .a = a }; sort (sorted, n_sorted, sizeof *sorted, ctables_cell_compare_3way, &aux); +#if 0 + for (size_t j = 0; j < n_sorted; j++) + { + printf ("%s (%s): %f/%f = %.1f%%\n", sorted[j]->name, sorted[j]->contributes_to_domains ? "y" : "n", sorted[j]->summaries[0].count, sorted[j]->domains[CTDT_COL]->e_count, sorted[j]->summaries[0].count / sorted[j]->domains[CTDT_COL]->e_count * 100.0); + } + printf ("\n"); +#endif + struct ctables_level { enum ctables_level_type diff --git a/tests/language/stats/ctables.at b/tests/language/stats/ctables.at index 49525da66f..e91301a0a5 100644 --- a/tests/language/stats/ctables.at +++ b/tests/language/stats/ctables.at @@ -987,9 +987,16 @@ CTABLES /TABLE x[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, TOTALS[COUNT, COLP /CATEGORIES VARIABLES=ALL TOTAL=YES. CTABLES /TABLE x[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, TOTALS[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, VALIDN, TOTALN]] /CATEGORIES VARIABLES=ALL TOTAL=YES MISSING=INCLUDE. -*CTABLES /TABLE x BY y. -*CTABLES /TABLE x BY y /CATEGORIES VARIABLES=ALL MISSING=INCLUDE. -*CTABLES /TABLE y BY x /CATEGORIES VARIABLES=ALL MISSING=INCLUDE. +CTABLES /TABLE x BY y[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, ROWPCT, ROWPCT.VALIDN, ROWPCT.TOTALN, TOTALS[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, ROWPCT, ROWPCT.VALIDN, ROWPCT.TOTALN, VALIDN, TOTALN]] + /CATEGORIES VARIABLES=ALL TOTAL=YES + /SLABELS POSITION=ROW. +CTABLES /TABLE x BY y[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, ROWPCT, ROWPCT.VALIDN, ROWPCT.TOTALN, TOTALS[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, ROWPCT, ROWPCT.VALIDN, ROWPCT.TOTALN, VALIDN, TOTALN]] + /CATEGORIES VARIABLES=ALL TOTAL=YES MISSING=INCLUDE + /SLABELS POSITION=ROW. +CTABLES /TABLE x BY y[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, ROWPCT, ROWPCT.VALIDN, ROWPCT.TOTALN, TOTALS[COUNT, COLPCT, COLPCT.VALIDN, COLPCT.TOTALN, ROWPCT, ROWPCT.VALIDN, ROWPCT.TOTALN, VALIDN, TOTALN]] + /CATEGORIES VARIABLES=x [1, 2, 3, 4] TOTAL=YES + /CATEGORIES VARIABLES=y [1, 3, 4, 5] TOTAL=YES + /SLABELS POSITION=ROW. ]]) AT_CHECK([pspp ctables.sps -O box=unicode -O width=120], [0], [dnl Custom Tables @@ -1019,5 +1026,176 @@ dnl is expected behavior. dnl Note that Column Total N % doesn't add up to 100 because system-missing dnl values are included in the total but not shown as a category and this dnl is expected behavior. + + Custom Tables +╭────────────────────────┬───────────────────────────╮ +│ │ y │ +│ ├──────┬──────┬──────┬──────┤ +│ │ 1.00 │ 4.00 │ 5.00 │ Total│ +├────────────────────────┼──────┼──────┼──────┼──────┤ +│x 3.00 Count │ 1│ 1│ 1│ 3│ +│ Column % │ 33.3%│ 33.3%│ 33.3%│ .│ +│ Column Valid N %│ 33.3%│ 33.3%│ 33.3%│ .│ +│ Column Total N %│ 16.7%│ 16.7%│ 16.7%│ .│ +│ Row % │ 33.3%│ 33.3%│ 33.3%│100.0%│ +│ Row Valid N % │ 33.3%│ 33.3%│ 33.3%│100.0%│ +│ Row Total N % │ 16.7%│ 16.7%│ 16.7%│100.0%│ +│ Valid N │ │ │ │ 3│ +│ Total N │ │ │ │ 6│ +│ ╶──────────────────────┼──────┼──────┼──────┼──────┤ +│ 4.00 Count │ 1│ 1│ 1│ 3│ +│ Column % │ 33.3%│ 33.3%│ 33.3%│ .│ +│ Column Valid N %│ 33.3%│ 33.3%│ 33.3%│ .│ +│ Column Total N %│ 16.7%│ 16.7%│ 16.7%│ .│ +│ Row % │ 33.3%│ 33.3%│ 33.3%│100.0%│ +│ Row Valid N % │ 33.3%│ 33.3%│ 33.3%│100.0%│ +│ Row Total N % │ 16.7%│ 16.7%│ 16.7%│100.0%│ +│ Valid N │ │ │ │ 3│ +│ Total N │ │ │ │ 6│ +│ ╶──────────────────────┼──────┼──────┼──────┼──────┤ +│ 5.00 Count │ 1│ 1│ 1│ 3│ +│ Column % │ 33.3%│ 33.3%│ 33.3%│ .│ +│ Column Valid N %│ 33.3%│ 33.3%│ 33.3%│ .│ +│ Column Total N %│ 16.7%│ 16.7%│ 16.7%│ .│ +│ Row % │ 33.3%│ 33.3%│ 33.3%│100.0%│ +│ Row Valid N % │ 33.3%│ 33.3%│ 33.3%│100.0%│ +│ Row Total N % │ 16.7%│ 16.7%│ 16.7%│100.0%│ +│ Valid N │ │ │ │ 3│ +│ Total N │ │ │ │ 6│ +│ ╶──────────────────────┼──────┼──────┼──────┼──────┤ +│ Total Count │ 3│ 3│ 3│ 9│ +│ Column % │100.0%│100.0%│100.0%│ .│ +│ Column Valid N %│100.0%│100.0%│100.0%│ .│ +│ Column Total N %│100.0%│100.0%│100.0%│ .│ +│ Row % │ .│ .│ .│ .│ +│ Row Valid N % │ .│ .│ .│ .│ +│ Row Total N % │ .│ .│ .│ .│ +│ Valid N │ 3│ 3│ 3│ 9│ +│ Total N │ 6│ 6│ 6│ 36│ +╰────────────────────────┴──────┴──────┴──────┴──────╯ + + Custom Tables +╭────────────────────────┬─────────────────────────────────────────╮ +│ │ y │ +│ ├──────┬──────┬──────┬──────┬──────┬──────┤ +│ │ 1.00 │ 2.00 │ 3.00 │ 4.00 │ 5.00 │ Total│ +├────────────────────────┼──────┼──────┼──────┼──────┼──────┼──────┤ +│x 1.00 Count │ 1│ 1│ 1│ 1│ 1│ 5│ +│ Column % │ 20.0%│ 20.0%│ 20.0%│ 20.0%│ 20.0%│ .│ +│ Column Valid N %│ .0%│ .│ .│ .0%│ .0%│ .│ +│ Column Total N %│ 16.7%│ 16.7%│ 16.7%│ 16.7%│ 16.7%│ .│ +│ Row % │ 20.0%│ 20.0%│ 20.0%│ 20.0%│ 20.0%│100.0%│ +│ Row Valid N % │ .│ .│ .│ .│ .│ .│ +│ Row Total N % │ 16.7%│ 16.7%│ 16.7%│ 16.7%│ 16.7%│100.0%│ +│ Valid N │ │ │ │ │ │ 0│ +│ Total N │ │ │ │ │ │ 6│ +│ ╶──────────────────────┼──────┼──────┼──────┼──────┼──────┼──────┤ +│ 2.00 Count │ 1│ 1│ 1│ 1│ 1│ 5│ +│ Column % │ 20.0%│ 20.0%│ 20.0%│ 20.0%│ 20.0%│ .│ +│ Column Valid N %│ .0%│ .│ .│ .0%│ .0%│ .│ +│ Column Total N %│ 16.7%│ 16.7%│ 16.7%│ 16.7%│ 16.7%│ .│ +│ Row % │ 20.0%│ 20.0%│ 20.0%│ 20.0%│ 20.0%│100.0%│ +│ Row Valid N % │ .│ .│ .│ .│ .│ .│ +│ Row Total N % │ 16.7%│ 16.7%│ 16.7%│ 16.7%│ 16.7%│100.0%│ +│ Valid N │ │ │ │ │ │ 0│ +│ Total N │ │ │ │ │ │ 6│ +│ ╶──────────────────────┼──────┼──────┼──────┼──────┼──────┼──────┤ +│ 3.00 Count │ 1│ 1│ 1│ 1│ 1│ 5│ +│ Column % │ 20.0%│ 20.0%│ 20.0%│ 20.0%│ 20.0%│ .│ +│ Column Valid N %│ 33.3%│ .│ .│ 33.3%│ 33.3%│ .│ +│ Column Total N %│ 16.7%│ 16.7%│ 16.7%│ 16.7%│ 16.7%│ .│ +│ Row % │ 20.0%│ 20.0%│ 20.0%│ 20.0%│ 20.0%│100.0%│ +│ Row Valid N % │ 33.3%│ .0%│ .0%│ 33.3%│ 33.3%│100.0%│ +│ Row Total N % │ 16.7%│ 16.7%│ 16.7%│ 16.7%│ 16.7%│100.0%│ +│ Valid N │ │ │ │ │ │ 3│ +│ Total N │ │ │ │ │ │ 6│ +│ ╶──────────────────────┼──────┼──────┼──────┼──────┼──────┼──────┤ +│ 4.00 Count │ 1│ 1│ 1│ 1│ 1│ 5│ +│ Column % │ 20.0%│ 20.0%│ 20.0%│ 20.0%│ 20.0%│ .│ +│ Column Valid N %│ 33.3%│ .│ .│ 33.3%│ 33.3%│ .│ +│ Column Total N %│ 16.7%│ 16.7%│ 16.7%│ 16.7%│ 16.7%│ .│ +│ Row % │ 20.0%│ 20.0%│ 20.0%│ 20.0%│ 20.0%│100.0%│ +│ Row Valid N % │ 33.3%│ .0%│ .0%│ 33.3%│ 33.3%│100.0%│ +│ Row Total N % │ 16.7%│ 16.7%│ 16.7%│ 16.7%│ 16.7%│100.0%│ +│ Valid N │ │ │ │ │ │ 3│ +│ Total N │ │ │ │ │ │ 6│ +│ ╶──────────────────────┼──────┼──────┼──────┼──────┼──────┼──────┤ +│ 5.00 Count │ 1│ 1│ 1│ 1│ 1│ 5│ +│ Column % │ 20.0%│ 20.0%│ 20.0%│ 20.0%│ 20.0%│ .│ +│ Column Valid N %│ 33.3%│ .│ .│ 33.3%│ 33.3%│ .│ +│ Column Total N %│ 16.7%│ 16.7%│ 16.7%│ 16.7%│ 16.7%│ .│ +│ Row % │ 20.0%│ 20.0%│ 20.0%│ 20.0%│ 20.0%│100.0%│ +│ Row Valid N % │ 33.3%│ .0%│ .0%│ 33.3%│ 33.3%│100.0%│ +│ Row Total N % │ 16.7%│ 16.7%│ 16.7%│ 16.7%│ 16.7%│100.0%│ +│ Valid N │ │ │ │ │ │ 3│ +│ Total N │ │ │ │ │ │ 6│ +│ ╶──────────────────────┼──────┼──────┼──────┼──────┼──────┼──────┤ +│ Total Count │ 5│ 5│ 5│ 5│ 5│ 25│ +│ Column % │100.0%│100.0%│100.0%│100.0%│100.0%│ .│ +│ Column Valid N %│100.0%│ .│ .│100.0%│100.0%│ .│ +│ Column Total N %│100.0%│100.0%│100.0%│100.0%│100.0%│ .│ +│ Row % │ .│ .│ .│ .│ .│ .│ +│ Row Valid N % │ .│ .│ .│ .│ .│ .│ +│ Row Total N % │ .│ .│ .│ .│ .│ .│ +│ Valid N │ 3│ 0│ 0│ 3│ 3│ 9│ +│ Total N │ 6│ 6│ 6│ 6│ 6│ 36│ +╰────────────────────────┴──────┴──────┴──────┴──────┴──────┴──────╯ + + Custom Tables +╭────────────────────────┬──────────────────────────────────╮ +│ │ y │ +│ ├──────┬──────┬──────┬──────┬──────┤ +│ │ 1.00 │ 3.00 │ 4.00 │ 5.00 │ Total│ +├────────────────────────┼──────┼──────┼──────┼──────┼──────┤ +│x 1.00 Count │ 1│ 1│ 1│ 1│ 4│ +│ Column % │ 25.0%│ 25.0%│ 25.0%│ 25.0%│ .│ +│ Column Valid N %│ .0%│ .│ .0%│ .0%│ .│ +│ Column Total N %│ 20.0%│ 20.0%│ 20.0%│ 20.0%│ .│ +│ Row % │ 25.0%│ 25.0%│ 25.0%│ 25.0%│100.0%│ +│ Row Valid N % │ .│ .│ .│ .│ .│ +│ Row Total N % │ 16.7%│ 16.7%│ 16.7%│ 16.7%│100.0%│ +│ Valid N │ │ │ │ │ 0│ +│ Total N │ │ │ │ │ 6│ +│ ╶──────────────────────┼──────┼──────┼──────┼──────┼──────┤ +│ 2.00 Count │ 1│ 1│ 1│ 1│ 4│ +│ Column % │ 25.0%│ 25.0%│ 25.0%│ 25.0%│ .│ +│ Column Valid N %│ .0%│ .│ .0%│ .0%│ .│ +│ Column Total N %│ 20.0%│ 20.0%│ 20.0%│ 20.0%│ .│ +│ Row % │ 25.0%│ 25.0%│ 25.0%│ 25.0%│100.0%│ +│ Row Valid N % │ .│ .│ .│ .│ .│ +│ Row Total N % │ 16.7%│ 16.7%│ 16.7%│ 16.7%│100.0%│ +│ Valid N │ │ │ │ │ 0│ +│ Total N │ │ │ │ │ 6│ +│ ╶──────────────────────┼──────┼──────┼──────┼──────┼──────┤ +│ 3.00 Count │ 1│ 1│ 1│ 1│ 4│ +│ Column % │ 25.0%│ 25.0%│ 25.0%│ 25.0%│ .│ +│ Column Valid N %│ 50.0%│ .│ 50.0%│ 50.0%│ .│ +│ Column Total N %│ 20.0%│ 20.0%│ 20.0%│ 20.0%│ .│ +│ Row % │ 25.0%│ 25.0%│ 25.0%│ 25.0%│100.0%│ +│ Row Valid N % │ 33.3%│ .0%│ 33.3%│ 33.3%│100.0%│ +│ Row Total N % │ 16.7%│ 16.7%│ 16.7%│ 16.7%│100.0%│ +│ Valid N │ │ │ │ │ 3│ +│ Total N │ │ │ │ │ 6│ +│ ╶──────────────────────┼──────┼──────┼──────┼──────┼──────┤ +│ 4.00 Count │ 1│ 1│ 1│ 1│ 4│ +│ Column % │ 25.0%│ 25.0%│ 25.0%│ 25.0%│ .│ +│ Column Valid N %│ 50.0%│ .│ 50.0%│ 50.0%│ .│ +│ Column Total N %│ 20.0%│ 20.0%│ 20.0%│ 20.0%│ .│ +│ Row % │ 25.0%│ 25.0%│ 25.0%│ 25.0%│100.0%│ +│ Row Valid N % │ 33.3%│ .0%│ 33.3%│ 33.3%│100.0%│ +│ Row Total N % │ 16.7%│ 16.7%│ 16.7%│ 16.7%│100.0%│ +│ Valid N │ │ │ │ │ 3│ +│ Total N │ │ │ │ │ 6│ +│ ╶──────────────────────┼──────┼──────┼──────┼──────┼──────┤ +│ Total Count │ 4│ 4│ 4│ 4│ 16│ +│ Column % │100.0%│100.0%│100.0%│100.0%│ .│ +│ Column Valid N %│100.0%│ .│100.0%│100.0%│ .│ +│ Column Total N %│100.0%│100.0%│100.0%│100.0%│ .│ +│ Row % │ .│ .│ .│ .│ .│ +│ Row Valid N % │ .│ .│ .│ .│ .│ +│ Row Total N % │ .│ .│ .│ .│ .│ +│ Valid N │ 2│ 0│ 2│ 2│ 6│ +│ Total N │ 5│ 5│ 5│ 5│ 30│ +╰────────────────────────┴──────┴──────┴──────┴──────┴──────╯ ]) AT_CLEANUP \ No newline at end of file -- 2.30.2