033b6a18a07c8bdb705c0bfb3ec44f9270f80cb5
[pspp-builds.git] / src / math / categoricals.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2009 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include <stdio.h>
20
21 #include "categoricals.h"
22
23 #include <gl/xalloc.h>
24 #include <data/variable.h>
25 #include <data/case.h>
26 #include <data/value.h>
27 #include <libpspp/hmap.h>
28 #include <libpspp/pool.h>
29
30
31 struct value_node
32 {
33   struct hmap_node node;      /* Node in hash map. */
34   union value value;          /* The value being labeled. */
35   double cc;                  /* The total of the weights of cases with this value */
36   int subscript;              /* A zero based integer, unique within the variable.
37                                  Can be used as an index into an array */
38 };
39
40
41 struct var_params
42 {
43   /* A map indexed by a union values */
44   struct hmap map;
45
46   int base_subscript;
47
48   /* The number of distinct values of this variable */
49   int n_cats;
50
51   /* A map of values indexed by subscript */
52   const struct value_node **reverse_value_map;
53 };
54
55
56 struct categoricals
57 {
58   const struct variable **vars;
59   size_t n_vars;
60
61   const struct variable *wv;
62
63   /* An array of var_params */
64   struct var_params *vp;
65
66   /* A map to enable the lookup of variables indexed by subscript */
67   int *reverse_variable_map;
68
69   size_t n_cats_total;
70
71   struct pool *pool;
72 };
73
74
75 void
76 categoricals_destroy ( struct categoricals *cat)
77 {
78   int i;
79   for (i = 0 ; i < cat->n_vars; ++i)
80     hmap_destroy (&cat->vp[i].map);
81
82   pool_destroy (cat->pool);
83   free (cat);
84 }
85
86
87 void
88 categoricals_dump (const struct categoricals *cat)
89 {
90   int v;
91
92   for (v = 0 ; v < cat->n_vars; ++v)
93     {
94       const struct var_params *vp = &cat->vp[v];
95       const struct hmap *m = &vp->map;
96       size_t width = var_get_width (cat->vars[v]);
97       struct hmap_node *node ;
98       int x;
99      
100       printf ("\n%s (%d):\n", var_get_name (cat->vars[v]), vp->base_subscript);
101
102       assert (vp->reverse_value_map);
103
104       printf ("Reverse map\n");
105       for (x = 0 ; x < vp->n_cats; ++x)
106         {
107           const struct value_node *vn = vp->reverse_value_map[x];
108           printf ("Value for %d is %s\n", x, value_str (&vn->value, width));
109         }
110
111       printf ("\nForward map\n");
112       for (node = hmap_first (m); node; node = hmap_next (m, node))
113         {
114           const struct value_node *vn = HMAP_DATA (node, struct value_node, node);
115           printf ("Value: %s; Index %d; CC %g\n",
116                   value_str (&vn->value, width),  vn->subscript, vn->cc);
117         }
118     }
119 }
120
121
122
123 static struct value_node *
124 lookup_value (const struct hmap *map, const struct variable *var, const union value *val)
125 {
126   struct value_node *foo;
127   unsigned int width = var_get_width (var);
128   size_t hash = value_hash (val, width, 0);
129
130   HMAP_FOR_EACH_WITH_HASH (foo, struct value_node, node, hash, map)
131     {
132       if (value_equal (val, &foo->value, width))
133         break;
134
135       fprintf (stderr, "Warning: Hash table collision\n");
136     }
137
138   return foo;
139 }
140
141
142
143 struct categoricals *
144 categoricals_create (const struct variable **v, size_t n_vars, const struct variable *wv)
145 {
146   size_t i;
147   struct categoricals *cat = xmalloc (sizeof *cat);
148   
149   cat->vars = v;
150   cat->n_vars = n_vars;
151   cat->wv = wv;
152   cat->n_cats_total = 0;
153   cat->reverse_variable_map = NULL;
154   cat->pool = pool_create ();
155
156   cat->vp = pool_calloc (cat->pool, n_vars, sizeof *cat->vp);
157
158   for (i = 0 ; i < cat->n_vars; ++i)
159     hmap_init (&cat->vp[i].map);
160
161   return cat;
162 }
163
164
165
166 void
167 categoricals_update (struct categoricals *cat, const struct ccase *c)
168 {
169   size_t i;
170   
171   const double weight = cat->wv ? case_data (c, cat->wv)->f : 1.0;
172
173   assert (NULL == cat->reverse_variable_map);
174
175   for (i = 0 ; i < cat->n_vars; ++i)
176     {
177       unsigned int width = var_get_width (cat->vars[i]);
178       const union value *val = case_data (c, cat->vars[i]);
179       size_t hash = value_hash (val, width, 0);
180
181       struct value_node  *node = lookup_value (&cat->vp[i].map, cat->vars[i], val);
182       if ( NULL == node)
183         {
184           node = pool_malloc (cat->pool, sizeof *node);
185
186           value_init (&node->value, width);
187           value_copy (&node->value, val, width);
188           node->cc = 0.0;
189
190           hmap_insert (&cat->vp[i].map, &node->node,  hash);
191           cat->n_cats_total ++;
192           node->subscript = cat->vp[i].n_cats++ ;
193         }
194
195       node->cc += weight;
196     }
197 }
198
199 /* Return the number of categories (distinct values) for variable N */
200 size_t
201 categoricals_n_count (const struct categoricals *cat, size_t n)
202 {
203   return hmap_count (&cat->vp[n].map);
204 }
205
206
207 /* Return the index for value VAL in the Nth variable */
208 int
209 categoricals_index (const struct categoricals *cat, size_t n, const union value *val)
210 {
211   struct value_node *vn = lookup_value (&cat->vp[n].map, cat->vars[n], val);
212
213   if ( vn == NULL)
214     return -1;
215
216   return vn->subscript;
217 }
218
219
220 /* Return the total number of categories */
221 size_t
222 categoricals_total (const struct categoricals *cat)
223 {
224   return cat->n_cats_total;
225 }
226
227
228 /* This function must be called *before* any call to categoricals_get_*_by subscript an
229  *after* all calls to categoricals_update */
230 void
231 categoricals_done (struct categoricals *cat)
232 {
233   /* Implementation Note: Whilst this function is O(n) in cat->n_cats_total, in most
234      uses it will be more efficient that using a tree based structure, since it
235      is called only once, and means that subsequent lookups will be O(1).
236
237      1 call of O(n) + 10^9 calls of O(1) is better than 10^9 calls of O(log n).
238   */
239   int v;
240   int idx = 0;
241   cat->reverse_variable_map = pool_calloc (cat->pool, cat->n_cats_total, sizeof *cat->reverse_variable_map);
242   
243   for (v = 0 ; v < cat->n_vars; ++v)
244     {
245       int i;
246       struct var_params *vp = &cat->vp[v];
247       int n_cats_total = categoricals_n_count (cat, v);
248       struct hmap_node *node ;
249
250       vp->reverse_value_map = pool_calloc (cat->pool, n_cats_total, sizeof *vp->reverse_value_map);
251
252       vp->base_subscript = idx;
253
254       for (node = hmap_first (&vp->map); node; node = hmap_next (&vp->map, node))
255         {
256           const struct value_node *vn = HMAP_DATA (node, struct value_node, node);
257           vp->reverse_value_map[vn->subscript] = vn;
258         }
259
260       for (i = 0; i < vp->n_cats; ++i)
261         cat->reverse_variable_map[idx++] = v;
262     }
263 }
264
265
266
267 /* Return the categorical variable corresponding to SUBSCRIPT */
268 const struct variable *
269 categoricals_get_variable_by_subscript (const struct categoricals *cat, int subscript)
270 {
271   int index;
272
273   assert (cat->reverse_variable_map);
274   
275   index = cat->reverse_variable_map[subscript];
276
277   return cat->vars[index];
278 }
279
280
281 /* Return the value corresponding to SUBSCRIPT */
282 const union value *
283 categoricals_get_value_by_subscript (const struct categoricals *cat, int subscript)
284 {
285   int vindex = cat->reverse_variable_map[subscript];
286   const struct var_params *vp = &cat->vp[vindex];
287   const struct value_node *vn = vp->reverse_value_map [subscript - vp->base_subscript];
288
289   return &vn->value;
290 }
291
292
293 /* Returns unity if the value in case C at SUBSCRIPT is equal to the category
294    for that subscript */
295 double
296 categoricals_get_binary_by_subscript (const struct categoricals *cat, int subscript,
297                                       const struct ccase *c)
298 {
299   const struct variable *var = categoricals_get_variable_by_subscript (cat, subscript);
300   int width = var_get_width (var);
301
302   const union value *val = case_data (c, var);
303
304   return value_equal (val, categoricals_get_value_by_subscript (cat, subscript), width);
305 }