work
authorBen Pfaff <blp@cs.stanford.edu>
Fri, 29 Jul 2022 22:41:35 +0000 (15:41 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Fri, 29 Jul 2022 22:41:35 +0000 (15:41 -0700)
src/data/dataset.c
src/data/dataset.h
src/language/stats/ctables.c
tests/language/stats/ctables.at

index c13a941ba8a169ac83c79e3f57038ddaf8c1ed9f..931d3dcbbfb1ac1a23066719d68d4bf76f69ebff 100644 (file)
@@ -1026,15 +1026,14 @@ add_measurement_level_trns_proc__ (struct measurement_level_var *mlv, double val
   return MEASURE_UNKNOWN;
 }
 
-static enum trns_result
-add_measurement_level_trns_proc (void *mlt_, struct ccase **c,
-                                 casenumber case_nr UNUSED)
+static void
+measurement_level_trns_run (struct measurement_level_trns *mlt,
+                            const struct ccase *c)
 {
-  struct measurement_level_trns *mlt = mlt_;
   for (size_t i = 0; i < mlt->n_vars; )
     {
       struct measurement_level_var *mlv = &mlt->vars[i];
-      double value = case_num (*c, mlv->var);
+      double value = case_num (c, mlv->var);
       enum measure m = add_measurement_level_trns_proc__ (mlv, value);
       if (m != MEASURE_UNKNOWN)
         {
@@ -1046,6 +1045,14 @@ add_measurement_level_trns_proc (void *mlt_, struct ccase **c,
       else
         i++;
     }
+}
+
+static enum trns_result
+add_measurement_level_trns_proc (void *mlt_, struct ccase **c,
+                                 casenumber case_nr UNUSED)
+{
+  struct measurement_level_trns *mlt = mlt_;
+  measurement_level_trns_run (mlt, *c);
   return TRNS_CONTINUE;
 }
 
@@ -1062,15 +1069,21 @@ add_measurement_level_trns_free__ (struct measurement_level_trns *mlt)
   free (mlt);
 }
 
-static bool
-add_measurement_level_trns_free (void *mlt_)
+static void
+measurement_level_trns_commit (struct measurement_level_trns *mlt)
 {
-  struct measurement_level_trns *mlt = mlt_;
   for (size_t i = 0; i < mlt->n_vars; i++)
     {
       struct measurement_level_var *mlv = &mlt->vars[i];
       var_set_measure (mlv->var, add_measurement_level_var_interpret (mlv));
     }
+}
+
+static bool
+add_measurement_level_trns_free (void *mlt_)
+{
+  struct measurement_level_trns *mlt = mlt_;
+  measurement_level_trns_commit (mlt);
   add_measurement_level_trns_free__ (mlt);
   return true;
 }
@@ -1081,8 +1094,8 @@ static const struct trns_class add_measurement_level_trns_class = {
   .destroy = add_measurement_level_trns_free,
 };
 
-static void
-add_measurement_level_trns (struct dataset *ds, struct dictionary *dict)
+static struct measurement_level_trns *
+create_measurement_level_trns (struct dictionary *dict)
 {
   struct measurement_level_var *mlvs = NULL;
   size_t n_mlvs = 0;
@@ -1113,14 +1126,22 @@ add_measurement_level_trns (struct dataset *ds, struct dictionary *dict)
       hmap_init (mlv->values);
     }
   if (!n_mlvs)
-    return;
+    return NULL;
 
   struct measurement_level_trns *mlt = xmalloc (sizeof *mlt);
   *mlt = (struct measurement_level_trns) {
     .vars = mlvs,
     .n_vars = n_mlvs,
   };
-  add_transformation (ds, &add_measurement_level_trns_class, mlt);
+  return mlt;
+}
+
+static void
+add_measurement_level_trns (struct dataset *ds, struct dictionary *dict)
+{
+  struct measurement_level_trns *mlt = create_measurement_level_trns (dict);
+  if (mlt)
+    add_transformation (ds, &add_measurement_level_trns_class, mlt);
 }
 
 static void
@@ -1137,6 +1158,40 @@ cancel_measurement_level_trns (struct trns_chain *chain)
   add_measurement_level_trns_free__ (mlt);
   chain->n--;
 }
