5785623a6ab0fd519d2a7d8105833f2528c71b8d
[pspp] / src / math / levene.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2010, 2011 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "levene.h"
20 #include <math.h>
21
22 #include "libpspp/misc.h"
23 #include "libpspp/hmap.h"
24 #include "data/value.h"
25 #include "data/val-type.h"
26
27 #include <gl/xalloc.h>
28 #include <assert.h>
29
30 struct lev
31 {
32   struct hmap_node node;
33   union value group;
34
35   double t_bar;
36   double z_mean;
37   double n;
38 };
39
40 typedef unsigned int hash_func (const struct levene *, const union value *v);
41 typedef bool cmp_func (const struct levene *, const union value *v0, const union value *v1);
42
43 struct levene
44 {
45   /* Width of the categorical variable */
46   int gvw ;
47
48   /* The value dividing the groups. Valid only for dichotomous categorical variable.*/
49   const union value *cutpoint;
50
51
52   /* A hashtable of struct lev objects indexed by union value */
53   struct hmap hmap;
54
55   hash_func *hash;
56   cmp_func *cmp;
57
58
59   /* A state variable indicating how many passes have been done */
60   int pass;
61
62   double grand_n;
63   double z_grand_mean;
64
65   double denominator;
66 };
67
68
69 static unsigned int
70 unique_hash (const struct levene *nl, const union value *val)
71 {
72   return value_hash (val, nl->gvw, 0);
73 }
74
75 static bool
76 unique_cmp (const struct levene *nl, const union value *val0, const union value *val1)
77 {
78   return value_equal (val0, val1, nl->gvw);
79 }
80
81 static unsigned int
82 cutpoint_hash (const struct levene *nl, const union value *val)
83 {
84   int x = value_compare_3way (val, nl->cutpoint, nl->gvw);
85
86   return (x < 0);
87 }
88
89 static bool
90 cutpoint_cmp (const struct levene *nl, const union value *val0, const union value *val1)
91 {
92   int x = value_compare_3way (val0, nl->cutpoint, nl->gvw);
93
94   int y = value_compare_3way (val1, nl->cutpoint, nl->gvw);
95
96   if (x == 0) x = 1;
97   if (y == 0) y = 1;
98
99   return (x == y);
100 }
101
102
103
104 static struct lev *
105 find_group (const struct levene *nl, const union value *target)
106 {
107   struct lev *l = NULL;
108
109   HMAP_FOR_EACH_WITH_HASH (l, struct lev, node, nl->hash (nl, target), &nl->hmap)
110     {
111       if (nl->cmp (nl, &l->group, target))
112         break;
113     }
114   return l;
115 }
116
117
118 struct levene *
119 levene_create (int indep_width, const union value *cutpoint)
120 {
121   struct levene *nl = xzalloc (sizeof *nl);
122
123   hmap_init (&nl->hmap);
124
125   nl->gvw = indep_width;
126   nl->cutpoint = cutpoint;
127
128   nl->hash  = cutpoint ? cutpoint_hash : unique_hash;
129   nl->cmp   = cutpoint ? cutpoint_cmp : unique_cmp;
130
131   return nl;
132 }
133
134
135 /* Data accumulation. First pass */
136 void
137 levene_pass_one (struct levene *nl, double value, double weight, const union value *gv)
138 {
139   struct lev *lev = find_group (nl, gv);
140
141   if (nl->pass == 0)
142     {
143       nl->pass = 1;
144     }
145   assert (nl->pass == 1);
146
147   if (NULL == lev)
148     {
149       struct lev *l = xzalloc (sizeof *l);
150       value_clone (&l->group, gv, nl->gvw);
151       hmap_insert (&nl->hmap, &l->node, nl->hash (nl, &l->group));
152       lev = l;
153     }
154
155   lev->n += weight;
156   lev->t_bar += value * weight;
157
158   nl->grand_n += weight;
159 }
160
161 /* Data accumulation. Second pass */
162 void
163 levene_pass_two (struct levene *nl, double value, double weight, const union value *gv)
164 {
165   struct lev *lev = NULL;
166
167   if (nl->pass == 1)
168     {
169       struct lev *next;
170       struct lev *l;
171
172       nl->pass = 2;
173
174       HMAP_FOR_EACH_SAFE (l, next, struct lev, node, &nl->hmap)
175       {
176         l->t_bar /= l->n;
177       }
178     }
179   assert (nl->pass == 2);
180
181   lev = find_group (nl, gv);
182
183   lev->z_mean += fabs (value - lev->t_bar) * weight;
184   nl->z_grand_mean += fabs (value - lev->t_bar) * weight;
185 }
186
187 /* Data accumulation. Third pass */
188 void
189 levene_pass_three (struct levene *nl, double value, double weight, const union value *gv)
190 {
191   double z;
192   struct lev *lev = NULL;
193
194   if (nl->pass == 2)
195     {
196       struct lev *next;
197       struct lev *l;
198
199       nl->pass = 3;
200
201       HMAP_FOR_EACH_SAFE (l, next, struct lev, node, &nl->hmap)
202       {
203         l->z_mean /= l->n;
204       }
205
206       nl->z_grand_mean /= nl->grand_n;
207   }
208
209   assert (nl->pass == 3);
210   lev = find_group (nl, gv);
211
212   z = fabs (value - lev->t_bar);
213   nl->denominator += pow2 (z - lev->z_mean) * weight;
214 }
215
216
217 /* Return the value of the levene statistic */
218 double
219 levene_calculate (struct levene *nl)
220 {
221   struct lev *next;
222   struct lev *l;
223
224   double numerator = 0.0;
225   double nn = 0.0;
226
227   /* The Levene calculation requires three passes.
228      Normally this should have been done prior to calling this function.
229      However, in abnormal circumstances (eg. the dataset is empty) there
230      will have been no passes.
231    */
232   assert (nl->pass == 0 || nl->pass == 3);
233
234   if (nl->pass == 0)
235     return SYSMIS;
236
237   nl->denominator *= hmap_count (&nl->hmap) - 1;
238
239   HMAP_FOR_EACH_SAFE (l, next, struct lev, node, &nl->hmap)
240     {
241       numerator += l->n * pow2 (l->z_mean - nl->z_grand_mean);
242       nn += l->n;
243     }
244
245   numerator *= nn - hmap_count (&nl->hmap);
246
247   return numerator / nl->denominator;
248 }
249
250 void
251 levene_destroy (struct levene *nl)
252 {
253   struct lev *next;
254   struct lev *l;
255
256   HMAP_FOR_EACH_SAFE (l, next, struct lev, node, &nl->hmap)
257     {
258       value_destroy (&l->group, nl->gvw);
259       free (l);
260     }
261
262   hmap_destroy (&nl->hmap);
263   free (nl);
264 }