Files
Mini-Nav/hw/sim/tests/model/test_ref_model_noise.py
SikongJueluo 8b4d4c1b57 refactor(cam): remove read noise from noise architecture (Phase 2)
- Make cam_read_noise a pass-through module, removing all noise injection logic
- Switch write noise to use noise_mask_bernoulli instead of noise_mask_grouped
- Add state machine to cam_write_noise for mask generation timing
- Remove noise_mask_grouped.sv (no longer needed)
- Remove read noise parameters from cam_noisy and cam_top
- Update simulation and benchmark code to reflect read noise removal
- Sync documentation to reflect Phase 2 architecture
2026-05-26 23:45:52 +08:00

103 lines
3.8 KiB
Python
Raw Permalink 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.
# -*- coding: utf-8 -*-
"""
参考模型ref_model的纯 Python 单元测试 — Phase 2 cleaned.
本文件不涉及任何 RTL / Verilator 仿真,仅验证 Python 参考模型的正确性。
Phase 2 后只保留 pure matching 函数;所有 grouped/read-noise helpers 已删除。
测试覆盖:
1. XNOR 评分语义 — 确认是「匹配位数」而非「汉明距离」
2. Top-1 matching — 纯匹配,正确选出最高分索引
3. Top-K matching — 返回排序后的行索引列表
4. Top-K 排序规则 — 分数降序、平局行号升序
5. Top-K k 超过行数时 clamp
"""
from __future__ import annotations
from model.ref_model import (
match_top1,
match_topk,
match_topk_from_scores,
xnor_popcount_score,
)
import numpy as np
# ==============================================================================
# 测试 1评分函数语义 — 确认是「XNOR 匹配位数」而非「汉明距离」
# ==============================================================================
def test_score_is_bit_match_popcount_not_hamming_distance():
"""
关键语义验证xnor_popcount_score 计算的是匹配位的数量,不是汉明距离。
示例:
query = 0b1010
stored = 0b1000
XNOR = 0b1101 → popcount = 3有 3 个位匹配)
汉明距离 = 1 → 只有一个位不同
为什么这个区分很重要:
- 如果 RTL 或模型错误地使用了汉明距离作为分数,则:
完全匹配的分数会是 0 而非 hash_bits512
Top-K 排序会颠倒(分数低的反而排前面)
- 这会导致整个 CAM 检索系统返回错误结果
"""
query = 0b1010
stored = 0b1000
assert xnor_popcount_score(query, stored, width=4) == 3
# ==============================================================================
# 测试 2Top-1 matching
# ==============================================================================
def test_match_top1_selects_highest_xnor_score_with_row_index_tiebreak():
"""Top-1 应选出 XNOR 分最高的行;平局时选最小行号。"""
rows = [0b0000, 0b1111, 0b0011, 0b0101]
query = 0b0000
result = match_top1(query, rows, width=4)
assert result.top1_index == 0
assert result.top1_score == 4
assert result.scores.tolist() == [4, 0, 2, 2]
# ==============================================================================
# 测试 3Top-K matching
# ==============================================================================
def test_match_topk_scores_rows_by_xnor_popcount():
"""match_topk 通过 xnor_popcount 计算分数,返回排序后的行索引和分数数组。"""
rows = [0b0000, 0b1111, 0b0011, 0b0101]
query = 0b0000
indices, scores = match_topk(query, rows, width=4, k=3)
assert scores.tolist() == [4, 0, 2, 2]
assert indices == [0, 2, 3]
# ==============================================================================
# 测试 4Top-K 排序 — 分数降序、平局行号升序
# ==============================================================================
def test_match_topk_from_scores_uses_score_desc_then_row_asc():
"""Top-K 排序规则:分数越大越优先;分数相同时行号越小越优先。"""
scores = np.array([7, 9, 9, 2, 7], dtype=np.int32)
assert match_topk_from_scores(scores, 4) == [1, 2, 0, 4]
# ==============================================================================
# 测试 5Top-K k 超过行数时 clamp
# ==============================================================================
def test_match_topk_clamps_k_to_row_count():
"""当 k 超过实际行数时,返回所有行(按排序)。"""
indices, scores = match_topk(0, [0, 1], width=1, k=5)
assert scores.tolist() == [1, 0]
assert indices == [0, 1]