Fixed memory leak. Made coeff a linreg_coeff** for easier use.
[pspp-builds.git] / src / math / linreg / coefficient.c
1 /*
2   lib/linreg/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 <math/linreg/coefficient.h>
25 #include <math/linreg/linreg.h>
26 #include "src/math/design-matrix.h"
27
28 #include <gl/xalloc.h>
29
30
31 struct varinfo
32 {
33   const struct variable *v;     /* Variable associated with this
34                                    coefficient. Note this variable
35                                    may not be unique. In other words,
36                                    a coefficient structure may have
37                                    other v_info's, each with its own
38                                    variable. */
39   const union value *val;       /* Value of the variable v which this varinfo
40                                    refers to. This member is relevant only to
41                                    categorical variables. */
42 };
43
44 void
45 pspp_linreg_coeff_free (struct pspp_linreg_coeff *c)
46 {
47   free (c->v_info);
48   free (c);
49 }
50
51 /*
52   Initialize the variable and value pointers inside the
53   coefficient structures for the linear model.
54  */
55 void
56 pspp_linreg_coeff_init (pspp_linreg_cache * c, struct design_matrix *X)
57 {
58   size_t i;
59   size_t j;
60   int n_vals = 1;
61   struct pspp_linreg_coeff *coeff;
62
63   c->coeff = xnmalloc (X->m->size2 + 1, sizeof (*c->coeff));
64   c->coeff[0] = xmalloc (sizeof (*c->coeff[0]));
65   c->coeff[0]->v_info = NULL;   /* Intercept has no associated variable. */
66   for (i = 0; i < X->m->size2; i++)
67     {
68       j = i + 1;                /* The first coefficient is the intercept. */
69       c->coeff[j] = xmalloc (sizeof (*c->coeff[j]));
70       coeff = c->coeff[j];
71       coeff->n_vars = n_vals;   /* Currently, no procedures allow
72                                    interactions.  This line will have to
73                                    change when procedures that allow
74                                    interaction terms are written. 
75                                  */
76       coeff->v_info = xnmalloc (coeff->n_vars, sizeof (*coeff->v_info));
77       assert (coeff->v_info != NULL);
78       coeff->v_info->v =
79         (const struct variable *) design_matrix_col_to_var (X, i);
80
81       if (coeff->v_info->v->type == ALPHA)
82         {
83           size_t k;
84           k = design_matrix_var_to_column (X, coeff->v_info->v);
85           assert (k <= i);
86           k = i - k;
87           coeff->v_info->val =
88             cat_subscript_to_value (k, (struct variable *) coeff->v_info->v);
89         }
90     }
91 }
92 void
93 pspp_linreg_coeff_set_estimate (struct pspp_linreg_coeff *c, double estimate)
94 {
95   c->estimate = estimate;
96 }
97
98 void
99 pspp_linreg_coeff_set_std_err (struct pspp_linreg_coeff *c, double std_err)
100 {
101   c->std_err = std_err;
102 }
103
104 /*
105   Return the estimated value of the coefficient.
106  */
107 double
108 pspp_linreg_coeff_get_est (const struct pspp_linreg_coeff *c)
109 {
110   if (c == NULL)
111     {
112       return 0.0;
113     }
114   return c->estimate;
115 }
116
117 /*
118   Return the standard error of the estimated coefficient.
119 */
120 double
121 pspp_linreg_coeff_get_std_err (const struct pspp_linreg_coeff *c)
122 {
123   if (c == NULL)
124     {
125       return 0.0;
126     }
127   return c->std_err;
128 }
129
130 /*
131   How many variables are associated with this coefficient?
132  */
133 int
134 pspp_linreg_coeff_get_n_vars (struct pspp_linreg_coeff *c)
135 {
136   if (c == NULL)
137     {
138       return 0;
139     }
140   return c->n_vars;
141 }
142
143 /*
144   Which variable does this coefficient match? I should be
145   0 unless the coefficient refers to an interaction term.
146  */
147 const struct variable *
148 pspp_linreg_coeff_get_var (struct pspp_linreg_coeff *c, int i)
149 {
150   if (c == NULL)
151     {
152       return NULL;
153     }
154   assert (i < c->n_vars);
155   return (c->v_info + i)->v;
156 }
157
158 /*
159   Which value is associated with this coefficient/variable combination?
160  */
161 const union value *
162 pspp_linreg_coeff_get_value (struct pspp_linreg_coeff *c,
163                              const struct variable *v)
164 {
165   int i = 0;
166   const struct variable *candidate;
167
168   if (c == NULL || v == NULL)
169     {
170       return NULL;
171     }
172   if (v->type == NUMERIC)
173     {
174       return NULL;
175     }
176   while (i < c->n_vars)
177     {
178       candidate = pspp_linreg_coeff_get_var (c, i);
179       if (v->index == candidate->index)
180         {
181           return (c->v_info + i)->val;
182         }
183       i++;
184     }
185   return NULL;
186 }
187
188 /*
189   Which coefficient is associated with V? The VAL argument is relevant
190   only to categorical variables.
191  */
192 const struct pspp_linreg_coeff *
193 pspp_linreg_get_coeff (const pspp_linreg_cache * c,
194                        const struct variable *v, const union value *val)
195 {
196   int i = 1;
197   struct pspp_linreg_coeff *result = NULL;
198   const struct variable *tmp = NULL;
199
200   if (c == NULL)
201     {
202       return NULL;
203     }
204   if (c->coeff == NULL || c->n_indeps == 0 || v == NULL)
205     {
206       return NULL;
207     }
208
209   result = c->coeff[i];
210   tmp = pspp_linreg_coeff_get_var (result, 0);
211   while (tmp->index != v->index && i < c->n_coeffs)
212     {
213       result = c->coeff[i];
214       tmp = pspp_linreg_coeff_get_var (result, 0);
215       i++;
216     }
217   if (i > c->n_coeffs)
218     {
219       return NULL;
220     }
221   if (v->type == NUMERIC)
222     {
223       return result;
224     }
225   else if (val != NULL)
226     {
227       /*
228          If v is categorical, we need to ensure the coefficient
229          matches the VAL.
230        */
231       while (tmp->index != v->index && i < c->n_coeffs
232              && compare_values (pspp_linreg_coeff_get_value (result, tmp),
233                                 val, v->width))
234         {                       /* FIX THIS */
235           i++;
236           result = c->coeff[i];
237           tmp = pspp_linreg_coeff_get_var (result, 0);
238         }
239       if (i == c->n_coeffs)
240         {
241           return NULL;
242         }
243       return result;
244     }
245   return NULL;
246 }