ce4f016d99063acabf0dd71abab6d36245229aa3
[pspp] / src / language / stats / oneway.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2007, 2009, 2010 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 <data/case.h>
20 #include <data/casegrouper.h>
21 #include <data/casereader.h>
22
23 #include <libpspp/ll.h>
24
25 #include <language/lexer/lexer.h>
26 #include <language/lexer/variable-parser.h>
27 #include <language/lexer/value-parser.h>
28 #include <language/command.h>
29
30 #include <data/procedure.h>
31 #include <data/dictionary.h>
32
33
34 #include <language/dictionary/split-file.h>
35 #include <libpspp/hash.h>
36 #include <libpspp/taint.h>
37 #include <math/group-proc.h>
38 #include <math/levene.h>
39 #include <libpspp/misc.h>
40
41 #include <output/tab.h>
42
43 #include <gsl/gsl_cdf.h>
44 #include <math.h>
45 #include <data/format.h>
46
47 #include <libpspp/message.h>
48
49 #include "gettext.h"
50 #define _(msgid) gettext (msgid)
51
52 enum missing_type
53   {
54     MISS_LISTWISE,
55     MISS_ANALYSIS,
56   };
57
58 enum statistics
59   {
60     STATS_DESCRIPTIVES = 0x0001,
61     STATS_HOMOGENEITY = 0x0002
62   };
63
64 struct coeff_node
65 {
66   struct ll ll; 
67   double coeff; 
68 };
69
70
71 struct contrasts_node
72 {
73   struct ll ll; 
74   struct ll_list coefficient_list;
75
76   bool bad_count; /* True if the number of coefficients does not equal the number of groups */
77 };
78
79 struct oneway_spec
80 {
81   size_t n_vars;
82   const struct variable **vars;
83
84   const struct dictionary *dict;
85
86   const struct variable *indep_var;
87
88   enum statistics stats;
89
90   enum missing_type missing_type;
91   enum mv_class exclude;
92
93   /* List of contrasts */
94   struct ll_list contrast_list;
95 };
96
97 struct oneway_workspace
98 {
99   /* The number of distinct values of the independent variable, when all
100      missing values are disregarded */
101   int actual_number_of_groups;
102
103   /* A  hash table containing all the distinct values of the independent
104      variable */
105   struct hsh_table *group_hash;
106 };
107
108 /* Routines to show the output tables */
109 static void show_anova_table (const struct oneway_spec *);
110 static void show_descriptives (const struct oneway_spec *, const struct dictionary *dict);
111 static void show_homogeneity (const struct oneway_spec *);
112
113 static void output_oneway (const struct oneway_spec *, struct oneway_workspace *ws);
114 static void run_oneway (const struct oneway_spec *cmd, struct casereader *input, const struct dataset *ds);
115
116 int
117 cmd_oneway (struct lexer *lexer, struct dataset *ds)
118 {
119   struct oneway_spec oneway ;
120   oneway.n_vars = 0;
121   oneway.vars = NULL;
122   oneway.indep_var = NULL;
123   oneway.stats = 0;
124   oneway.missing_type = MISS_ANALYSIS;
125   oneway.exclude = MV_ANY;
126   oneway.dict = dataset_dict (ds);  
127
128   ll_init (&oneway.contrast_list);
129
130   
131   if ( lex_match (lexer, '/'))
132     {
133       if (!lex_force_match_id (lexer, "VARIABLES"))
134         {
135           goto error;
136         }
137       lex_match (lexer, '=');
138     }
139
140   if (!parse_variables_const (lexer, oneway.dict,
141                               &oneway.vars, &oneway.n_vars,
142                               PV_NO_DUPLICATE | PV_NUMERIC))
143     goto error;
144
145   lex_force_match (lexer, T_BY);
146
147   oneway.indep_var = parse_variable_const (lexer, oneway.dict);
148
149   while (lex_token (lexer) != '.')
150     {
151       lex_match (lexer, '/');
152
153       if (lex_match_id (lexer, "STATISTICS"))
154         {
155           lex_match (lexer, '=');
156           while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
157             {
158               if (lex_match_id (lexer, "DESCRIPTIVES"))
159                 {
160                   oneway.stats |= STATS_DESCRIPTIVES;
161                 }
162               else if (lex_match_id (lexer, "HOMOGENEITY"))
163                 {
164                   oneway.stats |= STATS_HOMOGENEITY;
165                 }
166               else
167                 {
168                   lex_error (lexer, NULL);
169                   goto error;
170                 }
171             }
172         }
173       else if (lex_match_id (lexer, "CONTRAST"))
174         {
175           struct contrasts_node *cl = xzalloc (sizeof *cl);
176
177           struct ll_list *coefficient_list = &cl->coefficient_list;
178           lex_match (lexer, '=');
179
180           ll_init (coefficient_list);
181
182           while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
183             {
184               if ( lex_is_number (lexer))
185                 {
186                   struct coeff_node *cc = xmalloc (sizeof *cc);
187                   cc->coeff = lex_number (lexer);
188
189                   ll_push_tail (coefficient_list, &cc->ll);
190                   lex_get (lexer);
191                 }
192               else
193                 {
194                   lex_error (lexer, NULL);
195                   goto error;
196                 }
197             }
198
199           ll_push_tail (&oneway.contrast_list, &cl->ll);
200         }
201       else if (lex_match_id (lexer, "MISSING"))
202         {
203           lex_match (lexer, '=');
204           while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
205             {
206               if (lex_match_id (lexer, "INCLUDE"))
207                 {
208                   oneway.exclude = MV_SYSTEM;
209                 }
210               else if (lex_match_id (lexer, "EXCLUDE"))
211                 {
212                   oneway.exclude = MV_ANY;
213                 }
214               else if (lex_match_id (lexer, "LISTWISE"))
215                 {
216                   oneway.missing_type = MISS_LISTWISE;
217                 }
218               else if (lex_match_id (lexer, "ANALYSIS"))
219                 {
220                   oneway.missing_type = MISS_ANALYSIS;
221                 }
222               else
223                 {
224                   lex_error (lexer, NULL);
225                   goto error;
226                 }
227             }
228         }
229       else
230         {
231           lex_error (lexer, NULL);
232           goto error;
233         }
234     }
235
236
237   {
238     struct casegrouper *grouper;
239     struct casereader *group;
240     bool ok;
241
242     grouper = casegrouper_create_splits (proc_open (ds), oneway.dict);
243     while (casegrouper_get_next_group (grouper, &group))
244       run_oneway (&oneway, group, ds);
245     ok = casegrouper_destroy (grouper);
246     ok = proc_commit (ds) && ok;
247   }
248
249   free (oneway.vars);
250   return CMD_SUCCESS;
251
252  error:
253   free (oneway.vars);
254   return CMD_FAILURE;
255 }
256
257
258 \f
259
260 static int
261 compare_double_3way (const void *a_, const void *b_, const void *aux UNUSED)
262 {
263   const double *a = a_;
264   const double *b = b_;
265   return *a < *b ? -1 : *a > *b;
266 }
267
268 static unsigned
269 do_hash_double (const void *value_, const void *aux UNUSED)
270 {
271   const double *value = value_;
272   return hash_double (*value, 0);
273 }
274
275 static void
276 free_double (void *value_, const void *aux UNUSED)
277 {
278   double *value = value_;
279   free (value);
280 }
281
282 static void postcalc (const struct oneway_spec *cmd);
283 static void  precalc (const struct oneway_spec *cmd);
284
285
286 static void
287 run_oneway (const struct oneway_spec *cmd,
288             struct casereader *input,
289             const struct dataset *ds)
290 {
291   struct taint *taint;
292   struct dictionary *dict = dataset_dict (ds);
293   struct casereader *reader;
294   struct ccase *c;
295
296   struct oneway_workspace ws;
297
298   c = casereader_peek (input, 0);
299   if (c == NULL)
300     {
301       casereader_destroy (input);
302       return;
303     }
304   output_split_file_values (ds, c);
305   case_unref (c);
306
307   taint = taint_clone (casereader_get_taint (input));
308
309   ws.group_hash = hsh_create (4,
310                                   compare_double_3way,
311                                   do_hash_double,
312                                   free_double,
313                                   cmd->indep_var);
314
315   precalc (cmd);
316
317   input = casereader_create_filter_missing (input, &cmd->indep_var, 1,
318                                             cmd->exclude, NULL, NULL);
319   if (cmd->missing_type == MISS_LISTWISE)
320     input = casereader_create_filter_missing (input, cmd->vars, cmd->n_vars,
321                                               cmd->exclude, NULL, NULL);
322   input = casereader_create_filter_weight (input, dict, NULL, NULL);
323
324   reader = casereader_clone (input);
325   for (; (c = casereader_read (reader)) != NULL; case_unref (c))
326     {
327       size_t i;
328
329       const double weight = dict_get_case_weight (dict, c, NULL);
330
331       const union value *indep_val = case_data (c, cmd->indep_var);
332       void **p = hsh_probe (ws.group_hash, &indep_val->f);
333       if (*p == NULL)
334         {
335           double *value = *p = xmalloc (sizeof *value);
336           *value = indep_val->f;
337         }
338
339       for (i = 0; i < cmd->n_vars; ++i)
340         {
341           const struct variable *v = cmd->vars[i];
342
343           const union value *val = case_data (c, v);
344
345           struct group_proc *gp = group_proc_get (cmd->vars[i]);
346           struct hsh_table *group_hash = gp->group_hash;
347
348           struct group_statistics *gs;
349
350           gs = hsh_find (group_hash, indep_val );
351
352           if ( ! gs )
353             {
354               gs = xmalloc (sizeof *gs);
355               gs->id = *indep_val;
356               gs->sum = 0;
357               gs->n = 0;
358               gs->ssq = 0;
359               gs->sum_diff = 0;
360               gs->minimum = DBL_MAX;
361               gs->maximum = -DBL_MAX;
362
363               hsh_insert ( group_hash, gs );
364             }
365
366           if (!var_is_value_missing (v, val, cmd->exclude))
367             {
368               struct group_statistics *totals = &gp->ugs;
369
370               totals->n += weight;
371               totals->sum += weight * val->f;
372               totals->ssq += weight * pow2 (val->f);
373
374               if ( val->f * weight  < totals->minimum )
375                 totals->minimum = val->f * weight;
376
377               if ( val->f * weight  > totals->maximum )
378                 totals->maximum = val->f * weight;
379
380               gs->n += weight;
381               gs->sum += weight * val->f;
382               gs->ssq += weight * pow2 (val->f);
383
384               if ( val->f * weight  < gs->minimum )
385                 gs->minimum = val->f * weight;
386
387               if ( val->f * weight  > gs->maximum )
388                 gs->maximum = val->f * weight;
389             }
390
391           gp->n_groups = hsh_count (group_hash );
392         }
393
394     }
395   casereader_destroy (reader);
396
397   postcalc (cmd);
398
399   if ( cmd->stats & STATS_HOMOGENEITY )
400     levene (dict, casereader_clone (input), cmd->indep_var,
401             cmd->n_vars, cmd->vars, cmd->exclude);
402
403   casereader_destroy (input);
404
405   ws.actual_number_of_groups = hsh_count (ws.group_hash);
406
407   if (!taint_has_tainted_successor (taint))
408     output_oneway (cmd, &ws);
409
410   taint_destroy (taint);
411 }
412
413 /* Pre calculations */
414 static void
415 precalc (const struct oneway_spec *cmd)
416 {
417   size_t i = 0;
418
419   for (i = 0; i < cmd->n_vars; ++i)
420     {
421       struct group_proc *gp = group_proc_get (cmd->vars[i]);
422       struct group_statistics *totals = &gp->ugs;
423
424       /* Create a hash for each of the dependent variables.
425          The hash contains a group_statistics structure,
426          and is keyed by value of the independent variable */
427
428       gp->group_hash = hsh_create (4, compare_group, hash_group,
429                                    (hsh_free_func *) free_group,
430                                    cmd->indep_var);
431
432       totals->sum = 0;
433       totals->n = 0;
434       totals->ssq = 0;
435       totals->sum_diff = 0;
436       totals->maximum = -DBL_MAX;
437       totals->minimum = DBL_MAX;
438     }
439 }
440
441 /* Post calculations for the ONEWAY command */
442 static void
443 postcalc (const struct oneway_spec *cmd)
444 {
445   size_t i = 0;
446
447   for (i = 0; i < cmd->n_vars; ++i)
448     {
449       struct group_proc *gp = group_proc_get (cmd->vars[i]);
450       struct hsh_table *group_hash = gp->group_hash;
451       struct group_statistics *totals = &gp->ugs;
452
453       struct hsh_iterator g;
454       struct group_statistics *gs;
455
456       for (gs =  hsh_first (group_hash, &g);
457            gs != 0;
458            gs = hsh_next (group_hash, &g))
459         {
460           gs->mean = gs->sum / gs->n;
461           gs->s_std_dev = sqrt (gs->ssq / gs->n - pow2 (gs->mean));
462
463           gs->std_dev = sqrt (
464                               gs->n / (gs->n - 1) *
465                               ( gs->ssq / gs->n - pow2 (gs->mean))
466                               );
467
468           gs->se_mean = gs->std_dev / sqrt (gs->n);
469           gs->mean_diff = gs->sum_diff / gs->n;
470         }
471
472       totals->mean = totals->sum / totals->n;
473       totals->std_dev = sqrt (
474                               totals->n / (totals->n - 1) *
475                               (totals->ssq / totals->n - pow2 (totals->mean))
476                               );
477
478       totals->se_mean = totals->std_dev / sqrt (totals->n);
479     }
480 }
481
482 static void show_contrast_coeffs (const struct oneway_spec *cmd, struct oneway_workspace *ws);
483 static void show_contrast_tests (const struct oneway_spec *cmd, struct oneway_workspace *ws);
484
485 static void
486 output_oneway (const struct oneway_spec *cmd, struct oneway_workspace *ws)
487 {
488   size_t i = 0;
489
490   /* Check the sanity of the given contrast values */
491   struct contrasts_node *coeff_list  = NULL;
492   ll_for_each (coeff_list, struct contrasts_node, ll, &cmd->contrast_list)
493     {
494       struct coeff_node *cn = NULL;
495       double sum = 0;
496       struct ll_list *cl = &coeff_list->coefficient_list;
497       ++i;
498
499       if (ll_count (cl) != ws->actual_number_of_groups)
500         {
501           msg (SW,
502                _("Number of contrast coefficients must equal the number of groups"));
503           coeff_list->bad_count = true;
504           continue;
505         }
506
507       ll_for_each (cn, struct coeff_node, ll, cl)
508         sum += cn->coeff;
509
510       if ( sum != 0.0 )
511         msg (SW, _("Coefficients for contrast %zu do not total zero"), i);
512     }
513
514   if (cmd->stats & STATS_DESCRIPTIVES)
515     show_descriptives (cmd, cmd->dict);
516
517   if (cmd->stats & STATS_HOMOGENEITY)
518     show_homogeneity (cmd);
519
520   show_anova_table (cmd);
521
522
523   if (ll_count (&cmd->contrast_list) > 0)
524     {
525       show_contrast_coeffs (cmd, ws);
526       show_contrast_tests (cmd, ws);
527     }
528
529
530   /* Clean up */
531   for (i = 0; i < cmd->n_vars; ++i )
532     {
533       struct hsh_table *group_hash = group_proc_get (cmd->vars[i])->group_hash;
534
535       hsh_destroy (group_hash);
536     }
537
538   hsh_destroy (ws->group_hash);
539 }
540
541
542 /* Show the ANOVA table */
543 static void
544 show_anova_table (const struct oneway_spec *cmd)
545 {
546   size_t i;
547   int n_cols =7;
548   size_t n_rows = cmd->n_vars * 3 + 1;
549
550   struct tab_table *t = tab_create (n_cols, n_rows);
551
552   tab_headers (t, 2, 0, 1, 0);
553
554   tab_box (t,
555            TAL_2, TAL_2,
556            -1, TAL_1,
557            0, 0,
558            n_cols - 1, n_rows - 1);
559
560   tab_hline (t, TAL_2, 0, n_cols - 1, 1 );
561   tab_vline (t, TAL_2, 2, 0, n_rows - 1);
562   tab_vline (t, TAL_0, 1, 0, 0);
563
564   tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Sum of Squares"));
565   tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("df"));
566   tab_text (t, 4, 0, TAB_CENTER | TAT_TITLE, _("Mean Square"));
567   tab_text (t, 5, 0, TAB_CENTER | TAT_TITLE, _("F"));
568   tab_text (t, 6, 0, TAB_CENTER | TAT_TITLE, _("Significance"));
569
570
571   for (i = 0; i < cmd->n_vars; ++i)
572     {
573       struct group_statistics *totals = &group_proc_get (cmd->vars[i])->ugs;
574       struct hsh_table *group_hash = group_proc_get (cmd->vars[i])->group_hash;
575       struct hsh_iterator g;
576       struct group_statistics *gs;
577       double ssa = 0;
578       const char *s = var_to_string (cmd->vars[i]);
579
580       for (gs =  hsh_first (group_hash, &g);
581            gs != 0;
582            gs = hsh_next (group_hash, &g))
583         {
584           ssa += pow2 (gs->sum) / gs->n;
585         }
586
587       ssa -= pow2 (totals->sum) / totals->n;
588
589       tab_text (t, 0, i * 3 + 1, TAB_LEFT | TAT_TITLE, s);
590       tab_text (t, 1, i * 3 + 1, TAB_LEFT | TAT_TITLE, _("Between Groups"));
591       tab_text (t, 1, i * 3 + 2, TAB_LEFT | TAT_TITLE, _("Within Groups"));
592       tab_text (t, 1, i * 3 + 3, TAB_LEFT | TAT_TITLE, _("Total"));
593
594       if (i > 0)
595         tab_hline (t, TAL_1, 0, n_cols - 1, i * 3 + 1);
596
597       {
598         struct group_proc *gp = group_proc_get (cmd->vars[i]);
599         const double sst = totals->ssq - pow2 (totals->sum) / totals->n;
600         const double df1 = gp->n_groups - 1;
601         const double df2 = totals->n - gp->n_groups;
602         const double msa = ssa / df1;
603
604         gp->mse  = (sst - ssa) / df2;
605
606
607         /* Sums of Squares */
608         tab_double (t, 2, i * 3 + 1, 0, ssa, NULL);
609         tab_double (t, 2, i * 3 + 3, 0, sst, NULL);
610         tab_double (t, 2, i * 3 + 2, 0, sst - ssa, NULL);
611
612
613         /* Degrees of freedom */
614         tab_fixed (t, 3, i * 3 + 1, 0, df1, 4, 0);
615         tab_fixed (t, 3, i * 3 + 2, 0, df2, 4, 0);
616         tab_fixed (t, 3, i * 3 + 3, 0, totals->n - 1, 4, 0);
617
618         /* Mean Squares */
619         tab_double (t, 4, i * 3 + 1, TAB_RIGHT, msa, NULL);
620         tab_double (t, 4, i * 3 + 2, TAB_RIGHT, gp->mse, NULL);
621
622         {
623           const double F = msa / gp->mse ;
624
625           /* The F value */
626           tab_double (t, 5, i * 3 + 1, 0,  F, NULL);
627
628           /* The significance */
629           tab_double (t, 6, i * 3 + 1, 0, gsl_cdf_fdist_Q (F, df1, df2), NULL);
630         }
631       }
632     }
633
634
635   tab_title (t, _("ANOVA"));
636   tab_submit (t);
637 }
638
639
640 /* Show the descriptives table */
641 static void
642 show_descriptives (const struct oneway_spec *cmd, const struct dictionary *dict)
643 {
644   size_t v;
645   int n_cols = 10;
646   struct tab_table *t;
647   int row;
648
649   const double confidence = 0.95;
650   const double q = (1.0 - confidence) / 2.0;
651
652   const struct variable *wv = dict_get_weight (dict);
653   const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : & F_8_0;
654
655   int n_rows = 2;
656
657   for ( v = 0; v < cmd->n_vars; ++v )
658     n_rows += group_proc_get (cmd->vars[v])->n_groups + 1;
659
660   t = tab_create (n_cols, n_rows);
661   tab_headers (t, 2, 0, 2, 0);
662
663
664   /* Put a frame around the entire box, and vertical lines inside */
665   tab_box (t,
666            TAL_2, TAL_2,
667            -1, TAL_1,
668            0, 0,
669            n_cols - 1, n_rows - 1);
670
671   /* Underline headers */
672   tab_hline (t, TAL_2, 0, n_cols - 1, 2);
673   tab_vline (t, TAL_2, 2, 0, n_rows - 1);
674
675   tab_text (t, 2, 1, TAB_CENTER | TAT_TITLE, _("N"));
676   tab_text (t, 3, 1, TAB_CENTER | TAT_TITLE, _("Mean"));
677   tab_text (t, 4, 1, TAB_CENTER | TAT_TITLE, _("Std. Deviation"));
678   tab_text (t, 5, 1, TAB_CENTER | TAT_TITLE, _("Std. Error"));
679
680
681   tab_vline (t, TAL_0, 7, 0, 0);
682   tab_hline (t, TAL_1, 6, 7, 1);
683   tab_joint_text_format (t, 6, 0, 7, 0, TAB_CENTER | TAT_TITLE,
684                          _("%g%% Confidence Interval for Mean"),
685                          confidence*100.0);
686
687   tab_text (t, 6, 1, TAB_CENTER | TAT_TITLE, _("Lower Bound"));
688   tab_text (t, 7, 1, TAB_CENTER | TAT_TITLE, _("Upper Bound"));
689
690   tab_text (t, 8, 1, TAB_CENTER | TAT_TITLE, _("Minimum"));
691   tab_text (t, 9, 1, TAB_CENTER | TAT_TITLE, _("Maximum"));
692
693
694   tab_title (t, _("Descriptives"));
695
696
697   row = 2;
698   for (v = 0; v < cmd->n_vars; ++v)
699     {
700       double T;
701       double std_error;
702
703       struct group_proc *gp = group_proc_get (cmd->vars[v]);
704
705       struct group_statistics *gs;
706       struct group_statistics *totals = &gp->ugs;
707
708       const char *s = var_to_string (cmd->vars[v]);
709       const struct fmt_spec *fmt = var_get_print_format (cmd->vars[v]);
710
711       struct group_statistics *const *gs_array =
712         (struct group_statistics *const *) hsh_sort (gp->group_hash);
713       int count = 0;
714
715       tab_text (t, 0, row, TAB_LEFT | TAT_TITLE, s);
716       if ( v > 0)
717         tab_hline (t, TAL_1, 0, n_cols - 1, row);
718
719       for (count = 0; count < hsh_count (gp->group_hash); ++count)
720         {
721           struct string vstr;
722           ds_init_empty (&vstr);
723           gs = gs_array[count];
724
725           var_append_value_name (cmd->indep_var, &gs->id, &vstr);
726
727           tab_text (t, 1, row + count,
728                     TAB_LEFT | TAT_TITLE,
729                     ds_cstr (&vstr));
730
731           ds_destroy (&vstr);
732
733           /* Now fill in the numbers ... */
734
735           tab_fixed (t, 2, row + count, 0, gs->n, 8, 0);
736
737           tab_double (t, 3, row + count, 0, gs->mean, NULL);
738
739           tab_double (t, 4, row + count, 0, gs->std_dev, NULL);
740
741           std_error = gs->std_dev / sqrt (gs->n) ;
742           tab_double (t, 5, row + count, 0,
743                       std_error, NULL);
744
745           /* Now the confidence interval */
746
747           T = gsl_cdf_tdist_Qinv (q, gs->n - 1);
748
749           tab_double (t, 6, row + count, 0,
750                       gs->mean - T * std_error, NULL);
751
752           tab_double (t, 7, row + count, 0,
753                       gs->mean + T * std_error, NULL);
754
755           /* Min and Max */
756
757           tab_double (t, 8, row + count, 0,  gs->minimum, fmt);
758           tab_double (t, 9, row + count, 0,  gs->maximum, fmt);
759         }
760
761       tab_text (t, 1, row + count,
762                 TAB_LEFT | TAT_TITLE, _("Total"));
763
764       tab_double (t, 2, row + count, 0, totals->n, wfmt);
765
766       tab_double (t, 3, row + count, 0, totals->mean, NULL);
767
768       tab_double (t, 4, row + count, 0, totals->std_dev, NULL);
769
770       std_error = totals->std_dev / sqrt (totals->n) ;
771
772       tab_double (t, 5, row + count, 0, std_error, NULL);
773
774       /* Now the confidence interval */
775
776       T = gsl_cdf_tdist_Qinv (q, totals->n - 1);
777
778       tab_double (t, 6, row + count, 0,
779                   totals->mean - T * std_error, NULL);
780
781       tab_double (t, 7, row + count, 0,
782                   totals->mean + T * std_error, NULL);
783
784       /* Min and Max */
785
786       tab_double (t, 8, row + count, 0,  totals->minimum, fmt);
787       tab_double (t, 9, row + count, 0,  totals->maximum, fmt);
788
789       row += gp->n_groups + 1;
790     }
791
792   tab_submit (t);
793 }
794
795 /* Show the homogeneity table */
796 static void
797 show_homogeneity (const struct oneway_spec *cmd)
798 {
799   size_t v;
800   int n_cols = 5;
801   size_t n_rows = cmd->n_vars + 1;
802
803   struct tab_table *t;
804
805
806   t = tab_create (n_cols, n_rows);
807   tab_headers (t, 1, 0, 1, 0);
808
809
810   /* Put a frame around the entire box, and vertical lines inside */
811   tab_box (t,
812            TAL_2, TAL_2,
813            -1, TAL_1,
814            0, 0,
815            n_cols - 1, n_rows - 1);
816
817
818   tab_hline (t, TAL_2, 0, n_cols - 1, 1);
819   tab_vline (t, TAL_2, 1, 0, n_rows - 1);
820
821
822   tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Levene Statistic"));
823   tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("df1"));
824   tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("df2"));
825   tab_text (t, 4, 0, TAB_CENTER | TAT_TITLE, _("Significance"));
826
827   tab_title (t, _("Test of Homogeneity of Variances"));
828
829   for (v = 0; v < cmd->n_vars; ++v)
830     {
831       double F;
832       const struct variable *var = cmd->vars[v];
833       const struct group_proc *gp = group_proc_get (cmd->vars[v]);
834       const char *s = var_to_string (var);
835       const struct group_statistics *totals = &gp->ugs;
836
837       const double df1 = gp->n_groups - 1;
838       const double df2 = totals->n - gp->n_groups;
839
840       tab_text (t, 0, v + 1, TAB_LEFT | TAT_TITLE, s);
841
842       F = gp->levene;
843       tab_double (t, 1, v + 1, TAB_RIGHT, F, NULL);
844       tab_fixed (t, 2, v + 1, TAB_RIGHT, df1, 8, 0);
845       tab_fixed (t, 3, v + 1, TAB_RIGHT, df2, 8, 0);
846
847       /* Now the significance */
848       tab_double (t, 4, v + 1, TAB_RIGHT,gsl_cdf_fdist_Q (F, df1, df2), NULL);
849     }
850
851   tab_submit (t);
852 }
853
854
855 /* Show the contrast coefficients table */
856 static void
857 show_contrast_coeffs (const struct oneway_spec *cmd, struct oneway_workspace *ws)
858 {
859   int c_num = 0;
860   struct ll *cli;
861
862   int n_contrasts = ll_count (&cmd->contrast_list);
863   int n_cols = 2 + ws->actual_number_of_groups;
864   int n_rows = 2 + n_contrasts;
865
866   void *const *group_values;
867
868   struct tab_table *t;
869
870   t = tab_create (n_cols, n_rows);
871   tab_headers (t, 2, 0, 2, 0);
872
873   /* Put a frame around the entire box, and vertical lines inside */
874   tab_box (t,
875            TAL_2, TAL_2,
876            -1, TAL_1,
877            0, 0,
878            n_cols - 1, n_rows - 1);
879
880   tab_box (t,
881            -1, -1,
882            TAL_0, TAL_0,
883            2, 0,
884            n_cols - 1, 0);
885
886   tab_box (t,
887            -1, -1,
888            TAL_0, TAL_0,
889            0, 0,
890            1, 1);
891
892   tab_hline (t, TAL_1, 2, n_cols - 1, 1);
893   tab_hline (t, TAL_2, 0, n_cols - 1, 2);
894
895   tab_vline (t, TAL_2, 2, 0, n_rows - 1);
896
897   tab_title (t, _("Contrast Coefficients"));
898
899   tab_text (t,  0, 2, TAB_LEFT | TAT_TITLE, _("Contrast"));
900
901
902   tab_joint_text (t, 2, 0, n_cols - 1, 0, TAB_CENTER | TAT_TITLE,
903                   var_to_string (cmd->indep_var));
904
905   group_values = hsh_sort (ws->group_hash);
906
907   for ( cli = ll_head (&cmd->contrast_list);
908         cli != ll_null (&cmd->contrast_list);
909         cli = ll_next (cli))
910     {
911       int count = 0;
912       struct contrasts_node *cn = ll_data (cli, struct contrasts_node, ll);
913       struct ll *coeffi = ll_head (&cn->coefficient_list);
914
915       tab_text_format (t, 1, c_num + 2, TAB_CENTER, "%d", c_num + 1);
916
917       for (count = 0;
918            count < hsh_count (ws->group_hash) && coeffi != ll_null (&cn->coefficient_list);
919            ++count)
920         {
921           double *group_value_p;
922           union value group_value;
923           struct string vstr;
924
925           ds_init_empty (&vstr);
926
927           group_value_p = group_values[count];
928           group_value.f = *group_value_p;
929           var_append_value_name (cmd->indep_var, &group_value, &vstr);
930
931           tab_text (t, count + 2, 1, TAB_CENTER | TAT_TITLE, ds_cstr (&vstr));
932
933           ds_destroy (&vstr);
934
935           if (cn->bad_count)
936             tab_text (t, count + 2, c_num + 2, TAB_RIGHT, "?" );
937           else
938             {
939               struct coeff_node *coeffn = ll_data (coeffi, struct coeff_node, ll);
940
941               tab_text_format (t, count + 2, c_num + 2, TAB_RIGHT, "%g", coeffn->coeff);
942             }
943
944           coeffi = ll_next (coeffi);
945         }
946       ++c_num;
947     }
948
949   tab_submit (t);
950 }
951
952
953 /* Show the results of the contrast tests */
954 static void
955 show_contrast_tests (const struct oneway_spec *cmd, struct oneway_workspace *ws)
956 {
957   int n_contrasts = ll_count (&cmd->contrast_list);
958   size_t v;
959   int n_cols = 8;
960   size_t n_rows = 1 + cmd->n_vars * 2 * n_contrasts;
961
962   struct tab_table *t;
963
964   t = tab_create (n_cols, n_rows);
965   tab_headers (t, 3, 0, 1, 0);
966
967   /* Put a frame around the entire box, and vertical lines inside */
968   tab_box (t,
969            TAL_2, TAL_2,
970            -1, TAL_1,
971            0, 0,
972            n_cols - 1, n_rows - 1);
973
974   tab_box (t,
975            -1, -1,
976            TAL_0, TAL_0,
977            0, 0,
978            2, 0);
979
980   tab_hline (t, TAL_2, 0, n_cols - 1, 1);
981   tab_vline (t, TAL_2, 3, 0, n_rows - 1);
982
983
984   tab_title (t, _("Contrast Tests"));
985
986   tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Contrast"));
987   tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Value of Contrast"));
988   tab_text (t,  4, 0, TAB_CENTER | TAT_TITLE, _("Std. Error"));
989   tab_text (t,  5, 0, TAB_CENTER | TAT_TITLE, _("t"));
990   tab_text (t,  6, 0, TAB_CENTER | TAT_TITLE, _("df"));
991   tab_text (t,  7, 0, TAB_CENTER | TAT_TITLE, _("Sig. (2-tailed)"));
992
993   for (v = 0; v < cmd->n_vars; ++v)
994     {
995       struct ll *cli;
996       int i = 0;
997       int lines_per_variable = 2 * n_contrasts;
998
999       tab_text (t,  0, (v * lines_per_variable) + 1, TAB_LEFT | TAT_TITLE,
1000                 var_to_string (cmd->vars[v]));
1001
1002       for ( cli = ll_head (&cmd->contrast_list);
1003             cli != ll_null (&cmd->contrast_list);
1004             ++i, cli = ll_next (cli))
1005         {
1006           struct contrasts_node *cn = ll_data (cli, struct contrasts_node, ll);
1007           struct ll *coeffi = ll_head (&cn->coefficient_list);
1008           int ci;
1009           double contrast_value = 0.0;
1010           double coef_msq = 0.0;
1011           struct group_proc *grp_data = group_proc_get (cmd->vars[v]);
1012           struct hsh_table *group_hash = grp_data->group_hash;
1013
1014           void *const *group_stat_array;
1015
1016           double T;
1017           double std_error_contrast;
1018           double df;
1019           double sec_vneq = 0.0;
1020
1021           /* Note: The calculation of the degrees of freedom in the
1022              "variances not equal" case is painfull!!
1023              The following formula may help to understand it:
1024              \frac{\left (\sum_{i=1}^k{c_i^2\frac{s_i^2}{n_i}}\right)^2}
1025              {
1026              \sum_{i=1}^k\left (
1027              \frac{\left (c_i^2\frac{s_i^2}{n_i}\right)^2}  {n_i-1}
1028              \right)
1029              }
1030           */
1031
1032           double df_denominator = 0.0;
1033           double df_numerator = 0.0;
1034           if ( i == 0 )
1035             {
1036               tab_text (t,  1, (v * lines_per_variable) + i + 1,
1037                         TAB_LEFT | TAT_TITLE,
1038                         _("Assume equal variances"));
1039
1040               tab_text (t,  1, (v * lines_per_variable) + i + 1 + n_contrasts,
1041                         TAB_LEFT | TAT_TITLE,
1042                         _("Does not assume equal"));
1043             }
1044
1045           tab_text_format (t,  2, (v * lines_per_variable) + i + 1,
1046                            TAB_CENTER | TAT_TITLE, "%d", i + 1);
1047
1048
1049           tab_text_format (t,  2,
1050                            (v * lines_per_variable) + i + 1 + n_contrasts,
1051                            TAB_CENTER | TAT_TITLE, "%d", i + 1);
1052
1053           if (cn->bad_count)
1054             continue;
1055
1056           group_stat_array = hsh_sort (group_hash);
1057
1058           for (ci = 0;
1059                coeffi != ll_null (&cn->coefficient_list) && 
1060                  ci < hsh_count (group_hash);
1061                ++ci, coeffi = ll_next (coeffi))
1062             {
1063               struct coeff_node *cn = ll_data (coeffi, struct coeff_node, ll);
1064               const double coef = cn->coeff; 
1065               struct group_statistics *gs = group_stat_array[ci];
1066
1067               const double winv = pow2 (gs->std_dev) / gs->n;
1068
1069               contrast_value += coef * gs->mean;
1070
1071               coef_msq += (coef * coef) / gs->n;
1072
1073               sec_vneq += (coef * coef) * pow2 (gs->std_dev) /gs->n;
1074
1075               df_numerator += (coef * coef) * winv;
1076               df_denominator += pow2((coef * coef) * winv) / (gs->n - 1);
1077             }
1078
1079           sec_vneq = sqrt (sec_vneq);
1080
1081           df_numerator = pow2 (df_numerator);
1082
1083           tab_double (t,  3, (v * lines_per_variable) + i + 1,
1084                       TAB_RIGHT, contrast_value, NULL);
1085
1086           tab_double (t,  3, (v * lines_per_variable) + i + 1 +
1087                       n_contrasts,
1088                       TAB_RIGHT, contrast_value, NULL);
1089
1090           std_error_contrast = sqrt (grp_data->mse * coef_msq);
1091
1092           /* Std. Error */
1093           tab_double (t,  4, (v * lines_per_variable) + i + 1,
1094                       TAB_RIGHT, std_error_contrast,
1095                       NULL);
1096
1097           T = fabs (contrast_value / std_error_contrast);
1098
1099           /* T Statistic */
1100
1101           tab_double (t,  5, (v * lines_per_variable) + i + 1,
1102                       TAB_RIGHT, T,
1103                       NULL);
1104
1105           df = grp_data->ugs.n - grp_data->n_groups;
1106
1107           /* Degrees of Freedom */
1108           tab_fixed (t,  6, (v * lines_per_variable) + i + 1,
1109                      TAB_RIGHT,  df,
1110                      8, 0);
1111
1112
1113           /* Significance TWO TAILED !!*/
1114           tab_double (t,  7, (v * lines_per_variable) + i + 1,
1115                       TAB_RIGHT,  2 * gsl_cdf_tdist_Q (T, df),
1116                       NULL);
1117
1118           /* Now for the Variances NOT Equal case */
1119
1120           /* Std. Error */
1121           tab_double (t,  4,
1122                       (v * lines_per_variable) + i + 1 + n_contrasts,
1123                       TAB_RIGHT, sec_vneq,
1124                       NULL);
1125
1126           T = contrast_value / sec_vneq;
1127           tab_double (t,  5,
1128                       (v * lines_per_variable) + i + 1 + n_contrasts,
1129                       TAB_RIGHT, T,
1130                       NULL);
1131
1132           df = df_numerator / df_denominator;
1133
1134           tab_double (t,  6,
1135                       (v * lines_per_variable) + i + 1 + n_contrasts,
1136                       TAB_RIGHT, df,
1137                       NULL);
1138
1139           /* The Significance */
1140           tab_double (t, 7, (v * lines_per_variable) + i + 1 + n_contrasts,
1141                       TAB_RIGHT,  2 * gsl_cdf_tdist_Q (T,df),
1142                       NULL);
1143         }
1144
1145       if ( v > 0 )
1146         tab_hline (t, TAL_1, 0, n_cols - 1, (v * lines_per_variable) + 1);
1147     }
1148
1149   tab_submit (t);
1150 }
1151
1152