Adopt use of gnulib for portability.
[pspp-builds.git] / src / examine.q
index 517b24f9b4b22329229084ade60461b2c7db989e..b54f574b5c36631f79ed2b7e98f0fd5f3daca5f3 100644 (file)
@@ -15,8 +15,8 @@ General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
 
 #include <config.h>
 #include <gsl/gsl_cdf.h>
@@ -44,12 +44,16 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "moments.h"
 #include "percentiles.h"
 
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+#define N_(msgid) msgid
+
 /* (headers) */
 #include "chart.h"
 
 /* (specification)
    "EXAMINE" (xmn_):
-   *variables=custom;
+   *^variables=custom;
    +total=custom;
    +nototal=custom;
    +missing=miss:pairwise/!listwise,
@@ -116,8 +120,8 @@ static void show_descriptives(struct variable **dependent_var,
                              struct factor *factor);
 
 static void show_percentiles(struct variable **dependent_var, 
-                             int n_dep_var, 
-                             struct factor *factor);
+                            int n_dep_var, 
+                            struct factor *factor);
 
 
 
@@ -132,7 +136,7 @@ void box_plot_group(const struct factor *fctr,
 
 
 void box_plot_variables(const struct factor *fctr, 
-                       struct variable **vars, int n_vars, 
+                       const struct variable **vars, int n_vars, 
                        const struct variable *id
                        );
 
@@ -151,8 +155,8 @@ void factor_calc(struct ccase *c, int case_no,
 /* Represent a factor as a string, so it can be
    printed in a human readable fashion */
 const char * factor_to_string(const struct factor *fctr, 
-                       struct factor_statistics *fs,
-                       const struct variable *var);
+                             struct factor_statistics *fs,
+                             const struct variable *var);
 
 
 /* Represent a factor as a string, so it can be
@@ -211,7 +215,25 @@ cmd_examine(void)
   multipass_procedure_with_splits (run_examine, &cmd);
 
   if ( totals ) 
-    free(totals);
+    {
+      free( totals );
+    }
+  
+  if ( dependent_vars ) 
+    free (dependent_vars);
+
+  {
+    struct factor *f = factors ;
+    while ( f ) 
+      {
+       struct factor *ff = f;
+
+       f = f->next;
+       free ( ff->fs );
+       hsh_destroy ( ff->fstats ) ;
+       free ( ff ) ;
+      }
+  }
 
   subc_list_double_destroy(&percentile_list);
 
@@ -264,7 +286,6 @@ output_examine(void)
                                   cmd.v_id);
            }
 
-#ifndef NO_CHARTS
          if ( cmd.a_plot[XMN_PLT_HISTOGRAM] ) 
            {
              for ( v = 0 ; v < n_dependent_vars; ++v ) 
@@ -280,7 +301,6 @@ output_examine(void)
                                 &normal, 0);
                }
            }
-#endif
 
        }
 
@@ -332,7 +352,6 @@ output_examine(void)
                  if ( cmd.a_plot[XMN_PLT_NPPLOT] ) 
                    np_plot(&(*fs)->m[v], s);
 
-#ifndef NO_CHARTS
                  if ( cmd.a_plot[XMN_PLT_HISTOGRAM] ) 
                    {
                      struct normal_curve normal;
@@ -344,7 +363,6 @@ output_examine(void)
                      histogram_plot((*fs)->m[v].histogram, 
                                     s,  &normal, 0);
                    }
-#endif
                  
                } /* for ( fs .... */
 
@@ -358,6 +376,8 @@ output_examine(void)
 }
 
 
