1db0a1b79be2c526aebaebbe81eb471c7376a0dc
[pspp-builds.git] / src / language / stats / npar.c
1 /* PSPP - a program for statistical analysis. -*-c-*-
2    Copyright (C) 2006, 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 <language/stats/npar.h>
20 #include "npar-summary.h"
21
22 #include <stdlib.h>
23 #include <math.h>
24
25 #include "xalloc.h"
26
27 #include <data/case.h>
28 #include <data/casegrouper.h>
29 #include <data/casereader.h>
30 #include <data/dictionary.h>
31 #include <data/procedure.h>
32 #include <data/settings.h>
33 #include <data/variable.h>
34 #include <libpspp/assertion.h>
35 #include <libpspp/cast.h>
36 #include <libpspp/hmapx.h>
37 #include <libpspp/hash-functions.h>
38 #include <libpspp/message.h>
39 #include <libpspp/pool.h>
40 #include <libpspp/str.h>
41 #include <libpspp/taint.h>
42 #include <language/command.h>
43 #include <language/lexer/lexer.h>
44 #include <language/lexer/variable-parser.h>
45 #include <language/lexer/value-parser.h>
46 #include <language/stats/binomial.h>
47 #include <language/stats/chisquare.h>
48 #include <language/stats/runs.h>
49 #include <language/stats/friedman.h>
50 #include <language/stats/kruskal-wallis.h>
51 #include <language/stats/wilcoxon.h>
52 #include <language/stats/sign.h>
53 #include <math/moments.h>
54
55 #include "gettext.h"
56 #define _(msgid) gettext (msgid)
57
58 /* Settings for subcommand specifiers. */
59 enum missing_type
60   {
61     MISS_ANALYSIS,
62     MISS_LISTWISE,
63   };
64
65 /* Array indices for STATISTICS subcommand. */
66 enum
67   {
68     NPAR_ST_DESCRIPTIVES = 0,
69     NPAR_ST_QUARTILES = 1,
70     NPAR_ST_ALL = 2,
71     NPAR_ST_count
72   };
73
74 /* NPAR TESTS structure. */
75 struct cmd_npar_tests
76   {
77     /* Count variables indicating how many
78        of the subcommands have been given. */
79     int chisquare;
80     int binomial;
81     int wilcoxon;
82     int sign;
83     int runs;
84     int friedman;
85     int kruskal_wallis;
86     int missing;
87     int method;
88     int statistics;
89
90     /* How missing values should be treated */
91     long miss;
92
93     /* Which statistics have been requested */
94     int a_statistics[NPAR_ST_count];
95   };
96
97
98 struct npar_specs
99 {
100   struct pool *pool;
101   struct npar_test **test;
102   size_t n_tests;
103
104   const struct variable **vv; /* Compendium of all variables
105                                   (those mentioned on ANY subcommand */
106   int n_vars; /* Number of variables in vv */
107
108   enum mv_class filter;    /* Missing values to filter. */
109
110   bool descriptives;       /* Descriptive statistics should be calculated */
111   bool quartiles;          /* Quartiles should be calculated */
112
113   bool exact;  /* Whether exact calculations have been requested */
114   double timer;   /* Maximum time (in minutes) to wait for exact calculations */
115 };
116
117
118 /* Prototype for custom subcommands of NPAR TESTS. */
119 static int npar_chisquare (struct lexer *, struct dataset *, struct npar_specs *);
120 static int npar_binomial (struct lexer *, struct dataset *,  struct npar_specs *);
121 static int npar_runs (struct lexer *, struct dataset *, struct npar_specs *);
122 static int npar_friedman (struct lexer *, struct dataset *, struct npar_specs *);
123 static int npar_wilcoxon (struct lexer *, struct dataset *, struct npar_specs *);
124 static int npar_sign (struct lexer *, struct dataset *, struct npar_specs *);
125 static int npar_kruskal_wallis (struct lexer *, struct dataset *, struct npar_specs *);
126 static int npar_method (struct lexer *, struct npar_specs *);
127
128 /* Command parsing functions. */
129 static int parse_npar_tests (struct lexer *lexer, struct dataset *ds, struct cmd_npar_tests *p,
130                              struct npar_specs *npar_specs );
131
132 static int
133 parse_npar_tests (struct lexer *lexer, struct dataset *ds, struct cmd_npar_tests *npt,
134                   struct npar_specs *nps)
135 {
136   npt->chisquare = 0;
137   npt->binomial = 0;
138   npt->wilcoxon = 0;
139   npt->runs = 0;
140   npt->friedman = 0;
141   npt->sign = 0;
142   npt->missing = 0;
143   npt->miss = MISS_ANALYSIS;
144   npt->method = 0;
145   npt->statistics = 0;
146   memset (npt->a_statistics, 0, sizeof npt->a_statistics);
147   for (;;)
148     {
149       if (lex_match_hyphenated_word (lexer, "FRIEDMAN"))
150         {
151           npt->friedman++;
152           switch (npar_friedman (lexer, ds, nps))
153             {
154             case 0:
155               goto lossage;
156             case 1:
157               break;
158             case 2:
159               lex_error (lexer, NULL);
160               goto lossage;
161             default:
162               NOT_REACHED ();
163             }
164         }
165       else if (lex_match_hyphenated_word (lexer, "RUNS"))
166         {
167           npt->runs++;
168           switch (npar_runs (lexer, ds, nps))
169             {
170             case 0:
171               goto lossage;
172             case 1:
173               break;
174             case 2:
175               lex_error (lexer, NULL);
176               goto lossage;
177             default:
178               NOT_REACHED ();
179             }
180         }
181       else if (lex_match_hyphenated_word (lexer, "CHISQUARE"))
182         {
183           lex_match (lexer, '=');
184           npt->chisquare++;
185           switch (npar_chisquare (lexer, ds, nps))
186             {
187             case 0:
188               goto lossage;
189             case 1:
190               break;
191             case 2:
192               lex_error (lexer, NULL);
193               goto lossage;
194             default:
195               NOT_REACHED ();
196             }
197         }
198       else if (lex_match_hyphenated_word (lexer, "BINOMIAL"))
199         {
200           lex_match (lexer, '=');
201           npt->binomial++;
202           switch (npar_binomial (lexer, ds, nps))
203             {
204             case 0:
205               goto lossage;
206             case 1:
207               break;
208             case 2:
209               lex_error (lexer, NULL);
210               goto lossage;
211             default:
212               NOT_REACHED ();
213             }
214         }
215       else if (lex_match_hyphenated_word (lexer, "K-W") ||
216                lex_match_hyphenated_word (lexer, "KRUSKAL-WALLIS"))
217         {
218           lex_match (lexer, '=');
219           npt->kruskal_wallis++;
220           switch (npar_kruskal_wallis (lexer, ds, nps))
221             {
222             case 0:
223               goto lossage;
224             case 1:
225               break;
226             case 2:
227               lex_error (lexer, NULL);
228               goto lossage;
229             default:
230               NOT_REACHED ();
231             }
232         }
233       else if (lex_match_hyphenated_word (lexer, "WILCOXON"))
234         {
235           lex_match (lexer, '=');
236           npt->wilcoxon++;
237           switch (npar_wilcoxon (lexer, ds, nps))
238             {
239             case 0:
240               goto lossage;
241             case 1:
242               break;
243             case 2:
244               lex_error (lexer, NULL);
245               goto lossage;
246             default:
247               NOT_REACHED ();
248             }
249         }
250       else if (lex_match_hyphenated_word (lexer, "SIGN"))
251         {
252           lex_match (lexer, '=');
253           npt->sign++;
254           switch (npar_sign (lexer, ds, nps))
255             {
256             case 0:
257               goto lossage;
258             case 1:
259               break;
260             case 2:
261               lex_error (lexer, NULL);
262               goto lossage;
263             default:
264               NOT_REACHED ();
265             }
266         }
267       else if (lex_match_hyphenated_word (lexer, "MISSING"))
268         {
269           lex_match (lexer, '=');
270           npt->missing++;
271           if (npt->missing > 1)
272             {
273               msg (SE, _("The %s subcommand may be given only once."), "MISSING");
274               goto lossage;
275             }
276           while (lex_token (lexer) != '/' && lex_token (lexer) != '.')
277             {
278               if (lex_match_hyphenated_word (lexer, "ANALYSIS"))
279                 npt->miss = MISS_ANALYSIS;
280               else if (lex_match_hyphenated_word (lexer, "LISTWISE"))
281                 npt->miss = MISS_LISTWISE;
282               else if (lex_match_hyphenated_word (lexer, "INCLUDE"))
283                 nps->filter = MV_SYSTEM;
284               else if (lex_match_hyphenated_word (lexer, "EXCLUDE"))
285                 nps->filter = MV_ANY;
286               else
287                 {
288                   lex_error (lexer, NULL);
289                   goto lossage;
290                 }
291               lex_match (lexer, ',');
292             }
293         }
294       else if (lex_match_hyphenated_word (lexer, "METHOD"))
295         {
296           lex_match (lexer, '=');
297           npt->method++;
298           if (npt->method > 1)
299             {
300               msg (SE, _("The %s subcommand may be given only once."), "METHOD");
301               goto lossage;
302             }
303           switch (npar_method (lexer, nps))
304             {
305             case 0:
306               goto lossage;
307             case 1:
308               break;
309             case 2:
310               lex_error (lexer, NULL);
311               goto lossage;
312             default:
313               NOT_REACHED ();
314             }
315         }
316       else if (lex_match_hyphenated_word (lexer, "STATISTICS"))
317         {
318           lex_match (lexer, '=');
319           npt->statistics++;
320           while (lex_token (lexer) != '/' && lex_token (lexer) != '.')
321             {
322               if (lex_match_hyphenated_word (lexer, "DESCRIPTIVES"))
323                 npt->a_statistics[NPAR_ST_DESCRIPTIVES] = 1;
324               else if (lex_match_hyphenated_word (lexer, "QUARTILES"))
325                 npt->a_statistics[NPAR_ST_QUARTILES] = 1;
326               else if (lex_match (lexer, T_ALL))
327                 npt->a_statistics[NPAR_ST_ALL] = 1;
328               else
329                 {
330                   lex_error (lexer, NULL);
331                   goto lossage;
332                 }
333               lex_match (lexer, ',');
334             }
335         }
336       else if ( settings_get_syntax () != COMPATIBLE && lex_match_id (lexer, "ALGORITHM"))
337         {
338           lex_match (lexer, '=');
339           if (lex_match_id (lexer, "COMPATIBLE"))
340             settings_set_cmd_algorithm (COMPATIBLE);
341           else if (lex_match_id (lexer, "ENHANCED"))
342             settings_set_cmd_algorithm (ENHANCED);
343           }
344         if (!lex_match (lexer, '/'))
345           break;
346       }
347
348     if (lex_token (lexer) != '.')
349       {
350         lex_error (lexer, _("expecting end of command"));
351         goto lossage;
352       }
353
354   return true;
355
356 lossage:
357   return false;
358 }
359
360
361 static void one_sample_insert_variables (const struct npar_test *test,
362                                          struct hmapx *);
363
364 static void two_sample_insert_variables (const struct npar_test *test,
365                                          struct hmapx *);
366
367 static void n_sample_insert_variables (const struct npar_test *test,
368                                        struct hmapx *);
369
370 static void
371 npar_execute (struct casereader *input,
372              const struct npar_specs *specs,
373              const struct dataset *ds)
374 {
375   int t;
376   struct descriptives *summary_descriptives = NULL;
377
378   for ( t = 0 ; t < specs->n_tests; ++t )
379     {
380       const struct npar_test *test = specs->test[t];
381       if ( NULL == test->execute )
382         {
383           msg (SW, _("NPAR subcommand not currently implemented."));
384           continue;
385         }
386       test->execute (ds, casereader_clone (input), specs->filter, test, specs->exact, specs->timer);
387     }
388
389   if ( specs->descriptives )
390     {
391       summary_descriptives = xnmalloc (sizeof (*summary_descriptives),
392                                        specs->n_vars);
393
394       npar_summary_calc_descriptives (summary_descriptives,
395                                       casereader_clone (input),
396                                       dataset_dict (ds),
397                                       specs->vv, specs->n_vars,
398                                       specs->filter);
399     }
400
401   if ( (specs->descriptives || specs->quartiles)
402        && !taint_has_tainted_successor (casereader_get_taint (input)) )
403     do_summary_box (summary_descriptives, specs->vv, specs->n_vars );
404
405   free (summary_descriptives);
406   casereader_destroy (input);
407 }
408
409 int
410 cmd_npar_tests (struct lexer *lexer, struct dataset *ds)
411 {
412   struct cmd_npar_tests cmd;
413   bool ok;
414   int i;
415   struct npar_specs npar_specs = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
416   struct casegrouper *grouper;
417   struct casereader *input, *group;
418   struct hmapx var_map = HMAPX_INITIALIZER (var_map);
419
420
421   npar_specs.pool = pool_create ();
422   npar_specs.filter = MV_ANY;
423   npar_specs.n_vars = -1;
424   npar_specs.vv = NULL;
425
426   if ( ! parse_npar_tests (lexer, ds, &cmd, &npar_specs) )
427     {
428       pool_destroy (npar_specs.pool);
429       return CMD_FAILURE;
430     }
431
432   for (i = 0; i < npar_specs.n_tests; ++i )
433     {
434       const struct npar_test *test = npar_specs.test[i];
435       test->insert_variables (test, &var_map);
436     }
437
438   {
439     struct hmapx_node *node;
440     struct variable *var;
441     npar_specs.n_vars = 0;
442
443     HMAPX_FOR_EACH (var, node, &var_map)
444       {
445         npar_specs.n_vars ++;
446         npar_specs.vv = pool_nrealloc (npar_specs.pool, npar_specs.vv, npar_specs.n_vars, sizeof (*npar_specs.vv));
447         npar_specs.vv[npar_specs.n_vars - 1] = var;
448       }
449   }
450
451   qsort (npar_specs.vv, npar_specs.n_vars, sizeof (*npar_specs.vv), 
452          compare_var_ptrs_by_name);
453
454   if ( cmd.statistics )
455     {
456       int i;
457
458       for ( i = 0 ; i < NPAR_ST_count; ++i )
459         {
460           if ( cmd.a_statistics[i] )
461             {
462               switch ( i )
463                 {
464                 case NPAR_ST_DESCRIPTIVES:
465                   npar_specs.descriptives = true;
466                   break;
467                 case NPAR_ST_QUARTILES:
468                   npar_specs.quartiles = true;
469                   break;
470                 case NPAR_ST_ALL:
471                   npar_specs.quartiles = true;
472                   npar_specs.descriptives = true;
473                   break;
474                 default:
475                   NOT_REACHED ();
476                 };
477             }
478         }
479     }
480
481   input = proc_open (ds);
482   if ( cmd.miss == MISS_LISTWISE )
483     {
484       input = casereader_create_filter_missing (input,
485                                                 npar_specs.vv,
486                                                 npar_specs.n_vars,
487                                                 npar_specs.filter,
488                                                 NULL, NULL);
489     }
490
491
492   grouper = casegrouper_create_splits (input, dataset_dict (ds));
493   while (casegrouper_get_next_group (grouper, &group))
494     npar_execute (group, &npar_specs, ds);
495   ok = casegrouper_destroy (grouper);
496   ok = proc_commit (ds) && ok;
497
498   pool_destroy (npar_specs.pool);
499   hmapx_destroy (&var_map);
500
501   return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
502 }
503
504 static int
505 npar_runs (struct lexer *lexer, struct dataset *ds,
506            struct npar_specs *specs)
507 {
508   struct runs_test *rt = pool_alloc (specs->pool, sizeof (*rt));
509   struct one_sample_test *tp = &rt->parent;
510   struct npar_test *nt = &tp->parent;
511
512   nt->execute = runs_execute;
513   nt->insert_variables = one_sample_insert_variables;
514
515   if ( lex_force_match (lexer, '(') )
516     {
517       if ( lex_match_id (lexer, "MEAN"))
518         {
519           rt->cp_mode = CP_MEAN;
520         }
521       else if (lex_match_id (lexer, "MEDIAN"))
522         {
523           rt->cp_mode = CP_MEDIAN;
524         }
525       else if (lex_match_id (lexer, "MODE"))
526         {
527           rt->cp_mode = CP_MODE;
528         }
529       else if (lex_is_number (lexer))
530         {
531           rt->cutpoint = lex_number (lexer);
532           rt->cp_mode = CP_CUSTOM;
533           lex_get (lexer);
534         }
535       else
536         {
537           lex_error (lexer, _("Expecting MEAN, MEDIAN, MODE or number"));
538           return 0;
539         }
540                   
541       lex_force_match (lexer, ')');
542       lex_force_match (lexer, '=');
543       if (!parse_variables_const_pool (lexer, specs->pool, dataset_dict (ds),
544                                   &tp->vars, &tp->n_vars,
545                                   PV_NO_SCRATCH | PV_NO_DUPLICATE | PV_NUMERIC))
546         {
547           return 2;
548         }
549     }
550
551   specs->n_tests++;
552   specs->test = pool_realloc (specs->pool,
553                               specs->test,
554                               sizeof (*specs->test) * specs->n_tests);
555
556   specs->test[specs->n_tests - 1] = nt;
557
558   return 1;
559 }
560
561 static int
562 npar_friedman (struct lexer *lexer, struct dataset *ds,
563                struct npar_specs *specs)
564 {
565   struct one_sample_test *ft = pool_alloc (specs->pool, sizeof (*ft)); 
566   struct npar_test *nt = &ft->parent;
567
568   nt->execute = friedman_execute;
569   nt->insert_variables = one_sample_insert_variables;
570
571   lex_match (lexer, '=');
572
573   if (!parse_variables_const_pool (lexer, specs->pool, dataset_dict (ds),
574                                    &ft->vars, &ft->n_vars,
575                                    PV_NO_SCRATCH | PV_NO_DUPLICATE | PV_NUMERIC))
576     {
577       return 2;
578     }
579
580   specs->n_tests++;
581   specs->test = pool_realloc (specs->pool,
582                               specs->test,
583                               sizeof (*specs->test) * specs->n_tests);
584
585   specs->test[specs->n_tests - 1] = nt;
586
587   return 1;
588 }
589
590
591 static int
592 npar_chisquare (struct lexer *lexer, struct dataset *ds,
593                 struct npar_specs *specs)
594 {
595   struct chisquare_test *cstp = pool_alloc (specs->pool, sizeof (*cstp));
596   struct one_sample_test *tp = &cstp->parent;
597   struct npar_test *nt = &tp->parent;
598
599
600   nt->execute = chisquare_execute;
601   nt->insert_variables = one_sample_insert_variables;
602
603   if (!parse_variables_const_pool (lexer, specs->pool, dataset_dict (ds),
604                                    &tp->vars, &tp->n_vars,
605                                    PV_NO_SCRATCH | PV_NO_DUPLICATE))
606     {
607       return 2;
608     }
609
610   cstp->ranged = false;
611
612   if ( lex_match (lexer, '('))
613     {
614       cstp->ranged = true;
615       if ( ! lex_force_num (lexer)) return 0;
616       cstp->lo = lex_integer (lexer);
617       lex_get (lexer);
618       lex_force_match (lexer, ',');
619       if (! lex_force_num (lexer) ) return 0;
620       cstp->hi = lex_integer (lexer);
621       if ( cstp->lo >= cstp->hi )
622         {
623           msg (ME,
624               _("The specified value of HI (%d) is "
625                 "lower than the specified value of LO (%d)"),
626               cstp->hi, cstp->lo);
627           return 0;
628         }
629       lex_get (lexer);
630       if (! lex_force_match (lexer, ')')) return 0;
631     }
632
633   cstp->n_expected = 0;
634   cstp->expected = NULL;
635   if ( lex_match (lexer, '/') )
636     {
637       if ( lex_match_id (lexer, "EXPECTED") )
638         {
639           lex_force_match (lexer, '=');
640           if ( ! lex_match_id (lexer, "EQUAL") )
641             {
642               double f;
643               int n;
644               while ( lex_is_number (lexer) )
645                 {
646                   int i;
647                   n = 1;
648                   f = lex_number (lexer);
649                   lex_get (lexer);
650                   if ( lex_match (lexer, '*'))
651                     {
652                       n = f;
653                       f = lex_number (lexer);
654                       lex_get (lexer);
655                     }
656                   lex_match (lexer, ',');
657
658                   cstp->n_expected += n;
659                   cstp->expected = pool_realloc (specs->pool,
660                                                  cstp->expected,
661                                                  sizeof (double) *
662                                                  cstp->n_expected);
663                   for ( i = cstp->n_expected - n ;
664                         i < cstp->n_expected;
665                         ++i )
666                     cstp->expected[i] = f;
667
668                 }
669             }
670         }
671       else
672         lex_put_back (lexer, '/');
673     }
674
675   if ( cstp->ranged && cstp->n_expected > 0 &&
676        cstp->n_expected != cstp->hi - cstp->lo + 1 )
677     {
678       msg (ME,
679           _("%d expected values were given, but the specified "
680             "range (%d-%d) requires exactly %d values."),
681           cstp->n_expected, cstp->lo, cstp->hi,
682           cstp->hi - cstp->lo +1);
683       return 0;
684     }
685
686   specs->n_tests++;
687   specs->test = pool_realloc (specs->pool,
688                               specs->test,
689                               sizeof (*specs->test) * specs->n_tests);
690
691   specs->test[specs->n_tests - 1] = nt;
692
693   return 1;
694 }
695
696
697 static int
698 npar_binomial (struct lexer *lexer, struct dataset *ds,
699                struct npar_specs *specs)
700 {
701   struct binomial_test *btp = pool_alloc (specs->pool, sizeof (*btp));
702   struct one_sample_test *tp = &btp->parent;
703   struct npar_test *nt = &tp->parent;
704
705   nt->execute = binomial_execute;
706   nt->insert_variables = one_sample_insert_variables;
707
708   btp->category1 = btp->category2 = btp->cutpoint = SYSMIS;
709
710   btp->p = 0.5;
711
712   if ( lex_match (lexer, '(') )
713     {
714       if ( lex_force_num (lexer) )
715         {
716           btp->p = lex_number (lexer);
717           lex_get (lexer);
718           lex_force_match (lexer, ')');
719         }
720       else
721         return 0;
722     }
723   else
724     /* Kludge: q2c swallows the '=' so put it back here  */
725      lex_put_back (lexer, '=');
726
727   if (lex_match (lexer, '=') )
728     {
729       if (parse_variables_const_pool (lexer, specs->pool, dataset_dict (ds),
730                                       &tp->vars, &tp->n_vars,
731                                       PV_NUMERIC | PV_NO_SCRATCH | PV_NO_DUPLICATE) )
732         {
733           if (lex_match (lexer, '('))
734             {
735               lex_force_num (lexer);
736               btp->category1 = lex_number (lexer);
737               lex_get (lexer);
738               if ( lex_match (lexer, ','))
739                 {
740                   if ( ! lex_force_num (lexer) ) return 2;
741                   btp->category2 = lex_number (lexer);
742                   lex_get (lexer);
743                 }
744               else
745                 {
746                   btp->cutpoint = btp->category1;
747                 }
748
749               lex_force_match (lexer, ')');
750             }
751         }
752       else
753         return 2;
754
755     }
756
757   specs->n_tests++;
758   specs->test = pool_realloc (specs->pool,
759                               specs->test,
760                               sizeof (*specs->test) * specs->n_tests);
761
762   specs->test[specs->n_tests - 1] = nt;
763
764   return 1;
765 }
766
767
768 static bool
769 parse_two_sample_related_test (struct lexer *lexer,
770                                     const struct dictionary *dict,
771                                     struct two_sample_test *test_parameters,
772                                     struct pool *pool
773                                     );
774
775
776 static bool
777 parse_two_sample_related_test (struct lexer *lexer,
778                                const struct dictionary *dict,
779                                struct two_sample_test *test_parameters,
780                                struct pool *pool
781                                )
782 {
783   int n = 0;
784   bool paired = false;
785   bool with = false;
786   const struct variable **vlist1;
787   size_t n_vlist1;
788
789   const struct variable **vlist2;
790   size_t n_vlist2;
791
792   test_parameters->parent.insert_variables = two_sample_insert_variables;
793
794   if (!parse_variables_const_pool (lexer, pool,
795                                    dict,
796                                    &vlist1, &n_vlist1,
797                                    PV_NUMERIC | PV_NO_SCRATCH | PV_NO_DUPLICATE) )
798     return false;
799
800   if ( lex_match (lexer, T_WITH))
801     {
802       with = true;
803       if ( !parse_variables_const_pool (lexer, pool, dict,
804                                         &vlist2, &n_vlist2,
805                                         PV_NUMERIC | PV_NO_SCRATCH | PV_NO_DUPLICATE) )
806         return false;
807
808       paired = (lex_match (lexer, '(') &&
809                 lex_match_id (lexer, "PAIRED") && lex_match (lexer, ')'));
810     }
811
812
813   if ( with )
814     {
815       if (paired)
816         {
817           if ( n_vlist1 != n_vlist2)
818             msg (SE, _("PAIRED was specified but the number of variables "
819                        "preceding WITH (%zu) did not match the number "
820                        "following (%zu)."), n_vlist1, n_vlist2);
821
822           test_parameters->n_pairs = n_vlist1 ;
823         }
824       else
825         {
826           test_parameters->n_pairs = n_vlist1 * n_vlist2;
827         }
828     }
829   else
830     {
831       test_parameters->n_pairs = (n_vlist1 * (n_vlist1 - 1)) / 2 ;
832     }
833
834   test_parameters->pairs =
835     pool_alloc (pool, sizeof ( variable_pair) * test_parameters->n_pairs);
836
837   if ( with )
838     {
839       if (paired)
840         {
841           int i;
842           assert (n_vlist1 == n_vlist2);
843           for ( i = 0 ; i < n_vlist1; ++i )
844             {
845               test_parameters->pairs[n][1] = vlist1[i];
846               test_parameters->pairs[n][0] = vlist2[i];
847               n++;
848             }
849         }
850       else
851         {
852           int i,j;
853           for ( i = 0 ; i < n_vlist1; ++i )
854             {
855               for ( j = 0 ; j < n_vlist2; ++j )
856                 {
857                   test_parameters->pairs[n][1] = vlist1[i];
858                   test_parameters->pairs[n][0] = vlist2[j];
859                   n++;
860                 }
861             }
862         }
863     }
864   else
865     {
866       int i,j;
867       for ( i = 0 ; i < n_vlist1 - 1; ++i )
868         {
869           for ( j = i + 1 ; j < n_vlist1; ++j )
870             {
871               assert ( n < test_parameters->n_pairs);
872               test_parameters->pairs[n][1] = vlist1[i];
873               test_parameters->pairs[n][0] = vlist1[j];
874               n++;
875             }
876         }
877     }
878
879   assert ( n == test_parameters->n_pairs);
880
881   return true;
882 }
883
884
885 static bool
886 parse_n_sample_related_test (struct lexer *lexer,
887                              const struct dictionary *dict,
888                              struct n_sample_test *nst,
889                              struct pool *pool
890                              )
891 {
892   if (!parse_variables_const_pool (lexer, pool,
893                                    dict,
894                                    &nst->vars, &nst->n_vars,
895                                    PV_NUMERIC | PV_NO_SCRATCH | PV_NO_DUPLICATE) )
896     return false;
897
898   if ( ! lex_force_match (lexer, T_BY))
899     return false;
900
901   nst->indep_var = parse_variable_const (lexer, dict);
902
903   if ( ! lex_force_match (lexer, '('))
904     return false;
905
906   value_init (&nst->val1, var_get_width (nst->indep_var));
907   if ( ! parse_value (lexer, &nst->val1, var_get_width (nst->indep_var)))
908     {
909       value_destroy (&nst->val1, var_get_width (nst->indep_var));
910       return false;
911     }
912
913   if ( ! lex_force_match (lexer, ','))
914     return false;
915
916   value_init (&nst->val2, var_get_width (nst->indep_var));
917   if ( ! parse_value (lexer, &nst->val2, var_get_width (nst->indep_var)))
918     {
919       value_destroy (&nst->val2, var_get_width (nst->indep_var));
920       return false;
921     }
922
923   if ( ! lex_force_match (lexer, ')'))
924     return false;
925
926   return true;
927 }
928
929 static int
930 npar_wilcoxon (struct lexer *lexer,
931                struct dataset *ds,
932                struct npar_specs *specs )
933 {
934
935
936   struct two_sample_test *tp = pool_alloc (specs->pool, sizeof (*tp));
937   struct npar_test *nt = &tp->parent;
938   nt->execute = wilcoxon_execute;
939
940   if (!parse_two_sample_related_test (lexer, dataset_dict (ds),
941                                       tp, specs->pool) )
942     return 0;
943
944   specs->n_tests++;
945   specs->test = pool_realloc (specs->pool,
946                               specs->test,
947                               sizeof (*specs->test) * specs->n_tests);
948   specs->test[specs->n_tests - 1] = nt;
949
950   return 1;
951 }
952
953 static int
954 npar_sign (struct lexer *lexer, struct dataset *ds,
955            struct npar_specs *specs)
956 {
957   struct two_sample_test *tp = pool_alloc (specs->pool, sizeof (*tp));
958   struct npar_test *nt = &tp->parent;
959
960   nt->execute = sign_execute;
961
962   if (!parse_two_sample_related_test (lexer, dataset_dict (ds),
963                                       tp, specs->pool) )
964     return 0;
965
966   specs->n_tests++;
967   specs->test = pool_realloc (specs->pool,
968                               specs->test,
969                               sizeof (*specs->test) * specs->n_tests);
970   specs->test[specs->n_tests - 1] = nt;
971
972   return 1;
973 }
974
975 static int
976 npar_kruskal_wallis (struct lexer *lexer, struct dataset *ds,
977                       struct npar_specs *specs)
978 {
979   struct n_sample_test *tp = pool_alloc (specs->pool, sizeof (*tp));
980   struct npar_test *nt = &tp->parent;
981
982   nt->insert_variables = n_sample_insert_variables;
983
984   nt->execute = kruskal_wallis_execute;
985
986   if (!parse_n_sample_related_test (lexer, dataset_dict (ds),
987                                       tp, specs->pool) )
988     return 0;
989
990   specs->n_tests++;
991   specs->test = pool_realloc (specs->pool,
992                               specs->test,
993                               sizeof (*specs->test) * specs->n_tests);
994   specs->test[specs->n_tests - 1] = nt;
995
996   return 1;
997 }
998
999 static void
1000 insert_variable_into_map (struct hmapx *var_map, const struct variable *var)
1001 {
1002   size_t hash = hash_pointer (var, 0);
1003   struct hmapx_node *node;
1004   const struct variable *v = NULL;
1005       
1006   HMAPX_FOR_EACH_WITH_HASH (v, node, hash, var_map)
1007     {
1008       if ( v == var)
1009         return ;
1010     }
1011
1012   hmapx_insert (var_map, CONST_CAST (struct variable *, var), hash);
1013 }
1014
1015 /* Insert the variables for TEST into VAR_MAP */
1016 static void
1017 one_sample_insert_variables (const struct npar_test *test,
1018                              struct hmapx *var_map)
1019 {
1020   int i;
1021   const struct one_sample_test *ost = UP_CAST (test, const struct one_sample_test, parent);
1022
1023   for ( i = 0 ; i < ost->n_vars ; ++i )
1024     insert_variable_into_map (var_map, ost->vars[i]);
1025 }
1026
1027
1028 static void
1029 two_sample_insert_variables (const struct npar_test *test,
1030                              struct hmapx *var_map)
1031 {
1032   int i;
1033   const struct two_sample_test *tst = UP_CAST (test, const struct two_sample_test, parent);
1034
1035   for ( i = 0 ; i < tst->n_pairs ; ++i )
1036     {
1037       variable_pair *pair = &tst->pairs[i];
1038
1039       insert_variable_into_map (var_map, (*pair)[0]);
1040       insert_variable_into_map (var_map, (*pair)[1]);
1041     }
1042 }
1043
1044 static void 
1045 n_sample_insert_variables (const struct npar_test *test,
1046                            struct hmapx *var_map)
1047 {
1048   int i;
1049   const struct n_sample_test *tst = UP_CAST (test, const struct n_sample_test, parent);
1050
1051   for ( i = 0 ; i < tst->n_vars ; ++i )
1052     insert_variable_into_map (var_map, tst->vars[i]);
1053
1054   insert_variable_into_map (var_map, tst->indep_var);
1055 }
1056
1057
1058 static int
1059 npar_method (struct lexer *lexer,  struct npar_specs *specs)
1060 {
1061   if ( lex_match_id (lexer, "EXACT") )
1062     {
1063       specs->exact = true;
1064       specs->timer = 0.0;
1065       if (lex_match_id (lexer, "TIMER"))
1066         {
1067           specs->timer = 5.0;
1068
1069           if ( lex_match (lexer, '('))
1070             {
1071               if ( lex_force_num (lexer) )
1072                 {
1073                   specs->timer = lex_number (lexer);
1074                   lex_get (lexer);
1075                 }
1076               lex_force_match (lexer, ')');
1077             }
1078         }
1079     }
1080
1081   return 1;
1082 }