+ struct record_metadata *md = record->metadata[norm->scorefield];
+ rp->score = md->data.fnumber;
+ }
+ yaz_log(YLOG_LOG,"Got score for %d/%d : %f ",
+ norm->num, record->position, rp->score );
+ record -> score = rp->score;
+ if ( norm->count == 1 )
+ {
+ norm->max = rp->score;
+ norm->min = rp->score;
+ } else {
+ if ( rp->score > norm->max )
+ norm->max = rp->score;
+ if ( rp->score < norm->min )
+ norm->min = rp->score;
+ }
+ }
+}
+
+// Calculate the squared sum of residuals, that is the difference from
+// normalized values to the target curve, which is 1/n
+static double squaresum( struct norm_record *rp, double a, double b)
+{
+ double sum = 0.0;
+ for ( ; rp; rp = rp->next )
+ {
+ double target = 1.0 / rp->record->position;
+ double normscore = rp->score * a + b;
+ double diff = target - normscore;
+ sum += diff * diff;
+ }
+ return sum;
+}
+
+// For each client, normalize scores
+static void normalize_scores(struct relevance *rel)
+{
+ const int maxiterations = 1000;
+ const double enough = 100.0; // sets the number of decimals we are happy with
+ const double stepchange = 0.5; // reduction of the step size when finding middle
+ // 0.5 sems to be magical, much better than 0.4 or 0.6
+ struct norm_client *norm;
+ for ( norm = rel->norm; norm; norm = norm->next )
+ {
+ yaz_log(YLOG_LOG,"Normalizing client %d: scorefield=%d count=%d range=%f %f = %f",
+ norm->num, norm->scorefield, norm->count, norm->min,
+ norm->max, norm->max-norm->min);
+ norm->a = 1.0; // default normalizing factors, no change
+ norm->b = 0.0;
+ if ( norm->scorefield != scorefield_none &&
+ norm->scorefield != scorefield_position )
+ { // have something to normalize
+ double range = norm->max - norm->min;
+ int it = 0;
+ double a,b; // params to optimize
+ double as,bs; // step sizes
+ double chi;
+ char *branch = "?";
+ // initial guesses for the parameters
+ // Rmax = a * rmax + b # want to be 1.0
+ // Rmin = a * rmin + b # want to be 0.0
+ // Rmax - Rmin = a ( rmax - rmin ) # subtracting equations
+ // 1.0 - 0.0 = a ( rmax - rmin )
+ // a = 1 / range
+ // Rmin = a * rmin + b
+ // b = Rmin - a * rmin
+ // = 0.0 - 1/range * rmin
+ // = - rmin / range
+
+ if ( range < 1e-6 ) // practically zero
+ range = norm->max;
+ a = 1.0 / range;
+ b = -1.0 * norm->min / range;
+ // b = fabs(norm->min) / range;
+ as = a / 10;
+ bs = fabs(b) / 10;
+ chi = squaresum( norm->records, a,b);
+ yaz_log(YLOG_LOG,"Initial done: it=%d: a=%f / %f b=%f / %f chi = %f",
+ 0, a, as, b, bs, chi );
+ while (it++ < maxiterations) // safeguard against things not converging