Replace checkbox-treeview functions with a object PsppireCheckboxTreeview
[pspp] / 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   if ( i->n_vars == 0)
150     {
151       printf ("(empty)\n");
152       return;
153     }
154   printf ("%s", var_get_name (i->vars[v]));
155   for (v = 1; v < i->n_vars; ++v)
156     printf (" * %s", var_get_name (i->vars[v]));
157   printf ("\n");
158 }
159
160 /* Appends STR with a representation of the interaction, suitable for user
161    display.
162
163    STR must have been initialised prior to calling this function.
164 */
165 void
166 interaction_to_string (const struct interaction *iact, struct string *str)
167 {
168   int v = 0;
169   if ( iact->n_vars == 0)
170     return;
171   ds_put_cstr (str, var_to_string (iact->vars[v]));
172   for (v = 1; v < iact->n_vars; ++v)
173     {
174       ds_put_cstr (str, " * ");
175       ds_put_cstr (str, var_to_string (iact->vars[v]));
176     }
177 }
178
179 unsigned int
180 interaction_case_hash (const struct interaction *iact, const struct ccase *c, unsigned int base)
181 {
182   int i;
183   size_t hash = base;
184   for (i = 0; i < iact->n_vars; ++i)
185     {
186       const struct variable *var = iact->vars[i];
187       const union value *val = case_data (c, var);
188       hash = value_hash (val, var_get_width (var), hash);
189     }
190   return hash;
191 }
192
193 bool
194 interaction_case_equal (const struct interaction *iact, const struct ccase *c1, const struct ccase *c2)
195 {
196   int i;
197   bool same = true;
198
199   for (i = 0; i < iact->n_vars; ++i)
200     {
201       const struct variable *var = iact->vars[i];
202       if ( ! value_equal (case_data (c1, var), case_data (c2, var), var_get_width (var)))
203         {
204           same = false;
205           break;
206         }
207     }
208
209   return same;
210 }
211
212
213 int
214 interaction_case_cmp_3way (const struct interaction *iact, const struct ccase *c1, const struct ccase *c2)
215 {
216   int i;
217   int result = 0;
218
219   for (i = 0; i < iact->n_vars; ++i)
220     {
221       const struct variable *var = iact->vars[i];
222       result = value_compare_3way (case_data (c1, var), case_data (c2, var), var_get_width (var));
223       if (result != 0)
224         break;
225     }
226
227   return result;
228 }
229
230
231 bool
232 interaction_case_is_missing (const struct interaction *iact, const struct ccase *c, enum mv_class exclude)
233 {
234   int i;
235   bool missing = false;
236
237   for (i = 0; i < iact->n_vars; ++i)
238     {
239       if ( var_is_value_missing (iact->vars[i], case_data (c, iact->vars[i]), exclude))
240         {
241           missing = true;
242           break;
243         }
244     }
245
246   return missing;
247 }
248