4e4134f0ffcceb0b1ac79b5a8e0b583a3924be41
[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 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   ds_put_cstr (str, var_to_string (iact->vars[v]));
167   for (v = 1; v < iact->n_vars; ++v)
168     {
169       ds_put_cstr (str, " * ");
170       ds_put_cstr (str, var_to_string (iact->vars[v]));
171     }
172 }
173
174 unsigned int
175 interaction_case_hash (const struct interaction *iact, const struct ccase *c, unsigned int base)
176 {
177   int i;
178   size_t hash = base;
179   for (i = 0; i < iact->n_vars; ++i)
180     {
181       const struct variable *var = iact->vars[i];
182       const union value *val = case_data (c, var);
183       hash = value_hash (val, var_get_width (var), hash);
184     }
185   return hash;
186 }
187
188 bool
189 interaction_case_equal (const struct interaction *iact, const struct ccase *c1, const struct ccase *c2)
190 {
191   int i;
192   bool same = true;
193
194   for (i = 0; i < iact->n_vars; ++i)
195     {
196       const struct variable *var = iact->vars[i];
197       if ( ! value_equal (case_data (c1, var), case_data (c2, var), var_get_width (var)))
198         {
199           same = false;
200           break;
201         }
202     }
203
204   return same;
205 }
206
207
208 int
209 interaction_case_cmp_3way (const struct interaction *iact, const struct ccase *c1, const struct ccase *c2)
210 {
211   int i;
212   int result = 0;
213
214   for (i = 0; i < iact->n_vars; ++i)
215     {
216       const struct variable *var = iact->vars[i];
217       result = value_compare_3way (case_data (c1, var), case_data (c2, var), var_get_width (var));
218       if (result != 0)
219         break;
220     }
221
222   return result;
223 }
224
225
226 bool
227 interaction_case_is_missing (const struct interaction *iact, const struct ccase *c, enum mv_class exclude)
228 {
229   int i;
230   bool missing = false;
231
232   for (i = 0; i < iact->n_vars; ++i)
233     {
234       if ( var_is_value_missing (iact->vars[i], case_data (c, iact->vars[i]), exclude))
235         {
236           missing = true;
237           break;
238         }
239     }
240
241   return missing;
242 }
243