Change license from GPLv2+ to GPLv3+.
[pspp-builds.git] / src / math / design-matrix.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2005 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 /*
18   Create design matrices for procedures that need them.
19 */
20 #include <config.h>
21
22 #include "design-matrix.h"
23
24 #include <assert.h>
25 #include <math.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include <libpspp/alloc.h>
30 #include <libpspp/message.h>
31 #include <data/variable.h>
32 #include <data/category.h>
33 #include <data/value.h>
34
35 #include <gsl/gsl_machine.h>
36 #include <gsl/gsl_vector.h>
37 #include <gsl/gsl_matrix.h>
38
39 #define DM_COLUMN_NOT_FOUND -1
40 #define DM_INDEX_NOT_FOUND -3
41
42
43 struct design_matrix *
44 design_matrix_create (int n_variables,
45                       const struct variable *v_variables[],
46                       const size_t n_data)
47 {
48   struct design_matrix *dm;
49   const struct variable *v;
50   size_t i;
51   size_t n_cols = 0;
52   size_t col;
53
54   dm = xmalloc (sizeof *dm);
55   dm->vars = xnmalloc (n_variables, sizeof *dm->vars);
56   dm->n_vars = n_variables;
57
58   for (i = 0; i < n_variables; i++)
59     {
60       v = v_variables[i];
61       assert ((dm->vars + i) != NULL);
62       (dm->vars + i)->v = v;    /* Allows us to look up the variable from
63                                    the design matrix. */
64       (dm->vars + i)->first_column = n_cols;
65       if (var_is_numeric (v))
66         {
67           (dm->vars + i)->last_column = n_cols;
68           n_cols++;
69         }
70       else if (var_is_alpha (v))
71         {
72           size_t n_categories = cat_get_n_categories (v);
73           (dm->vars + i)->last_column =
74             (dm->vars + i)->first_column + n_categories - 2;
75           n_cols += n_categories - 1;
76         }
77     }
78   dm->m = gsl_matrix_calloc (n_data, n_cols);
79   col = 0;
80
81   return dm;
82 }
83
84 void
85 design_matrix_destroy (struct design_matrix *dm)
86 {
87   free (dm->vars);
88   gsl_matrix_free (dm->m);
89   free (dm);
90 }
91
92 /*
93   Return the index of the variable for the
94   given column.
95  */
96 const struct variable *
97 design_matrix_col_to_var (const struct design_matrix *dm, size_t col)
98 {
99   size_t i;
100   struct design_matrix_var v;
101
102   for (i = 0; i < dm->n_vars; i++)
103     {
104       v = dm->vars[i];
105       if (v.first_column <= col && col <= v.last_column)
106         return v.v;
107     }
108   return NULL;
109 }
110
111 /*
112   Return the number of the first column which holds the
113   values for variable v.
114  */
115 size_t
116 design_matrix_var_to_column (const struct design_matrix * dm,
117                              const struct variable * v)
118 {
119   size_t i;
120   struct design_matrix_var tmp;
121
122   for (i = 0; i < dm->n_vars; i++)
123     {
124       tmp = dm->vars[i];
125       if (tmp.v == v)
126         {
127           return tmp.first_column;
128         }
129     }
130   return DM_COLUMN_NOT_FOUND;
131 }
132
133 /* Last column. */
134 static size_t
135 dm_var_to_last_column (const struct design_matrix *dm,
136                        const struct variable *v)
137 {
138   size_t i;
139   struct design_matrix_var tmp;
140
141   for (i = 0; i < dm->n_vars; i++)
142     {
143       tmp = dm->vars[i];
144       if (tmp.v == v)
145         {
146           return tmp.last_column;
147         }
148     }
149   return DM_COLUMN_NOT_FOUND;
150 }
151
152 /*
153   Set the appropriate value in the design matrix,
154   whether that value is from a categorical or numeric
155   variable. For a categorical variable, only the usual
156   binary encoding is allowed.
157  */
158 void
159 design_matrix_set_categorical (struct design_matrix *dm, size_t row,
160                                const struct variable *var,
161                                const union value *val)
162 {
163   size_t col;
164   size_t is_one;
165   size_t fc;
166   size_t lc;
167   double entry;
168
169   assert (var_is_alpha (var));
170   fc = design_matrix_var_to_column (dm, var);
171   lc = dm_var_to_last_column (dm, var);
172   assert (lc != DM_COLUMN_NOT_FOUND);
173   assert (fc != DM_COLUMN_NOT_FOUND);
174   is_one = fc + cat_value_find (var, val);
175   for (col = fc; col <= lc; col++)
176     {
177       entry = (col == is_one) ? 1.0 : 0.0;
178       gsl_matrix_set (dm->m, row, col, entry);
179     }
180 }
181
182 void
183 design_matrix_set_numeric (struct design_matrix *dm, size_t row,
184                            const struct variable *var, const union value *val)
185 {
186   size_t col;
187
188   assert (var_is_numeric (var));
189   col = design_matrix_var_to_column ((const struct design_matrix *) dm, var);
190   assert (col != DM_COLUMN_NOT_FOUND);
191   gsl_matrix_set (dm->m, row, col, val->f);
192 }