108 lines
4.4 KiB
Python
108 lines
4.4 KiB
Python
"""偏好重排纯函数合同:分列计数、有界惩罚、确定性探索位与权重护栏。"""
|
||
|
||
import pytest
|
||
|
||
from muse.上下文.偏好重排 import (
|
||
偏好信号,
|
||
偏好值,
|
||
合并信号表,
|
||
应用拒绝惩罚,
|
||
权重表,
|
||
构建偏好路,
|
||
注入探索位,
|
||
)
|
||
|
||
|
||
@pytest.mark.case_id(
|
||
"NC-w32-a10015",
|
||
environment="离线",
|
||
given="挑选信号行与消费统计",
|
||
when="合并信号表",
|
||
then=["弱强信号分列计数不混算;同版本两路信号并存"],
|
||
contract="docs/系统架构/新版设计/模块设计/B09-上下文.md#偏好重排通路",
|
||
)
|
||
def test_合并信号表分列不混算__a10015():
|
||
表 = 合并信号表(
|
||
[
|
||
{"method_version_id": "v1", "选用次数": 3, "拒绝次数": 1, "选中位次": [1, 2]},
|
||
{"method_version_id": "v2", "选用次数": 0, "拒绝次数": 2, "选中位次": []},
|
||
],
|
||
{"v1": 5, "v3": 2},
|
||
)
|
||
assert 表["v1"] == 偏好信号(3, 1, 5, (1, 2))
|
||
assert 表["v2"] == 偏好信号(0, 2, 0, ())
|
||
assert 表["v3"] == 偏好信号(0, 0, 2, ())
|
||
# 分列:选用与消费不互相折算
|
||
assert 偏好值(表["v1"]) == pytest.approx(3 * 0.05 + 1 * -0.08 + 5 * 0.10)
|
||
|
||
|
||
@pytest.mark.case_id(
|
||
"NC-w32-a10016",
|
||
environment="离线",
|
||
given="正负偏好信号与双路融合分",
|
||
when="构建偏好路并应用拒绝惩罚",
|
||
then=["只有正偏好进路;惩罚有界且不超过偏好路末位贡献"],
|
||
contract="docs/系统架构/新版设计/模块设计/B09-上下文.md#偏好重排通路",
|
||
)
|
||
def test_正偏好进路负偏好有界惩罚__a10016():
|
||
信号表 = {
|
||
"v1": 偏好信号(选用次数=2),
|
||
"v2": 偏好信号(拒绝次数=3),
|
||
"v3": 偏好信号(),
|
||
}
|
||
路 = 构建偏好路(信号表)
|
||
assert set(路) == {"v1"} and 路["v1"] > 0
|
||
融合 = {"v1": 0.03, "v2": 0.03, "v3": 0.03}
|
||
调整 = 应用拒绝惩罚(融合, 信号表)
|
||
assert 调整["v1"] == 0.03 and 调整["v3"] == 0.03
|
||
assert 调整["v2"] < 0.03
|
||
# 惩罚上界 = 路权重/61(偏好路末位贡献量级)
|
||
assert 0.03 - 调整["v2"] <= 权重表["路权重"] / 61.0 + 1e-12
|
||
# 大量拒绝也不能把惩罚推出上界(有界归一)
|
||
巨量 = {"v9": 偏好信号(拒绝次数=10000)}
|
||
融合巨量 = {"v9": 0.03}
|
||
assert 0.03 - 应用拒绝惩罚(融合巨量, 巨量)["v9"] < 权重表["路权重"] / 61.0
|
||
|
||
|
||
@pytest.mark.case_id(
|
||
"NC-w32-a10017",
|
||
environment="离线",
|
||
given="含已探索头部与未探索尾部的排名",
|
||
when="注入探索位",
|
||
then=["至多两个未探索版本晋升,替换头部末尾已探索项,结果确定"],
|
||
contract="docs/系统架构/新版设计/模块设计/B09-上下文.md#偏好重排通路",
|
||
)
|
||
def test_探索位晋升确定且有界__a10017():
|
||
信号表 = {"a": 偏好信号(选用次数=1), "b": 偏好信号(消费次数=1), "c": 偏好信号(拒绝次数=1)}
|
||
排名 = [("a", 0.9), ("b", 0.8), ("c", 0.7), ("d", 0.6), ("e", 0.5)]
|
||
新排名, 探索集 = 注入探索位(排名, 信号表, 3)
|
||
头部 = [vid for vid, _ in 新排名[:3]]
|
||
# d、e 未探索:晋升两个,替换头部末尾的已探索项(c、b)
|
||
assert 头部[0] == "a" and set(头部[1:]) == {"d", "e"}
|
||
assert 探索集 == {"d", "e"}
|
||
# 未晋升的尾部按原序接回,候选回填链完整、总长度不变
|
||
assert [vid for vid, _ in 新排名] == ["a", "d", "e", "b", "c"]
|
||
# 确定性:同输入同输出
|
||
assert 注入探索位(排名, 信号表, 3)[0] == 新排名
|
||
# 头部已含足量未探索项时不动
|
||
不动, 集 = 注入探索位([("d", 0.9), ("e", 0.8), ("a", 0.7)], 信号表, 3)
|
||
assert [vid for vid, _ in 不动] == ["d", "e", "a"] and 集 == {"d", "e"}
|
||
# 全已探索且无尾部候选时不动
|
||
全探索 = [("a", 0.9), ("b", 0.8)]
|
||
assert 注入探索位(全探索, 信号表, 2)[0] == 全探索
|
||
|
||
|
||
@pytest.mark.case_id(
|
||
"NC-w32-a10018",
|
||
environment="离线",
|
||
given="版本化权重表",
|
||
when="核对权重护栏",
|
||
then=["偏好路权重不超过0.25,权重表带版本标识"],
|
||
contract="docs/系统架构/新版设计/模块设计/B09-上下文.md#偏好重排通路",
|
||
)
|
||
def test_权重表护栏__a10018():
|
||
assert 权重表["version"] == "preference-rerank-v1"
|
||
assert 0 < 权重表["路权重"] <= 0.25
|
||
assert 权重表["种类权重"]["拒绝"] < 0 < 权重表["种类权重"]["选用"]
|
||
assert 权重表["探索位"] in (1, 2)
|