categoricals: Make parameter to categoricals_done() const.
[pspp-builds.git] / src / language / stats / reliability.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 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 <math.h>
20
21 #include <libpspp/misc.h>
22
23 #include <libpspp/str.h>
24 #include <libpspp/message.h>
25
26
27 #include <data/procedure.h>
28 #include <data/missing-values.h>
29 #include <data/casereader.h>
30 #include <data/casegrouper.h>
31 #include <data/dictionary.h>
32 #include <data/format.h>
33
34 #include <language/lexer/variable-parser.h>
35 #include <language/command.h>
36 #include <language/lexer/lexer.h>
37
38 #include <math/moments.h>
39 #include <output/tab.h>
40 #include <output/text-item.h>
41
42 #include "gettext.h"
43 #define _(msgid) gettext (msgid)
44 #define N_(msgid) msgid
45
46 struct cronbach
47 {
48   const struct variable **items;
49   size_t n_items;
50   double alpha;
51   double sum_of_variances;
52   double variance_of_sums;
53   int totals_idx;          /* Casereader index into the totals */
54
55   struct moments1 **m ;    /* Moments of the items */
56   struct moments1 *total ; /* Moments of the totals */
57 };
58
59 #if 0
60 static void
61 dump_cronbach (const struct cronbach *s)
62 {
63   int i;
64   printf ("N items %d\n", s->n_items);
65   for (i = 0 ; i < s->n_items; ++i)
66     {
67       printf ("%s\n", var_get_name (s->items[i]));
68     }
69
70   printf ("Totals idx %d\n", s->totals_idx);
71
72   printf ("scale variance %g\n", s->variance_of_sums);
73   printf ("alpha %g\n", s->alpha);
74   putchar ('\n');
75 }
76 #endif
77
78 enum model
79   {
80     MODEL_ALPHA,
81     MODEL_SPLIT
82   };
83
84
85 enum summary_opts
86   {
87     SUMMARY_TOTAL = 0x0001,
88   };
89
90
91 struct reliability
92 {
93   const struct variable **variables;
94   size_t n_variables;
95   enum mv_class exclude;
96
97   struct cronbach *sc;
98   int n_sc;
99
100   int total_start;
101
102   struct string scale_name;
103
104   enum model model;
105   int split_point;
106
107
108   enum summary_opts summary;
109
110   const struct variable *wv;
111 };
112
113
114 static bool run_reliability (struct dataset *ds, const struct reliability *reliability);
115
116 int
117 cmd_reliability (struct lexer *lexer, struct dataset *ds)
118 {
119   const struct dictionary *dict = dataset_dict (ds);
120
121   struct reliability reliability;
122   reliability.n_variables = 0;
123   reliability.variables = NULL;
124   reliability.model = MODEL_ALPHA;
125     reliability.exclude = MV_ANY;
126   reliability.summary = 0;
127
128   reliability.wv = dict_get_weight (dict);
129
130   reliability.total_start = 0;
131
132   lex_match (lexer, T_SLASH);
133
134   if (!lex_force_match_id (lexer, "VARIABLES"))
135     {
136       goto error;
137     }
138
139   lex_match (lexer, T_EQUALS);
140
141   if (!parse_variables_const (lexer, dict, &reliability.variables, &reliability.n_variables,
142                               PV_NO_DUPLICATE | PV_NUMERIC))
143     goto error;
144
145   if (reliability.n_variables < 2)
146     msg (MW, _("Reliability on a single variable is not useful."));
147
148
149     {
150       int i;
151       struct cronbach *c;
152       /* Create a default Scale */
153
154       reliability.n_sc = 1;
155       reliability.sc = xzalloc (sizeof (struct cronbach) * reliability.n_sc);
156
157       ds_init_cstr (&reliability.scale_name, "ANY");
158
159       c = &reliability.sc[0];
160       c->n_items = reliability.n_variables;
161       c->items = xzalloc (sizeof (struct variable*) * c->n_items);
162
163       for (i = 0 ; i < c->n_items ; ++i)
164         c->items[i] = reliability.variables[i];
165     }
166
167
168
169   while (lex_token (lexer) != T_ENDCMD)
170     {
171       lex_match (lexer, T_SLASH);
172
173       if (lex_match_id (lexer, "SCALE"))
174         {
175           struct const_var_set *vs;
176           if ( ! lex_force_match (lexer, T_LPAREN))
177             goto error;
178
179           if ( ! lex_force_string (lexer) ) 
180             goto error;
181
182           ds_init_substring (&reliability.scale_name, lex_tokss (lexer));
183
184           lex_get (lexer);
185
186           if ( ! lex_force_match (lexer, T_RPAREN))
187             goto error;
188
189           lex_match (lexer, T_EQUALS);
190
191           vs = const_var_set_create_from_array (reliability.variables, reliability.n_variables);
192
193
194           if (!parse_const_var_set_vars (lexer, vs, &reliability.sc->items, &reliability.sc->n_items, 0))
195             {
196               const_var_set_destroy (vs);
197               goto error;
198             }
199
200           const_var_set_destroy (vs);
201         }
202       else if (lex_match_id (lexer, "MODEL"))
203         {
204           lex_match (lexer, T_EQUALS);
205           if (lex_match_id (lexer, "ALPHA"))
206             {
207               reliability.model = MODEL_ALPHA;
208             }
209           else if (lex_match_id (lexer, "SPLIT"))
210             {
211               reliability.model = MODEL_SPLIT;
212               reliability.split_point = -1;
213
214               if ( lex_match (lexer, T_LPAREN))
215                 {
216                   lex_force_num (lexer);
217                   reliability.split_point = lex_number (lexer);
218                   lex_get (lexer);
219                   lex_force_match (lexer, T_RPAREN);
220                 }
221             }
222           else
223             goto error;
224         }
225       else if (lex_match_id (lexer, "SUMMARY"))
226         {
227           lex_match (lexer, T_EQUALS);
228           if (lex_match_id (lexer, "TOTAL"))
229             {
230               reliability.summary |= SUMMARY_TOTAL;
231             }
232           else if (lex_match (lexer, T_ALL))
233             {
234               reliability.summary = 0xFFFF;
235             }
236           else
237             goto error;
238         }
239       else if (lex_match_id (lexer, "MISSING"))
240         {
241           lex_match (lexer, T_EQUALS);
242           while (lex_token (lexer) != T_ENDCMD && lex_token (lexer) != T_SLASH)
243             {
244               if (lex_match_id (lexer, "INCLUDE"))
245                 {
246                   reliability.exclude = MV_SYSTEM;
247                 }
248               else if (lex_match_id (lexer, "EXCLUDE"))
249                 {
250                   reliability.exclude = MV_ANY;
251                 }
252               else
253                 {
254                   lex_error (lexer, NULL);
255                   goto error;
256                 }
257             }
258         }
259       else
260         {
261           lex_error (lexer, NULL);
262           goto error;
263         }
264     }
265
266   if ( reliability.model == MODEL_SPLIT)
267     {
268       int i;
269       const struct cronbach *s;
270
271       reliability.n_sc += 2 ;
272       reliability.sc = xrealloc (reliability.sc, sizeof (struct cronbach) * reliability.n_sc);
273
274       s = &reliability.sc[0];
275
276       reliability.sc[1].n_items =
277         (reliability.split_point == -1) ? s->n_items / 2 : reliability.split_point;
278
279       reliability.sc[2].n_items = s->n_items - reliability.sc[1].n_items;
280       reliability.sc[1].items = xzalloc (sizeof (struct variable *)
281                                  * reliability.sc[1].n_items);
282
283       reliability.sc[2].items = xzalloc (sizeof (struct variable *) *
284                                  reliability.sc[2].n_items);
285
286       for  (i = 0; i < reliability.sc[1].n_items ; ++i)
287         reliability.sc[1].items[i] = s->items[i];
288
289       while (i < s->n_items)
290         {
291           reliability.sc[2].items[i - reliability.sc[1].n_items] = s->items[i];
292           i++;
293         }
294     }
295
296   if ( reliability.summary & SUMMARY_TOTAL)
297     {
298       int i;
299       const int base_sc = reliability.n_sc;
300
301       reliability.total_start = base_sc;
302
303       reliability.n_sc +=  reliability.sc[0].n_items ;
304       reliability.sc = xrealloc (reliability.sc, sizeof (struct cronbach) * reliability.n_sc);
305
306
307       for (i = 0 ; i < reliability.sc[0].n_items; ++i )
308         {
309           int v_src;
310           int v_dest = 0;
311           struct cronbach *s = &reliability.sc[i + base_sc];
312
313           s->n_items = reliability.sc[0].n_items - 1;
314           s->items = xzalloc (sizeof (struct variable *) * s->n_items);
315           for (v_src = 0 ; v_src < reliability.sc[0].n_items ; ++v_src)
316             {
317               if ( v_src != i)
318                 s->items[v_dest++] = reliability.sc[0].items[v_src];
319             }
320         }
321     }
322
323
324   if ( ! run_reliability (ds, &reliability)) 
325     goto error;
326
327   free (reliability.variables);
328   return CMD_SUCCESS;
329
330  error:
331   free (reliability.variables);
332   return CMD_FAILURE;
333 }
334
335
336 static void
337 do_reliability (struct casereader *group, struct dataset *ds,
338                 const struct reliability *rel);
339
340
341 static void reliability_summary_total (const struct reliability *rel);
342
343 static void reliability_statistics (const struct reliability *rel);
344
345
346 static bool
347 run_reliability (struct dataset *ds, const struct reliability *reliability)
348 {
349   struct dictionary *dict = dataset_dict (ds);
350   bool ok;
351   struct casereader *group;
352
353   struct casegrouper *grouper = casegrouper_create_splits (proc_open (ds), dict);
354
355
356   while (casegrouper_get_next_group (grouper, &group))
357     {
358       do_reliability (group, ds, reliability);
359
360       reliability_statistics (reliability);
361
362       if (reliability->summary & SUMMARY_TOTAL )
363         reliability_summary_total (reliability);
364     }
365
366   ok = casegrouper_destroy (grouper);
367   ok = proc_commit (ds) && ok;
368
369   return ok;
370 }
371
372
373 \f
374
375
376 /* Return the sum of all the item variables in S */
377 static  double
378 append_sum (const struct ccase *c, casenumber n UNUSED, void *aux)
379 {
380   double sum = 0;
381   const struct cronbach *s = aux;
382
383   int v;
384   for (v = 0 ; v < s->n_items; ++v)
385     {
386       sum += case_data (c, s->items[v])->f;
387     }
388
389   return sum;
390 };
391
392 static void
393 case_processing_summary (casenumber n_valid, casenumber n_missing,
394                          const struct dictionary *dict);
395
396
397 static double
398 alpha (int k, double sum_of_variances, double variance_of_sums)
399 {
400   return k / ( k - 1.0) * ( 1 - sum_of_variances / variance_of_sums);
401 }
402
403 static void
404 do_reliability (struct casereader *input, struct dataset *ds,
405                 const struct reliability *rel)
406 {
407   int i;
408   int si;
409   struct ccase *c;
410   casenumber n_missing ;
411   casenumber n_valid = 0;
412
413
414   for (si = 0 ; si < rel->n_sc; ++si)
415     {
416       struct cronbach *s = &rel->sc[si];
417
418       s->m = xzalloc (sizeof (s->m) * s->n_items);
419       s->total = moments1_create (MOMENT_VARIANCE);
420
421       for (i = 0 ; i < s->n_items ; ++i )
422         s->m[i] = moments1_create (MOMENT_VARIANCE);
423     }
424
425   input = casereader_create_filter_missing (input,
426                                             rel->variables,
427                                             rel->n_variables,
428                                             rel->exclude,
429                                             &n_missing,
430                                             NULL);
431
432   for (si = 0 ; si < rel->n_sc; ++si)
433     {
434       struct cronbach *s = &rel->sc[si];
435
436
437       s->totals_idx = caseproto_get_n_widths (casereader_get_proto (input));
438       input =
439         casereader_create_append_numeric (input, append_sum,
440                                           s, NULL);
441     }
442
443   for (; (c = casereader_read (input)) != NULL; case_unref (c))
444     {
445       double weight = 1.0;
446       n_valid ++;
447
448       for (si = 0; si < rel->n_sc; ++si)
449         {
450           struct cronbach *s = &rel->sc[si];
451
452           for (i = 0 ; i < s->n_items ; ++i )
453             moments1_add (s->m[i], case_data (c, s->items[i])->f, weight);
454
455           moments1_add (s->total, case_data_idx (c, s->totals_idx)->f, weight);
456         }
457     }
458   casereader_destroy (input);
459
460   for (si = 0; si < rel->n_sc; ++si)
461     {
462       struct cronbach *s = &rel->sc[si];
463
464       s->sum_of_variances = 0;
465       for (i = 0 ; i < s->n_items ; ++i )
466         {
467           double weight, mean, variance;
468           moments1_calculate (s->m[i], &weight, &mean, &variance, NULL, NULL);
469
470           s->sum_of_variances += variance;
471         }
472
473       moments1_calculate (s->total, NULL, NULL, &s->variance_of_sums,
474                           NULL, NULL);
475
476       s->alpha =
477         alpha (s->n_items, s->sum_of_variances, s->variance_of_sums);
478     }
479
480   text_item_submit (text_item_create_format (TEXT_ITEM_PARAGRAPH, "Scale: %s",
481                                              ds_cstr (&rel->scale_name)));
482
483   case_processing_summary (n_valid, n_missing, dataset_dict (ds));
484 }
485
486
487
488
489
490 static void
491 case_processing_summary (casenumber n_valid, casenumber n_missing,
492                          const struct dictionary *dict)
493 {
494   const struct variable *wv = dict_get_weight (dict);
495   const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : & F_8_0;
496
497   casenumber total;
498   int n_cols = 4;
499   int n_rows = 4;
500   int heading_columns = 2;
501   int heading_rows = 1;
502   struct tab_table *tbl;
503   tbl = tab_create (n_cols, n_rows);
504   tab_headers (tbl, heading_columns, 0, heading_rows, 0);
505
506   tab_title (tbl, _("Case Processing Summary"));
507
508   /* Vertical lines for the data only */
509   tab_box (tbl,
510            -1, -1,
511            -1, TAL_1,
512            heading_columns, 0,
513            n_cols - 1, n_rows - 1);
514
515   /* Box around table */
516   tab_box (tbl,
517            TAL_2, TAL_2,
518            -1, -1,
519            0, 0,
520            n_cols - 1, n_rows - 1);
521
522
523   tab_hline (tbl, TAL_2, 0, n_cols - 1, heading_rows);
524
525   tab_vline (tbl, TAL_2, heading_columns, 0, n_rows - 1);
526
527
528   tab_text (tbl, 0, heading_rows, TAB_LEFT | TAT_TITLE,
529                 _("Cases"));
530
531   tab_text (tbl, 1, heading_rows, TAB_LEFT | TAT_TITLE,
532                 _("Valid"));
533
534   tab_text (tbl, 1, heading_rows + 1, TAB_LEFT | TAT_TITLE,
535                 _("Excluded"));
536
537   tab_text (tbl, 1, heading_rows + 2, TAB_LEFT | TAT_TITLE,
538                 _("Total"));
539
540   tab_text (tbl, heading_columns, 0, TAB_CENTER | TAT_TITLE,
541                 _("N"));
542
543   tab_text (tbl, heading_columns + 1, 0, TAB_CENTER | TAT_TITLE, _("%"));
544
545   total = n_missing + n_valid;
546
547   tab_double (tbl, 2, heading_rows, TAB_RIGHT,
548              n_valid, wfmt);
549
550
551   tab_double (tbl, 2, heading_rows + 1, TAB_RIGHT,
552              n_missing, wfmt);
553
554
555   tab_double (tbl, 2, heading_rows + 2, TAB_RIGHT,
556              total, wfmt);
557
558
559   tab_double (tbl, 3, heading_rows, TAB_RIGHT,
560              100 * n_valid / (double) total, NULL);
561
562
563   tab_double (tbl, 3, heading_rows + 1, TAB_RIGHT,
564              100 * n_missing / (double) total, NULL);
565
566
567   tab_double (tbl, 3, heading_rows + 2, TAB_RIGHT,
568              100 * total / (double) total, NULL);
569
570
571   tab_submit (tbl);
572 }
573
574
575
576 static void
577 reliability_summary_total (const struct reliability *rel)
578 {
579   int i;
580   const int n_cols = 5;
581   const int heading_columns = 1;
582   const int heading_rows = 1;
583   const int n_rows = rel->sc[0].n_items + heading_rows ;
584
585   struct tab_table *tbl = tab_create (n_cols, n_rows);
586   tab_headers (tbl, heading_columns, 0, heading_rows, 0);
587
588   tab_title (tbl, _("Item-Total Statistics"));
589
590   /* Vertical lines for the data only */
591   tab_box (tbl,
592            -1, -1,
593            -1, TAL_1,
594            heading_columns, 0,
595            n_cols - 1, n_rows - 1);
596
597   /* Box around table */
598   tab_box (tbl,
599            TAL_2, TAL_2,
600            -1, -1,
601            0, 0,
602            n_cols - 1, n_rows - 1);
603
604
605   tab_hline (tbl, TAL_2, 0, n_cols - 1, heading_rows);
606
607   tab_vline (tbl, TAL_2, heading_columns, 0, n_rows - 1);
608
609   tab_text (tbl, 1, 0, TAB_CENTER | TAT_TITLE,
610             _("Scale Mean if Item Deleted"));
611
612   tab_text (tbl, 2, 0, TAB_CENTER | TAT_TITLE,
613             _("Scale Variance if Item Deleted"));
614
615   tab_text (tbl, 3, 0, TAB_CENTER | TAT_TITLE,
616             _("Corrected Item-Total Correlation"));
617
618   tab_text (tbl, 4, 0, TAB_CENTER | TAT_TITLE,
619             _("Cronbach's Alpha if Item Deleted"));
620
621
622   for (i = 0 ; i < rel->sc[0].n_items; ++i)
623     {
624       double cov, item_to_total_r;
625       double mean, weight, var;
626
627       const struct cronbach *s = &rel->sc[rel->total_start + i];
628       tab_text (tbl, 0, heading_rows + i, TAB_LEFT| TAT_TITLE,
629                 var_to_string (rel->sc[0].items[i]));
630
631       moments1_calculate (s->total, &weight, &mean, &var, 0, 0);
632
633       tab_double (tbl, 1, heading_rows + i, TAB_RIGHT,
634                  mean, NULL);
635
636       tab_double (tbl, 2, heading_rows + i, TAB_RIGHT,
637                  s->variance_of_sums, NULL);
638
639       tab_double (tbl, 4, heading_rows + i, TAB_RIGHT,
640                  s->alpha, NULL);
641
642
643       moments1_calculate (rel->sc[0].m[i], &weight, &mean, &var, 0,0);
644       cov = rel->sc[0].variance_of_sums + var - s->variance_of_sums;
645       cov /= 2.0;
646
647       item_to_total_r = (cov - var) / (sqrt(var) * sqrt (s->variance_of_sums));
648
649
650       tab_double (tbl, 3, heading_rows + i, TAB_RIGHT,
651                  item_to_total_r, NULL);
652     }
653
654
655   tab_submit (tbl);
656 }
657
658
659 static void reliability_statistics_model_alpha (struct tab_table *tbl,
660                                                 const struct reliability *rel);
661
662 static void reliability_statistics_model_split (struct tab_table *tbl,
663                                                 const struct reliability *rel);
664
665
666 struct reliability_output_table
667 {
668   int n_cols;
669   int n_rows;
670   int heading_cols;
671   int heading_rows;
672   void (*populate) (struct tab_table *, const struct reliability *);
673 };
674
675
676 static struct reliability_output_table rol[2] =
677   {
678     { 2, 2, 1, 1, reliability_statistics_model_alpha},
679     { 4, 9, 3, 0, reliability_statistics_model_split}
680   };
681
682 static void
683 reliability_statistics (const struct reliability *rel)
684 {
685   int n_cols = rol[rel->model].n_cols;
686   int n_rows = rol[rel->model].n_rows;
687   int heading_columns = rol[rel->model].heading_cols;
688   int heading_rows = rol[rel->model].heading_rows;
689
690   struct tab_table *tbl = tab_create (n_cols, n_rows);
691   tab_headers (tbl, heading_columns, 0, heading_rows, 0);
692
693   tab_title (tbl, _("Reliability Statistics"));
694
695   /* Vertical lines for the data only */
696   tab_box (tbl,
697            -1, -1,
698            -1, TAL_1,
699            heading_columns, 0,
700            n_cols - 1, n_rows - 1);
701
702   /* Box around table */
703   tab_box (tbl,
704            TAL_2, TAL_2,
705            -1, -1,
706            0, 0,
707            n_cols - 1, n_rows - 1);
708
709
710   tab_hline (tbl, TAL_2, 0, n_cols - 1, heading_rows);
711
712   tab_vline (tbl, TAL_2, heading_columns, 0, n_rows - 1);
713
714   if ( rel->model == MODEL_ALPHA )
715     reliability_statistics_model_alpha (tbl, rel);
716   else if (rel->model == MODEL_SPLIT )
717     reliability_statistics_model_split (tbl, rel);
718
719   tab_submit (tbl);
720 }
721
722
723 static void
724 reliability_statistics_model_alpha (struct tab_table *tbl,
725                                     const struct reliability *rel)
726 {
727   const struct variable *wv = rel->wv;
728   const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : & F_8_0;
729
730   const struct cronbach *s = &rel->sc[0];
731
732   tab_text (tbl, 0, 0, TAB_CENTER | TAT_TITLE,
733                 _("Cronbach's Alpha"));
734
735   tab_text (tbl, 1, 0, TAB_CENTER | TAT_TITLE,
736                 _("N of Items"));
737
738   tab_double (tbl, 0, 1, TAB_RIGHT, s->alpha, NULL);
739
740   tab_double (tbl, 1, 1, TAB_RIGHT, s->n_items, wfmt);
741 }
742
743
744 static void
745 reliability_statistics_model_split (struct tab_table *tbl,
746                                     const struct reliability *rel)
747 {
748   const struct variable *wv = rel->wv;
749   const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : & F_8_0;
750
751   tab_text (tbl, 0, 0, TAB_LEFT,
752             _("Cronbach's Alpha"));
753
754   tab_text (tbl, 1, 0, TAB_LEFT,
755             _("Part 1"));
756
757   tab_text (tbl, 2, 0, TAB_LEFT,
758             _("Value"));
759
760   tab_text (tbl, 2, 1, TAB_LEFT,
761             _("N of Items"));
762
763
764
765   tab_text (tbl, 1, 2, TAB_LEFT,
766             _("Part 2"));
767
768   tab_text (tbl, 2, 2, TAB_LEFT,
769             _("Value"));
770
771   tab_text (tbl, 2, 3, TAB_LEFT,
772             _("N of Items"));
773
774
775
776   tab_text (tbl, 1, 4, TAB_LEFT,
777             _("Total N of Items"));
778
779   tab_text (tbl, 0, 5, TAB_LEFT,
780             _("Correlation Between Forms"));
781
782
783   tab_text (tbl, 0, 6, TAB_LEFT,
784             _("Spearman-Brown Coefficient"));
785
786   tab_text (tbl, 1, 6, TAB_LEFT,
787             _("Equal Length"));
788
789   tab_text (tbl, 1, 7, TAB_LEFT,
790             _("Unequal Length"));
791
792
793   tab_text (tbl, 0, 8, TAB_LEFT,
794             _("Guttman Split-Half Coefficient"));
795
796
797
798   tab_double (tbl, 3, 0, TAB_RIGHT, rel->sc[1].alpha, NULL);
799   tab_double (tbl, 3, 2, TAB_RIGHT, rel->sc[2].alpha, NULL);
800
801   tab_double (tbl, 3, 1, TAB_RIGHT, rel->sc[1].n_items, wfmt);
802   tab_double (tbl, 3, 3, TAB_RIGHT, rel->sc[2].n_items, wfmt);
803
804   tab_double (tbl, 3, 4, TAB_RIGHT,
805              rel->sc[1].n_items + rel->sc[2].n_items, wfmt);
806
807   {
808     /* R is the correlation between the two parts */
809     double r = rel->sc[0].variance_of_sums -
810       rel->sc[1].variance_of_sums -
811       rel->sc[2].variance_of_sums ;
812
813     /* Guttman Split Half Coefficient */
814     double g = 2 * r / rel->sc[0].variance_of_sums;
815
816     /* Unequal Length Spearman Brown Coefficient, and
817      intermediate value used in the computation thereof */
818     double uly, tmp;
819
820     r /= sqrt (rel->sc[1].variance_of_sums);
821     r /= sqrt (rel->sc[2].variance_of_sums);
822     r /= 2.0;
823
824     tab_double (tbl, 3, 5, TAB_RIGHT, r, NULL);
825
826     /* Equal length Spearman-Brown Coefficient */
827     tab_double (tbl, 3, 6, TAB_RIGHT, 2 * r / (1.0 + r), NULL);
828
829     tab_double (tbl, 3, 8, TAB_RIGHT, g, NULL);
830
831     tmp = (1.0 - r*r) * rel->sc[1].n_items * rel->sc[2].n_items /
832       pow2 (rel->sc[0].n_items);
833
834     uly = sqrt( pow4 (r) + 4 * pow2 (r) * tmp);
835     uly -= pow2 (r);
836     uly /= 2 * tmp;
837
838     tab_double (tbl, 3, 7, TAB_RIGHT, uly, NULL);
839   }
840 }
841