Make the missing value code do more work, so that its callers can do
[pspp-builds.git] / src / math / coefficient.c
1 /*
2   src/math/coefficient.c
3   
4   Copyright (C) 2005 Free Software Foundation, Inc. Written by Jason H Stover.
5   
6   This program is free software; you can redistribute it and/or modify it under
7   the terms of the GNU General Public License as published by the Free
8   Software Foundation; either version 2 of the License, or (at your option)
9   any later version.
10   
11   This program is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14   more details.
15   
16   You should have received a copy of the GNU General Public License along with
17   this program; if not, write to the Free Software Foundation, Inc., 51
18   Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
19 */
20
21 /*
22   Accessor functions for matching coefficients and variables.
23  */
24 #include <config.h>
25 #include <math/coefficient.h>
26 #include <math/linreg/linreg.h>
27 #include "src/math/design-matrix.h"
28
29 #include <gl/xalloc.h>
30
31
32 struct varinfo
33 {
34   const struct variable *v;     /* Variable associated with this
35                                    coefficient. Note this variable
36                                    may not be unique. In other words,
37                                    a coefficient structure may have
38                                    other v_info's, each with its own
39                                    variable. */
40   const union value *val;       /* Value of the variable v which this varinfo
41                                    refers to. This member is relevant only to
42                                    categorical variables. */
43 };
44
45 void
46 pspp_coeff_free (struct pspp_coeff *c)
47 {
48   free (c->v_info);
49   free (c);
50 }
51
52 /*
53   Initialize the variable and value pointers inside the
54   coefficient structures for the linear model.
55  */
56 void
57 pspp_coeff_init (struct pspp_coeff ** c, const struct design_matrix *X)
58 {
59   size_t i;
60   int n_vals = 1;
61
62   for (i = 0; i < X->m->size2; i++)
63     {
64       c[i] = xmalloc (sizeof (*c[i]));
65       c[i]->n_vars = n_vals;    /* Currently, no procedures allow
66                                    interactions.  This line will have to
67                                    change when procedures that allow
68                                    interaction terms are written. 
69                                  */
70       c[i]->v_info = xnmalloc (c[i]->n_vars, sizeof (*c[i]->v_info));
71       assert (c[i]->v_info != NULL);
72       c[i]->v_info->v =
73         (const struct variable *) design_matrix_col_to_var (X, i);
74
75       if (var_is_alpha (c[i]->v_info->v))
76         {
77           size_t k;
78           k = design_matrix_var_to_column (X, c[i]->v_info->v);
79           assert (k <= i);
80           k = i - k;
81           c[i]->v_info->val =
82             cat_subscript_to_value (k, (struct variable *) c[i]->v_info->v);
83         }
84     }
85 }
86 void
87 pspp_coeff_set_estimate (struct pspp_coeff *c, double estimate)
88 {
89   c->estimate = estimate;
90 }
91
92 void
93 pspp_coeff_set_std_err (struct pspp_coeff *c, double std_err)
94 {
95   c->std_err = std_err;
96 }
97
98 /*
99   Return the estimated value of the coefficient.
100  */
101 double
102 pspp_coeff_get_est (const struct pspp_coeff *c)
103 {
104   if (c == NULL)
105     {
106       return 0.0;
107     }
108   return c->estimate;
109 }
110
111 /*
112   Return the standard error of the estimated coefficient.
113 */
114 double
115 pspp_coeff_get_std_err (const struct pspp_coeff *c)
116 {
117   if (c == NULL)
118     {
119       return 0.0;
120     }
121   return c->std_err;
122 }
123
124 /*
125   How many variables are associated with this coefficient?
126  */
127 int
128 pspp_coeff_get_n_vars (struct pspp_coeff *c)
129 {
130   if (c == NULL)
131     {
132       return 0;
133     }
134   return c->n_vars;
135 }
136
137 /*
138   Which variable does this coefficient match? I should be
139   0 unless the coefficient refers to an interaction term.
140  */
141 const struct variable *
142 pspp_coeff_get_var (struct pspp_coeff *c, int i)
143 {
144   if (c == NULL)
145     {
146       return NULL;
147     }
148   assert (i < c->n_vars);
149   return (c->v_info + i)->v;
150 }
151
152 /*
153   Which value is associated with this coefficient/variable combination?
154  */
155 const union value *
156 pspp_coeff_get_value (struct pspp_coeff *c,
157                              const struct variable *v)
158 {
159   int i = 0;
160   const struct variable *candidate;
161
162   if (c == NULL || v == NULL)
163     {
164       return NULL;
165     }
166   if (var_is_numeric (v))
167     {
168       return NULL;
169     }
170   while (i < c->n_vars)
171     {
172       candidate = pspp_coeff_get_var (c, i);
173       if (v == candidate)
174         {
175           return (c->v_info + i)->val;
176         }
177       i++;
178     }
179   return NULL;
180 }
181
182 /*
183   Which coefficient is associated with V? The VAL argument is relevant
184   only to categorical variables.
185  */
186 const struct pspp_coeff *
187 pspp_linreg_get_coeff (const pspp_linreg_cache * c,
188                        const struct variable *v, const union value *val)
189 {
190   int i = 1;
191   struct pspp_coeff *result = NULL;
192   const struct variable *tmp = NULL;
193
194   if (c == NULL)
195     {
196       return NULL;
197     }
198   if (c->coeff == NULL || c->n_indeps == 0 || v == NULL)
199     {
200       return NULL;
201     }
202
203   result = c->coeff[i];
204   tmp = pspp_coeff_get_var (result, 0);
205   while (tmp != v && i < c->n_coeffs)
206     {
207       result = c->coeff[i];
208       tmp = pspp_coeff_get_var (result, 0);
209       i++;
210     }
211   if (i > c->n_coeffs)
212     {
213       return NULL;
214     }
215   if (var_is_numeric (v))
216     {
217       return result;
218     }
219   else if (val != NULL)
220     {
221       /*
222          If v is categorical, we need to ensure the coefficient
223          matches the VAL.
224        */
225       while (tmp != v && i < c->n_coeffs
226              && compare_values (pspp_coeff_get_value (result, tmp),
227                                 val, var_get_width (v)))
228         {                       /* FIX THIS */
229           i++;
230           result = c->coeff[i];
231           tmp = pspp_coeff_get_var (result, 0);
232         }
233       if (i == c->n_coeffs)
234         {
235           return NULL;
236         }
237       return result;
238     }
239   return NULL;
240 }