1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
33 #include "debug-print.h"
35 /* FIXME: This module is less than ideally efficient, both in space
36 and time. If anyone cares, it would be a good project. */
38 /* FIXME: Implement PRINT subcommand. */
40 /* Explains how to recode one value. `from' must be first element. */
43 union value from; /* Original value. */
44 double to; /* Recoded value. */
47 /* Explains how to recode an AUTORECODE variable. */
50 struct variable *src; /* Source variable. */
51 struct variable *dest; /* Target variable. */
52 struct hsh_table *items; /* Hash table of `freq's. */
55 /* AUTORECODE transformation. */
56 struct autorecode_trns
59 struct pool *owner; /* Contains AUTORECODE specs. */
60 struct arc_spec *arc; /* AUTORECODE specifications. */
61 int n_arc; /* Number of specifications. */
64 /* Source and target variables, hash table translator. */
65 static struct variable **v_src;
66 static struct variable **v_dest;
67 static struct hsh_table **h_trans;
70 /* Pool for allocation of hash table entries. */
71 static struct pool *hash_pool;
77 static int autorecode_trns_proc (struct trns_header *, struct ccase *);
78 static void autorecode_trns_free (struct trns_header *);
79 static int autorecode_proc_func (struct ccase *);
80 static hsh_compare_func compare_alpha_value, compare_numeric_value;
81 static hsh_hash_func hash_alpha_value, hash_numeric_value;
82 static void recode (void);
84 /* Performs the AUTORECODE procedure. */
98 lex_match_id ("AUTORECODE");
99 lex_match_id ("VARIABLES");
101 if (!parse_variables (default_dict, &v_src, &nv_src, PV_NO_DUPLICATE))
103 if (!lex_force_match_id ("INTO"))
106 if (!parse_DATA_LIST_vars (&n_dest, &nv_dest, PV_NONE))
108 if (nv_dest != nv_src)
110 msg (SE, _("Number of source variables (%d) does not match number "
111 "of target variables (%d)."), nv_src, nv_dest);
114 while (lex_match ('/'))
115 if (lex_match_id ("DESCENDING"))
117 else if (lex_match_id ("PRINT"))
121 lex_error (_("expecting end of command"));
125 for (i = 0; i < nv_dest; i++)
129 if (dict_lookup_var (default_dict, n_dest[i]) != NULL)
131 msg (SE, _("Target variable %s duplicates existing variable %s."),
132 n_dest[i], n_dest[i]);
135 for (j = 0; j < i; j++)
136 if (!strcmp (n_dest[i], n_dest[j]))
138 msg (SE, _("Duplicate variable name %s among target variables."),
144 hash_pool = pool_create ();
146 v_dest = xmalloc (sizeof *v_dest * nv_dest);
147 h_trans = xmalloc (sizeof *h_trans * nv_dest);
148 for (i = 0; i < nv_dest; i++)
149 if (v_src[i]->type == ALPHA)
150 h_trans[i] = hsh_create (10, compare_alpha_value,
151 hash_alpha_value, NULL, v_src[i]);
153 h_trans[i] = hsh_create (10, compare_numeric_value,
154 hash_numeric_value, NULL, NULL);
156 procedure (NULL, autorecode_proc_func, NULL);
158 for (i = 0; i < nv_dest; i++)
160 v_dest[i] = dict_create_var (default_dict, n_dest[i], 0);
161 assert (v_dest[i] != NULL);
175 for (i = 0; i < nv_src; i++)
176 hsh_destroy (h_trans[i]);
177 for (i = 0; i < nv_dest; i++)
184 /* AUTORECODE transformation. */
189 struct autorecode_trns *t;
190 struct pool *arc_pool;
193 arc_pool = pool_create ();
194 t = xmalloc (sizeof *t);
195 t->h.proc = autorecode_trns_proc;
196 t->h.free = autorecode_trns_free;
198 t->arc = pool_alloc (arc_pool, sizeof *t->arc * nv_src);
200 for (i = 0; i < nv_src; i++)
202 struct arc_spec *spec = &t->arc[i];
203 void **p = hsh_sort (h_trans[i]);
204 int count = hsh_count (h_trans[i]);
207 spec->src = v_src[i];
208 spec->dest = v_dest[i];
210 if (v_src[i]->type == ALPHA)
211 spec->items = hsh_create (2 * count, compare_alpha_value,
212 hash_alpha_value, NULL, v_src[i]);
214 spec->items = hsh_create (2 * count, compare_numeric_value,
215 hash_numeric_value, NULL, NULL);
217 for (j = 0; *p; p++, j++)
219 struct arc_item *item = pool_alloc (arc_pool, sizeof *item);
220 union value *vp = *p;
222 if (v_src[i]->type == NUMERIC)
223 item->from.f = vp->f;
225 item->from.c = pool_strdup (arc_pool, vp->c);
226 item->to = !descend ? j + 1 : count - j;
227 hsh_force_insert (spec->items, item);
230 hsh_destroy (h_trans[i]);
233 pool_destroy (hash_pool);
234 add_transformation ((struct trns_header *) t);
238 autorecode_trns_proc (struct trns_header * trns, struct ccase * c)
240 struct autorecode_trns *t = (struct autorecode_trns *) trns;
243 for (i = 0; i < t->n_arc; i++)
245 struct arc_spec *spec = &t->arc[i];
246 struct arc_item *item;
248 if (spec->src->type == NUMERIC)
249 item = hsh_force_find (spec->items, &c->data[spec->src->fv].f);
253 v.c = c->data[spec->src->fv].s;
254 item = hsh_force_find (spec->items, &v);
257 c->data[spec->dest->fv].f = item->to;
263 autorecode_trns_free (struct trns_header * trns)
265 struct autorecode_trns *t = (struct autorecode_trns *) trns;
268 for (i = 0; i < t->n_arc; i++)
269 hsh_destroy (t->arc[i].items);
270 pool_destroy (t->owner);
273 /* AUTORECODE procedure. */
276 compare_alpha_value (const void *a_, const void *b_, void *v_)
278 const union value *a = a_;
279 const union value *b = b_;
280 const struct variable *v = v_;
282 return memcmp (a->c, b->c, v->width);
286 hash_alpha_value (const void *a_, void *v_)
288 const union value *a = a_;
289 const struct variable *v = v_;
291 return hsh_hash_bytes (a->c, v->width);
295 compare_numeric_value (const void *a_, const void *b_, void *foo unused)
297 const union value *a = a_;
298 const union value *b = b_;
300 return a->f < b->f ? -1 : a->f > b->f;
304 hash_numeric_value (const void *a_, void *foo unused)
306 const union value *a = a_;
308 return hsh_hash_double (a->f);
312 autorecode_proc_func (struct ccase * c)
316 for (i = 0; i < nv_src; i++)
322 if (v_src[i]->type == NUMERIC)
324 v.f = c->data[v_src[i]->fv].f;
325 vpp = (union value **) hsh_probe (h_trans[i], &v);
328 vp = pool_alloc (hash_pool, sizeof (union value));
335 v.c = c->data[v_src[i]->fv].s;
336 vpp = (union value **) hsh_probe (h_trans[i], &v);
339 vp = pool_alloc (hash_pool, sizeof (union value));
340 vp->c = pool_strndup (hash_pool, v.c, v_src[i]->width);