a1c6f50269b1b8e7c506f994b0377ca6f174f538
[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
29 struct categoricals
30 {
31   const struct variable **vars;
32   size_t n_vars;
33
34   const struct variable *wv;
35
36   struct hmap *map;
37
38   int *next_index;
39
40   size_t n_cats;
41 };
42
43
44 struct value_node
45   {
46     struct hmap_node node;      /* Node in hash map. */
47     union value value;          /* The value being labeled. */
48     double cc;                  /* The total of the weights of cases with this value */
49     int index;                  /* A zero based integer, unique within the variable.
50                                    Can be used as an index into an array */
51   };
52
53
54 static struct value_node *
55 lookup_value (const struct hmap *map, const struct variable *var, const union value *val)
56 {
57   struct value_node *foo;
58   unsigned int width = var_get_width (var);
59   size_t hash = value_hash (val, width, 0);
60
61   HMAP_FOR_EACH_WITH_HASH (foo, struct value_node, node, hash, map)
62     {
63       if (value_equal (val, &foo->value, width))
64         break;
65     }
66
67   return foo;
68 }
69
70
71 struct categoricals *
72 categoricals_create (const struct variable **v, size_t n_vars, const struct variable *wv)
73 {
74   size_t i;
75   struct categoricals *cat = xmalloc (sizeof *cat);
76   
77   cat->vars = v;
78   cat->n_vars = n_vars;
79   cat->wv = wv;
80   cat->n_cats = 0;
81
82   cat->map = xmalloc (sizeof *cat->map * n_vars);
83   cat->next_index = xcalloc (sizeof *cat->next_index, n_vars);
84
85   for (i = 0 ; i < cat->n_vars; ++i)
86     {
87       hmap_init (&cat->map[i]);
88     }
89
90   return cat;
91 }
92
93
94 void
95 categoricals_update (struct categoricals *cat, const struct ccase *c)
96 {
97   size_t i;
98   
99   const double weight = cat->wv ? case_data (c, cat->wv)->f : 1.0;
100
101   for (i = 0 ; i < cat->n_vars; ++i)
102     {
103       unsigned int width = var_get_width (cat->vars[i]);
104       const union value *val = case_data (c, cat->vars[i]);
105       size_t hash = value_hash (val, width, 0);
106
107       struct value_node  *node = lookup_value (&cat->map[i], cat->vars[i], val);
108
109       if ( NULL == node)
110         {
111           node = xmalloc (sizeof *node);
112
113           value_init (&node->value, width);
114           value_copy (&node->value, val, width);
115           node->cc = 0.0;
116
117           hmap_insert (&cat->map[i], &node->node,  hash);
118           cat->n_cats ++;
119           node->index = cat->next_index[i]++ ;
120         }
121
122       node->cc += weight;
123     }
124 }
125
126 /* Return the number of categories (distinct values) for variable N */
127 size_t
128 categoricals_n_count (const struct categoricals *cat, size_t n)
129 {
130   return hmap_count (&cat->map[n]);
131 }
132
133
134 /* Return the index for value VAL in the Nth variable */
135 int
136 categoricals_index (const struct categoricals *cat, size_t n, const union value *val)
137 {
138   struct value_node *vn = lookup_value (&cat->map[n], cat->vars[n], val);
139
140   if ( vn == NULL)
141     return -1;
142
143   return vn->index;
144 }
145
146
147 /* Return the total number of categories */
148 size_t
149 categoricals_total (const struct categoricals *cat)
150 {
151   return cat->n_cats;
152 }
153
154
155
156
157
158