Fix subtotal calculations.
[pspp] / src / language / stats / ctables.c
index 4235002c28932deeb3dfe7ea4486d57758dcf4ab..b57f33f5d7ef4a35203433e231d49057820fffb9 100644 (file)
@@ -328,7 +328,7 @@ struct ctables_table
 
     const struct variable *clabels_example;
     struct hmap clabels_values_map;
-    union value *clabels_values;
+    struct ctables_value **clabels_values;
     size_t n_clabels_values;
 
     enum pivot_axis_type slabels_axis;
@@ -1925,7 +1925,8 @@ ctables_summary_add (union ctables_summary *s,
     case CTSF_LAYERPCT_SUM:
     case CTSF_LAYERROWPCT_SUM:
     case CTSF_LAYERCOLPCT_SUM:
-      moments1_add (s->moments, value->f, weight);
+      if (!var_is_value_missing (var, value))
+        moments1_add (s->moments, value->f, weight);
       break;
 
     case CTSF_MEDIAN:
@@ -2566,12 +2567,16 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t)
     pivot_table_set_caption (
       pt, pivot_value_new_user_text (t->corner, SIZE_MAX));
 
-  bool summary_dimension = t->summary_axis != t->slabels_axis;
+  bool summary_dimension = (t->summary_axis != t->slabels_axis
+                            || (!t->slabels_visible
+                                && t->summary_specs.n > 1));
   if (summary_dimension)
     {
       struct pivot_dimension *d = pivot_dimension_create (
-        pt, t->slabels_axis, N_("Summaries"));
+        pt, t->slabels_axis, N_("Statistics"));
       const struct ctables_summary_spec_set *specs = &t->summary_specs;
+      if (!t->slabels_visible)
+        d->hide_all_labels = true;
       for (size_t i = 0; i < specs->n; i++)
         pivot_category_create_leaf (
           d->root, pivot_value_new_text (specs->specs[i].label));
@@ -2589,15 +2594,11 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t)
       const struct ctables_categories *c = t->categories[var_get_dict_index (var)];
       for (size_t i = 0; i < t->n_clabels_values; i++)
         {
-          const union value *value = &t->clabels_values[i];
-          const struct ctables_category *cat = ctables_categories_match (c, value, var);
-          if (!cat)
-            {
-              pivot_category_create_leaf (d->root, pivot_value_new_integer (value->f)); /* XXX */
-              continue;
-            }
+          const struct ctables_value *value = t->clabels_values[i];
+          const struct ctables_category *cat = ctables_categories_match (c, &value->value, var);
+          assert (cat != NULL);
           pivot_category_create_leaf (d->root, ctables_category_create_label (
-                                        cat, t->clabels_example, value));
+                                        cat, t->clabels_example, &value->value));
         }
     }
 
@@ -2682,13 +2683,11 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t)
           if (new_subtable)
             {
               n_levels = 0;
-              printf ("%s levels:", pivot_axis_type_to_string (a));
               for (size_t k = 0; k < nest->n; k++)
                 {
                   enum ctables_vlabel vlabel = ct->vlabels[var_get_dict_index (nest->vars[k])];
                   if (vlabel != CTVL_NONE)
                     {
-                      printf (" var(%s)", var_get_name (nest->vars[k]));
                       levels[n_levels++] = (struct ctables_level) {
                         .type = CTL_VAR,
                         .var_idx = k,
@@ -2698,7 +2697,6 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t)
                   if (nest->scale_idx != k
                       && (k != nest->n - 1 || t->label_axis[a] == a))
                     {
-                      printf (" category(%s)", var_get_name (nest->vars[k]));
                       levels[n_levels++] = (struct ctables_level) {
                         .type = CTL_CATEGORY,
                         .var_idx = k,
@@ -2706,15 +2704,13 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t)
                     }
                 }
 
-              if (a == t->slabels_axis && a == t->summary_axis)
+              if (!summary_dimension && a == t->slabels_axis)
                 {
-                  printf (" summary");
                   levels[n_levels++] = (struct ctables_level) {
                     .type = CTL_SUMMARY,
                     .var_idx = SIZE_MAX,
                   };
                 }
-              printf ("\n");
             }
 
           size_t n_common = 0;
@@ -2726,17 +2722,16 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t)
                   if (level->type == CTL_CATEGORY)
                     {
                       size_t var_idx = level->var_idx;
-                      if (prev->axes[a].cvs[var_idx].category
-                          != cell->axes[a].cvs[var_idx].category)
-                        {
-                          break;
-                        }
-                      else if (!value_equal (&prev->axes[a].cvs[var_idx].value,
-                                           &cell->axes[a].cvs[var_idx].value,
-                                             var_get_type (nest->vars[var_idx])))
-                        {
-                          break;
-                        }
+                      const struct ctables_category *c = cell->axes[a].cvs[var_idx].category;
+                      if (prev->axes[a].cvs[var_idx].category != c)
+                        break;
+                      else if (c->type != CCT_SUBTOTAL
+                               && c->type != CCT_HSUBTOTAL
+                               && c->type != CCT_TOTAL
+                               && !value_equal (&prev->axes[a].cvs[var_idx].value,
+                                                &cell->axes[a].cvs[var_idx].value,
+                                                var_get_type (nest->vars[var_idx])))
+                        break;
                     }
                 }
             }
