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