"""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 # 后验差一级