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