LIST: Remove WEIGHT subcommand.
[pspp-builds.git] / src / language / stats / reliability.q
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2008, 2009 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/manager.h>
31 #include <output/table.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
383   {
384     struct tab_table *tab = tab_create(1, 1);
385
386     tab_dim (tab, tab_natural_dimensions, NULL, NULL);
387     tab_flags (tab, SOMF_NO_TITLE );
388
389     tab_text_format (tab, 0, 0, 0, "Scale: %s", ds_cstr (&rel->scale_name));
390
391     tab_submit(tab);
392   }
393
394
395   case_processing_summary (n_valid, n_missing, dataset_dict (ds));
396 }
397
398
399 static void reliability_statistics_model_alpha (struct tab_table *tbl,
400                                                 const struct reliability *rel);
401
402 static void reliability_statistics_model_split (struct tab_table *tbl,
403                                                 const struct reliability *rel);
404
405 struct reliability_output_table
406 {
407   int n_cols;
408   int n_rows;
409   int heading_cols;
410   int heading_rows;
411   void (*populate) (struct tab_table *, const struct reliability *);
412 };
413
414 static struct reliability_output_table rol[2] =
415   {
416     { 2, 2, 1, 1, reliability_statistics_model_alpha},
417     { 4, 9, 3, 0, reliability_statistics_model_split}
418   };
419
420 static void
421 reliability_statistics (const struct reliability *rel)
422 {
423   int n_cols = rol[rel->model].n_cols;
424   int n_rows = rol[rel->model].n_rows;
425   int heading_columns = rol[rel->model].heading_cols;
426   int heading_rows = rol[rel->model].heading_rows;
427
428   struct tab_table *tbl = tab_create (n_cols, n_rows);
429   tab_headers (tbl, heading_columns, 0, heading_rows, 0);
430
431   tab_dim (tbl, tab_natural_dimensions, NULL, NULL);
432
433   tab_title (tbl, _("Reliability Statistics"));
434
435   /* Vertical lines for the data only */
436   tab_box (tbl,
437            -1, -1,
438            -1, TAL_1,
439            heading_columns, 0,
440            n_cols - 1, n_rows - 1);
441
442   /* Box around table */
443   tab_box (tbl,
444            TAL_2, TAL_2,
445            -1, -1,
446            0, 0,
447            n_cols - 1, n_rows - 1);
448
449
450   tab_hline (tbl, TAL_2, 0, n_cols - 1, heading_rows);
451
452   tab_vline (tbl, TAL_2, heading_columns, 0, n_rows - 1);
453
454   if ( rel->model == MODEL_ALPHA )
455     reliability_statistics_model_alpha (tbl, rel);
456   else if (rel->model == MODEL_SPLIT )
457     reliability_statistics_model_split (tbl, rel);
458
459   tab_submit (tbl);
460 }
461
462 static void
463 reliability_summary_total (const struct reliability *rel)
464 {
465   int i;
466   const int n_cols = 5;
467   const int heading_columns = 1;
468   const int heading_rows = 1;
469   const int n_rows = rel->sc[0].n_items + heading_rows ;
470
471   struct tab_table *tbl = tab_create (n_cols, n_rows);
472   tab_headers (tbl, heading_columns, 0, heading_rows, 0);
473
474   tab_dim (tbl, tab_natural_dimensions, NULL, NULL);
475
476   tab_title (tbl, _("Item-Total Statistics"));
477
478   /* Vertical lines for the data only */
479   tab_box (tbl,
480            -1, -1,
481            -1, TAL_1,
482            heading_columns, 0,
483            n_cols - 1, n_rows - 1);
484
485   /* Box around table */
486   tab_box (tbl,
487            TAL_2, TAL_2,
488            -1, -1,
489            0, 0,
490            n_cols - 1, n_rows - 1);
491
492
493   tab_hline (tbl, TAL_2, 0, n_cols - 1, heading_rows);
494
495   tab_vline (tbl, TAL_2, heading_columns, 0, n_rows - 1);
496
497   tab_text (tbl, 1, 0, TAB_CENTER | TAT_TITLE,
498             _("Scale Mean if Item Deleted"));
499
500   tab_text (tbl, 2, 0, TAB_CENTER | TAT_TITLE,
501             _("Scale Variance if Item Deleted"));
502
503   tab_text (tbl, 3, 0, TAB_CENTER | TAT_TITLE,
504             _("Corrected Item-Total Correlation"));
505
506   tab_text (tbl, 4, 0, TAB_CENTER | TAT_TITLE,
507             _("Cronbach's Alpha if Item Deleted"));
508
509
510   for (i = 0 ; i < rel->sc[0].n_items; ++i)
511     {
512       double cov, item_to_total_r;
513       double mean, weight, var;
514
515       const struct cronbach *s = &rel->sc[rel->total_start + i];
516       tab_text (tbl, 0, heading_rows + i, TAB_LEFT| TAT_TITLE,
517                 var_to_string (rel->sc[0].items[i]));
518
519       moments1_calculate (s->total, &weight, &mean, &var, 0, 0);
520
521       tab_double (tbl, 1, heading_rows + i, TAB_RIGHT,
522                  mean, NULL);
523
524       tab_double (tbl, 2, heading_rows + i, TAB_RIGHT,
525                  s->variance_of_sums, NULL);
526
527       tab_double (tbl, 4, heading_rows + i, TAB_RIGHT,
528                  s->alpha, NULL);
529
530
531       moments1_calculate (rel->sc[0].m[i], &weight, &mean, &var, 0,0);
532       cov = rel->sc[0].variance_of_sums + var - s->variance_of_sums;
533       cov /= 2.0;
534
535       item_to_total_r = (cov - var) / (sqrt(var) * sqrt (s->variance_of_sums));
536
537
538       tab_double (tbl, 3, heading_rows + i, TAB_RIGHT,
539                  item_to_total_r, NULL);
540     }
541
542
543   tab_submit (tbl);
544 }
545
546
547 static void
548 reliability_statistics_model_alpha (struct tab_table *tbl,
549                                     const struct reliability *rel)
550 {
551   const struct variable *wv = dict_get_weight (rel->dict);
552   const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : & F_8_0;
553
554   const struct cronbach *s = &rel->sc[0];
555
556   tab_text (tbl, 0, 0, TAB_CENTER | TAT_TITLE,
557                 _("Cronbach's Alpha"));
558
559   tab_text (tbl, 1, 0, TAB_CENTER | TAT_TITLE,
560                 _("N of items"));
561
562   tab_double (tbl, 0, 1, TAB_RIGHT, s->alpha, NULL);
563
564   tab_double (tbl, 1, 1, TAB_RIGHT, s->n_items, wfmt);
565 }
566
567
568 static void
569 reliability_statistics_model_split (struct tab_table *tbl,
570                                     const struct reliability *rel)
571 {
572   const struct variable *wv = dict_get_weight (rel->dict);
573   const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : & F_8_0;
574
575   tab_text (tbl, 0, 0, TAB_LEFT,
576             _("Cronbach's Alpha"));
577
578   tab_text (tbl, 1, 0, TAB_LEFT,
579             _("Part 1"));
580
581   tab_text (tbl, 2, 0, TAB_LEFT,
582             _("Value"));
583
584   tab_text (tbl, 2, 1, TAB_LEFT,
585             _("N of Items"));
586
587
588
589   tab_text (tbl, 1, 2, TAB_LEFT,
590             _("Part 2"));
591
592   tab_text (tbl, 2, 2, TAB_LEFT,
593             _("Value"));
594
595   tab_text (tbl, 2, 3, TAB_LEFT,
596             _("N of Items"));
597
598
599
600   tab_text (tbl, 1, 4, TAB_LEFT,
601             _("Total N of Items"));
602
603   tab_text (tbl, 0, 5, TAB_LEFT,
604             _("Correlation Between Forms"));
605
606
607   tab_text (tbl, 0, 6, TAB_LEFT,
608             _("Spearman-Brown Coefficient"));
609
610   tab_text (tbl, 1, 6, TAB_LEFT,
611             _("Equal Length"));
612
613   tab_text (tbl, 1, 7, TAB_LEFT,
614             _("Unequal Length"));
615
616
617   tab_text (tbl, 0, 8, TAB_LEFT,
618             _("Guttman Split-Half Coefficient"));
619
620
621
622   tab_double (tbl, 3, 0, TAB_RIGHT, rel->sc[1].alpha, NULL);
623   tab_double (tbl, 3, 2, TAB_RIGHT, rel->sc[2].alpha, NULL);
624
625   tab_double (tbl, 3, 1, TAB_RIGHT, rel->sc[1].n_items, wfmt);
626   tab_double (tbl, 3, 3, TAB_RIGHT, rel->sc[2].n_items, wfmt);
627
628   tab_double (tbl, 3, 4, TAB_RIGHT,
629              rel->sc[1].n_items + rel->sc[2].n_items, wfmt);
630
631   {
632     /* R is the correlation between the two parts */
633     double r = rel->sc[0].variance_of_sums -
634       rel->sc[1].variance_of_sums -
635       rel->sc[2].variance_of_sums ;
636
637     /* Guttman Split Half Coefficient */
638     double g = 2 * r / rel->sc[0].variance_of_sums;
639
640     /* Unequal Length Spearman Brown Coefficient, and
641      intermediate value used in the computation thereof */
642     double uly, tmp;
643
644     r /= sqrt (rel->sc[1].variance_of_sums);
645     r /= sqrt (rel->sc[2].variance_of_sums);
646     r /= 2.0;
647
648     tab_double (tbl, 3, 5, TAB_RIGHT, r, NULL);
649
650     /* Equal length Spearman-Brown Coefficient */
651     tab_double (tbl, 3, 6, TAB_RIGHT, 2 * r / (1.0 + r), NULL);
652
653     tab_double (tbl, 3, 8, TAB_RIGHT, g, NULL);
654
655     tmp = (1.0 - r*r) * rel->sc[1].n_items * rel->sc[2].n_items /
656       pow2 (rel->sc[0].n_items);
657
658     uly = sqrt( pow4 (r) + 4 * pow2 (r) * tmp);
659     uly -= pow2 (r);
660     uly /= 2 * tmp;
661
662     tab_double (tbl, 3, 7, TAB_RIGHT, uly, NULL);
663   }
664 }
665
666
667
668 static void
669 case_processing_summary (casenumber n_valid, casenumber n_missing,
670                          const struct dictionary *dict)
671 {
672   const struct variable *wv = dict_get_weight (dict);
673   const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : & F_8_0;
674
675   casenumber total;
676   int n_cols = 4;
677   int n_rows = 4;
678   int heading_columns = 2;
679   int heading_rows = 1;
680   struct tab_table *tbl;
681   tbl = tab_create (n_cols, n_rows);
682   tab_headers (tbl, heading_columns, 0, heading_rows, 0);
683
684   tab_dim (tbl, tab_natural_dimensions, NULL, NULL);
685
686   tab_title (tbl, _("Case Processing Summary"));
687
688   /* Vertical lines for the data only */
689   tab_box (tbl,
690            -1, -1,
691            -1, TAL_1,
692            heading_columns, 0,
693            n_cols - 1, n_rows - 1);
694
695   /* Box around table */
696   tab_box (tbl,
697            TAL_2, TAL_2,
698            -1, -1,
699            0, 0,
700            n_cols - 1, n_rows - 1);
701
702
703   tab_hline (tbl, TAL_2, 0, n_cols - 1, heading_rows);
704
705   tab_vline (tbl, TAL_2, heading_columns, 0, n_rows - 1);
706
707
708   tab_text (tbl, 0, heading_rows, TAB_LEFT | TAT_TITLE,
709                 _("Cases"));
710
711   tab_text (tbl, 1, heading_rows, TAB_LEFT | TAT_TITLE,
712                 _("Valid"));
713
714   tab_text (tbl, 1, heading_rows + 1, TAB_LEFT | TAT_TITLE,
715                 _("Excluded"));
716
717   tab_text (tbl, 1, heading_rows + 2, TAB_LEFT | TAT_TITLE,
718                 _("Total"));
719
720   tab_text (tbl, heading_columns, 0, TAB_CENTER | TAT_TITLE,
721                 _("N"));
722
723   tab_text (tbl, heading_columns + 1, 0, TAB_CENTER | TAT_TITLE, _("%"));
724
725   total = n_missing + n_valid;
726
727   tab_double (tbl, 2, heading_rows, TAB_RIGHT,
728              n_valid, wfmt);
729
730
731   tab_double (tbl, 2, heading_rows + 1, TAB_RIGHT,
732              n_missing, wfmt);
733
734
735   tab_double (tbl, 2, heading_rows + 2, TAB_RIGHT,
736              total, wfmt);
737
738
739   tab_double (tbl, 3, heading_rows, TAB_RIGHT,
740              100 * n_valid / (double) total, NULL);
741
742
743   tab_double (tbl, 3, heading_rows + 1, TAB_RIGHT,
744              100 * n_missing / (double) total, NULL);
745
746
747   tab_double (tbl, 3, heading_rows + 2, TAB_RIGHT,
748              100 * total / (double) total, NULL);
749
750
751   tab_submit (tbl);
752 }
753
754 static int
755 rel_custom_model (struct lexer *lexer, struct dataset *ds UNUSED,
756                   struct cmd_reliability *cmd UNUSED, void *aux)
757 {
758   struct reliability *rel = aux;
759
760   if (lex_match_id (lexer, "ALPHA"))
761     {
762       rel->model = MODEL_ALPHA;
763     }
764   else if (lex_match_id (lexer, "SPLIT"))
765     {
766       rel->model = MODEL_SPLIT;
767       rel->split_point = -1;
768       if ( lex_match (lexer, '('))
769         {
770           lex_force_num (lexer);
771           rel->split_point = lex_number (lexer);
772           lex_get (lexer);
773           lex_force_match (lexer, ')');
774         }
775     }
776   else
777     return 0;
778
779   return 1;
780 }
781
782
783
784 static int
785 rel_custom_scale (struct lexer *lexer, struct dataset *ds UNUSED,
786                   struct cmd_reliability *p, void *aux)
787 {
788   struct const_var_set *vs;
789   struct reliability *rel = aux;
790   struct cronbach *scale;
791
792   rel->n_sc = 1;
793   rel->sc = xzalloc (sizeof (struct cronbach) * rel->n_sc);
794   scale = &rel->sc[0];
795
796   if ( ! lex_force_match (lexer, '(')) return 0;
797
798   if ( ! lex_force_string (lexer) ) return 0;
799
800   ds_init_string (&rel->scale_name, lex_tokstr (lexer));
801
802   lex_get (lexer);
803
804   if ( ! lex_force_match (lexer, ')')) return 0;
805
806   lex_match (lexer, '=');
807
808   vs = const_var_set_create_from_array (p->v_variables, p->n_variables);
809
810   if (!parse_const_var_set_vars (lexer, vs, &scale->items, &scale->n_items, 0))
811     {
812       const_var_set_destroy (vs);
813       return 2;
814     }
815
816   const_var_set_destroy (vs);
817   return 1;
818 }
819
820 /*
821    Local Variables:
822    mode: c
823    End:
824 */