#undef S
};
+struct ctables_subtable
+ {
+ /* In struct ctables's 'subtables' hmap. Indexed by all the values in all
+ the axes except the innermost row and column variable and the scalar
+ variable, if any. (If the scalar variable is the innermost row or
+ column variable, then the second-to-innermost variable is also omitted
+ along that axis.) */
+ struct hmap_node node;
+
+ const struct ctables_freq *example;
+
+ double valid;
+ double missing;
+ };
+
+struct ctables_layer
+ {
+ /* In struct ctables's 'layers' hmap. Indexed by all the values in the
+ layer axis, except the scalar variable, if any. */
+ struct hmap_node node;
+
+ double valid;
+ double missing;
+ };
+
+struct ctables_freq
+ {
+ /* In struct ctables's 'ft' hmap. Indexed by all the values in all the
+ axes (except the scalar variable, if any). */
+ struct hmap_node node;
+
+ /* The subtable that contains this cell. */
+ struct ctables_subtable *subtable;
+
+ /* The layer that contains this cell. */
+
+ struct
+ {
+ size_t vaa_idx;
+ union value *values;
+ int leaf;
+ }
+ axes[PIVOT_N_AXES];
+
+ union ctables_summary *summaries;
+ };
+
struct ctables
{
struct pivot_table_look *look;
struct variable **vars;
size_t n;
size_t scale_idx;
+ size_t subtable_idx;
struct ctables_summary_spec *summaries;
size_t n_summaries;
struct var_array2 vaas[PIVOT_N_AXES];
enum pivot_axis_type summary_axis;
struct hmap ft;
+ struct hmap subtables;
enum pivot_axis_type slabels_position;
bool slabels_visible;
}
static double
-ctables_summary_value (union ctables_summary *s,
+ctables_summary_value (const struct ctables_freq *f,
+ union ctables_summary *s,
const struct ctables_summary_spec *ss)
{
switch (ss->function)
case CTSF_ECOUNT:
return s->valid;
+ case CTSF_SUBTABLEPCT_COUNT:
+ return f->subtable->valid ? s->valid / f->subtable->valid * 100 : SYSMIS;
+
case CTSF_ROWPCT_COUNT:
case CTSF_COLPCT_COUNT:
case CTSF_TABLEPCT_COUNT:
- case CTSF_SUBTABLEPCT_COUNT:
case CTSF_LAYERPCT_COUNT:
case CTSF_LAYERROWPCT_COUNT:
case CTSF_LAYERCOLPCT_COUNT:
NOT_REACHED ();
}
-struct ctables_freq
- {
- struct hmap_node node; /* Element in hash table. */
-
- struct
- {
- size_t vaa_idx;
- union value *values;
- int leaf;
- }
- axes[PIVOT_N_AXES];
-
- union ctables_summary *summaries;
- };
-
-#if 0
-static struct ctables_freq *
-ctables_freq_create (struct ctables_freqtab *ft)
-{
- struct ctables_freq *f = xmalloc (sizeof *f + ft->vars.n * sizeof *f->values);
- f->summaries = xmalloc (ft->n_summaries * sizeof *f->summaries);
- for (size_t i = 0; i < ft->n_summaries; i++)
- ctables_summary_init (&f->summaries[i], &ft->summaries[i]);
- return f;
-}
-
-static void
-ctables_freq_add (struct ctables_freqtab *ft, struct ctables_freq *f,
- const struct variable *var, const union value *value,
- double weight)
-{
- for (size_t i = 0; i < ft->n_summaries; i++)
- ctables_summary_add (&f->summaries[i], &ft->summaries[i],
- var, value, weight);
-}
-#endif
-
struct ctables_freq_sort_aux
{
const struct ctables_table *t;
Fill the table entry using the indexes from before.
*/
+static struct ctables_subtable *
+ctables_subtable_insert (struct ctables_table *t, struct ctables_freq *f)
+{
+ size_t hash = 0;
+ for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
+ {
+ size_t idx = f->axes[a].vaa_idx;
+ const struct var_array *va = &t->vaas[a].vas[idx];
+ hash = hash_int (idx, hash);
+ for (size_t i = 0; i < va->n; i++)
+ if (i != va->scale_idx && i != va->subtable_idx)
+ hash = value_hash (&f->axes[a].values[i],
+ var_get_width (va->vars[i]), hash);
+ }
+
+ struct ctables_subtable *st;
+ HMAP_FOR_EACH_WITH_HASH (st, struct ctables_subtable, node, hash, &t->subtables)
+ {
+ const struct ctables_freq *stf = st->example;
+ for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
+ {
+ size_t idx = f->axes[a].vaa_idx;
+ if (idx != stf->axes[a].vaa_idx)
+ goto not_equal;
+
+ const struct var_array *va = &t->vaas[a].vas[idx];
+ for (size_t i = 0; i < va->n; i++)
+ if (i != va->scale_idx && i != va->subtable_idx
+ && !value_equal (&stf->axes[a].values[i],
+ &f->axes[a].values[i],
+ var_get_width (va->vars[i])))
+ goto not_equal;
+ }
+
+ return st;
+
+ not_equal: ;
+ }
+
+ st = xmalloc (sizeof *st);
+ *st = (struct ctables_subtable) { .example = f };
+ hmap_insert (&t->subtables, &st->node, hash);
+ return st;
+}
+
static void
ctables_freqtab_insert (struct ctables_table *t,
const struct ccase *c,
f->summaries = xmalloc (ss->n_summaries * sizeof *f->summaries);
for (size_t i = 0; i < ss->n_summaries; i++)
ctables_summary_init (&f->summaries[i], &ss->summaries[i]);
+ f->subtable = ctables_subtable_insert (t, f);
hmap_insert (&t->ft, &f->node, hash);
summarize:
for (size_t i = 0; i < ss->n_summaries; i++)
ctables_summary_add (&f->summaries[i], &ss->summaries[i], ss->summary_var,
case_data (c, ss->summary_var), weight);
+ f->subtable->valid += weight;
}
static bool
struct ctables_table *t = ct->tables[i];
for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
if (t->axes[a])
- t->vaas[a] = enumerate_fts (a, t->axes[a]);
+ {
+ t->vaas[a] = enumerate_fts (a, t->axes[a]);
+ for (size_t j = 0; j < t->vaas[a].n; j++)
+ {
+ struct var_array *va = &t->vaas[a].vas[j];
+ va->subtable_idx = (
+ a == PIVOT_AXIS_LAYER ? SIZE_MAX
+ : va->n == 0 ? SIZE_MAX
+ : va->scale_idx != va->n - 1 ? va->n - 1
+ : va->n == 1 ? SIZE_MAX
+ : va->n - 2);
+ }
+ }
else
{
struct var_array *va = xmalloc (sizeof *va);
dindexes[n_dindexes++] = leaf;
}
- double d = ctables_summary_value (&f->summaries[j], &ss->summaries[j]);
+ double d = ctables_summary_value (f, &f->summaries[j], &ss->summaries[j]);
struct pivot_value *value = pivot_value_new_number (d);
value->numeric.format = ss->summaries[j].format;
pivot_table_put (pt, dindexes, n_dindexes, value);
struct ctables_table *t = xmalloc (sizeof *t);
*t = (struct ctables_table) {
.ft = HMAP_INITIALIZER (t->ft),
+ .subtables = HMAP_INITIALIZER (t->subtables),
.slabels_position = PIVOT_AXIS_COLUMN,
.slabels_visible = true,
.row_labels = CTLP_NORMAL,