# -*- coding: utf-8 -*-
"""【推断 · GPT 级大模型收益】基于实测规律的外推,不是验证结论。

一句话结论:
    本机 12G 显存 + 16G 内存加载不了 GPT 级权重,无法实测。本例把 README
    「GPT 收益推断」节的推理过程固化成可复现脚本,分三块:
      ① 三条实测规律(小→大模型)的落地证据;
      ② 跨规模扫描(层越宽越省越稳),直接支撑「GPT 的 FFN 极宽层收益更大」;
      ③ 成熟模型 K=1 全局低秩证据(ResNet50 方向)——证明「成熟精炼权重没有
         聚类结构、只有低秩结构」,这是 GPT 级 FFN 函数化路线的关键依据;
      ④ 按规律外推 GPT 级,但明确标注「不验证」这条硬边界。

这与 gpt_preview.py 的分工:
    - gpt_preview.py:GPT 级的「接口可跑性」预演(玩具尺寸 S+F+低秩组合 + 尺寸体积估算)。
    - 本脚本:GPT 级的「收益趋势」外推(跨规模扫描 + K=1 低秩证据 + 三条规律落地),
      把 README 里那些数字背后的推算过程跑出来、可复现。
"""
import _common  # noqa: F401  # 先导入:完成 src 路径引导

import numpy as np

import nrfunc


# ── 三条实测规律(README「从小模型到大模型」节,固定种子复现值)──
LAWS = [
    ('体积省钱随冗余度上升',
     '小 MLP 省 82% → 大 CNN 92.9%(最大层)→ 玩具 ViT 90.5%,越大越省'),
    ('内存/显存靠「K≪n」才兑现',
     '充要条件 K×(1+r)<n,小层会反涨、大层净省'),
    ('CPU 提速只在「大模型 + Rust/GPU」兑现',
     'numpy 小模型反慢,大层(K≪n)才转正'),
]


def law_evidence():
    """三条实测规律 + 各自在库里的落地证据(不重训,只引用既有可复现数据)。"""
    print('=' * 88)
    print('① 三条实测规律(从小模型到大模型)')
    print('=' * 88)
    for name, ev in LAWS:
        print(f'  · {name}:{ev}')
    print()
    print('  落地证据(均固定种子可复现,见对应示例):')
    print('    - 体积:mlp_classification(小 MLP 82%) / cnn_classification(大 CNN 92.9%)')
    print('      / transformer_structure_partition(玩具 ViT 90.5%)。')
    print('    - 内存:auto_alloc 硬约束「净省」K×(1+r)<n 先验剪枝(auto_alloc_demo 5 例)。')
    print('    - CPU:functional_forward_demo(0 阶 29.9×、1 阶 1.62× 的 numpy 实测,')
    print('      1 阶批量则需 Rust/GPU 兑现,见 examples/rust)。')
    print()


def scale_scan():
    """② 跨规模扫描的权威数据:指向 scale_scan.py(真实 MNIST + 真实掉点)。

    本脚本不造假数字,也不把旧结果硬编码在这里——「跨规模实测」的权威值来自
    `reports/scale_scan.log`(scale_scan.py 每次重跑都会覆盖它)。下面的表从 log
    解析得到,log 更新则表自动更新,绝不用 README 或旧脚本里的字面量「套着写死」。
    若 log 缺失/无法解析,则明确提示需先跑 `python scale_scan.py`,而非退回硬编码。
    """
    print('=' * 88)
    print('② 跨规模扫描(权威数据来自 reports/scale_scan.log,本表动态解析,不硬编码)')
    print('=' * 88)
    rows = _load_scale_scan_rows()
    if rows is None:
        print('未找到 reports/scale_scan.log 或无法解析。')
        print('请先运行 `python scale_scan.py` 产出最新实测,再看本表。')
        print('(不在此处回退硬编码旧数字,避免拟合历史记录。)')
        print()
        return
    print('权威实测(等宽三隐层 784→h→h→h→10,新版 auto_alloc,固定 seed):')
    print()
    print(f"{'隐层宽 h':<10}{'参数量':<10}{'叠加掉点':<12}{'整体节省率':<12}")
    print('-' * 44)
    for h, p, drop, saving in rows:
        print(f'{h:<10}{p:<10}{drop:<12}{saving:<12}')
    print('-' * 44)
    print()
    print('趋势(新版 nrfunc):')
    print('  · 掉点断崖收敛:h=128 起压进 2pt、h=256 起 <1.1pt、h=2048 甚至精度反升;')
    print('  · 节省率整体随宽度上升,因 3pt 红线主动牺牲少量压缩,不再严格单调。')
    print('  · 完整复现入口:`python scale_scan.py`(训练 6 个 MLP,较慢)。')
    print()