+/* Create a hash table of percentiles and their values from the list of
+   percentiles */
 static struct hsh_table *
 list_to_ptile_hash(const subc_list_double *l)
 {
@@ -377,6 +397,7 @@ list_to_ptile_hash(const subc_list_double *l)
       struct percentile *p = xmalloc (sizeof (struct percentile));
       
       p->p = subc_list_double_at(l,i);
+      p->v = SYSMIS;
 
       hsh_insert(h, p);
 
@@ -396,9 +417,9 @@ xmn_custom_percentiles(struct cmd_examine *p UNUSED)
 
   lex_match('(');
 
-  while ( lex_double_p() ) 
+  while ( lex_is_number() ) 
     {
-      subc_list_double_push(&percentile_list,lex_double());
+      subc_list_double_push(&percentile_list,lex_number());
 
       lex_get();
 
@@ -468,16 +489,18 @@ xmn_custom_nototal(struct cmd_examine *p)
 
 
 
-/* Parser for the variables sub command */
+/* Parser for the variables sub command  
+   Returns 1 on success */
 static int
 xmn_custom_variables(struct cmd_examine *cmd )
 {
-
   lex_match('=');
 
   if ((token != T_ID || dict_lookup_var (default_dict, tokid) == NULL)
       && token != T_ALL)
-    return 2;
+    {
+      return 2;
+    }
   
   if (!parse_variables (default_dict, &dependent_vars, &n_dependent_vars,
                        PV_NO_DUPLICATE | PV_NUMERIC | PV_NO_SCRATCH) )
@@ -492,7 +515,13 @@ xmn_custom_variables(struct cmd_examine *cmd )
 
   if ( lex_match(T_BY))
     {
-      return examine_parse_independent_vars(cmd);
+      int success ; 
+      success =  examine_parse_independent_vars(cmd);
+      if ( success != 1 ) {
+        free (dependent_vars);
+       free (totals) ; 
+      }
+      return success;
     }
 
   return 1;
@@ -504,12 +533,15 @@ xmn_custom_variables(struct cmd_examine *cmd )
 static int
 examine_parse_independent_vars(struct cmd_examine *cmd)
 {
-
+  int success;
   struct factor *sf = xmalloc(sizeof(struct factor));
 
   if ((token != T_ID || dict_lookup_var (default_dict, tokid) == NULL)
       && token != T_ALL)
-    return 2;
+    {
+      free ( sf ) ;
+      return 2;
+    }
 
 
   sf->indep_var[0] = parse_variable();
@@ -522,7 +554,10 @@ examine_parse_independent_vars(struct cmd_examine *cmd)
 
       if ((token != T_ID || dict_lookup_var (default_dict, tokid) == NULL)
          && token != T_ALL)
-       return 2;
+       {
+         free ( sf ) ;
+         return 2;
+       }
 
       sf->indep_var[1] = parse_variable();
 
@@ -543,7 +578,12 @@ examine_parse_independent_vars(struct cmd_examine *cmd)
   if ( token == '.' || token == '/' ) 
     return 1;
 
-  return examine_parse_independent_vars(cmd);
+  success =  examine_parse_independent_vars(cmd);
+  
+  if ( success != 1 ) 
+    free ( sf ) ; 
+
+  return success;
 }
 
 
@@ -576,6 +616,7 @@ factor_calc(struct ccase *c, int case_no, double weight, int case_missing)
 
   while ( fctr) 
     {
+      struct factor_statistics **foo ;
       union value indep_vals[2] ;
 
       indep_vals[0] = * case_data(c, fctr->indep_var[0]->fv);
@@ -587,7 +628,7 @@ factor_calc(struct ccase *c, int case_no, double weight, int case_missing)
 
       assert(fctr->fstats);
 
-      struct factor_statistics **foo = ( struct factor_statistics ** ) 
+      foo = ( struct factor_statistics ** ) 
        hsh_probe(fctr->fstats, (void *) &indep_vals);
 
       if ( !*foo ) 
@@ -790,8 +831,15 @@ run_examine(const struct casefile *cf, void *cmd_ )
 
   output_examine();
 
-  for ( v = 0 ; v < n_dependent_vars ; ++v ) 
-    hsh_destroy(totals[v].ordered_data);
+
+  if ( totals ) 
+    {
+      int i;
+      for ( i = 0 ; i < n_dependent_vars ; ++i ) 
+       {
+         metrics_destroy(&totals[i]);
+       }
+    }
 
 }
 
@@ -823,7 +871,7 @@ show_summary(struct variable **dependent_var, int n_dep_var,
       n_rows = n_dep_var * n_factors ;
 
       if ( fctr->indep_var[1] )
-         heading_columns = 3;
+       heading_columns = 3;
     }
   else
     {
@@ -948,17 +996,17 @@ show_summary(struct variable **dependent_var, int n_dep_var,
              if ( 0 != compare_values(&prev, &(*fs)->id[0], 
                                       fctr->indep_var[0]->width))
                {
-                  tab_text (tbl, 
-                            1,
-                            (i * n_factors ) + count + 
-                            heading_rows,
-                            TAB_LEFT | TAT_TITLE, 
-                            value_to_string(&(*fs)->id[0], fctr->indep_var[0])
-                            );
-
-                  if (fctr->indep_var[1] && count > 0 ) 
-                    tab_hline(tbl, TAL_1, 1, n_cols - 1, 
-                              (i * n_factors ) + count + heading_rows);
+                 tab_text (tbl, 
+                           1,
+                           (i * n_factors ) + count + 
+                           heading_rows,
+                           TAB_LEFT | TAT_TITLE, 
+                           value_to_string(&(*fs)->id[0], fctr->indep_var[0])
+                           );
+
+                 if (fctr->indep_var[1] && count > 0 ) 
+                   tab_hline(tbl, TAL_1, 1, n_cols - 1, 
+                             (i * n_factors ) + count + heading_rows);
 
                }
              
@@ -1041,7 +1089,7 @@ show_extremes(struct variable **dependent_var, int n_dep_var,
       n_rows = n_dep_var * 2 * n_extremities * n_factors;
 
       if ( fctr->indep_var[1] )
-         heading_columns = 3;
+       heading_columns = 3;
     }
   else
     {
@@ -1218,7 +1266,7 @@ populate_extremes(struct tab_table *t,
                    cn->num, 8, 0);
 
          if ( cn->next ) 
-             cn = cn->next;
+           cn = cn->next;
 
        }
 
@@ -1247,7 +1295,7 @@ populate_extremes(struct tab_table *t,
                    cn->num, 8, 0);
 
          if ( cn->next ) 
-             cn = cn->next;
+           cn = cn->next;
 
        }
 
@@ -1282,7 +1330,7 @@ show_descriptives(struct variable **dependent_var,
       n_rows = n_dep_var * n_stat_rows * n_factors;
 
       if ( fctr->indep_var[1] )
-         heading_columns = 5;
+       heading_columns = 5;
     }
   else
     {
@@ -1382,7 +1430,7 @@ show_descriptives(struct variable **dependent_var,
                          );
 
              populate_descriptives(tbl, heading_columns - 2, 
-                               row, &(*fs)->m[i]);
+                                   row, &(*fs)->m[i]);
 
              count++ ; 
              fs++;
@@ -1465,8 +1513,8 @@ populate_descriptives(struct tab_table *tbl, int col, int row,
 
   tab_text (tbl, col, 
            row + 3,
-           TAB_LEFT | TAT_TITLE,
-           _("5% Trimmed Mean"));
+           TAB_LEFT | TAT_TITLE | TAT_PRINTF,
+           _("5%% Trimmed Mean"));
 
   tab_float (tbl, col + 2, 
             row + 3,
@@ -1487,12 +1535,14 @@ populate_descriptives(struct tab_table *tbl, int col, int row,
     
     assert(p);
 
+
     tab_float (tbl, col + 2, 
               row + 4,
               TAB_CENTER,
               p->v,
               8, 2);
   }
+    
 
   tab_text (tbl, col, 
            row + 5,
@@ -1627,10 +1677,10 @@ populate_descriptives(struct tab_table *tbl, int col, int row,
 
 void
 box_plot_variables(const struct factor *fctr, 
-                  struct variable **vars, int n_vars, 
+                  const struct variable **vars, int n_vars, 
                   const struct variable *id)
 {
-#ifndef NO_CHARTS
+
   int i;
   struct factor_statistics **fs ;
 
@@ -1644,13 +1694,10 @@ box_plot_variables(const struct factor *fctr,
     {
       double y_min = DBL_MAX;
       double y_max = -DBL_MAX;
-      struct chart ch;
-
-      chart_initialise(&ch);
-
+      struct chart *ch = chart_create();
       const char *s = factor_to_string(fctr, *fs, 0 );
 
-      chart_write_title(&ch, s);
+      chart_write_title(ch, s);
 
       for ( i = 0 ; i < n_vars ; ++i ) 
        {
@@ -1658,18 +1705,18 @@ box_plot_variables(const struct factor *fctr,
          y_min = min(y_min, (*fs)->m[i].min);
        }
       
-      boxplot_draw_yscale(&ch, y_max, y_min);
+      boxplot_draw_yscale(ch, y_max, y_min);
          
       for ( i = 0 ; i < n_vars ; ++i ) 
        {
 
-         const double box_width = (ch.data_right - ch.data_left) 
+         const double box_width = (ch->data_right - ch->data_left) 
            / (n_vars * 2.0 ) ;
 
          const double box_centre = ( i * 2 + 1) * box_width 
-           + ch.data_left;
+           + ch->data_left;
              
-         boxplot_draw_boxplot(&ch,
+         boxplot_draw_boxplot(ch,
                               box_centre, box_width,
                               &(*fs)->m[i],
                               var_to_string(vars[i]));
@@ -1677,10 +1724,9 @@ box_plot_variables(const struct factor *fctr,
 
        }
 
-      chart_finalise(&ch);
+      chart_submit(ch);
 
     }
-#endif
 }
 
 
@@ -1692,28 +1738,28 @@ void
 box_plot_group(const struct factor *fctr, 
               const struct variable **vars, 
               int n_vars,
-              const struct variable *id)
+              const struct variable *id UNUSED)
 {
-#ifndef NO_CHARTS
+
   int i;
 
   for ( i = 0 ; i < n_vars ; ++i ) 
     {
       struct factor_statistics **fs ;
-      struct chart ch;
+      struct chart *ch;
 
-      chart_initialise(&ch);
+      ch = chart_create();
 
-      boxplot_draw_yscale(&ch, totals[i].max, totals[i].min);
+      boxplot_draw_yscale(ch, totals[i].max, totals[i].min);
 
       if ( fctr ) 
        {
          int n_factors = 0;
          int f=0;
          for ( fs = fctr->fs ; *fs ; ++fs ) 
-             ++n_factors;
+           ++n_factors;
 
-         chart_write_title(&ch, _("Boxplot of %s vs. %s"), 
+         chart_write_title(ch, _("Boxplot of %s vs. %s"), 
                            var_to_string(vars[i]), var_to_string(fctr->indep_var[0]) );
 
          for ( fs = fctr->fs ; *fs ; ++fs ) 
@@ -1721,35 +1767,34 @@ box_plot_group(const struct factor *fctr,
              
              const char *s = factor_to_string_concise(fctr, *fs);
 
-             const double box_width = (ch.data_right - ch.data_left) 
+             const double box_width = (ch->data_right - ch->data_left) 
                / (n_factors * 2.0 ) ;
 
              const double box_centre = ( f++ * 2 + 1) * box_width 
-               + ch.data_left;
+               + ch->data_left;
              
-             boxplot_draw_boxplot(&ch,
+             boxplot_draw_boxplot(ch,
                                   box_centre, box_width,
                                   &(*fs)->m[i],
                                   s);
            }
        }
-      else
+      else if ( ch )
        {
-         const double box_width = (ch.data_right - ch.data_left) / 3.0;
-         const double box_centre = (ch.data_right + ch.data_left) / 2.0;
+         const double box_width = (ch->data_right - ch->data_left) / 3.0;
+         const double box_centre = (ch->data_right + ch->data_left) / 2.0;
 
-         chart_write_title(&ch, _("Boxplot"));
+         chart_write_title(ch, _("Boxplot"));
 
-         boxplot_draw_boxplot(&ch,
+         boxplot_draw_boxplot(ch,
                               box_centre,    box_width, 
                               &totals[i],
                               var_to_string(vars[i]) );
          
        }
 
-      chart_finalise(&ch);
+      chart_submit(ch);
     }
-#endif
 }
 
 
@@ -1758,15 +1803,14 @@ box_plot_group(const struct factor *fctr,
 void
 np_plot(const struct metrics *m, const char *factorname)
 {
-#ifndef NO_CHARTS
   int i;
   double yfirst=0, ylast=0;
 
   /* Normal Plot */
-  struct chart np_chart;
+  struct chart *np_chart;
 
   /* Detrended Normal Plot */
-  struct chart dnp_chart;
+  struct chart *dnp_chart;
 
   /* The slope and intercept of the ideal normal probability line */
   const double slope = 1.0 / m->stddev;
@@ -1776,16 +1820,21 @@ np_plot(const struct metrics *m, const char *factorname)
   if ( m->n_data == 0 ) 
     return ; 
 
-  chart_initialise(&np_chart);
-  chart_write_title(&np_chart, _("Normal Q-Q Plot of %s"), factorname);
-  chart_write_xlabel(&np_chart, _("Observed Value"));
-  chart_write_ylabel(&np_chart, _("Expected Normal"));
+  np_chart = chart_create();
+  dnp_chart = chart_create();
+
+  if ( !np_chart || ! dnp_chart ) 
+    return ;
 
-  chart_initialise(&dnp_chart);
-  chart_write_title(&dnp_chart, _("Detrended Normal Q-Q Plot of %s"), 
+  chart_write_title(np_chart, _("Normal Q-Q Plot of %s"), factorname);
+  chart_write_xlabel(np_chart, _("Observed Value"));
+  chart_write_ylabel(np_chart, _("Expected Normal"));
+
+
+  chart_write_title(dnp_chart, _("Detrended Normal Q-Q Plot of %s"), 
                    factorname);
-  chart_write_xlabel(&dnp_chart, _("Observed Value"));
-  chart_write_ylabel(&dnp_chart, _("Dev from Normal"));
+  chart_write_xlabel(dnp_chart, _("Observed Value"));
+  chart_write_ylabel(dnp_chart, _("Dev from Normal"));
 
   yfirst = gsl_cdf_ugaussian_Pinv (m->wvp[0]->rank / ( m->n + 1));
   ylast =  gsl_cdf_ugaussian_Pinv (m->wvp[m->n_data-1]->rank / ( m->n + 1));
@@ -1798,46 +1847,44 @@ np_plot(const struct metrics *m, const char *factorname)
     double x_upper = max(m->max, (ylast  - intercept) / slope) ;
     double slack = (x_upper - x_lower)  * 0.05 ;
 
-    chart_write_xscale(&np_chart, x_lower - slack, x_upper + slack, 5);
+    chart_write_xscale(np_chart, x_lower - slack, x_upper + slack, 5);
 
-    chart_write_xscale(&dnp_chart, m->min, m->max, 5);
+    chart_write_xscale(dnp_chart, m->min, m->max, 5);
 
   }
 
-  chart_write_yscale(&np_chart, yfirst, ylast, 5);
+  chart_write_yscale(np_chart, yfirst, ylast, 5);
 
   {
-  /* We have to cache the detrended data, beacause we need to 
-     find its limits before we can plot it */
-  double *d_data;
-  d_data = xmalloc (m->n_data * sizeof(double));
-  double d_max = -DBL_MAX;
-  double d_min = DBL_MAX;
-  for ( i = 0 ; i < m->n_data; ++i ) 
-    {
-      const double ns = gsl_cdf_ugaussian_Pinv (m->wvp[i]->rank / ( m->n + 1));
+    /* We have to cache the detrended data, beacause we need to 
+       find its limits before we can plot it */
+    double *d_data = xmalloc (m->n_data * sizeof(double));
+    double d_max = -DBL_MAX;
+    double d_min = DBL_MAX;
+    for ( i = 0 ; i < m->n_data; ++i ) 
+      {
+       const double ns = gsl_cdf_ugaussian_Pinv (m->wvp[i]->rank / ( m->n + 1));
 
-      chart_datum(&np_chart, 0, m->wvp[i]->v.f, ns);
+       chart_datum(np_chart, 0, m->wvp[i]->v.f, ns);
 
-      d_data[i] = (m->wvp[i]->v.f - m->mean) / m->stddev  - ns;
+       d_data[i] = (m->wvp[i]->v.f - m->mean) / m->stddev  - ns;
    
-      if ( d_data[i] < d_min ) d_min = d_data[i];
-      if ( d_data[i] > d_max ) d_max = d_data[i];
-    }
-  chart_write_yscale(&dnp_chart, d_min, d_max, 5);
+       if ( d_data[i] < d_min ) d_min = d_data[i];
+       if ( d_data[i] > d_max ) d_max = d_data[i];
+      }
+    chart_write_yscale(dnp_chart, d_min, d_max, 5);
 
-  for ( i = 0 ; i < m->n_data; ++i ) 
-      chart_datum(&dnp_chart, 0, m->wvp[i]->v.f, d_data[i]);
+    for ( i = 0 ; i < m->n_data; ++i ) 
+      chart_datum(dnp_chart, 0, m->wvp[i]->v.f, d_data[i]);
 
-  free(d_data);
+    free(d_data);
   }
 
-  chart_line(&np_chart, slope, intercept, yfirst, ylast , CHART_DIM_Y);
-  chart_line(&dnp_chart, 0, 0, m->min, m->max , CHART_DIM_X);
+  chart_line(np_chart, slope, intercept, yfirst, ylast , CHART_DIM_Y);
+  chart_line(dnp_chart, 0, 0, m->min, m->max , CHART_DIM_X);
 
-  chart_finalise(&np_chart);
-  chart_finalise(&dnp_chart);
-#endif
+  chart_submit(np_chart);
+  chart_submit(dnp_chart);
 }
 
 
@@ -1846,8 +1893,8 @@ np_plot(const struct metrics *m, const char *factorname)
 /* Show the percentiles */
 void
 show_percentiles(struct variable **dependent_var, 
-                 int n_dep_var, 
-                 struct factor *fctr)
+                int n_dep_var, 
+                struct factor *fctr)
 {
   struct tab_table *tbl;
   int i;
@@ -1872,7 +1919,7 @@ show_percentiles(struct variable **dependent_var,
       ptiles = (*fs)->m[0].ptile_hash;
 
       if ( fctr->indep_var[1] )
-         n_heading_columns = 4;
+       n_heading_columns = 4;
     }
   else
     {
@@ -2014,7 +2061,7 @@ show_percentiles(struct variable **dependent_var,
 
 
              populate_percentiles(tbl, n_heading_columns - 1, 
-                               row, &(*fs)->m[i]);
+                                  row, &(*fs)->m[i]);
 
 
              count++ ; 
@@ -2026,8 +2073,8 @@ show_percentiles(struct variable **dependent_var,
       else 
        {
          populate_percentiles(tbl, n_heading_columns - 1, 
-                               i * n_stat_rows * n_factors  + n_heading_rows,
-                               &totals[i]);
+                              i * n_stat_rows * n_factors  + n_heading_rows,
+                              &totals[i]);
        }
 
 
@@ -2136,7 +2183,7 @@ factor_to_string(const struct factor *fctr,
 
 const char *
 factor_to_string_concise(const struct factor *fctr, 
-                struct factor_statistics *fs)
+                        struct factor_statistics *fs)
 
 {