Added (some of the) calculations for the examine command.
[pspp-builds.git] / src / examine.q
1 /* PSPP - EXAMINE data for normality . -*-c-*-
2
3 Copyright (C) 2004 Free Software Foundation, Inc.
4 Author: John Darrington 2004
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 02111-1307, USA. */
20
21 #include <config.h>
22 #include <gsl/gsl_cdf.h>
23 #include "error.h"
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <math.h>
27 #include "alloc.h"
28 #include "str.h"
29 #include "case.h"
30 #include "command.h"
31 #include "lexer.h"
32 #include "error.h"
33 #include "magic.h"
34 #include "misc.h"
35 #include "tab.h"
36 #include "som.h"
37 #include "value-labels.h"
38 #include "var.h"
39 #include "vfm.h"
40 #include "hash.h"
41 #include "casefile.h"
42 #include "factor_stats.h"
43
44 /* (specification)
45    "EXAMINE" (xmn_):
46    *variables=custom;
47    +total=custom;
48    +nototal=custom;
49    +missing=miss:pairwise/!listwise,
50    rep:report/!noreport,
51    incl:include/!exclude;
52    +compare=cmp:variables/!groups;
53    +plot[plt_]=stemleaf,boxplot,npplot,:spreadlevel(*d:n),histogram,all,none;
54    +cinterval=double;
55    +statistics[st_]=descriptives,:extreme(*d:n),all,none.
56 */
57
58 /* (declarations) */
59
60 /* (functions) */
61
62
63
64 static struct cmd_examine cmd;
65
66 static struct variable **dependent_vars;
67
68 static int n_dependent_vars;
69
70 static struct hsh_table *hash_table_factors;
71
72
73
74
75 struct factor 
76 {
77   /* The independent variable for this factor */
78   struct variable *indep_var;
79
80   /* The  factor statistics for each value of the independent variable */
81   struct hsh_table *hash_table_val;
82
83   /* The subfactor (if any) */
84   struct factor *subfactor;
85
86 };
87
88
89
90
91 /* Parse the clause specifying the factors */
92 static int examine_parse_independent_vars(struct cmd_examine *cmd, 
93                                           struct hsh_table *hash_factors );
94
95
96
97
98 /* Functions to support hashes of factors */
99 int compare_factors(const struct factor *f1, const struct factor *f2, 
100                     void *aux);
101
102 unsigned hash_factor(const struct factor *f, void *aux);
103
104 void free_factor(struct factor *f, void *aux UNUSED);
105
106
107 /* Output functions */
108 static void show_summary(struct variable **dependent_var, int n_dep_var, 
109                          struct factor *f);
110
111 static void show_descriptives(struct variable **dependent_var, 
112                               int n_dep_var, 
113                               struct factor *factor);
114
115
116 static void show_extremes(struct variable **dependent_var, 
117                           int n_dep_var, 
118                           struct factor *factor,
119                           int n_extremities);
120
121
122 /* Per Split function */
123 static void run_examine(const struct casefile *cf, void *cmd_);
124
125 static void output_examine(void);
126
127
128 static struct factor_statistics *totals = 0;
129
130
131
132 int
133 cmd_examine(void)
134 {
135
136   if ( !parse_examine(&cmd) )
137     return CMD_FAILURE;
138   
139   if ( cmd.st_n == SYSMIS ) 
140     cmd.st_n = 5;
141
142   if ( ! cmd.sbc_cinterval) 
143     cmd.n_cinterval[0] = 95.0;
144
145
146   totals = xmalloc ( sizeof (struct factor_statistics *) );
147
148   totals->stats = xmalloc(sizeof ( struct metrics ) * n_dependent_vars);
149
150   multipass_procedure_with_splits (run_examine, &cmd);
151
152
153   hsh_destroy(hash_table_factors);
154
155   free(totals->stats);
156   free(totals);
157
158   return CMD_SUCCESS;
159 };
160
161
162 /* Show all the appropriate tables */
163 static void
164 output_examine(void)
165 {
166
167   /* Show totals if appropriate */
168   if ( ! cmd.sbc_nototal || 
169        ! hash_table_factors || 0 == hsh_count (hash_table_factors))
170     {
171       show_summary(dependent_vars, n_dependent_vars,0);
172
173       if ( cmd.sbc_statistics ) 
174         {
175           if ( cmd.a_statistics[XMN_ST_DESCRIPTIVES]) 
176             show_descriptives(dependent_vars, n_dependent_vars, 0);
177           
178           if ( cmd.a_statistics[XMN_ST_EXTREME]) 
179             show_extremes(dependent_vars, n_dependent_vars, 0, cmd.st_n);
180         }
181     }
182
183   /* Show grouped statistics  if appropriate */
184   if ( hash_table_factors && 0 != hsh_count (hash_table_factors))
185     {
186       struct hsh_iterator hi;
187       struct factor *f;
188
189       for(f = hsh_first(hash_table_factors,&hi);
190           f != 0;
191           f = hsh_next(hash_table_factors,&hi)) 
192         {
193           show_summary(dependent_vars, n_dependent_vars,f);
194
195           if ( cmd.sbc_statistics )
196             {
197               if ( cmd.a_statistics[XMN_ST_DESCRIPTIVES])
198                 show_descriptives(dependent_vars, n_dependent_vars, f);
199               
200               if ( cmd.a_statistics[XMN_ST_EXTREME])
201                 show_extremes(dependent_vars, n_dependent_vars, f, cmd.st_n);
202             }
203         }
204     }
205
206
207 }
208
209
210
211 /* TOTAL and NOTOTAL are simple, mutually exclusive flags */
212 static int
213 xmn_custom_total(struct cmd_examine *p)
214 {
215   if ( p->sbc_nototal ) 
216     {
217       msg (SE, _("%s and %s are mutually exclusive"),"TOTAL","NOTOTAL");
218       return 0;
219     }
220
221   return 1;
222 }
223
224 static int
225 xmn_custom_nototal(struct cmd_examine *p)
226 {
227   if ( p->sbc_total ) 
228     {
229       msg (SE, _("%s and %s are mutually exclusive"),"TOTAL","NOTOTAL");
230       return 0;
231     }
232
233   return 1;
234 }
235
236
237 /* Compare two factors */
238 int 
239 compare_factors (const struct factor *f1, 
240                  const struct factor *f2, 
241                  void *aux)
242 {
243   int indep_var_cmp = strcmp(f1->indep_var->name, f2->indep_var->name);
244
245   if ( 0 != indep_var_cmp ) 
246     return indep_var_cmp;
247
248   /* If the names are identical, and there are no subfactors then
249      the factors are identical */
250   if ( ! f1->subfactor &&  ! f2->subfactor ) 
251     return 0;
252     
253   /* ... otherwise we must compare the subfactors */
254
255   return compare_factors(f1->subfactor, f2->subfactor, aux);
256
257 }
258
259 /* Create a hash of a factor */
260 unsigned 
261 hash_factor( const struct factor *f, void *aux)
262 {
263   unsigned h;
264   h = hsh_hash_string(f->indep_var->name);
265   
266   if ( f->subfactor ) 
267     h += hash_factor(f->subfactor, aux);
268
269   return h;
270 }
271
272
273 /* Free up a factor */
274 void
275 free_factor(struct factor *f, void *aux)
276 {
277   hsh_destroy(f->hash_table_val);
278
279   if ( f->subfactor ) 
280     free_factor(f->subfactor, aux);
281
282   free(f);
283 }
284
285
286 /* Parser for the variables sub command */
287 static int
288 xmn_custom_variables(struct cmd_examine *cmd )
289 {
290
291   lex_match('=');
292
293   if ((token != T_ID || dict_lookup_var (default_dict, tokid) == NULL)
294       && token != T_ALL)
295     return 2;
296   
297   if (!parse_variables (default_dict, &dependent_vars, &n_dependent_vars,
298                         PV_NO_DUPLICATE | PV_NUMERIC | PV_NO_SCRATCH) )
299     {
300       free (dependent_vars);
301       return 0;
302     }
303
304   assert(n_dependent_vars);
305
306   if ( lex_match(T_BY))
307     {
308       hash_table_factors = hsh_create(4, 
309                                       (hsh_compare_func *) compare_factors, 
310                                       (hsh_hash_func *) hash_factor, 
311                                       (hsh_free_func *) free_factor, 0);
312
313       return examine_parse_independent_vars(cmd, hash_table_factors);
314     }
315
316   
317   
318   return 1;
319 }
320
321
322 /* Parse the clause specifying the factors */
323 static int
324 examine_parse_independent_vars(struct cmd_examine *cmd, 
325                                struct hsh_table *hash_table_factors )
326 {
327   struct factor *f = 0;
328
329   if ((token != T_ID || dict_lookup_var (default_dict, tokid) == NULL)
330       && token != T_ALL)
331     return 2;
332
333   if ( !f ) 
334     {
335       f = xmalloc(sizeof(struct factor));
336       f->indep_var = 0;
337       f->hash_table_val = 0;
338       f->subfactor = 0;
339     }
340   
341   f->indep_var = parse_variable();
342   
343   if ( ! f->hash_table_val ) 
344     f->hash_table_val = hsh_create(4,(hsh_compare_func *) compare_indep_values,
345                                    (hsh_hash_func *) hash_indep_value,
346                                    (hsh_free_func *) free_factor_stats,
347                                    (void *) f->indep_var->width);
348
349   if ( token == T_BY ) 
350     {
351       lex_match(T_BY);
352
353       if ((token != T_ID || dict_lookup_var (default_dict, tokid) == NULL)
354           && token != T_ALL)
355         return 2;
356
357       f->subfactor = xmalloc(sizeof(struct factor));
358
359       f->subfactor->indep_var = parse_variable();
360       
361       f->subfactor->subfactor = 0;
362
363       f->subfactor->hash_table_val = 
364         hsh_create(4,
365                    (hsh_compare_func *) compare_indep_values,
366                    (hsh_hash_func *) hash_indep_value,
367                    (hsh_free_func *) free_factor_stats,
368                    (void *) f->subfactor->indep_var->width);
369     }
370
371   hsh_insert(hash_table_factors, f);
372   
373   lex_match(',');
374
375   if ( token == '.' || token == '/' ) 
376     return 1;
377
378   return examine_parse_independent_vars(cmd, hash_table_factors);
379 }
380
381
382 void populate_descriptives(struct tab_table *t, int col, int row, 
383                            const struct metrics *fs);
384
385
386 void populate_extremities(struct tab_table *t, int col, int row, int n);
387
388
389 /* Show the descriptives table */
390 void
391 show_descriptives(struct variable **dependent_var, 
392                   int n_dep_var, 
393                   struct factor *factor)
394 {
395   int i;
396   int heading_columns ;
397   int n_cols;
398   const int n_stat_rows = 13;
399
400   const int heading_rows = 1;
401   int n_rows = heading_rows ;
402
403   struct tab_table *t;
404
405
406   if ( !factor ) 
407     {
408       heading_columns = 1;
409       n_rows += n_dep_var * n_stat_rows;
410     }
411   else
412     {
413       assert(factor->indep_var);
414       if ( factor->subfactor == 0 ) 
415         {
416           heading_columns = 2;
417           n_rows += n_dep_var * hsh_count(factor->hash_table_val) * n_stat_rows;
418         }
419       else
420         {
421           heading_columns = 3;
422           n_rows += n_dep_var * hsh_count(factor->hash_table_val) * 
423             hsh_count(factor->subfactor->hash_table_val) * n_stat_rows ;
424         }
425     }
426
427   n_cols = heading_columns + 4;
428
429   t = tab_create (n_cols, n_rows, 0);
430
431   tab_headers (t, heading_columns + 1, 0, heading_rows, 0);
432
433   tab_dim (t, tab_natural_dimensions);
434
435   /* Outline the box and have no internal lines*/
436   tab_box (t, 
437            TAL_2, TAL_2,
438            -1, -1,
439            0, 0,
440            n_cols - 1, n_rows - 1);
441
442   tab_hline (t, TAL_2, 0, n_cols - 1, heading_rows );
443
444   tab_vline (t, TAL_1, heading_columns, 0, n_rows - 1);
445   tab_vline (t, TAL_2, n_cols - 2, 0, n_rows - 1);
446   tab_vline (t, TAL_1, n_cols - 1, 0, n_rows - 1);
447
448   tab_text (t, n_cols - 2, 0, TAB_CENTER | TAT_TITLE, _("Statistic"));
449   tab_text (t, n_cols - 1, 0, TAB_CENTER | TAT_TITLE, _("Std. Error"));
450
451
452   for ( i = 0 ; i < n_dep_var ; ++i ) 
453     {
454       int row;
455       int n_subfactors = 1;
456       int n_factors = 1;
457         
458       if ( factor ) 
459         {
460           n_factors = hsh_count(factor->hash_table_val);
461           if (  factor->subfactor ) 
462             n_subfactors = hsh_count(factor->subfactor->hash_table_val);
463         }
464
465
466       row = heading_rows + i * n_stat_rows * n_factors * n_subfactors; 
467
468       if ( i > 0 )
469         tab_hline(t, TAL_1, 0, n_cols - 1, row );
470
471       if ( factor  )
472         {
473           struct hsh_iterator hi;
474           const struct factor_statistics *fs;
475           int count = 0;
476
477           tab_text (t, 1, heading_rows - 1, TAB_CENTER | TAT_TITLE, 
478                     var_to_string(factor->indep_var));
479
480
481
482           for (fs  = hsh_first(factor->hash_table_val, &hi);
483                fs != 0;
484                fs  = hsh_next(factor->hash_table_val,  &hi))
485             {
486               tab_text (t, 1, 
487                         row  + count * n_subfactors * n_stat_rows,
488                         TAB_RIGHT | TAT_TITLE, 
489                         value_to_string(fs->id, factor->indep_var)
490                         );
491
492               if ( count > 0 ) 
493                 tab_hline (t, TAL_1, 1, n_cols - 1,  
494                            row  + count * n_subfactors * n_stat_rows);
495
496               if ( factor->subfactor ) 
497                 {
498                   int count2=0;
499                   struct hsh_iterator h2;
500                   const struct factor_statistics *sub_fs;
501               
502                   tab_text (t, 2, heading_rows - 1, TAB_CENTER | TAT_TITLE, 
503                             var_to_string(factor->subfactor->indep_var));
504
505                   for ( sub_fs = hsh_first(factor->subfactor->hash_table_val, 
506                                            &h2);
507                         sub_fs != 0;
508                         sub_fs = hsh_next(factor->subfactor->hash_table_val, 
509                                           &h2))
510                     {
511                         
512                       tab_text(t, 2, 
513                                row
514                                + count * n_subfactors * n_stat_rows 
515                                + count2 * n_stat_rows,
516                                TAB_RIGHT | TAT_TITLE ,
517                                value_to_string(sub_fs->id, factor->subfactor->indep_var)
518                                );
519
520                       if ( count2 > 0 ) 
521                         tab_hline (t, TAL_1, 2, n_cols - 1,  
522                                    row
523                                    + count * n_subfactors * n_stat_rows 
524                                    + count2 * n_stat_rows);
525                                
526                       populate_descriptives(t, heading_columns,
527                                             row
528                                             + count * n_subfactors 
529                                             * n_stat_rows 
530                                             + count2 * n_stat_rows,
531                                             &sub_fs->stats[i]);
532                                             
533                         
534                       count2++;
535                     }
536                 }
537               else
538                 {
539                   
540                   populate_descriptives(t, heading_columns, 
541                                         row  
542                                         + count * n_subfactors * n_stat_rows, 
543                                         &fs->stats[i]);
544                 }
545
546               count ++;
547             }
548         }
549       else
550         {
551           populate_descriptives(t, heading_columns, 
552                                 row, &totals->stats[i]);
553         }
554
555       tab_text (t, 
556                 0, row,
557                 TAB_LEFT | TAT_TITLE, 
558                 var_to_string(dependent_var[i])
559                 );
560
561     }
562
563   tab_title (t, 0, _("Descriptives"));
564
565   tab_submit(t);
566
567 }
568
569
570
571 /* Fill in the descriptives data */
572 void
573 populate_descriptives(struct tab_table *tbl, int col, int row, 
574                       const struct metrics *m)
575 {
576
577   const double t = gsl_cdf_tdist_Qinv(1 - cmd.n_cinterval[0]/100.0/2.0, \
578                                        m->n -1);
579
580
581   tab_text (tbl, col, 
582             row,
583             TAB_LEFT | TAT_TITLE,
584             _("Mean"));
585
586   tab_float (tbl, col + 2,
587              row,
588              TAB_CENTER,
589              m->mean,
590              8,2);
591   
592   tab_float (tbl, col + 3,
593              row,
594              TAB_CENTER,
595              m->stderr,
596              8,3);
597   
598
599   tab_text (tbl, col, 
600             row + 1,
601             TAB_LEFT | TAT_TITLE | TAT_PRINTF,
602             _("%g%% Confidence Interval for Mean"), cmd.n_cinterval[0]);
603
604
605   tab_text (tbl, col + 1, 
606             row  + 1,
607             TAB_LEFT | TAT_TITLE,
608             _("Lower Bound"));
609
610   tab_float (tbl, col + 2,
611              row + 1,
612              TAB_CENTER,
613              m->mean - t * m->stderr, 
614              8,3);
615
616   tab_text (tbl, col + 1,  
617             row + 2,
618             TAB_LEFT | TAT_TITLE,
619             _("Upper Bound"));
620
621
622   tab_float (tbl, col + 2,
623              row + 2,
624              TAB_CENTER,
625              m->mean + t * m->stderr, 
626              8,3);
627
628   tab_text (tbl, col, 
629             row + 3,
630             TAB_LEFT | TAT_TITLE,
631             _("5% Trimmed Mean"));
632
633   tab_text (tbl, col, 
634             row + 4,
635             TAB_LEFT | TAT_TITLE,
636             _("Median"));
637
638   tab_text (tbl, col, 
639             row + 5,
640             TAB_LEFT | TAT_TITLE,
641             _("Variance"));
642
643   tab_float (tbl, col + 2,
644              row + 5,
645              TAB_CENTER,
646              m->var,
647              8,3);
648
649
650   tab_text (tbl, col, 
651             row + 6,
652             TAB_LEFT | TAT_TITLE,
653             _("Std. Deviation"));
654
655
656   tab_float (tbl, col + 2,
657              row + 6,
658              TAB_CENTER,
659              m->stddev,
660              8,3);
661
662   
663   tab_text (tbl, col, 
664             row + 7,
665             TAB_LEFT | TAT_TITLE,
666             _("Minimum"));
667
668   tab_float (tbl, col + 2,
669              row + 7,
670              TAB_CENTER,
671              m->min,
672              8,3);
673
674   tab_text (tbl, col, 
675             row + 8,
676             TAB_LEFT | TAT_TITLE,
677             _("Maximum"));
678
679   tab_float (tbl, col + 2,
680              row + 8,
681              TAB_CENTER,
682              m->max,
683              8,3);
684
685
686   tab_text (tbl, col, 
687             row + 9,
688             TAB_LEFT | TAT_TITLE,
689             _("Range"));
690
691
692   tab_float (tbl, col + 2,
693              row + 9,
694              TAB_CENTER,
695              m->max - m->min,
696              8,3);
697
698   tab_text (tbl, col, 
699             row + 10,
700             TAB_LEFT | TAT_TITLE,
701             _("Interquartile Range"));
702
703   tab_text (tbl, col, 
704             row + 11,
705             TAB_LEFT | TAT_TITLE,
706             _("Skewness"));
707
708   tab_text (tbl, col, 
709             row + 12,
710             TAB_LEFT | TAT_TITLE,
711             _("Kurtosis"));
712 }
713
714
715 void
716 show_summary(struct variable **dependent_var, 
717              int n_dep_var, 
718              struct factor *factor)
719 {
720   static const char *subtitle[]=
721     {
722       N_("Valid"),
723       N_("Missing"),
724       N_("Total")
725     };
726
727   int i;
728   int heading_columns ;
729   int n_cols;
730   const int heading_rows = 3;
731   struct tab_table *tbl;
732
733   int n_rows = heading_rows;
734
735   if ( !factor ) 
736     {
737       heading_columns = 1;
738       n_rows += n_dep_var;
739     }
740   else
741     {
742       assert(factor->indep_var);
743       if ( factor->subfactor == 0 ) 
744         {
745           heading_columns = 2;
746           n_rows += n_dep_var * hsh_count(factor->hash_table_val);
747         }
748       else
749         {
750           heading_columns = 3;
751           n_rows += n_dep_var * hsh_count(factor->hash_table_val) * 
752             hsh_count(factor->subfactor->hash_table_val) ;
753         }
754     }
755
756
757   n_cols = heading_columns + 6;
758
759   tbl = tab_create (n_cols,n_rows,0);
760   tab_headers (tbl, heading_columns, 0, heading_rows, 0);
761
762   tab_dim (tbl, tab_natural_dimensions);
763   
764   /* Outline the box and have vertical internal lines*/
765   tab_box (tbl, 
766            TAL_2, TAL_2,
767            -1, TAL_1,
768            0, 0,
769            n_cols - 1, n_rows - 1);
770
771   tab_hline (tbl, TAL_2, 0, n_cols - 1, heading_rows );
772   tab_hline (tbl, TAL_1, heading_columns, n_cols - 1, 1 );
773   tab_hline (tbl, TAL_1, 0, n_cols - 1, heading_rows -1 );
774
775   tab_vline (tbl, TAL_2, heading_columns, 0, n_rows - 1);
776
777
778   tab_title (tbl, 0, _("Case Processing Summary"));
779   
780
781   tab_joint_text(tbl, heading_columns, 0, 
782                  n_cols -1, 0,
783                  TAB_CENTER | TAT_TITLE,
784                  _("Cases"));
785
786   /* Remove lines ... */
787   tab_box (tbl, 
788            -1, -1,
789            TAL_0, TAL_0,
790            heading_columns, 0,
791            n_cols - 1, 0);
792
793   if ( factor ) 
794     {
795       tab_text (tbl, 1, heading_rows - 1, TAB_CENTER | TAT_TITLE, 
796                 var_to_string(factor->indep_var));
797
798       if ( factor->subfactor ) 
799         tab_text (tbl, 2, heading_rows - 1, TAB_CENTER | TAT_TITLE, 
800                   var_to_string(factor->subfactor->indep_var));
801     }
802
803   for ( i = 0 ; i < 3 ; ++i ) 
804     {
805       tab_text (tbl, heading_columns + i*2 , 2, TAB_CENTER | TAT_TITLE, _("N"));
806       tab_text (tbl, heading_columns + i*2 + 1, 2, TAB_CENTER | TAT_TITLE, 
807                 _("Percent"));
808
809       tab_joint_text(tbl, heading_columns + i*2 , 1,
810                      heading_columns + i*2 + 1, 1,
811                      TAB_CENTER | TAT_TITLE,
812                      subtitle[i]);
813
814       tab_box (tbl, -1, -1,
815                TAL_0, TAL_0,
816                heading_columns + i*2, 1,
817                heading_columns + i*2 + 1, 1);
818
819     }
820
821
822   for ( i = 0 ; i < n_dep_var ; ++i ) 
823     {
824       int n_subfactors = 1;
825       int n_factors = 1;
826         
827       if ( factor ) 
828         {
829           n_factors = hsh_count(factor->hash_table_val);
830           if (  factor->subfactor ) 
831             n_subfactors = hsh_count(factor->subfactor->hash_table_val);
832         }
833
834       tab_text (tbl, 
835                 0, i * n_factors * n_subfactors + heading_rows,
836                 TAB_LEFT | TAT_TITLE, 
837                 var_to_string(dependent_var[i])
838                 );
839
840       if ( factor  )
841         {
842           struct hsh_iterator hi;
843           const struct factor_statistics *fs;
844           int count = 0;
845
846           for (fs  = hsh_first(factor->hash_table_val, &hi);
847                fs != 0;
848                fs  = hsh_next(factor->hash_table_val,  &hi))
849             {
850               tab_text (tbl, 1, 
851                         i * n_factors * n_subfactors + heading_rows
852                         + count * n_subfactors,
853                         TAB_RIGHT | TAT_TITLE, 
854                         value_to_string(fs->id, factor->indep_var)
855                         );
856
857               if ( factor->subfactor ) 
858                 {
859                   int count2=0;
860                   struct hsh_iterator h2;
861                   const struct factor_statistics *sub_fs;
862                 
863                   for ( sub_fs = hsh_first(factor->subfactor->hash_table_val, 
864                                            &h2);
865                         sub_fs != 0;
866                         sub_fs = hsh_next(factor->subfactor->hash_table_val, 
867                                           &h2))
868                     {
869                         
870                       tab_text(tbl, 2, 
871                                i * n_factors * n_subfactors + heading_rows
872                                + count * n_subfactors + count2,
873                                TAB_RIGHT | TAT_TITLE ,
874                                value_to_string(sub_fs->id, factor->subfactor->indep_var)
875                                );
876                         
877                       count2++;
878                     }
879                 }
880               count ++;
881             }
882         }
883     }
884
885
886   tab_submit (tbl);
887   
888 }
889
890 static int bad_weight_warn = 1;
891
892
893 static void 
894 run_examine(const struct casefile *cf, void *cmd_)
895 {
896   struct hsh_iterator hi;
897   struct factor *fctr;
898
899   struct casereader *r;
900   struct ccase c;
901   int v;
902
903   const struct cmd_examine *cmd = (struct cmd_examine *) cmd_;
904
905   /* Make sure we haven't got rubbish left over from a 
906      previous split */
907   if ( hash_table_factors ) 
908     {
909       for ( fctr = hsh_first(hash_table_factors, &hi);
910             fctr != 0;
911             fctr = hsh_next (hash_table_factors, &hi) )
912         {
913           hsh_clear(fctr->hash_table_val);
914
915           while ( (fctr = fctr->subfactor) )
916             hsh_clear(fctr->hash_table_val);
917         }
918     }
919
920   for ( v = 0 ; v < n_dependent_vars ; ++v ) 
921     metrics_precalc(&totals->stats[v]);
922
923   for(r = casefile_get_reader (cf);
924       casereader_read (r, &c) ;
925       case_destroy (&c)) 
926     {
927       const double weight = 
928         dict_get_case_weight(default_dict, &c, &bad_weight_warn);
929
930       for ( v = 0 ; v < n_dependent_vars ; ++v ) 
931         {
932           const struct variable *var = dependent_vars[v];
933           const union value *val = case_data (&c, var->fv);
934
935           metrics_calc(&totals->stats[v], val->f, weight);
936         }
937
938       if ( hash_table_factors ) 
939         {
940           for ( fctr = hsh_first(hash_table_factors, &hi);
941                 fctr != 0;
942                 fctr = hsh_next (hash_table_factors, &hi) )
943             {
944               const union value *indep_val = 
945                 case_data(&c, fctr->indep_var->fv);
946
947               struct factor_statistics **foo = ( struct factor_statistics ** ) 
948                 hsh_probe(fctr->hash_table_val, (void *) &indep_val);
949
950               if ( !*foo ) 
951                 {
952                   *foo = xmalloc ( sizeof ( struct factor_statistics));
953                   (*foo)->id = indep_val;
954                   (*foo)->stats = xmalloc ( sizeof ( struct metrics ) 
955                                             * n_dependent_vars);
956
957                   for ( v =  0 ; v  < n_dependent_vars ; ++v ) 
958                     metrics_precalc( &(*foo)->stats[v] );
959
960                   hsh_insert(fctr->hash_table_val, (void *) *foo);
961                 }
962
963               for ( v =  0 ; v  < n_dependent_vars ; ++v ) 
964                 {
965                   const struct variable *var = dependent_vars[v];
966                   const union value *val = case_data (&c, var->fv);
967
968                   metrics_calc( &(*foo)->stats[v], val->f, weight );
969                 }
970
971               if ( fctr->subfactor  ) 
972                 {
973                   struct factor *sfctr  = fctr->subfactor;
974
975                   const union value *ii_val = 
976                     case_data (&c, sfctr->indep_var->fv);
977
978                   struct factor_statistics **bar = 
979                     (struct factor_statistics **)
980                     hsh_probe(sfctr->hash_table_val, (void *) &ii_val);
981
982                   if ( !*bar ) 
983                     {
984                       *bar = xmalloc ( sizeof ( struct factor_statistics));
985                       (*bar)->id = ii_val;
986                       (*bar)->stats = xmalloc ( sizeof ( struct metrics ) 
987                                                 * n_dependent_vars);
988                   
989                       for ( v =  0 ; v  < n_dependent_vars ; ++v ) 
990                         metrics_precalc( &(*bar)->stats[v] );
991
992                       hsh_insert(sfctr->hash_table_val, 
993                                  (void *) *bar);
994                     }
995
996                   for ( v =  0 ; v  < n_dependent_vars ; ++v ) 
997                     {
998                       const struct variable *var = dependent_vars[v];
999                       const union value *val = case_data (&c, var->fv);
1000
1001                       metrics_calc( &(*bar)->stats[v], val->f, weight );
1002                     }
1003                 }
1004             }
1005         }
1006
1007     }
1008
1009   for ( v = 0 ; v < n_dependent_vars ; ++v)
1010     {
1011       for ( fctr = hsh_first(hash_table_factors, &hi);
1012             fctr != 0;
1013             fctr = hsh_next (hash_table_factors, &hi) )
1014         {
1015           struct hsh_iterator h2;
1016           struct factor_statistics *fs;
1017
1018           for ( fs = hsh_first(fctr->hash_table_val,&h2);
1019                 fs != 0;
1020                 fs = hsh_next(fctr->hash_table_val,&h2))
1021               {
1022                 metrics_postcalc( &fs->stats[v] );
1023               }
1024
1025           if ( fctr->subfactor) 
1026             {
1027               struct hsh_iterator hsf;
1028               struct factor_statistics *fss;
1029
1030               for ( fss = hsh_first(fctr->subfactor->hash_table_val,&hsf);
1031                     fss != 0;
1032                     fss = hsh_next(fctr->subfactor->hash_table_val,&hsf))
1033                 {
1034                   metrics_postcalc( &fss->stats[v] );
1035                 }
1036             }
1037         }
1038
1039       metrics_postcalc(&totals->stats[v]);
1040     }
1041
1042   output_examine();
1043
1044 }
1045
1046
1047 static void 
1048 show_extremes(struct variable **dependent_var, 
1049               int n_dep_var, 
1050               struct factor *factor,
1051               int n_extremities)
1052 {
1053   int i;
1054   int heading_columns ;
1055   int n_cols;
1056   const int heading_rows = 1;
1057   struct tab_table *t;
1058
1059   int n_rows = heading_rows;
1060
1061   if ( !factor ) 
1062     {
1063       heading_columns = 1 + 1;
1064       n_rows += n_dep_var * 2 * n_extremities;
1065     }
1066   else
1067     {
1068       assert(factor->indep_var);
1069       if ( factor->subfactor == 0 ) 
1070         {
1071           heading_columns = 2 + 1;
1072           n_rows += n_dep_var * 2 * n_extremities 
1073             * hsh_count(factor->hash_table_val);
1074         }
1075       else
1076         {
1077           heading_columns = 3 + 1;
1078           n_rows += n_dep_var * 2 * n_extremities 
1079             * hsh_count(factor->hash_table_val)
1080             * hsh_count(factor->subfactor->hash_table_val) ;
1081         }
1082     }
1083
1084
1085   n_cols = heading_columns + 3;
1086
1087   t = tab_create (n_cols,n_rows,0);
1088   tab_headers (t, heading_columns, 0, heading_rows, 0);
1089
1090   tab_dim (t, tab_natural_dimensions);
1091   
1092   /* Outline the box and have vertical internal lines*/
1093   tab_box (t, 
1094            TAL_2, TAL_2,
1095            -1, TAL_1,
1096            0, 0,
1097            n_cols - 1, n_rows - 1);
1098
1099
1100
1101   tab_hline (t, TAL_2, 0, n_cols - 1, heading_rows );
1102
1103   tab_title (t, 0, _("Extreme Values"));
1104
1105
1106
1107
1108   /* Remove lines ... */
1109   tab_box (t, 
1110            -1, -1,
1111            TAL_0, TAL_0,
1112            heading_columns, 0,
1113            n_cols - 1, 0);
1114
1115   if ( factor ) 
1116     {
1117       tab_text (t, 1, heading_rows - 1, TAB_CENTER | TAT_TITLE, 
1118                 var_to_string(factor->indep_var));
1119
1120       if ( factor->subfactor ) 
1121         tab_text (t, 2, heading_rows - 1, TAB_CENTER | TAT_TITLE, 
1122                   var_to_string(factor->subfactor->indep_var));
1123     }
1124
1125   tab_text (t, n_cols - 1, 0, TAB_CENTER | TAT_TITLE, _("Value"));
1126   tab_text (t, n_cols - 2, 0, TAB_CENTER | TAT_TITLE, _("Case Number"));
1127
1128
1129   for ( i = 0 ; i < n_dep_var ; ++i ) 
1130     {
1131       int n_subfactors = 1;
1132       int n_factors = 1;
1133         
1134       if ( factor ) 
1135         {
1136           n_factors = hsh_count(factor->hash_table_val);
1137           if (  factor->subfactor ) 
1138             n_subfactors = hsh_count(factor->subfactor->hash_table_val);
1139         }
1140
1141       tab_text (t, 
1142                 0, i * 2 * n_extremities * n_factors * 
1143                 n_subfactors + heading_rows,
1144                 TAB_LEFT | TAT_TITLE, 
1145                 var_to_string(dependent_var[i])
1146                 );
1147
1148
1149       if ( i > 0 ) 
1150         tab_hline (t, 
1151                    TAL_1, 0, n_cols - 1,  
1152                    heading_rows + 2 * n_extremities * 
1153                    (i * n_factors * n_subfactors )
1154                    );
1155
1156       if ( factor  )
1157         {
1158           struct hsh_iterator hi;
1159           const struct factor_statistics *fs;
1160           int count = 0;
1161
1162           for ( fs  = hsh_first(factor->hash_table_val, &hi);
1163                 fs != 0;
1164                 fs  = hsh_next(factor->hash_table_val,  &hi))
1165             {
1166               tab_text (t, 1, heading_rows + 2 * n_extremities * 
1167                         (i * n_factors * n_subfactors 
1168                          + count * n_subfactors),
1169                         TAB_RIGHT | TAT_TITLE, 
1170                         value_to_string(fs->id, factor->indep_var)
1171                         );
1172
1173               if ( count > 0 ) 
1174                 tab_hline (t, TAL_1, 1, n_cols - 1,  
1175                            heading_rows + 2 * n_extremities *
1176                            (i * n_factors * n_subfactors 
1177                             + count * n_subfactors));
1178
1179
1180               if ( factor->subfactor ) 
1181                 {
1182                   struct hsh_iterator h2;
1183                   const struct factor_statistics *sub_fs;
1184                   int count2=0;
1185
1186                   for ( sub_fs = hsh_first(factor->subfactor->hash_table_val, 
1187                                            &h2);
1188                         sub_fs != 0;
1189                         sub_fs = hsh_next(factor->subfactor->hash_table_val, 
1190                                           &h2))
1191                     {
1192                         
1193                       tab_text(t, 2, heading_rows + 2 * n_extremities *
1194                                (i * n_factors * n_subfactors 
1195                                 + count * n_subfactors + count2 ),
1196                                TAB_RIGHT | TAT_TITLE ,
1197                                value_to_string(sub_fs->id, 
1198                                                factor->subfactor->indep_var)
1199                                );
1200
1201
1202                       if ( count2 > 0 ) 
1203                         tab_hline (t, TAL_1, 2, n_cols - 1,  
1204                                    heading_rows + 2 * n_extremities *
1205                                    (i * n_factors * n_subfactors 
1206                                     + count * n_subfactors + count2 ));
1207
1208                       populate_extremities(t,3, 
1209                                            heading_rows + 2 * n_extremities *
1210                                            (i * n_factors * n_subfactors 
1211                                             + count * n_subfactors + count2),
1212                                            n_extremities );
1213                                            
1214                       count2++;
1215                     }
1216                 }
1217               else
1218                 {
1219                   populate_extremities(t,2, 
1220                                        heading_rows + 2 * n_extremities *
1221                                        (i * n_factors * n_subfactors 
1222                                         + count * n_subfactors),
1223                                        n_extremities);
1224                 }
1225
1226               count ++;
1227             }
1228         }
1229       else
1230         {
1231           populate_extremities(t, 1, 
1232                                heading_rows + 2 * n_extremities *
1233                                (i * n_factors * n_subfactors ),
1234                                n_extremities);
1235
1236         }
1237     }
1238
1239   tab_submit (t);
1240 }
1241
1242
1243
1244 /* Fill in the extremities table */
1245 void 
1246 populate_extremities(struct tab_table *t, int col, int row, int n)
1247 {
1248   int i;
1249
1250   tab_text(t, col, row,
1251            TAB_RIGHT | TAT_TITLE ,
1252            _("Highest")
1253            );
1254
1255   tab_text(t, col, row + n ,
1256            TAB_RIGHT | TAT_TITLE ,
1257            _("Lowest")
1258            );
1259
1260   for (i = 0; i < n ; ++i ) 
1261     {
1262       tab_float(t, col + 1, row + i,
1263                 TAB_RIGHT,
1264                 i + 1, 8, 0);
1265
1266       tab_float(t, col + 1, row + i + n,
1267                 TAB_RIGHT,
1268                 i + 1, 8, 0);
1269     }
1270 }
1271
1272