Ü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>
54 lines
2.4 KiB
Python
54 lines
2.4 KiB
Python
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 <= 0.4\\) & 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$"
|