1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2007 Free Software Foundation, Inc.
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.
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.
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/>. */
18 #include <data/val-type.h>
19 #include <data/casereader.h>
23 #include <data/casereader-provider.h>
24 #include <libpspp/taint.h>
28 /* Casereader that applies a user-supplied function to translate
29 each case into another in an arbitrary fashion. */
31 /* A translating casereader. */
32 struct casereader_translator
34 struct casereader *subreader; /* Source of input cases. */
36 void (*translate) (struct ccase *input, struct ccase *output, void *aux);
37 bool (*destroy) (void *aux);
41 static const struct casereader_class casereader_translator_class;
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.
49 When the translating casereader is destroyed, DESTROY will be
50 called to allow any state maintained by TRANSLATE to be freed.
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. */
56 casereader_create_translator (struct casereader *subreader,
57 size_t output_value_cnt,
58 void (*translate) (struct ccase *input,
61 bool (*destroy) (void *aux),
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;
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));
78 /* Internal read function for translating casereader. */
80 casereader_translator_read (struct casereader *reader UNUSED,
81 void *ct_, struct ccase *c)
83 struct casereader_translator *ct = ct_;
86 if (casereader_read (ct->subreader, &tmp))
88 ct->translate (&tmp, c, ct->aux);
95 /* Internal destroy function for translating casereader. */
97 casereader_translator_destroy (struct casereader *reader UNUSED, void *ct_)
99 struct casereader_translator *ct = ct_;
100 casereader_destroy (ct->subreader);
101 ct->destroy (ct->aux);
105 /* Casereader class for translating casereader. */
106 static const struct casereader_class casereader_translator_class =
108 casereader_translator_read,
109 casereader_translator_destroy,
116 struct casereader_append_numeric
120 new_value_func *func;
122 void (*destroy) (void *aux);
125 static bool can_destroy (void *can_);
127 static void can_translate (struct ccase *input, struct ccase *output,
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.
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. */
141 casereader_create_append_numeric (struct casereader *subreader,
142 new_value_func func, void *aux,
143 void (*destroy) (void *aux))
145 struct casereader_append_numeric *can = xmalloc (sizeof *can);
146 can->value_ofs = casereader_get_value_cnt (subreader);
150 can->destroy = destroy;
151 return casereader_create_translator (subreader, can->value_ofs + 1,
152 can_translate, can_destroy, can);
157 can_translate (struct ccase *input, struct ccase *output, void *can_)
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;
168 can_destroy (void *can_)
170 struct casereader_append_numeric *can = can_;
172 can->destroy (can->aux);
179 struct arithmetic_sequence
186 next_arithmetic (const struct ccase *c UNUSED,
190 struct arithmetic_sequence *as = aux;
191 return n * as->increment + as->first;
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.
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. */
204 casereader_create_arithmetic_sequence (struct casereader *subreader,
205 double first, double increment)
207 struct arithmetic_sequence *as = xzalloc (sizeof *as);
209 as->increment = increment;
210 return casereader_create_append_numeric (subreader, next_arithmetic,
217 struct casereader_append_rank
219 struct casereader *clone;
221 const struct variable *var;
222 const struct variable *weight;
227 distinct_func *distinct;
231 static bool car_destroy (void *car_);
233 static void car_translate (struct ccase *input, struct ccase *output,
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.
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.
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. */
250 casereader_create_append_rank (struct casereader *subreader,
251 const struct variable *v,
252 const struct variable *w,
253 distinct_func *distinct_callback,
257 struct casereader_append_rank *car = xmalloc (sizeof *car);
258 car->value_ofs = casereader_get_value_cnt (subreader);
264 car->clone = casereader_clone (subreader);
265 car->distinct = distinct_callback;
268 return casereader_create_translator (subreader, car->value_ofs + 1,
269 car_translate, car_destroy, car);
274 car_destroy (void *car_)
276 struct casereader_append_rank *car = car_;
277 casereader_destroy (car->clone);
284 car_translate (struct ccase *input, struct ccase *output, void *car_)
286 struct casereader_append_rank *car = car_;
288 double value = case_data (input, car->var)->f;
290 if ( car->n_common == 1)
296 weight = case_data (input, car->weight)->f;
301 if ( ! casereader_peek (car->clone, car->n + ++k, &c))
303 vxx = case_data (&c, car->var)->f;
308 weight += case_data (&c, car->weight)->f;
315 while (vxx == value);
316 car->mean_rank = car->cc + (weight + 1) / 2.0;
320 car->distinct (value, car->n_common, weight, car->aux);
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 ;