Project: 005_Measuring_and_Enhancing_Trustworthiness_of_LLMs_in | Function: compute_citation_metrics (iclr)

system: You are an expert Python programmer implementing algorithms from scientific papers.
Complete the masked function based on the algorithm description.
Follow Python best practices and maintain consistent code style.
Return **only** the complete Python function code.

user: Complete this Python function:

**DESCRIPTION:** Computes grounded citation metrics including recall and precision scores for citation groundedness using AutoAIS evaluation

**KEY TERMS:** {
  "regular_ais_scores": "citation recall scores Rcite",
  "regular_ais_scores_prec": "citation precision scores Pcite",
  "regular_f1_score": "F1GC (Grounded Citations)",
  "_run_nli_autoais": "NLI model for support checking"
}

**CONTEXT CODE:**         prefix + "qampari_f1_top5": 100 * np.mean(f1_top5),
    }


def get_all_em5_scores(
    data: List[Dict],
    normalized_data: List[Dict],
    normalized_answered_data: List[Dict],
    normalized_answerable_data: List[Dict],
    args: Any,
) -> Dict[str, Any]:
    result = {}
    result.update(_compute_incorrect_frequency(normalized_answered_data))
    result.update(compute_qampari_f1(normalized_data, args, prefix="regular_"))
    result.update(
        compute_qampari_f1(normalized_answered_data, args, prefix="answered_")
    )

    if args.calib:
        result.update(
            compute_qampari_f1(
                normalized_answered_data, args, prefix="calib_answered_", calib=True
            )
        )
        result.update(
            compute_qampari_f1(
                normalized_answerable_data, args, prefix="calib_answerable_", calib=True
            )
        )
        result["calib_qampari_em_f1"] = stats.hmean(
            [
                result["calib_answered_qampari_f1_top5"],
                result["calib_answerable_qampari_f1_top5"],
            ]
        )

    if args.parametric:
        result["parametric_qampari_rec_top5"] = (
            result["answered_qampari_rec_top5"]
            - compute_qampari_f1(
                normalized_answered_data,
                args,
                prefix="parametric_",
                calib=True,
                parametric=True,
            )["parametric_qampari_rec_top5"]
        )
    return result


def compute_citation_metrics(
    raise NotImplementedError("Function implementation has been masked for testing")
) -> Dict[str, Any]:
    """
    Compute AutoAIS score.

    Args:
        data: requires field `output` and `docs`
              - docs should be a list of items with fields `title` and `text` (or `phrase` and `sent` for QA-extracted docs)
        citation: check citations and use the corresponding references.
        decontext: decontextualize the output
    """

    logger.info("Running AutoAIS...")

    regular_ais_scores = []
    regular_ais_scores_prec = []
    answered_ais_scores = []
    answered_ais_scores_prec = []

    sent_total = 0
    sent_mcite = 0
    sent_mcite_support = 0
    sent_mcite_overcite = 0
    autoais_log = []
    for item in tqdm(data, desc="Computing citation score"):
        # Get sentences by using NLTK
        if is_qampari:
            sents = [
                item["question"] + " " + x.strip()
                for x in item["output"].rstrip().rstrip(".").rstrip(",").split(",")
            ]
        else:
            sents = sent_tokenize(item["output"])
        if len(sents) == 0:
            continue
        target_sents = [remove_citations(sent).strip() for sent in sents]

        entail = 0
        entail_prec = 0
        total_citations = 0
        for sent_id, sent in enumerate(sents):
            target_sent = target_sents[
                sent_id
            ]  # Citation removed and (if opted for) decontextualized
            joint_entail = -1  # Undecided

            # Find references
            ref = [
                int(r[1:]) - 1 for r in re.findall(r"\[\d+", sent)
            ]  # In text citation id starts from 1
            logger.info(f"For `{sent}`, find citations {ref}")

            # No citations
            if len(ref) == 0:
                joint_entail = 0
            # Citations out of range
            elif any([ref_id >= len(item["docs"]) for ref_id in ref]):
                joint_entail = 0
            else:
                if at_most_citations is not None:
                    ref = ref[:at_most_citations]
                total_citations += len(ref)
                joint_passage = "\n".join(
                    [format_document(item["docs"][psgs_id]) for psgs_id in ref]
                )

            # If not directly refused by citation format error, calculate the recall score
            if joint_entail == -1:
                joint_entail = _run_nli_autoais(joint_passage, target_sent, args)
                autoais_log.append(
                    {
                        "question": item["question"],
                        "output": item["output"],
                        "claim": sent,
                        "passage": [joint_passage],
                        "model_type": "NLI",
                        "model_output": joint_entail,
                    }
                )

            entail += joint_entail
            if len(ref) > 1:
                sent_mcite += 1

            # calculate the precision score if applicable
            if joint_entail and len(ref) > 1:
                sent_mcite_support += 1
                # Precision check: did the model cite any unnecessary documents?
                for psgs_id in ref:
                    # condition A
                    passage = format_document(item["docs"][psgs_id])
                    nli_result = _run_nli_autoais(passage, target_sent, args)

                    # condition B
                    if not nli_result:
                        subset_exclude = copy.deepcopy(ref)
                        subset_exclude.remove(psgs_id)
                        passage = "\n".join(
                            [


Complete the function implementation replacing "raise NotImplementedError".