RANK: Add support for temporary transformations.
authorBen Pfaff <blp@cs.stanford.edu>
Fri, 1 Feb 2013 06:02:08 +0000 (22:02 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Fri, 1 Feb 2013 06:02:08 +0000 (22:02 -0800)
Bug #37999.
Reported by Zoltan Fabian.

src/data/dataset.c
src/data/dataset.h
src/data/dictionary.c
src/data/dictionary.h
src/language/stats/rank.c
tests/language/stats/rank.at

index 26c3a49244783f4ff84a734d8c024d8470a2b6d0..9c3fe8cfecffc9003781836fe616bd3dc5858bf3 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011, 2013 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -805,6 +805,39 @@ proc_cancel_all_transformations (struct dataset *ds)
 
   return ok;
 }
+
+static int
+store_case_num (void *var_, struct ccase **cc, casenumber case_num)
+{
+  struct variable *var = var_;
+
+  *cc = case_unshare (*cc);
+  case_data_rw (*cc, var)->f = case_num;
+
+  return TRNS_CONTINUE;
+}
+
+/* Add a variable which we can sort by to get back the original order. */
+struct variable *
+add_permanent_ordering_transformation (struct dataset *ds)
+{
+  struct variable *temp_var;
+
+  temp_var = dict_create_var_assert (ds->dict, "$ORDER", 0);
+  if (proc_in_temporary_transformations (ds))
+    {
+      struct variable *perm_var;
+
+      perm_var = dict_clone_var_in_place_assert (ds->permanent_dict, temp_var);
+      trns_chain_append (ds->permanent_trns_chain, NULL, store_case_num,
+                         NULL, perm_var);
+      trns_chain_finalize (ds->permanent_trns_chain);
+    }
+  else
+    add_transformation (ds, store_case_num, NULL, temp_var);
+
+  return temp_var;
+}
 \f
 /* Causes output from the next procedure to be discarded, instead
    of being preserved for use as input for the next procedure. */
index 8445094713cdc38bb1eb9e9f72bf4309bf3e0013..ce8b980d2e69c1cbc6207bd7c3ce8dc3b77a3c23 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011, 2013 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -93,6 +93,7 @@ void proc_start_temporary_transformations (struct dataset *ds);
 bool proc_in_temporary_transformations (const struct dataset *ds);
 bool proc_make_temporary_transformations_permanent (struct dataset *ds);
 bool proc_cancel_temporary_transformations (struct dataset *ds);
+struct variable *add_permanent_ordering_transformation (struct dataset *);
 \f
 /* Procedures. */
 
index 024f97b3d5dd45b5d94d5778582456af30aa19c5..04c082fca7854a3513baa4553a43fbf788b4a75e 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -363,10 +363,13 @@ dict_get_vars_mutable (const struct dictionary *d, struct variable ***vars,
 }
 
 static struct variable *
