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