1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2009, 2010, 2011 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 structure 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 "math/interaction.h"
40 #include "data/dictionary.h"
41 #include "data/value.h"
42 #include "data/variable.h"
44 #include "gl/xalloc.h"
46 struct interaction_variable
49 const struct variable **members;
50 struct variable *intr;
54 struct interaction_value
56 const struct interaction_variable *intr;
57 union value val; /* Concatenation of the string values in this
58 interaction's value, or the product of a bunch
59 of numeric values for a purely numeric
62 double f; /* Product of the numerical values in this interaction's value. */
66 An interaction_variable has type alpha if any of members have type
67 alpha. Otherwise, its type is numeric.
69 struct interaction_variable *
70 interaction_variable_create (const struct variable **vars, int n_vars)
72 struct interaction_variable *result = NULL;
79 result = xmalloc (sizeof (*result));
81 result->members = xnmalloc (n_vars, sizeof (*result->members));
82 result->n_vars = n_vars;
83 for (i = 0; i < n_vars; i++)
85 result->members[i] = vars[i];
86 if (var_is_alpha (vars[i]))
89 width += var_get_width (vars[i]);
92 result->intr = dict_create_internal_var (0, width);
97 void interaction_variable_destroy (struct interaction_variable *iv)
99 dict_destroy_internal_var (iv->intr);
105 Get one of the member variables.
107 const struct variable *
108 interaction_get_member (const struct interaction_variable *iv, size_t i)
110 return iv->members[i];
114 interaction_get_n_vars (const struct interaction_variable *iv)
116 return (iv == NULL) ? 0 : iv->n_vars;
120 interaction_get_n_alpha (const struct interaction_variable *iv)
126 interaction_get_n_numeric (const struct interaction_variable *iv)
128 return (interaction_get_n_vars (iv) - interaction_get_n_alpha (iv));
132 Get the interaction variable itself.
134 const struct variable *
135 interaction_get_variable (const struct interaction_variable *iv)
140 Given list of values, compute the value of the corresponding
141 interaction. This "value" is not stored as the typical vector of
142 0's and one double, but rather the string values are concatenated to
143 make one big string value, and the numerical values are multiplied
144 together to give the non-zero entry of the corresponding vector.
146 struct interaction_value *
147 interaction_value_create (const struct interaction_variable *var, const union value **vals)
149 struct interaction_value *result = NULL;
154 int val_width = var_get_width (interaction_get_variable (var));
156 size_t n_vars = interaction_get_n_vars (var);
158 result = xmalloc (sizeof (*result));
161 value_init (&result->val, val_width);
164 for (i = 0; i < n_vars; i++)
166 const struct variable *member = interaction_get_member (var, i);
168 if (var_is_value_missing (member, vals[i], MV_ANY))
170 value_set_missing (&result->val, val_width);
176 if (var_is_alpha (var->members[i]))
178 uint8_t *val = value_str_rw (&result->val, val_width);
179 int w = var_get_width (var->members[i]);
180 u8_cpy (val + offset, value_str (vals[i], w), w);
183 else if (var_is_numeric (var->members[i]))
185 result->f *= vals[i]->f;
189 if (interaction_get_n_alpha (var) == 0)
192 If there are no categorical variables, then the
193 interaction consists of only numeric data. In this case,
194 code that uses this interaction_value will see the union
195 member as the numeric value. If we were to store that
196 numeric value in result->f as well, the calling code may
197 inadvertently square this value by multiplying by
198 result->val->f. Such multiplication would be correct for an
199 interaction consisting of both categorical and numeric
200 data, but a mistake for purely numerical interactions. To
201 avoid the error, we set result->f to 1.0 for numeric
204 result->val.f = result->f;
212 interaction_value_get (const struct interaction_value *val)
218 Returns the numeric value of the non-zero entry for the vector
219 corresponding to this interaction. Do not use this function to get
220 the numeric value of a purely numeric interaction. Instead, use the
221 union value * returned by interaction_value_get.
224 interaction_value_get_nonzero_entry (const struct interaction_value *val)
232 interaction_value_destroy (struct interaction_value *val)
236 int val_width = var_get_width (interaction_get_variable (val->intr));
238 value_destroy (&val->val, val_width);
244 Return a value from a variable that is an interaction.
246 struct interaction_value *
247 interaction_case_data (const struct ccase *ccase, const struct interaction_variable *iv)
251 const struct variable *member;
252 const union value **vals = NULL;
254 n_vars = interaction_get_n_vars (iv);
255 vals = xnmalloc (n_vars, sizeof (*vals));
257 for (i = 0; i < n_vars; i++)
259 member = interaction_get_member (iv, i);
260 vals[i] = case_data (ccase, member);
263 return interaction_value_create (iv, vals);
267 is_interaction (const struct variable *var, const struct interaction_variable **iv, size_t n_intr)
270 const struct variable *intr;
272 for (i = 0; i < n_intr; i++)
274 intr = interaction_get_variable (iv[i]);