freqtabs are per-table
authorBen Pfaff <blp@cs.stanford.edu>
Thu, 30 Dec 2021 19:47:17 +0000 (11:47 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Thu, 13 Jan 2022 05:52:26 +0000 (21:52 -0800)
src/language/stats/ctables.c

index 268a44692e8f1ca1256441263594734daa734bff..dc761ade728e85235f89953dcd6d093303cdffec 100644 (file)
@@ -256,6 +256,9 @@ struct ctables_table
 
     struct ctables_chisq *chisq;
     struct ctables_pairwise *pairwise;
+
+    struct ctables_freqtab **fts;
+    size_t n_fts;
   };
 
 struct ctables_var
@@ -1379,11 +1382,10 @@ compare_freq_3way (const void *a_, const void *b_, const void *vars_)
 static bool
 ctables_execute (struct dataset *ds, struct ctables *ct)
 {
-  struct ctables_freqtab **fts = NULL;
-  size_t n_fts = 0;
-  size_t allocated_fts = 0;
   for (size_t i = 0; i < ct->n_tables; i++)
     {
+      size_t allocated_fts = 0;
+
       struct ctables_table *t = &ct->tables[i];
       struct var_array2 vaa = enumerate_fts (t->axes[PIVOT_AXIS_ROW]);
       vaa = nest_fts (vaa, enumerate_fts (t->axes[PIVOT_AXIS_COLUMN]));
@@ -1401,15 +1403,15 @@ ctables_execute (struct dataset *ds, struct ctables *ct)
 
       for (size_t j = 0; j < vaa.n; j++)
         {
-          if (n_fts >= allocated_fts)
-            fts = x2nrealloc (fts, &allocated_fts, sizeof *fts);
-
           struct ctables_freqtab *ft = xmalloc (sizeof *ft);
           *ft = (struct ctables_freqtab) {
             .vars = vaa.vas[j],
             .data = HMAP_INITIALIZER (ft->data),
           };
-          fts[n_fts++] = ft;
+
+          if (t->n_fts >= allocated_fts)
+            t->fts = x2nrealloc (t->fts, &allocated_fts, sizeof *t->fts);
+          t->fts[t->n_fts++] = ft;
         }
 
       free (vaa.vas);
@@ -1424,83 +1426,99 @@ ctables_execute (struct dataset *ds, struct ctables *ct)
     {
       double weight = dict_get_case_weight (dataset_dict (ds), c,
                                             &warn_on_invalid);
-      for (size_t i = 0; i < n_fts; i++)
-        {
-          struct ctables_freqtab *ft = fts[i];
 
-          size_t hash = 0;
+      for (size_t i = 0; i < ct->n_tables; i++)
+        {
+          struct ctables_table *t = &ct->tables[i];
 
-          for (size_t j = 0; j < ft->vars.n; j++)
+          for (size_t j = 0; j < t->n_fts; j++)
             {
-              const struct variable *var = ft->vars.vars[j];
-              hash = value_hash (case_data (c, var), var_get_width (var), hash);
-            }
+              struct ctables_freqtab *ft = t->fts[j];
 
-          struct freq *f;
-          HMAP_FOR_EACH_WITH_HASH (f, struct freq, node, hash, &ft->data)
-            {
-              for (size_t j = 0; j < ft->vars.n; j++)
+              size_t hash = 0;
+
+              for (size_t k = 0; k < ft->vars.n; k++)
                 {
-                  const struct variable *var = ft->vars.vars[j];
-                  if (!value_equal (case_data (c, var), &f->values[j],
-                                    var_get_width (var)))
-                    goto next_hash_node;
+                  const struct variable *var = ft->vars.vars[k];
+                  hash = value_hash (case_data (c, var), var_get_width (var), hash);
                 }
 
-              f->count += weight;
-              goto next_ft;
+              struct freq *f;
+              HMAP_FOR_EACH_WITH_HASH (f, struct freq, node, hash, &ft->data)
+                {
+                  for (size_t k = 0; k < ft->vars.n; k++)
+                    {
+                      const struct variable *var = ft->vars.vars[k];
+                      if (!value_equal (case_data (c, var), &f->values[k],
+                                        var_get_width (var)))
+                        goto next_hash_node;
+                    }
 
-            next_hash_node: ;
-            }
+                  f->count += weight;
+                  goto next_ft;
 
-        f = xmalloc (table_entry_size (ft->vars.n));
-        f->count = weight;
-        for (size_t j = 0; j < ft->vars.n; j++)
-          {
-            const struct variable *var = ft->vars.vars[j];
-            value_clone (&f->values[j], case_data (c, var),
-                         var_get_width (var));
-          }
-        hmap_insert (&ft->data, &f->node, hash);
+                next_hash_node: ;
+                }
 
-        next_ft: ;
+              f = xmalloc (table_entry_size (ft->vars.n));
+              f->count = weight;
+              for (size_t k = 0; k < ft->vars.n; k++)
+                {
+                  const struct variable *var = ft->vars.vars[k];
+                  value_clone (&f->values[k], case_data (c, var),
+                               var_get_width (var));
+                }
+              hmap_insert (&ft->data, &f->node, hash);
+
+            next_ft: ;
+            }
         }
     }
   casereader_destroy (input);
 
-  for (size_t i = 0; i < n_fts; i++)
+  for (size_t i = 0; i < ct->n_tables; i++)
     {
-      struct ctables_freqtab *ft = fts[i];
-      ft->sorted = xnmalloc (ft->data.count, sizeof *ft->sorted);
-
-      struct freq *f;
-      size_t n = 0;
-      HMAP_FOR_EACH (f, struct freq, node, &ft->data)
-        ft->sorted[n++] = f;
-      sort (ft->sorted, ft->data.count, sizeof *ft->sorted,
-            compare_freq_3way, &ft->vars);
+      struct ctables_table *t = &ct->tables[i];
+
+      for (size_t j = 0; j < t->n_fts; j++)
+        {
+          struct ctables_freqtab *ft = t->fts[j];
+          ft->sorted = xnmalloc (ft->data.count, sizeof *ft->sorted);
+
+          struct freq *f;
+          size_t n = 0;
+          HMAP_FOR_EACH (f, struct freq, node, &ft->data)
+            ft->sorted[n++] = f;
+          sort (ft->sorted, ft->data.count, sizeof *ft->sorted,
+                compare_freq_3way, &ft->vars);
+        }
     }
 
-  for (size_t i = 0; i < n_fts; i++)
+  for (size_t i = 0; i < ct->n_tables; i++)
     {
-      struct ctables_freqtab *ft = fts[i];
-      struct freq *f, *next;
-      HMAP_FOR_EACH_SAFE (f, next, struct freq, node, &ft->data)
+      struct ctables_table *t = &ct->tables[i];
+
+      for (size_t j = 0; j < t->n_fts; j++)
         {
-          hmap_delete (&ft->data, &f->node);
-          for (size_t j = 0; j < ft->vars.n; j++)
+          struct ctables_freqtab *ft = t->fts[j];
+          struct freq *f, *next;
+          HMAP_FOR_EACH_SAFE (f, next, struct freq, node, &ft->data)
             {
-              const struct variable *var = ft->vars.vars[j];
-              value_destroy (&f->values[j], var_get_width (var));
+              hmap_delete (&ft->data, &f->node);
+              for (size_t k = 0; k < ft->vars.n; k++)
+                {
+                  const struct variable *var = ft->vars.vars[k];
+                  value_destroy (&f->values[k], var_get_width (var));
+                }
+              free (f);
             }
-          free (f);
+          hmap_destroy (&ft->data);
+          free (ft->sorted);
+          var_array_uninit (&ft->vars);
+          free (ft);
         }
-      hmap_destroy (&ft->data);
-      free (ft->sorted);
-      var_array_uninit (&ft->vars);
-      free (ft);
+      free (t->fts);
     }
-  free (fts);
 
   return proc_commit (ds);
 }