Added some error checking to casereader_create_append_rank
authorJohn Darrington <jmd@pc-188.(none)>
Mon, 15 Sep 2008 03:42:43 +0000 (11:42 +0800)
committerJohn Darrington <jmd@pc-188.(none)>
Mon, 15 Sep 2008 03:42:43 +0000 (11:42 +0800)
Thanks to Ben Pfaff for this suggestion.

src/data/casereader-translator.c
src/data/casereader.h

index 14fcd9ab70b6e3be60df6a585cfda094e48c844a..ae22f1297e19dbe5a12e6d9e2ec49f75ce8de087 100644 (file)
@@ -17,7 +17,6 @@
 #include <config.h>
 #include <data/val-type.h>
 #include <data/casereader.h>
 #include <config.h>
 #include <data/val-type.h>
 #include <data/casereader.h>
-#include <assert.h>
 #include <stdlib.h>
 
 #include <data/casereader-provider.h>
 #include <stdlib.h>
 
 #include <data/casereader-provider.h>
@@ -131,7 +130,7 @@ static void can_translate (struct ccase *input, struct ccase *output,
    by reading from SUBREADER and appending an additional value,
    generated by FUNC.  AUX is an optional parameter which
    gets passed to FUNC. FUNC will also receive N as it, which is
    by reading from SUBREADER and appending an additional value,
    generated by FUNC.  AUX is an optional parameter which
    gets passed to FUNC. FUNC will also receive N as it, which is
-   the ordinal number of the case in the reader.  DESTROY is an 
+   the ordinal number of the case in the reader.  DESTROY is an
    optional parameter used to destroy AUX.
 
    After this function is called, SUBREADER must not ever again
    optional parameter used to destroy AUX.
 
    After this function is called, SUBREADER must not ever again
@@ -226,6 +225,8 @@ struct casereader_append_rank
   double cc;
   distinct_func *distinct;
   void *aux;
   double cc;
   distinct_func *distinct;
   void *aux;
+  enum rank_error *err;
+  double prev_value;
 };
 
 static bool car_destroy (void *car_);
 };
 
 static bool car_destroy (void *car_);
