Fix crash when opening empty dataset
[pspp-builds.git] / src / math / coefficient.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2005, 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 /*
18   Accessor functions for matching coefficients and variables.
19  */
20 #include <config.h>
21 #include <math/coefficient.h>
22 #include "src/math/design-matrix.h"
23
24 #include <gl/xalloc.h>
25
26
27 struct varinfo
28 {
29   const struct variable *v;     /* Variable associated with this
30                                    coefficient. Note this variable
31                                    may not be unique. In other words,
32                                    a coefficient structure may have
33                                    other v_info's, each with its own
34                                    variable. */
35   const union value *val;       /* Value of the variable v which this varinfo
36                                    refers to. This member is relevant only to
37                                    categorical variables. */
38   double mean; /* Mean for this variable */
39   double sd; /* Standard deviation for this variable */
40 };
41
42 void
43 pspp_coeff_free (struct pspp_coeff *c)
44 {
45   free (c->v_info);
46   free (c);
47 }
48
49 /*
50   Initialize the variable and value pointers inside the
51   coefficient structures for the model.
52  */
53 void
54 pspp_coeff_init (struct pspp_coeff ** coeff, const struct design_matrix *X)
55 {
56   size_t i;
57   int n_vals = 1;
58
59   assert (coeff != NULL);
60   for (i = 0; i < X->m->size2; i++)
61     {
62       coeff[i] = xmalloc (sizeof (*coeff[i]));
63       coeff[i]->n_vars = n_vals;        /* Currently, no procedures allow
64                                            interactions.  This line will have to
65                                            change when procedures that allow
66                                            interaction terms are written.
67                                         */
68       coeff[i]->v_info = xnmalloc (coeff[i]->n_vars, sizeof (*coeff[i]->v_info));
69       assert (coeff[i]->v_info != NULL);
70       coeff[i]->v_info->v = design_matrix_col_to_var (X, i);
71       
72       if (var_is_alpha (coeff[i]->v_info->v))
73         {
74           size_t k;
75           k = design_matrix_var_to_column (X, coeff[i]->v_info->v);
76           assert (k <= i);
77           k = i - k;
78           coeff[i]->v_info->val =
79             cat_subscript_to_value (k, coeff[i]->v_info->v);
80         }
81       coeff[i]->v_info->mean = 0.0;
82       coeff[i]->v_info->sd = 0.0;
83     }
84 }
85 void
86 pspp_coeff_set_estimate (struct pspp_coeff *coef, double estimate)
87 {
88   coef->estimate = estimate;
89 }
90
91 void
92 pspp_coeff_set_std_err (struct pspp_coeff *coef, double std_err)
93 {
94   coef->std_err = std_err;
95 }
96
97 /*
98   Return the estimated value of the coefficient.
99  */
100 double
101 pspp_coeff_get_est (const struct pspp_coeff *coef)
102 {
103   if (coef == NULL)
104     {
105       return 0.0;
106     }
107   return coef->estimate;
108 }
109
110 /*
111   Return the standard error of the estimated coefficient.
112 */
113 double
114 pspp_coeff_get_std_err (const struct pspp_coeff *coef)
115 {
116   if (coef == NULL)
117     {
118       return 0.0;
119     }
120   return coef->std_err;
121 }
122
123 /*
124   How many variables are associated with this coefficient?
125  */
126 int
127 pspp_coeff_get_n_vars (struct pspp_coeff *coef)
128 {
129   if (coef == NULL)
130     {
131       return 0;
132     }
133   return coef->n_vars;
134 }
135
136 /*
137   Which variable does this coefficient match? I should be
138   0 unless the coefficient refers to an interaction term.
139  */
140 const struct variable *
141 pspp_coeff_get_var (struct pspp_coeff *coef, int i)
142 {
143   if (coef == NULL)
144     {
145       return NULL;
146     }
147   assert (i < coef->n_vars);
148   return (coef->v_info + i)->v;
149 }
150
151 /*
152   Which coefficient does this variable match? If the variable is
153   categorical, and has more than one coefficient, use the VAL to find
154   its coefficient.
155  */
156 struct pspp_coeff *
157 pspp_coeff_var_to_coeff (const struct variable *v, struct pspp_coeff **coefs, 
158                          size_t n_coef, const union value *val)
159 {
160   size_t i = 0;
161   size_t j = 0;
162   size_t v_idx;
163
164   struct pspp_coeff *result = NULL;
165
166   if (v != NULL)
167     {
168       v_idx = var_get_dict_index (v);
169       while (i < n_coef)
170         {
171           if (coefs[i]->v_info != NULL)
172             {
173               if (var_get_dict_index (coefs[i]->v_info->v) == v_idx)
174                 {
175                   break;
176                 }
177             }
178           i++;
179         }
180       result = coefs[i];
181       if (var_is_alpha (v))
182         {
183           /*
184             Use the VAL to find the coefficient.
185            */
186           if (val != NULL)
187             {
188               int width = var_get_width (v);
189
190               j = i;
191               while (j < n_coef
192                      && value_compare_3way (pspp_coeff_get_value (coefs[j], v),
193                                             val, width) != 0)
194                 {
195                   j++;
196                 }
197               result = ((j < n_coef) ? coefs[j] : NULL);
198             }
199         }
200     }
201   return result;
202 }
203
204 /*
205   Which value is associated with this coefficient/variable combination?
206  */
207 const union value *
208 pspp_coeff_get_value (struct pspp_coeff *coef,
209                              const struct variable *v)
210 {
211   int i = 0;
212   const struct variable *candidate;
213
214   if (coef == NULL || v == NULL)
215     {
216       return NULL;
217     }
218   if (var_is_numeric (v))
219     {
220       return NULL;
221     }
222   while (i < coef->n_vars)
223     {
224       candidate = pspp_coeff_get_var (coef, i);
225       if (v == candidate)
226         {
227           return (coef->v_info + i)->val;
228         }
229       i++;
230     }
231   return NULL;
232 }
233
234 /*
235   Get or set the standard deviation of the variable associated with this coefficient.
236  */
237 double pspp_coeff_get_sd (const struct pspp_coeff *coef)
238 {
239   return coef->v_info->sd;
240 }
241 void pspp_coeff_set_sd (struct pspp_coeff *coef, double s)
242 {
243   coef->v_info->sd = s;
244 }
245
246 /*
247   Get or set the mean for the variable associated with this coefficient.
248 */
249 double pspp_coeff_get_mean (const struct pspp_coeff *coef)
250 {
251   return coef->v_info->mean;
252 }
253
254 void pspp_coeff_set_mean (struct pspp_coeff *coef, double m)
255 {
256   coef->v_info->mean = m;
257 }
258