+
+bool
+measure_guesser_is_needed (struct dataset *ds)
+{
+  struct measurement_level_trns *mlt
+    = create_measurement_level_trns (dataset_dict (ds));
+  if (mlt)
+    {
+      add_measurement_level_trns_free__ (mlt);
+      return true;
+    }
+  return false;
+}
+
+void
+measure_guesser_run (struct dataset *ds, const struct casereader *reader)
+{
+  struct measurement_level_trns *mlt
+    = create_measurement_level_trns (dataset_dict (ds));
+  if (!mlt)
+    return;
+
+  struct casereader *r = casereader_clone (reader);
+  while (mlt->n_vars > 0)
+    {
+      struct ccase *c = casereader_read (r);
+      measurement_level_trns_run (mlt, c);
+      case_unref (c);
+    }
+  casereader_destroy (r);
+
+  measurement_level_trns_commit (mlt);
+  add_measurement_level_trns_free__ (mlt);
+}
 \f
 static void
 dataset_changed__ (struct dataset *ds)
index 1fe535536f6cee4bd5d9da065d0e4a0bb7c9dedd..eaea34f91a3c5877e5cac8a3aae4f18518e1280b 100644 (file)
@@ -105,6 +105,9 @@ bool proc_commit (struct dataset *);
 
 bool dataset_end_of_command (struct dataset *);
 \f
+bool measure_guesser_is_needed (struct dataset *);
+void measure_guesser_run (struct dataset *, const struct casereader *);
+\f
 const struct ccase *lagged_case (const struct dataset *ds, int n_before);
 void dataset_need_lag (struct dataset *ds, int n_before);
 \f
index aa204b4ea5f0070bd1aa1a582ac09a4d63e7bdeb..b2bf14b39992e4f24a02aa55dd29d4af1002218a 100644 (file)
@@ -5317,7 +5317,8 @@ ctables_table_clear (struct ctables_table *t)
 }
 
 static bool
-ctables_execute (struct dataset *ds, struct ctables *ct)
+ctables_execute (struct dataset *ds, struct casereader *input,
+                 struct ctables *ct)
 {
   for (size_t i = 0; i < ct->n_tables; i++)
     {
@@ -5331,7 +5332,6 @@ ctables_execute (struct dataset *ds, struct ctables *ct)
     }
 
   struct dictionary *dict = dataset_dict (ds);
-  struct casereader *input = proc_open (ds);
   struct casegrouper *grouper
     = (dict_get_split_type (dict) == SPLIT_SEPARATE
        ? casegrouper_create_splits (input, dict)
@@ -5386,8 +5386,7 @@ ctables_execute (struct dataset *ds, struct ctables *ct)
           ctables_table_clear (t);
         }
     }
-  bool ok = casegrouper_destroy (grouper);
-  return proc_commit (ds) && ok;
+  return casegrouper_destroy (grouper);
 }
 \f
 /* Postcomputes. */
@@ -6022,6 +6021,15 @@ put_title_text (struct string *out, struct substring in, time_t now,
 int
 cmd_ctables (struct lexer *lexer, struct dataset *ds)
 {
+  struct casereader *input;
+  if (measure_guesser_is_needed (ds))
+    {
+      input = proc_open (ds);
+      measure_guesser_run (ds, input);
+    }
+  else
+    input = NULL;
+
   size_t n_vars = dict_get_n_vars (dataset_dict (ds));
   enum ctables_vlabel *vlabels = xnmalloc (n_vars, sizeof *vlabels);
   enum settings_value_show tvars = settings_get_show_variables ();
@@ -6750,11 +6758,17 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds)
     }
   while (lex_token (lexer) != T_ENDCMD);
 
-  bool ok = ctables_execute (ds, ct);
+  if (!input)
+    input = proc_open (ds);
+  bool ok = ctables_execute (ds, input, ct);
+  ok = proc_commit (ds) && ok;
+
   ctables_destroy (ct);
   return ok ? CMD_SUCCESS : CMD_FAILURE;
 
 error:
+  if (input)
+    proc_commit (ds);
   ctables_destroy (ct);
   return CMD_FAILURE;
 }
index d45478f0a1afa3cb50647bb330a4d77d428e4ecf..b1a497db3c69ce58de7c78a3d945125371ef3c73 100644 (file)
@@ -1,10 +1,7 @@
 AT_BANNER([CTABLES])
 
-dnl Features not yet implemented:
-dnl
-dnl - Preprocessing to distinguish categorical from scale.
-dnl
 dnl Features not yet tested:
+dnl - Preprocessing to distinguish categorical from scale.
 dnl - Parsing (positive and negative)
 dnl - String variables and values
 dnl - Testing details of missing value handling in summaries.