Merge commit 'origin/stable'
[pspp-builds.git] / src / math / interaction.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2009 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   An interaction is a gsl_vector containing a "product" of other
19   variables. The variables can be either categorical or numeric.
20   If the variables are all numeric, the interaction is just the
21   scalar product. If any of the variables are categorical, their
22   product is a vector containing 0's in all but one entry. This entry
23   is found by combining the vectors corresponding to the variables'
24   OBS_VALS member. If there are K categorical variables, each with
25   N_1, N_2, ..., N_K categories, then the interaction will have
26   N_1 * N_2 * N_3 *...* N_K - 1 entries.
27
28   When using these functions, make sure the orders of variables and
29   values match when appropriate.
30  */
31
32 #include <config.h>
33 #include <assert.h>
34 #include <gsl/gsl_math.h>
35 #include <gsl/gsl_vector.h>
36 #include <data/value.h>
37 #include <data/variable.h>
38 #include <math/interaction.h>
39 #include <string.h>
40 #include <xalloc.h>
41
42 struct interaction_variable
43 {
44   int n_vars;
45   const struct variable **members;
46   struct variable *intr;
47 };
48
49 struct interaction_value
50 {
51   const struct interaction_variable *intr;
52   union value *strings; /* Concatenation of the string values in this interaction's value. */
53   double f; /* Product of the numerical values in this interaction's value. */
54 };
55
56 struct interaction_variable *
57 interaction_variable_create (const struct variable **vars, int n_vars)
58 {
59   struct interaction_variable *result = NULL;
60   size_t i;
61
62   if (n_vars > 0)
63     {
64       result = xmalloc (sizeof (*result));
65       result->members = xnmalloc (n_vars, sizeof (*result->members));
66       result->intr = var_create_internal (0);
67       result->n_vars = n_vars;
68       for (i = 0; i < n_vars; i++)
69         {
70           result->members[i] = vars[i];
71         }
72     }
73   return result;
74 }
75
76 void interaction_variable_destroy (struct interaction_variable *iv)
77 {
78   var_destroy (iv->intr);
79   free (iv->members);
80   free (iv);
81 }
82
83 size_t
84 interaction_variable_get_n_vars (const struct interaction_variable *iv)
85 {
86   return (iv == NULL) ? 0 : iv->n_vars;
87 }
88
89 /*
90   Given list of values, compute the value of the corresponding
91   interaction.  This "value" is not stored as the typical vector of
92   0's and one double, but rather the string values are concatenated to
93   make one big string value, and the numerical values are multiplied
94   together to give the non-zero entry of the corresponding vector.
95  */
96 struct interaction_value *
97 interaction_value_create (const struct interaction_variable *var, const union value **vals)
98 {
99   struct interaction_value *result = NULL;
100   size_t i;
101   size_t n_vars;
102   
103   if (var != NULL)
104     {
105       result = xmalloc (sizeof (*result));
106       result->intr = var;
107       n_vars = interaction_variable_get_n_vars (var);
108       result->strings = value_create (n_vars * MAX_SHORT_STRING + 1);
109       result->f = 1.0;
110       for (i = 0; i < n_vars; i++)
111         {
112           if (var_is_alpha (var->members[i]))
113             {
114               strncat (result->strings->s, vals[i]->s, MAX_SHORT_STRING);
115             }
116           else if (var_is_numeric (var->members[i]))
117             {
118               result->f *= vals[i]->f;
119             }
120         }
121     }
122   return result;
123 }
124
125 void 
126 interaction_value_destroy (struct interaction_value *val)
127 {
128   if (val != NULL)
129     {
130       free (val->strings);
131       free (val);
132     }
133 }
134