ZusandsTabelle / src /streamlit_app.py
NickK75's picture
Update src/streamlit_app.py
81932fe verified
Raw
History Blame Contribute Delete
5.76 kB
import streamlit as st
import pandas as pd
import itertools
import re
# --- Eigener LaTeX-Generator für die Schaltfunktion ---
def to_custom_latex(expr_str):
"""
Wandelt den bereinigten Python-Logik-String in sauberen LaTeX-Code
mit \overline{...} für NOT, \oplus für XOR, \wedge für AND und \vee für OR um.
"""
# Temporäre Platzhalter für geklammerte Negationen oder Variablen-Negationen
# Findet Ausdrücke wie ~(A) oder ~A und ersetzt sie durch \overline{...}
# Regulärer Ausdruck fängt Ausdrücke mit Tilde ab
# 1. Negationen mit Klammern: ~(A + B) -> \overline{A + B}
while "~(" in expr_str:
# Einfacher Parser für passende Klammern
start_idx = expr_str.find("~(")
open_brackets = 0
end_idx = -1
for i in range(start_idx + 1, len(expr_str)):
if expr_str[i] == "(":
open_brackets += 1
elif expr_str[i] == ")":
open_brackets -= 1
if open_brackets == 0:
end_idx = i
break
if end_idx != -1:
inner = expr_str[start_idx+2:end_idx]
# Rekursiver Aufruf für das Innere der Klammer
expr_str = expr_str[:start_idx] + f"\\overline{{{to_custom_latex(inner)}}}" + expr_str[end_idx+1:]
else:
break
# 2. Einfache Variablen-Negation: ~A -> \overline{A}
expr_str = re.sub(r'~([a-zA-Z])', r'\\overline{\1}', expr_str)
# 3. Restliche mathematische Symbole ersetzen
expr_str = expr_str.replace("&", r" \wedge ")
expr_str = expr_str.replace("|", r" \vee ")
expr_str = expr_str.replace("^", r" \oplus ")
return expr_str
# --- Streamlit UI ---
st.set_page_config(page_title="Wahrheitstabelle & Logik-Parser", layout="wide")
st.title("🎛️ Dynamischer Wahrheitstabellen-Generator")
st.markdown("""
Geben Sie eine Schaltfunktion ein. Folgende Operatoren sind definiert:
* **`*`** : UND ($\land$)
* **`+`** : ODER ($\lor$)
* **`^`** : EXKLUSIV-ODER ($\oplus$)
* **`!`** oder **`~`** : NEGATION ($\overline{A}$)
""")
# Layout: 2 Spalten
col1, col2 = col1, col2 = st.columns([1, 2])
with col1:
st.subheader("Eingabe & Konfiguration")
# Standard-Beispiel
user_input = st.text_input("Schaltfunktion f:", value="(A ^ B) * !C")
if user_input:
# Eingabe bereinigen und in valides Python-Boole-Format bringen
clean_expr = user_input.replace(" ", "")
clean_expr = clean_expr.replace("+", " | ")
clean_expr = clean_expr.replace("*", " & ")
clean_expr = clean_expr.replace("!", "~")
# Erkannte Variablen extrahieren
detected_vars = sorted(list(set(re.findall(r'[a-zA-Z]', clean_expr))))
if not detected_vars:
st.error("Keine Variablen (Buchstaben) in der Funktion gefunden.")
st.stop()
st.success("Funktion erfolgreich interpretiert!")
# --- Dynamische Sortierung der Spalten ---
st.markdown("### Spaltenreihenfolge")
ordered_vars = st.multiselect(
"Reihenfolge der Variablen festlegen:",
options=detected_vars,
default=detected_vars
)
# Validierung der Auswahl
missing_vars = set(detected_vars) - set(ordered_vars)
if missing_vars:
st.warning(f"Bitte alle Variablen auswählen. Es fehlen noch: {', '.join(missing_vars)}")
st.stop()
with col2:
st.subheader("Darstellung & Wahrheitstabelle")
if user_input and detected_vars:
# --- LaTeX Darstellung (Eigener Parser ohne SymPy-Winkel-Zwang) ---
st.markdown("#### Logische Formel (LaTeX)")
latex_formula = to_custom_latex(clean_expr)
st.latex(f"f = {latex_formula}")
# --- Wahrheitstabelle generieren via Python eval() ---
st.markdown("#### Wahrheitstabelle")
num_vars = len(ordered_vars)
combinations = list(itertools.product([0, 1], repeat=num_vars))
table_data = []
for combo in combinations:
# Zustand für die aktuelle Zeile als Dictionary (z.B. {'A': 0, 'B': 1})
var_values = dict(zip(ordered_vars, combo))
# Python-konformen String für die Auswertung vorbereiten.
# Da Python mit '&', '|', '~', '^' nativ auf Integers (0 und 1) bitweise rechnet,
# können wir den String direkt evaluieren, wenn wir die Variablen ersetzen.
eval_expr = clean_expr
for var, val in var_values.items():
# Nutze Regex-Word-Boundaries, damit 'A' nicht in 'and' oder längeren Ausdrücken ersetzt wird
eval_expr = re.sub(r'\b' + var + r'\b', str(val), eval_expr)
try:
# Berechne das Ergebnis (0 oder 1).
# Das bitweise NOT (~) von 0 ist in Python -1, von 1 ist es -2.
# Daher maskieren wir das Ergebnis am Ende mit & 1, um immer 0 oder 1 zu erhalten.
result = eval(eval_expr) & 1
except Exception as e:
st.error(f"Fehler bei der Tabellenberechnung: {e}")
st.stop()
row = list(combo) + [result]
table_data.append(row)
# DataFrame erstellen
column_names = ordered_vars + ["f"]
df = pd.DataFrame(table_data, columns=column_names)
# Tabelle anzeigen
st.dataframe(
df.style.format(hyperlinks="to_html")
.background_gradient(subset=["f"], cmap="Blues", low=0.1, high=0.05),
use_container_width=True,
hide_index=True
)