///|
pub fn trace_query(
qrels : Array[JudgedDoc],
run : Array[RetrievedDoc],
cutoff~ : Int,
threshold~ : Int,
) -> Array[TraceStep] {
let relevance = build_relevance_map(qrels)
let ranked = sorted_run_items(run)
let limit = Int::min(Int::max(cutoff, 0), ranked.length())
let mut relevant_total = 0
for _, value in relevance {
if value >= threshold {
relevant_total += 1
}
}
let steps : Array[TraceStep] = []
let mut hits = 0
for index in 0..= threshold {
hits += 1
}
steps.push({
rank: index + 1,
doc_id: item.doc_id,
score: item.score,
relevance: value,
judged,
hits,
precision: precision_from_counts(hits, index + 1),
recall: recall_from_counts(hits, relevant_total),
})
}
steps
}
///|
pub fn render_trace_tsv(steps : Array[TraceStep]) -> String {
let rows : Array[String] = [
"rank\tdoc_id\tscore\trelevance\tjudged\thits\tprecision\trecall",
]
for step in steps {
rows.push(
"\{step.rank}\t\{step.doc_id}\t\{step.score}\t\{step.relevance}\t\{step.judged}\t\{step.hits}\t\{step.precision}\t\{step.recall}",
)
}
rows.join("\n")
}
///|
pub fn trace_auc(steps : Array[TraceStep]) -> Double {
if steps.length() < 2 {
return 0.0
}
let mut area = 0.0
for index in 1.. Int {
for step in steps {
if step.judged {
return step.rank
}
}
0
}
///|
pub fn trace_first_relevant_rank(steps : Array[TraceStep]) -> Int {
for step in steps {
if step.relevance > 0 {
return step.rank
}
}
0
}