1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2007, 2009 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>
22 #include <data/casereader-provider.h>
23 #include <libpspp/taint.h>
27 /* Casereader that applies a user-supplied function to translate
28 each case into another in an arbitrary fashion. */
30 /* A translating casereader. */
31 struct casereader_translator
33 struct casereader *subreader; /* Source of input cases. */
35 struct ccase *(*translate) (struct ccase *input, void *aux);
36 bool (*destroy) (void *aux);
40 static const struct casereader_class casereader_translator_class;
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, and populate it based on
45 INPUT and auxiliary data AUX. TRANSLATE must destroy its
48 The cases returned by TRANSLATE must match OUTPUT_PROTO.
50 When the translating casereader is destroyed, DESTROY will be
51 called to allow any state maintained by TRANSLATE to be freed.
53 After this function is called, SUBREADER must not ever again
54 be referenced directly. It will be destroyed automatically
55 when the translating casereader is destroyed. */
57 casereader_create_translator (struct casereader *subreader,
58 const struct caseproto *output_proto,
59 struct ccase *(*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_proto, 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,
83 struct casereader_translator *ct = ct_;
84 struct ccase *tmp = casereader_read (ct->subreader);
86 tmp = ct->translate (tmp, ct->aux);
90 /* Internal destroy function for translating casereader. */
92 casereader_translator_destroy (struct casereader *reader UNUSED, void *ct_)
94 struct casereader_translator *ct = ct_;
95 casereader_destroy (ct->subreader);
96 ct->destroy (ct->aux);
100 /* Casereader class for translating casereader. */
101 static const struct casereader_class casereader_translator_class =
103 casereader_translator_read,
104 casereader_translator_destroy,
111 struct casereader_append_numeric
113 struct caseproto *proto;
115 new_value_func *func;
117 void (*destroy) (void *aux);
120 static bool can_destroy (void *can_);
122 static struct ccase *can_translate (struct ccase *, void *can_);
124 /* Creates and returns a new casereader whose cases are produced
125 by reading from SUBREADER and appending an additional value,
126 generated by FUNC. AUX is an optional parameter which
127 gets passed to FUNC. FUNC will also receive N as it, which is
128 the ordinal number of the case in the reader. DESTROY is an
129 optional parameter used to destroy AUX.
131 After this function is called, SUBREADER must not ever again
132 be referenced directly. It will be destroyed automatically
133 when the translating casereader is destroyed. */
135 casereader_create_append_numeric (struct casereader *subreader,
136 new_value_func func, void *aux,
137 void (*destroy) (void *aux))
139 struct casereader_append_numeric *can = xmalloc (sizeof *can);
140 can->proto = caseproto_ref (casereader_get_proto (subreader));
141 can->proto = caseproto_add_width (can->proto, 0);
145 can->destroy = destroy;
146 return casereader_create_translator (subreader, can->proto,
147 can_translate, can_destroy, can);
151 static struct ccase *
152 can_translate (struct ccase *c, void *can_)
154 struct casereader_append_numeric *can = can_;
155 double new_value = can->func (c, can->n++, can->aux);
156 c = case_unshare_and_resize (c, can->proto);
157 case_data_rw_idx (c, caseproto_get_n_widths (can->proto) - 1)->f = new_value;
162 can_destroy (void *can_)
164 struct casereader_append_numeric *can = can_;
166 can->destroy (can->aux);
167 caseproto_unref (can->proto);
174 struct arithmetic_sequence
181 next_arithmetic (const struct ccase *c UNUSED,
185 struct arithmetic_sequence *as = aux;
186 return n * as->increment + as->first;
189 /* Creates and returns a new casereader whose cases are produced
190 by reading from SUBREADER and appending an additional value,
191 which takes the value FIRST in the first case, FIRST +
192 INCREMENT in the second case, FIRST + INCREMENT * 2 in the
193 third case, and so on.
195 After this function is called, SUBREADER must not ever again
196 be referenced directly. It will be destroyed automatically
197 when the translating casereader is destroyed. */
199 casereader_create_arithmetic_sequence (struct casereader *subreader,
200 double first, double increment)
202 struct arithmetic_sequence *as = xzalloc (sizeof *as);
204 as->increment = increment;
205 return casereader_create_append_numeric (subreader, next_arithmetic,
212 struct casereader_append_rank
214 struct casereader *clone;
216 const struct variable *var;
217 const struct variable *weight;
218 struct caseproto *proto;
222 distinct_func *distinct;
224 enum rank_error *err;
228 static bool car_destroy (void *car_);
230 static struct ccase *car_translate (struct ccase *input, void *car_);
232 /* Creates and returns a new casereader whose cases are produced
233 by reading from SUBREADER and appending an additional value,
234 which is the rank of the observation. W is the weight variable
235 of the dictionary containing V, or NULL if there is no weight
238 The following preconditions must be met:
240 1. SUBREADER must be sorted on V.
242 2. The weight variables, must be non-negative.
244 If either of these preconditions are not satisfied, then the rank
245 variables may not be correct. In this case, if ERR is non-null,
246 it will be set according to the erroneous conditions encountered.
248 If DISTINCT_CALLBACK is non-null, then it will be called exactly
249 once for every case containing a distinct value of V. AUX is
250 an auxilliary pointer passed to DISTINCT_CALLBACK.
252 After this function is called, SUBREADER must not ever again
253 be referenced directly. It will be destroyed automatically
254 when the translating casereader is destroyed. */
256 casereader_create_append_rank (struct casereader *subreader,
257 const struct variable *v,
258 const struct variable *w,
259 enum rank_error *err,
260 distinct_func *distinct_callback,
264 struct casereader_append_rank *car = xmalloc (sizeof *car);
265 car->proto = caseproto_ref (casereader_get_proto (subreader));
266 car->proto = caseproto_add_width (car->proto, 0);
272 car->clone = casereader_clone (subreader);
273 car->distinct = distinct_callback;
276 car->prev_value = SYSMIS;
278 return casereader_create_translator (subreader, car->proto,
279 car_translate, car_destroy, car);
284 car_destroy (void *car_)
286 struct casereader_append_rank *car = car_;
287 casereader_destroy (car->clone);
288 caseproto_unref (car->proto);
293 static struct ccase *
294 car_translate (struct ccase *input, void *car_)
296 struct casereader_append_rank *car = car_;
298 const double value = case_data (input, car->var)->f;
300 if ( car->prev_value != SYSMIS)
302 if (car->err && value < car->prev_value)
303 *car->err |= RANK_ERR_UNSORTED;
306 if ( car->n_common == 1)
313 weight = case_data (input, car->weight)->f;
314 if ( car->err && weight < 0 )
315 *car->err |= RANK_ERR_NEGATIVE_WEIGHT;
320 struct ccase *c = casereader_peek (car->clone, car->n + ++k);
323 vxx = case_data (c, car->var)->f;
329 double w = case_data (c, car->weight)->f;
331 if ( car->err && w < 0 )
332 *car->err |= RANK_ERR_NEGATIVE_WEIGHT;
342 while (vxx == value);
343 car->mean_rank = car->cc + (weight + 1) / 2.0;
347 car->distinct (value, car->n_common, weight, car->aux);
354 input = case_unshare_and_resize (input, car->proto);
355 case_data_rw_idx (input, caseproto_get_n_widths (car->proto) - 1)->f
357 car->prev_value = value;