#ifdef RCSID static char rcsid[] = "$Header: /home/smart/release/src/libevaluate/trvec_trec_eval.c,v 11.0 1992/07/21 18:20:35 chrisb Exp chrisb $"; #endif /* Copyright (c) 2005 */ #include "common.h" #include "sysfunc.h" #include "smart_error.h" #include "tr_vec.h" #include "trec_eval.h" static int compare_iter_rank(); static void calc_cutoff_measures(EVAL_PARAM_INFO *epi, TR_VEC *tr_vec, TREC_EVAL *eval, long num_rel, long num_nonrel); static void calc_bpref_measures(EVAL_PARAM_INFO *epi, TR_VEC *tr_vec, TREC_EVAL *eval, long num_rel, long num_nonrel); static void calc_average_measures(EVAL_PARAM_INFO *epi, TR_VEC *tr_vec, TREC_EVAL *eval, long num_rel, long num_nonrel); static void calc_exact_measures(EVAL_PARAM_INFO *epi, TR_VEC *tr_vec, TREC_EVAL *eval, long num_rel, long num_nonrel); static void calc_time_measures(EVAL_PARAM_INFO *epi, TR_VEC *tr_vec, TREC_EVAL *eval, long num_rel, long num_nonrel); int trvec_trec_eval (epi, tr_vec, eval, num_rel, num_nonrel) EVAL_PARAM_INFO *epi; TR_VEC *tr_vec; TREC_EVAL *eval; long num_rel; /* Number relevant judged */ long num_nonrel; /* Number nonrelevant judged */ { long j; long max_iter; if (tr_vec == (TR_VEC *) NULL) return (UNDEF); /* Initialize everything to 0 */ bzero ((char *) eval, sizeof (TREC_EVAL)); eval->qid = tr_vec->qid; eval->num_queries = 1; /* If no retrieved docs, then just return */ if (tr_vec->num_tr == 0) { return (0); } eval->num_rel = num_rel; /* Evaluate only the docs on the last iteration of new_tr_vec */ /* Sort the tr tuples for this query by decreasing iter and increasing rank */ qsort ((char *) tr_vec->tr, (int) tr_vec->num_tr, sizeof (TR_TUP), compare_iter_rank); max_iter = tr_vec->tr[0].iter; for (j = 0; j < tr_vec->num_tr; j++) { if (tr_vec->tr[j].iter == max_iter) { eval->num_ret++; if (tr_vec->tr[j].rel >= epi->relevance_level) eval->num_rel_ret++; } else { if (tr_vec->tr[j].rel >= epi->relevance_level) eval->num_rel--; } } /* Calculate cutoff measures, and those measures dependant on them */ /* Also includes recip_rank and rank_first_rel */ calc_cutoff_measures (epi, tr_vec, eval, num_rel, num_nonrel); /* Calculate bpref and related measures (judged docs only) */ calc_bpref_measures (epi, tr_vec, eval, num_rel, num_nonrel); /* Calculate measures that average over ret or rel docs */ calc_average_measures (epi, tr_vec, eval, num_rel, num_nonrel); /* Calculate exact measures over entire retrieved sets */ calc_exact_measures (epi, tr_vec, eval, num_rel, num_nonrel); /* Calculate time measures, if wanted */ if (epi->time_flag) calc_time_measures (epi, tr_vec, eval, num_rel, num_nonrel); return (1); } static int compare_iter_rank (tr1, tr2) TR_TUP *tr1; TR_TUP *tr2; { if (tr1->iter > tr2->iter) return (-1); if (tr1->iter < tr2->iter) return (1); if (tr1->rank < tr2->rank) return (-1); if (tr1->rank > tr2->rank) return (1); return (0); } /* ********************************************************************* */ /* calculate cutoff measures */ /* cutoff values for recall precision output */ static int cutoff[NUM_CUTOFF] = CUTOFF_VALUES; static int three_pts[3] = THREE_PTS; static void calc_cutoff_measures(epi, tr_vec, eval, num_rel, num_nonrel) EVAL_PARAM_INFO *epi; TR_VEC *tr_vec; TREC_EVAL *eval; long num_rel; /* Number relevant judged */ long num_nonrel; /* Number nonrelevant judged */ { double recall, precis; /* current recall, precision values */ double rel_precis, rel_uap;/* relative precision, uap values */ double int_precis; /* current interpolated precision values */ long i,j; long cut_rp[NUM_RP_PTS]; /* number of rel docs needed to be retrieved for each recall-prec cutoff */ long cut_fr[NUM_FR_PTS]; /* number of non-rel docs needed to be retrieved for each fall-recall cutoff */ long cut_rprec[NUM_PREC_PTS]; /* Number of docs needed to be retrieved for each R-based prec cutoff */ long current_cutoff, current_cut_rp, current_cut_fr, current_cut_rprec; long rel_so_far = eval->num_rel_ret; /* Note for interpolated precision values (Prec(X) = MAX (PREC(Y)) for all Y >= X) */ int_precis = (float) rel_so_far / (float) eval->num_ret; /* Discover cutoff values for this query */ current_cutoff = NUM_CUTOFF - 1; while (current_cutoff > 0 && cutoff[current_cutoff] > eval->num_ret) current_cutoff--; for (i = 0; i < NUM_RP_PTS; i++) cut_rp[i] = ((eval->num_rel * i) + NUM_RP_PTS - 2) / (NUM_RP_PTS - 1); current_cut_rp = NUM_RP_PTS - 1; while (current_cut_rp > 0 && cut_rp[current_cut_rp] > eval->num_rel_ret) current_cut_rp--; for (i = 0; i < NUM_FR_PTS; i++) cut_fr[i] = ((MAX_FALL_RET * i) + NUM_FR_PTS - 2) / (NUM_FR_PTS - 1); current_cut_fr = NUM_FR_PTS - 1; while (current_cut_fr > 0 && cut_fr[current_cut_fr] > eval->num_ret - eval->num_rel_ret) current_cut_fr--; for (i = 1; i < NUM_PREC_PTS+1; i++) cut_rprec[i-1] = ((MAX_RPREC * eval->num_rel * i) + NUM_PREC_PTS - 2) / (NUM_PREC_PTS - 1); current_cut_rprec = NUM_PREC_PTS - 1; while (current_cut_rprec > 0 && cut_rprec[current_cut_rprec]>eval->num_ret) current_cut_rprec--; /* Loop over all retrieved docs in reverse order */ for (j = eval->num_ret; j > 0; j--) { if (rel_so_far > 0) { recall = (float) rel_so_far / (float) eval->num_rel; precis = (float) rel_so_far / (float) j; if (j > eval->num_rel) { rel_precis = (float) rel_so_far / (float) eval->num_rel; } else { rel_precis = (float) rel_so_far / (float) j; } } else { recall = 0.0; precis = 0.0; rel_precis = 0.0; } rel_uap = rel_precis * rel_precis; if (int_precis < precis) int_precis = precis; while (j == cutoff[current_cutoff]) { eval->recall_cut[current_cutoff] = recall; eval->precis_cut[current_cutoff] = precis; eval->rel_precis_cut[current_cutoff] = rel_precis; eval->uap_cut[current_cutoff] = precis * recall; eval->rel_uap_cut[current_cutoff] = rel_uap; current_cutoff--; } while (j == cut_rprec[current_cut_rprec]) { eval->R_prec_cut[current_cut_rprec] = precis; eval->int_R_prec_cut[current_cut_rprec] = int_precis; current_cut_rprec--; } if (j == eval->num_rel) { eval->R_recall_precis = precis; eval->int_R_recall_precis = int_precis; } if (tr_vec->tr[j-1].rel >= epi->relevance_level) { while (rel_so_far == cut_rp[current_cut_rp]) { eval->int_recall_precis[current_cut_rp] = int_precis; current_cut_rp--; } eval->recip_rank = 1.0 / (float) j; eval->rank_first_rel = j; rel_so_far--; } else { /* Note: for fallout-recall, the recall at X non-rel docs is used for the recall 'after' (X-1) non-rel docs. Ie. recall_used(X-1 non-rel docs) = MAX (recall(Y)) for Y retrieved docs where X-1 non-rel retrieved */ while (current_cut_fr >= 0 && j - rel_so_far == cut_fr[current_cut_fr] + 1) { eval->fall_recall[current_cut_fr] = recall; current_cut_fr--; } } } /* Fill in the 0.0 value for recall-precision (== max precision at any point in the retrieval ranking) */ eval->int_recall_precis[0] = int_precis; /* Fill in those cutoff values and averages that were not achieved because insufficient docs were retrieved. */ for (i = 0; i < NUM_CUTOFF; i++) { if (eval->num_ret < cutoff[i]) { if (eval->num_rel_ret > 0) { eval->recall_cut[i] = ((float) eval->num_rel_ret / (float) eval->num_rel); eval->precis_cut[i] = ((float) eval->num_rel_ret / (float) cutoff[i]); } eval->rel_precis_cut[i] = (cutoff[i] < eval->num_rel) ? eval->precis_cut[i] : eval->recall_cut[i]; eval->uap_cut[i] = eval->precis_cut[i] * eval->recall_cut[i]; eval->rel_uap_cut[i] = eval->precis_cut[i] * eval->precis_cut[i]; } } for (i = 0; i < NUM_FR_PTS; i++) { if (eval->num_ret - eval->num_rel_ret < cut_fr[i]) { if (eval->num_rel_ret > 0) eval->fall_recall[i] = (float) eval->num_rel_ret / (float) eval->num_rel; } } for (i = 0; i < NUM_PREC_PTS; i++) { if (eval->num_ret < cut_rprec[i]) { eval->R_prec_cut[i] = (float) eval->num_rel_ret / (float) cut_rprec[i]; eval->int_R_prec_cut[i] = (float) eval->num_rel_ret / (float) cut_rprec[i]; } } if (eval->num_rel > eval->num_ret) { eval->R_recall_precis = (float) eval->num_rel_ret / (float)eval->num_rel; eval->int_R_recall_precis = (float) eval->num_rel_ret / (float)eval->num_rel; } /* Calculate other indirect evaluation measure averages. */ /* average recall-precis of 3 and 11 intermediate points */ eval->int_av3_recall_precis = (eval->int_recall_precis[three_pts[0]] + eval->int_recall_precis[three_pts[1]] + eval->int_recall_precis[three_pts[2]]) / 3.0; for (i = 0; i < NUM_RP_PTS; i++) { eval->int_av11_recall_precis += eval->int_recall_precis[i]; } eval->int_av11_recall_precis /= NUM_RP_PTS; } static void calc_bpref_measures (epi, tr_vec, eval, num_rel, num_nonrel) EVAL_PARAM_INFO *epi; TR_VEC *tr_vec; TREC_EVAL *eval; long num_rel; /* Number relevant judged */ long num_nonrel; /* Number nonrelevant judged */ { long j; long nonrel_ret; long nonrel_so_far, rel_so_far, pool_unjudged_so_far; long bounded_5R_nonrel_so_far, bounded_10R_nonrel_so_far; long pref_top_nonrel_num = PREF_TOP_NONREL_NUM; long pref_top_50pRnonrel_num; long pref_top_25pRnonrel_num; long pref_top_25p2Rnonrel_num; long pref_top_10pRnonrel_num; long pref_top_Rnonrel_num; /* Calculate judgement based measures (dependent on only judged docs; no assumption of non-relevance if not judged) */ /* Binary Preference measures; here expressed as all docs with a higher value of rel are to be preferred. Optimize by keeping track of nonrel seen so far */ pref_top_nonrel_num = PREF_TOP_NONREL_NUM; pref_top_50pRnonrel_num = 50 + eval->num_rel; pref_top_25pRnonrel_num = 25 + eval->num_rel; pref_top_10pRnonrel_num = 10 + eval->num_rel; pref_top_Rnonrel_num = eval->num_rel; pref_top_25p2Rnonrel_num = 25 + (2 * eval->num_rel); nonrel_ret = 0; for (j = 0; j < tr_vec->num_tr; j++) { if (tr_vec->tr[j].rel >= 0 && tr_vec->tr[j].rel < epi->relevance_level) nonrel_ret++; } nonrel_so_far = 0; rel_so_far = 0; pool_unjudged_so_far = 0; bounded_5R_nonrel_so_far = 0; bounded_10R_nonrel_so_far = 0; for (j = 0; j < tr_vec->num_tr; j++) { if (tr_vec->tr[j].rel == RELVALUE_NONPOOL) /* document not in pool. Skip */ continue; if (tr_vec->tr[j].rel == RELVALUE_UNJUDGED) { /* document in pool but unjudged. */ pool_unjudged_so_far++; continue; } if (tr_vec->tr[j].rel >= 0 && tr_vec->tr[j].rel < epi->relevance_level) { /* Judged Nonrel document */ if (nonrel_so_far < 5 * eval->num_rel) { bounded_5R_nonrel_so_far++; if (nonrel_so_far < 10 * eval->num_rel) { bounded_10R_nonrel_so_far++; } } nonrel_so_far++; } else { /* Judged Rel doc */ rel_so_far++; /* Add fraction of correct preferences. */ /* Special case nonrel_so_far == 0 to avoid division by 0 */ if (nonrel_so_far > 0) { eval->bpref_allnonrel += 1.0 - (((float) nonrel_so_far) / (float) num_nonrel); eval->bpref_retnonrel += 1.0 - (((float) nonrel_so_far) / (float) nonrel_ret); eval->bpref_retall += 1.0 - (((float) nonrel_so_far) / (float) nonrel_ret); eval->bpref_num_correct += MIN (num_nonrel, pref_top_Rnonrel_num) - MIN (nonrel_so_far, pref_top_Rnonrel_num); eval->bpref += 1.0 - (((float) MIN (nonrel_so_far, pref_top_Rnonrel_num)) / (float) MIN (num_nonrel, pref_top_Rnonrel_num)); eval->old_bpref += 1.0 - (((float) MIN (nonrel_so_far, pref_top_Rnonrel_num)) / (float) MIN (nonrel_ret, pref_top_Rnonrel_num)); eval->bpref_topnonrel += 1.0 - (((float) MIN (nonrel_so_far, pref_top_nonrel_num)) / (float) MIN (num_nonrel, pref_top_nonrel_num)); eval->bpref_top50pRnonrel += 1.0 - (((float) MIN (nonrel_so_far, pref_top_50pRnonrel_num)) / (float) MIN (num_nonrel, pref_top_50pRnonrel_num)); eval->bpref_top25pRnonrel += 1.0 - (((float) MIN (nonrel_so_far, pref_top_25pRnonrel_num)) / (float) MIN (num_nonrel, pref_top_25pRnonrel_num)); eval->bpref_top10pRnonrel += 1.0 - (((float) MIN (nonrel_so_far, pref_top_10pRnonrel_num)) / (float) MIN (num_nonrel, pref_top_10pRnonrel_num)); eval->old_bpref_top10pRnonrel += 1.0 - (((float) MIN (nonrel_so_far, pref_top_10pRnonrel_num)) / (float) MIN (nonrel_ret, pref_top_10pRnonrel_num)); eval->bpref_top25p2Rnonrel += 1.0 - (((float) MIN (nonrel_so_far, pref_top_25p2Rnonrel_num)) / (float) MIN (num_nonrel, pref_top_25p2Rnonrel_num)); if (rel_so_far <= 5 && nonrel_so_far < 5) eval->bpref_5 += 1.0 - (float) nonrel_so_far / (float) MIN (num_nonrel, 5); if (rel_so_far <= 10 && nonrel_so_far < 10) eval->bpref_10 += 1.0 - (float) nonrel_so_far / (float) MIN (num_nonrel, 10); } else { eval->bpref += 1.0; eval->old_bpref += 1.0; eval->bpref_allnonrel += 1.0; eval->bpref_retnonrel += 1.0; eval->bpref_retall += 1.0; eval->bpref_topnonrel += 1.0; eval->bpref_top50pRnonrel += 1.0; eval->bpref_top25pRnonrel += 1.0; eval->bpref_top10pRnonrel += 1.0; eval->old_bpref_top10pRnonrel += 1.0; eval->bpref_top25p2Rnonrel += 1.0; if (rel_so_far <= 5) eval->bpref_5 += 1.0; if (rel_so_far <= 10) eval->bpref_10 += 1.0; } eval->bpref_top5Rnonrel += 1.0 - (((float) bounded_5R_nonrel_so_far) / (float) MIN (num_nonrel, eval->num_rel * 5)); eval->bpref_top10Rnonrel += 1.0 - (((float) bounded_10R_nonrel_so_far) / (float) MIN (num_nonrel, eval->num_rel * 10)); eval->bpref_num_all += num_nonrel - nonrel_so_far; eval->bpref_num_ret += nonrel_ret - nonrel_so_far; /* inf_ap */ if (0 == j) eval->inf_ap += 1.0; else { float fj = (float) j; eval->inf_ap += 1.0 / (fj+1.0) + (fj / (fj+1.0)) * ((rel_so_far-1+nonrel_so_far+pool_unjudged_so_far) / fj) * ((rel_so_far-1 + INFAP_EPSILON) / (rel_so_far-1 + nonrel_so_far + 2 * INFAP_EPSILON)); } } } if (eval->num_rel) { eval->bpref /= eval->num_rel; eval->old_bpref /= eval->num_rel; eval->bpref_allnonrel /= eval->num_rel; eval->bpref_retnonrel /= eval->num_rel; eval->bpref_topnonrel /= eval->num_rel; eval->bpref_top5Rnonrel /= eval->num_rel; eval->bpref_top10Rnonrel /= eval->num_rel; eval->bpref_top50pRnonrel /= eval->num_rel; eval->bpref_top25pRnonrel /= eval->num_rel; eval->bpref_top10pRnonrel /= eval->num_rel; eval->old_bpref_top10pRnonrel /= eval->num_rel; eval->bpref_top25p2Rnonrel /= eval->num_rel; if (eval->num_rel_ret) { eval->bpref_retall /= eval->num_rel_ret; eval->bpref_5 /= MIN (rel_so_far, 5); eval->bpref_10 /= MIN (rel_so_far, 10); } eval->bpref_num_possible = eval->num_rel * MIN (num_nonrel, pref_top_Rnonrel_num); eval->inf_ap /= eval->num_rel; } eval->num_nonrel_judged_ret = nonrel_ret; /* For those bpref measure variants which use the geometric mean instead of straight averages, compute them here. Original measure value is constrained to be greater than MIN_GEO_MEAN (for time being .00001, since trec_eval prints to four significant digits) */ eval->gm_bpref = (float) log ((double)(MAX (eval->bpref, MIN_GEO_MEAN))); } static void calc_average_measures (epi, tr_vec, eval, num_rel, num_nonrel) EVAL_PARAM_INFO *epi; TR_VEC *tr_vec; TREC_EVAL *eval; long num_rel; /* Number relevant judged */ long num_nonrel; /* Number nonrelevant judged */ { double recall, precis; /* current recall, precision values */ double rel_precis, rel_uap;/* relative precision, uap values */ double int_precis; /* current interpolated precision values */ long i,j; long rel_so_far; /* Note for interpolated precision values (Prec(X) = MAX (PREC(Y)) for all Y >= X) */ rel_so_far = eval->num_rel_ret; int_precis = (float) rel_so_far / (float) eval->num_ret; /* Loop over all retrieved docs in reverse order */ for (j = eval->num_ret; j > 0; j--) { if (rel_so_far > 0) { recall = (float) rel_so_far / (float) eval->num_rel; precis = (float) rel_so_far / (float) j; if (j > eval->num_rel) { rel_precis = (float) rel_so_far / (float) eval->num_rel; } else { rel_precis = (float) rel_so_far / (float) j; } } else { recall = 0.0; precis = 0.0; rel_precis = 0.0; } rel_uap = rel_precis * rel_precis; if (int_precis < precis) int_precis = precis; eval->av_rel_precis += rel_precis; eval->av_rel_uap += rel_uap; if (j < eval->num_rel) { eval->av_R_precis += precis; eval->int_av_R_precis += int_precis; } if (tr_vec->tr[j-1].rel >= epi->relevance_level) { eval->int_av_recall_precis += int_precis; eval->av_recall_precis += precis; eval->avg_doc_prec += precis; rel_so_far--; } else { /* Note: for fallout-recall, the recall at X non-rel docs is used for the recall 'after' (X-1) non-rel docs. Ie. recall_used(X-1 non-rel docs) = MAX (recall(Y)) for Y retrieved docs where X-1 non-rel retrieved */ if (j - rel_so_far < MAX_FALL_RET) { eval->av_fall_recall += recall; } } } if (eval->num_ret - eval->num_rel_ret < MAX_FALL_RET) { if (eval->num_rel_ret > 0) eval->av_fall_recall += ((MAX_FALL_RET - (eval->num_ret - eval->num_rel_ret)) * ((float)eval->num_rel_ret / (float)eval->num_rel)); } if (eval->num_rel > eval->num_ret) { for (i = eval->num_ret; i < eval->num_rel; i++) { eval->av_R_precis += (float) eval->num_rel_ret / (float) i; eval->int_av_R_precis += (float) eval->num_rel_ret / (float) i; } } /* Calculate all the other averages */ if (eval->num_rel_ret > 0) { /* TRECVID: calculate non-interpolated avg prec by dividing by the max result set size iff number of relevant > max result set size. */ /* eval->av_recall_precis /= eval->num_rel; ORIGINAL*/ if (eval->num_rel > epi->max_result_size) { eval->av_recall_precis /= (float) epi->max_result_size; } else { eval->av_recall_precis /= eval->num_rel; } eval->int_av_recall_precis /= eval->num_rel; } eval->av_fall_recall /= MAX_FALL_RET; eval->av_rel_precis /= eval->num_ret; eval->av_rel_uap /= eval->num_ret; if (eval->num_rel) { eval->av_R_precis /= eval->num_rel; eval->int_av_R_precis /= eval->num_rel; } /* For those measure variants which use the geometric mean instead of straight averages, compute them here. Original measure value is constrained to be greater than MIN_GEO_MEAN (for time being .00001, since trec_eval prints to four significant digits) */ eval->gm_ap = (float) log ((double)(MAX (eval->av_recall_precis, MIN_GEO_MEAN))); } static void calc_exact_measures (epi, tr_vec, eval, num_rel, num_nonrel) EVAL_PARAM_INFO *epi; TR_VEC *tr_vec; TREC_EVAL *eval; long num_rel; /* Number relevant judged */ long num_nonrel; /* Number nonrelevant judged */ { if (eval->num_rel) { eval->exact_recall = (double) eval->num_rel_ret / eval->num_rel; eval->exact_precis = (double) eval->num_rel_ret / eval->num_ret; eval->exact_uap = eval->exact_recall * eval->exact_precis; if (eval->num_rel > eval->num_ret) { eval->exact_rel_precis = eval->exact_precis; } else { eval->exact_rel_precis = eval->exact_recall; } eval->exact_rel_uap = eval->exact_precis * eval->exact_precis; eval->exact_utility = epi->utility_a * eval->num_rel_ret + epi->utility_b * (eval->num_ret - eval->num_rel_ret) + epi->utility_c * (eval->num_rel - eval->num_rel_ret) + epi->utility_d * (epi->num_docs_in_coll + eval->num_rel_ret - eval->num_ret - eval->num_rel); } } static void calc_time_measures (epi, tr_vec, eval, num_rel, num_nonrel) EVAL_PARAM_INFO *epi; TR_VEC *tr_vec; TREC_EVAL *eval; long num_rel; /* Number relevant judged */ long num_nonrel; /* Number nonrelevant judged */ { double recall, precis; /* current recall, precision values */ double rel_precis, rel_uap;/* relative precision, uap values */ double int_precis = 0.0; /* current interpolated precision values */ long i,j; long bucket; long last_time_bucket = NUM_TIME_PTS; /* Last time bucket filled in */ long rel_so_far = eval->num_rel_ret; long min_ret_rel = MIN(eval->num_rel, eval->num_ret); /* Loop over all retrieved docs in reverse order */ for (j = eval->num_ret; j > 0; j--) { if (rel_so_far > 0) { recall = (float) rel_so_far / (float) eval->num_rel; precis = (float) rel_so_far / (float) j; if (j > eval->num_rel) { rel_precis = (float) rel_so_far / (float) eval->num_rel; } else { rel_precis = (float) rel_so_far / (float) j; } } else { recall = 0.0; precis = 0.0; rel_precis = 0.0; } rel_uap = rel_precis * rel_precis; if (int_precis < precis) int_precis = precis; bucket = tr_vec->tr[j-1].sim * ((double) NUM_TIME_PTS / (double) MAX_TIME); if (bucket < 0) bucket = 0; if (bucket >= NUM_TIME_PTS) bucket = NUM_TIME_PTS-1; if (tr_vec->tr[j-1].rel >= epi->relevance_level) eval->time_num_rel[bucket]++; else eval->time_num_nrel[bucket]++; eval->time_precis[bucket] = (float)rel_so_far / (float) eval->num_ret; eval->time_relprecis[bucket] = ((float)rel_so_far) / (float) min_ret_rel; eval->time_uap[bucket] = (float) rel_so_far * rel_so_far / ((float) eval->num_ret * (float) min_ret_rel); eval->time_reluap[bucket] = (float) rel_so_far * rel_so_far / ((float) min_ret_rel * (float) min_ret_rel); eval->time_utility[bucket] = epi->utility_a * rel_so_far + epi->utility_b * (j - rel_so_far) + epi->utility_c * (eval->num_rel - rel_so_far) + epi->utility_d * (epi->num_docs_in_coll + rel_so_far - j - eval->num_rel); /* Need to fill in buckets up to last bucket */ /* note assumes buckets are decreasing */ /* Must do here since utility can be negative and zero cannot be used as flag later */ for (i = bucket+1; i < last_time_bucket; i++) { eval->time_precis[i] = eval->time_precis[bucket]; eval->time_relprecis[i] = eval->time_relprecis[bucket]; eval->time_uap[i] = eval->time_uap[bucket]; eval->time_reluap[i] = eval->time_reluap[bucket]; eval->time_utility[i] = eval->time_utility[bucket]; } last_time_bucket = bucket; } eval->time_cum_rel[0] = eval->time_num_rel[0]; eval->av_time_cum_rel = eval->time_num_rel[0]; for (i=1; i< NUM_TIME_PTS; i++) { eval->time_cum_rel[i] = eval->time_cum_rel[i-1] + eval->time_num_rel[i]; eval->av_time_cum_rel += eval->time_cum_rel[i]; eval->av_time_precis += eval->time_precis[i]; eval->av_time_relprecis += eval->time_relprecis[i]; eval->av_time_uap += eval->time_uap[i]; eval->av_time_reluap += eval->time_reluap[i]; eval->av_time_utility += eval->time_utility[i]; } eval->av_time_cum_rel /= NUM_TIME_PTS; eval->av_time_precis /= NUM_TIME_PTS; eval->av_time_relprecis /= NUM_TIME_PTS; eval->av_time_uap /= NUM_TIME_PTS; eval->av_time_reluap /= NUM_TIME_PTS; eval->av_time_utility /= NUM_TIME_PTS; }