moved knowledge of pspp_linreg_cache out of pspp_coeff_init
[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 <math/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_coeff_free (struct pspp_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_coeff_init (struct pspp_coeff ** c, struct design_matrix *X)
57 {
58   size_t i;
59   int n_vals = 1;
60
61   for (i = 0; i < X->m->size2; i++)
62     {
63       c[i] = xmalloc (sizeof (*c[i]));
64       c[i]->n_vars = n_vals;    /* Currently, no procedures allow
65                                    interactions.  This line will have to
66                                    change when procedures that allow
67                                    interaction terms are written. 
68                                  */
69       c[i]->v_info = xnmalloc (c[i]->n_vars, sizeof (*c[i]->v_info));
70       assert (c[i]->v_info != NULL);
71       c[i]->v_info->v =
72         (const struct variable *) design_matrix_col_to_var (X, i);
73
74       if (c[i]->v_info->v->type == ALPHA)
75         {
76           size_t k;
77           k = design_matrix_var_to_column (X, c[i]->v_info->v);
78           assert (k <= i);
79           k = i - k;
80           c[i]->v_info->val =
81             cat_subscript_to_value (k, (struct variable *) c[i]->v_info->v);
82         }
83     }
84 }
85 void
86 pspp_coeff_set_estimate (struct pspp_coeff *c, double estimate)
87 {
88   c->estimate = estimate;
89 }
90
91 void
92 pspp_coeff_set_std_err (struct pspp_coeff *c, double std_err)
93 {
94   c->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 *c)
102 {
103   if (c == NULL)
104     {
105       return 0.0;
106     }
107   return c->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 *c)
115 {
116   if (c == NULL)
117     {
118       return 0.0;
119     }
120   return c->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 *c)
128 {
129   if (c == NULL)
130     {
131       return 0;
132     }
133   return c->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 *c, int i)
142 {
143   if (c == NULL)
144     {
145       return NULL;
146     }
147   assert (i < c->n_vars);
148   return (c->v_info + i)->v;
149 }
150
151 /*
152   Which value is associated with this coefficient/variable combination?
153  */
154 const union value *
155 pspp_coeff_get_value (struct pspp_coeff *c,
156                              const struct variable *v)
157 {
158   int i = 0;
159   const struct variable *candidate;
160
161   if (c == NULL || v == NULL)
162     {
163       return NULL;
164     }
165   if (v->type == NUMERIC)
166     {
167       return NULL;
168     }
169   while (i < c->n_vars)
170     {
171       candidate = pspp_coeff_get_var (c, i);
172       if (v->index == candidate->index)
173         {
174           return (c->v_info + i)->val;
175         }
176       i++;
177     }
178   return NULL;
179 }
180
181 /*
182   Which coefficient is associated with V? The VAL argument is relevant
183   only to categorical variables.
184  */
185 const struct pspp_coeff *
186 pspp_linreg_get_coeff (const pspp_linreg_cache * c,
187                        const struct variable *v, const union value *val)
188 {
189   int i = 1;
190   struct pspp_coeff *result = NULL;
191   const struct variable *tmp = NULL;
192
193   if (c == NULL)
194     {
195       return NULL;
196     }
197   if (c->coeff == NULL || c->n_indeps == 0 || v == NULL)
198     {
199       return NULL;
200     }
201
202   result = c->coeff[i];
203   tmp = pspp_coeff_get_var (result, 0);
204   while (tmp->index != v->index && i < c->n_coeffs)
205     {
206       result = c->coeff[i];
207       tmp = pspp_coeff_get_var (result, 0);
208       i++;
209     }
210   if (i > c->n_coeffs)
211     {
212       return NULL;
213     }
214   if (v->type == NUMERIC)
215     {
216       return result;
217     }
218   else if (val != NULL)
219     {
220       /*
221          If v is categorical, we need to ensure the coefficient
222          matches the VAL.
223        */
224       while (tmp->index != v->index && i < c->n_coeffs
225              && compare_values (pspp_coeff_get_value (result, tmp),
226                                 val, v->width))
227         {                       /* FIX THIS */
228           i++;
229           result = c->coeff[i];
230           tmp = pspp_coeff_get_var (result, 0);
231         }
232       if (i == c->n_coeffs)
233         {
234           return NULL;
235         }
236       return result;
237     }
238   return NULL;
239 }