5695ed6478b64490095ea0c8abde83873fb38030
[pspp-builds.git] / src / language / stats / crosstabs.q
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2006, 2009 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 /* FIXME:
18
19    - Pearson's R (but not Spearman!) is off a little.
20    - T values for Spearman's R and Pearson's R are wrong.
21    - How to calculate significance of symmetric and directional measures?
22    - Asymmetric ASEs and T values for lambda are wrong.
23    - ASE of Goodman and Kruskal's tau is not calculated.
24    - ASE of symmetric somers' d is wrong.
25    - Approx. T of uncertainty coefficient is wrong.
26
27 */
28
29 #include <config.h>
30
31 #include <ctype.h>
32 #include <gsl/gsl_cdf.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35
36 #include <data/case.h>
37 #include <data/casegrouper.h>
38 #include <data/casereader.h>
39 #include <data/data-out.h>
40 #include <data/dictionary.h>
41 #include <data/format.h>
42 #include <data/procedure.h>
43 #include <data/value-labels.h>
44 #include <data/variable.h>
45 #include <language/command.h>
46 #include <language/dictionary/split-file.h>
47 #include <language/lexer/lexer.h>
48 #include <language/lexer/variable-parser.h>
49 #include <libpspp/array.h>
50 #include <libpspp/assertion.h>
51 #include <libpspp/compiler.h>
52 #include <libpspp/hash.h>
53 #include <libpspp/hmap.h>
54 #include <libpspp/hmapx.h>
55 #include <libpspp/message.h>
56 #include <libpspp/misc.h>
57 #include <libpspp/pool.h>
58 #include <libpspp/str.h>
59 #include <output/output.h>
60 #include <output/table.h>
61
62 #include "minmax.h"
63 #include "xalloc.h"
64 #include "xsize.h"
65
66 #include "gettext.h"
67 #define _(msgid) gettext (msgid)
68 #define N_(msgid) msgid
69
70 /* (headers) */
71
72 /* (specification)
73    crosstabs (crs_):
74      *^tables=custom;
75      +variables=custom;
76      missing=miss:!table/include/report;
77      +write[wr_]=none,cells,all;
78      +format=fmt:!labels/nolabels/novallabs,
79              val:!avalue/dvalue,
80              indx:!noindex/index,
81              tabl:!tables/notables,
82              box:!box/nobox,
83              pivot:!pivot/nopivot;
84      +cells[cl_]=count,expected,row,column,total,residual,sresidual,
85                  asresidual,all,none;
86      +statistics[st_]=chisq,phi,cc,lambda,uc,none,btau,ctau,risk,gamma,d,
87                       kappa,eta,corr,all.
88 */
89 /* (declarations) */
90 /* (functions) */
91
92 /* Number of chi-square statistics. */
93 #define N_CHISQ 5
94
95 /* Number of symmetric statistics. */
96 #define N_SYMMETRIC 9
97
98 /* Number of directional statistics. */
99 #define N_DIRECTIONAL 13
100
101 /* A single table entry for general mode. */
102 struct table_entry
103   {
104     struct hmap_node node;      /* Entry in hash table. */
105     double freq;                /* Frequency count. */
106     union value values[1];      /* Values. */
107   };
108
109 static size_t
110 table_entry_size (size_t n_values)
111 {
112   return (offsetof (struct table_entry, values)
113           + n_values * sizeof (union value));
114 }
115
116 /* Indexes into the 'vars' member of struct pivot_table and
117    struct crosstab member. */
118 enum
119   {
120     ROW_VAR = 0,                /* Row variable. */
121     COL_VAR = 1                 /* Column variable. */
122     /* Higher indexes cause multiple tables to be output. */
123   };
124
125 /* A crosstabulation of 2 or more variables. */
126 struct pivot_table
127   {
128     struct fmt_spec weight_format; /* Format for weight variable. */
129     double missing;             /* Weight of missing cases. */
130
131     /* Variables (2 or more). */
132     int n_vars;
133     const struct variable **vars;
134
135     /* Constants (0 or more). */
136     int n_consts;
137     const struct variable **const_vars;
138     union value *const_values;
139
140     /* Data. */
141     struct hmap data;
142     struct table_entry **entries;
143     size_t n_entries;
144
145     /* Column values, number of columns. */
146     union value *cols;
147     int n_cols;
148
149     /* Row values, number of rows. */
150     union value *rows;
151     int n_rows;
152
153     /* Number of statistically interesting columns/rows
154        (columns/rows with data in them). */
155     int ns_cols, ns_rows;
156
157     /* Matrix contents. */
158     double *mat;                /* Matrix proper. */
159     double *row_tot;            /* Row totals. */
160     double *col_tot;            /* Column totals. */
161     double total;               /* Grand total. */
162   };
163
164 /* Integer mode variable info. */
165 struct var_range
166   {
167     int min;                    /* Minimum value. */
168     int max;                    /* Maximum value + 1. */
169     int count;                  /* max - min. */
170   };
171
172 static inline struct var_range *
173 get_var_range (const struct variable *v)
174 {
175   return var_get_aux (v);
176 }
177
178 struct crosstabs_proc
179   {
180     const struct dictionary *dict;
181     enum { INTEGER, GENERAL } mode;
182     enum mv_class exclude;
183     bool pivot;
184     bool bad_warn;
185     struct fmt_spec weight_format;
186
187     /* Variables specifies on VARIABLES. */
188     const struct variable **variables;
189     size_t n_variables;
190
191     /* TABLES. */
192     struct pivot_table *pivots;
193     int n_pivots;
194
195     /* CELLS. */
196     int n_cells;                /* Number of cells requested. */
197     unsigned int cells;         /* Bit k is 1 if cell k is requested. */
198     int a_cells[CRS_CL_count];  /* 0...n_cells-1 are the requested cells. */
199
200     /* STATISTICS. */
201     unsigned int statistics;    /* Bit k is 1 if statistic k is requested. */
202   };
203
204 /* Auxiliary data structure for tab_dim. */
205 struct crosstabs_dim_aux
206   {
207     enum mv_class exclude;
208   };
209
210 static void
211 init_proc (struct crosstabs_proc *proc, struct dataset *ds)
212 {
213   const struct variable *wv = dict_get_weight (dataset_dict (ds));
214   proc->dict = dataset_dict (ds);
215   proc->bad_warn = true;
216   proc->variables = NULL;
217   proc->n_variables = 0;
218   proc->pivots = NULL;
219   proc->n_pivots = 0;
220   proc->weight_format = wv ? *var_get_print_format (wv) : F_8_0;
221 }
222
223 static void
224 free_proc (struct crosstabs_proc *proc)
225 {
226   struct pivot_table *pt;
227
228   free (proc->variables);
229   for (pt = &proc->pivots[0]; pt < &proc->pivots[proc->n_pivots]; pt++)
230     {
231       free (pt->vars);
232       free (pt->const_vars);
233       /* We must not call value_destroy on const_values because
234          it is a wild pointer; it never pointed to anything owned
235          by the pivot_table.
236
237          The rest of the data was allocated and destroyed at a
238          lower level already. */
239     }
240   free (proc->pivots);
241 }
242
243 static int internal_cmd_crosstabs (struct lexer *lexer, struct dataset *ds,
244                                    struct crosstabs_proc *);
245 static bool should_tabulate_case (const struct pivot_table *,
246                                   const struct ccase *, enum mv_class exclude);
247 static void tabulate_general_case (struct pivot_table *, const struct ccase *,
248                                    double weight);
249 static void tabulate_integer_case (struct pivot_table *, const struct ccase *,
250                                    double weight);
251 static void postcalc (struct crosstabs_proc *);
252 static void submit (struct crosstabs_proc *, struct pivot_table *,
253                     struct tab_table *);
254
255 /* Parse and execute CROSSTABS, then clean up. */
256 int
257 cmd_crosstabs (struct lexer *lexer, struct dataset *ds)
258 {
259   struct crosstabs_proc proc;
260   int result;
261
262   init_proc (&proc, ds);
263   result = internal_cmd_crosstabs (lexer, ds, &proc);
264   free_proc (&proc);
265
266   return result;
267 }
268
269 /* Parses and executes the CROSSTABS procedure. */
270 static int
271 internal_cmd_crosstabs (struct lexer *lexer, struct dataset *ds,
272                         struct crosstabs_proc *proc)
273 {
274   struct casegrouper *grouper;
275   struct casereader *input, *group;
276   struct cmd_crosstabs cmd;
277   struct pivot_table *pt;
278   bool ok;
279   int i;
280
281   if (!parse_crosstabs (lexer, ds, &cmd, proc))
282     return CMD_FAILURE;
283
284   proc->mode = proc->n_variables ? INTEGER : GENERAL;
285
286   /* CELLS. */
287   if (!cmd.sbc_cells)
288     proc->cells = 1u << CRS_CL_COUNT;
289   else if (cmd.a_cells[CRS_CL_ALL])
290     proc->cells = UINT_MAX;
291   else
292     {
293       proc->cells = 0;
294       for (i = 0; i < CRS_CL_count; i++)
295         if (cmd.a_cells[i])
296           proc->cells |= 1u << i;
297       if (proc->cells == 0)
298         proc->cells = ((1u << CRS_CL_COUNT)
299                        | (1u << CRS_CL_ROW)
300                        | (1u << CRS_CL_COLUMN)
301                        | (1u << CRS_CL_TOTAL));
302     }
303   proc->cells &= ((1u << CRS_CL_count) - 1);
304   proc->cells &= ~((1u << CRS_CL_NONE) | (1u << CRS_CL_ALL));
305   proc->n_cells = 0;
306   for (i = 0; i < CRS_CL_count; i++)
307     if (proc->cells & (1u << i))
308       proc->a_cells[proc->n_cells++] = i;
309
310   /* STATISTICS. */
311   if (cmd.a_statistics[CRS_ST_ALL])
312     proc->statistics = UINT_MAX;
313   else if (cmd.sbc_statistics)
314     {
315       int i;
316
317       proc->statistics = 0;
318       for (i = 0; i < CRS_ST_count; i++)
319         if (cmd.a_statistics[i])
320           proc->statistics |= 1u << i;
321       if (proc->statistics == 0)
322         proc->statistics |= 1u << CRS_ST_CHISQ;
323     }
324   else
325     proc->statistics = 0;
326
327   /* MISSING. */
328   proc->exclude = (cmd.miss == CRS_TABLE ? MV_ANY
329                    : cmd.miss == CRS_INCLUDE ? MV_SYSTEM
330                    : MV_NEVER);
331   if (proc->mode == GENERAL && proc->mode == MV_NEVER)
332     {
333       msg (SE, _("Missing mode REPORT not allowed in general mode.  "
334                  "Assuming MISSING=TABLE."));
335       proc->mode = MV_ANY;
336     }
337
338   /* PIVOT. */
339   proc->pivot = cmd.pivot == CRS_PIVOT;
340
341   input = casereader_create_filter_weight (proc_open (ds), dataset_dict (ds),
342                                            NULL, NULL);
343   grouper = casegrouper_create_splits (input, dataset_dict (ds));
344   while (casegrouper_get_next_group (grouper, &group))
345     {
346       struct ccase *c;
347
348       /* Output SPLIT FILE variables. */
349       c = casereader_peek (group, 0);
350       if (c != NULL)
351         {
352           output_split_file_values (ds, c);
353           case_unref (c);
354         }
355
356       /* Tabulate. */
357       for (; (c = casereader_read (group)) != NULL; case_unref (c))
358         for (pt = &proc->pivots[0]; pt < &proc->pivots[proc->n_pivots]; pt++)
359           {
360             double weight = dict_get_case_weight (dataset_dict (ds), c,
361                                                   &proc->bad_warn);
362             if (should_tabulate_case (pt, c, proc->exclude))
363               {
364                 if (proc->mode == GENERAL)
365                   tabulate_general_case (pt, c, weight);
366                 else
367                   tabulate_integer_case (pt, c, weight);
368               }
369             else
370               pt->missing += weight;
371           }
372       casereader_destroy (group);
373
374       /* Output. */
375       postcalc (proc);
376     }
377   ok = casegrouper_destroy (grouper);
378   ok = proc_commit (ds) && ok;
379
380   return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
381 }
382
383 /* Parses the TABLES subcommand. */
384 static int
385 crs_custom_tables (struct lexer *lexer, struct dataset *ds,
386                    struct cmd_crosstabs *cmd UNUSED, void *proc_)
387 {
388   struct crosstabs_proc *proc = proc_;
389   struct const_var_set *var_set;
390   int n_by;
391   const struct variable ***by = NULL;
392   int *by_iter;
393   size_t *by_nvar = NULL;
394   size_t nx = 1;
395   bool ok = false;
396   int i;
397
398   /* Ensure that this is a TABLES subcommand. */
399   if (!lex_match_id (lexer, "TABLES")
400       && (lex_token (lexer) != T_ID ||
401           dict_lookup_var (dataset_dict (ds), lex_tokid (lexer)) == NULL)
402       && lex_token (lexer) != T_ALL)
403     return 2;
404   lex_match (lexer, '=');
405
406   if (proc->variables != NULL)
407     var_set = const_var_set_create_from_array (proc->variables,
408                                                proc->n_variables);
409   else
410     var_set = const_var_set_create_from_dict (dataset_dict (ds));
411   assert (var_set != NULL);
412
413   for (n_by = 0; ;)
414     {
415       by = xnrealloc (by, n_by + 1, sizeof *by);
416       by_nvar = xnrealloc (by_nvar, n_by + 1, sizeof *by_nvar);
417       if (!parse_const_var_set_vars (lexer, var_set, &by[n_by], &by_nvar[n_by],
418                                      PV_NO_DUPLICATE | PV_NO_SCRATCH))
419         goto done;
420       if (xalloc_oversized (nx, by_nvar[n_by]))
421         {
422           msg (SE, _("Too many cross-tabulation variables or dimensions."));
423           goto done;
424         }
425       nx *= by_nvar[n_by];
426       n_by++;
427
428       if (!lex_match (lexer, T_BY))
429         {
430           if (n_by < 2)
431             {
432               lex_error (lexer, _("expecting BY"));
433               goto done;
434             }
435           else
436             break;
437         }
438     }
439
440   by_iter = xcalloc (n_by, sizeof *by_iter);
441   proc->pivots = xnrealloc (proc->pivots,
442                             proc->n_pivots + nx, sizeof *proc->pivots);
443   for (i = 0; i < nx; i++)
444     {
445       struct pivot_table *pt = &proc->pivots[proc->n_pivots++];
446       int j;
447
448       pt->weight_format = proc->weight_format;
449       pt->missing = 0.;
450       pt->n_vars = n_by;
451       pt->vars = xmalloc (n_by * sizeof *pt->vars);
452       pt->n_consts = 0;
453       pt->const_vars = NULL;
454       pt->const_values = NULL;
455       hmap_init (&pt->data);
456       pt->entries = NULL;
457       pt->n_entries = 0;
458
459       for (j = 0; j < n_by; j++)
460         pt->vars[j] = by[j][by_iter[j]];
461
462       for (j = n_by - 1; j >= 0; j--)
463         {
464           if (++by_iter[j] < by_nvar[j])
465             break;
466           by_iter[j] = 0;
467         }
468     }
469   free (by_iter);
470   ok = true;
471
472 done:
473   /* All return paths lead here. */
474   for (i = 0; i < n_by; i++)
475     free (by[i]);
476   free (by);
477   free (by_nvar);
478
479   const_var_set_destroy (var_set);
480
481   return ok;
482 }
483
484 /* Parses the VARIABLES subcommand. */
485 static int
486 crs_custom_variables (struct lexer *lexer, struct dataset *ds,
487                       struct cmd_crosstabs *cmd UNUSED, void *proc_)
488 {
489   struct crosstabs_proc *proc = proc_;
490   if (proc->n_pivots)
491     {
492       msg (SE, _("VARIABLES must be specified before TABLES."));
493       return 0;
494     }
495
496   lex_match (lexer, '=');
497
498   for (;;)
499     {
500       size_t orig_nv = proc->n_variables;
501       size_t i;
502
503       long min, max;
504
505       if (!parse_variables_const (lexer, dataset_dict (ds),
506                                   &proc->variables, &proc->n_variables,
507                                   (PV_APPEND | PV_NUMERIC
508                                    | PV_NO_DUPLICATE | PV_NO_SCRATCH)))
509         return 0;
510
511       if (lex_token (lexer) != '(')
512         {
513           lex_error (lexer, "expecting `('");
514           goto lossage;
515         }
516       lex_get (lexer);
517
518       if (!lex_force_int (lexer))
519         goto lossage;
520       min = lex_integer (lexer);
521       lex_get (lexer);
522
523       lex_match (lexer, ',');
524
525       if (!lex_force_int (lexer))
526         goto lossage;
527       max = lex_integer (lexer);
528       if (max < min)
529         {
530           msg (SE, _("Maximum value (%ld) less than minimum value (%ld)."),
531                max, min);
532           goto lossage;
533         }
534       lex_get (lexer);
535
536       if (lex_token (lexer) != ')')
537         {
538           lex_error (lexer, "expecting `)'");
539           goto lossage;
540         }
541       lex_get (lexer);
542
543       for (i = orig_nv; i < proc->n_variables; i++)
544         {
545           struct var_range *vr = xmalloc (sizeof *vr);
546           vr->min = min;
547           vr->max = max + 1.;
548           vr->count = max - min + 1;
549           var_attach_aux (proc->variables[i], vr, var_dtor_free);
550         }
551
552       if (lex_token (lexer) == '/')
553         break;
554     }
555
556   return 1;
557
558  lossage:
559   free (proc->variables);
560   proc->variables = NULL;
561   proc->n_variables = 0;
562   return 0;
563 }
564 \f
565 /* Data file processing. */
566
567 static bool
568 should_tabulate_case (const struct pivot_table *pt, const struct ccase *c,
569                       enum mv_class exclude)
570 {
571   int j;
572   for (j = 0; j < pt->n_vars; j++)
573     {
574       const struct variable *var = pt->vars[j];
575       struct var_range *range = get_var_range (var);
576
577       if (var_is_value_missing (var, case_data (c, var), exclude))
578         return false;
579
580       if (range != NULL)
581         {
582           double num = case_num (c, var);
583           if (num < range->min || num > range->max)
584             return false;
585         }
586     }
587   return true;
588 }
589
590 static void
591 tabulate_integer_case (struct pivot_table *pt, const struct ccase *c,
592                        double weight)
593 {
594   struct table_entry *te;
595   size_t hash;
596   int j;
597
598   hash = 0;
599   for (j = 0; j < pt->n_vars; j++)
600     {
601       /* Throw away fractional parts of values. */
602       hash = hash_int (case_num (c, pt->vars[j]), hash);
603     }
604
605   HMAP_FOR_EACH_WITH_HASH (te, struct table_entry, node, hash, &pt->data)
606     {
607       for (j = 0; j < pt->n_vars; j++)
608         if ((int) case_num (c, pt->vars[j]) != (int) te->values[j].f)
609           goto no_match;
610
611       /* Found an existing entry. */
612       te->freq += weight;
613       return;
614
615     no_match: ;
616     }
617
618   /* No existing entry.  Create a new one. */
619   te = xmalloc (table_entry_size (pt->n_vars));
620   te->freq = weight;
621   for (j = 0; j < pt->n_vars; j++)
622     te->values[j].f = (int) case_num (c, pt->vars[j]);
623   hmap_insert (&pt->data, &te->node, hash);
624 }
625
626 static void
627 tabulate_general_case (struct pivot_table *pt, const struct ccase *c,
628                        double weight)
629 {
630   struct table_entry *te;
631   size_t hash;
632   int j;
633
634   hash = 0;
635   for (j = 0; j < pt->n_vars; j++)
636     {
637       const struct variable *var = pt->vars[j];
638       hash = value_hash (case_data (c, var), var_get_width (var), hash);
639     }
640
641   HMAP_FOR_EACH_WITH_HASH (te, struct table_entry, node, hash, &pt->data)
642     {
643       for (j = 0; j < pt->n_vars; j++)
644         {
645           const struct variable *var = pt->vars[j];
646           if (!value_equal (case_data (c, var), &te->values[j],
647                             var_get_width (var)))
648             goto no_match;
649         }
650
651       /* Found an existing entry. */
652       te->freq += weight;
653       return;
654
655     no_match: ;
656     }
657
658   /* No existing entry.  Create a new one. */
659   te = xmalloc (table_entry_size (pt->n_vars));
660   te->freq = weight;
661   for (j = 0; j < pt->n_vars; j++)
662     {
663       const struct variable *var = pt->vars[j];
664       int width = var_get_width (var);
665       value_init (&te->values[j], width);
666       value_copy (&te->values[j], case_data (c, var), width);
667     }
668   hmap_insert (&pt->data, &te->node, hash);
669 }
670 \f
671 /* Post-data reading calculations. */
672
673 static int compare_table_entry_vars_3way (const struct table_entry *a,
674                                           const struct table_entry *b,
675                                           const struct pivot_table *pt,
676                                           int idx0, int idx1);
677 static int compare_table_entry_3way (const void *ap_, const void *bp_,
678                                      const void *pt_);
679 static void enum_var_values (const struct pivot_table *, int var_idx,
680                              union value **valuesp, int *n_values);
681 static void output_pivot_table (struct crosstabs_proc *,
682                                 struct pivot_table *);
683 static void make_pivot_table_subset (struct pivot_table *pt,
684                                      size_t row0, size_t row1,
685                                      struct pivot_table *subset);
686 static void make_summary_table (struct crosstabs_proc *);
687 static bool find_crosstab (struct pivot_table *, size_t *row0p, size_t *row1p);
688
689 static void
690 postcalc (struct crosstabs_proc *proc)
691 {
692   struct pivot_table *pt;
693
694   /* Convert hash tables into sorted arrays of entries. */
695   for (pt = &proc->pivots[0]; pt < &proc->pivots[proc->n_pivots]; pt++)
696     {
697       struct table_entry *e;
698       size_t i;
699
700       pt->n_entries = hmap_count (&pt->data);
701       pt->entries = xnmalloc (pt->n_entries, sizeof *pt->entries);
702       i = 0;
703       HMAP_FOR_EACH (e, struct table_entry, node, &pt->data)
704         pt->entries[i++] = e;
705       hmap_destroy (&pt->data);
706
707       sort (pt->entries, pt->n_entries, sizeof *pt->entries,
708             compare_table_entry_3way, pt);
709     }
710
711   make_summary_table (proc);
712
713   /* Output each pivot table. */
714   for (pt = &proc->pivots[0]; pt < &proc->pivots[proc->n_pivots]; pt++)
715     {
716       if (proc->pivot || pt->n_vars == 2)
717         output_pivot_table (proc, pt);
718       else
719         {
720           size_t row0 = 0, row1 = 0;
721           while (find_crosstab (pt, &row0, &row1))
722             {
723               struct pivot_table subset;
724               make_pivot_table_subset (pt, row0, row1, &subset);
725               output_pivot_table (proc, &subset);
726             }
727         }
728     }
729
730   /* Free output and prepare for next split file. */
731   for (pt = &proc->pivots[0]; pt < &proc->pivots[proc->n_pivots]; pt++)
732     {
733       size_t i;
734
735       pt->missing = 0.0;
736
737       /* Free only the members that were allocated in this
738          function.  The other pointer members are either both
739          allocated and destroyed at a lower level (in
740          output_pivot_table), or both allocated and destroyed at
741          a higher level (in crs_custom_tables and free_proc,
742          respectively). */
743       for (i = 0; i < pt->n_entries; i++)
744         free (pt->entries[i]);
745       free (pt->entries);
746     }
747 }
748
749 static void
750 make_pivot_table_subset (struct pivot_table *pt, size_t row0, size_t row1,
751                          struct pivot_table *subset)
752 {
753   *subset = *pt;
754   if (pt->n_vars > 2)
755     {
756       assert (pt->n_consts == 0);
757       subset->missing = pt->missing;
758       subset->n_vars = 2;
759       subset->vars = pt->vars;
760       subset->n_consts = pt->n_vars - 2;
761       subset->const_vars = pt->vars + 2;
762       subset->const_values = &pt->entries[row0]->values[2];
763     }
764   subset->entries = &pt->entries[row0];
765   subset->n_entries = row1 - row0;
766 }
767
768 static int
769 compare_table_entry_var_3way (const struct table_entry *a,
770                               const struct table_entry *b,
771                               const struct pivot_table *pt,
772                               int idx)
773 {
774   return value_compare_3way (&a->values[idx], &b->values[idx],
775                              var_get_width (pt->vars[idx]));
776 }
777
778 static int
779 compare_table_entry_vars_3way (const struct table_entry *a,
780                                const struct table_entry *b,
781                                const struct pivot_table *pt,
782                                int idx0, int idx1)
783 {
784   int i;
785
786   for (i = idx1 - 1; i >= idx0; i--)
787     {
788       int cmp = compare_table_entry_var_3way (a, b, pt, i);
789       if (cmp != 0)
790         return cmp;
791     }
792   return 0;
793 }
794
795 /* Compare the struct table_entry at *AP to the one at *BP and
796    return a strcmp()-type result. */
797 static int
798 compare_table_entry_3way (const void *ap_, const void *bp_, const void *pt_)
799 {
800   const struct table_entry *const *ap = ap_;
801   const struct table_entry *const *bp = bp_;
802   const struct table_entry *a = *ap;
803   const struct table_entry *b = *bp;
804   const struct pivot_table *pt = pt_;
805   int cmp;
806
807   cmp = compare_table_entry_vars_3way (a, b, pt, 2, pt->n_vars);
808   if (cmp != 0)
809     return cmp;
810
811   cmp = compare_table_entry_var_3way (a, b, pt, ROW_VAR);
812   if (cmp != 0)
813     return cmp;
814
815   return compare_table_entry_var_3way (a, b, pt, COL_VAR);
816 }
817
818 static int
819 find_first_difference (const struct pivot_table *pt, size_t row)
820 {
821   if (row == 0)
822     return pt->n_vars - 1;
823   else
824     {
825       const struct table_entry *a = pt->entries[row];
826       const struct table_entry *b = pt->entries[row - 1];
827       int col;
828
829       for (col = pt->n_vars - 1; col >= 0; col--)
830         if (compare_table_entry_var_3way (a, b, pt, col))
831           return col;
832       NOT_REACHED ();
833     }
834 }
835
836 /* Output a table summarizing the cases processed. */
837 static void
838 make_summary_table (struct crosstabs_proc *proc)
839 {
840   struct tab_table *summary;
841   struct pivot_table *pt;
842   struct string name;
843   int i;
844
845   summary = tab_create (7, 3 + proc->n_pivots);
846   tab_title (summary, _("Summary."));
847   tab_headers (summary, 1, 0, 3, 0);
848   tab_joint_text (summary, 1, 0, 6, 0, TAB_CENTER, _("Cases"));
849   tab_joint_text (summary, 1, 1, 2, 1, TAB_CENTER, _("Valid"));
850   tab_joint_text (summary, 3, 1, 4, 1, TAB_CENTER, _("Missing"));
851   tab_joint_text (summary, 5, 1, 6, 1, TAB_CENTER, _("Total"));
852   tab_hline (summary, TAL_1, 1, 6, 1);
853   tab_hline (summary, TAL_1, 1, 6, 2);
854   tab_vline (summary, TAL_1, 3, 1, 1);
855   tab_vline (summary, TAL_1, 5, 1, 1);
856   for (i = 0; i < 3; i++)
857     {
858       tab_text (summary, 1 + i * 2, 2, TAB_RIGHT, _("N"));
859       tab_text (summary, 2 + i * 2, 2, TAB_RIGHT, _("Percent"));
860     }
861   tab_offset (summary, 0, 3);
862
863   ds_init_empty (&name);
864   for (pt = &proc->pivots[0]; pt < &proc->pivots[proc->n_pivots]; pt++)
865     {
866       double valid;
867       double n[3];
868       size_t i;
869
870       tab_hline (summary, TAL_1, 0, 6, 0);
871
872       ds_clear (&name);
873       for (i = 0; i < pt->n_vars; i++)
874         {
875           if (i > 0)
876             ds_put_cstr (&name, " * ");
877           ds_put_cstr (&name, var_to_string (pt->vars[i]));
878         }
879       tab_text (summary, 0, 0, TAB_LEFT, ds_cstr (&name));
880
881       valid = 0.;
882       for (i = 0; i < pt->n_entries; i++)
883         valid += pt->entries[i]->freq;
884
885       n[0] = valid;
886       n[1] = pt->missing;
887       n[2] = n[0] + n[1];
888       for (i = 0; i < 3; i++)
889         {
890           tab_double (summary, i * 2 + 1, 0, TAB_RIGHT, n[i],
891                       &proc->weight_format);
892           tab_text_format (summary, i * 2 + 2, 0, TAB_RIGHT, "%.1f%%",
893                            n[i] / n[2] * 100.);
894         }
895
896       tab_next_row (summary);
897     }
898   ds_destroy (&name);
899
900   submit (proc, NULL, summary);
901 }
902 \f
903 /* Output. */
904
905 static struct tab_table *create_crosstab_table (struct crosstabs_proc *,
906                                                 struct pivot_table *);
907 static struct tab_table *create_chisq_table (struct pivot_table *);
908 static struct tab_table *create_sym_table (struct pivot_table *);
909 static struct tab_table *create_risk_table (struct pivot_table *);
910 static struct tab_table *create_direct_table (struct pivot_table *);
911 static void display_dimensions (struct crosstabs_proc *, struct pivot_table *,
912                                 struct tab_table *, int first_difference);
913 static void display_crosstabulation (struct crosstabs_proc *,
914                                      struct pivot_table *,
915                                      struct tab_table *);
916 static void display_chisq (struct pivot_table *, struct tab_table *,
917                            bool *showed_fisher);
918 static void display_symmetric (struct crosstabs_proc *, struct pivot_table *,
919                                struct tab_table *);
920 static void display_risk (struct pivot_table *, struct tab_table *);
921 static void display_directional (struct crosstabs_proc *, struct pivot_table *,
922                                  struct tab_table *);
923 static void crosstabs_dim (struct tab_rendering *, void *aux);
924 static void crosstabs_dim_free (void *aux);
925 static void table_value_missing (struct crosstabs_proc *proc,
926                                  struct tab_table *table, int c, int r,
927                                  unsigned char opt, const union value *v,
928                                  const struct variable *var);
929 static void delete_missing (struct pivot_table *);
930 static void build_matrix (struct pivot_table *);
931
932 /* Output pivot table beginning at PB and continuing until PE,
933    exclusive.  For efficiency, *MATP is a pointer to a matrix that can
934    hold *MAXROWS entries. */
935 static void
936 output_pivot_table (struct crosstabs_proc *proc, struct pivot_table *pt)
937 {
938   struct tab_table *table = NULL; /* Crosstabulation table. */
939   struct tab_table *chisq = NULL; /* Chi-square table. */
940   bool showed_fisher = false;
941   struct tab_table *sym = NULL;   /* Symmetric measures table. */
942   struct tab_table *risk = NULL;  /* Risk estimate table. */
943   struct tab_table *direct = NULL; /* Directional measures table. */
944   size_t row0, row1;
945
946   enum_var_values (pt, COL_VAR, &pt->cols, &pt->n_cols);
947
948   if (proc->cells)
949     table = create_crosstab_table (proc, pt);
950   if (proc->statistics & (1u << CRS_ST_CHISQ))
951     chisq = create_chisq_table (pt);
952   if (proc->statistics & ((1u << CRS_ST_PHI) | (1u << CRS_ST_CC)
953                           | (1u << CRS_ST_BTAU) | (1u << CRS_ST_CTAU)
954                           | (1u << CRS_ST_GAMMA) | (1u << CRS_ST_CORR)
955                           | (1u << CRS_ST_KAPPA)))
956     sym = create_sym_table (pt);
957   if (proc->statistics & (1u << CRS_ST_RISK))
958     risk = create_risk_table (pt);
959   if (proc->statistics & ((1u << CRS_ST_LAMBDA) | (1u << CRS_ST_UC)
960                           | (1u << CRS_ST_D) | (1u << CRS_ST_ETA)))
961     direct = create_direct_table (pt);
962
963   row0 = row1 = 0;
964   while (find_crosstab (pt, &row0, &row1))
965     {
966       struct pivot_table x;
967       int first_difference;
968
969       make_pivot_table_subset (pt, row0, row1, &x);
970
971       /* Find all the row variable values. */
972       enum_var_values (&x, ROW_VAR, &x.rows, &x.n_rows);
973
974       if (size_overflow_p (xtimes (xtimes (x.n_rows, x.n_cols),
975                                    sizeof (double))))
976         xalloc_die ();
977       x.row_tot = xmalloc (x.n_rows * sizeof *x.row_tot);
978       x.col_tot = xmalloc (x.n_cols * sizeof *x.col_tot);
979       x.mat = xmalloc (x.n_rows * x.n_cols * sizeof *x.mat);
980
981       /* Allocate table space for the matrix. */
982       if (table
983           && tab_row (table) + (x.n_rows + 1) * proc->n_cells > tab_nr (table))
984         tab_realloc (table, -1,
985                      MAX (tab_nr (table) + (x.n_rows + 1) * proc->n_cells,
986                           tab_nr (table) * pt->n_entries / x.n_entries));
987
988       build_matrix (&x);
989
990       /* Find the first variable that differs from the last subtable. */
991       first_difference = find_first_difference (pt, row0);
992       if (table)
993         {
994           display_dimensions (proc, &x, table, first_difference);
995           display_crosstabulation (proc, &x, table);
996         }
997
998       if (proc->exclude == MV_NEVER)
999         delete_missing (&x);
1000
1001       if (chisq)
1002         {
1003           display_dimensions (proc, &x, chisq, first_difference);
1004           display_chisq (&x, chisq, &showed_fisher);
1005         }
1006       if (sym)
1007         {
1008           display_dimensions (proc, &x, sym, first_difference);
1009           display_symmetric (proc, &x, sym);
1010         }
1011       if (risk)
1012         {
1013           display_dimensions (proc, &x, risk, first_difference);
1014           display_risk (&x, risk);
1015         }
1016       if (direct)
1017         {
1018           display_dimensions (proc, &x, direct, first_difference);
1019           display_directional (proc, &x, direct);
1020         }
1021
1022       /* Free the parts of x that are not owned by pt.  In
1023          particular we must not free x.cols, which is the same as
1024          pt->cols, which is freed at the end of this function. */
1025       free (x.rows);
1026
1027       free (x.mat);
1028       free (x.row_tot);
1029       free (x.col_tot);
1030     }
1031
1032   submit (proc, NULL, table);
1033
1034   if (chisq)
1035     {
1036       if (!showed_fisher)
1037         tab_resize (chisq, 4 + (pt->n_vars - 2), -1);
1038       submit (proc, pt, chisq);
1039     }
1040
1041   submit (proc, pt, sym);
1042   submit (proc, pt, risk);
1043   submit (proc, pt, direct);
1044
1045   free (pt->cols);
1046 }
1047
1048 static void
1049 build_matrix (struct pivot_table *x)
1050 {
1051   const int col_var_width = var_get_width (x->vars[COL_VAR]);
1052   const int row_var_width = var_get_width (x->vars[ROW_VAR]);
1053   int col, row;
1054   double *mp;
1055   struct table_entry **p;
1056
1057   mp = x->mat;
1058   col = row = 0;
1059   for (p = x->entries; p < &x->entries[x->n_entries]; p++)
1060     {
1061       const struct table_entry *te = *p;
1062
1063       while (!value_equal (&x->rows[row], &te->values[ROW_VAR], row_var_width))
1064         {
1065           for (; col < x->n_cols; col++)
1066             *mp++ = 0.0;
1067           col = 0;
1068           row++;
1069         }
1070
1071       while (!value_equal (&x->cols[col], &te->values[COL_VAR], col_var_width))
1072         {
1073           *mp++ = 0.0;
1074           col++;
1075         }
1076
1077       *mp++ = te->freq;
1078       if (++col >= x->n_cols)
1079         {
1080           col = 0;
1081           row++;
1082         }
1083     }
1084   while (mp < &x->mat[x->n_cols * x->n_rows])
1085     *mp++ = 0.0;
1086   assert (mp == &x->mat[x->n_cols * x->n_rows]);
1087
1088   /* Column totals, row totals, ns_rows. */
1089   mp = x->mat;
1090   for (col = 0; col < x->n_cols; col++)
1091     x->col_tot[col] = 0.0;
1092   for (row = 0; row < x->n_rows; row++)
1093     x->row_tot[row] = 0.0;
1094   x->ns_rows = 0;
1095   for (row = 0; row < x->n_rows; row++)
1096     {
1097       bool row_is_empty = true;
1098       for (col = 0; col < x->n_cols; col++)
1099         {
1100           if (*mp != 0.0)
1101             {
1102               row_is_empty = false;
1103               x->col_tot[col] += *mp;
1104               x->row_tot[row] += *mp;
1105             }
1106           mp++;
1107         }
1108       if (!row_is_empty)
1109         x->ns_rows++;
1110     }
1111   assert (mp == &x->mat[x->n_cols * x->n_rows]);
1112
1113   /* ns_cols. */
1114   x->ns_cols = 0;
1115   for (col = 0; col < x->n_cols; col++)
1116     for (row = 0; row < x->n_rows; row++)
1117       if (x->mat[col + row * x->n_cols] != 0.0)
1118         {
1119           x->ns_cols++;
1120           break;
1121         }
1122
1123   /* Grand total. */
1124   x->total = 0.0;
1125   for (col = 0; col < x->n_cols; col++)
1126     x->total += x->col_tot[col];
1127 }
1128
1129 static struct tab_table *
1130 create_crosstab_table (struct crosstabs_proc *proc, struct pivot_table *pt)
1131 {
1132   struct tuple
1133     {
1134       int value;
1135       const char *name;
1136     };
1137   static const struct tuple names[] =
1138     {
1139       {CRS_CL_COUNT, N_("count")},
1140       {CRS_CL_ROW, N_("row %")},
1141       {CRS_CL_COLUMN, N_("column %")},
1142       {CRS_CL_TOTAL, N_("total %")},
1143       {CRS_CL_EXPECTED, N_("expected")},
1144       {CRS_CL_RESIDUAL, N_("residual")},
1145       {CRS_CL_SRESIDUAL, N_("std. resid.")},
1146       {CRS_CL_ASRESIDUAL, N_("adj. resid.")},
1147     };
1148   const int n_names = sizeof names / sizeof *names;
1149   const struct tuple *t;
1150
1151   struct tab_table *table;
1152   struct string title;
1153   int i;
1154
1155   table = tab_create (pt->n_consts + 1 + pt->n_cols + 1,
1156                       (pt->n_entries / pt->n_cols) * 3 / 2 * proc->n_cells + 10);
1157   tab_headers (table, pt->n_consts + 1, 0, 2, 0);
1158
1159   /* First header line. */
1160   tab_joint_text (table, pt->n_consts + 1, 0,
1161                   (pt->n_consts + 1) + (pt->n_cols - 1), 0,
1162                   TAB_CENTER | TAT_TITLE, var_get_name (pt->vars[COL_VAR]));
1163
1164   tab_hline (table, TAL_1, pt->n_consts + 1,
1165              pt->n_consts + 2 + pt->n_cols - 2, 1);
1166
1167   /* Second header line. */
1168   for (i = 2; i < pt->n_consts + 2; i++)
1169     tab_joint_text (table, pt->n_consts + 2 - i - 1, 0,
1170                     pt->n_consts + 2 - i - 1, 1,
1171                     TAB_RIGHT | TAT_TITLE, var_to_string (pt->vars[i]));
1172   tab_text (table, pt->n_consts + 2 - 2, 1, TAB_RIGHT | TAT_TITLE,
1173             var_get_name (pt->vars[ROW_VAR]));
1174   for (i = 0; i < pt->n_cols; i++)
1175     table_value_missing (proc, table, pt->n_consts + 2 + i - 1, 1, TAB_RIGHT,
1176                          &pt->cols[i], pt->vars[COL_VAR]);
1177   tab_text (table, pt->n_consts + 2 + pt->n_cols - 1, 1, TAB_CENTER, _("Total"));
1178
1179   tab_hline (table, TAL_1, 0, pt->n_consts + 2 + pt->n_cols - 1, 2);
1180   tab_vline (table, TAL_1, pt->n_consts + 2 + pt->n_cols - 1, 0, 1);
1181
1182   /* Title. */
1183   ds_init_empty (&title);
1184   for (i = 0; i < pt->n_consts + 2; i++)
1185     {
1186       if (i)
1187         ds_put_cstr (&title, " * ");
1188       ds_put_cstr (&title, var_get_name (pt->vars[i]));
1189     }
1190   for (i = 0; i < pt->n_consts; i++)
1191     {
1192       const struct variable *var = pt->const_vars[i];
1193       size_t ofs;
1194       char *s = NULL;
1195
1196       ds_put_format (&title, ", %s=", var_get_name (var));
1197
1198       /* Insert the formatted value of the variable, then trim
1199          leading spaces in what was just inserted. */
1200       ofs = ds_length (&title);
1201       s = data_out (&pt->const_values[i], dict_get_encoding (proc->dict), var_get_print_format (var));
1202       ds_put_cstr (&title, s);
1203       free (s);
1204       ds_remove (&title, ofs, ss_cspan (ds_substr (&title, ofs, SIZE_MAX),
1205                                         ss_cstr (" ")));
1206     }
1207
1208   ds_put_cstr (&title, " [");
1209   i = 0;
1210   for (t = names; t < &names[n_names]; t++)
1211     if (proc->cells & (1u << t->value))
1212       {
1213         if (i++)
1214           ds_put_cstr (&title, ", ");
1215         ds_put_cstr (&title, gettext (t->name));
1216       }
1217   ds_put_cstr (&title, "].");
1218
1219   tab_title (table, "%s", ds_cstr (&title));
1220   ds_destroy (&title);
1221
1222   tab_offset (table, 0, 2);
1223   return table;
1224 }
1225
1226 static struct tab_table *
1227 create_chisq_table (struct pivot_table *pt)
1228 {
1229   struct tab_table *chisq;
1230
1231   chisq = tab_create (6 + (pt->n_vars - 2),
1232                       pt->n_entries / pt->n_cols * 3 / 2 * N_CHISQ + 10);
1233   tab_headers (chisq, 1 + (pt->n_vars - 2), 0, 1, 0);
1234
1235   tab_title (chisq, _("Chi-square tests."));
1236
1237   tab_offset (chisq, pt->n_vars - 2, 0);
1238   tab_text (chisq, 0, 0, TAB_LEFT | TAT_TITLE, _("Statistic"));
1239   tab_text (chisq, 1, 0, TAB_RIGHT | TAT_TITLE, _("Value"));
1240   tab_text (chisq, 2, 0, TAB_RIGHT | TAT_TITLE, _("df"));
1241   tab_text (chisq, 3, 0, TAB_RIGHT | TAT_TITLE,
1242             _("Asymp. Sig. (2-sided)"));
1243   tab_text (chisq, 4, 0, TAB_RIGHT | TAT_TITLE,
1244             _("Exact Sig. (2-sided)"));
1245   tab_text (chisq, 5, 0, TAB_RIGHT | TAT_TITLE,
1246             _("Exact Sig. (1-sided)"));
1247   tab_offset (chisq, 0, 1);
1248
1249   return chisq;
1250 }
1251
1252 /* Symmetric measures. */
1253 static struct tab_table *
1254 create_sym_table (struct pivot_table *pt)
1255 {
1256   struct tab_table *sym;
1257
1258   sym = tab_create (6 + (pt->n_vars - 2),
1259                     pt->n_entries / pt->n_cols * 7 + 10);
1260   tab_headers (sym, 2 + (pt->n_vars - 2), 0, 1, 0);
1261   tab_title (sym, _("Symmetric measures."));
1262
1263   tab_offset (sym, pt->n_vars - 2, 0);
1264   tab_text (sym, 0, 0, TAB_LEFT | TAT_TITLE, _("Category"));
1265   tab_text (sym, 1, 0, TAB_LEFT | TAT_TITLE, _("Statistic"));
1266   tab_text (sym, 2, 0, TAB_RIGHT | TAT_TITLE, _("Value"));
1267   tab_text (sym, 3, 0, TAB_RIGHT | TAT_TITLE, _("Asymp. Std. Error"));
1268   tab_text (sym, 4, 0, TAB_RIGHT | TAT_TITLE, _("Approx. T"));
1269   tab_text (sym, 5, 0, TAB_RIGHT | TAT_TITLE, _("Approx. Sig."));
1270   tab_offset (sym, 0, 1);
1271
1272   return sym;
1273 }
1274
1275 /* Risk estimate. */
1276 static struct tab_table *
1277 create_risk_table (struct pivot_table *pt)
1278 {
1279   struct tab_table *risk;
1280
1281   risk = tab_create (4 + (pt->n_vars - 2), pt->n_entries / pt->n_cols * 4 + 10);
1282   tab_headers (risk, 1 + pt->n_vars - 2, 0, 2, 0);
1283   tab_title (risk, _("Risk estimate."));
1284
1285   tab_offset (risk, pt->n_vars - 2, 0);
1286   tab_joint_text_format (risk, 2, 0, 3, 0, TAB_CENTER | TAT_TITLE,
1287                          _("95%% Confidence Interval"));
1288   tab_text (risk, 0, 1, TAB_LEFT | TAT_TITLE, _("Statistic"));
1289   tab_text (risk, 1, 1, TAB_RIGHT | TAT_TITLE, _("Value"));
1290   tab_text (risk, 2, 1, TAB_RIGHT | TAT_TITLE, _("Lower"));
1291   tab_text (risk, 3, 1, TAB_RIGHT | TAT_TITLE, _("Upper"));
1292   tab_hline (risk, TAL_1, 2, 3, 1);
1293   tab_vline (risk, TAL_1, 2, 0, 1);
1294   tab_offset (risk, 0, 2);
1295
1296   return risk;
1297 }
1298
1299 /* Directional measures. */
1300 static struct tab_table *
1301 create_direct_table (struct pivot_table *pt)
1302 {
1303   struct tab_table *direct;
1304
1305   direct = tab_create (7 + (pt->n_vars - 2),
1306                        pt->n_entries / pt->n_cols * 7 + 10);
1307   tab_headers (direct, 3 + (pt->n_vars - 2), 0, 1, 0);
1308   tab_title (direct, _("Directional measures."));
1309
1310   tab_offset (direct, pt->n_vars - 2, 0);
1311   tab_text (direct, 0, 0, TAB_LEFT | TAT_TITLE, _("Category"));
1312   tab_text (direct, 1, 0, TAB_LEFT | TAT_TITLE, _("Statistic"));
1313   tab_text (direct, 2, 0, TAB_LEFT | TAT_TITLE, _("Type"));
1314   tab_text (direct, 3, 0, TAB_RIGHT | TAT_TITLE, _("Value"));
1315   tab_text (direct, 4, 0, TAB_RIGHT | TAT_TITLE, _("Asymp. Std. Error"));
1316   tab_text (direct, 5, 0, TAB_RIGHT | TAT_TITLE, _("Approx. T"));
1317   tab_text (direct, 6, 0, TAB_RIGHT | TAT_TITLE, _("Approx. Sig."));
1318   tab_offset (direct, 0, 1);
1319
1320   return direct;
1321 }
1322
1323
1324 /* Delete missing rows and columns for statistical analysis when
1325    /MISSING=REPORT. */
1326 static void
1327 delete_missing (struct pivot_table *pt)
1328 {
1329   int r, c;
1330
1331   for (r = 0; r < pt->n_rows; r++)
1332     if (var_is_num_missing (pt->vars[ROW_VAR], pt->rows[r].f, MV_USER))
1333       {
1334         for (c = 0; c < pt->n_cols; c++)
1335           pt->mat[c + r * pt->n_cols] = 0.;
1336         pt->ns_rows--;
1337       }
1338
1339
1340   for (c = 0; c < pt->n_cols; c++)
1341     if (var_is_num_missing (pt->vars[COL_VAR], pt->cols[c].f, MV_USER))
1342       {
1343         for (r = 0; r < pt->n_rows; r++)
1344           pt->mat[c + r * pt->n_cols] = 0.;
1345         pt->ns_cols--;
1346       }
1347 }
1348
1349 /* Prepare table T for submission, and submit it. */
1350 static void
1351 submit (struct crosstabs_proc *proc, struct pivot_table *pt,
1352         struct tab_table *t)
1353 {
1354   struct crosstabs_dim_aux *aux;
1355   int i;
1356
1357   if (t == NULL)
1358     return;
1359
1360   tab_resize (t, -1, 0);
1361   if (tab_nr (t) == tab_t (t))
1362     {
1363       tab_destroy (t);
1364       return;
1365     }
1366   tab_offset (t, 0, 0);
1367   if (pt != NULL)
1368     for (i = 2; i < pt->n_vars; i++)
1369       tab_text (t, pt->n_vars - i - 1, 0, TAB_RIGHT | TAT_TITLE,
1370                 var_to_string (pt->vars[i]));
1371   tab_box (t, TAL_2, TAL_2, -1, -1, 0, 0, tab_nc (t) - 1, tab_nr (t) - 1);
1372   tab_box (t, -1, -1, -1, TAL_1, tab_l (t), tab_t (t) - 1, tab_nc (t) - 1,
1373            tab_nr (t) - 1);
1374   tab_box (t, -1, -1, -1, TAL_GAP, 0, tab_t (t), tab_l (t) - 1,
1375            tab_nr (t) - 1);
1376   tab_vline (t, TAL_2, tab_l (t), 0, tab_nr (t) - 1);
1377
1378   aux = xmalloc (sizeof *aux);
1379   aux->exclude = proc->exclude;
1380   tab_dim (t, crosstabs_dim, crosstabs_dim_free, aux);
1381
1382   tab_submit (t);
1383 }
1384
1385 /* Sets the widths of all the columns and heights of all the rows in
1386    table T for driver D. */
1387 static void
1388 crosstabs_dim (struct tab_rendering *r, void *aux_)
1389 {
1390   const struct tab_table *t = r->table;
1391   struct outp_driver *d = r->driver;
1392   struct crosstabs_dim_aux *aux = aux_;
1393   int i;
1394
1395   /* Width of a numerical column. */
1396   int c = outp_string_width (d, "0.000000", OUTP_PROPORTIONAL);
1397   if (aux->exclude == MV_NEVER)
1398     c += outp_string_width (d, "M", OUTP_PROPORTIONAL);
1399
1400   /* Set width for header columns. */
1401   if (tab_l (t) != 0)
1402     {
1403       size_t i;
1404       int w;
1405
1406       w = d->width - c * (tab_nc (t) - tab_l (t));
1407       for (i = 0; i <= tab_nc (t); i++)
1408         w -= r->wrv[i];
1409       w /= tab_l (t);
1410
1411       if (w < d->prop_em_width * 8)
1412         w = d->prop_em_width * 8;
1413
1414       if (w > d->prop_em_width * 15)
1415         w = d->prop_em_width * 15;
1416
1417       for (i = 0; i < tab_l (t); i++)
1418         r->w[i] = w;
1419     }
1420
1421   for (i = tab_l (t); i < tab_nc (t); i++)
1422     r->w[i] = c;
1423
1424   for (i = 0; i < tab_nr (t); i++)
1425     r->h[i] = tab_natural_height (r, i);
1426 }
1427
1428 static void
1429 crosstabs_dim_free (void *aux_)
1430 {
1431   struct crosstabs_dim_aux *aux = aux_;
1432   free (aux);
1433 }
1434
1435 static bool
1436 find_crosstab (struct pivot_table *pt, size_t *row0p, size_t *row1p)
1437 {
1438   size_t row0 = *row1p;
1439   size_t row1;
1440
1441   if (row0 >= pt->n_entries)
1442     return false;
1443
1444   for (row1 = row0 + 1; row1 < pt->n_entries; row1++)
1445     {
1446       struct table_entry *a = pt->entries[row0];
1447       struct table_entry *b = pt->entries[row1];
1448       if (compare_table_entry_vars_3way (a, b, pt, 2, pt->n_vars) != 0)
1449         break;
1450     }
1451   *row0p = row0;
1452   *row1p = row1;
1453   return true;
1454 }
1455
1456 /* Compares `union value's A_ and B_ and returns a strcmp()-like
1457    result.  WIDTH_ points to an int which is either 0 for a
1458    numeric value or a string width for a string value. */
1459 static int
1460 compare_value_3way (const void *a_, const void *b_, const void *width_)
1461 {
1462   const union value *a = a_;
1463   const union value *b = b_;
1464   const int *width = width_;
1465
1466   return value_compare_3way (a, b, *width);
1467 }
1468
1469 /* Given an array of ENTRY_CNT table_entry structures starting at
1470    ENTRIES, creates a sorted list of the values that the variable
1471    with index VAR_IDX takes on.  The values are returned as a
1472    malloc()'d array stored in *VALUES, with the number of values
1473    stored in *VALUE_CNT.
1474    */
1475 static void
1476 enum_var_values (const struct pivot_table *pt, int var_idx,
1477                  union value **valuesp, int *n_values)
1478 {
1479   const struct variable *var = pt->vars[var_idx];
1480   struct var_range *range = get_var_range (var);
1481   union value *values;
1482   size_t i;
1483
1484   if (range)
1485     {
1486       values = *valuesp = xnmalloc (range->count, sizeof *values);
1487       *n_values = range->count;
1488       for (i = 0; i < range->count; i++)
1489         values[i].f = range->min + i;
1490     }
1491   else
1492     {
1493       int width = var_get_width (var);
1494       struct hmapx_node *node;
1495       const union value *iter;
1496       struct hmapx set;
1497
1498       hmapx_init (&set);
1499       for (i = 0; i < pt->n_entries; i++)
1500         {
1501           const struct table_entry *te = pt->entries[i];
1502           const union value *value = &te->values[var_idx];
1503           size_t hash = value_hash (value, width, 0);
1504
1505           HMAPX_FOR_EACH_WITH_HASH (iter, node, hash, &set)
1506             if (value_equal (iter, value, width))
1507               goto next_entry;
1508
1509           hmapx_insert (&set, (union value *) value, hash);
1510
1511         next_entry: ;
1512         }
1513
1514       *n_values = hmapx_count (&set);
1515       values = *valuesp = xnmalloc (*n_values, sizeof *values);
1516       i = 0;
1517       HMAPX_FOR_EACH (iter, node, &set)
1518         values[i++] = *iter;
1519       hmapx_destroy (&set);
1520
1521       sort (values, *n_values, sizeof *values, compare_value_3way, &width);
1522     }
1523 }
1524
1525 /* Sets cell (C,R) in TABLE, with options OPT, to have a value taken
1526    from V, displayed with print format spec from variable VAR.  When
1527    in REPORT missing-value mode, missing values have an M appended. */
1528 static void
1529 table_value_missing (struct crosstabs_proc *proc,
1530                      struct tab_table *table, int c, int r, unsigned char opt,
1531                      const union value *v, const struct variable *var)
1532 {
1533   const char *label = var_lookup_value_label (var, v);
1534   if (label != NULL)
1535     tab_text (table, c, r, TAB_LEFT, label);
1536   else
1537     {
1538       const struct fmt_spec *print = var_get_print_format (var);
1539       if (proc->exclude == MV_NEVER && var_is_value_missing (var, v, MV_USER))
1540         {
1541           char *s = data_out (v, dict_get_encoding (proc->dict), print);
1542           tab_text_format (table, c, r, opt, "%sM", s + strspn (s, " "));
1543           free (s);
1544         }
1545       else
1546         tab_value (table, c, r, opt, v, proc->dict, print);
1547     }
1548 }
1549
1550 /* Draws a line across TABLE at the current row to indicate the most
1551    major dimension variable with index FIRST_DIFFERENCE out of N_VARS
1552    that changed, and puts the values that changed into the table.  TB
1553    and PT must be the corresponding table_entry and crosstab,
1554    respectively. */
1555 static void
1556 display_dimensions (struct crosstabs_proc *proc, struct pivot_table *pt,
1557                     struct tab_table *table, int first_difference)
1558 {
1559   tab_hline (table, TAL_1, pt->n_vars - first_difference - 1, tab_nc (table) - 1, 0);
1560
1561   for (; first_difference >= 2; first_difference--)
1562     table_value_missing (proc, table, pt->n_vars - first_difference - 1, 0,
1563                          TAB_RIGHT, &pt->entries[0]->values[first_difference],
1564                          pt->vars[first_difference]);
1565 }
1566
1567 /* Put VALUE into cell (C,R) of TABLE, suffixed with character
1568    SUFFIX if nonzero.  If MARK_MISSING is true the entry is
1569    additionally suffixed with a letter `M'. */
1570 static void
1571 format_cell_entry (struct tab_table *table, int c, int r, double value,
1572                    char suffix, bool mark_missing, const struct dictionary *dict)
1573 {
1574   const struct fmt_spec f = {FMT_F, 10, 1};
1575   union value v;
1576   char suffixes[3];
1577   int suffix_len;
1578   char *s;
1579
1580   v.f = value;
1581   s = data_out (&v, dict_get_encoding (dict), &f);
1582
1583   suffix_len = 0;
1584   if (suffix != 0)
1585     suffixes[suffix_len++] = suffix;
1586   if (mark_missing)
1587     suffixes[suffix_len++] = 'M';
1588   suffixes[suffix_len] = '\0';
1589
1590   tab_text_format (table, c, r, TAB_RIGHT, "%s%s",
1591                    s + strspn (s, " "), suffixes);
1592 }
1593
1594 /* Displays the crosstabulation table. */
1595 static void
1596 display_crosstabulation (struct crosstabs_proc *proc, struct pivot_table *pt,
1597                          struct tab_table *table)
1598 {
1599   int last_row;
1600   int r, c, i;
1601   double *mp;
1602
1603   for (r = 0; r < pt->n_rows; r++)
1604     table_value_missing (proc, table, pt->n_vars - 2, r * proc->n_cells,
1605                          TAB_RIGHT, &pt->rows[r], pt->vars[ROW_VAR]);
1606
1607   tab_text (table, pt->n_vars - 2, pt->n_rows * proc->n_cells,
1608             TAB_LEFT, _("Total"));
1609
1610   /* Put in the actual cells. */
1611   mp = pt->mat;
1612   tab_offset (table, pt->n_vars - 1, -1);
1613   for (r = 0; r < pt->n_rows; r++)
1614     {
1615       if (proc->n_cells > 1)
1616         tab_hline (table, TAL_1, -1, pt->n_cols, 0);
1617       for (c = 0; c < pt->n_cols; c++)
1618         {
1619           bool mark_missing = false;
1620           double expected_value = pt->row_tot[r] * pt->col_tot[c] / pt->total;
1621           if (proc->exclude == MV_NEVER
1622               && (var_is_num_missing (pt->vars[COL_VAR], pt->cols[c].f, MV_USER)
1623                   || var_is_num_missing (pt->vars[ROW_VAR], pt->rows[r].f,
1624                                          MV_USER)))
1625             mark_missing = true;
1626           for (i = 0; i < proc->n_cells; i++)
1627             {
1628               double v;
1629               int suffix = 0;
1630
1631               switch (proc->a_cells[i])
1632                 {
1633                 case CRS_CL_COUNT:
1634                   v = *mp;
1635                   break;
1636                 case CRS_CL_ROW:
1637                   v = *mp / pt->row_tot[r] * 100.;
1638                   suffix = '%';
1639                   break;
1640                 case CRS_CL_COLUMN:
1641                   v = *mp / pt->col_tot[c] * 100.;
1642                   suffix = '%';
1643                   break;
1644                 case CRS_CL_TOTAL:
1645                   v = *mp / pt->total * 100.;
1646                   suffix = '%';
1647                   break;
1648                 case CRS_CL_EXPECTED:
1649                   v = expected_value;
1650                   break;
1651                 case CRS_CL_RESIDUAL:
1652                   v = *mp - expected_value;
1653                   break;
1654                 case CRS_CL_SRESIDUAL:
1655                   v = (*mp - expected_value) / sqrt (expected_value);
1656                   break;
1657                 case CRS_CL_ASRESIDUAL:
1658                   v = ((*mp - expected_value)
1659                        / sqrt (expected_value
1660                                * (1. - pt->row_tot[r] / pt->total)
1661                                * (1. - pt->col_tot[c] / pt->total)));
1662                   break;
1663                 default:
1664                   NOT_REACHED ();
1665                 }
1666               format_cell_entry (table, c, i, v, suffix, mark_missing, proc->dict);
1667             }
1668
1669           mp++;
1670         }
1671
1672       tab_offset (table, -1, tab_row (table) + proc->n_cells);
1673     }
1674
1675   /* Row totals. */
1676   tab_offset (table, -1, tab_row (table) - proc->n_cells * pt->n_rows);
1677   for (r = 0; r < pt->n_rows; r++)
1678     {
1679       bool mark_missing = false;
1680
1681       if (proc->exclude == MV_NEVER
1682           && var_is_num_missing (pt->vars[ROW_VAR], pt->rows[r].f, MV_USER))
1683         mark_missing = true;
1684
1685       for (i = 0; i < proc->n_cells; i++)
1686         {
1687           char suffix = 0;
1688           double v;
1689
1690           switch (proc->a_cells[i])
1691             {
1692             case CRS_CL_COUNT:
1693               v = pt->row_tot[r];
1694               break;
1695             case CRS_CL_ROW:
1696               v = 100.0;
1697               suffix = '%';
1698               break;
1699             case CRS_CL_COLUMN:
1700               v = pt->row_tot[r] / pt->total * 100.;
1701               suffix = '%';
1702               break;
1703             case CRS_CL_TOTAL:
1704               v = pt->row_tot[r] / pt->total * 100.;
1705               suffix = '%';
1706               break;
1707             case CRS_CL_EXPECTED:
1708             case CRS_CL_RESIDUAL:
1709             case CRS_CL_SRESIDUAL:
1710             case CRS_CL_ASRESIDUAL:
1711               v = 0.;
1712               break;
1713             default:
1714               NOT_REACHED ();
1715             }
1716
1717           format_cell_entry (table, pt->n_cols, 0, v, suffix, mark_missing, proc->dict);
1718           tab_next_row (table);
1719         }
1720     }
1721
1722   /* Column totals, grand total. */
1723   last_row = 0;
1724   if (proc->n_cells > 1)
1725     tab_hline (table, TAL_1, -1, pt->n_cols, 0);
1726   for (c = 0; c <= pt->n_cols; c++)
1727     {
1728       double ct = c < pt->n_cols ? pt->col_tot[c] : pt->total;
1729       bool mark_missing = false;
1730       int i;
1731
1732       if (proc->exclude == MV_NEVER && c < pt->n_cols
1733           && var_is_num_missing (pt->vars[COL_VAR], pt->cols[c].f, MV_USER))
1734         mark_missing = true;
1735
1736       for (i = 0; i < proc->n_cells; i++)
1737         {
1738           char suffix = 0;
1739           double v;
1740
1741           switch (proc->a_cells[i])
1742             {
1743             case CRS_CL_COUNT:
1744               v = ct;
1745               break;
1746             case CRS_CL_ROW:
1747               v = ct / pt->total * 100.;
1748               suffix = '%';
1749               break;
1750             case CRS_CL_COLUMN:
1751               v = 100.;
1752               suffix = '%';
1753               break;
1754             case CRS_CL_TOTAL:
1755               v = ct / pt->total * 100.;
1756               suffix = '%';
1757               break;
1758             case CRS_CL_EXPECTED:
1759             case CRS_CL_RESIDUAL:
1760             case CRS_CL_SRESIDUAL:
1761             case CRS_CL_ASRESIDUAL:
1762               continue;
1763             default:
1764               NOT_REACHED ();
1765             }
1766
1767           format_cell_entry (table, c, i, v, suffix, mark_missing, proc->dict);
1768         }
1769       last_row = i;
1770     }
1771
1772   tab_offset (table, -1, tab_row (table) + last_row);
1773   tab_offset (table, 0, -1);
1774 }
1775
1776 static void calc_r (struct pivot_table *,
1777                     double *PT, double *Y, double *, double *, double *);
1778 static void calc_chisq (struct pivot_table *,
1779                         double[N_CHISQ], int[N_CHISQ], double *, double *);
1780
1781 /* Display chi-square statistics. */
1782 static void
1783 display_chisq (struct pivot_table *pt, struct tab_table *chisq,
1784                bool *showed_fisher)
1785 {
1786   static const char *chisq_stats[N_CHISQ] =
1787     {
1788       N_("Pearson Chi-Square"),
1789       N_("Likelihood Ratio"),
1790       N_("Fisher's Exact Test"),
1791       N_("Continuity Correction"),
1792       N_("Linear-by-Linear Association"),
1793     };
1794   double chisq_v[N_CHISQ];
1795   double fisher1, fisher2;
1796   int df[N_CHISQ];
1797
1798   int i;
1799
1800   calc_chisq (pt, chisq_v, df, &fisher1, &fisher2);
1801
1802   tab_offset (chisq, pt->n_vars - 2, -1);
1803
1804   for (i = 0; i < N_CHISQ; i++)
1805     {
1806       if ((i != 2 && chisq_v[i] == SYSMIS)
1807           || (i == 2 && fisher1 == SYSMIS))
1808         continue;
1809
1810       tab_text (chisq, 0, 0, TAB_LEFT, gettext (chisq_stats[i]));
1811       if (i != 2)
1812         {
1813           tab_double (chisq, 1, 0, TAB_RIGHT, chisq_v[i], NULL);
1814           tab_double (chisq, 2, 0, TAB_RIGHT, df[i], &pt->weight_format);
1815           tab_double (chisq, 3, 0, TAB_RIGHT,
1816                      gsl_cdf_chisq_Q (chisq_v[i], df[i]), NULL);
1817         }
1818       else
1819         {
1820           *showed_fisher = true;
1821           tab_double (chisq, 4, 0, TAB_RIGHT, fisher2, NULL);
1822           tab_double (chisq, 5, 0, TAB_RIGHT, fisher1, NULL);
1823         }
1824       tab_next_row (chisq);
1825     }
1826
1827   tab_text (chisq, 0, 0, TAB_LEFT, _("N of Valid Cases"));
1828   tab_double (chisq, 1, 0, TAB_RIGHT, pt->total, &pt->weight_format);
1829   tab_next_row (chisq);
1830
1831   tab_offset (chisq, 0, -1);
1832 }
1833
1834 static int calc_symmetric (struct crosstabs_proc *, struct pivot_table *,
1835                            double[N_SYMMETRIC], double[N_SYMMETRIC],
1836                            double[N_SYMMETRIC],
1837                            double[3], double[3], double[3]);
1838
1839 /* Display symmetric measures. */
1840 static void
1841 display_symmetric (struct crosstabs_proc *proc, struct pivot_table *pt,
1842                    struct tab_table *sym)
1843 {
1844   static const char *categories[] =
1845     {
1846       N_("Nominal by Nominal"),
1847       N_("Ordinal by Ordinal"),
1848       N_("Interval by Interval"),
1849       N_("Measure of Agreement"),
1850     };
1851
1852   static const char *stats[N_SYMMETRIC] =
1853     {
1854       N_("Phi"),
1855       N_("Cramer's V"),
1856       N_("Contingency Coefficient"),
1857       N_("Kendall's tau-b"),
1858       N_("Kendall's tau-c"),
1859       N_("Gamma"),
1860       N_("Spearman Correlation"),
1861       N_("Pearson's R"),
1862       N_("Kappa"),
1863     };
1864
1865   static const int stats_categories[N_SYMMETRIC] =
1866     {
1867       0, 0, 0, 1, 1, 1, 1, 2, 3,
1868     };
1869
1870   int last_cat = -1;
1871   double sym_v[N_SYMMETRIC], sym_ase[N_SYMMETRIC], sym_t[N_SYMMETRIC];
1872   double somers_d_v[3], somers_d_ase[3], somers_d_t[3];
1873   int i;
1874
1875   if (!calc_symmetric (proc, pt, sym_v, sym_ase, sym_t,
1876                        somers_d_v, somers_d_ase, somers_d_t))
1877     return;
1878
1879   tab_offset (sym, pt->n_vars - 2, -1);
1880
1881   for (i = 0; i < N_SYMMETRIC; i++)
1882     {
1883       if (sym_v[i] == SYSMIS)
1884         continue;
1885
1886       if (stats_categories[i] != last_cat)
1887         {
1888           last_cat = stats_categories[i];
1889           tab_text (sym, 0, 0, TAB_LEFT, gettext (categories[last_cat]));
1890         }
1891
1892       tab_text (sym, 1, 0, TAB_LEFT, gettext (stats[i]));
1893       tab_double (sym, 2, 0, TAB_RIGHT, sym_v[i], NULL);
1894       if (sym_ase[i] != SYSMIS)
1895         tab_double (sym, 3, 0, TAB_RIGHT, sym_ase[i], NULL);
1896       if (sym_t[i] != SYSMIS)
1897         tab_double (sym, 4, 0, TAB_RIGHT, sym_t[i], NULL);
1898       /*tab_double (sym, 5, 0, TAB_RIGHT, normal_sig (sym_v[i]), NULL);*/
1899       tab_next_row (sym);
1900     }
1901
1902   tab_text (sym, 0, 0, TAB_LEFT, _("N of Valid Cases"));
1903   tab_double (sym, 2, 0, TAB_RIGHT, pt->total, &pt->weight_format);
1904   tab_next_row (sym);
1905
1906   tab_offset (sym, 0, -1);
1907 }
1908
1909 static int calc_risk (struct pivot_table *,
1910                       double[], double[], double[], union value *);
1911
1912 /* Display risk estimate. */
1913 static void
1914 display_risk (struct pivot_table *pt, struct tab_table *risk)
1915 {
1916   char buf[256];
1917   double risk_v[3], lower[3], upper[3];
1918   union value c[2];
1919   int i;
1920
1921   if (!calc_risk (pt, risk_v, upper, lower, c))
1922     return;
1923
1924   tab_offset (risk, pt->n_vars - 2, -1);
1925
1926   for (i = 0; i < 3; i++)
1927     {
1928       const struct variable *cv = pt->vars[COL_VAR];
1929       const struct variable *rv = pt->vars[ROW_VAR];
1930       int cvw = var_get_width (cv);
1931       int rvw = var_get_width (rv);
1932
1933       if (risk_v[i] == SYSMIS)
1934         continue;
1935
1936       switch (i)
1937         {
1938         case 0:
1939           if (var_is_numeric (cv))
1940             sprintf (buf, _("Odds Ratio for %s (%g / %g)"),
1941                      var_get_name (cv), c[0].f, c[1].f);
1942           else
1943             sprintf (buf, _("Odds Ratio for %s (%.*s / %.*s)"),
1944                      var_get_name (cv),
1945                      cvw, value_str (&c[0], cvw),
1946                      cvw, value_str (&c[1], cvw));
1947           break;
1948         case 1:
1949         case 2:
1950           if (var_is_numeric (rv))
1951             sprintf (buf, _("For cohort %s = %g"),
1952                      var_get_name (rv), pt->rows[i - 1].f);
1953           else
1954             sprintf (buf, _("For cohort %s = %.*s"),
1955                      var_get_name (rv),
1956                      rvw, value_str (&pt->rows[i - 1], rvw));
1957           break;
1958         }
1959
1960       tab_text (risk, 0, 0, TAB_LEFT, buf);
1961       tab_double (risk, 1, 0, TAB_RIGHT, risk_v[i], NULL);
1962       tab_double (risk, 2, 0, TAB_RIGHT, lower[i], NULL);
1963       tab_double (risk, 3, 0, TAB_RIGHT, upper[i], NULL);
1964       tab_next_row (risk);
1965     }
1966
1967   tab_text (risk, 0, 0, TAB_LEFT, _("N of Valid Cases"));
1968   tab_double (risk, 1, 0, TAB_RIGHT, pt->total, &pt->weight_format);
1969   tab_next_row (risk);
1970
1971   tab_offset (risk, 0, -1);
1972 }
1973
1974 static int calc_directional (struct crosstabs_proc *, struct pivot_table *,
1975                              double[N_DIRECTIONAL], double[N_DIRECTIONAL],
1976                              double[N_DIRECTIONAL]);
1977
1978 /* Display directional measures. */
1979 static void
1980 display_directional (struct crosstabs_proc *proc, struct pivot_table *pt,
1981                      struct tab_table *direct)
1982 {
1983   static const char *categories[] =
1984     {
1985       N_("Nominal by Nominal"),
1986       N_("Ordinal by Ordinal"),
1987       N_("Nominal by Interval"),
1988     };
1989
1990   static const char *stats[] =
1991     {
1992       N_("Lambda"),
1993       N_("Goodman and Kruskal tau"),
1994       N_("Uncertainty Coefficient"),
1995       N_("Somers' d"),
1996       N_("Eta"),
1997     };
1998
1999   static const char *types[] =
2000     {
2001       N_("Symmetric"),
2002       N_("%s Dependent"),
2003       N_("%s Dependent"),
2004     };
2005
2006   static const int stats_categories[N_DIRECTIONAL] =
2007     {
2008       0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2,
2009     };
2010
2011   static const int stats_stats[N_DIRECTIONAL] =
2012     {
2013       0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4,
2014     };
2015
2016   static const int stats_types[N_DIRECTIONAL] =
2017     {
2018       0, 1, 2, 1, 2, 0, 1, 2, 0, 1, 2, 1, 2,
2019     };
2020
2021   static const int *stats_lookup[] =
2022     {
2023       stats_categories,
2024       stats_stats,
2025       stats_types,
2026     };
2027
2028   static const char **stats_names[] =
2029     {
2030       categories,
2031       stats,
2032       types,
2033     };
2034
2035   int last[3] =
2036     {
2037       -1, -1, -1,
2038     };
2039
2040   double direct_v[N_DIRECTIONAL];
2041   double direct_ase[N_DIRECTIONAL];
2042   double direct_t[N_DIRECTIONAL];
2043
2044   int i;
2045
2046   if (!calc_directional (proc, pt, direct_v, direct_ase, direct_t))
2047     return;
2048
2049   tab_offset (direct, pt->n_vars - 2, -1);
2050
2051   for (i = 0; i < N_DIRECTIONAL; i++)
2052     {
2053       if (direct_v[i] == SYSMIS)
2054         continue;
2055
2056       {
2057         int j;
2058
2059         for (j = 0; j < 3; j++)
2060           if (last[j] != stats_lookup[j][i])
2061             {
2062               if (j < 2)
2063                 tab_hline (direct, TAL_1, j, 6, 0);
2064
2065               for (; j < 3; j++)
2066                 {
2067                   const char *string;
2068                   int k = last[j] = stats_lookup[j][i];
2069
2070                   if (k == 0)
2071                     string = NULL;
2072                   else if (k == 1)
2073                     string = var_get_name (pt->vars[0]);
2074                   else
2075                     string = var_get_name (pt->vars[1]);
2076
2077                   tab_text_format (direct, j, 0, TAB_LEFT,
2078                                    gettext (stats_names[j][k]), string);
2079                 }
2080             }
2081       }
2082
2083       tab_double (direct, 3, 0, TAB_RIGHT, direct_v[i], NULL);
2084       if (direct_ase[i] != SYSMIS)
2085         tab_double (direct, 4, 0, TAB_RIGHT, direct_ase[i], NULL);
2086       if (direct_t[i] != SYSMIS)
2087         tab_double (direct, 5, 0, TAB_RIGHT, direct_t[i], NULL);
2088       /*tab_double (direct, 6, 0, TAB_RIGHT, normal_sig (direct_v[i]), NULL);*/
2089       tab_next_row (direct);
2090     }
2091
2092   tab_offset (direct, 0, -1);
2093 }
2094 \f
2095 /* Statistical calculations. */
2096
2097 /* Returns the value of the gamma (factorial) function for an integer
2098    argument PT. */
2099 static double
2100 gamma_int (double pt)
2101 {
2102   double r = 1;
2103   int i;
2104
2105   for (i = 2; i < pt; i++)
2106     r *= i;
2107   return r;
2108 }
2109
2110 /* Calculate P_r as specified in _SPSS Statistical Algorithms_,
2111    Appendix 5. */
2112 static inline double
2113 Pr (int a, int b, int c, int d)
2114 {
2115   return (gamma_int (a + b + 1.) / gamma_int (a + 1.)
2116           * gamma_int (c + d + 1.) / gamma_int (b + 1.)
2117           * gamma_int (a + c + 1.) / gamma_int (c + 1.)
2118           * gamma_int (b + d + 1.) / gamma_int (d + 1.)
2119           / gamma_int (a + b + c + d + 1.));
2120 }
2121
2122 /* Swap the contents of A and B. */
2123 static inline void
2124 swap (int *a, int *b)
2125 {
2126   int t = *a;
2127   *a = *b;
2128   *b = t;
2129 }
2130
2131 /* Calculate significance for Fisher's exact test as specified in
2132    _SPSS Statistical Algorithms_, Appendix 5. */
2133 static void
2134 calc_fisher (int a, int b, int c, int d, double *fisher1, double *fisher2)
2135 {
2136   int pt;
2137
2138   if (MIN (c, d) < MIN (a, b))
2139     swap (&a, &c), swap (&b, &d);
2140   if (MIN (b, d) < MIN (a, c))
2141     swap (&a, &b), swap (&c, &d);
2142   if (b * c < a * d)
2143     {
2144       if (b < c)
2145         swap (&a, &b), swap (&c, &d);
2146       else
2147         swap (&a, &c), swap (&b, &d);
2148     }
2149
2150   *fisher1 = 0.;
2151   for (pt = 0; pt <= a; pt++)
2152     *fisher1 += Pr (a - pt, b + pt, c + pt, d - pt);
2153
2154   *fisher2 = *fisher1;
2155   for (pt = 1; pt <= b; pt++)
2156     *fisher2 += Pr (a + pt, b - pt, c - pt, d + pt);
2157 }
2158
2159 /* Calculates chi-squares into CHISQ.  MAT is a matrix with N_COLS
2160    columns with values COLS and N_ROWS rows with values ROWS.  Values
2161    in the matrix sum to pt->total. */
2162 static void
2163 calc_chisq (struct pivot_table *pt,
2164             double chisq[N_CHISQ], int df[N_CHISQ],
2165             double *fisher1, double *fisher2)
2166 {
2167   int r, c;
2168
2169   chisq[0] = chisq[1] = 0.;
2170   chisq[2] = chisq[3] = chisq[4] = SYSMIS;
2171   *fisher1 = *fisher2 = SYSMIS;
2172
2173   df[0] = df[1] = (pt->ns_cols - 1) * (pt->ns_rows - 1);
2174
2175   if (pt->ns_rows <= 1 || pt->ns_cols <= 1)
2176     {
2177       chisq[0] = chisq[1] = SYSMIS;
2178       return;
2179     }
2180
2181   for (r = 0; r < pt->n_rows; r++)
2182     for (c = 0; c < pt->n_cols; c++)
2183       {
2184         const double expected = pt->row_tot[r] * pt->col_tot[c] / pt->total;
2185         const double freq = pt->mat[pt->n_cols * r + c];
2186         const double residual = freq - expected;
2187
2188         chisq[0] += residual * residual / expected;
2189         if (freq)
2190           chisq[1] += freq * log (expected / freq);
2191       }
2192
2193   if (chisq[0] == 0.)
2194     chisq[0] = SYSMIS;
2195
2196   if (chisq[1] != 0.)
2197     chisq[1] *= -2.;
2198   else
2199     chisq[1] = SYSMIS;
2200
2201   /* Calculate Yates and Fisher exact test. */
2202   if (pt->ns_cols == 2 && pt->ns_rows == 2)
2203     {
2204       double f11, f12, f21, f22;
2205
2206       {
2207         int nz_cols[2];
2208         int i, j;
2209
2210         for (i = j = 0; i < pt->n_cols; i++)
2211           if (pt->col_tot[i] != 0.)
2212             {
2213               nz_cols[j++] = i;
2214               if (j == 2)
2215                 break;
2216             }
2217
2218         assert (j == 2);
2219
2220         f11 = pt->mat[nz_cols[0]];
2221         f12 = pt->mat[nz_cols[1]];
2222         f21 = pt->mat[nz_cols[0] + pt->n_cols];
2223         f22 = pt->mat[nz_cols[1] + pt->n_cols];
2224       }
2225
2226       /* Yates. */
2227       {
2228         const double pt_ = fabs (f11 * f22 - f12 * f21) - 0.5 * pt->total;
2229
2230         if (pt_ > 0.)
2231           chisq[3] = (pt->total * pow2 (pt_)
2232                       / (f11 + f12) / (f21 + f22)
2233                       / (f11 + f21) / (f12 + f22));
2234         else
2235           chisq[3] = 0.;
2236
2237         df[3] = 1.;
2238       }
2239
2240       /* Fisher. */
2241       if (f11 < 5. || f12 < 5. || f21 < 5. || f22 < 5.)
2242         calc_fisher (f11 + .5, f12 + .5, f21 + .5, f22 + .5, fisher1, fisher2);
2243     }
2244
2245   /* Calculate Mantel-Haenszel. */
2246   if (var_is_numeric (pt->vars[ROW_VAR]) && var_is_numeric (pt->vars[COL_VAR]))
2247     {
2248       double r, ase_0, ase_1;
2249       calc_r (pt, (double *) pt->rows, (double *) pt->cols, &r, &ase_0, &ase_1);
2250
2251       chisq[4] = (pt->total - 1.) * r * r;
2252       df[4] = 1;
2253     }
2254 }
2255
2256 /* Calculate the value of Pearson's r.  r is stored into R, ase_1 into
2257    ASE_1, and ase_0 into ASE_0.  The row and column values must be
2258    passed in PT and Y. */
2259 static void
2260 calc_r (struct pivot_table *pt,
2261         double *PT, double *Y, double *r, double *ase_0, double *ase_1)
2262 {
2263   double SX, SY, S, T;
2264   double Xbar, Ybar;
2265   double sum_XYf, sum_X2Y2f;
2266   double sum_Xr, sum_X2r;
2267   double sum_Yc, sum_Y2c;
2268   int i, j;
2269
2270   for (sum_X2Y2f = sum_XYf = 0., i = 0; i < pt->n_rows; i++)
2271     for (j = 0; j < pt->n_cols; j++)
2272       {
2273         double fij = pt->mat[j + i * pt->n_cols];
2274         double product = PT[i] * Y[j];
2275         double temp = fij * product;
2276         sum_XYf += temp;
2277         sum_X2Y2f += temp * product;
2278       }
2279
2280   for (sum_Xr = sum_X2r = 0., i = 0; i < pt->n_rows; i++)
2281     {
2282       sum_Xr += PT[i] * pt->row_tot[i];
2283       sum_X2r += pow2 (PT[i]) * pt->row_tot[i];
2284     }
2285   Xbar = sum_Xr / pt->total;
2286
2287   for (sum_Yc = sum_Y2c = 0., i = 0; i < pt->n_cols; i++)
2288     {
2289       sum_Yc += Y[i] * pt->col_tot[i];
2290       sum_Y2c += Y[i] * Y[i] * pt->col_tot[i];
2291     }
2292   Ybar = sum_Yc / pt->total;
2293
2294   S = sum_XYf - sum_Xr * sum_Yc / pt->total;
2295   SX = sum_X2r - pow2 (sum_Xr) / pt->total;
2296   SY = sum_Y2c - pow2 (sum_Yc) / pt->total;
2297   T = sqrt (SX * SY);
2298   *r = S / T;
2299   *ase_0 = sqrt ((sum_X2Y2f - pow2 (sum_XYf) / pt->total) / (sum_X2r * sum_Y2c));
2300
2301   {
2302     double s, c, y, t;
2303
2304     for (s = c = 0., i = 0; i < pt->n_rows; i++)
2305       for (j = 0; j < pt->n_cols; j++)
2306         {
2307           double Xresid, Yresid;
2308           double temp;
2309
2310           Xresid = PT[i] - Xbar;
2311           Yresid = Y[j] - Ybar;
2312           temp = (T * Xresid * Yresid
2313                   - ((S / (2. * T))
2314                      * (Xresid * Xresid * SY + Yresid * Yresid * SX)));
2315           y = pt->mat[j + i * pt->n_cols] * temp * temp - c;
2316           t = s + y;
2317           c = (t - s) - y;
2318           s = t;
2319         }
2320     *ase_1 = sqrt (s) / (T * T);
2321   }
2322 }
2323
2324 /* Calculate symmetric statistics and their asymptotic standard
2325    errors.  Returns 0 if none could be calculated. */
2326 static int
2327 calc_symmetric (struct crosstabs_proc *proc, struct pivot_table *pt,
2328                 double v[N_SYMMETRIC], double ase[N_SYMMETRIC],
2329                 double t[N_SYMMETRIC],
2330                 double somers_d_v[3], double somers_d_ase[3],
2331                 double somers_d_t[3])
2332 {
2333   int q, i;
2334
2335   q = MIN (pt->ns_rows, pt->ns_cols);
2336   if (q <= 1)
2337     return 0;
2338
2339   for (i = 0; i < N_SYMMETRIC; i++)
2340     v[i] = ase[i] = t[i] = SYSMIS;
2341
2342   /* Phi, Cramer's V, contingency coefficient. */
2343   if (proc->statistics & ((1u << CRS_ST_PHI) | (1u << CRS_ST_CC)))
2344     {
2345       double Xp = 0.;   /* Pearson chi-square. */
2346       int r, c;
2347
2348       for (r = 0; r < pt->n_rows; r++)
2349         for (c = 0; c < pt->n_cols; c++)
2350           {
2351             const double expected = pt->row_tot[r] * pt->col_tot[c] / pt->total;
2352             const double freq = pt->mat[pt->n_cols * r + c];
2353             const double residual = freq - expected;
2354
2355             Xp += residual * residual / expected;
2356           }
2357
2358       if (proc->statistics & (1u << CRS_ST_PHI))
2359         {
2360           v[0] = sqrt (Xp / pt->total);
2361           v[1] = sqrt (Xp / (pt->total * (q - 1)));
2362         }
2363       if (proc->statistics & (1u << CRS_ST_CC))
2364         v[2] = sqrt (Xp / (Xp + pt->total));
2365     }
2366
2367   if (proc->statistics & ((1u << CRS_ST_BTAU) | (1u << CRS_ST_CTAU)
2368                           | (1u << CRS_ST_GAMMA) | (1u << CRS_ST_D)))
2369     {
2370       double *cum;
2371       double Dr, Dc;
2372       double P, Q;
2373       double btau_cum, ctau_cum, gamma_cum, d_yx_cum, d_xy_cum;
2374       double btau_var;
2375       int r, c;
2376
2377       Dr = Dc = pow2 (pt->total);
2378       for (r = 0; r < pt->n_rows; r++)
2379         Dr -= pow2 (pt->row_tot[r]);
2380       for (c = 0; c < pt->n_cols; c++)
2381         Dc -= pow2 (pt->col_tot[c]);
2382
2383       cum = xnmalloc (pt->n_cols * pt->n_rows, sizeof *cum);
2384       for (c = 0; c < pt->n_cols; c++)
2385         {
2386           double ct = 0.;
2387
2388           for (r = 0; r < pt->n_rows; r++)
2389             cum[c + r * pt->n_cols] = ct += pt->mat[c + r * pt->n_cols];
2390         }
2391
2392       /* P and Q. */
2393       {
2394         int i, j;
2395         double Cij, Dij;
2396
2397         P = Q = 0.;
2398         for (i = 0; i < pt->n_rows; i++)
2399           {
2400             Cij = Dij = 0.;
2401
2402             for (j = 1; j < pt->n_cols; j++)
2403               Cij += pt->col_tot[j] - cum[j + i * pt->n_cols];
2404
2405             if (i > 0)
2406               for (j = 1; j < pt->n_cols; j++)
2407                 Dij += cum[j + (i - 1) * pt->n_cols];
2408
2409             for (j = 0;;)
2410               {
2411                 double fij = pt->mat[j + i * pt->n_cols];
2412                 P += fij * Cij;
2413                 Q += fij * Dij;
2414
2415                 if (++j == pt->n_cols)
2416                   break;
2417                 assert (j < pt->n_cols);
2418
2419                 Cij -= pt->col_tot[j] - cum[j + i * pt->n_cols];
2420                 Dij += pt->col_tot[j - 1] - cum[j - 1 + i * pt->n_cols];
2421
2422                 if (i > 0)
2423                   {
2424                     Cij += cum[j - 1 + (i - 1) * pt->n_cols];
2425                     Dij -= cum[j + (i - 1) * pt->n_cols];
2426                   }
2427               }
2428           }
2429       }
2430
2431       if (proc->statistics & (1u << CRS_ST_BTAU))
2432         v[3] = (P - Q) / sqrt (Dr * Dc);
2433       if (proc->statistics & (1u << CRS_ST_CTAU))
2434         v[4] = (q * (P - Q)) / (pow2 (pt->total) * (q - 1));
2435       if (proc->statistics & (1u << CRS_ST_GAMMA))
2436         v[5] = (P - Q) / (P + Q);
2437
2438       /* ASE for tau-b, tau-c, gamma.  Calculations could be
2439          eliminated here, at expense of memory.  */
2440       {
2441         int i, j;
2442         double Cij, Dij;
2443
2444         btau_cum = ctau_cum = gamma_cum = d_yx_cum = d_xy_cum = 0.;
2445         for (i = 0; i < pt->n_rows; i++)
2446           {
2447             Cij = Dij = 0.;
2448
2449             for (j = 1; j < pt->n_cols; j++)
2450               Cij += pt->col_tot[j] - cum[j + i * pt->n_cols];
2451
2452             if (i > 0)
2453               for (j = 1; j < pt->n_cols; j++)
2454                 Dij += cum[j + (i - 1) * pt->n_cols];
2455
2456             for (j = 0;;)
2457               {
2458                 double fij = pt->mat[j + i * pt->n_cols];
2459
2460                 if (proc->statistics & (1u << CRS_ST_BTAU))
2461                   {
2462                     const double temp = (2. * sqrt (Dr * Dc) * (Cij - Dij)
2463                                          + v[3] * (pt->row_tot[i] * Dc
2464                                                    + pt->col_tot[j] * Dr));
2465                     btau_cum += fij * temp * temp;
2466                   }
2467
2468                 {
2469                   const double temp = Cij - Dij;
2470                   ctau_cum += fij * temp * temp;
2471                 }
2472
2473                 if (proc->statistics & (1u << CRS_ST_GAMMA))
2474                   {
2475                     const double temp = Q * Cij - P * Dij;
2476                     gamma_cum += fij * temp * temp;
2477                   }
2478
2479                 if (proc->statistics & (1u << CRS_ST_D))
2480                   {
2481                     d_yx_cum += fij * pow2 (Dr * (Cij - Dij)
2482                                             - (P - Q) * (pt->total - pt->row_tot[i]));
2483                     d_xy_cum += fij * pow2 (Dc * (Dij - Cij)
2484                                             - (Q - P) * (pt->total - pt->col_tot[j]));
2485                   }
2486
2487                 if (++j == pt->n_cols)
2488                   break;
2489                 assert (j < pt->n_cols);
2490
2491                 Cij -= pt->col_tot[j] - cum[j + i * pt->n_cols];
2492                 Dij += pt->col_tot[j - 1] - cum[j - 1 + i * pt->n_cols];
2493
2494                 if (i > 0)
2495                   {
2496                     Cij += cum[j - 1 + (i - 1) * pt->n_cols];
2497                     Dij -= cum[j + (i - 1) * pt->n_cols];
2498                   }
2499               }
2500           }
2501       }
2502
2503       btau_var = ((btau_cum
2504                    - (pt->total * pow2 (pt->total * (P - Q) / sqrt (Dr * Dc) * (Dr + Dc))))
2505                   / pow2 (Dr * Dc));
2506       if (proc->statistics & (1u << CRS_ST_BTAU))
2507         {
2508           ase[3] = sqrt (btau_var);
2509           t[3] = v[3] / (2 * sqrt ((ctau_cum - (P - Q) * (P - Q) / pt->total)
2510                                    / (Dr * Dc)));
2511         }
2512       if (proc->statistics & (1u << CRS_ST_CTAU))
2513         {
2514           ase[4] = ((2 * q / ((q - 1) * pow2 (pt->total)))
2515                     * sqrt (ctau_cum - (P - Q) * (P - Q) / pt->total));
2516           t[4] = v[4] / ase[4];
2517         }
2518       if (proc->statistics & (1u << CRS_ST_GAMMA))
2519         {
2520           ase[5] = ((4. / ((P + Q) * (P + Q))) * sqrt (gamma_cum));
2521           t[5] = v[5] / (2. / (P + Q)
2522                          * sqrt (ctau_cum - (P - Q) * (P - Q) / pt->total));
2523         }
2524       if (proc->statistics & (1u << CRS_ST_D))
2525         {
2526           somers_d_v[0] = (P - Q) / (.5 * (Dc + Dr));
2527           somers_d_ase[0] = 2. * btau_var / (Dr + Dc) * sqrt (Dr * Dc);
2528           somers_d_t[0] = (somers_d_v[0]
2529                            / (4 / (Dc + Dr)
2530                               * sqrt (ctau_cum - pow2 (P - Q) / pt->total)));
2531           somers_d_v[1] = (P - Q) / Dc;
2532           somers_d_ase[1] = 2. / pow2 (Dc) * sqrt (d_xy_cum);
2533           somers_d_t[1] = (somers_d_v[1]
2534                            / (2. / Dc
2535                               * sqrt (ctau_cum - pow2 (P - Q) / pt->total)));
2536           somers_d_v[2] = (P - Q) / Dr;
2537           somers_d_ase[2] = 2. / pow2 (Dr) * sqrt (d_yx_cum);
2538           somers_d_t[2] = (somers_d_v[2]
2539                            / (2. / Dr
2540                               * sqrt (ctau_cum - pow2 (P - Q) / pt->total)));
2541         }
2542
2543       free (cum);
2544     }
2545
2546   /* Spearman correlation, Pearson's r. */
2547   if (proc->statistics & (1u << CRS_ST_CORR))
2548     {
2549       double *R = xmalloc (sizeof *R * pt->n_rows);
2550       double *C = xmalloc (sizeof *C * pt->n_cols);
2551
2552       {
2553         double y, t, c = 0., s = 0.;
2554         int i = 0;
2555
2556         for (;;)
2557           {
2558             R[i] = s + (pt->row_tot[i] + 1.) / 2.;
2559             y = pt->row_tot[i] - c;
2560             t = s + y;
2561             c = (t - s) - y;
2562             s = t;
2563             if (++i == pt->n_rows)
2564               break;
2565             assert (i < pt->n_rows);
2566           }
2567       }
2568
2569       {
2570         double y, t, c = 0., s = 0.;
2571         int j = 0;
2572
2573         for (;;)
2574           {
2575             C[j] = s + (pt->col_tot[j] + 1.) / 2;
2576             y = pt->col_tot[j] - c;
2577             t = s + y;
2578             c = (t - s) - y;
2579             s = t;
2580             if (++j == pt->n_cols)
2581               break;
2582             assert (j < pt->n_cols);
2583           }
2584       }
2585
2586       calc_r (pt, R, C, &v[6], &t[6], &ase[6]);
2587       t[6] = v[6] / t[6];
2588
2589       free (R);
2590       free (C);
2591
2592       calc_r (pt, (double *) pt->rows, (double *) pt->cols, &v[7], &t[7], &ase[7]);
2593       t[7] = v[7] / t[7];
2594     }
2595
2596   /* Cohen's kappa. */
2597   if (proc->statistics & (1u << CRS_ST_KAPPA) && pt->ns_rows == pt->ns_cols)
2598     {
2599       double sum_fii, sum_rici, sum_fiiri_ci, sum_fijri_ci2, sum_riciri_ci;
2600       int i, j;
2601
2602       for (sum_fii = sum_rici = sum_fiiri_ci = sum_riciri_ci = 0., i = j = 0;
2603            i < pt->ns_rows; i++, j++)
2604         {
2605           double prod, sum;
2606
2607           while (pt->col_tot[j] == 0.)
2608             j++;
2609
2610           prod = pt->row_tot[i] * pt->col_tot[j];
2611           sum = pt->row_tot[i] + pt->col_tot[j];
2612
2613           sum_fii += pt->mat[j + i * pt->n_cols];
2614           sum_rici += prod;
2615           sum_fiiri_ci += pt->mat[j + i * pt->n_cols] * sum;
2616           sum_riciri_ci += prod * sum;
2617         }
2618       for (sum_fijri_ci2 = 0., i = 0; i < pt->ns_rows; i++)
2619         for (j = 0; j < pt->ns_cols; j++)
2620           {
2621             double sum = pt->row_tot[i] + pt->col_tot[j];
2622             sum_fijri_ci2 += pt->mat[j + i * pt->n_cols] * sum * sum;
2623           }
2624
2625       v[8] = (pt->total * sum_fii - sum_rici) / (pow2 (pt->total) - sum_rici);
2626
2627       ase[8] = sqrt ((pow2 (pt->total) * sum_rici
2628                       + sum_rici * sum_rici
2629                       - pt->total * sum_riciri_ci)
2630                      / (pt->total * (pow2 (pt->total) - sum_rici) * (pow2 (pt->total) - sum_rici)));
2631 #if 0
2632       t[8] = v[8] / sqrt (pt->total * (((sum_fii * (pt->total - sum_fii))
2633                                 / pow2 (pow2 (pt->total) - sum_rici))
2634                                + ((2. * (pt->total - sum_fii)
2635                                    * (2. * sum_fii * sum_rici
2636                                       - pt->total * sum_fiiri_ci))
2637                                   / cube (pow2 (pt->total) - sum_rici))
2638                                + (pow2 (pt->total - sum_fii)
2639                                   * (pt->total * sum_fijri_ci2 - 4.
2640                                      * sum_rici * sum_rici)
2641                                   / pow4 (pow2 (pt->total) - sum_rici))));
2642 #else
2643       t[8] = v[8] / ase[8];
2644 #endif
2645     }
2646
2647   return 1;
2648 }
2649
2650 /* Calculate risk estimate. */
2651 static int
2652 calc_risk (struct pivot_table *pt,
2653            double *value, double *upper, double *lower, union value *c)
2654 {
2655   double f11, f12, f21, f22;
2656   double v;
2657
2658   {
2659     int i;
2660
2661     for (i = 0; i < 3; i++)
2662       value[i] = upper[i] = lower[i] = SYSMIS;
2663   }
2664
2665   if (pt->ns_rows != 2 || pt->ns_cols != 2)
2666     return 0;
2667
2668   {
2669     int nz_cols[2];
2670     int i, j;
2671
2672     for (i = j = 0; i < pt->n_cols; i++)
2673       if (pt->col_tot[i] != 0.)
2674         {
2675           nz_cols[j++] = i;
2676           if (j == 2)
2677             break;
2678         }
2679
2680     assert (j == 2);
2681
2682     f11 = pt->mat[nz_cols[0]];
2683     f12 = pt->mat[nz_cols[1]];
2684     f21 = pt->mat[nz_cols[0] + pt->n_cols];
2685     f22 = pt->mat[nz_cols[1] + pt->n_cols];
2686
2687     c[0] = pt->cols[nz_cols[0]];
2688     c[1] = pt->cols[nz_cols[1]];
2689   }
2690
2691   value[0] = (f11 * f22) / (f12 * f21);
2692   v = sqrt (1. / f11 + 1. / f12 + 1. / f21 + 1. / f22);
2693   lower[0] = value[0] * exp (-1.960 * v);
2694   upper[0] = value[0] * exp (1.960 * v);
2695
2696   value[1] = (f11 * (f21 + f22)) / (f21 * (f11 + f12));
2697   v = sqrt ((f12 / (f11 * (f11 + f12)))
2698             + (f22 / (f21 * (f21 + f22))));
2699   lower[1] = value[1] * exp (-1.960 * v);
2700   upper[1] = value[1] * exp (1.960 * v);
2701
2702   value[2] = (f12 * (f21 + f22)) / (f22 * (f11 + f12));
2703   v = sqrt ((f11 / (f12 * (f11 + f12)))
2704             + (f21 / (f22 * (f21 + f22))));
2705   lower[2] = value[2] * exp (-1.960 * v);
2706   upper[2] = value[2] * exp (1.960 * v);
2707
2708   return 1;
2709 }
2710
2711 /* Calculate directional measures. */
2712 static int
2713 calc_directional (struct crosstabs_proc *proc, struct pivot_table *pt,
2714                   double v[N_DIRECTIONAL], double ase[N_DIRECTIONAL],
2715                   double t[N_DIRECTIONAL])
2716 {
2717   {
2718     int i;
2719
2720     for (i = 0; i < N_DIRECTIONAL; i++)
2721       v[i] = ase[i] = t[i] = SYSMIS;
2722   }
2723
2724   /* Lambda. */
2725   if (proc->statistics & (1u << CRS_ST_LAMBDA))
2726     {
2727       double *fim = xnmalloc (pt->n_rows, sizeof *fim);
2728       int *fim_index = xnmalloc (pt->n_rows, sizeof *fim_index);
2729       double *fmj = xnmalloc (pt->n_cols, sizeof *fmj);
2730       int *fmj_index = xnmalloc (pt->n_cols, sizeof *fmj_index);
2731       double sum_fim, sum_fmj;
2732       double rm, cm;
2733       int rm_index, cm_index;
2734       int i, j;
2735
2736       /* Find maximum for each row and their sum. */
2737       for (sum_fim = 0., i = 0; i < pt->n_rows; i++)
2738         {
2739           double max = pt->mat[i * pt->n_cols];
2740           int index = 0;
2741
2742           for (j = 1; j < pt->n_cols; j++)
2743             if (pt->mat[j + i * pt->n_cols] > max)
2744               {
2745                 max = pt->mat[j + i * pt->n_cols];
2746                 index = j;
2747               }
2748
2749           sum_fim += fim[i] = max;
2750           fim_index[i] = index;
2751         }
2752
2753       /* Find maximum for each column. */
2754       for (sum_fmj = 0., j = 0; j < pt->n_cols; j++)
2755         {
2756           double max = pt->mat[j];
2757           int index = 0;
2758
2759           for (i = 1; i < pt->n_rows; i++)
2760             if (pt->mat[j + i * pt->n_cols] > max)
2761               {
2762                 max = pt->mat[j + i * pt->n_cols];
2763                 index = i;
2764               }
2765
2766           sum_fmj += fmj[j] = max;
2767           fmj_index[j] = index;
2768         }
2769
2770       /* Find maximum row total. */
2771       rm = pt->row_tot[0];
2772       rm_index = 0;
2773       for (i = 1; i < pt->n_rows; i++)
2774         if (pt->row_tot[i] > rm)
2775           {
2776             rm = pt->row_tot[i];
2777             rm_index = i;
2778           }
2779
2780       /* Find maximum column total. */
2781       cm = pt->col_tot[0];
2782       cm_index = 0;
2783       for (j = 1; j < pt->n_cols; j++)
2784         if (pt->col_tot[j] > cm)
2785           {
2786             cm = pt->col_tot[j];
2787             cm_index = j;
2788           }
2789
2790       v[0] = (sum_fim + sum_fmj - cm - rm) / (2. * pt->total - rm - cm);
2791       v[1] = (sum_fmj - rm) / (pt->total - rm);
2792       v[2] = (sum_fim - cm) / (pt->total - cm);
2793
2794       /* ASE1 for Y given PT. */
2795       {
2796         double accum;
2797
2798         for (accum = 0., i = 0; i < pt->n_rows; i++)
2799           for (j = 0; j < pt->n_cols; j++)
2800             {
2801               const int deltaj = j == cm_index;
2802               accum += (pt->mat[j + i * pt->n_cols]
2803                         * pow2 ((j == fim_index[i])
2804                                - deltaj
2805                                + v[0] * deltaj));
2806             }
2807
2808         ase[2] = sqrt (accum - pt->total * v[0]) / (pt->total - cm);
2809       }
2810
2811       /* ASE0 for Y given PT. */
2812       {
2813         double accum;
2814
2815         for (accum = 0., i = 0; i < pt->n_rows; i++)
2816           if (cm_index != fim_index[i])
2817             accum += (pt->mat[i * pt->n_cols + fim_index[i]]
2818                       + pt->mat[i * pt->n_cols + cm_index]);
2819         t[2] = v[2] / (sqrt (accum - pow2 (sum_fim - cm) / pt->total) / (pt->total - cm));
2820       }
2821
2822       /* ASE1 for PT given Y. */
2823       {
2824         double accum;
2825
2826         for (accum = 0., i = 0; i < pt->n_rows; i++)
2827           for (j = 0; j < pt->n_cols; j++)
2828             {
2829               const int deltaj = i == rm_index;
2830               accum += (pt->mat[j + i * pt->n_cols]
2831                         * pow2 ((i == fmj_index[j])
2832                                - deltaj
2833                                + v[0] * deltaj));
2834             }
2835
2836         ase[1] = sqrt (accum - pt->total * v[0]) / (pt->total - rm);
2837       }
2838
2839       /* ASE0 for PT given Y. */
2840       {
2841         double accum;
2842
2843         for (accum = 0., j = 0; j < pt->n_cols; j++)
2844           if (rm_index != fmj_index[j])
2845             accum += (pt->mat[j + pt->n_cols * fmj_index[j]]
2846                       + pt->mat[j + pt->n_cols * rm_index]);
2847         t[1] = v[1] / (sqrt (accum - pow2 (sum_fmj - rm) / pt->total) / (pt->total - rm));
2848       }
2849
2850       /* Symmetric ASE0 and ASE1. */
2851       {
2852         double accum0;
2853         double accum1;
2854
2855         for (accum0 = accum1 = 0., i = 0; i < pt->n_rows; i++)
2856           for (j = 0; j < pt->n_cols; j++)
2857             {
2858               int temp0 = (fmj_index[j] == i) + (fim_index[i] == j);
2859               int temp1 = (i == rm_index) + (j == cm_index);
2860               accum0 += pt->mat[j + i * pt->n_cols] * pow2 (temp0 - temp1);
2861               accum1 += (pt->mat[j + i * pt->n_cols]
2862                          * pow2 (temp0 + (v[0] - 1.) * temp1));
2863             }
2864         ase[0] = sqrt (accum1 - 4. * pt->total * v[0] * v[0]) / (2. * pt->total - rm - cm);
2865         t[0] = v[0] / (sqrt (accum0 - pow2 ((sum_fim + sum_fmj - cm - rm) / pt->total))
2866                        / (2. * pt->total - rm - cm));
2867       }
2868
2869       free (fim);
2870       free (fim_index);
2871       free (fmj);
2872       free (fmj_index);
2873
2874       {
2875         double sum_fij2_ri, sum_fij2_ci;
2876         double sum_ri2, sum_cj2;
2877
2878         for (sum_fij2_ri = sum_fij2_ci = 0., i = 0; i < pt->n_rows; i++)
2879           for (j = 0; j < pt->n_cols; j++)
2880             {
2881               double temp = pow2 (pt->mat[j + i * pt->n_cols]);
2882               sum_fij2_ri += temp / pt->row_tot[i];
2883               sum_fij2_ci += temp / pt->col_tot[j];
2884             }
2885
2886         for (sum_ri2 = 0., i = 0; i < pt->n_rows; i++)
2887           sum_ri2 += pow2 (pt->row_tot[i]);
2888
2889         for (sum_cj2 = 0., j = 0; j < pt->n_cols; j++)
2890           sum_cj2 += pow2 (pt->col_tot[j]);
2891
2892         v[3] = (pt->total * sum_fij2_ci - sum_ri2) / (pow2 (pt->total) - sum_ri2);
2893         v[4] = (pt->total * sum_fij2_ri - sum_cj2) / (pow2 (pt->total) - sum_cj2);
2894       }
2895     }
2896
2897   if (proc->statistics & (1u << CRS_ST_UC))
2898     {
2899       double UX, UY, UXY, P;
2900       double ase1_yx, ase1_xy, ase1_sym;
2901       int i, j;
2902
2903       for (UX = 0., i = 0; i < pt->n_rows; i++)
2904         if (pt->row_tot[i] > 0.)
2905           UX -= pt->row_tot[i] / pt->total * log (pt->row_tot[i] / pt->total);
2906
2907       for (UY = 0., j = 0; j < pt->n_cols; j++)
2908         if (pt->col_tot[j] > 0.)
2909           UY -= pt->col_tot[j] / pt->total * log (pt->col_tot[j] / pt->total);
2910
2911       for (UXY = P = 0., i = 0; i < pt->n_rows; i++)
2912         for (j = 0; j < pt->n_cols; j++)
2913           {
2914             double entry = pt->mat[j + i * pt->n_cols];
2915
2916             if (entry <= 0.)
2917               continue;
2918
2919             P += entry * pow2 (log (pt->col_tot[j] * pt->row_tot[i] / (pt->total * entry)));
2920             UXY -= entry / pt->total * log (entry / pt->total);
2921           }
2922
2923       for (ase1_yx = ase1_xy = ase1_sym = 0., i = 0; i < pt->n_rows; i++)
2924         for (j = 0; j < pt->n_cols; j++)
2925           {
2926             double entry = pt->mat[j + i * pt->n_cols];
2927
2928             if (entry <= 0.)
2929               continue;
2930
2931             ase1_yx += entry * pow2 (UY * log (entry / pt->row_tot[i])
2932                                     + (UX - UXY) * log (pt->col_tot[j] / pt->total));
2933             ase1_xy += entry * pow2 (UX * log (entry / pt->col_tot[j])
2934                                     + (UY - UXY) * log (pt->row_tot[i] / pt->total));
2935             ase1_sym += entry * pow2 ((UXY
2936                                       * log (pt->row_tot[i] * pt->col_tot[j] / pow2 (pt->total)))
2937                                      - (UX + UY) * log (entry / pt->total));
2938           }
2939
2940       v[5] = 2. * ((UX + UY - UXY) / (UX + UY));
2941       ase[5] = (2. / (pt->total * pow2 (UX + UY))) * sqrt (ase1_sym);
2942       t[5] = v[5] / ((2. / (pt->total * (UX + UY)))
2943                      * sqrt (P - pow2 (UX + UY - UXY) / pt->total));
2944
2945       v[6] = (UX + UY - UXY) / UX;
2946       ase[6] = sqrt (ase1_xy) / (pt->total * UX * UX);
2947       t[6] = v[6] / (sqrt (P - pt->total * pow2 (UX + UY - UXY)) / (pt->total * UX));
2948
2949       v[7] = (UX + UY - UXY) / UY;
2950       ase[7] = sqrt (ase1_yx) / (pt->total * UY * UY);
2951       t[7] = v[7] / (sqrt (P - pt->total * pow2 (UX + UY - UXY)) / (pt->total * UY));
2952     }
2953
2954   /* Somers' D. */
2955   if (proc->statistics & (1u << CRS_ST_D))
2956     {
2957       double v_dummy[N_SYMMETRIC];
2958       double ase_dummy[N_SYMMETRIC];
2959       double t_dummy[N_SYMMETRIC];
2960       double somers_d_v[3];
2961       double somers_d_ase[3];
2962       double somers_d_t[3];
2963
2964       if (calc_symmetric (proc, pt, v_dummy, ase_dummy, t_dummy,
2965                           somers_d_v, somers_d_ase, somers_d_t))
2966         {
2967           int i;
2968           for (i = 0; i < 3; i++)
2969             {
2970               v[8 + i] = somers_d_v[i];
2971               ase[8 + i] = somers_d_ase[i];
2972               t[8 + i] = somers_d_t[i];
2973             }
2974         }
2975     }
2976
2977   /* Eta. */
2978   if (proc->statistics & (1u << CRS_ST_ETA))
2979     {
2980       {
2981         double sum_Xr, sum_X2r;
2982         double SX, SXW;
2983         int i, j;
2984
2985         for (sum_Xr = sum_X2r = 0., i = 0; i < pt->n_rows; i++)
2986           {
2987             sum_Xr += pt->rows[i].f * pt->row_tot[i];
2988             sum_X2r += pow2 (pt->rows[i].f) * pt->row_tot[i];
2989           }
2990         SX = sum_X2r - pow2 (sum_Xr) / pt->total;
2991
2992         for (SXW = 0., j = 0; j < pt->n_cols; j++)
2993           {
2994             double cum;
2995
2996             for (cum = 0., i = 0; i < pt->n_rows; i++)
2997               {
2998                 SXW += pow2 (pt->rows[i].f) * pt->mat[j + i * pt->n_cols];
2999                 cum += pt->rows[i].f * pt->mat[j + i * pt->n_cols];
3000               }
3001
3002             SXW -= cum * cum / pt->col_tot[j];
3003           }
3004         v[11] = sqrt (1. - SXW / SX);
3005       }
3006
3007       {
3008         double sum_Yc, sum_Y2c;
3009         double SY, SYW;
3010         int i, j;
3011
3012         for (sum_Yc = sum_Y2c = 0., i = 0; i < pt->n_cols; i++)
3013           {
3014             sum_Yc += pt->cols[i].f * pt->col_tot[i];
3015             sum_Y2c += pow2 (pt->cols[i].f) * pt->col_tot[i];
3016           }
3017         SY = sum_Y2c - sum_Yc * sum_Yc / pt->total;
3018
3019         for (SYW = 0., i = 0; i < pt->n_rows; i++)
3020           {
3021             double cum;
3022
3023             for (cum = 0., j = 0; j < pt->n_cols; j++)
3024               {
3025                 SYW += pow2 (pt->cols[j].f) * pt->mat[j + i * pt->n_cols];
3026                 cum += pt->cols[j].f * pt->mat[j + i * pt->n_cols];
3027               }
3028
3029             SYW -= cum * cum / pt->row_tot[i];
3030           }
3031         v[12] = sqrt (1. - SYW / SY);
3032       }
3033     }
3034
3035   return 1;
3036 }
3037
3038 /*
3039    Local Variables:
3040    mode: c
3041    End:
3042 */