import subprocess import sys from typing import Optional def run_python_snippet(code: str, timeout_sec: int = 45) -> str: """Execute Python in a subprocess (no network). For short derived calculations.""" if not code.strip(): return "Error: empty code." try: proc = subprocess.run( [sys.executable, "-c", code], capture_output=True, text=True, timeout=timeout_sec, env={**__import__("os").environ, "PYTHONHASHSEED": "0"}, ) except subprocess.TimeoutExpired: return "Error: execution timed out." out = (proc.stdout or "").strip() err = (proc.stderr or "").strip() if proc.returncode != 0: return f"Exit {proc.returncode}. stderr: {err[:2000]}" if err: out = f"{out}\n(stderr: {err[:1500]})" if out else err return out[:30_000] if out else "(no stdout)" def run_python_file(file_path: str, timeout_sec: int = 60) -> str: """Run an attached .py file and capture stdout.""" if not file_path.endswith(".py"): return "Error: not a .py path." try: proc = subprocess.run( [sys.executable, file_path], capture_output=True, text=True, timeout=timeout_sec, env={**__import__("os").environ, "PYTHONHASHSEED": "0"}, ) except subprocess.TimeoutExpired: return "Error: execution timed out." out = (proc.stdout or "").strip() err = (proc.stderr or "").strip() if proc.returncode != 0: return f"Exit {proc.returncode}. stderr: {err[:2000]}" return (out or err)[:30_000] def solve_cayley_noncommutative_subset(question: str) -> Optional[str]: """ Parse a Cayley table from the question (markdown) and return the sorted comma-separated elements involved in any non-commuting pair. """ if "* on the set S" not in question and "not commutative" not in question: return None lines = [ln.strip() for ln in question.splitlines() if ln.strip().startswith("|")] if len(lines) < 3: return None def split_row(ln: str) -> list[str]: parts = [p.strip() for p in ln.strip("|").split("|")] return parts header = split_row(lines[0]) if len(header) < 2 or header[0] != "*": return None cols = header[1:] op: dict[tuple[str, str], str] = {} for ln in lines[1:]: cells = split_row(ln) if len(cells) < 2: continue row_sym = cells[0] for j, c in enumerate(cols): if j + 1 >= len(cells): break op[(row_sym, c)] = cells[j + 1] elems = cols involved: set[str] = set() for a in elems: for b in elems: ab = op.get((a, b)) ba = op.get((b, a)) if ab is None or ba is None: continue if ab != ba: involved.add(a) involved.add(b) if not involved: return None return ", ".join(sorted(involved)) def reverse_english_puzzle_answer(question: str) -> Optional[str]: """If the question is reversed English about 'left', return 'right'.""" q = question.strip() if not q: return None rev = q[::-1] if "opposite" in rev.lower() and '"left"' in rev and "answer" in rev.lower(): return "right" return None