#include <config.h>
#include <data/val-type.h>
#include <data/casereader.h>
-#include <assert.h>
#include <stdlib.h>
#include <data/casereader-provider.h>
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
double cc;
distinct_func *distinct;
void *aux;
+ enum rank_error *err;
+ double prev_value;
};
static bool car_destroy (void *car_);
/* 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
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
)
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);
{
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)
{
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
{
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++;
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;
}