CTABLES fixes for totals.
[pspp] / src / language / stats / ctables.c
index 92e7a55fa5cda8763f28762424b768a5da22656c..d3a00312a93a670f8d0159363f567ca73e0b39d9 100644 (file)
@@ -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