Files
Jyotisha/scripts/add_d60_to_test_charts.py
732642856 0406723b7e v6.1.3: D9/D60 engine upgrade + 5 bottleneck rules tuned
Engine (yoga_engine.py):
- Added D60/Shashtiamsa context injection (d60_house_of, d60_sign_of, etc.)
- Added D9 dignity queries (is_exalted_in_d9, is_own_sign_in_d9, etc.)
- Added functional_malefics() / functional_benefics()
- Added is_shashtiamsa_evil/good() and vaiseshikamsa_score()
- Exposed all new methods to rule expression sandbox

Data (_compute_one_chart.py):
- Generate D60 positions alongside D1/D9
- Inject D60 into context for all computed charts

Rules (yoga_rules.json):
- thrikaala_gnana: D1 strong = exalted/own/moola only (kendra/trikona removed)
  + D9 strong check (at least 1 of 3 in D9 exalted/own/moola)
  FP: 12→0, FN: stable
- dharidhra: restored method1 (L2/L11 in dusthana + unfriendly navamsa + malefic aspect)
  FN reduced
- bandhubhisthyaktha: added is_shashtiamsa_evil(lord_4)
- nishkapata: added vaiseshikamsa_score(lord(1)) >= 15
- kapata: reverted functional_malefics (caused 22 FN), back to MALEFICS

Validation:
- FP: 45→39 (-6)
- FN: 72→67 (-5)
- F1: 94.35%→94.88% (+0.53%)
- Precision: 95.60%→96.18% (+0.58%)

New scripts:
- scripts/add_d60_to_test_charts.py: batch D60 augmentation
- scripts/ashtottari_dasha.py, yogini_dasha.py, kalachakra_dasha.py
- scripts/report_orchestrator.py

D60 data added to all 60 standard test charts.
2026-06-07 14:44:53 +08:00

49 lines
1.6 KiB
Python

#!/usr/bin/env python3
"""为 standard_test_charts.json 批量补充 D60 (Shashtiamsa) 数据。"""
import json
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from _compute_one_chart import compute_yogas
ROOT = Path(__file__).resolve().parents[1]
STANDARD = ROOT / "references" / "standard_test_charts.json"
def main() -> int:
data = json.loads(STANDARD.read_text(encoding="utf-8"))
charts = data.get("charts", [])
print(f"Processing {len(charts)} charts for D60 augmentation...")
updated = 0
for i, chart in enumerate(charts):
name = chart.get("name", f"chart_{i}")
# Skip if already has d60
if chart.get("context", {}).get("d60"):
print(f" [{i+1}/{len(charts)}] {name}: already has D60, skipping")
continue
# Call compute_yogas to get full context with D60
result = compute_yogas(chart)
if "error" in result:
print(f" [{i+1}/{len(charts)}] {name}: ERROR - {result['error']}")
continue
new_context = result.get("context", {})
d60_data = new_context.get("d60")
if d60_data:
chart["context"]["d60"] = d60_data
updated += 1
print(f" [{i+1}/{len(charts)}] {name}: D60 added (asc={d60_data.get('ascendant')})")
else:
print(f" [{i+1}/{len(charts)}] {name}: no D60 data generated")
# Write back
STANDARD.write_text(json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8")
print(f"\nDone. Updated {updated}/{len(charts)} charts with D60 data.")
return 0
if __name__ == "__main__":
raise SystemExit(main())