# -*- coding: utf-8 -*- """Generate the Vibe Math V2 framework diagram (架构图) as a PNG poster. Output: 示例图/框架图-v2.png (run from anywhere: python docs/generate_framework_diagram_v2.py) Layout: left = pipeline (交互/调度/子代理·方向/子代理·验证/收口), right = 数据层 aligned by stage. """ import matplotlib matplotlib.use("Agg") import os import matplotlib.pyplot as plt from matplotlib.patches import FancyBboxPatch, Rectangle, FancyArrowPatch plt.rcParams["font.sans-serif"] = ["Microsoft YaHei", "SimHei"] plt.rcParams["axes.unicode_minus"] = False BASE = os.path.dirname(os.path.abspath(__file__)) ROOT = os.path.dirname(BASE) OUT = os.path.join(ROOT, "示例图", "框架图-v2.png") fig = plt.figure(figsize=(18, 11.5)) ax = fig.add_axes([0, 0, 1, 1]) ax.axis("off") ax.set_xlim(0, 18) ax.set_ylim(0, 11.5) def box(x0, y0, w, h, fc, ec="#37474F", lw=1.6, rounding=0.16, z=3): ax.add_patch(FancyBboxPatch((x0, y0), w, h, boxstyle=f"round,pad=0.10,rounding_size={rounding}", facecolor=fc, edgecolor=ec, linewidth=lw, zorder=z)) def txt(cx, cy, s, fs=11, color="#263238", weight="normal", z=5): ax.text(cx, cy, s, ha="center", va="center", fontsize=fs, color=color, fontweight=weight, linespacing=1.45, zorder=z) def arrow(x1, y1, x2, y2, label=None, lx=0, ly=0.24, ls=9.5, rad=0.0, style="->", lw=1.8, color="#455A64", dashed=False, z=4): ax.add_patch(FancyArrowPatch((x1, y1), (x2, y2), arrowstyle=style, mutation_scale=17, linewidth=lw, color=color, zorder=z, connectionstyle=f"arc3,rad={rad}", linestyle="--" if dashed else "-")) if label: ax.text((x1 + x2) / 2 + lx, (y1 + y2) / 2 + ly, label, fontsize=ls, ha="center", va="center", color="#333", bbox=dict(fc="white", ec="none", alpha=0.85, pad=1.0), zorder=6) def band(x0, y0, x1, y1, fc, title, tc="#607D8B"): ax.add_patch(Rectangle((x0, y0), x1 - x0, y1 - y0, facecolor=fc, edgecolor="none", alpha=0.5, zorder=1)) # title pinned to the band's top-left corner, drawn ABOVE the boxes, with a # white backing so it is never obscured by the rectangles ax.text(x0 + 0.35, y1 - 0.12, title, fontsize=11.5, color=tc, fontweight="bold", ha="left", va="top", zorder=6, bbox=dict(fc="white", ec="none", alpha=0.85, pad=1.2)) # ── title ──────────────────────────────────────────────────────────────── ax.text(9, 11.12, "Vibe Math V2 — 多代理数学问题求解与验证框架(概率驱动)", fontsize=21, ha="center", va="center", color="#1A237E", fontweight="bold") ax.text(9, 10.66, "qs.json 问题清单 + Propos/ 命题库 · 按正确概率/价值调度 · explorer → 逐方向 solver → 多验证器辩论裁决", fontsize=10.5, ha="center", va="center", color="#555") # ── layer bands ────────────────────────────────────────────────────────── band(0.3, 9.45, 17.7, 10.45, "#E3F2FD", "交互层") band(0.3, 7.70, 17.7, 8.95, "#FFF8E1", "调度层 · 插件代码") band(0.3, 5.95, 17.7, 7.20, "#E8F5E9", "子代理层 · 方向求解") band(0.3, 4.20, 17.7, 5.45, "#E8F5E9", "子代理层 · 交叉验证") band(0.3, 1.50, 17.7, 4.00, "#F3E5F5", "收口 · 回写 · 数据层") # ── left pipeline (x 1.0–8.0) ──────────────────────────────────────────── box(1.0, 9.60, 7.0, 0.75, "#BBDEFB") txt(4.5, 9.98, "用户 · 主代理(助手 + 汇报者)\n自然语言 · 翻译需求/汇报/配置 · 不求解不调度", fs=11) box(1.0, 7.85, 7.0, 0.95, "#FFE0B2") txt(4.5, 8.33, "调度器(插件代码 · 概率驱动)\n唯一文件写者 · 按优先级调度 · 状态机 · 断点持久化", fs=11) box(1.0, 6.10, 7.0, 0.95, "#C8E6C9") txt(4.5, 6.58, "Explorer → Solver × N\n拆方向(全死路→重派生)· 逐方向多轮迭代", fs=11) box(1.0, 4.35, 7.0, 0.95, "#C8E6C9") txt(4.5, 4.83, "Verifier × ≥3(严苛审稿人)\n独立审查 → 辩论(交流群)→ 裁决(flat/forced)", fs=11) box(1.0, 2.60, 7.0, 0.95, "#C8E6C9") txt(4.5, 3.08, "概率 = 1 → 收口\n问题 solved · 命题 1/0 · 优先级 never", fs=11) # ── right data boxes (x 10.2–17.0) ─────────────────────────────────────── box(10.2, 7.85, 6.8, 0.95, "#E1BEE7") txt(13.6, 8.33, "qs/qs.json\n问题清单 + 解法(正确概率)", fs=10.5) box(10.2, 6.10, 6.8, 0.95, "#E1BEE7") txt(13.6, 6.58, "Propos/<分类>_Propos.json\n命题:布尔估计 · 证明/证伪列表", fs=10.5) box(10.2, 4.35, 6.8, 0.95, "#E1BEE7") txt(13.6, 4.83, "Verified/\n定论事实(布尔估计 0/1)", fs=10.5) box(10.2, 2.90, 6.8, 0.70, "#E1BEE7") txt(13.6, 3.25, "Verification_logs/ · Progress_Logs/\n辩论记录 · 进度报告", fs=10) box(10.2, 1.60, 6.8, 0.70, "#E1BEE7") txt(13.6, 1.95, "Reliable/\n可信参考文献(只读)", fs=10) # ── pipeline arrows ────────────────────────────────────────────────────── arrow(4.5, 9.60, 4.5, 8.80, "vibe_math_* 工具", ly=0.26) arrow(4.5, 7.85, 4.5, 7.05, "① 按优先级取问题 · 派 Explorer / 每方向 Solver", ly=0.24) arrow(4.5, 6.10, 4.5, 5.30, "④ 选 r(命题 / 命题+证明·证伪 / 问题+解法)派 ≥3 验证器", ly=0.24) arrow(4.5, 4.35, 4.5, 3.55, "⑤ 裁决 0/1/中间 → ⑥ 概率=1 收口", ly=0.24) arrow(0.55, 3.08, 0.55, 8.33, "读取 qs / 已解决回写", lx=0.85, ly=0) # ── stage↔data links ───────────────────────────────────────────────────── arrow(8.0, 8.33, 10.2, 8.33, "读写 qs.json", ly=0.28, style="<|-|>") arrow(8.0, 6.58, 10.2, 6.58, "② 引理/解法写入(概率<1)", ly=0.28) arrow(10.2, 6.30, 8.1, 4.90, "③ 命题/证明 → 验证", ly=0.24, rad=-0.15) arrow(8.0, 4.83, 10.2, 4.83, "⑥ 定论 → 晋升/证伪", ly=0.28) arrow(7.9, 4.40, 10.3, 3.60, "辩论记录", ly=0.24, rad=-0.1) # ── feature strip ──────────────────────────────────────────────────────── feat = ["概率=1 自动收口(solved / 1|0)", "never = 永不调度 · 不阻塞终止", "断点续跑(resume · 进程纪元)", "reportMode file|push|both · 按项目隔离"] fx = [0.6, 5.0, 9.4, 13.8] for x0, s in zip(fx, feat): box(x0, 0.40, 3.9, 0.72, "#ECEFF1", lw=1.2, rounding=0.2) txt(x0 + 1.95, 0.76, s, fs=9.5) plt.savefig(OUT, dpi=170, bbox_inches="tight", facecolor="white") print("saved " + OUT)