Categoricals: Replace single value by a case, so that interactions can be supported
[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->vars[0] = v;
52   i->n_vars = 1;
53   return i;
54 }
55
56 void
57 interaction_destroy (struct interaction *i)
58 {
59   free (i->vars);
60   free (i);
61 }
62
63 void
64 interaction_add_variable (struct interaction *i, const struct variable *v)
65 {
66   i->vars = xrealloc (i->vars, sizeof (*i->vars) * ++i->n_vars);
67   i->vars[i->n_vars - 1] = v;
68 }
69
70
71 void
72 interaction_dump (const struct interaction *i)
73 {
74   int v = 0;
75   printf ("%s", var_get_name (i->vars[v]));
76   for (v = 1; v < i->n_vars; ++v)
77     {
78       printf (" * %s", var_get_name (i->vars[v]));
79     }
80   printf ("\n");
81 }
82
83 /* Appends STR with a representation of the interaction, suitable for user
84    display.
85
86    STR must have been initialised prior to calling this function.
87 */
88 void
89 interaction_to_string (const struct interaction *iact, struct string *str)
90 {
91   int v = 0;
92   ds_put_cstr (str, var_to_string (iact->vars[v]));
93   for (v = 1; v < iact->n_vars; ++v)
94     {
95       ds_put_cstr (str, " * ");
96       ds_put_cstr (str, var_to_string (iact->vars[v]));
97     }
98 }
99
100 unsigned int
101 interaction_case_hash (const struct interaction *iact, const struct ccase *c)
102 {
103   int i;
104   size_t hash = 0;
105   for (i = 0; i < iact->n_vars; ++i)
106     {
107       const struct variable *var = iact->vars[i];
108       const union value *val = case_data (c, var);
109       hash = value_hash (val, var_get_width (var), hash);
110     }
111   return hash;
112 }
113
114 bool
115 interaction_case_equal (const struct interaction *iact, const struct ccase *c1, const struct ccase *c2)
116 {
117   int i;
118   bool same = true;
119
120   for (i = 0; i < iact->n_vars; ++i)
121     {
122       const struct variable *var = iact->vars[i];
123       if ( ! value_equal (case_data (c1, var), case_data (c2, var), var_get_width (var)))
124         {
125           same = false;
126           break;
127         }
128     }
129
130   return same;
131 }
132
133
134 int
135 interaction_case_cmp_3way (const struct interaction *iact, const struct ccase *c1, const struct ccase *c2)
136 {
137   int i;
138   int result = 0;
139
140   for (i = 0; i < iact->n_vars; ++i)
141     {
142       const struct variable *var = iact->vars[i];
143       result = value_compare_3way (case_data (c1, var), case_data (c2, var), var_get_width (var));
144       if (result != 0)
145         break;
146     }
147
148   return result;
149 }
150
151
152 bool
153 interaction_case_is_missing (const struct interaction *iact, const struct ccase *c, enum mv_class exclude)
154 {
155   int i;
156   bool missing = false;
157
158   for (i = 0; i < iact->n_vars; ++i)
159     {
160       if ( var_is_value_missing (iact->vars[i], case_data (c, iact->vars[i]), exclude))
161         {
162           missing = true;
163           break;
164         }
165     }
166
167   return missing;
168 }
169