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