44b7c0d3219b764b827f704a6b807c60a9adf2e0
[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   for (i = 0; i < X->m->size2; i++)
59     {
60       c[i] = xmalloc (sizeof (*c[i]));
61       c[i]->n_vars = n_vals;    /* Currently, no procedures allow
62                                    interactions.  This line will have to
63                                    change when procedures that allow
64                                    interaction terms are written.
65                                  */
66       c[i]->v_info = xnmalloc (c[i]->n_vars, sizeof (*c[i]->v_info));
67       assert (c[i]->v_info != NULL);
68       c[i]->v_info->v = design_matrix_col_to_var (X, i);
69
70       if (var_is_alpha (c[i]->v_info->v))
71         {
72           size_t k;
73           k = design_matrix_var_to_column (X, c[i]->v_info->v);
74           assert (k <= i);
75           k = i - k;
76           c[i]->v_info->val =
77             cat_subscript_to_value (k, c[i]->v_info->v);
78         }
79     }
80 }
81 void
82 pspp_coeff_set_estimate (struct pspp_coeff *c, double estimate)
83 {
84   c->estimate = estimate;
85 }
86
87 void
88 pspp_coeff_set_std_err (struct pspp_coeff *c, double std_err)
89 {
90   c->std_err = std_err;
91 }
92
93 /*
94   Return the estimated value of the coefficient.
95  */
96 double
97 pspp_coeff_get_est (const struct pspp_coeff *c)
98 {
99   if (c == NULL)
100     {
101       return 0.0;
102     }
103   return c->estimate;
104 }
105
106 /*
107   Return the standard error of the estimated coefficient.
108 */
109 double
110 pspp_coeff_get_std_err (const struct pspp_coeff *c)
111 {
112   if (c == NULL)
113     {
114       return 0.0;
115     }
116   return c->std_err;
117 }
118
119 /*
120   How many variables are associated with this coefficient?
121  */
122 int
123 pspp_coeff_get_n_vars (struct pspp_coeff *c)
124 {
125   if (c == NULL)
126     {
127       return 0;
128     }
129   return c->n_vars;
130 }
131
132 /*
133   Which variable does this coefficient match? I should be
134   0 unless the coefficient refers to an interaction term.
135  */
136 const struct variable *
137 pspp_coeff_get_var (struct pspp_coeff *c, int i)
138 {
139   if (c == NULL)
140     {
141       return NULL;
142     }
143   assert (i < c->n_vars);
144   return (c->v_info + i)->v;
145 }
146
147 /*
148   Which value is associated with this coefficient/variable combination?
149  */
150 const union value *
151 pspp_coeff_get_value (struct pspp_coeff *c,
152                              const struct variable *v)
153 {
154   int i = 0;
155   const struct variable *candidate;
156
157   if (c == NULL || v == NULL)
158     {
159       return NULL;
160     }
161   if (var_is_numeric (v))
162     {
163       return NULL;
164     }
165   while (i < c->n_vars)
166     {
167       candidate = pspp_coeff_get_var (c, i);
168       if (v == candidate)
169         {
170           return (c->v_info + i)->val;
171         }
172       i++;
173     }
174   return NULL;
175 }
176
177 /*
178   Which coefficient is associated with V? The VAL argument is relevant
179   only to categorical variables.
180  */
181 const struct pspp_coeff *
182 pspp_linreg_get_coeff (const pspp_linreg_cache * c,
183                        const struct variable *v, const union value *val)
184 {
185   int i = 1;
186   struct pspp_coeff *result = NULL;
187   const struct variable *tmp = NULL;
188
189   if (c == NULL)
190     {
191       return NULL;
192     }
193   if (c->coeff == NULL || c->n_indeps == 0 || v == NULL)
194     {
195       return NULL;
196     }
197
198   result = c->coeff[i];
199   tmp = pspp_coeff_get_var (result, 0);
200   while (tmp != v && i < c->n_coeffs)
201     {
202       result = c->coeff[i];
203       tmp = pspp_coeff_get_var (result, 0);
204       i++;
205     }
206   if (i > c->n_coeffs)
207     {
208       return NULL;
209     }
210   if (var_is_numeric (v))
211     {
212       return result;
213     }
214   else if (val != NULL)
215     {
216       /*
217          If v is categorical, we need to ensure the coefficient
218          matches the VAL.
219        */
220       while (tmp != v && i < c->n_coeffs
221              && compare_values (pspp_coeff_get_value (result, tmp),
222                                 val, var_get_width (v)))
223         {                       /* FIX THIS */
224           i++;
225           result = c->coeff[i];
226           tmp = pspp_coeff_get_var (result, 0);
227         }
228       if (i == c->n_coeffs)
229         {
230           return NULL;
231         }
232       return result;
233     }
234   return NULL;
235 }