feat: add auditable Trikona Shodhana

(cherry picked from commit 9531d1dcc70d1c3e2b70c9627ac077d47d484b92)
This commit is contained in:
732642856
2026-10-02 23:40:59 +08:00
committed by Jesse_Chen
parent 45d6dbf6ca
commit 54f6930b23
2 changed files with 48 additions and 0 deletions
+34
View File
@@ -586,3 +586,37 @@ def calc_sodhita_av(bav_results: Dict, planets: Dict, asc_sign_idx: int) -> Dict
'reduction_summary': total_reduction,
'validation_note': 'Sodhita AV ≤ 原始BAV(逐宫位)',
}
TRIKONA_SIGN_GROUPS = (
(0, 4, 8), # Aries, Leo, Sagittarius
(1, 5, 9), # Taurus, Virgo, Capricorn
(2, 6, 10), # Gemini, Libra, Aquarius
(3, 7, 11), # Cancer, Scorpio, Pisces
)
def calc_trikona_shodhana(sav_scores: List[int]) -> Dict:
"""Apply the classical Trikona Shodhana reduction to a 12-sign SAV row.
The minimum value in each elemental trine is removed from all three signs;
the original row remains in the result for auditability.
"""
if len(sav_scores) != 12:
raise ValueError('SAV scores must contain exactly 12 signs')
original = [int(value) for value in sav_scores]
reduced = original[:]
groups = []
for indexes in TRIKONA_SIGN_GROUPS:
baseline = min(original[index] for index in indexes)
for index in indexes:
reduced[index] -= baseline
groups.append({'sign_indexes': list(indexes), 'baseline_removed': baseline})
return {
'method': 'Trikona Shodhana',
'original_scores': original,
'reduced_scores': reduced,
'trikona_groups': groups,
'status': 'executed',
'claim_boundary': 'Standalone classical reduction; Ekadhipatya Shodhana remains a separate layer.',
}
+14
View File
@@ -0,0 +1,14 @@
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / 'scripts'))
from ashtakavarga import calc_trikona_shodhana # noqa: E402
def test_trikona_shodhana_removes_each_trine_baseline() -> None:
result = calc_trikona_shodhana(list(range(1, 13)))
assert result['reduced_scores'] == [0, 0, 0, 0, 4, 4, 4, 4, 8, 8, 8, 8]
assert result['trikona_groups'][0]['baseline_removed'] == 1