返回列表

15th Place Solution

675. NeurIPS 2025 - Google Code Golf Championship | google-code-golf-2025

开始: 2025-07-31 结束: 2025-10-30 数学与计算 数据算法赛
第 15 名解决方案 - Google Code Golf 2025

第 15 名解决方案

作者: chimaki
发布日期: 2025 年 11 月 6 日
竞赛: Google Code Golf 2025
排名: 第 15 名

我们要感谢主办方和 Kaggle 团队组织了如此富有创意和启发性的比赛。
这是我们第一次接触代码高尔夫(Code Golf),通过这次激动人心的挑战,我们学到了很多。

团队成员: @chimaki821 @isakatsuyoshi @denden12 @hikari30 @kosirowada

目录:

  1. 手动代码高尔夫
  2. 使用大语言模型 (LLM) 进行代码高尔夫
  3. 基于规则的代码高尔夫
  4. 基于压缩的代码高尔夫

1. 手动代码高尔夫

由于大语言模型很难从头开始解决任务或从根本上改进算法,我们手动创建了许多“初始解决方案”。
在这个过程中,论坛上的讨论非常有帮助。特别是我们发布的两个讨论帖:

[1] 如何进行邻居检查高尔夫?(task279)

[2] 对角线扩展 (task034)

这两个帖子与许多参与者进行了富有成效的交流,我们能够 Incorporate 从中获得的见解。我们真诚地感谢每一位贡献者。

1.1. 算法改进

我们专注于通过仔细观察测试用例并利用网格中的结构模式来简化算法。
我们的主要策略如下:

(a) 通过观察简化

  • 识别固定的输入/输出大小或重复出现的数字。
  • 检测常见的布局,例如上半部分有一个对象,下半部分有另一个对象。
  • 尽可能对整个行或网格应用操作。

(b) 编写简洁高效的逻辑

  • 使用高级函数,如 any, all, zip, map, filter, 和 sum
  • 用更直接的操作替换嵌套循环和索引访问。
  • 优先使用 list.indexenumerate 而不是手动的 range 循环。

(c) 智能技巧

  • 采用递归和网格旋转来减少重复的邻居检查。
  • 尽可能利用正则表达式 (regex) — 我们用基于正则的解决方案解决了 31 个任务。

1.2. 识别相似问题

在手动解决任务时,我们注意到许多问题具有相似的结构。识别这些模式使我们能够将一个任务的成功策略应用到另一个任务。
感谢 @denden12 编译了总结所有任务的 PDF,使我们能够更容易地发现这种相似性。

例如:

  • task154 和 task390
  • task351 和 task400
  • task246 和 task335

由于这些问题几乎相同,我们将它们一起处理,并同时 aiming for 分数改进。


2. 使用大语言模型 (LLM) 进行代码高尔夫

我们通过采用强大的人工编写的种子解决方案,然后使用像 GPT-5 Pro 这样的 AI 对其进行“后续代码高尔夫优化”,积累了大量分数。

我们采用这种工作流程有几个原因:

  • 我们希望节省人力,让 AI 处理 AI 能做的事情。
  • 当前的高端 AI 在方法方向明确时,可以相对轻松地进行代码高尔夫优化。
    • 然而,AI 难以进行从 0 到 1 的创建或跳出局部最优,此时手动代码高尔夫仍然有效。
  • 多样性是跳出局部最优的关键,例如从手动解决方案转向 AI,或从一个 AI 转向另一个 AI,是跳出局部最优的关键。

2.1. 我们使用的 LLM

  • 我们尝试了 GPT, Claude, Gemini 和 Grok。
  • 在早期阶段,我们使用 Claude Code 配合 DSL 实现来达到 AC (Accepted) 结果。
  • 在 GPT-5 发布后,我们转向了它。GPT-5 的表现令人惊讶,实现了许多从 0 到 1 的 AC 结果。
  • 最后,我们主要使用 GPT-5 Codex 和 GPT-5 Pro。

2.2. 提示词工程 (Prompt Engineering)

我们在提示词设计和系统级上下文构建上投入了大量精力。
关键思想是提供良好的示例和丰富的上下文,以便 LLM 能够学习如何有效地进行高尔夫优化。

  • 添加了许多已经匹配第一名分数的代码示例。
    • 这使得模型能够执行高级转换,例如递归,这通常对 LLM 来说很困难。
  • 包含有效高尔夫技巧的前后对比示例。
  • 使用 GPT-5 提示词优化器 系统地提高输出质量和一致性。
  • 用自定义文本文件补充提示词,其中包括:
  • 将这些组合成每个问题的结构化“提示词文件”,包含代码示例、测试数据和文本提示。
    下图显示了用于 AI 驱动代码高尔夫实验的此类提示词文件示例。
