Move interaction subset predicates out of glm.c into interaction.c
[pspp-builds.git] / src / math / interaction.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2011 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
19 #include "data/case.h"
20 #include "interaction.h"
21
22 #include "data/value.h"
23 #include "data/variable.h"
24 #include "libpspp/str.h"
25
26 #include "gl/xalloc.h"
27
28 #include <stdio.h>
29
30
31 /*
32   An interaction is a structure containing a "product" of other
33   variables. The variables can be either string or numeric.
34
35   Interaction is commutative.  That means, that from a mathematical point of
36   view,  the order of the variables is irrelevant.  However, for display
37   purposes, and for matching with an interaction's value the order is 
38   pertinent.
39   
40   Therefore, when using these functions, make sure the orders of variables 
41   and values match when appropriate.
42 */
43
44
45
46 struct interaction *
47 interaction_create (const struct variable *v)
48 {
49   struct interaction  *i = xmalloc (sizeof *i);
50   i->vars = xmalloc (sizeof *i->vars);
51   i->n_vars = 0;
52   if ( v )
53     {
54       i->vars[0] = v;
55       i->n_vars = 1;
56     }
57   return i;
58 }
59
60 void
61 interaction_destroy (struct interaction *i)
62 {
63   free (i->vars);
64   free (i);
65 }
66
67 void
68 interaction_add_variable (struct interaction *i, const struct variable *v)
69 {
70   i->vars = xrealloc (i->vars, sizeof (*i->vars) * ++i->n_vars);
71   i->vars[i->n_vars - 1] = v;
72 }
73
74
75 /*
76   Do the variables in X->VARS constitute a proper
77   subset of the variables in Y->VARS?
78  */
79 bool
80 interaction_is_proper_subset (const struct interaction *x, const struct interaction *y)
81 {
82   if (x->n_vars >= y->n_vars)
83     return false;
84
85   return interaction_is_subset (x, y);
86 }
87
88 /*
89   Do the variables in X->VARS constitute a 
90   subset (proper or otherwise) of the variables in Y->VARS?
91  */
92 bool
93 interaction_is_subset (const struct interaction *x, const struct interaction *y)
94 {
95   size_t i;
96   size_t j;
97   size_t n = 0;
98
99   /* By definition, a subset cannot have more members than its superset */
100   if (x->n_vars > y->n_vars)
101     return false;
102
103   /* Count the number of values which are members of both sets */
104   for (i = 0; i < x->n_vars; i++)
105     {
106       for (j = 0; j < y->n_vars; j++)
107         {
108           if (x->vars [i] == y->vars [j])
109             {
110               n++;
111             }
112         }
113     }
114
115   /* If ALL the members of X were also found in Y, then this must be a subset */    
116   if (n >= x->n_vars)
117     return true;
118
119   return false;
120 }
121
122
123
124
125 void
126 interaction_dump (const struct interaction *i)
127 {
128   int v = 0;
129   printf ("%s", var_get_name (i->vars[v]));
130   for (v = 1; v < i->n_vars; ++v)
131     {
132       printf (" * %s", var_get_name (i->vars[v]));
133     }
134   printf ("\n");
135 }
136
137 /* Appends STR with a representation of the interaction, suitable for user
138    display.
139
140    STR must have been initialised prior to calling this function.
141 */
142 void
143 interaction_to_string (const struct interaction *iact, struct string *str)
144 {
145   int v = 0;
146   ds_put_cstr (str, var_to_string (iact->vars[v]));
147   for (v = 1; v < iact->n_vars; ++v)
148     {
149       ds_put_cstr (str, " * ");
150       ds_put_cstr (str, var_to_string (iact->vars[v]));
151     }
152 }
153
154 unsigned int
155 interaction_case_hash (const struct interaction *iact, const struct ccase *c)
156 {
157   int i;
158   size_t hash = 0;
159   for (i = 0; i < iact->n_vars; ++i)
160     {
161       const struct variable *var = iact->vars[i];
162       const union value *val = case_data (c, var);
163       hash = value_hash (val, var_get_width (var), hash);
164     }
165   return hash;
166 }
167
168 bool
169 interaction_case_equal (const struct interaction *iact, const struct ccase *c1, const struct ccase *c2)
170 {
171   int i;
172   bool same = true;
173
174   for (i = 0; i < iact->n_vars; ++i)
175     {
176       const struct variable *var = iact->vars[i];
177       if ( ! value_equal (case_data (c1, var), case_data (c2, var), var_get_width (var)))
178         {
179           same = false;
180           break;
181         }
182     }
183
184   return same;
185 }
186
187
188 int
189 interaction_case_cmp_3way (const struct interaction *iact, const struct ccase *c1, const struct ccase *c2)
190 {
191   int i;
192   int result = 0;
193
194   for (i = 0; i < iact->n_vars; ++i)
195     {
196       const struct variable *var = iact->vars[i];
197       result = value_compare_3way (case_data (c1, var), case_data (c2, var), var_get_width (var));
198       if (result != 0)
199         break;
200     }
201
202   return result;
203 }
204
205
206 bool
207 interaction_case_is_missing (const struct interaction *iact, const struct ccase *c, enum mv_class exclude)
208 {
209   int i;
210   bool missing = false;
211
212   for (i = 0; i < iact->n_vars; ++i)
213     {
214       if ( var_is_value_missing (iact->vars[i], case_data (c, iact->vars[i]), exclude))
215         {
216           missing = true;
217           break;
218         }
219     }
220
221   return missing;
222 }
223