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