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