Prompt File Example
  • 使用手动编写更短代码时学到的技巧有助于提示词获得更好的分数。通过这个聪明的想法,即使是 gpt-5-mini 也能大约每 50 次尝试中获得一次更好的分数。

这些结构化的提示词文件帮助模型理解问题格式和高尔夫策略的本质,从而产生 consistently 更好的代码压缩效果。

2.3. 用于 AI 代理的自定义评估脚本

我们修改了官方评估脚本以更好地支持基于 LLM 的实验:

  • 显示 plain byte count 和 zlib/zopfli 压缩后的大小。
  • 计算并显示与第一名分数的差距。
    • 例如,GPT-5 Codex 经常将约 50 分的差距缩小到与第一名分数匹配。
  • 实施黑客过滤器以拒绝无效或 exploit 的输出,例如:
p=lambda g:type("",(),{"__eq__":lambda*_:1})()

(这是一个 46 字节的片段,可以在本地通过任何测试用例,但在排行榜上会失败)。

2.4. API 自动化

在收集了足够多的强初始解决方案后,我们自动化了这个过程:

对于每个任务,我们向模型提示:

  • 一组编程竞赛风格的测试用例,
  • 当前已知的最短代码,以及
  • 30-50 个从其他问题中随机选择的解决方案。

使用 gpt-5, gpt-5-mini 和 grok-4,我们进行了迭代改进。
平均而言,gpt-5 每 50 个问题产生一次几字节的改进,gpt-5-mini 每 100 个问题产生一次。


3. 基于规则的代码高尔夫

我们的团队在整个比赛期间维护了两个同步的数据集:

  1. Plain Shortest Codes:最短的未压缩版本。
  2. Best Score Codes:考虑压缩后达到最佳分数的版本。

每次更新或改进后,两个数据集都会通过后处理管道自动刷新。

3.1. 基于规则的后处理 Notebook

我们开发了 23 个基于规则的 Notebook,每分钟自动顺序执行。
每个 Notebook 应用特定的转换以进一步缩短代码,同时保持正确性。
以下是使用的主要规则总结:

  1. 移除注释
  2. 移除不必要的空白
  3. 移除软性(非关键)空白
  4. 展开 if True: 块并完全移除 if False:
  5. True/False 替换为 1/0
  6. len(x) == 0 替换为 not x
  7. x == False 替换为 not x
  8. x == True 替换为 x
  9. 安全地移除 pass 语句
  10. 缩短 return Nonereturn
  11. 移除尾部分号 ;
  12. 移除冗余括号
  13. 移除未使用的导入
  14. 移除字面量不必要的 list() 调用
  15. 自动将局部变量、函数和参数名称缩短为一个字符
  16. 通过 AST 转换应用全局单字符重命名
  17. 移除缩进并将函数体压缩为单行
  18. l.append(x) 替换为 l += [x]
  19. 缩短 from X import Yfrom X import *
  20. 使用外部库(例如基于 pyminifier 的工具)最小化标识符
  21. 将缩进宽度从 4 个空格减少到 1 个空格
  22. 为内置函数注入短别名(例如 range → R
  23. 移除所有 print 语句

这个自动化管道不断完善提交内容以接近最小字节数。
通过保持这些转换模块化和增量式,我们确保即使 minor 编辑也能安全地传播到最新代码版本。

3.2. 基于 AI 的后处理

除了基于规则的框架外,我们还使用 OpenAI API, Gemini API 和 Grok API 自动化了基于 AI 的后处理 Notebook。
这些 Notebook 定期执行,以执行更灵活、非基于规则的优化,并捕捉纯静态规则无法捕捉的改进。

3.3. pysearch

我们使用 pysearch 应用了 targeted 转换。
通过指定期望的输入/输出对,pysearch 合成满足它们的最短逻辑,这改进了一些问题的分数。

示例:
对于 task144.py,我们需要 3*(x==y),其中 x∈[0,7]y∈[0,2]
pysearch 将其重写为 3>>x+y,节省了 2 个字节。


4. 基于压缩的代码高尔夫

  • 语法优化:考虑到 zlib/zopfli 压缩,我们有时故意增加原始字节数以获得更好的压缩分数。
    例如,将 range 别名为 R=range 并使用 R() 可以减少原始字节,但不别名可能压缩得更好。
    我们首先手动执行了一些此类转换,然后将它们转化为提示词示例,并使用 GPT-5 相应地修订代码。

  • 变量名优化:基于 Garry Moss 的 Notebook compressed-variable-name-optimization
    我们加速并调整了搜索。
    我们推迟了昂贵的正确性检查,首先计算压缩字节数以加快迭代,并在分数提高时重置试验计数器。
    在实践中,我们首先运行感知压缩的重写,然后应用变量名优化,这产生了更好的整体压缩效率。

同比赛其他方案