case: Introduce new functions for numbers and substrings in cases.
[pspp] / src / language / data-io / matrix-reader.c
index 65e3cf4d08cd59219e65fec3211ec875c841c026..a7db15e029d8b9feac1d9111a8297edb87c6540b 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2017 Free Software Foundation, Inc.
+   Copyright (C) 2017, 2019 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
 #include <stdbool.h>
 
-#include <libpspp/hash-functions.h>
 #include <libpspp/message.h>
+#include <libpspp/str.h>
 #include <data/casegrouper.h>
 #include <data/casereader.h>
 #include <data/dictionary.h>
 #include <data/variable.h>
+#include <data/data-out.h>
+#include <data/format.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -85,9 +87,6 @@ struct matrix_reader
   gsl_matrix *n_vectors;
   gsl_matrix *mean_vectors;
   gsl_matrix *var_vectors;
-
-  gsl_matrix *correlation;
-  gsl_matrix *covariance;
 };
 
 struct matrix_reader *
@@ -96,8 +95,8 @@ create_matrix_reader_from_case_reader (const struct dictionary *dict, struct cas
 {
   struct matrix_reader *mr = xzalloc (sizeof *mr);
 
-  mr->dict = dict;
   mr->varname = dict_lookup_var (dict, "varname_");
+  mr->dict = dict;
   if (mr->varname == NULL)
     {
       msg (ME, _("Matrix dataset lacks a variable called %s."), "VARNAME_");
@@ -105,6 +104,14 @@ create_matrix_reader_from_case_reader (const struct dictionary *dict, struct cas
       return NULL;
     }
 
+  if (!var_is_alpha (mr->varname))
+    {
+      msg (ME, _("Matrix dataset variable %s should be of string type."),
+          "VARNAME_");
+      free (mr);
+      return NULL;
+    }
+
   mr->rowtype = dict_lookup_var (dict, "rowtype_");
   if (mr->rowtype == NULL)
     {
@@ -113,6 +120,14 @@ create_matrix_reader_from_case_reader (const struct dictionary *dict, struct cas
       return NULL;
     }
 
+  if (!var_is_alpha (mr->rowtype))
+    {
+      msg (ME, _("Matrix dataset variable %s should be of string type."),
+          "ROWTYPE_");
+      free (mr);
+      return NULL;
+    }
+
   size_t dvarcnt;
   const struct variable **dvars = NULL;
   dict_get_vars (dict, &dvars, &dvarcnt, DC_SCRATCH);
@@ -123,7 +138,7 @@ create_matrix_reader_from_case_reader (const struct dictionary *dict, struct cas
   if (vars)
     {
       int i;
-      *vars = xcalloc (sizeof (struct variable **), *n_vars);
+      *vars = xcalloc (*n_vars, sizeof (struct variable **));
 
       for (i = 0; i < *n_vars; ++i)
        {
@@ -167,7 +182,7 @@ matrix_fill_row (gsl_matrix **matrix,
   for (col = 0; col < n_vars; ++col)
     {
       const struct variable *cv = vars [col];
-      double x = case_data (c, cv)->f;
+      double x = case_num (c, cv);
       assert (col  < (*matrix)->size2);
       assert (mrow < (*matrix)->size1);
       gsl_matrix_set (*matrix, mrow, col, x);
@@ -198,76 +213,72 @@ next_matrix_from_reader (struct matrix_material *mm,
   mm->mean_matrix = mr->mean_vectors;
   mm->var_matrix = mr->var_vectors;
 
-  // FIXME: Make this into a hash table.
-  unsigned long *table = xmalloc (sizeof (*table) * n_vars);
-  int i;
-  for (i = 0; i < n_vars; ++i)
+  struct substring *var_names = XCALLOC (n_vars,  struct substring);
+  for (int i = 0; i < n_vars; ++i)
     {
-      const int w = var_get_width (mr->varname);
-      uint8_t s[w];
-      memset (s, 0, w);
-      const char *name = var_get_name (vars[i]);
-      strcpy (s, name);
-      unsigned long h = hash_bytes (s, w, 0);
-      table[i] = h;
+      ss_alloc_substring (var_names + i, ss_cstr (var_get_name (vars[i])));
     }
 
   struct ccase *c;
-  for ( ; (c = casereader_read (group) ); case_unref (c))
+  for (; (c = casereader_read (group)); case_unref (c))
     {
-      const union value *uv  = case_data (c, mr->rowtype);
+      const union value *uv = case_data (c, mr->rowtype);
+      const char *row_type = CHAR_CAST (const char *, uv->s);
       int col, row;
       for (col = 0; col < n_vars; ++col)
        {
-         const struct variable *cv
-           = vars ? vars[col] : dict_get_var (mr->dict, var_get_dict_index (mr->varname) + 1 + col);
+         const struct variable *cv = vars[col];
          double x = case_data (c, cv)->f;
-         if (0 == strncasecmp ((char *)value_str (uv, 8), "N       ", 8))
+         if (0 == strncasecmp (row_type, "N       ", 8))
            for (row = 0; row < n_vars; ++row)
              gsl_matrix_set (mr->n_vectors, row, col, x);
-         else if (0 == strncasecmp ((char *) value_str (uv, 8), "MEAN    ", 8))
+         else if (0 == strncasecmp (row_type, "MEAN    ", 8))
            for (row = 0; row < n_vars; ++row)
              gsl_matrix_set (mr->mean_vectors, row, col, x);
-         else if (0 == strncasecmp ((char *) value_str (uv, 8), "STDDEV  ", 8))
+         else if (0 == strncasecmp (row_type, "STDDEV  ", 8))
            for (row = 0; row < n_vars; ++row)
              gsl_matrix_set (mr->var_vectors, row, col, x * x);
        }
 
+      const char *enc = dict_get_encoding (mr->dict);
+
       const union value *uvv  = case_data (c, mr->varname);
-      const uint8_t *vs = value_str (uvv, var_get_width (mr->varname));
       int w = var_get_width (mr->varname);
-      unsigned long h = hash_bytes (vs, w, 0);
+
+      struct fmt_spec fmt = { .type = FMT_A };
+      fmt.w = w;
+      char *vname = data_out (uvv, enc, &fmt, settings_get_fmt_settings ());
+      struct substring the_name = ss_cstr (vname);
 
       int mrow = -1;
-      for (i = 0; i < n_vars; ++i)
+      for (int i = 0; i < n_vars; ++i)
        {
-         if (table[i] == h)
+         if (ss_equals (var_names[i], the_name))
            {
              mrow = i;
              break;
            }
        }
+      free (vname);
 
       if (mrow == -1)
        continue;
 
-
-      if (0 == strncasecmp ((char *) value_str (uv, 8), "CORR    ", 8))
+      if (0 == strncasecmp (row_type, "CORR    ", 8))
        {
-         matrix_fill_row (&mr->correlation, c, mrow, vars, n_vars);
+         matrix_fill_row (&mm->corr, c, mrow, vars, n_vars);
        }
-      else if (0 == strncasecmp ((char *) value_str (uv, 8), "COV     ", 8))
+      else if (0 == strncasecmp (row_type, "COV     ", 8))
        {
-         matrix_fill_row (&mr->covariance, c, mrow, vars, n_vars);
+         matrix_fill_row (&mm->cov, c, mrow, vars, n_vars);
        }
     }
 
   casereader_destroy (group);
 
-  mm->cov = mr->covariance;
-  mm->corr = mr->correlation;
-
-  free (table);
+  for (int i = 0; i < n_vars; ++i)
+    ss_dealloc (var_names + i);
+  free (var_names);
 
   return true;
 }