Categoricals cleanup: New structure 'payload' which reduces the
[pspp-builds.git] / src / math / interaction.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2011, 2012 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 struct interaction *
46 interaction_create (const struct variable *v)
47 {
48   struct interaction  *i = xmalloc (sizeof *i);
49   i->vars = xmalloc (sizeof *i->vars);
50   i->n_vars = 0;
51   if ( v )
52     {
53       i->vars[0] = v;
54       i->n_vars = 1;
55     }
56   return i;
57 }
58
59 /* Deep copy an interaction */
60 struct interaction *
61 interaction_clone (const struct interaction *iact)
62 {
63   int v;
64   struct interaction  *i = xmalloc (sizeof *i);
65   i->vars = xcalloc (iact->n_vars, sizeof *i->vars);
66   i->n_vars = iact->n_vars;
67
68   for (v = 0; v < iact->n_vars; ++v)
69     {
70       i->vars[v] = iact->vars[v];
71     }
72
73   return i;
74 }
75
76
77 void
78 interaction_destroy (struct interaction *i)
79 {
80   if (NULL == i)
81     return;
82
83   free (i->vars);
84   free (i);
85 }
86
87 void
88 interaction_add_variable (struct interaction *i, const struct variable *v)
89 {
90   i->vars = xrealloc (i->vars, sizeof (*i->vars) * ++i->n_vars);
91   i->vars[i->n_vars - 1] = v;
92 }
93
94
95 /*
96   Do the variables in X->VARS constitute a proper
97   subset of the variables in Y->VARS?
98  */
99 bool
100 interaction_is_proper_subset (const struct interaction *x, const struct interaction *y)
101 {
102   if (x->n_vars >= y->n_vars)
103     return false;
104
105   return interaction_is_subset (x, y);
106 }
107
108 /*
109   Do the variables in X->VARS constitute a 
110   subset (proper or otherwise) of the variables in Y->VARS?
111  */
112 bool
113 interaction_is_subset (const struct interaction *x, const struct interaction *y)
114 {
115   size_t i;
116   size_t j;
117   size_t n = 0;
118
119   /* By definition, a subset cannot have more members than its superset */
120   if (x->n_vars > y->n_vars)
121     return false;
122
123   /* Count the number of values which are members of both sets */
124   for (i = 0; i < x->n_vars; i++)
125     {
126       for (j = 0; j < y->n_vars; j++)
127         {
128           if (x->vars [i] == y->vars [j])
129             {
130               n++;
131             }
132         }
133     }
134
135   /* If ALL the members of X were also found in Y, then this must be a subset */    
136   if (n >= x->n_vars)
137     return true;
138
139   return false;
140 }
141
142
143
144
145 void
146 interaction_dump (const struct interaction *i)
147 {
148   int v = 0;
149   printf ("%s", var_get_name (i->vars[v]));
150   for (v = 1; v < i->n_vars; ++v)
151     {
152       printf (" * %s", var_get_name (i->vars[v]));
153     }
154   printf ("\n");
155 }
156
157 /* Appends STR with a representation of the interaction, suitable for user
158    display.
159
160    STR must have been initialised prior to calling this function.
161 */
162 void
163 interaction_to_string (const struct interaction *iact, struct string *str)
164 {
165   int v = 0;
166   if ( iact->n_vars == 0)
167     return;
168   ds_put_cstr (str, var_to_string (iact->vars[v]));
169   for (v = 1; v < iact->n_vars; ++v)
170     {
171       ds_put_cstr (str, " * ");
172       ds_put_cstr (str, var_to_string (iact->vars[v]));
173     }
174 }
175
176 unsigned int
177 interaction_case_hash (const struct interaction *iact, const struct ccase *c, unsigned int base)
178 {
179   int i;
180   size_t hash = base;
181   for (i = 0; i < iact->n_vars; ++i)
182     {
183       const struct variable *var = iact->vars[i];
184       const union value *val = case_data (c, var);
185       hash = value_hash (val, var_get_width (var), hash);
186     }
187   return hash;
188 }
189
190 bool
191 interaction_case_equal (const struct interaction *iact, const struct ccase *c1, const struct ccase *c2)
192 {
193   int i;
194   bool same = true;
195
196   for (i = 0; i < iact->n_vars; ++i)
197     {
198       const struct variable *var = iact->vars[i];
199       if ( ! value_equal (case_data (c1, var), case_data (c2, var), var_get_width (var)))
200         {
201           same = false;
202           break;
203         }
204     }
205
206   return same;
207 }
208
209
210 int
211 interaction_case_cmp_3way (const struct interaction *iact, const struct ccase *c1, const struct ccase *c2)
212 {
213   int i;
214   int result = 0;
215
216   for (i = 0; i < iact->n_vars; ++i)
217     {
218       const struct variable *var = iact->vars[i];
219       result = value_compare_3way (case_data (c1, var), case_data (c2, var), var_get_width (var));
220       if (result != 0)
221         break;
222     }
223
224   return result;
225 }
226
227
228 bool
229 interaction_case_is_missing (const struct interaction *iact, const struct ccase *c, enum mv_class exclude)
230 {
231   int i;
232   bool missing = false;
233
234   for (i = 0; i < iact->n_vars; ++i)
235     {
236       if ( var_is_value_missing (iact->vars[i], case_data (c, iact->vars[i]), exclude))
237         {
238           missing = true;
239           break;
240         }
241     }
242
243   return missing;
244 }
245