Eliminate unused code in glm.q, regression.q.
[pspp-builds.git] / src / language / stats / glm.q
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2007 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include <gsl/gsl_cdf.h>
20 #include <gsl/gsl_matrix.h>
21 #include <gsl/gsl_vector.h>
22 #include <math.h>
23 #include <stdlib.h>
24
25 #include <data/case.h>
26 #include <data/category.h>
27 #include <data/casegrouper.h>
28 #include <data/casereader.h>
29 #include <data/dictionary.h>
30 #include <data/missing-values.h>
31 #include <data/procedure.h>
32 #include <data/transformations.h>
33 #include <data/value-labels.h>
34 #include <data/variable.h>
35 #include <language/command.h>
36 #include <language/dictionary/split-file.h>
37 #include <language/data-io/file-handle.h>
38 #include <language/lexer/lexer.h>
39 #include <libpspp/compiler.h>
40 #include <libpspp/message.h>
41 #include <math/covariance-matrix.h>
42 #include <math/coefficient.h>
43 #include <math/linreg.h>
44 #include <math/moments.h>
45 #include <output/table.h>
46
47 #include "xalloc.h"
48 #include "gettext.h"
49
50 #define GLM_LARGE_DATA 10000
51
52 /* (headers) */
53
54 /* (specification)
55    "GLM" (glm_):
56    *dependent=custom;
57    by=varlist;
58    with=varlist.
59 */
60 /* (declarations) */
61 /* (functions) */
62 static struct cmd_glm cmd;
63
64 /*
65   Moments for each of the variables used.
66  */
67 struct moments_var
68 {
69   struct moments1 *m;
70   double *weight;
71   double *mean;
72   double *variance;
73   const struct variable *v;
74 };
75
76
77 /*
78   Dependent variable used.
79  */
80 static const struct variable **v_dependent;
81
82 /*
83   Number of dependent variables.
84  */
85 static size_t n_dependent;
86
87 #if 0
88 /*
89   Return value for the procedure.
90  */
91 static int pspp_glm_rc = CMD_SUCCESS;
92 #else
93 int cmd_glm (struct lexer *lexer, struct dataset *ds);
94 #endif
95
96 static bool run_glm (struct casereader *,
97                      struct cmd_glm *,
98                      const struct dataset *);
99
100 int
101 cmd_glm (struct lexer *lexer, struct dataset *ds)
102 {
103   struct casegrouper *grouper;
104   struct casereader *group;
105
106   bool ok;
107
108   if (!parse_glm (lexer, ds, &cmd, NULL))
109     return CMD_FAILURE;
110
111   /* Data pass. */
112   grouper = casegrouper_create_splits (proc_open (ds), dataset_dict (ds));
113   while (casegrouper_get_next_group (grouper, &group))
114     {
115       run_glm (group, &cmd, ds);
116     }
117   ok = casegrouper_destroy (grouper);
118   ok = proc_commit (ds) && ok;
119
120   free (v_dependent);
121   return ok ? CMD_SUCCESS : CMD_FAILURE;
122 }
123
124 /* Parser for the dependent sub command */
125 static int
126 glm_custom_dependent (struct lexer *lexer, struct dataset *ds,
127                       struct cmd_glm *cmd UNUSED, void *aux UNUSED)
128 {
129   const struct dictionary *dict = dataset_dict (ds);
130
131   if ((lex_token (lexer) != T_ID
132        || dict_lookup_var (dict, lex_tokid (lexer)) == NULL)
133       && lex_token (lexer) != T_ALL)
134     return 2;
135
136   if (!parse_variables_const
137       (lexer, dict, &v_dependent, &n_dependent, PV_NONE))
138     {
139       free (v_dependent);
140       return 0;
141     }
142   assert (n_dependent);
143   if (n_dependent > 1)
144     msg (SE, _("Multivariate GLM not yet supported"));
145   n_dependent = 1;              /* Drop this line after adding support for multivariate GLM. */
146
147   return 1;
148 }
149
150 /*
151   COV is the covariance matrix for variables included in the
152   model. That means the dependent variable is in there, too.
153  */
154 static void
155 coeff_init (pspp_linreg_cache * c, struct design_matrix *cov)
156 {
157   c->coeff = xnmalloc (cov->m->size2, sizeof (*c->coeff));
158   c->n_coeffs = cov->m->size2 - 1;
159   pspp_coeff_init (c->coeff, cov);
160 }
161
162 /* Encode categorical variables.
163    Returns number of valid cases. */
164 static int
165 data_pass_one (struct casereader *input,
166                const struct variable **vars, size_t n_vars,
167                struct moments_var **mom)
168 {
169   int n_data;
170   struct ccase c;
171   size_t i;
172
173   for (i = 0; i < n_vars; i++)
174     {
175       mom[i] = xmalloc (sizeof (*mom[i]));
176       mom[i]->v = vars[i];
177       mom[i]->mean = xmalloc (sizeof (*mom[i]->mean));
178       mom[i]->variance = xmalloc (sizeof (*mom[i]->mean));
179       mom[i]->weight = xmalloc (sizeof (*mom[i]->weight));
180       mom[i]->m = moments1_create (MOMENT_VARIANCE);
181       if (var_is_alpha (vars[i]))
182         cat_stored_values_create (vars[i]);
183     }
184
185   n_data = 0;
186   for (; casereader_read (input, &c); case_destroy (&c))
187     {
188       /*
189          The second condition ensures the program will run even if
190          there is only one variable to act as both explanatory and
191          response.
192        */
193       for (i = 0; i < n_vars; i++)
194         {
195           const union value *val = case_data (&c, vars[i]);
196           if (var_is_alpha (vars[i]))
197             cat_value_update (vars[i], val);
198           else
199             moments1_add (mom[i]->m, val->f, 1.0);
200         }
201       n_data++;
202     }
203   casereader_destroy (input);
204   for (i = 0; i < n_vars; i++)
205     {
206       if (var_is_numeric (mom[i]->v))
207         {
208           moments1_calculate (mom[i]->m, mom[i]->weight, mom[i]->mean,
209                               mom[i]->variance, NULL, NULL);
210         }
211     }
212
213   return n_data;
214 }
215
216 static bool
217 run_glm (struct casereader *input,
218          struct cmd_glm *cmd,
219          const struct dataset *ds)
220 {
221   pspp_linreg_cache *model = NULL; 
222   size_t i;
223   size_t j;
224   int n_indep = 0;
225   struct ccase c;
226   const struct variable **indep_vars;
227   const struct variable **all_vars;
228   struct design_matrix *X;
229   struct moments_var **mom;
230   struct casereader *reader;
231   casenumber row;
232   size_t n_all_vars;
233   size_t n_data;                /* Number of valid cases. */
234
235   pspp_linreg_opts lopts;
236
237   if (!casereader_peek (input, 0, &c))
238     {
239       casereader_destroy (input);
240       return true;
241     }
242   output_split_file_values (ds, &c);
243   case_destroy (&c);
244
245   if (!v_dependent)
246     {
247       dict_get_vars (dataset_dict (ds), &v_dependent, &n_dependent,
248                      1u << DC_SYSTEM);
249     }
250
251   lopts.get_depvar_mean_std = 1;
252
253   lopts.get_indep_mean_std = xnmalloc (n_dependent, sizeof (int));
254   indep_vars = xnmalloc (cmd->n_by, sizeof *indep_vars);
255   n_all_vars = cmd->n_by + n_dependent;
256   all_vars = xnmalloc (n_all_vars, sizeof *all_vars);
257
258   for (i = 0; i < n_dependent; i++)
259     {
260       all_vars[i] = v_dependent[i];
261     }
262   for (i = 0; i < cmd->n_by; i++)
263     {
264       indep_vars[i] = cmd->v_by[i];
265       all_vars[i + n_dependent] = cmd->v_by[i];
266     }
267   n_indep = cmd->n_by;
268   mom = xnmalloc (n_all_vars, sizeof (*mom));
269
270
271   reader = casereader_clone (input);
272   reader = casereader_create_filter_missing (reader, indep_vars, n_indep,
273                                              MV_ANY, NULL, NULL);
274   reader = casereader_create_filter_missing (reader, v_dependent, 1,
275                                              MV_ANY, NULL, NULL);
276   n_data = data_pass_one (casereader_clone (reader),
277                           (const struct variable **) all_vars, n_all_vars,
278                           mom);
279
280   if ((n_data > 0) && (n_indep > 0))
281     {
282       for (i = 0; i < n_all_vars; i++)
283         if (var_is_alpha (all_vars[i]))
284           cat_stored_values_create (all_vars[i]);
285       
286       X =
287         covariance_matrix_create (n_all_vars,
288                                   (const struct variable **) all_vars);
289       reader = casereader_create_counter (reader, &row, -1);
290       for (; casereader_read (reader, &c); case_destroy (&c))
291         {
292           /* 
293              Accumulate the covariance matrix.
294            */
295           for (i = 0; i < n_all_vars; ++i)
296             {
297               const struct variable *v = all_vars[i];
298               const union value *val_v = case_data (&c, v);
299               if (var_is_alpha (all_vars[i]))
300                 cat_value_update (all_vars[i], val_v);
301               for (j = i; j < n_all_vars; j++)
302                 {
303                   const struct variable *w = all_vars[j];
304                   const union value *val_w = case_data (&c, w);
305                   covariance_pass_two (X, *mom[i]->mean, *mom[j]->mean,
306                                        (double) n_data,
307                                        v, w, val_v, val_w);
308                 }
309             }
310         }
311       model = pspp_linreg_cache_alloc (v_dependent[0], indep_vars, n_data, n_indep);
312       /*
313         For large data sets, use QR decomposition.
314       */
315       if (n_data > sqrt (n_indep) && n_data > GLM_LARGE_DATA)
316         {
317           model->method = PSPP_LINREG_QR;
318         }
319       coeff_init (model, X);
320       pspp_linreg_with_cov (X, model);
321       casereader_destroy (reader);
322       for (i = 0; i < n_all_vars; i++)
323         {
324           moments1_destroy (mom[i]->m);
325           free (mom[i]->mean);
326           free (mom[i]->variance);
327           free (mom[i]->weight);
328           free (mom[i]);
329         }
330       free (mom);
331       covariance_matrix_destroy (X);
332     }
333   else
334     {
335       msg (SE, gettext ("No valid data found. This command was skipped."));
336     }
337   free (indep_vars);
338   free (lopts.get_indep_mean_std);
339   pspp_linreg_cache_free (model);
340   casereader_destroy (input);
341
342   return true;
343 }
344
345 /*
346   Local Variables:   
347   mode: c
348   End:
349 */