92a1959b659c68c4050481876113fe74dafb0fbd
[pspp] / src / language / stats / glm.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2010, 2011, 2012 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_combination.h>
22 #include <math.h>
23
24 #include "data/case.h"
25 #include "data/casegrouper.h"
26 #include "data/casereader.h"
27 #include "data/dataset.h"
28 #include "data/dictionary.h"
29 #include "data/format.h"
30 #include "data/value.h"
31 #include "language/command.h"
32 #include "language/dictionary/split-file.h"
33 #include "language/lexer/lexer.h"
34 #include "language/lexer/value-parser.h"
35 #include "language/lexer/variable-parser.h"
36 #include "libpspp/assertion.h"
37 #include "libpspp/ll.h"
38 #include "libpspp/message.h"
39 #include "libpspp/misc.h"
40 #include "libpspp/taint.h"
41 #include "linreg/sweep.h"
42 #include "math/categoricals.h"
43 #include "math/covariance.h"
44 #include "math/interaction.h"
45 #include "math/moments.h"
46 #include "output/pivot-table.h"
47
48 #include "gettext.h"
49 #define N_(msgid) msgid
50 #define _(msgid) gettext (msgid)
51
52 struct glm_spec
53 {
54   size_t n_dep_vars;
55   const struct variable **dep_vars;
56
57   size_t n_factor_vars;
58   const struct variable **factor_vars;
59
60   size_t n_interactions;
61   struct interaction **interactions;
62
63   enum mv_class exclude;
64
65   /* The weight variable */
66   const struct variable *wv;
67
68   const struct dictionary *dict;
69
70   int ss_type;
71   bool intercept;
72
73   double alpha;
74
75   bool dump_coding;
76 };
77
78 struct glm_workspace
79 {
80   double total_ssq;
81   struct moments *totals;
82
83   struct categoricals *cats;
84
85   /*
86      Sums of squares due to different variables. Element 0 is the SSE
87      for the entire model. For i > 0, element i is the SS due to
88      variable i.
89    */
90   gsl_vector *ssq;
91 };
92
93
94 /* Default design: all possible interactions */
95 static void
96 design_full (struct glm_spec *glm)
97 {
98   int sz;
99   int i = 0;
100   glm->n_interactions = (1 << glm->n_factor_vars) - 1;
101
102   glm->interactions = xcalloc (glm->n_interactions, sizeof *glm->interactions);
103
104   /* All subsets, with exception of the empty set, of [0, glm->n_factor_vars) */
105   for (sz = 1; sz <= glm->n_factor_vars; ++sz)
106     {
107       gsl_combination *c = gsl_combination_calloc (glm->n_factor_vars, sz);
108
109       do
110         {
111           struct interaction *iact = interaction_create (NULL);
112           int e;
113           for (e = 0 ; e < gsl_combination_k (c); ++e)
114             interaction_add_variable (iact, glm->factor_vars [gsl_combination_get (c, e)]);
115
116           glm->interactions[i++] = iact;
117         }
118       while (gsl_combination_next (c) == GSL_SUCCESS);
119
120       gsl_combination_free (c);
121     }
122 }
123
124 static void output_glm (const struct glm_spec *,
125                         const struct glm_workspace *ws);
126 static void run_glm (struct glm_spec *cmd, struct casereader *input,
127                      const struct dataset *ds);
128
129
130 static bool parse_design_spec (struct lexer *lexer, struct glm_spec *glm);
131
132
133 int
134 cmd_glm (struct lexer *lexer, struct dataset *ds)
135 {
136   int i;
137   struct const_var_set *factors = NULL;
138   struct glm_spec glm;
139   bool design = false;
140   glm.dict = dataset_dict (ds);
141   glm.n_dep_vars = 0;
142   glm.n_factor_vars = 0;
143   glm.n_interactions = 0;
144   glm.interactions = NULL;
145   glm.dep_vars = NULL;
146   glm.factor_vars = NULL;
147   glm.exclude = MV_ANY;
148   glm.intercept = true;
149   glm.wv = dict_get_weight (glm.dict);
150   glm.alpha = 0.05;
151   glm.dump_coding = false;
152   glm.ss_type = 3;
153
154   int dep_vars_start = lex_ofs (lexer);
155   if (!parse_variables_const (lexer, glm.dict,
156                               &glm.dep_vars, &glm.n_dep_vars,
157                               PV_NO_DUPLICATE | PV_NUMERIC))
158     goto error;
159   int dep_vars_end = lex_ofs (lexer) - 1;
160
161   if (! lex_force_match (lexer, T_BY))
162     goto error;
163
164   if (!parse_variables_const (lexer, glm.dict,
165                               &glm.factor_vars, &glm.n_factor_vars,
166                               PV_NO_DUPLICATE | PV_NUMERIC))
167     goto error;
168
169   if (glm.n_dep_vars > 1)
170     {
171       lex_ofs_error (lexer, dep_vars_start, dep_vars_end,
172                      _("Multivariate analysis is not yet implemented"));
173       return CMD_FAILURE;
174     }
175
176   factors =
177     const_var_set_create_from_array (glm.factor_vars, glm.n_factor_vars);
178
179   while (lex_token (lexer) != T_ENDCMD)
180     {
181       lex_match (lexer, T_SLASH);
182
183       if (lex_match_id (lexer, "MISSING"))
184         {
185           lex_match (lexer, T_EQUALS);
186           while (lex_token (lexer) != T_ENDCMD
187                  && lex_token (lexer) != T_SLASH)
188             {
189               if (lex_match_id (lexer, "INCLUDE"))
190                 {
191                   glm.exclude = MV_SYSTEM;
192                 }
193               else if (lex_match_id (lexer, "EXCLUDE"))
194                 {
195                   glm.exclude = MV_ANY;
196                 }
197               else
198                 {
199                   lex_error (lexer, NULL);
200                   goto error;
201                 }
202             }
203         }
204       else if (lex_match_id (lexer, "INTERCEPT"))
205         {
206           lex_match (lexer, T_EQUALS);
207           while (lex_token (lexer) != T_ENDCMD
208                  && lex_token (lexer) != T_SLASH)
209             {
210               if (lex_match_id (lexer, "INCLUDE"))
211                 {
212                   glm.intercept = true;
213                 }
214               else if (lex_match_id (lexer, "EXCLUDE"))
215                 {
216                   glm.intercept = false;
217                 }
218               else
219                 {
220                   lex_error (lexer, NULL);
221                   goto error;
222                 }
223             }
224         }
225       else if (lex_match_id (lexer, "CRITERIA"))
226         {
227           lex_match (lexer, T_EQUALS);
228           if (lex_match_id (lexer, "ALPHA"))
229             {
230               if (lex_force_match (lexer, T_LPAREN))
231                 {
232                   if (! lex_force_num (lexer))
233                     {
234                       lex_error (lexer, NULL);
235                       goto error;
236                     }
237
238                   glm.alpha = lex_number (lexer);
239                   lex_get (lexer);
240                   if (! lex_force_match (lexer, T_RPAREN))
241                     {
242                       lex_error (lexer, NULL);
243                       goto error;
244                     }
245                 }
246             }
247           else
248             {
249               lex_error (lexer, NULL);
250               goto error;
251             }
252         }
253       else if (lex_match_id (lexer, "METHOD"))
254         {
255           lex_match (lexer, T_EQUALS);
256           if (!lex_force_match_id (lexer, "SSTYPE"))
257             {
258               lex_error (lexer, NULL);
259               goto error;
260             }
261
262           if (! lex_force_match (lexer, T_LPAREN))
263             {
264               lex_error (lexer, NULL);
265               goto error;
266             }
267
268           if (!lex_force_int_range (lexer, "SSTYPE", 1, 3))
269             {
270               lex_error (lexer, NULL);
271               goto error;
272             }
273
274           glm.ss_type = lex_integer (lexer);
275           lex_get (lexer);
276
277           if (! lex_force_match (lexer, T_RPAREN))
278             {
279               lex_error (lexer, NULL);
280               goto error;
281             }
282         }
283       else if (lex_match_id (lexer, "DESIGN"))
284         {
285           lex_match (lexer, T_EQUALS);
286
287           if (! parse_design_spec (lexer, &glm))
288             goto error;
289
290           if (glm.n_interactions > 0)
291             design = true;
292         }
293       else if (lex_match_id (lexer, "SHOWCODES"))
294         /* Undocumented debug option */
295         {
296           lex_match (lexer, T_EQUALS);
297
298           glm.dump_coding = true;
299         }
300       else
301         {
302           lex_error (lexer, NULL);
303           goto error;
304         }
305     }
306
307   if (! design)
308     {
309       design_full (&glm);
310     }
311
312   {
313     struct casegrouper *grouper;
314     struct casereader *group;
315     bool ok;
316
317     grouper = casegrouper_create_splits (proc_open (ds), glm.dict);
318     while (casegrouper_get_next_group (grouper, &group))
319       run_glm (&glm, group, ds);
320     ok = casegrouper_destroy (grouper);
321     ok = proc_commit (ds) && ok;
322   }
323
324   const_var_set_destroy (factors);
325   free (glm.factor_vars);
326   for (i = 0 ; i < glm.n_interactions; ++i)
327     interaction_destroy (glm.interactions[i]);
328
329   free (glm.interactions);
330   free (glm.dep_vars);
331
332
333   return CMD_SUCCESS;
334
335 error:
336
337   const_var_set_destroy (factors);
338   free (glm.factor_vars);
339   for (i = 0 ; i < glm.n_interactions; ++i)
340     interaction_destroy (glm.interactions[i]);
341
342   free (glm.interactions);
343   free (glm.dep_vars);
344
345   return CMD_FAILURE;
346 }
347
348 static inline bool
349 not_dropped (size_t j, const bool *ff)
350 {
351   return ! ff[j];
352 }
353
354 static void
355 fill_submatrix (const gsl_matrix * cov, gsl_matrix * submatrix, bool *dropped_f)
356 {
357   size_t i;
358   size_t j;
359   size_t n = 0;
360   size_t m = 0;
361
362   for (i = 0; i < cov->size1; i++)
363     {
364       if (not_dropped (i, dropped_f))
365         {
366           m = 0;
367           for (j = 0; j < cov->size2; j++)
368             {
369               if (not_dropped (j, dropped_f))
370                 {
371                   gsl_matrix_set (submatrix, n, m,
372                                   gsl_matrix_get (cov, i, j));
373                   m++;
374                 }
375             }
376           n++;
377         }
378     }
379 }
380
381
382 /*
383    Type 1 sums of squares.
384    Populate SSQ with the Type 1 sums of squares according to COV
385  */
386 static void
387 ssq_type1 (struct covariance *cov, gsl_vector *ssq, const struct glm_spec *cmd)
388 {
389   const gsl_matrix *cm = covariance_calculate_unnormalized (cov);
390   size_t i;
391   size_t k;
392   bool *model_dropped = XCALLOC (covariance_dim (cov), bool);
393   bool *submodel_dropped = XCALLOC (covariance_dim (cov), bool);
394   const struct categoricals *cats = covariance_get_categoricals (cov);
395
396   size_t n_dropped_model = 0;
397   size_t n_dropped_submodel = 0;
398
399   for (i = cmd->n_dep_vars; i < covariance_dim (cov); i++)
400     {
401       n_dropped_model++;
402       n_dropped_submodel++;
403       model_dropped[i] = true;
404       submodel_dropped[i] = true;
405     }
406
407   for (k = 0; k < cmd->n_interactions; k++)
408     {
409       gsl_matrix *model_cov = NULL;
410       gsl_matrix *submodel_cov = NULL;
411
412       n_dropped_submodel = n_dropped_model;
413       for (i = cmd->n_dep_vars; i < covariance_dim (cov); i++)
414         {
415           submodel_dropped[i] = model_dropped[i];
416         }
417
418       for (i = cmd->n_dep_vars; i < covariance_dim (cov); i++)
419         {
420           const struct interaction * x =
421             categoricals_get_interaction_by_subscript (cats, i - cmd->n_dep_vars);
422
423           if (x == cmd->interactions [k])
424             {
425               model_dropped[i] = false;
426               n_dropped_model--;
427             }
428         }
429
430       model_cov = gsl_matrix_alloc (cm->size1 - n_dropped_model, cm->size2 - n_dropped_model);
431       submodel_cov = gsl_matrix_alloc (cm->size1 - n_dropped_submodel, cm->size2 - n_dropped_submodel);
432
433       fill_submatrix (cm, model_cov,    model_dropped);
434       fill_submatrix (cm, submodel_cov, submodel_dropped);
435
436       reg_sweep (model_cov, 0);
437       reg_sweep (submodel_cov, 0);
438
439       gsl_vector_set (ssq, k + 1,
440                       gsl_matrix_get (submodel_cov, 0, 0) - gsl_matrix_get (model_cov, 0, 0)
441                 );
442
443       gsl_matrix_free (model_cov);
444       gsl_matrix_free (submodel_cov);
445     }
446
447   free (model_dropped);
448   free (submodel_dropped);
449 }
450
451 /*
452    Type 2 sums of squares.
453    Populate SSQ with the Type 2 sums of squares according to COV
454  */
455 static void
456 ssq_type2 (struct covariance *cov, gsl_vector *ssq, const struct glm_spec *cmd)
457 {
458   const gsl_matrix *cm = covariance_calculate_unnormalized (cov);
459   size_t i;
460   size_t k;
461   bool *model_dropped = XCALLOC (covariance_dim (cov), bool);
462   bool *submodel_dropped = XCALLOC (covariance_dim (cov), bool);
463   const struct categoricals *cats = covariance_get_categoricals (cov);
464
465   for (k = 0; k < cmd->n_interactions; k++)
466     {
467       gsl_matrix *model_cov = NULL;
468       gsl_matrix *submodel_cov = NULL;
469       size_t n_dropped_model = 0;
470       size_t n_dropped_submodel = 0;
471       for (i = cmd->n_dep_vars; i < covariance_dim (cov); i++)
472         {
473           const struct interaction * x =
474             categoricals_get_interaction_by_subscript (cats, i - cmd->n_dep_vars);
475
476           model_dropped[i] = false;
477           submodel_dropped[i] = false;
478           if (interaction_is_subset (cmd->interactions [k], x))
479             {
480               assert (n_dropped_submodel < covariance_dim (cov));
481               n_dropped_submodel++;
482               submodel_dropped[i] = true;
483
484               if (cmd->interactions [k]->n_vars < x->n_vars)
485                 {
486                   assert (n_dropped_model < covariance_dim (cov));
487                   n_dropped_model++;
488                   model_dropped[i] = true;
489                 }
490             }
491         }
492
493       model_cov = gsl_matrix_alloc (cm->size1 - n_dropped_model, cm->size2 - n_dropped_model);
494       submodel_cov = gsl_matrix_alloc (cm->size1 - n_dropped_submodel, cm->size2 - n_dropped_submodel);
495
496       fill_submatrix (cm, model_cov,    model_dropped);
497       fill_submatrix (cm, submodel_cov, submodel_dropped);
498
499       reg_sweep (model_cov, 0);
500       reg_sweep (submodel_cov, 0);
501
502       gsl_vector_set (ssq, k + 1,
503                       gsl_matrix_get (submodel_cov, 0, 0) - gsl_matrix_get (model_cov, 0, 0)
504                 );
505
506       gsl_matrix_free (model_cov);
507       gsl_matrix_free (submodel_cov);
508     }
509
510   free (model_dropped);
511   free (submodel_dropped);
512 }
513
514 /*
515    Type 3 sums of squares.
516    Populate SSQ with the Type 2 sums of squares according to COV
517  */
518 static void
519 ssq_type3 (struct covariance *cov, gsl_vector *ssq, const struct glm_spec *cmd)
520 {
521   const gsl_matrix *cm = covariance_calculate_unnormalized (cov);
522   size_t i;
523   size_t k;
524   bool *model_dropped = XCALLOC (covariance_dim (cov), bool);
525   bool *submodel_dropped = XCALLOC (covariance_dim (cov), bool);
526   const struct categoricals *cats = covariance_get_categoricals (cov);
527
528   double ss0;
529   gsl_matrix *submodel_cov = gsl_matrix_alloc (cm->size1, cm->size2);
530   fill_submatrix (cm, submodel_cov, submodel_dropped);
531   reg_sweep (submodel_cov, 0);
532   ss0 = gsl_matrix_get (submodel_cov, 0, 0);
533   gsl_matrix_free (submodel_cov);
534   free (submodel_dropped);
535
536   for (k = 0; k < cmd->n_interactions; k++)
537     {
538       gsl_matrix *model_cov = NULL;
539       size_t n_dropped_model = 0;
540
541       for (i = cmd->n_dep_vars; i < covariance_dim (cov); i++)
542         {
543           const struct interaction * x =
544             categoricals_get_interaction_by_subscript (cats, i - cmd->n_dep_vars);
545
546           model_dropped[i] = false;
547
548           if (cmd->interactions [k] == x)
549             {
550               assert (n_dropped_model < covariance_dim (cov));
551               n_dropped_model++;
552               model_dropped[i] = true;
553             }
554         }
555
556       model_cov = gsl_matrix_alloc (cm->size1 - n_dropped_model, cm->size2 - n_dropped_model);
557
558       fill_submatrix (cm, model_cov,    model_dropped);
559
560       reg_sweep (model_cov, 0);
561
562       gsl_vector_set (ssq, k + 1,
563                       gsl_matrix_get (model_cov, 0, 0) - ss0);
564
565       gsl_matrix_free (model_cov);
566     }
567   free (model_dropped);
568 }
569
570
571
572 //static  void dump_matrix (const gsl_matrix *m);
573
574 static void
575 run_glm (struct glm_spec *cmd, struct casereader *input,
576          const struct dataset *ds)
577 {
578   bool warn_bad_weight = true;
579   int v;
580   struct taint *taint;
581   struct dictionary *dict = dataset_dict (ds);
582   struct casereader *reader;
583   struct ccase *c;
584
585   struct glm_workspace ws;
586   struct covariance *cov;
587
588   input  = casereader_create_filter_missing (input,
589                                              cmd->dep_vars, cmd->n_dep_vars,
590                                              cmd->exclude,
591                                              NULL,  NULL);
592
593   input  = casereader_create_filter_missing (input,
594                                              cmd->factor_vars, cmd->n_factor_vars,
595                                              cmd->exclude,
596                                              NULL,  NULL);
597
598   ws.cats = categoricals_create (cmd->interactions, cmd->n_interactions,
599                                  cmd->wv, MV_ANY);
600
601   cov = covariance_2pass_create (cmd->n_dep_vars, cmd->dep_vars,
602                                  ws.cats, cmd->wv, cmd->exclude, true);
603
604
605   c = casereader_peek (input, 0);
606   if (c == NULL)
607     {
608       casereader_destroy (input);
609       return;
610     }
611   output_split_file_values (ds, c);
612   case_unref (c);
613
614   taint = taint_clone (casereader_get_taint (input));
615
616   ws.totals = moments_create (MOMENT_VARIANCE);
617
618   for (reader = casereader_clone (input);
619        (c = casereader_read (reader)) != NULL; case_unref (c))
620     {
621       double weight = dict_get_case_weight (dict, c, &warn_bad_weight);
622
623       for (v = 0; v < cmd->n_dep_vars; ++v)
624         moments_pass_one (ws.totals, case_num (c, cmd->dep_vars[v]), weight);
625
626       covariance_accumulate_pass1 (cov, c);
627     }
628   casereader_destroy (reader);
629
630   if (cmd->dump_coding)
631     reader = casereader_clone (input);
632   else
633     reader = input;
634
635   for (;
636        (c = casereader_read (reader)) != NULL; case_unref (c))
637     {
638       double weight = dict_get_case_weight (dict, c, &warn_bad_weight);
639
640       for (v = 0; v < cmd->n_dep_vars; ++v)
641         moments_pass_two (ws.totals, case_num (c, cmd->dep_vars[v]), weight);
642
643       covariance_accumulate_pass2 (cov, c);
644     }
645   casereader_destroy (reader);
646
647
648   if (cmd->dump_coding)
649     {
650       struct pivot_table *t = covariance_dump_enc_header (cov);
651       for (reader = input;
652            (c = casereader_read (reader)) != NULL; case_unref (c))
653         {
654           covariance_dump_enc (cov, c, t);
655         }
656
657       pivot_table_submit (t);
658     }
659
660   {
661     const gsl_matrix *ucm = covariance_calculate_unnormalized (cov);
662     gsl_matrix *cm = gsl_matrix_alloc (ucm->size1, ucm->size2);
663     gsl_matrix_memcpy (cm, ucm);
664
665     //    dump_matrix (cm);
666
667     ws.total_ssq = gsl_matrix_get (cm, 0, 0);
668
669     reg_sweep (cm, 0);
670
671     /*
672       Store the overall SSE.
673     */
674     ws.ssq = gsl_vector_alloc (cm->size1);
675     gsl_vector_set (ws.ssq, 0, gsl_matrix_get (cm, 0, 0));
676     switch (cmd->ss_type)
677       {
678       case 1:
679         ssq_type1 (cov, ws.ssq, cmd);
680         break;
681       case 2:
682         ssq_type2 (cov, ws.ssq, cmd);
683         break;
684       case 3:
685         ssq_type3 (cov, ws.ssq, cmd);
686         break;
687       default:
688         NOT_REACHED ();
689         break;
690       }
691     //    dump_matrix (cm);
692     gsl_matrix_free (cm);
693   }
694
695   if (!taint_has_tainted_successor (taint))
696     output_glm (cmd, &ws);
697
698   gsl_vector_free (ws.ssq);
699
700   covariance_destroy (cov);
701   moments_destroy (ws.totals);
702
703   taint_destroy (taint);
704 }
705
706 static void
707 put_glm_row (struct pivot_table *table, int row,
708              double a, double b, double c, double d, double e)
709 {
710   double entries[] = { a, b, c, d, e };
711
712   for (size_t col = 0; col < sizeof entries / sizeof *entries; col++)
713     if (entries[col] != SYSMIS)
714       pivot_table_put2 (table, col, row,
715                         pivot_value_new_number (entries[col]));
716 }
717
718 static void
719 output_glm (const struct glm_spec *cmd, const struct glm_workspace *ws)
720 {
721   struct pivot_table *table = pivot_table_create (
722     N_("Tests of Between-Subjects Effects"));
723
724   pivot_dimension_create (table, PIVOT_AXIS_COLUMN, N_("Statistics"),
725                           (cmd->ss_type == 1 ? N_("Type I Sum Of Squares")
726                            : cmd->ss_type == 2 ? N_("Type II Sum Of Squares")
727                            : N_("Type III Sum Of Squares")), PIVOT_RC_OTHER,
728                           N_("df"), PIVOT_RC_COUNT,
729                           N_("Mean Square"), PIVOT_RC_OTHER,
730                           N_("F"), PIVOT_RC_OTHER,
731                           N_("Sig."), PIVOT_RC_SIGNIFICANCE);
732
733   struct pivot_dimension *source = pivot_dimension_create (
734     table, PIVOT_AXIS_ROW, N_("Source"),
735     cmd->intercept ? N_("Corrected Model") : N_("Model"));
736
737   double n_total, mean;
738   moments_calculate (ws->totals, &n_total, &mean, NULL, NULL, NULL);
739
740   double df_corr = 1.0 + categoricals_df_total (ws->cats);
741
742   double mse = gsl_vector_get (ws->ssq, 0) / (n_total - df_corr);
743   double intercept_ssq = pow2 (mean * n_total) / n_total;
744   if (cmd->intercept)
745     {
746       int row = pivot_category_create_leaf (
747         source->root, pivot_value_new_text (N_("Intercept")));
748
749       /* The intercept for unbalanced models is of limited use and
750          nobody knows how to calculate it properly */
751       if (categoricals_isbalanced (ws->cats))
752         {
753           const double df = 1.0;
754           const double F = intercept_ssq / df / mse;
755           put_glm_row (table, row, intercept_ssq, 1.0, intercept_ssq / df,
756                        F, gsl_cdf_fdist_Q (F, df, n_total - df_corr));
757         }
758     }
759
760   double ssq_effects = 0.0;
761   for (int f = 0; f < cmd->n_interactions; ++f)
762     {
763       double df = categoricals_df (ws->cats, f);
764       double ssq = gsl_vector_get (ws->ssq, f + 1);
765       ssq_effects += ssq;
766       if (!cmd->intercept)
767         {
768           df++;
769           ssq += intercept_ssq;
770         }
771       double F = ssq / df / mse;
772
773       struct string str = DS_EMPTY_INITIALIZER;
774       interaction_to_string (cmd->interactions[f], &str);
775       int row = pivot_category_create_leaf (
776         source->root, pivot_value_new_user_text_nocopy (ds_steal_cstr (&str)));
777
778       put_glm_row (table, row, ssq, df, ssq / df, F,
779                    gsl_cdf_fdist_Q (F, df, n_total - df_corr));
780     }
781
782   {
783     /* Model / Corrected Model */
784     double df = df_corr;
785     double ssq = ws->total_ssq - gsl_vector_get (ws->ssq, 0);
786     if (cmd->intercept)
787       df--;
788     else
789       ssq += intercept_ssq;
790     double F = ssq / df / mse;
791     put_glm_row (table, 0, ssq, df, ssq / df, F,
792                  gsl_cdf_fdist_Q (F, df, n_total - df_corr));
793   }
794
795   {
796     int row = pivot_category_create_leaf (source->root,
797                                           pivot_value_new_text (N_("Error")));
798     const double df = n_total - df_corr;
799     const double ssq = gsl_vector_get (ws->ssq, 0);
800     const double mse = ssq / df;
801     put_glm_row (table, row, ssq, df, mse, SYSMIS, SYSMIS);
802   }
803
804   {
805     int row = pivot_category_create_leaf (source->root,
806                                           pivot_value_new_text (N_("Total")));
807     put_glm_row (table, row, ws->total_ssq + intercept_ssq, n_total,
808                  SYSMIS, SYSMIS, SYSMIS);
809   }
810
811   if (cmd->intercept)
812     {
813       int row = pivot_category_create_leaf (
814         source->root, pivot_value_new_text (N_("Corrected Total")));
815       put_glm_row (table, row, ws->total_ssq, n_total - 1.0, SYSMIS,
816                    SYSMIS, SYSMIS);
817     }
818
819   pivot_table_submit (table);
820 }
821
822 #if 0
823 static void
824 dump_matrix (const gsl_matrix * m)
825 {
826   size_t i, j;
827   for (i = 0; i < m->size1; ++i)
828     {
829       for (j = 0; j < m->size2; ++j)
830         {
831           double x = gsl_matrix_get (m, i, j);
832           printf ("%.3f ", x);
833         }
834       printf ("\n");
835     }
836   printf ("\n");
837 }
838 #endif
839
840
841 \f
842 static bool
843 parse_nested_variable (struct lexer *lexer, struct glm_spec *glm)
844 {
845   const struct variable *v = NULL;
846   if (! lex_match_variable (lexer, glm->dict, &v))
847     return false;
848
849   if (lex_match (lexer, T_LPAREN))
850     {
851       if (! parse_nested_variable (lexer, glm))
852         return false;
853
854       if (! lex_force_match (lexer, T_RPAREN))
855         return false;
856     }
857
858   lex_error (lexer, "Nested variables are not yet implemented");
859   return false;
860 }
861
862 /* A design term is an interaction OR a nested variable */
863 static bool
864 parse_design_term (struct lexer *lexer, struct glm_spec *glm)
865 {
866   struct interaction *iact = NULL;
867   if (parse_design_interaction (lexer, glm->dict, &iact))
868     {
869       /* Interaction parsing successful.  Add to list of interactions */
870       glm->interactions = xrealloc (glm->interactions, sizeof (*glm->interactions) * ++glm->n_interactions);
871       glm->interactions[glm->n_interactions - 1] = iact;
872       return true;
873     }
874
875   if (parse_nested_variable (lexer, glm))
876     return true;
877
878   return false;
879 }
880
881
882
883 /* Parse a complete DESIGN specification.
884    A design spec is a design term, optionally followed by a comma,
885    and another design spec.
886 */
887 static bool
888 parse_design_spec (struct lexer *lexer, struct glm_spec *glm)
889 {
890   if  (lex_token (lexer) == T_ENDCMD || lex_token (lexer) == T_SLASH)
891     return true;
892
893   if (! parse_design_term (lexer, glm))
894     return false;
895
896   lex_match (lexer, T_COMMA);
897
898   return parse_design_spec (lexer, glm);
899 }