@@ -2806,10 +2801,8 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t)
               const struct variable *var = clabels_nest->vars[clabels_nest->n - 1];
               const union value *value = &cell->axes[t->clabels_from_axis].cvs[clabels_nest->n - 1].value;
               const struct ctables_value *ctv = ctables_value_find (t, value, var_get_width (var));
-
-              printf ("leaf=%d\n", ctv ? ctv->leaf : 0);
-              dindexes[n_dindexes++] = ctv ? ctv->leaf : 0; /* XXX */
-              //dindexes[n_dindexes++] = 0;
+              assert (ctv != NULL);
+              dindexes[n_dindexes++] = ctv->leaf;
             }
 
           for (enum pivot_axis_type a = 0; a < PIVOT_N_AXES; a++)
@@ -3085,9 +3078,17 @@ ctables_insert_clabels_values (struct ctables_table *t, const struct ccase *c,
   for (size_t i = 0; i < stack->n; i++)
     {
       const struct ctables_nest *nest = &stack->nests[i];
-      const struct variable *v = nest->vars[nest->n - 1];
-      int width = var_get_width (v);
-      const union value *value = case_data (c, v);
+      const struct variable *var = nest->vars[nest->n - 1];
+      int width = var_get_width (var);
+      const union value *value = case_data (c, var);
+
+      if (var_is_numeric (var) && value->f == SYSMIS)
+        continue;
+
+      if (!ctables_categories_match (t->categories [var_get_dict_index (var)],
+                                     value, var))
+        continue;
+
       unsigned int hash = value_hash (value, width, 0);
 
       struct ctables_value *clv = ctables_value_find__ (t, value, width, hash);
@@ -3103,10 +3104,12 @@ ctables_insert_clabels_values (struct ctables_table *t, const struct ccase *c,
 static int
 compare_clabels_values_3way (const void *a_, const void *b_, const void *width_)
 {
-  const union value *a = a_;
-  const union value *b = b_;
+  const struct ctables_value *const *ap = a_;
+  const struct ctables_value *const *bp = b_;
+  const struct ctables_value *a = *ap;
+  const struct ctables_value *b = *bp;
   const int *width = width_;
-  return value_compare_3way (a, b, *width);
+  return value_compare_3way (&a->value, &b->value, *width);
 }
 
 static void
@@ -3120,16 +3123,15 @@ ctables_sort_clabels_values (struct ctables_table *t)
   struct ctables_value *clv;
   size_t i = 0;
   HMAP_FOR_EACH (clv, struct ctables_value, node, &t->clabels_values_map)
-    {
-      clv->leaf = i;
-      t->clabels_values[i] = clv->value;
-      i++;
-    }
+    t->clabels_values[i++] = clv;
   t->n_clabels_values = n;
   assert (i == n);
 
   sort (t->clabels_values, n, sizeof *t->clabels_values,
         compare_clabels_values_3way, &width);
+
+  for (size_t i = 0; i < n; i++)
+    t->clabels_values[i]->leaf = i;
 }
 
 static bool