Restart of new means implementation
[pspp] / src / language / stats / means-parser.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2011, 2012, 2013, 2019 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 "data/casegrouper.h"
21 #include "data/casereader.h"
22 #include "data/dataset.h"
23 #include "data/dictionary.h"
24 #include "data/format.h"
25 #include "data/variable.h"
26
27 #include "language/command.h"
28 #include "language/lexer/lexer.h"
29 #include "language/lexer/variable-parser.h"
30
31 #include "libpspp/hmap.h"
32 #include "libpspp/bt.h"
33 #include "libpspp/misc.h"
34 #include "libpspp/pool.h"
35
36 #include "means.h"
37
38 /* Parse the /TABLES stanza of the command.  */
39 static bool
40 parse_means_table_syntax (struct lexer *lexer, const struct means *cmd,
41                           struct mtable *table)
42 {
43   table->n_layers = 0;
44   table->layers = NULL;
45
46   /* Dependent variable (s) */
47   if (!parse_variables_const_pool (lexer, cmd->pool, cmd->dict,
48                                    &table->dep_vars, &table->n_dep_vars,
49                                    PV_NO_DUPLICATE | PV_NUMERIC))
50     return false;
51
52
53   /* Factor variable (s) */
54   while (lex_match (lexer, T_BY))
55     {
56       struct layer *layer = xzalloc (sizeof *layer);
57       hmap_init (&layer->instances.map);
58
59       table->n_layers++;
60       table->layers  = xrealloc (table->layers,
61                                  table->n_layers * sizeof *table->layers);
62
63       table->layers[table->n_layers - 1] = layer;
64
65       if (!parse_variables_const_pool
66           (lexer, cmd->pool, cmd->dict,
67            &layer->factor_vars,
68            &layer->n_factor_vars,
69            PV_NO_DUPLICATE))
70         return false;
71     }
72
73   return true;
74 }
75
76 /* Match a variable.
77    If the match succeeds, the variable will be placed in VAR.
78    Returns true if successful */
79 static bool
80 lex_is_variable (struct lexer *lexer, const struct dictionary *dict,
81                  int n)
82 {
83   const char *tstr;
84   if (lex_next_token (lexer, n) !=  T_ID)
85     return false;
86
87   tstr = lex_next_tokcstr (lexer, n);
88
89   if (NULL == dict_lookup_var (dict, tstr) )
90     return false;
91
92   return true;
93 }
94
95 static bool
96 means_parse (struct lexer *lexer, struct means *means)
97 {
98   /*   Optional TABLES =   */
99   if (lex_match_id (lexer, "TABLES"))
100     {
101       if (! lex_force_match (lexer, T_EQUALS))
102         return false;
103     }
104
105   bool more_tables = true;
106   /* Parse the "tables" */
107   while (more_tables)
108     {
109       means->n_tables ++;
110       means->table = pool_realloc (means->pool, means->table, means->n_tables * sizeof (*means->table));
111
112       if (! parse_means_table_syntax (lexer, means,
113                                       &means->table[means->n_tables - 1]))
114         {
115           return false;
116         }
117
118       /* Look ahead to see if there are more tables to be parsed */
119       more_tables = false;
120       if ( T_SLASH == lex_next_token (lexer, 0) )
121         {
122           if (lex_is_variable (lexer, means->dict, 1) )
123             {
124               more_tables = true;
125               lex_match (lexer, T_SLASH);
126             }
127         }
128     }
129
130   /* /MISSING subcommand */
131   while (lex_token (lexer) != T_ENDCMD)
132     {
133       lex_match (lexer, T_SLASH);
134
135       if (lex_match_id (lexer, "MISSING"))
136         {
137           /*
138             If no MISSING subcommand is specified, each combination of
139             a dependent variable and categorical variables is handled
140             separately.
141           */
142           lex_match (lexer, T_EQUALS);
143           if (lex_match_id (lexer, "INCLUDE"))
144             {
145               /*
146                 Use the subcommand  "/MISSING=INCLUDE" to include user-missing
147                 values in the analysis.
148               */
149
150               means->exclude = MV_SYSTEM;
151               means->dep_exclude = MV_SYSTEM;
152             }
153           else if (lex_match_id (lexer, "TABLE"))
154             /*
155               This is the default. (I think).
156               Every case containing a complete set of variables for a given
157               table. If any variable, categorical or dependent for in a table
158               is missing (as defined by what?), then that variable will
159               be dropped FOR THAT TABLE ONLY.
160             */
161             {
162               means->listwise_exclude = true;
163             }
164           else if (lex_match_id (lexer, "DEPENDENT"))
165             /*
166               Use the command "/MISSING=DEPENDENT" to
167               include user-missing values for the categorical variables,
168               while excluding them for the dependent variables.
169
170               Cases are dropped only when user-missing values
171               appear in dependent  variables.  User-missing
172               values for categorical variables are treated according to
173               their face value.
174
175               Cases are ALWAYS dropped when System Missing values appear
176               in the categorical variables.
177             */
178             {
179               means->dep_exclude = MV_ANY;
180               means->exclude = MV_SYSTEM;
181             }
182           else
183             {
184               lex_error (lexer, NULL);
185               return false;
186             }
187         }
188       else if (lex_match_id (lexer, "CELLS"))
189         {
190           lex_match (lexer, T_EQUALS);
191
192           /* The default values become overwritten */
193           means->n_statistics = 0;
194           free (means->statistics);
195           means->statistics = 0;
196           while (lex_token (lexer) != T_ENDCMD
197                  && lex_token (lexer) != T_SLASH)
198             {
199               if (lex_match (lexer, T_ALL))
200                 {
201                   free (means->statistics);
202                   means->statistics = xcalloc (n_MEANS_STATISTICS, sizeof (*means->statistics));
203                   means->n_statistics = n_MEANS_STATISTICS;
204                   int i;
205                   for (i = 0; i < n_MEANS_STATISTICS; ++i)
206                     {
207                       means->statistics[i] = i;
208                     }
209                 }
210               else if (lex_match_id (lexer, "NONE"))
211                 {
212                   means->n_statistics = 0;
213                   free (means->statistics);
214                   means->statistics = 0;
215                 }
216               else if (lex_match_id (lexer, "DEFAULT"))
217                 {
218                   means->n_statistics = 3;
219                   means->statistics = xcalloc (3, sizeof *means->statistics);
220                   means->statistics[0] = MEANS_MEAN;
221                   means->statistics[1] = MEANS_N;
222                   means->statistics[2] = MEANS_STDDEV;
223                 }
224               else
225                 {
226                   int i;
227                   for (i = 0; i < n_MEANS_STATISTICS; ++i)
228                     {
229                       const struct cell_spec *cs = cell_spec + i;
230                       if (lex_match_id (lexer, cs->keyword))
231                         {
232                           means->statistics
233                             = xrealloc (means->statistics,
234                                         (means->n_statistics + 1)
235                                         * sizeof (*means->statistics));
236
237                           means->statistics[means->n_statistics] = i;
238                           means->n_statistics++;
239                           break;
240                         }
241                     }
242
243                   if (i >= n_MEANS_STATISTICS)
244                     {
245                       lex_error (lexer, NULL);
246                       return false;
247                     }
248                 }
249             }
250         }
251       else
252         {
253           lex_error (lexer, NULL);
254           return false;
255         }
256     }
257   return true;
258 }
259
260 int
261 cmd_means (struct lexer *lexer, struct dataset *ds)
262 {
263   struct means means;
264   means.pool = pool_create ();
265
266   means.exclude = MV_ANY;
267   means.dep_exclude = MV_ANY;
268   means.listwise_exclude = false;
269   means.table = NULL;
270   means.n_tables = 0;
271
272   means.dict = dataset_dict (ds);
273
274   means.n_statistics = 3;
275   means.statistics = xcalloc (3, sizeof *means.statistics);
276   means.statistics[0] = MEANS_MEAN;
277   means.statistics[1] = MEANS_N;
278   means.statistics[2] = MEANS_STDDEV;
279
280   if (! means_parse (lexer, &means))
281     goto error;
282
283   {
284     struct casegrouper *grouper;
285     struct casereader *group;
286     bool ok;
287
288     grouper = casegrouper_create_splits (proc_open (ds), means.dict);
289     while (casegrouper_get_next_group (grouper, &group))
290       {
291         run_means (&means, group, ds);
292       }
293     ok = casegrouper_destroy (grouper);
294     ok = proc_commit (ds) && ok;
295   }
296
297   for (int t = 0; t < means.n_tables; ++t)
298     {
299       const struct mtable *table  = means.table + t;
300       means_shipout (table, &means);
301     }
302
303   return CMD_SUCCESS;
304
305  error:
306
307   return CMD_FAILURE;
308 }
309
310
311 \f
312
313