Files
InfoRSI/tests/fixtures/rules/misc.json
T
iomgaa 60c21ae346 feat: 研究规则 rules 模块(任务书 02)
rules 是纯计算,src/rules 共 1761 行:方法.md 第六部分的全部公式、第七部分的余额与扣次、4.2 的入口分配,以及种子与规则登记表。

预期值有三个来源:方法.md 的手算例;tests/fixtures/rules/ 下不看实现写的 Python 脚本;参考项目 calc15、calc14b 里与现行方法一致的部分。审阅做了两轮,每轮都换一个全新上下文的子 Agent,提出的问题都已修复或写明不修的理由。

用户确认的约定(原话"1–8 都同意"):入池、采纳、消融中发现都用严格不等号;成本用 max(0, ĝ₀);没测的格附"含它的最好组合"的净值;战绩在分数原值上判。三个数改为严格递增后,删掉了尖峰的全部专门处理(bfb96ba)。vocab 里 Range 的说明同步改为严格递增。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 01:50:21 -04:00

944 lines
16 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"generator": "gen_forward_info.py",
"tolerance": {
"abs": 1e-12,
"note": "全是离散结果,必须完全相同。"
},
"scenarios": [
{
"name": "entries_rule1_unique",
"section": "4.2 分配规则;约定 38",
"params": {},
"input": {
"researchers": [
"r1",
"r2",
"r3"
],
"entries": [
{
"id": "e1",
"author": "r1"
},
{
"id": "e2",
"author": "r1"
},
{
"id": "e3",
"author": "r2"
},
{
"id": "e4",
"author": "r2"
},
{
"id": "e5",
"author": "r3"
},
{
"id": "e6",
"author": "r3"
}
],
"preferences": {
"r1": [
"e1",
"e3",
"e5"
],
"r2": [
"e3",
"e1",
"e5"
],
"r3": [
"e6",
"e1",
"e2"
]
}
},
"expected": {
"assignments": {
"r1": {
"entry": "e1",
"choice": 1
},
"r2": {
"entry": "e3",
"choice": 1
},
"r3": {
"entry": "e6",
"choice": 1
}
}
},
"note": "规则 1:第 1 志愿互不相同,各得第 1 志愿。"
},
{
"name": "entries_rule2_author_wins",
"section": "4.2 分配规则;约定 38",
"params": {},
"input": {
"researchers": [
"r1",
"r2",
"r3"
],
"entries": [
{
"id": "e1",
"author": "r1"
},
{
"id": "e2",
"author": "r1"
},
{
"id": "e3",
"author": "r2"
},
{
"id": "e4",
"author": "r2"
},
{
"id": "e5",
"author": "r3"
},
{
"id": "e6",
"author": "r3"
}
],
"preferences": {
"r1": [
"e3",
"e1",
"e2"
],
"r2": [
"e3",
"e4",
"e1"
],
"r3": [
"e3",
"e5",
"e1"
]
}
},
"expected": {
"assignments": {
"r1": {
"entry": "e1",
"choice": 2
},
"r2": {
"entry": "e3",
"choice": 1
},
"r3": {
"entry": "e5",
"choice": 2
}
}
},
"note": "规则 2:三人都选 e3,作者 r2 在其中,归 r2;r1、r3 进入第 2 轮,各得 e1、e5(第 2 志愿)。"
},
{
"name": "entries_rule2_smallest_index",
"section": "4.2 分配规则;约定 38",
"params": {},
"input": {
"researchers": [
"r1",
"r2",
"r3"
],
"entries": [
{
"id": "e1",
"author": "r1"
},
{
"id": "e2",
"author": "r1"
},
{
"id": "e3",
"author": "r2"
},
{
"id": "e4",
"author": "r2"
},
{
"id": "e5",
"author": "r3"
},
{
"id": "e6",
"author": "r3"
}
],
"preferences": {
"r1": [
"e5",
"e2",
"e3"
],
"r2": [
"e1",
"e4",
"e5"
],
"r3": [
"e1",
"e4",
"e2"
]
}
},
"expected": {
"assignments": {
"r1": {
"entry": "e5",
"choice": 1
},
"r2": {
"entry": "e1",
"choice": 1
},
"r3": {
"entry": "e4",
"choice": 2
}
}
},
"note": "规则 2:r2、r3 同选 e1,作者 r1 不在其中,归编号小的 r2;第 2 轮 r3 选 e4 得到。"
},
{
"name": "entries_identical_prefs",
"section": "4.2 分配规则;约定 38",
"params": {},
"input": {
"researchers": [
"r1",
"r2",
"r3"
],
"entries": [
{
"id": "e1",
"author": "r1"
},
{
"id": "e2",
"author": "r1"
},
{
"id": "e3",
"author": "r2"
},
{
"id": "e4",
"author": "r2"
},
{
"id": "e5",
"author": "r3"
},
{
"id": "e6",
"author": "r3"
}
],
"preferences": {
"r1": [
"e1",
"e2",
"e3"
],
"r2": [
"e1",
"e2",
"e3"
],
"r3": [
"e1",
"e2",
"e3"
]
}
},
"expected": {
"assignments": {
"r1": {
"entry": "e1",
"choice": 1
},
"r2": {
"entry": "e2",
"choice": 2
},
"r3": {
"entry": "e3",
"choice": 3
}
}
},
"note": "三人志愿完全相同:第 1 轮 e1 归作者 r1;第 2 轮 r2、r3 选 e2,作者 r1 已分到不在其中,归 r2;第 3 轮 r3 选 e3 得到。"
},
{
"name": "entries_rule3_exhausted",
"section": "4.2 分配规则;约定 38",
"params": {},
"input": {
"researchers": [
"r1",
"r2",
"r3"
],
"entries": [
{
"id": "e1",
"author": "r1"
},
{
"id": "e2",
"author": "r1"
},
{
"id": "e3",
"author": "r2"
},
{
"id": "e4",
"author": "r2"
},
{
"id": "e5",
"author": "r3"
},
{
"id": "e6",
"author": "r3"
}
],
"preferences": {
"r1": [
"e3",
"e5"
],
"r2": [
"e3",
"e5"
],
"r3": [
"e3",
"e5"
]
}
},
"expected": {
"assignments": {
"r1": {
"entry": "e1",
"choice": null
},
"r2": {
"entry": "e3",
"choice": 1
},
"r3": {
"entry": "e5",
"choice": 2
}
}
},
"note": "志愿用完:第 1 轮 e3 归作者 r2;第 2 轮 r1、r3 选 e5,作者 r3 在其中归 r3;r1 志愿用完,按规则 3 拿剩下编号最小的 e1,choice 为 null。"
},
{
"name": "entries_N1",
"section": "4.2 分配规则;约定 38",
"params": {},
"input": {
"researchers": [
"r1"
],
"entries": [
{
"id": "e1",
"author": "r1"
},
{
"id": "e2",
"author": "r1"
}
],
"preferences": {
"r1": [
"e2",
"e1"
]
}
},
"expected": {
"assignments": {
"r1": {
"entry": "e2",
"choice": 1
}
}
},
"note": "N=1:直接给第一志愿。"
},
{
"name": "entries_natural_rule2",
"section": "4.2 分配规则;约定 38",
"params": {},
"input": {
"researchers": [
"researcher-10",
"researcher-3",
"researcher-2"
],
"entries": [
{
"id": "e10",
"author": "researcher-2"
},
{
"id": "e1",
"author": "researcher-3"
},
{
"id": "e2",
"author": "researcher-3"
}
],
"preferences": {
"researcher-10": [
"e1"
],
"researcher-2": [
"e1"
],
"researcher-3": [
"e10"
]
}
},
"expected": {
"assignments": {
"researcher-2": {
"entry": "e1",
"choice": 1
},
"researcher-3": {
"entry": "e10",
"choice": 1
},
"researcher-10": {
"entry": "e2",
"choice": null
}
}
},
"note": "规则 2:researcher-10 与 researcher-2 同选 e1,作者 researcher-3 不在其中,归编号小的 researcher-2(按字符串序会错给 researcher-10);researcher-3 独选 e10;researcher-10 志愿用完,按规则 3 拿剩下的 e2。"
},
{
"name": "entries_natural_rule3",
"section": "4.2 分配规则;约定 38",
"params": {},
"input": {
"researchers": [
"researcher-10",
"researcher-3",
"researcher-2"
],
"entries": [
{
"id": "e10",
"author": "researcher-2"
},
{
"id": "e1",
"author": "researcher-3"
},
{
"id": "e2",
"author": "researcher-3"
}
],
"preferences": {
"researcher-10": [
"e1"
],
"researcher-2": [
"e1"
],
"researcher-3": [
"e1"
]
}
},
"expected": {
"assignments": {
"researcher-2": {
"entry": "e2",
"choice": null
},
"researcher-3": {
"entry": "e1",
"choice": 1
},
"researcher-10": {
"entry": "e10",
"choice": null
}
}
},
"note": "三人同选 e1,作者 researcher-3 在其中归他;researcher-2、researcher-10 志愿用完,按编号从小到大拿剩下编号最小的入口:researcher-2 拿 e2,researcher-10 拿 e10(按字符串序会把 e10 排在 e2 前面)。"
},
{
"name": "balance_part7_table",
"section": "第七部分示例;约定 35–36",
"params": {
"totalRuns": 13,
"batchCap": 2
},
"input": {
"steps": [
{
"step": "基线",
"added": [
"started"
]
},
{
"step": "第 1 轮正向",
"added": [
"started",
"started"
]
},
{
"step": "第 1 轮消融",
"added": [
"started",
"started"
]
},
{
"step": "第 2 轮正向",
"added": [
"started",
"started"
]
},
{
"step": "第 3 轮正向",
"added": [
"started",
"started"
]
},
{
"step": "第 3 轮消融",
"added": []
},
{
"step": "第 4 轮正向",
"added": [
"started",
"started"
]
},
{
"step": "第 5 轮正向",
"added": [
"started",
"started"
]
}
]
},
"expected": {
"afterEachStep": [
{
"step": "基线",
"added": [
"started"
],
"charged": 1,
"occupied": 1,
"balance": 12,
"forwardK": 2,
"ablationMax": 11
},
{
"step": "第 1 轮正向",
"added": [
"started",
"started"
],
"charged": 3,
"occupied": 3,
"balance": 10,
"forwardK": 2,
"ablationMax": 9
},
{
"step": "第 1 轮消融",
"added": [
"started",
"started"
],
"charged": 5,
"occupied": 5,
"balance": 8,
"forwardK": 2,
"ablationMax": 7
},
{
"step": "第 2 轮正向",
"added": [
"started",
"started"
],
"charged": 7,
"occupied": 7,
"balance": 6,
"forwardK": 2,
"ablationMax": 5
},
{
"step": "第 3 轮正向",
"added": [
"started",
"started"
],
"charged": 9,
"occupied": 9,
"balance": 4,
"forwardK": 2,
"ablationMax": 3
},
{
"step": "第 3 轮消融",
"added": [],
"charged": 9,
"occupied": 9,
"balance": 4,
"forwardK": 2,
"ablationMax": 3
},
{
"step": "第 4 轮正向",
"added": [
"started",
"started"
],
"charged": 11,
"occupied": 11,
"balance": 2,
"forwardK": 2,
"ablationMax": 1
},
{
"step": "第 5 轮正向",
"added": [
"started",
"started"
],
"charged": 13,
"occupied": 13,
"balance": 0,
"forwardK": 0,
"ablationMax": 0
}
]
},
"note": "每一步追加的运行记录状态,累计后算余额。余额序列 12,10,8,6,4,4,2,0。forwardK = min(每批上限, 余额);ablationMax = 余额−1(余额 ≤ 1 时 0)。"
},
{
"name": "balance_mixed_states",
"section": "第七部分;约定 35–36",
"params": {
"totalRuns": 6,
"batchCap": 2
},
"input": {
"runs": [
"started",
"reserved",
"notStarted",
"started",
"reserved"
]
},
"expected": {
"charged": 2,
"occupied": 4,
"balance": 2,
"forwardK": 2,
"ablationMax": 1
},
"note": "started 扣次;reserved(含状态未知)占着名额;notStarted 退还。已扣 2,占用 4,余额 2。"
},
{
"name": "balance_0",
"section": "第七部分;约定 36",
"params": {
"totalRuns": 3,
"batchCap": 2
},
"input": {
"runs": [
"started",
"started",
"started"
]
},
"expected": {
"charged": 3,
"occupied": 3,
"balance": 0,
"forwardK": 0,
"ablationMax": 0
},
"note": "余额 0、1、2 时的正向批量与消融上限。"
},
{
"name": "balance_1",
"section": "第七部分;约定 36",
"params": {
"totalRuns": 3,
"batchCap": 2
},
"input": {
"runs": [
"started",
"started"
]
},
"expected": {
"charged": 2,
"occupied": 2,
"balance": 1,
"forwardK": 1,
"ablationMax": 0
},
"note": "余额 0、1、2 时的正向批量与消融上限。"
},
{
"name": "balance_2",
"section": "第七部分;约定 36",
"params": {
"totalRuns": 3,
"batchCap": 2
},
"input": {
"runs": [
"started"
]
},
"expected": {
"charged": 1,
"occupied": 1,
"balance": 2,
"forwardK": 2,
"ablationMax": 1
},
"note": "余额 0、1、2 时的正向批量与消融上限。"
},
{
"name": "seed_study-a_r1",
"section": "约定 39–40",
"params": {},
"input": {
"studyId": "study-a",
"round": 1,
"version": 1,
"candidates": [
"c1",
"c2",
"c3",
"c4",
"c5"
],
"batchSize": 2,
"cells": [
"p1",
"p2",
"p3",
"p4"
],
"cellCount": 2,
"candidatesMany": [
"c1",
"c2",
"c3",
"c4",
"c5",
"c6",
"c7",
"c8",
"c9",
"c10",
"c11",
"c12"
],
"cellsMany": [
"p1",
"p2",
"p3",
"p4",
"p5",
"p6",
"p7",
"p8",
"p9",
"p10",
"p11",
"p12"
],
"manyCount": 4
},
"expected": {
"canonical": "{\"round\":1,\"studyId\":\"study-a\",\"version\":1}",
"seed": "39855ea9f581fcad6cb7710ac02151da468f2300ef72fefbbdabb3e191f62ff0",
"first6BytesHex": [
"d2d2a16d557a",
"c85c9f2d75ac",
"61392fbb6bbb"
],
"uniformInt10First5": [
2,
0,
7,
0,
2
],
"batchSample": [
"c2",
"c3"
],
"cellSample": [
"p3",
"p4"
],
"batchSampleMany": [
"c5",
"c7",
"c9",
"c10"
],
"cellSampleMany": [
"p5",
"p7",
"p9",
"p10"
]
},
"note": "种子 = sha256(规范 JSON {round, studyId, version})。uniformInt:sha256(`${seed}:${counter}`) 前 6 字节大端,counter 从 0 起;uniformInt10First5 是同一个生成器连续 5 次。batchSample、cellSample 各自用一个从 counter=0 开始的新生成器,部分 Fisher–Yates 后取前 size 个再排序。候选、因子编号都按自然序(c2 < c10、p2 < p10);*Many 两项用 12 个编号核对这一点。"
},
{
"name": "seed_15-real-1_r3",
"section": "约定 39–40",
"params": {},
"input": {
"studyId": "15-real-1",
"round": 3,
"version": 1,
"candidates": [
"c1",
"c2",
"c3",
"c4",
"c5"
],
"batchSize": 2,
"cells": [
"p1",
"p2",
"p3",
"p4"
],
"cellCount": 2,
"candidatesMany": [
"c1",
"c2",
"c3",
"c4",
"c5",
"c6",
"c7",
"c8",
"c9",
"c10",
"c11",
"c12"
],
"cellsMany": [
"p1",
"p2",
"p3",
"p4",
"p5",
"p6",
"p7",
"p8",
"p9",
"p10",
"p11",
"p12"
],
"manyCount": 4
},
"expected": {
"canonical": "{\"round\":3,\"studyId\":\"15-real-1\",\"version\":1}",
"seed": "cb9cc4dbd939af39de4852c42806f3471e90bd0e16427ced09087345586506ff",
"first6BytesHex": [
"f5b64e27d768",
"0b0216f8610e",
"b48a7659e2b5"
],
"uniformInt10First5": [
8,
4,
7,
7,
6
],
"batchSample": [
"c1",
"c4"
],
"cellSample": [
"p1",
"p3"
],
"batchSampleMany": [
"c6",
"c9",
"c10",
"c11"
],
"cellSampleMany": [
"p6",
"p9",
"p10",
"p11"
]
},
"note": "种子 = sha256(规范 JSON {round, studyId, version})。uniformInt:sha256(`${seed}:${counter}`) 前 6 字节大端,counter 从 0 起;uniformInt10First5 是同一个生成器连续 5 次。batchSample、cellSample 各自用一个从 counter=0 开始的新生成器,部分 Fisher–Yates 后取前 size 个再排序。候选、因子编号都按自然序(c2 < c10、p2 < p10);*Many 两项用 12 个编号核对这一点。"
}
]
}