Fixed some bugs related to empty parentheses
[pspp] / src / language / stats / reliability.c
index c73790713cebaceedf0bdc42a87e594eaa5cc43f..90baa51fe2b861539291996bb6286858150b4232 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011, 2013, 2015 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 <math.h>
 
-#include <libpspp/misc.h>
-
-#include <libpspp/str.h>
-#include <libpspp/message.h>
-
-
-#include <data/procedure.h>
-#include <data/missing-values.h>
-#include <data/casereader.h>
-#include <data/casegrouper.h>
-#include <data/dictionary.h>
-#include <data/format.h>
-
-#include <language/lexer/variable-parser.h>
-#include <language/command.h>
-#include <language/lexer/lexer.h>
-
-#include <math/moments.h>
-#include <output/tab.h>
-#include <output/text-item.h>
+#include "data/casegrouper.h"
+#include "data/casereader.h"
+#include "data/dataset.h"
+#include "data/dictionary.h"
+#include "data/format.h"
+#include "data/missing-values.h"
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/str.h"
+#include "math/moments.h"
+#include "output/tab.h"
+#include "output/text-item.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -113,6 +108,27 @@ struct reliability
 
 static bool run_reliability (struct dataset *ds, const struct reliability *reliability);
 
+static void
+reliability_destroy (struct reliability *rel)
+{
+  int j;
+  ds_destroy (&rel->scale_name);
+  if (rel->sc)
+    for (j = 0; j < rel->n_sc ; ++j)
+      {
+       int x;
+       free (rel->sc[j].items);
+        moments1_destroy (rel->sc[j].total);
+        if (rel->sc[j].m)
+          for (x = 0; x < rel->sc[j].n_items; ++x)
+            free (rel->sc[j].m[x]);
+       free (rel->sc[j].m);
+      }
+
+  free (rel->sc);
+  free (rel->variables);
+}
+
 int
 cmd_reliability (struct lexer *lexer, struct dataset *ds)
 {
@@ -122,28 +138,30 @@ cmd_reliability (struct lexer *lexer, struct dataset *ds)
   reliability.n_variables = 0;
   reliability.variables = NULL;
   reliability.model = MODEL_ALPHA;
-    reliability.exclude = MV_ANY;
+  reliability.exclude = MV_ANY;
   reliability.summary = 0;
-
+  reliability.n_sc = 0;
+  reliability.sc = NULL;
   reliability.wv = dict_get_weight (dict);
-
   reliability.total_start = 0;
+  ds_init_empty (&reliability.scale_name);
+
 
-  lex_match (lexer, '/');
+  lex_match (lexer, T_SLASH);
 
   if (!lex_force_match_id (lexer, "VARIABLES"))
     {
       goto error;
     }
 
-  lex_match (lexer, '=');
+  lex_match (lexer, T_EQUALS);
 
   if (!parse_variables_const (lexer, dict, &reliability.variables, &reliability.n_variables,
                              PV_NO_DUPLICATE | PV_NUMERIC))
     goto error;
 
   if (reliability.n_variables < 2)
-    msg (MW, _("Reliabilty on a single variable is not useful."));
+    msg (MW, _("Reliability on a single variable is not useful."));
 
 
     {
@@ -154,7 +172,7 @@ cmd_reliability (struct lexer *lexer, struct dataset *ds)
       reliability.n_sc = 1;
       reliability.sc = xzalloc (sizeof (struct cronbach) * reliability.n_sc);
 
-      ds_init_cstr (&reliability.scale_name, "ANY");
+      ds_assign_cstr (&reliability.scale_name, "ANY");
 
       c = &reliability.sc[0];
       c->n_items = reliability.n_variables;
@@ -166,31 +184,31 @@ cmd_reliability (struct lexer *lexer, struct dataset *ds)
 
 
 
-  while (lex_token (lexer) != '.')
+  while (lex_token (lexer) != T_ENDCMD)
     {
-      lex_match (lexer, '/');
+      lex_match (lexer, T_SLASH);
 
       if (lex_match_id (lexer, "SCALE"))
        {
          struct const_var_set *vs;
-         if ( ! lex_force_match (lexer, '('))
+         if ( ! lex_force_match (lexer, T_LPAREN))
            goto error;
 
          if ( ! lex_force_string (lexer) ) 
            goto error;
 
-         ds_init_string (&reliability.scale_name, lex_tokstr (lexer));
+         ds_assign_substring (&reliability.scale_name, lex_tokss (lexer));
 
          lex_get (lexer);
 
-         if ( ! lex_force_match (lexer, ')'))
+         if ( ! lex_force_match (lexer, T_RPAREN))
            goto error;
 
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
 
          vs = const_var_set_create_from_array (reliability.variables, reliability.n_variables);
 
-
+         free (reliability.sc->items);
          if (!parse_const_var_set_vars (lexer, vs, &reliability.sc->items, &reliability.sc->n_items, 0))
            {
              const_var_set_destroy (vs);
@@ -201,7 +219,7 @@ cmd_reliability (struct lexer *lexer, struct dataset *ds)
        }
       else if (lex_match_id (lexer, "MODEL"))
        {
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
          if (lex_match_id (lexer, "ALPHA"))
            {
              reliability.model = MODEL_ALPHA;
@@ -211,12 +229,12 @@ cmd_reliability (struct lexer *lexer, struct dataset *ds)
              reliability.model = MODEL_SPLIT;
              reliability.split_point = -1;
 
-             if ( lex_match (lexer, '('))
+             if ( lex_match (lexer, T_LPAREN)
+                  && lex_force_num (lexer))
                {
-                 lex_force_num (lexer);
                  reliability.split_point = lex_number (lexer);
                  lex_get (lexer);
-                 lex_force_match (lexer, ')');
+                 lex_force_match (lexer, T_RPAREN);
                }
            }
          else
@@ -224,7 +242,7 @@ cmd_reliability (struct lexer *lexer, struct dataset *ds)
        }
       else if (lex_match_id (lexer, "SUMMARY"))
         {
-          lex_match (lexer, '=');
+          lex_match (lexer, T_EQUALS);
          if (lex_match_id (lexer, "TOTAL"))
            {
              reliability.summary |= SUMMARY_TOTAL;
@@ -238,8 +256,8 @@ cmd_reliability (struct lexer *lexer, struct dataset *ds)
        }
       else if (lex_match_id (lexer, "MISSING"))
         {
-          lex_match (lexer, '=');
-          while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+          lex_match (lexer, T_EQUALS);
+          while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
             {
              if (lex_match_id (lexer, "INCLUDE"))
                {
@@ -256,6 +274,14 @@ cmd_reliability (struct lexer *lexer, struct dataset *ds)
                }
            }
        }
+      else if (lex_match_id (lexer, "STATISTICS"))
+        {
+          lex_match (lexer, T_EQUALS);
+          msg (SW, _("The STATISTICS subcommand is not yet implemented.  "
+                     "No statistics will be produced."));
+          while (lex_match (lexer, T_ID))
+            continue;
+        }
       else
        {
          lex_error (lexer, NULL);
@@ -268,6 +294,12 @@ cmd_reliability (struct lexer *lexer, struct dataset *ds)
       int i;
       const struct cronbach *s;
 
+      if ( reliability.split_point >= reliability.n_variables)
+        {
+          msg (ME, _("The split point must be less than the number of variables"));
+          goto error;
+        }
+
       reliability.n_sc += 2 ;
       reliability.sc = xrealloc (reliability.sc, sizeof (struct cronbach) * reliability.n_sc);
 
@@ -324,11 +356,11 @@ cmd_reliability (struct lexer *lexer, struct dataset *ds)
   if ( ! run_reliability (ds, &reliability)) 
     goto error;
 
-  free (reliability.variables);
+  reliability_destroy (&reliability);
   return CMD_SUCCESS;
 
  error:
-  free (reliability.variables);
+  reliability_destroy (&reliability);
   return CMD_FAILURE;
 }
 
@@ -351,6 +383,19 @@ run_reliability (struct dataset *ds, const struct reliability *reliability)
   struct casereader *group;
 
   struct casegrouper *grouper = casegrouper_create_splits (proc_open (ds), dict);
+  int si;
+
+  for (si = 0 ; si < reliability->n_sc; ++si)
+    {
+      struct cronbach *s = &reliability->sc[si];
+      int i;
+
+      s->m = xzalloc (sizeof *s->m * s->n_items);
+      s->total = moments1_create (MOMENT_VARIANCE);
+
+      for (i = 0 ; i < s->n_items ; ++i )
+       s->m[i] = moments1_create (MOMENT_VARIANCE);
+    }
 
 
   while (casegrouper_get_next_group (grouper, &group))
@@ -415,11 +460,10 @@ do_reliability (struct casereader *input, struct dataset *ds,
     {
       struct cronbach *s = &rel->sc[si];
 
-      s->m = xzalloc (sizeof (s->m) * s->n_items);
-      s->total = moments1_create (MOMENT_VARIANCE);
+      moments1_clear (s->total);
 
       for (i = 0 ; i < s->n_items ; ++i )
-       s->m[i] = moments1_create (MOMENT_VARIANCE);
+        moments1_clear (s->m[i]);
     }
 
   input = casereader_create_filter_missing (input,
@@ -477,7 +521,7 @@ do_reliability (struct casereader *input, struct dataset *ds,
        alpha (s->n_items, s->sum_of_variances, s->variance_of_sums);
     }
 
-  text_item_submit (text_item_create_format (TEXT_ITEM_PARAGRAPH, "Scale: %s",
+  text_item_submit (text_item_create_format (TEXT_ITEM_PARAGRAPH, _("Scale: %s"),
                                              ds_cstr (&rel->scale_name)));
 
   case_processing_summary (n_valid, n_missing, dataset_dict (ds));
@@ -501,6 +545,7 @@ case_processing_summary (casenumber n_valid, casenumber n_missing,
   int heading_rows = 1;
   struct tab_table *tbl;
   tbl = tab_create (n_cols, n_rows);
+  tab_set_format (tbl, RC_WEIGHT, wfmt);
   tab_headers (tbl, heading_columns, 0, heading_rows, 0);
 
   tab_title (tbl, _("Case Processing Summary"));
@@ -545,27 +590,27 @@ case_processing_summary (casenumber n_valid, casenumber n_missing,
   total = n_missing + n_valid;
 
   tab_double (tbl, 2, heading_rows, TAB_RIGHT,
-            n_valid, wfmt);
+            n_valid, NULL, RC_WEIGHT);
 
 
   tab_double (tbl, 2, heading_rows + 1, TAB_RIGHT,
-            n_missing, wfmt);
+            n_missing, NULL, RC_WEIGHT);
 
 
   tab_double (tbl, 2, heading_rows + 2, TAB_RIGHT,
-            total, wfmt);
+            total, NULL, RC_WEIGHT);
 
 
   tab_double (tbl, 3, heading_rows, TAB_RIGHT,
-            100 * n_valid / (double) total, NULL);
+             100 * n_valid / (double) total, NULL, RC_OTHER);
 
 
   tab_double (tbl, 3, heading_rows + 1, TAB_RIGHT,
-            100 * n_missing / (double) total, NULL);
+             100 * n_missing / (double) total, NULL, RC_OTHER);
 
 
   tab_double (tbl, 3, heading_rows + 2, TAB_RIGHT,
-            100 * total / (double) total, NULL);
+             100 * total / (double) total, NULL, RC_OTHER);
 
 
   tab_submit (tbl);
@@ -581,8 +626,10 @@ reliability_summary_total (const struct reliability *rel)
   const int heading_columns = 1;
   const int heading_rows = 1;
   const int n_rows = rel->sc[0].n_items + heading_rows ;
-
+  const struct variable *wv = rel->wv;
+  const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : & F_8_0;
   struct tab_table *tbl = tab_create (n_cols, n_rows);
+  tab_set_format (tbl, RC_WEIGHT, wfmt);
   tab_headers (tbl, heading_columns, 0, heading_rows, 0);
 
   tab_title (tbl, _("Item-Total Statistics"));
@@ -631,13 +678,13 @@ reliability_summary_total (const struct reliability *rel)
       moments1_calculate (s->total, &weight, &mean, &var, 0, 0);
 
       tab_double (tbl, 1, heading_rows + i, TAB_RIGHT,
-                mean, NULL);
+                 mean, NULL, RC_OTHER);
 
       tab_double (tbl, 2, heading_rows + i, TAB_RIGHT,
-                s->variance_of_sums, NULL);
+                 s->variance_of_sums, NULL, RC_OTHER);
 
       tab_double (tbl, 4, heading_rows + i, TAB_RIGHT,
-                s->alpha, NULL);
+                 s->alpha, NULL, RC_OTHER);
 
 
       moments1_calculate (rel->sc[0].m[i], &weight, &mean, &var, 0,0);
@@ -648,7 +695,7 @@ reliability_summary_total (const struct reliability *rel)
 
 
       tab_double (tbl, 3, heading_rows + i, TAB_RIGHT,
-                item_to_total_r, NULL);
+                 item_to_total_r, NULL, RC_OTHER);
     }
 
 
