Change how checking for missing values works.
[pspp] / src / language / stats / means.c
index f0174c4ea39038a8658211160fac2107b1b8dfe8..4ebd60d83ab496239d21ef1a556e44ebeefd75c4 100644 (file)
 #include "libpspp/hmap.h"
 #include "libpspp/bt.h"
 #include "libpspp/hash-functions.h"
+#include "libpspp/misc.h"
+#include "libpspp/pool.h"
+
+#include "language/command.h"
 
 #include "count-one-bits.h"
 #include "count-leading-zeros.h"
@@ -116,8 +120,10 @@ destroy_workspace (const struct mtable *mt, struct workspace *ws)
       struct instance *inst;
       struct instance *next;
       HMAP_FOR_EACH_SAFE (inst, next, struct instance, hmap_node,
-                    &instances->map)
+                         &instances->map)
        {
+         int width = var_get_width (inst->var);
+         value_destroy (&inst->value, width);
          free (inst);
        }
       hmap_destroy (&instances->map);
@@ -183,15 +189,17 @@ means_destroy_cells (const struct means *means, struct cell *cell,
       struct cell *sub_cell;
       struct cell *next;
       HMAP_FOR_EACH_SAFE (sub_cell,  next, struct cell, hmap_node,
-                         &container->map)
-       {
-         means_destroy_cells (means, sub_cell, table);
-       }
+                         &container->map)
+       {
+         means_destroy_cells (means, sub_cell, table);
+       }
     }
 
   destroy_cell (means, table, cell);
 }
 
+#if 0
+
 static void
 dump_cell (const struct cell *cell, const struct mtable *mt, int level)
 {
@@ -252,6 +260,8 @@ dump_tree (const struct cell *cell, const struct mtable *table,
     }
 }
 
+#endif
+
 /* Generate a hash based on the values of the N variables in
    the array VARS which are taken from the case C.  */
 static unsigned int