-add_var (struct dictionary *d, struct variable *v)
+add_var_with_case_index (struct dictionary *d, struct variable *v,
+                         int case_index)
 {
   struct vardict_info *vardict;
 
+  assert (case_index >= d->next_value_idx);
+
   /* Update dictionary. */
   if (d->var_cnt >= d->var_cap)
     {
@@ -387,19 +390,25 @@ add_var (struct dictionary *d, struct variable *v)
   vardict->var = v;
   hmap_insert (&d->name_map, &vardict->name_node,
                utf8_hash_case_string (var_get_name (v), 0));
-  vardict->case_index = d->next_value_idx;
+  vardict->case_index = case_index;
   var_set_vardict (v, vardict);
 
   if ( d->changed ) d->changed (d, d->changed_data);
   if ( d->callbacks &&  d->callbacks->var_added )
     d->callbacks->var_added (d, var_get_dict_index (v), d->cb_data);
 
-  d->next_value_idx++;
   invalidate_proto (d);
+  d->next_value_idx = case_index + 1;
 
   return v;
 }
 
+static struct variable *
+add_var (struct dictionary *d, struct variable *v)
+{
+  return add_var_with_case_index (d, v, d->next_value_idx);
+}
+
 /* Creates and returns a new variable in D with the given NAME
    and WIDTH.  Returns a null pointer if the given NAME would
    duplicate that of an existing variable in the dictionary. */
@@ -468,6 +477,15 @@ dict_clone_var_as_assert (struct dictionary *d, const struct variable *old_var,
   return add_var (d, new_var);
 }
 
+struct variable *
+dict_clone_var_in_place_assert (struct dictionary *d,
+                                const struct variable *old_var)
+{
+  assert (dict_lookup_var (d, var_get_name (old_var)) == NULL);
+  return add_var_with_case_index (d, var_clone (old_var),
+                                  var_get_case_index (old_var));
+}
+
 /* Returns the variable named NAME in D, or a null pointer if no
    variable has that name. */
 struct variable *
index 4050756799b7f71591b180cd0ccc04e970b08044..c725d5a5a6d0d218ae06b953a88b208278c44aaa 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2004, 2007, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2007, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -64,6 +64,9 @@ struct variable *dict_clone_var_as_assert (struct dictionary *,
                                            const struct variable *,
                                            const char *);
 
+struct variable *dict_clone_var_in_place_assert (struct dictionary *,
+                                                 const struct variable *);
+
 /* Deleting variables. */
 void dict_delete_var (struct dictionary *, struct variable *);
 void dict_delete_vars (struct dictionary *,
index 19861cc0904e05aa7cf5635ac197bd7653c8706f..5f5591adb989fdd25b2c57bc7dc3a7239b4f0919 100644 (file)
@@ -589,22 +589,9 @@ rank_sorted_file (struct casereader *input,
 }
 
 
-/* Transformation function to enumerate all the cases */
-static int
-create_resort_key (void *key_var_, struct ccase **cc, casenumber case_num)
-{
-  struct variable *key_var = key_var_;
-
-  *cc = case_unshare (*cc);
-  case_data_rw (*cc, key_var)->f = case_num;
-
-  return TRNS_CONTINUE;
-}
-
 static bool
 rank_cmd (struct dataset *ds,  const struct rank *cmd);
 
-
 static const char *
 fraction_name (const struct rank *cmd)
 {
@@ -1000,11 +987,7 @@ rank_cmd (struct dataset *ds, const struct rank *cmd)
   bool ok = true;
   int i;
 
-  /* Add a variable which we can sort by to get back the original
-     order */
-  order_var = dict_create_var_assert (dataset_dict (ds), "$ORDER", 0);
-
-  add_transformation (ds, create_resort_key, 0, order_var);
+  order_var = add_permanent_ordering_transformation (ds);
 
   /* Create output files. */
   {
index 61c41805f7898b8bf96cac8708616254b2930147..45ca41aea016a0d30c050fda87327d46a3d1b2b3 100644 (file)
@@ -411,6 +411,62 @@ x,w,xl,xh,xc,Nx
 ])
 AT_CLEANUP
 
+AT_SETUP([RANK and TEMPORARY])
+AT_DATA([rank.sps], [dnl
+DATA LIST LIST NOTABLE /age (f2) gender (a1).
+BEGIN DATA.
+44 m
+32 f
+43 m
+49 m
+33 f
+35 f
+29 f
+50 m
+42 m
+33 f
+48 m
+END DATA.
+
+TEMPORARY.
+SELECT IF gender = 'm'.
+RANK age /RANK INTO Rm.
+
+TEMPORARY.
+SELECT IF gender = 'f'.
+RANK age /RANK INTO Rf.
+
+LIST.
+])
+AT_CHECK([pspp -O format=csv rank.sps], [0], [dnl
+Variables Created By RANK
+
+
+
+age into Rm(RANK of age)
+
+Variables Created By RANK
+
+
+
+age into Rf(RANK of age)
+
+Table: Data List
+age,gender,Rm,Rf
+44,m,3.000,.   @&t@
+32,f,.   ,2.000
+43,m,2.000,.   @&t@
+49,m,5.000,.   @&t@
+33,f,.   ,3.500
+35,f,.   ,5.000
+29,f,.   ,1.000
+50,m,6.000,.   @&t@
+42,m,1.000,.   @&t@
+33,f,.   ,3.500
+48,m,4.000,.   @&t@
+])
+AT_CLEANUP
+
 AT_SETUP([RANK variable name fallback])
 AT_DATA([rank.sps], [dnl
 DATA LIST LIST NOTABLE /foo * rfoo * ran003 *.