Source code for eval_framework.tasks.benchmarks.hendrycks_math_ellamind
"""German Hendrycks Math (EllaMind) tasks.
https://huggingface.co/datasets/ellamind/hendrycks-math-multilingual
"""
from typing import Any
from eval_framework.metrics.completion.math_minerva_completion import (
MathMinervaCompletionDE,
MathMinervaCompletionRelaxedDE,
)
from eval_framework.metrics.completion.minerva_math_utils import extract_answers
from eval_framework.tasks.base import Language, Sample
from eval_framework.tasks.benchmarks.math_reasoning import MATHMinerva
from eval_framework.tasks.dataset_revisions import HF_REVISIONS_LOCKFILE
from eval_framework.tasks.task_style import BPBStyle
[docs]
class MATHMinervaDE_OLMES(MATHMinerva):
"""German Hendrycks Math - MATHMinerva-style reasoning generation.
Dataset: https://huggingface.co/datasets/ellamind/hendrycks-math-multilingual
Matches the English ``MATHMinerva_OLMES`` task with these German adaptations:
* prompt markers translated: ``Aufgabe:`` / ``Lösung:``
* stop sequences adjusted accordingly
* few-shot examples drawn from the dataset (not the hardcoded English
``_OLMES_FEWSHOTS`` list the parent uses)
* few-shot targets end with a German Minerva-style final-answer line.
The EllaMind dataset is test-only; few-shot sampling uses the same
oversample-and-drop guard as ``BaseTask._sample_fewshot_examples`` while
filtering out multi-paragraph solutions. Solutions preserve the original
``\\boxed{...}`` markers, so the parent's ground-truth extraction and the
Minerva metric's boxed-answer fallback both keep working unchanged.
"""
REVISION_LOCKFILE = HF_REVISIONS_LOCKFILE
NAME = "MATHMinervaDE_OLMES"
DATASET_PATH = "ellamind/hendrycks-math-multilingual"
SAMPLE_SPLIT = "test"
FEWSHOT_SPLIT = "test" # EllaMind only ships a test split
SUBJECTS = ["deu"]
LANGUAGE = Language.DEU
METRICS = [MathMinervaCompletionDE, MathMinervaCompletionRelaxedDE]
def __init__(self, num_fewshot: int = 4) -> None:
super().__init__(num_fewshot)
self.stop_sequences = ["Aufgabe:", "\n\n"]
def _get_instruction_text(self, item: dict[str, Any]) -> str:
return "Aufgabe:\n" + item["problem"] + "\n\n"
def _get_cue_text(self, item: dict[str, Any]) -> str:
return "Lösung:"
def _get_fewshot_target_text(self, item: dict[str, Any]) -> str:
# Mirror the English Minerva format's "Final Answer: The final answer is ..."
# so the model learns to terminate each solution with an explicit final-answer line.
return (
f"{self._get_cue_text(item)} {item['solution']}\n"
f"Finale Antwort: Die finale Antwort lautet ${item['extracted_answer']}$. "
"Ich hoffe, die Antwort ist korrekt."
)
def _sample_fewshot_examples(self, item: dict[str, Any]) -> list[dict]:
# Restrict to single-paragraph solutions so the "\n\n" stop sequence fires between
# few-shot blocks rather than mid-solution
pool = [ex for ex in self.dataset[self.FEWSHOT_SPLIT] if "\n\n" not in ex["solution"]]
# Same-split guard: oversample by one and drop the target item if present.
assert self.rnd is not None, "Task RNG is unseeded; build tasks via `with_overwrite`."
candidates = self.rnd.sample(pool, self.num_fewshot + 1)
return [ex for ex in candidates if ex != item][: self.num_fewshot]
[docs]
def post_process_generated_completion(self, completion_text: str, sample: Sample | None = None) -> str:
candidates = extract_answers(completion_text, use_cot=True, cot_style="minerva_de", relaxed=True)
return candidates[0] if candidates else "[no_answer]"
[docs]
class MATHMinervaDE_BPB_OLMES(MATHMinervaDE_OLMES):
"""German HENDRYCKS Math - BPB format.
Dataset: https://huggingface.co/datasets/ellamind/hendrycks-math-multilingual
"""
REVISION_LOCKFILE = HF_REVISIONS_LOCKFILE
NAME = "MATHMinervaDE_BPB_OLMES"
TASK_STYLER = BPBStyle(cue_text="")
def _get_raw_question(self, item: dict[str, Any]) -> str:
return item["problem"]
def _get_choices(self, item: dict[str, Any]) -> list[str]:
return [
(
f"{item['solution']}\n"
f"Finale Antwort: Die finale Antwort lautet ${item['extracted_answer']}$. "
"Ich hoffe, die Antwort ist korrekt."
)
]
# Needs to be set again, because one of the parents overrides the default implementation.
def _get_ground_truth(self, item: dict[str, Any]) -> str:
return f" {self._get_choices(item)[0]}"
def _get_correct_index(self, item: dict[str, Any]) -> int:
return 0
[docs]
class MATHMinervaDE_OLMES_NONL(MATHMinervaDE_OLMES):
"""Same as MATHMinervaDE_OLMES, but without `\\n\\n` as stop sequence."""
NAME = "MATHMinervaDE_OLMES_NONL"
def __init__(self, num_fewshot: int = 4) -> None:
super().__init__(num_fewshot)
self.stop_sequences = ["Aufgabe:"]