@@ -686,8 +733,11 @@ reliability_statistics (const struct reliability *rel)
   int n_rows = rol[rel->model].n_rows;
   int heading_columns = rol[rel->model].heading_cols;
   int heading_rows = rol[rel->model].heading_rows;
-
+  const struct variable *wv = rel->wv;
+  const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : & F_8_0;
   struct tab_table *tbl = tab_create (n_cols, n_rows);
+  tab_set_format (tbl, RC_WEIGHT, wfmt);
+
   tab_headers (tbl, heading_columns, 0, heading_rows, 0);
 
   tab_title (tbl, _("Reliability Statistics"));
@@ -724,9 +774,6 @@ static void
 reliability_statistics_model_alpha (struct tab_table *tbl,
                                    const struct reliability *rel)
 {
-  const struct variable *wv = rel->wv;
-  const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : & F_8_0;
-
   const struct cronbach *s = &rel->sc[0];
 
   tab_text (tbl, 0, 0, TAB_CENTER | TAT_TITLE,
@@ -735,9 +782,9 @@ reliability_statistics_model_alpha (struct tab_table *tbl,
   tab_text (tbl, 1, 0, TAB_CENTER | TAT_TITLE,
                _("N of Items"));
 
-  tab_double (tbl, 0, 1, TAB_RIGHT, s->alpha, NULL);
+  tab_double (tbl, 0, 1, TAB_RIGHT, s->alpha, NULL, RC_OTHER);
 
-  tab_double (tbl, 1, 1, TAB_RIGHT, s->n_items, wfmt);
+  tab_double (tbl, 1, 1, TAB_RIGHT, s->n_items, NULL, RC_WEIGHT);
 }
 
 
@@ -745,9 +792,6 @@ static void
 reliability_statistics_model_split (struct tab_table *tbl,
                                    const struct reliability *rel)
 {
-  const struct variable *wv = rel->wv;
-  const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : & F_8_0;
-
   tab_text (tbl, 0, 0, TAB_LEFT,
            _("Cronbach's Alpha"));
 
@@ -760,8 +804,6 @@ reliability_statistics_model_split (struct tab_table *tbl,
   tab_text (tbl, 2, 1, TAB_LEFT,
            _("N of Items"));
 
-
-
   tab_text (tbl, 1, 2, TAB_LEFT,
            _("Part 2"));
 
@@ -771,15 +813,12 @@ reliability_statistics_model_split (struct tab_table *tbl,
   tab_text (tbl, 2, 3, TAB_LEFT,
            _("N of Items"));
 
-
-
   tab_text (tbl, 1, 4, TAB_LEFT,
            _("Total N of Items"));
 
   tab_text (tbl, 0, 5, TAB_LEFT,
            _("Correlation Between Forms"));
 
-
   tab_text (tbl, 0, 6, TAB_LEFT,
            _("Spearman-Brown Coefficient"));
 
@@ -795,14 +834,14 @@ reliability_statistics_model_split (struct tab_table *tbl,
 
 
 
-  tab_double (tbl, 3, 0, TAB_RIGHT, rel->sc[1].alpha, NULL);
-  tab_double (tbl, 3, 2, TAB_RIGHT, rel->sc[2].alpha, NULL);
+  tab_double (tbl, 3, 0, TAB_RIGHT, rel->sc[1].alpha, NULL, RC_OTHER);
+  tab_double (tbl, 3, 2, TAB_RIGHT, rel->sc[2].alpha, NULL, RC_OTHER);
 
-  tab_double (tbl, 3, 1, TAB_RIGHT, rel->sc[1].n_items, wfmt);
-  tab_double (tbl, 3, 3, TAB_RIGHT, rel->sc[2].n_items, wfmt);
+  tab_double (tbl, 3, 1, TAB_RIGHT, rel->sc[1].n_items, NULL, RC_WEIGHT);
+  tab_double (tbl, 3, 3, TAB_RIGHT, rel->sc[2].n_items, NULL, RC_WEIGHT);
 
   tab_double (tbl, 3, 4, TAB_RIGHT,
-            rel->sc[1].n_items + rel->sc[2].n_items, wfmt);
+            rel->sc[1].n_items + rel->sc[2].n_items, NULL, RC_WEIGHT);
 
   {
     /* R is the correlation between the two parts */
@@ -821,12 +860,12 @@ reliability_statistics_model_split (struct tab_table *tbl,
     r /= sqrt (rel->sc[2].variance_of_sums);
     r /= 2.0;
 
-    tab_double (tbl, 3, 5, TAB_RIGHT, r, NULL);
+    tab_double (tbl, 3, 5, TAB_RIGHT, r, NULL, RC_OTHER);
 
     /* Equal length Spearman-Brown Coefficient */
-    tab_double (tbl, 3, 6, TAB_RIGHT, 2 * r / (1.0 + r), NULL);
+    tab_double (tbl, 3, 6, TAB_RIGHT, 2 * r / (1.0 + r), NULL, RC_OTHER);
 
-    tab_double (tbl, 3, 8, TAB_RIGHT, g, NULL);
+    tab_double (tbl, 3, 8, TAB_RIGHT, g, NULL, RC_OTHER);
 
     tmp = (1.0 - r*r) * rel->sc[1].n_items * rel->sc[2].n_items /
       pow2 (rel->sc[0].n_items);
@@ -835,7 +874,7 @@ reliability_statistics_model_split (struct tab_table *tbl,
     uly -= pow2 (r);
     uly /= 2 * tmp;
 
-    tab_double (tbl, 3, 7, TAB_RIGHT, uly, NULL);
+    tab_double (tbl, 3, 7, TAB_RIGHT, uly, NULL, RC_OTHER);
   }
 }