def _load_scale_scan_rows():
    """从 reports/scale_scan.log 解析「汇总表」6 行,不加任何硬编码数字。

    解析「=== 汇总表 ===」之后的 6 行:`隐层宽h  参数量  叠加掉点  整体节省率`。
    返回 None 表示 log 缺失或格式不符(调用方据此提示重跑,而非回退旧值)。
    """
    import os
    import re
    here = os.path.dirname(os.path.abspath(__file__))
    log_path = os.path.join(here, 'reports', 'scale_scan.log')
    if not os.path.exists(log_path):
        return None
    lines = open(log_path, encoding='utf-8').read().splitlines()
    # 定位「=== 汇总表」段落后的数据行;行格式:`64        5.9万       4.16pt       71.7%`
    rows = []
    in_summary = False
    for ln in lines:
        if '汇总表' in ln:
            in_summary = True
            continue
        if not in_summary:
            continue
        m = re.match(r'^\s*(\d+)\s+([\d.]+)万\s+(-?[\d.]+)pt\s+([\d.]+)%', ln)
        if m:
            h = int(m.group(1))
            p = m.group(2) + ' 万'
            drop = m.group(3) + 'pt'
            saving = m.group(4) + '%'
            rows.append((str(h), p, drop, saving))
    return rows if len(rows) == 6 else None


def k1_lowrank_evidence():
    """③ 成熟模型 K=1 全局低秩证据(ResNet50 方向):成熟精炼权重无聚类、只有低秩。

    构造一个「成熟精炼」的宽层权重(无簇结构、仅低秩 —— 真实成熟 CNN 卷积核的
    典型形态),对比两种函数化:
      - K>1 几何聚类(k-means):找不出有意义簇,EV 提升有限、还可能因 K 增大而
        消耗更多参数换不来保真;
      - K=1 全局低秩(等价 PCA):只需少量主成分即高保真,参数最省。
    结论:成熟权重正解是 K=1 全局低秩,而不是聚类。这直接支撑 README ResNet50
    的实测(旧版缺 K=1 全 skip,新版 K=1 全局低秩 14 层全函数化、省 11.2%、掉点 -0.44pt),
    并支撑 GPT 级 FFN(同样是成熟、无聚类、低秩的宽层)用 K=1 + 低秩的路线。
    """
    print('=' * 88)
    print('③ 成熟模型 K=1 全局低秩证据(ResNet50 方向)')
    print('=' * 88)
    n, D, rank_true = 512, 1024, 16  # 宽层,真实秩很低(成熟精炼)
    rng = np.random.default_rng(0)
    # 构造「纯低秩、无簇结构」的成熟权重:随机基 × 随机系数
    base = rng.standard_normal((rank_true, D))
    coeff = rng.standard_normal((n, rank_true))
    W = (coeff @ base + 0.01 * rng.standard_normal((n, D))).astype(np.float64)

    print(f'合成成熟宽层:n={n}, D={D}, 真实秩≈{rank_true}(无簇、仅低秩)')
    print()
    print(f"{'方案':<20}{'K':<6}{'r':<6}{'重建EV':<10}{'字节(8bit后)':<12}")
    print('-' * 56)

    # 方案 A:K=1 全局低秩(成熟权重的正解)
    res_k1 = nrfunc.regionify(W, signal='G', K=1, order=1, r=16, seed=0)
    _print_plan('K=1 全局低秩', res_k1, n, D)

    # 方案 B:K=8 几何聚类 + 0 阶(聚类对成熟权重无效)
    res_k8 = nrfunc.regionify(W, signal='G', K=8, order=0, seed=0)
    _print_plan('K=8 聚类 0阶', res_k8, n, D)

    # 方案 C:K=8 几何聚类 + 1 阶低秩(组合,参数更多)
    res_k8r = nrfunc.regionify(W, signal='G', K=8, order=1, r=4, seed=0)
    _print_plan('K=8 聚类 1阶(r=4)', res_k8r, n, D)

    print('-' * 56)
    print()
    print('结论:')
    print('  · 成熟精炼权重「没有几何聚类结构、只有低秩结构」,K=1 全局低秩(等价 PCA)')
    print('    才是正解——在达到高保真(EV≈1.000)的方案里字节数最少;聚类 K=8 的 0 阶')
    print('    字节虽更少,但 EV 仅 0.202、1 阶字节更多且 EV 仅 0.556,都浪费参数换不来保真。')
    print('  · 简单说:对成熟权重,聚类(K>1)既换不来保真、又浪费空间,K=1 低秩是唯一正确选择。')
    print('  · 这对应 README 实测:ResNet50 旧版 auto_alloc(缺 K=1)13 层全 skip,')
    print('    新版(K=1 全局低秩 + 谱探测 + distortion)14 层全函数化、省 11.2%、')
    print('    掉点 -0.44pt(精度不降反升)。')
    print()


