Files

79 lines
2.6 KiB
Python
Raw Permalink Normal View History

"""decision 包测试。"""
from __future__ import annotations
import numpy as np
import pytest
pytestmark = pytest.mark.skip(reason="未实现:见 docs/03-roadmap.md L1")
def test_topsis_ranks_dominated_alternative_last():
"""一个在所有指标上都最差的方案,TOPSIS 必须排最后。"""
from mcm_toolkit.decision import topsis
X = np.array(
[
[9.0, 8.0, 7.0], # 全面最优
[5.0, 5.0, 5.0], # 中等
[1.0, 1.0, 1.0], # 全面最差
]
)
r = topsis(X, benefit_columns=[0, 1, 2])
ranks = dict(zip(range(3), r.data["rank"], strict=False))
assert ranks[0] == 1
assert ranks[2] == 3
def test_topsis_direction_flips_result():
"""把某列从效益型改成成本型,排名必须变——方向不能静默搞错。"""
from mcm_toolkit.decision import topsis
X = np.array([[9.0, 1.0], [1.0, 9.0]])
a = topsis(X, benefit_columns=[0, 1])
b = topsis(X, benefit_columns=[0])
assert list(a.data["rank"]) != list(b.data["rank"])
def test_entropy_weights_sum_to_one_and_prefers_dispersed_column(rng):
from mcm_toolkit.decision import entropy_weights
X = np.column_stack([rng.normal(size=50), np.ones(50)]) # 第二列无差异
r = entropy_weights(X)
assert np.isclose(r.params["weights"].sum(), 1.0)
assert r.params["weights"][0] > r.params["weights"][1]
def test_entropy_weights_handles_zero_and_negative():
"""熵权法的三个坑之一:零值不能产生 NaN。"""
from mcm_toolkit.decision import entropy_weights
r = entropy_weights(np.array([[0.0, 1.0], [1.0, 2.0], [2.0, 0.0]]))
assert np.isfinite(r.params["weights"]).all()
def test_ahp_consistency_for_consistent_matrix():
"""完全一致的判断矩阵 CR 应接近 0。"""
from mcm_toolkit.decision import ahp_weights
A = np.array([[1, 2, 4], [0.5, 1, 2], [0.25, 0.5, 1]], dtype=float)
r = ahp_weights(A)
assert r.metrics["CR"] < 0.01
def test_ahp_weights_match_geometric_mean_for_consistent_matrix():
from mcm_toolkit.decision import ahp_weights
A = np.array([[1, 2, 4], [0.5, 1, 2], [0.25, 0.5, 1]], dtype=float)
r = ahp_weights(A)
geo = (A.prod(axis=1)) ** (1 / 3)
assert np.allclose(r.params["weights"], geo / geo.sum(), atol=1e-3)
def test_gm11_fits_exponential_sequence():
"""GM(1,1) 对纯指数序列应拟合得极好。"""
from mcm_toolkit.decision import gm11_fit_predict
series = [2.0 * 1.1**k for k in range(6)]
r = gm11_fit_predict(series, steps=2)
assert r.metrics["c_ratio"] < 0.35 # 后验差一级