@@ -290,7 +300,7 @@ generate_cell (const struct means *means,
               const struct workspace *ws)
 {
   int n_vars = count_one_bits (not_wild);
-  struct cell *cell = xzalloc ((sizeof *cell));
+  struct cell *cell = XZALLOC (struct cell);
   cell->values = xcalloc (n_vars, sizeof *cell->values);
   cell->vars = xcalloc (n_vars, sizeof *cell->vars);
   cell->not_wild = not_wild;
@@ -527,7 +537,7 @@ populate_table (const struct means *means, const struct mtable *mt,
                 const struct cell *cell,
                 struct pivot_table *pt)
 {
-  size_t *indexes = xcalloc (pt->n_dimensions, sizeof *indexes);
+  size_t *indexes = XCALLOC (pt->n_dimensions, size_t);
   for (int v = 0; v < mt->n_dep_vars; ++v)
     {
       for (int s = 0; s < means->n_statistics; ++s)
@@ -561,8 +571,14 @@ populate_table (const struct means *means, const struct mtable *mt,
           }
 
          int idx = s + v * means->n_statistics;
-          pivot_table_put (pt, indexes, pt->n_dimensions,
-                           pivot_value_new_number (sg (cell->stat[idx])));
+         struct pivot_value *pv
+           = pivot_value_new_number (sg (cell->stat[idx]));
+         if (NULL == cell_spec[stat].rc)
+           {
+             const struct variable *dv = mt->dep_vars[v];
+             pv->numeric.format = * var_get_print_format (dv);
+           }
+          pivot_table_put (pt, indexes, pt->n_dimensions, pv);
         }
     }
   free (indexes);
@@ -672,7 +688,7 @@ populate_case_processing_summary (struct pivot_category *pc,
 }
 
 /* Create the "Case Processing Summary" table.  */
-void
+static void
 means_case_processing_summary (const struct mtable *mt)
 {
   struct pivot_table *pt = pivot_table_create (N_("Case Processing Summary"));
@@ -735,7 +751,6 @@ means_shipout_single (const struct mtable *mt, const struct means *means,
                      const struct workspace *ws)
 {
   struct pivot_table *pt = pivot_table_create (N_("Report"));
-  pt->omit_empty = true;
 
   struct pivot_dimension *dim_cells =
     pivot_dimension_create (pt, PIVOT_AXIS_COLUMN, N_("Statistics"));
@@ -763,22 +778,20 @@ means_shipout_multivar (const struct mtable *mt, const struct means *means,
   ds_init_empty (&dss);
   for (int dv = 0; dv < mt->n_dep_vars; ++dv)
     {
-      ds_put_cstr (&dss, var_get_name (mt->dep_vars[dv]));
-      if (mt->n_layers > 0)
+      if (dv > 0)
        ds_put_cstr (&dss, " * ");
+      ds_put_cstr (&dss, var_get_name (mt->dep_vars[dv]));
     }
 
   for (int l = 0; l < mt->n_layers; ++l)
     {
+      ds_put_cstr (&dss, " * ");
       const struct layer *layer = mt->layers[l];
       const struct variable *var = layer->factor_vars[ws->control_idx[l]];
       ds_put_cstr (&dss, var_get_name (var));
-      if (l < mt->n_layers - 1)
-       ds_put_cstr (&dss, " * ");
     }
 
   struct pivot_table *pt = pivot_table_create (ds_cstr (&dss));
-  pt->omit_empty = true;
   ds_destroy (&dss);
 
   struct pivot_dimension *dim_cells =
@@ -809,7 +822,7 @@ means_shipout_multivar (const struct mtable *mt, const struct means *means,
   pivot_table_submit (pt);
 }
 
-void
+static void
 means_shipout (const struct mtable *mt, const struct means *means)
 {
   for (int cmb = 0; cmb < mt->n_combinations; ++cmb)
@@ -855,7 +868,7 @@ control_var_missing (const struct means *means,
       const struct variable *var = layer->factor_vars[ws->control_idx[l]];
       const union value *vv = case_data (c, var);
 
-      miss = var_is_value_missing (var, vv, means->ctrl_exclude);
+      miss = (var_is_value_missing (var, vv) & means->ctrl_exclude) != 0;
       if (miss)
        break;
     }
@@ -917,7 +930,7 @@ service_cell_map (const struct means *means, const struct mtable *mt,
             {
               const struct variable *dep_var = mt->dep_vars[v];
              const union value *vv = case_data (c, dep_var);
-             if (var_is_value_missing (dep_var, vv, means->dep_exclude))
+             if (var_is_value_missing (dep_var, vv) & means->dep_exclude)
                continue;
 
               for (int stat = 0; stat < means->n_statistics; ++stat)
@@ -926,7 +939,7 @@ service_cell_map (const struct means *means, const struct mtable *mt,
                                                               NULL);
                   stat_update *su = cell_spec[means->statistics[stat]].su;
                   su (cell->stat[stat + v * means->n_statistics], weight,
-                     case_data (c, dep_var)->f);
+                     case_num (c, dep_var));
                 }
             }
         }
@@ -953,21 +966,12 @@ prepare_means (struct means *cmd)
     {
       struct mtable *mt = cmd->table + t;
 
-      mt->n_combinations = 1;
-      for (int l = 0; l < mt->n_layers; ++l)
-        mt->n_combinations *= mt->layers[l]->n_factor_vars;
-
-      mt->ws = xzalloc (mt->n_combinations * sizeof (*mt->ws));
-      mt->summ = xzalloc (mt->n_combinations * mt->n_dep_vars
-                            * sizeof (*mt->summ));
       for (int i = 0; i < mt->n_combinations; ++i)
         {
           struct workspace *ws = mt->ws + i;
          ws->root_cell = NULL;
-          ws->control_idx = xzalloc (mt->n_layers
-                                        * sizeof *ws->control_idx);
-          ws->instances = xzalloc (mt->n_layers
-                                        * sizeof *ws->instances);
+          ws->control_idx = xcalloc (mt->n_layers, sizeof *ws->control_idx);
+          ws->instances = xcalloc (mt->n_layers, sizeof *ws->instances);
           int cmb = i;
           for (int l = mt->n_layers - 1; l >= 0; --l)
             {
@@ -1043,7 +1047,7 @@ update_summaries (const struct means *means, struct mtable *mt,
          const struct variable *var = mt->dep_vars[dv];
          const union value *vv = case_data (c, var);
          /* First check if the dependent variable is missing.  */
-         if (var_is_value_missing (var, vv, means->dep_exclude))
+         if (var_is_value_missing (var, vv) & means->dep_exclude)
            summ->n_missing += weight;
          /* If the dep var is not missing, then check each
             control variable.  */
@@ -1054,7 +1058,7 @@ update_summaries (const struct means *means, struct mtable *mt,
                const struct variable *var
                  = layer->factor_vars[ws->control_idx[l]];
                const union value *vv = case_data (c, var);
-               if (var_is_value_missing (var, vv, means->ctrl_exclude))
+               if (var_is_value_missing (var, vv) & means->ctrl_exclude)
                  {
                    summ->n_missing += weight;
                    break;
@@ -1098,29 +1102,95 @@ run_means (struct means *cmd, struct casereader *input,
   post_means (cmd);
 }
 
+struct lexer;
 
-/* Release all resources allocated by this routine.
-   This does not include those allocated by the parser,
-   which exclusively use MEANS->pool.  */
-void
-destroy_means (struct means *means)
+int
+cmd_means (struct lexer *lexer, struct dataset *ds)
 {
-  for (int t = 0; t < means->n_tables; ++t)
+  struct means means;
+  means.pool = pool_create ();
+
+  means.ctrl_exclude = MV_ANY;
+  means.dep_exclude = MV_ANY;
+  means.table = NULL;
+  means.n_tables = 0;
+
+  means.dict = dataset_dict (ds);
+
+  means.n_statistics = 3;
+  means.statistics = pool_calloc (means.pool, 3, sizeof *means.statistics);
+  means.statistics[0] = MEANS_MEAN;
+  means.statistics[1] = MEANS_N;
+  means.statistics[2] = MEANS_STDDEV;
+
+  if (! means_parse (lexer, &means))
+    goto error;
+
+  /* Calculate some constant data for each table.  */
+  for (int t = 0; t < means.n_tables; ++t)
     {
-      const struct mtable *table = means->table + t;
-      for (int i = 0; i < table->n_combinations; ++i)
-        {
-         struct workspace *ws = table->ws + i;
-         if (ws->root_cell == NULL)
-           continue;
-         means_destroy_cells (means, ws->root_cell, table);
-       }
-      for (int i = 0; i < table->n_combinations; ++i)
-        {
-         struct workspace *ws = table->ws + i;
-         destroy_workspace (table, ws);
-       }
-      free (table->ws);
-      free (table->summ);
+      struct mtable *mt = means.table + t;
+      mt->n_combinations = 1;
+      for (int l = 0; l < mt->n_layers; ++l)
+       mt->n_combinations *= mt->layers[l]->n_factor_vars;
     }
+
+  {
+    struct casegrouper *grouper;
+    struct casereader *group;
+    bool ok;
+
+    grouper = casegrouper_create_splits (proc_open (ds), means.dict);
+    while (casegrouper_get_next_group (grouper, &group))
+      {
+       /* Allocate the workspaces.  */
+       for (int t = 0; t < means.n_tables; ++t)
+       {
+         struct mtable *mt = means.table + t;
+         mt->summ = xcalloc (mt->n_combinations * mt->n_dep_vars,
+                             sizeof (*mt->summ));
+         mt->ws = xcalloc (mt->n_combinations, sizeof (*mt->ws));
+       }
+       run_means (&means, group, ds);
+       for (int t = 0; t < means.n_tables; ++t)
+         {
+           const struct mtable *mt = means.table + t;
+
+           means_case_processing_summary (mt);
+           means_shipout (mt, &means);
+
+           for (int i = 0; i < mt->n_combinations; ++i)
+             {
+               struct workspace *ws = mt->ws + i;
+               if (ws->root_cell == NULL)
+                 continue;
+
+               means_destroy_cells (&means, ws->root_cell, mt);
+             }
+         }
+
+       /* Destroy the workspaces.  */
+       for (int t = 0; t < means.n_tables; ++t)
+         {
+           struct mtable *mt = means.table + t;
+           free (mt->summ);
+           for (int i = 0; i < mt->n_combinations; ++i)
+             {
+               struct workspace *ws = mt->ws + i;
+               destroy_workspace (mt, ws);
+             }
+           free (mt->ws);
+         }
+      }
+    ok = casegrouper_destroy (grouper);
+    ok = proc_commit (ds) && ok;
+  }
+
+  pool_destroy (means.pool);
+  return CMD_SUCCESS;
+
+ error:
+
+  pool_destroy (means.pool);
+  return CMD_FAILURE;
 }