1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2009 Free Software Foundation, Inc.
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.
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.
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/>. */
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.
28 When using these functions, make sure the orders of variables and
29 values match when appropriate.
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>
42 struct interaction_variable
45 const struct variable **members;
46 struct variable *intr;
50 struct interaction_value
52 const struct interaction_variable *intr;
53 union value *val; /* Concatenation of the string values in this
54 interaction's value, or the product of a bunch
55 of numeric values for a purely numeric
58 double f; /* Product of the numerical values in this interaction's value. */
62 An interaction_variable has type alpha if any of members have type
63 alpha. Otherwise, its type is numeric.
65 struct interaction_variable *
66 interaction_variable_create (const struct variable **vars, int n_vars)
68 struct interaction_variable *result = NULL;
73 result = xmalloc (sizeof (*result));
75 result->members = xnmalloc (n_vars, sizeof (*result->members));
76 result->intr = var_create_internal (0);
77 result->n_vars = n_vars;
78 for (i = 0; i < n_vars; i++)
80 result->members[i] = vars[i];
81 if (var_is_alpha (vars[i]))
88 VAR_SET_WIDTH sets the type of the variable.
90 var_set_width (result->intr, MAX_SHORT_STRING * result->n_alpha + 1);
94 void interaction_variable_destroy (struct interaction_variable *iv)
96 var_destroy (iv->intr);
102 Get one of the member variables.
104 const struct variable *
105 interaction_variable_get_member (const struct interaction_variable *iv, size_t i)
107 return iv->members[i];
111 interaction_get_n_vars (const struct interaction_variable *iv)
113 return (iv == NULL) ? 0 : iv->n_vars;
117 interaction_get_n_alpha (const struct interaction_variable *iv)
123 interaction_get_n_numeric (const struct interaction_variable *iv)
125 return (interaction_get_n_vars (iv) - interaction_get_n_alpha (iv));
129 Get the interaction varibale itself.
131 const struct variable *
132 interaction_variable_get_var (const struct interaction_variable *iv)
137 Given list of values, compute the value of the corresponding
138 interaction. This "value" is not stored as the typical vector of
139 0's and one double, but rather the string values are concatenated to
140 make one big string value, and the numerical values are multiplied
141 together to give the non-zero entry of the corresponding vector.
143 struct interaction_value *
144 interaction_value_create (const struct interaction_variable *var, const union value **vals)
146 struct interaction_value *result = NULL;
147 const struct variable *member;
153 result = xmalloc (sizeof (*result));
155 n_vars = interaction_get_n_vars (var);
156 result->val = value_create (n_vars * MAX_SHORT_STRING + 1);
158 for (i = 0; i < n_vars; i++)
160 member = interaction_variable_get_member (var, i);
162 if (var_is_value_missing (member, vals[i], MV_ANY))
164 value_set_missing (result->val, MAX_SHORT_STRING);
170 if (var_is_alpha (var->members[i]))
172 strncat (result->val->s, vals[i]->s, MAX_SHORT_STRING);
174 else if (var_is_numeric (var->members[i]))
176 result->f *= vals[i]->f;
180 if (interaction_get_n_alpha (var) == 0)
183 If there are no categorical variables, then the
184 interaction consists of only numeric data. In this case,
185 code that uses this interaction_value will see the union
186 member as the numeric value. If we were to store that
187 numeric value in result->f as well, the calling code may
188 inadvertently square this value by multiplying by
189 result->val->f. Such multiplication would be correct for an
190 interaction consisting of both categorical and numeric
191 data, but a mistake for purely numerical interactions. To
192 avoid the error, we set result->f to 1.0 for numeric
195 result->val->f = result->f;
203 interaction_value_get (const struct interaction_value *val)
209 Returns the numeric value of the non-zero entry for the vector
210 corresponding to this interaction. Do not use this function to get
211 the numeric value of a purley numeric interaction. Instead, use the
212 union value * returned by interaction_value_get.
215 interaction_value_get_nonzero_entry (const struct interaction_value *val)
223 interaction_value_destroy (struct interaction_value *val)
233 Return a value from a variable that is an interaction.
235 struct interaction_value *
236 interaction_case_data (const struct ccase *ccase, const struct variable *var,
237 const struct interaction_variable **intr_vars, size_t n_intr)
241 const struct interaction_variable *iv;
242 const struct variable *intr;
243 const struct variable *member;
244 const union value **vals = NULL;
246 for (i = 0; i < n_intr; i++)
249 intr = interaction_variable_get_var (iv);
250 if (var_get_dict_index (intr) == var_get_dict_index (var))
255 n_vars = interaction_get_n_vars (iv);
256 vals = xnmalloc (n_vars, sizeof (*vals));
257 for (i = 0; i < n_vars; i++)
259 member = interaction_variable_get_member (iv, i);
260 vals[i] = case_data (ccase, member);
262 return interaction_value_create (iv, vals);
266 is_interaction (const struct variable *var, const struct interaction_variable **iv, size_t n_intr)
269 const struct variable *intr;
271 for (i = 0; i < n_intr; i++)
273 intr = interaction_variable_get_var (iv[i]);
274 if (var_get_dict_index (intr) == var_get_dict_index (var))