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