Verify whether a student's math answer is equivalent to a reference answer. Handle numeric comparisons (with tolerance), symbolic equivalence for simple expressions, and string normalization for exact matching.
import re
from typing import Union
def normalize_answer(answer: str) -> str:
answer = answer.strip()
answer = answer.replace(" ", "")
answer = re.sub(r'\\left|\\right', '', answer)
answer = answer.replace("\\frac", "frac")
answer = answer.replace("\\cdot", "*")
answer = answer.replace("\\times", "*")
return answer
def try_parse_number(s: str) -> Union[float, None]:
s = s.strip().replace(",", "")
# Handle fractions like 3/4
frac_match = re.match(r'^(-?\d+)\s*/\s*(-?\d+)$', s)
if frac_match:
num, den = int(frac_match.group(1)), int(frac_match.group(2))
return num / den if den != 0 else None
try:
return float(s)
except ValueError:
return None
def math_answer_verify(
student_answer: str,
reference_answer: str,
tolerance: float = 1e-6
) -> bool:
s_num = try_parse_number(student_answer)
r_num = try_parse_number(reference_answer)
if s_num is not None and r_num is not None:
return abs(s_num - r_num) <= tolerance
s_norm = normalize_answer(student_answer)
r_norm = normalize_answer(reference_answer)
return s_norm == r_norm3/4).\left and \right, and unifying multiplication symbols.