text_to_solver_program/test_report_math.py
dschlueter b74445b8d6 Erste öffentliche Fassung: Math Model Generator & Solver
Übersetzt natürlichsprachige Optimierungsaufgaben (Deutsch) per LLM in
eine geprüfte Modellspezifikation, erzeugt Solver-Code und führt ihn in
einer bubblewrap-Sandbox aus. Deterministische Prüfungen ohne LLM,
Report als Markdown/HTML, Benchmark mit 19 verifizierten Fällen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 11:42:58 +02:00

54 lines
2.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import pytest
from report import Math, _html_inline, _md_inline, split_math
def marked(text: str) -> str:
"""Formelteile mit «…» markieren – kompakt vergleichbar."""
return "".join(f"«{part}»" if is_math else part for is_math, part in split_math(text))
@pytest.mark.parametrize("text, expected", [
# ohne Begrenzer (häufigster Fall in LLM-Texten, beobachtet in gespeicherten Läufen)
("U_i = 0.40 für alle i \\in I", "«U_i = 0.40» für alle «i \\in I»"),
("R_{\\min} = 0.08", "«R_{\\min} = 0.08»"),
("r_A=0.07, r_B=0.10", "«r_A=0.07, r_B=0.10»"),
("lautet \\sqrt{\\mathbf{w}^\\top \\Sigma \\mathbf{w}}. Das ist konvex.",
"lautet «\\sqrt{\\mathbf{w}^\\top \\Sigma \\mathbf{w}}». Das ist konvex."),
("j \\in I = \\{A,B,C,D\\} (für Kovarianzterme)", "«j \\in I = \\{A,B,C,D\\}» (für Kovarianzterme)"),
("x_{p,d,s} = 1, wenn Person p arbeitet", "«x_{p,d,s} = 1», wenn Person p arbeitet"),
# Mehrbuchstaben-Index klammern, % maskieren
("Mindestrendite r_min = 0.08 gilt", "Mindestrendite «r_{min} = 0.08» gilt"),
("bei w_A = 23.21%.", "bei «w_A = 23.21\\%»."),
# explizite Begrenzer
("Mitarbeitende: \\(p \\in P\\)", "Mitarbeitende: «p \\in P»"),
("Fonds $i \\in I$ gesamt", "Fonds «i \\in I» gesamt"),
("\\begin{pmatrix} 1 & 2 \\\\ 3 & 4 \\end{pmatrix}", "«\\begin{pmatrix} 1 & 2 \\\\ 3 & 4 \\end{pmatrix}»"),
])
def test_formulas_are_detected(text, expected):
assert marked(text) == expected
@pytest.mark.parametrize("text", [
"Erwartete Jahresrendite von Fonds i",
"Kapazitaet_M1 ist ausgelastet",
"WARNING [UNDECLARED_SYMBOL] Symbol 'h' fehlt",
"Kosten $5 bzw. $7",
"1, wenn Person p am Tag d in Schicht s arbeitet, sonst 0.",
"(F = Frühschicht, S = Spätschicht)",
"Second-Order Cone Programming (SOCP)",
])
def test_plain_text_stays_text(text):
assert split_math(text) == [(False, text)]
def test_html_free_text_wraps_formulas_and_escapes_text():
rendered = _html_inline("Anteil w_i <= 0.4 & mehr")
assert rendered == "Anteil \\(w_i &lt;= 0.4\\) &amp; mehr"
def test_markdown_table_cell_escapes_pipes_outside_and_inside_math():
rendered = _md_inline("Norm \\(\\|w\\|\\) | Rest", in_table=True)
assert rendered == "Norm $\\Vert w\\Vert $ \\| Rest"
assert _md_inline(Math("|x|"), in_table=True) == "$\\vert x\\vert $"
assert _md_inline(Math("x"), in_table=False) == "$x$"