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