def _print_plan(name, res, n, D):
    after = nrfunc.size_bytes_regionalized(res, bits=8)
    # 0 阶无主成分(r=0);1 阶 r = components 的第二维
    r = res['components'].shape[1] if res['order'] == 1 else 0
    print(f'{name:<20}{res["K"]:<6}{r:<6}{res["explained"]:>10.3f}'
          f'{after:>12}')


def extrapolate_gpt():
    """④ 按三条规律外推 GPT 级(只推断,不验证)。"""
    print('=' * 88)
    print('④ 按三条规律外推 GPT 级')
    print('=' * 88)
    print('  1. 体积/内存:收益大概率显著更高')
    print('     GPT 的 FFN、注意力层 n 可达数千、D 数千,K≪n 天然成立、冗余充分,')
    print('     外推体积省可能到 95%+、内存净省空间比小模型大得多。')
    print('  2. CPU:首次有「真提速」的土壤')
    print('     GPT 层 K≪n,函数前向共享计算 + 查表广播的收益才浮现——但前提是')
    print('     Rust/CUDA kernel 兑现,numpy 参考实现仍受 gather/循环拖累。')
    print('  3. 掉点:分型手段能兜住,但「不验证」是硬边界')
    print('     实测 F(大 CNN 2.75pt)、S(玩具 ViT 0.71pt) 均 <3pt,auto_alloc 的')
    print('     eval_fn 能逐层压住;理论上 GPT 用 S+F+FFN低秩 组合分型有机会守住红线,')
    print('     但 GPT 级真实掉点没有验证。')
    print()
    print('=' * 88)
    print('为什么不直接给结论:')
    print('  · 本机 12G 显存 + 16G 内存,加载不了 GPT 级权重,无法实测;')
    print('  · GPT 的权重/激活分布、冗余结构与小模型不同,前面规律不能保证线性外推;')
    print('  · 库的诚实边界:GPT 级「谁有条件谁验证」,本库只提供接口与理论预演。')
    print('=' * 88)


def main():
    law_evidence()
    scale_scan()
    k1_lowrank_evidence()
    extrapolate_gpt()


if __name__ == '__main__':
    main()