21506ed8b5d0af64b2d2dc0e538776d9db27a78e
[pspp-builds.git] / src / data / category.c
1 /* PSPP - binary encodings for categorical variables.
2    Copyright (C) 2005 Free Software Foundation, Inc.
3    Written by Jason H Stover <jason@sakla.net>.
4
5    This program is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18    02110-1301, USA. */
19
20 /*
21   Functions and data structures to store values of a categorical
22   variable, and to recode those values into binary vectors.
23
24   For some statistical models, it is necessary to change each value
25   of a categorical variable to a vector with binary entries. These
26   vectors are then stored as sub-rows within a matrix during
27   model-fitting. For example, we need functions and data strucutres to map a
28   value, say 'a', of a variable named 'cat_var', to a vector, say (0
29   1 0 0 0), and vice versa.  We also need to be able to map the
30   vector back to the value 'a', and if the vector is a sub-row of a
31   matrix, we need to know which sub-row corresponds to the variable
32   'cat_var'.
33 */
34 #include <config.h>
35
36 #include "category.h"
37
38 #include <assert.h>
39 #include <stdlib.h>
40 #include <string.h>
41
42 #include <libpspp/alloc.h>
43 #include <libpspp/message.h>
44 #include "cat-routines.h"
45 #include "variable.h"
46
47 #define N_INITIAL_CATEGORIES 1
48
49 void
50 cat_stored_values_create (struct variable *v)
51 {
52   if (v->obs_vals == NULL)
53     {
54       v->obs_vals = xmalloc (sizeof (*v->obs_vals));
55       v->obs_vals->n_categories = 0;
56       v->obs_vals->n_allocated_categories = N_INITIAL_CATEGORIES;
57       v->obs_vals->vals =
58         xnmalloc (N_INITIAL_CATEGORIES, sizeof *v->obs_vals->vals);
59     }
60 }
61
62 void
63 cat_stored_values_destroy (struct variable *v)
64 {
65   assert (v != NULL);
66
67   if (v->obs_vals != NULL)
68     {
69       if (v->obs_vals->n_allocated_categories > 0)
70         {
71           free (v->obs_vals->vals);
72           v->obs_vals->vals = NULL;
73         }
74       free (v->obs_vals);
75       v->obs_vals = NULL;
76     }
77 }
78
79 /*
80   Which subscript corresponds to val?
81  */
82 size_t
83 cat_value_find (const struct variable *v, const union value *val)
84 {
85   size_t i;
86   const union value *candidate;
87
88   assert (val != NULL);
89   assert (v != NULL);
90   assert (v->obs_vals != NULL);
91   for (i = 0; i < v->obs_vals->n_categories; i++)
92     {
93       candidate = v->obs_vals->vals + i;
94       assert (candidate != NULL);
95       if (!compare_values (candidate, val, var_get_width (v)))
96         {
97           return i;
98         }
99     }
100   return CAT_VALUE_NOT_FOUND;
101 }
102
103 /*
104    Add the new value unless it is already present.
105  */
106 void
107 cat_value_update (struct variable *v, const union value *val)
108 {
109   struct cat_vals *cv;
110
111   if (var_is_alpha (v))
112     {
113       assert (val != NULL);
114       assert (v != NULL);
115       cv = v->obs_vals;
116       if (cat_value_find (v, val) == CAT_VALUE_NOT_FOUND)
117         {
118           if (cv->n_categories >= cv->n_allocated_categories)
119             {
120               cv->n_allocated_categories *= 2;
121               cv->vals = xnrealloc (cv->vals,
122                                     cv->n_allocated_categories,
123                                     sizeof *cv->vals);
124             }
125           cv->vals[cv->n_categories] = *val;
126           cv->n_categories++;
127         }
128     }
129 }
130
131 union value *
132 cat_subscript_to_value (const size_t s, struct variable *v)
133 {
134   assert (v->obs_vals != NULL);
135   if (s < v->obs_vals->n_categories)
136     {
137       return (v->obs_vals->vals + s);
138     }
139   else
140     {
141       return NULL;
142     }
143 }
144
145 /*
146   Return the number of categories of a categorical variable.
147  */
148 size_t 
149 cat_get_n_categories (const struct variable *v)
150 {
151   return v->obs_vals->n_categories;
152 }
153