1868bda4aa6ceb30b85a4b77191c70c4fc83f6f7
[pspp-builds.git] / src / math / coefficient.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   Accessor functions for matching coefficients and variables.
19  */
20 #include <config.h>
21 #include <math/coefficient.h>
22 #include <math/linreg/linreg.h>
23 #include "src/math/design-matrix.h"
24
25 #include <gl/xalloc.h>
26
27
28 struct varinfo
29 {
30   const struct variable *v;     /* Variable associated with this
31                                    coefficient. Note this variable
32                                    may not be unique. In other words,
33                                    a coefficient structure may have
34                                    other v_info's, each with its own
35                                    variable. */
36   const union value *val;       /* Value of the variable v which this varinfo
37                                    refers to. This member is relevant only to
38                                    categorical variables. */
39 };
40
41 void
42 pspp_coeff_free (struct pspp_coeff *c)
43 {
44   free (c->v_info);
45   free (c);
46 }
47
48 /*
49   Initialize the variable and value pointers inside the
50   coefficient structures for the linear model.
51  */
52 void
53 pspp_coeff_init (struct pspp_coeff ** c, const struct design_matrix *X)
54 {
55   size_t i;
56   int n_vals = 1;
57
58   assert (c != NULL);
59   for (i = 0; i < X->m->size2; i++)
60     {
61       c[i] = xmalloc (sizeof (*c[i]));
62       c[i]->n_vars = n_vals;    /* Currently, no procedures allow
63                                    interactions.  This line will have to
64                                    change when procedures that allow
65                                    interaction terms are written.
66                                  */
67       c[i]->v_info = xnmalloc (c[i]->n_vars, sizeof (*c[i]->v_info));
68       assert (c[i]->v_info != NULL);
69       c[i]->v_info->v = design_matrix_col_to_var (X, i);
70
71       if (var_is_alpha (c[i]->v_info->v))
72         {
73           size_t k;
74           k = design_matrix_var_to_column (X, c[i]->v_info->v);
75           assert (k <= i);
76           k = i - k;
77           c[i]->v_info->val =
78             cat_subscript_to_value (k, c[i]->v_info->v);
79         }
80     }
81 }
82 void
83 pspp_coeff_set_estimate (struct pspp_coeff *c, double estimate)
84 {
85   c->estimate = estimate;
86 }
87
88 void
89 pspp_coeff_set_std_err (struct pspp_coeff *c, double std_err)
90 {
91   c->std_err = std_err;
92 }
93
94 /*
95   Return the estimated value of the coefficient.
96  */
97 double
98 pspp_coeff_get_est (const struct pspp_coeff *c)
99 {
100   if (c == NULL)
101     {
102       return 0.0;
103     }
104   return c->estimate;
105 }
106
107 /*
108   Return the standard error of the estimated coefficient.
109 */
110 double
111 pspp_coeff_get_std_err (const struct pspp_coeff *c)
112 {
113   if (c == NULL)
114     {
115       return 0.0;
116     }
117   return c->std_err;
118 }
119
120 /*
121   How many variables are associated with this coefficient?
122  */
123 int
124 pspp_coeff_get_n_vars (struct pspp_coeff *c)
125 {
126   if (c == NULL)
127     {
128       return 0;
129     }
130   return c->n_vars;
131 }
132
133 /*
134   Which variable does this coefficient match? I should be
135   0 unless the coefficient refers to an interaction term.
136  */
137 const struct variable *
138 pspp_coeff_get_var (struct pspp_coeff *c, int i)
139 {
140   if (c == NULL)
141     {
142       return NULL;
143     }
144   assert (i < c->n_vars);
145   return (c->v_info + i)->v;
146 }
147
148 /*
149   Which value is associated with this coefficient/variable combination?
150  */
151 const union value *
152 pspp_coeff_get_value (struct pspp_coeff *c,
153                              const struct variable *v)
154 {
155   int i = 0;
156   const struct variable *candidate;
157
158   if (c == NULL || v == NULL)
159     {
160       return NULL;
161     }
162   if (var_is_numeric (v))
163     {
164       return NULL;
165     }
166   while (i < c->n_vars)
167     {
168       candidate = pspp_coeff_get_var (c, i);
169       if (v == candidate)
170         {
171           return (c->v_info + i)->val;
172         }
173       i++;
174     }
175   return NULL;
176 }
177
178 /*
179   Which coefficient is associated with V? The VAL argument is relevant
180   only to categorical variables.
181  */
182 const struct pspp_coeff *
183 pspp_linreg_get_coeff (const pspp_linreg_cache * c,
184                        const struct variable *v, const union value *val)
185 {
186   int i;
187   struct pspp_coeff *result = NULL;
188   const struct variable *tmp = NULL;
189
190   if (c == NULL)
191     {
192       return NULL;
193     }
194   if (c->coeff == NULL || c->n_indeps == 0 || v == NULL)
195     {
196       return NULL;
197     }
198   /*
199     C->N_COEFFS == 1 means regression through the origin.
200    */
201   i = (c->n_coeffs > 1) ? 1 : 0;
202   result = c->coeff[i];
203   tmp = pspp_coeff_get_var (result, 0);
204   while (tmp != v && 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 (var_is_numeric (v))
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 != v && i < c->n_coeffs
225              && compare_values (pspp_coeff_get_value (result, tmp),
226                                 val, var_get_width (v)))
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 }