Fix bug 22419
[pspp-builds.git] / src / math / linreg / predict.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 #include <config.h>
18 #include <math/linreg/linreg.h>
19 #include <math/coefficient.h>
20 #include <gl/xalloc.h>
21
22 /*
23   Is the coefficient COEF contained in the list of coefficients
24   COEF_LIST?
25  */
26 static int
27 has_coefficient (const struct pspp_coeff **coef_list, const struct pspp_coeff *coef,
28                  size_t n)
29 {
30   size_t i = 0;
31
32   while (i < n)
33     {
34       if (coef_list[i] == coef)
35         {
36           return 1;
37         }
38       i++;
39     }
40   return 0;
41 }
42 /*
43   Predict the value of the dependent variable with the
44   new set of predictors. PREDICTORS must point to a list
45   of variables, each of whose values are stored in VALS,
46   in the same order.
47  */
48 double
49 pspp_linreg_predict (const struct variable **predictors,
50                      const union value **vals, const void *c_, int n_vals)
51 {
52   const pspp_linreg_cache *c = c_;
53   int j;
54   size_t next_coef = 1;
55   const struct pspp_coeff **coef_list;
56   const struct pspp_coeff *coe;
57   double result;
58   double tmp;
59
60   if (predictors == NULL || vals == NULL || c == NULL)
61     {
62       return GSL_NAN;
63     }
64   if (c->coeff == NULL)
65     {
66       /* The stupid model: just guess the mean. */
67       return c->depvar_mean;
68     }
69   coef_list = xnmalloc (c->n_coeffs, sizeof (*coef_list));
70   *coef_list = c->coeff[0];
71   result = c->coeff[0]->estimate;       /* Intercept. */
72
73   /*
74      The loops guard against the possibility that the caller passed us
75      inadequate information, such as too few or too many values, or
76      a redundant list of variable names.
77    */
78   for (j = 0; j < n_vals; j++)
79     {
80       coe = pspp_linreg_get_coeff (c, predictors[j], vals[j]);
81       if (!has_coefficient (coef_list, coe, next_coef))
82         {
83           tmp = pspp_coeff_get_est (coe);
84           if (var_is_numeric (predictors[j]))
85             {
86               tmp *= vals[j]->f;
87             }
88           result += tmp;
89           coef_list[next_coef++] = coe;
90         }
91     }
92   free (coef_list);
93
94   return result;
95 }
96
97 double
98 pspp_linreg_residual (const struct variable **predictors,
99                       const union value **vals,
100                       const union value *obs, const void *c, int n_vals)
101 {
102   double pred;
103   double result;
104
105   if (predictors == NULL || vals == NULL || c == NULL || obs == NULL)
106     {
107       return GSL_NAN;
108     }
109   pred = pspp_linreg_predict (predictors, vals, c, n_vals);
110
111   result = gsl_isnan (pred) ? GSL_NAN : (obs->f - pred);
112   return result;
113 }