Merge branch 'master' of ssh://jmd@git.sv.gnu.org/srv/git/pspp
[pspp-builds.git] / src / data / casereader-translator.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2007 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 #include <data/val-type.h>
19 #include <data/casereader.h>
20 #include <stdlib.h>
21
22 #include <data/casereader-provider.h>
23 #include <libpspp/taint.h>
24
25 #include "xalloc.h"
26
27 /* Casereader that applies a user-supplied function to translate
28    each case into another in an arbitrary fashion. */
29
30 /* A translating casereader. */
31 struct casereader_translator
32   {
33     struct casereader *subreader; /* Source of input cases. */
34
35     void (*translate) (struct ccase *input, struct ccase *output, void *aux);
36     bool (*destroy) (void *aux);
37     void *aux;
38   };
39
40 static const struct casereader_class casereader_translator_class;
41
42 /* Creates and returns a new casereader whose cases are produced
43    by reading from SUBREADER and passing through TRANSLATE, which
44    must create case OUTPUT, with OUTPUT_VALUE_CNT values, and
45    populate it based on INPUT and auxiliary data AUX.  TRANSLATE
46    must also destroy INPUT.
47
48    When the translating casereader is destroyed, DESTROY will be
49    called to allow any state maintained by TRANSLATE to be freed.
50
51    After this function is called, SUBREADER must not ever again
52    be referenced directly.  It will be destroyed automatically
53    when the translating casereader is destroyed. */
54 struct casereader *
55 casereader_create_translator (struct casereader *subreader,
56                               size_t output_value_cnt,
57                               void (*translate) (struct ccase *input,
58                                                  struct ccase *output,
59                                                  void *aux),
60                               bool (*destroy) (void *aux),
61                               void *aux)
62 {
63   struct casereader_translator *ct = xmalloc (sizeof *ct);
64   struct casereader *reader;
65   ct->subreader = casereader_rename (subreader);
66   ct->translate = translate;
67   ct->destroy = destroy;
68   ct->aux = aux;
69   reader = casereader_create_sequential (
70     NULL, output_value_cnt, casereader_get_case_cnt (ct->subreader),
71     &casereader_translator_class, ct);
72   taint_propagate (casereader_get_taint (ct->subreader),
73                    casereader_get_taint (reader));
74   return reader;
75 }
76
77 /* Internal read function for translating casereader. */
78 static bool
79 casereader_translator_read (struct casereader *reader UNUSED,
80                             void *ct_, struct ccase *c)
81 {
82   struct casereader_translator *ct = ct_;
83   struct ccase tmp;
84
85   if (casereader_read (ct->subreader, &tmp))
86     {
87       ct->translate (&tmp, c, ct->aux);
88       return true;
89     }
90   else
91     return false;
92 }
93
94 /* Internal destroy function for translating casereader. */
95 static void
96 casereader_translator_destroy (struct casereader *reader UNUSED, void *ct_)
97 {
98   struct casereader_translator *ct = ct_;
99   casereader_destroy (ct->subreader);
100   ct->destroy (ct->aux);
101   free (ct);
102 }
103
104 /* Casereader class for translating casereader. */
105 static const struct casereader_class casereader_translator_class =
106   {
107     casereader_translator_read,
108     casereader_translator_destroy,
109     NULL,
110     NULL,
111   };
112
113 \f
114
115 struct casereader_append_numeric
116 {
117   int value_ofs;
118   casenumber n;
119   new_value_func *func;
120   void *aux;
121   void (*destroy) (void *aux);
122 };
123
124 static bool can_destroy (void *can_);
125
126 static void can_translate (struct ccase *input, struct ccase *output,
127                            void *can_);
128
129 /* Creates and returns a new casereader whose cases are produced
130    by reading from SUBREADER and appending an additional value,
131    generated by FUNC.  AUX is an optional parameter which
132    gets passed to FUNC. FUNC will also receive N as it, which is
133    the ordinal number of the case in the reader.  DESTROY is an
134    optional parameter used to destroy AUX.
135
136    After this function is called, SUBREADER must not ever again
137    be referenced directly.  It will be destroyed automatically
138    when the translating casereader is destroyed. */
139 struct casereader *
140 casereader_create_append_numeric (struct casereader *subreader,
141                                   new_value_func func, void *aux,
142                                   void (*destroy) (void *aux))
143 {
144   struct casereader_append_numeric *can = xmalloc (sizeof *can);
145   can->value_ofs = casereader_get_value_cnt (subreader);
146   can->n = 0;
147   can->aux = aux;
148   can->func = func;
149   can->destroy = destroy;
150   return casereader_create_translator (subreader, can->value_ofs + 1,
151                                        can_translate, can_destroy, can);
152 }
153
154
155 static void
156 can_translate (struct ccase *input, struct ccase *output, void *can_)
157 {
158   struct casereader_append_numeric *can = can_;
159   double new_value = can->func (input, can->n++, can->aux);
160   case_nullify (output);
161   case_move (output, input);
162   case_resize (output, can->value_ofs + 1);
163   case_data_rw_idx (output, can->value_ofs)->f = new_value;
164 }
165
166 static bool
167 can_destroy (void *can_)
168 {
169   struct casereader_append_numeric *can = can_;
170   if (can->destroy)
171     can->destroy (can->aux);
172   free (can);
173   return true;
174 }
175
176 \f
177
178 struct arithmetic_sequence
179 {
180   double first;
181   double increment;
182 };
183
184 static double
185 next_arithmetic (const struct ccase *c UNUSED,
186                  casenumber n,
187                  void *aux)
188 {
189   struct arithmetic_sequence *as = aux;
190   return n * as->increment + as->first;
191 }
192
193 /* Creates and returns a new casereader whose cases are produced
194    by reading from SUBREADER and appending an additional value,
195    which takes the value FIRST in the first case, FIRST +
196    INCREMENT in the second case, FIRST + INCREMENT * 2 in the
197    third case, and so on.
198
199    After this function is called, SUBREADER must not ever again
200    be referenced directly.  It will be destroyed automatically
201    when the translating casereader is destroyed. */
202 struct casereader *
203 casereader_create_arithmetic_sequence (struct casereader *subreader,
204                                        double first, double increment)
205 {
206   struct arithmetic_sequence *as = xzalloc (sizeof *as);
207   as->first = first;
208   as->increment = increment;
209   return casereader_create_append_numeric (subreader, next_arithmetic,
210                                            as, free);
211 }
212
213
214 \f
215
216 struct casereader_append_rank
217 {
218   struct casereader *clone;
219   casenumber n;
220   const struct variable *var;
221   const struct variable *weight;
222   int value_ofs;
223   casenumber n_common;
224   double mean_rank;
225   double cc;
226   distinct_func *distinct;
227   void *aux;
228   enum rank_error *err;
229   double prev_value;
230 };
231
232 static bool car_destroy (void *car_);
233
234 static void car_translate (struct ccase *input, struct ccase *output,
235                            void *car_);
236
237 /* Creates and returns a new casereader whose cases are produced
238    by reading from SUBREADER and appending an additional value,
239    which is the rank of the observation.   W is the weight variable
240    of the dictionary containing V, or NULL if there is no weight
241    variable.
242
243    The following preconditions must be met:
244
245    1.    SUBREADER must be sorted on V.
246
247    2.    The weight variables, must be non-negative.
248
249    If either of these preconditions are not satisfied, then the rank
250    variables may not be correct.  In this case, if ERR is non-null,
251    it will be set according to the erroneous conditions encountered.
252
253    If DISTINCT_CALLBACK is non-null, then  it will be called exactly
254    once for every case containing a distinct value of V.  AUX is
255    an auxilliary pointer passed to DISTINCT_CALLBACK.
256
257    After this function is called, SUBREADER must not ever again
258    be referenced directly.  It will be destroyed automatically
259    when the translating casereader is destroyed. */
260 struct casereader *
261 casereader_create_append_rank (struct casereader *subreader,
262                                const struct variable *v,
263                                const struct variable *w,
264                                enum rank_error *err,
265                                distinct_func *distinct_callback,
266                                void *aux
267                                )
268 {
269   struct casereader_append_rank *car = xmalloc (sizeof *car);
270   car->value_ofs = casereader_get_value_cnt (subreader);
271   car->weight = w;
272   car->var = v;
273   car->n = 0;
274   car->n_common = 1;
275   car->cc = 0.0;
276   car->clone = casereader_clone (subreader);
277   car->distinct = distinct_callback;
278   car->aux = aux;
279   car->err = err;
280   car->prev_value = SYSMIS;
281
282   return casereader_create_translator (subreader, car->value_ofs + 1,
283                                        car_translate, car_destroy, car);
284 }
285
286
287 static bool
288 car_destroy (void *car_)
289 {
290   struct casereader_append_rank *car = car_;
291   casereader_destroy (car->clone);
292   free (car);
293   return true;
294 }
295
296
297 static void
298 car_translate (struct ccase *input, struct ccase *output,  void *car_)
299 {
300   struct casereader_append_rank *car = car_;
301
302   const double value = case_data (input, car->var)->f;
303
304   if ( car->prev_value != SYSMIS)
305     {
306       if (car->err && value < car->prev_value)
307         *car->err |= RANK_ERR_UNSORTED;
308     }
309
310   if ( car->n_common == 1)
311     {
312       double vxx = SYSMIS;
313       casenumber k = 0;
314       double weight = 1.0;
315       if (car->weight)
316         {
317           weight = case_data (input, car->weight)->f;
318           if ( car->err && weight < 0 )
319             *car->err |= RANK_ERR_NEGATIVE_WEIGHT;
320         }
321
322       do
323         {
324           struct ccase c;
325           if ( ! casereader_peek (car->clone, car->n + ++k, &c))
326             break;
327           vxx = case_data (&c, car->var)->f;
328
329           if ( vxx == value)
330             {
331               if (car->weight)
332                 {
333                   double w = case_data (&c, car->weight)->f;
334
335                   if ( car->err && w < 0 )
336                     *car->err |= RANK_ERR_NEGATIVE_WEIGHT;
337
338                   weight += w;
339                 }
340               else
341                 weight += 1.0;
342               car->n_common++;
343             }
344           case_destroy (&c);
345         }
346       while (vxx == value);
347       car->mean_rank = car->cc + (weight + 1) / 2.0;
348       car->cc += weight;
349
350       if (car->distinct)
351         car->distinct (value, car->n_common, weight, car->aux);
352     }
353   else
354     car->n_common--;
355
356   car->n++;
357
358   case_nullify (output);
359   case_move (output, input);
360   case_resize (output, car->value_ofs + 1);
361   case_data_rw_idx (output, car->value_ofs)->f = car->mean_rank ;
362   car->prev_value = value;
363 }
364
365