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