@@ -235,9 +236,19 @@ static void car_translate (struct ccase *input, struct ccase *output,
 
 /* Creates and returns a new casereader whose cases are produced
    by reading from SUBREADER and appending an additional value,
 
 /* Creates and returns a new casereader whose cases are produced
    by reading from SUBREADER and appending an additional value,
-   which is the rank of the observation.  SUBREADER must be sorted
-   on V.  W is the weight variable of the dictionary containing V,
-   or NULL if there is no weight variable.
+   which is the rank of the observation.   W is the weight variable
+   of the dictionary containing V, or NULL if there is no weight
+   variable.
+
+   The following preconditions must be met:
+
+   1.    SUBREADER must be sorted on V.
+
+   2.    The weight variables, must be non-negative.
+
+   If either of these preconditions are not satisfied, then the rank
+   variables may not be correct.  In this case, if ERR is non-null,
+   it will be set according to the erroneous conditions encountered.
 
    If DISTINCT_CALLBACK is non-null, then  it will be called exactly
    once for every case containing a distinct value of V.  AUX is
 
    If DISTINCT_CALLBACK is non-null, then  it will be called exactly
    once for every case containing a distinct value of V.  AUX is
@@ -250,6 +261,7 @@ struct casereader *
 casereader_create_append_rank (struct casereader *subreader,
                               const struct variable *v,
                               const struct variable *w,
 casereader_create_append_rank (struct casereader *subreader,
                               const struct variable *v,
                               const struct variable *w,
+                              enum rank_error *err,
                               distinct_func *distinct_callback,
                               void *aux
                               )
                               distinct_func *distinct_callback,
                               void *aux
                               )
@@ -264,6 +276,8 @@ casereader_create_append_rank (struct casereader *subreader,
   car->clone = casereader_clone (subreader);
   car->distinct = distinct_callback;
   car->aux = aux;
   car->clone = casereader_clone (subreader);
   car->distinct = distinct_callback;
   car->aux = aux;
+  car->err = err;
+  car->prev_value = SYSMIS;
 
   return casereader_create_translator (subreader, car->value_ofs + 1,
                                        car_translate, car_destroy, car);
 
   return casereader_create_translator (subreader, car->value_ofs + 1,
                                        car_translate, car_destroy, car);
@@ -285,7 +299,13 @@ car_translate (struct ccase *input, struct ccase *output,  void *car_)
 {
   struct casereader_append_rank *car = car_;
 
 {
   struct casereader_append_rank *car = car_;
 
-  double value = case_data (input, car->var)->f;
+  const double value = case_data (input, car->var)->f;
+
+  if ( car->prev_value != SYSMIS)
+    {
+      if (car->err && value < car->prev_value)
+       *car->err |= RANK_ERR_UNSORTED;
+    }
 
   if ( car->n_common == 1)
     {
 
   if ( car->n_common == 1)
     {
@@ -293,7 +313,11 @@ car_translate (struct ccase *input, struct ccase *output,  void *car_)
       casenumber k = 0;
       double weight = 1.0;
       if (car->weight)
       casenumber k = 0;
       double weight = 1.0;
       if (car->weight)
-       weight = case_data (input, car->weight)->f;
+       {
+         weight = case_data (input, car->weight)->f;
+         if ( car->err && weight < 0 )
+           *car->err |= RANK_ERR_NEGATIVE_WEIGHT;
+       }
 
       do
        {
 
       do
        {
@@ -305,7 +329,14 @@ car_translate (struct ccase *input, struct ccase *output,  void *car_)
          if ( vxx == value)
            {
              if (car->weight)
          if ( vxx == value)
            {
              if (car->weight)
-               weight += case_data (&c, car->weight)->f;
+               {
+                 double w = case_data (&c, car->weight)->f;
+
+                 if ( car->err && w < 0 )
+                   *car->err |= RANK_ERR_NEGATIVE_WEIGHT;
+
+                 weight += w;
+               }
              else
                weight += 1.0;
              car->n_common++;
              else
                weight += 1.0;
              car->n_common++;
@@ -328,6 +359,7 @@ car_translate (struct ccase *input, struct ccase *output,  void *car_)
   case_move (output, input);
   case_resize (output, car->value_ofs + 1);
   case_data_rw_idx (output, car->value_ofs)->f = car->mean_rank ;
   case_move (output, input);
   case_resize (output, car->value_ofs + 1);
   case_data_rw_idx (output, car->value_ofs)->f = car->mean_rank ;
+  car->prev_value = value;
 }
 
 
 }
 
 
index a2d9403bb03bce10ede5a638f459261889d373ad..3df80cb08fb8d38acc302e0654a0217dd666287a 100644 (file)
@@ -125,12 +125,20 @@ struct casereader *
 casereader_create_arithmetic_sequence (struct casereader *,
                                        double first, double increment);
 
 casereader_create_arithmetic_sequence (struct casereader *,
                                        double first, double increment);
 
+enum rank_error
+  {
+    RANK_ERR_NONE = 0,
+    RANK_ERR_NEGATIVE_WEIGHT = 0x01,
+    RANK_ERR_UNSORTED = 0x02
+  };
+
 
 typedef void distinct_func (double v, casenumber n, double w, void *aux);
 
 struct casereader *
 casereader_create_append_rank (struct casereader *,
                               const struct variable *v, const struct variable *w,
 
 typedef void distinct_func (double v, casenumber n, double w, void *aux);
 
 struct casereader *
 casereader_create_append_rank (struct casereader *,
                               const struct variable *v, const struct variable *w,
+                              enum rank_error *err,
                               distinct_func *distinct_callback, void *aux);
 
 
                               distinct_func *distinct_callback, void *aux);