+ yaz_log(YLOG_LOG,"Normalizing client %d: scorefield=%d count=%d",
+ norm->num, norm->scorefield, norm->count);
+ 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;
+ // initial guesses for the parameters
+ if ( range < 1e-6 ) // practically zero
+ range = norm->max;
+ a = 1.0 / range;
+ b = abs(norm->min);
+ as = a / 3;
+ bs = b / 3;
+ chi = squaresum( norm->records, a,b);
+ while (it++ < 100) // safeguard against things not converging
+ {
+ // optimize a
+ double plus = squaresum(norm->records, a+as, b);
+ double minus= squaresum(norm->records, a-as, b);
+ if ( plus < chi && plus < minus )
+ {
+ a = a + as;
+ chi = plus;
+ }
+ else if ( minus < chi && minus < plus )
+ {
+ a = a - as;
+ chi = minus;
+ }
+ else
+ as = as / 2;
+ // optimize b
+ plus = squaresum(norm->records, a, b+bs);
+ minus= squaresum(norm->records, a, b-bs);
+ if ( plus < chi && plus < minus )
+ {
+ b = b + bs;
+ chi = plus;
+ }
+ else if ( minus < chi && minus < plus )
+ {
+ b = b - bs;
+ chi = minus;
+ }
+ else
+ bs = bs / 2;
+ yaz_log(YLOG_LOG,"Fitting it=%d: a=%f / %f b=%f / %f chi = %f",
+ it, a, as, b, bs, chi );
+ norm->a = a;
+ norm->b = b;
+ if ( abs(as) * 1000.0 < abs(a) &&
+ abs(bs) * 1000.0 < abs(b) )
+ break; // not changing much any more
+ }
+ }
+
+ if ( norm->scorefield != scorefield_none )
+ { // distribute the normalized scores to the records
+ struct norm_record *nr = norm->records;
+ for ( ; nr ; nr = nr->next ) {
+ double r = nr->score;
+ r = norm->a * r + norm -> b;
+ nr->clust->relevance_score = 10000 * r;
+ yaz_log(YLOG_LOG,"Normalized %f * %f + %f = %f",
+ nr->score, norm->a, norm->b, r );
+ // TODO - This keeps overwriting the cluster score in random order!
+ // Need to merge results better
+ }
+
+ }