From 706a317592761872bc0c432cad854207f40f0870 Mon Sep 17 00:00:00 2001 From: John Darrington Date: Fri, 21 May 2010 13:03:03 +0200 Subject: [PATCH] Revert "Removed src/math/interaction.[ch] which has been superseded by categoricals.[ch]" This reverts commit a456c361c0d324475da63d8420a2f0b108b61243. It's still needed after all. --- src/math/automake.mk | 1 + src/math/interaction.c | 278 +++++++++++++++++++++++++++++++++++++++++ src/math/interaction.h | 40 ++++++ 3 files changed, 319 insertions(+) create mode 100644 src/math/interaction.c create mode 100644 src/math/interaction.h diff --git a/src/math/automake.mk b/src/math/automake.mk index 1b7ab004..b443d9f9 100644 --- a/src/math/automake.mk +++ b/src/math/automake.mk @@ -20,6 +20,7 @@ src_math_libpspp_math_la_SOURCES = \ src/math/group.c src/math/group.h \ src/math/group-proc.h \ src/math/histogram.c src/math/histogram.h \ + src/math/interaction.c src/math/interaction.h \ src/math/levene.c src/math/levene.h \ src/math/linreg.c src/math/linreg.h \ src/math/merge.c src/math/merge.h \ diff --git a/src/math/interaction.c b/src/math/interaction.c new file mode 100644 index 00000000..2f8da8cc --- /dev/null +++ b/src/math/interaction.c @@ -0,0 +1,278 @@ +/* PSPP - a program for statistical analysis. + Copyright (C) 2009, 2010 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* + An interaction is a structure containing a "product" of other + variables. The variables can be either categorical or numeric. + If the variables are all numeric, the interaction is just the + scalar product. If any of the variables are categorical, their + product is a vector containing 0's in all but one entry. This entry + is found by combining the vectors corresponding to the variables' + OBS_VALS member. If there are K categorical variables, each with + N_1, N_2, ..., N_K categories, then the interaction will have + N_1 * N_2 * N_3 *...* N_K - 1 entries. + + When using these functions, make sure the orders of variables and + values match when appropriate. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct interaction_variable +{ + int n_vars; + const struct variable **members; + struct variable *intr; + size_t n_alpha; +}; + +struct interaction_value +{ + const struct interaction_variable *intr; + union value val; /* Concatenation of the string values in this + interaction's value, or the product of a bunch + of numeric values for a purely numeric + interaction. + */ + double f; /* Product of the numerical values in this interaction's value. */ +}; + +/* + An interaction_variable has type alpha if any of members have type + alpha. Otherwise, its type is numeric. + */ +struct interaction_variable * +interaction_variable_create (const struct variable **vars, int n_vars) +{ + struct interaction_variable *result = NULL; + size_t i; + + if (n_vars > 0) + { + int width = 0; + + result = xmalloc (sizeof (*result)); + result->n_alpha = 0; + result->members = xnmalloc (n_vars, sizeof (*result->members)); + result->n_vars = n_vars; + for (i = 0; i < n_vars; i++) + { + result->members[i] = vars[i]; + if (var_is_alpha (vars[i])) + { + result->n_alpha++; + width += var_get_width (vars[i]); + } + } + result->intr = dict_create_internal_var (0, width); + } + + return result; +} +void interaction_variable_destroy (struct interaction_variable *iv) +{ + dict_destroy_internal_var (iv->intr); + free (iv->members); + free (iv); +} + +/* + Get one of the member variables. + */ +const struct variable * +interaction_get_member (const struct interaction_variable *iv, size_t i) +{ + return iv->members[i]; +} + +size_t +interaction_get_n_vars (const struct interaction_variable *iv) +{ + return (iv == NULL) ? 0 : iv->n_vars; +} + +size_t +interaction_get_n_alpha (const struct interaction_variable *iv) +{ + return iv->n_alpha; +} + +size_t +interaction_get_n_numeric (const struct interaction_variable *iv) +{ + return (interaction_get_n_vars (iv) - interaction_get_n_alpha (iv)); +} + +/* + Get the interaction variable itself. + */ +const struct variable * +interaction_get_variable (const struct interaction_variable *iv) +{ + return iv->intr; +} +/* + Given list of values, compute the value of the corresponding + interaction. This "value" is not stored as the typical vector of + 0's and one double, but rather the string values are concatenated to + make one big string value, and the numerical values are multiplied + together to give the non-zero entry of the corresponding vector. + */ +struct interaction_value * +interaction_value_create (const struct interaction_variable *var, const union value **vals) +{ + struct interaction_value *result = NULL; + + if (var != NULL) + { + size_t i; + int val_width = var_get_width (interaction_get_variable (var)); + int offset = 0; + size_t n_vars = interaction_get_n_vars (var); + + result = xmalloc (sizeof (*result)); + result->intr = var; + + value_init (&result->val, val_width); + + result->f = 1.0; + for (i = 0; i < n_vars; i++) + { + const struct variable *member = interaction_get_member (var, i); + + if (var_is_value_missing (member, vals[i], MV_ANY)) + { + value_set_missing (&result->val, val_width); + result->f = SYSMIS; + break; + } + else + { + if (var_is_alpha (var->members[i])) + { + uint8_t *val = value_str_rw (&result->val, val_width); + int w = var_get_width (var->members[i]); + u8_cpy (val + offset, value_str (vals[i], w), w); + offset += w; + } + else if (var_is_numeric (var->members[i])) + { + result->f *= vals[i]->f; + } + } + } + if (interaction_get_n_alpha (var) == 0) + { + /* + If there are no categorical variables, then the + interaction consists of only numeric data. In this case, + code that uses this interaction_value will see the union + member as the numeric value. If we were to store that + numeric value in result->f as well, the calling code may + inadvertently square this value by multiplying by + result->val->f. Such multiplication would be correct for an + interaction consisting of both categorical and numeric + data, but a mistake for purely numerical interactions. To + avoid the error, we set result->f to 1.0 for numeric + interactions. + */ + result->val.f = result->f; + result->f = 1.0; + } + } + return result; +} + +const union value * +interaction_value_get (const struct interaction_value *val) +{ + return &val->val; +} + +/* + Returns the numeric value of the non-zero entry for the vector + corresponding to this interaction. Do not use this function to get + the numeric value of a purely numeric interaction. Instead, use the + union value * returned by interaction_value_get. + */ +double +interaction_value_get_nonzero_entry (const struct interaction_value *val) +{ + if (val != NULL) + return val->f; + return 1.0; +} + +void +interaction_value_destroy (struct interaction_value *val) +{ + if (val != NULL) + { + int val_width = var_get_width (interaction_get_variable (val->intr)); + + value_destroy (&val->val, val_width); + free (val); + } +} + +/* + Return a value from a variable that is an interaction. + */ +struct interaction_value * +interaction_case_data (const struct ccase *ccase, const struct interaction_variable *iv) +{ + size_t i; + size_t n_vars; + const struct variable *member; + const union value **vals = NULL; + + n_vars = interaction_get_n_vars (iv); + vals = xnmalloc (n_vars, sizeof (*vals)); + + for (i = 0; i < n_vars; i++) + { + member = interaction_get_member (iv, i); + vals[i] = case_data (ccase, member); + } + + return interaction_value_create (iv, vals); +} + +bool +is_interaction (const struct variable *var, const struct interaction_variable **iv, size_t n_intr) +{ + size_t i; + const struct variable *intr; + + for (i = 0; i < n_intr; i++) + { + intr = interaction_get_variable (iv[i]); + if (intr == var) + { + return true; + } + } + return false; +} + diff --git a/src/math/interaction.h b/src/math/interaction.h new file mode 100644 index 00000000..995d0684 --- /dev/null +++ b/src/math/interaction.h @@ -0,0 +1,40 @@ +/* PSPP - a program for statistical analysis. + Copyright (C) 2009 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef INTERACTION_H +#define INTERACTION_H +#include + +struct interaction_variable; +struct interaction_value; + +struct interaction_variable * interaction_variable_create (const struct variable **, int); +void interaction_variable_destroy (struct interaction_variable *); +struct interaction_value * interaction_value_create (const struct interaction_variable *, const union value **); +void interaction_value_destroy (struct interaction_value *); +size_t interaction_variable_get_n_vars (const struct interaction_variable *); +double interaction_value_get_nonzero_entry (const struct interaction_value *); +const union value *interaction_value_get (const struct interaction_value *); +const struct variable * interaction_get_variable (const struct interaction_variable *); +size_t interaction_get_n_numeric (const struct interaction_variable *); +size_t interaction_get_n_alpha (const struct interaction_variable *); +size_t interaction_get_n_vars (const struct interaction_variable *); +const struct variable * interaction_get_member (const struct interaction_variable *, size_t); +bool is_interaction (const struct variable *, const struct interaction_variable **, size_t); +struct interaction_value * +interaction_case_data (const struct ccase *, const struct interaction_variable *); +double interaction_value_get_nonzero_entry (const struct interaction_value *); +#endif -- 2.30.2