Files
Jyotisha/tests/verify_large_scale.py
2026-07-16 23:45:00 +08:00

214 lines
9.9 KiB
Python

#!/usr/bin/env python3
"""
大规模协同验证:18名人婚姻案例 × 5功能模块
测试: Double Transit PAC+D9, Transit LL/7L, 行星聚集, Vivah Saham, Chara Dasha
"""
import sys, json, os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'scripts'))
import swisseph as swe
swe.set_ephe_path('')
from jyotish_engine import (
compute_chart_data, cmd_double_transit_pac, cmd_transit_ll7l,
cmd_planetary_congregation, cmd_vivah_saham, SIGN_LORDS, SIGNS
)
from jaimini import calc_chara_dasha_with_antardasha
# 18名人案例(来自 v6.1 验证脚本)
CASES = [
{'name':'Nelson Mandela','birth':(1918,7,18,14.0,-33.32,26.52),'gender':'M',
'marriage1':(1944,10,5)},
{'name':'Tom Cruise','birth':(1962,7,3,19.25,43.05,-76.15),'gender':'M',
'marriage1':(1987,5,9)},
{'name':'Elon Musk','birth':(1971,6,28,5.0,-25.74,28.19),'gender':'M',
'marriage1':(2000,1,1)},
{'name':'Oprah Winfrey','birth':(1954,1,29,11.88,33.51,-88.52),'gender':'F',
'marriage1':(1986,1,1)},
{'name':'Prince Harry','birth':(1984,9,15,15.33,51.5,-0.17),'gender':'M',
'marriage1':(2018,5,19)},
{'name':'Jeff Bezos','birth':(1964,1,12,9.63,25.78,-80.19),'gender':'M',
'marriage1':(1993,1,1)},
{'name':'Priyanka Chopra','birth':(1982,7,18,10.5,23.57,87.19),'gender':'F',
'marriage1':(2018,12,1)},
{'name':'Shah Rukh Khan','birth':(1965,11,1,21.25,28.61,77.21),'gender':'M',
'marriage1':(1991,10,25)},
{'name':'Britney Spears','birth':(1981,12,2,19.92,31.17,-89.18),'gender':'F',
'marriage1':(2004,1,3)},
{'name':'Mark Zuckerberg','birth':(1984,5,14,19.67,40.71,-74.01),'gender':'M',
'marriage1':(2012,5,19)},
{'name':'Narendra Modi','birth':(1950,9,17,4.78,23.03,72.58),'gender':'M',
'marriage1':(1968,1,1)},
{'name':'Amitabh Bachchan','birth':(1942,10,11,10.5,25.43,81.85),'gender':'M',
'marriage1':(1973,6,3)},
]
def make_args(y,m,d,h,mi,lat,lon,tz,date_str,house=7):
"""构建 args 对象"""
return type('Args', (), {
'year':y,'month':m,'day':d,'hour':h,'minute':mi,
'lat':lat,'lon':lon,'tz':tz,
'date':date_str,'house':house,
'transit_date':date_str,
})()
def run():
results = []
stats = {'dt':0,'p5':0,'p8':0,'pariv':0,'cong':0,'vs':0,'cd':0}
total = 0
for case in CASES:
y,m,d,h_utc,lat,lon = case['birth']
name = case['name']
my,mm,md_d = case['marriage1']
date_str = f"{my}-{mm:02d}-{md_d:02d}"
total += 1
# 转UTC hour (假设 birth 中 h 已经是 UTC)
hour_int = int(h_utc)
minute_int = int((h_utc - hour_int) * 60)
tz = 0 # UTC
print(f"\n{'='*50}")
print(f"[{total}] {name} | 婚姻: {date_str}")
print(f"{'='*50}")
signals = []
# 1. Double Transit PAC + D9
dt_hit = False
try:
dt_r = cmd_double_transit_pac(make_args(y,m,d,hour_int,minute_int,lat,lon,tz,date_str))
dt_hit = len(dt_r.get('double_transit',[])) > 0
if dt_hit:
signals.append('DT')
stats['dt'] += 1
dt_list = dt_r.get('double_transit',[])
layer_str = ','.join(set(l['layer'] for l in dt_list)) if dt_list else '-'
dt_summary = dt_r.get('summary','')
print(f" [DT PAC+D9] {'' if dt_hit else ''} layers={layer_str} {dt_summary}")
except Exception as e:
print(f" [DT PAC+D9] ERROR: {e}")
dt_hit = False # ERROR不计为hit
# 2. Transit LL/7L
try:
ll7l_r = cmd_transit_ll7l(make_args(y,m,d,hour_int,minute_int,lat,lon,tz,date_str))
p5 = ll7l_r['p5']['hit']
p8 = ll7l_r['p8']['hit']
pariv = ll7l_r['parivartana']['hit']
if p5: signals.append('P5'); stats['p5'] += 1
if p8: signals.append('P8'); stats['p8'] += 1
if pariv: signals.append('Pariv'); stats['pariv'] += 1
print(f" [LL/7L] P5={'' if p5 else ''} P8={'' if p8 else ''} Pariv={'' if pariv else ''}")
except Exception as e:
print(f" [LL/7L] ERROR: {e}")
# 3. 行星聚集
try:
cong_r = cmd_planetary_congregation(make_args(y,m,d,hour_int,minute_int,lat,lon,tz,date_str,7))
cong_hit = cong_r.get('hit', False)
if cong_hit: signals.append('聚集'); stats['cong'] += 1
print(f" [聚集] {'' if cong_hit else ''} {cong_r.get('summary','')}")
except Exception as e:
print(f" [聚集] ERROR: {e}")
# 4. Vivah Saham
try:
vs_r = cmd_vivah_saham(make_args(y,m,d,hour_int,minute_int,lat,lon,tz,date_str))
ta = vs_r.get('transit_activation', {})
vs_double = ta.get('double_activation', False) if ta else False
if vs_double: signals.append('VS双星'); stats['vs'] += 1
jup = [c['type'] for c in ta.get('jupiter',[])] if ta else []
sat = [c['type'] for c in ta.get('saturn',[])] if ta else []
vs_s = vs_r.get('vivah_saham',{})
print(f" [VivahSaham] {vs_s.get('sign_cn','?')} {vs_s.get('degree_in_sign',0):.1f}° | 双星={'' if vs_double else ''} Jup={jup} Sat={sat}")
except Exception as e:
print(f" [VivahSaham] ERROR: {e}")
# 5. Chara Dasha (Antardasha)
try:
chart, asc_idx, jd, aya = compute_chart_data(y,m,d,hour_int,minute_int,lat,lon,tz)
if chart:
p_lons = {pn: pd['degree'] for pn, pd in chart['planets'].items() if 'degree' in pd}
cd = calc_chara_dasha_with_antardasha(asc_idx, p_lons, y, m)
m_year, m_month = my, mm
md_name = ''; ad_name = ''
for md_d in cd['dasha_sequence']:
s_y, s_m = map(int, md_d['start_date'].split('-'))
e_y, e_m = map(int, md_d['end_date'].split('-'))
if (m_year > s_y or (m_year == s_y and m_month >= s_m)) and \
(m_year < e_y or (m_year == e_y and m_month <= e_m)):
md_name = f"{md_d['sign']}({md_d['lord']})"
for ad in md_d.get('antardashas', []):
as_y, as_m = map(int, ad['start_date'].split('-'))
ae_y, ae_m = map(int, ad['end_date'].split('-'))
if (m_year > as_y or (m_year == as_y and m_month >= as_m)) and \
(m_year < ae_y or (m_year == ae_y and m_month <= ae_m)):
ad_name = f"{ad['sign']}({ad['lord']})"
break
break
# 检查 MD 或 AD 是否涉及 7 宫相关
seven_sign = SIGNS[(asc_idx + 6) % 12]
seven_lord = SIGN_LORDS[seven_sign]
ll = SIGN_LORDS[SIGNS[asc_idx]]
cd_relevant = seven_lord in md_name or ll in md_name or seven_lord in ad_name or ll in ad_name
if cd_relevant: signals.append('CD'); stats['cd'] += 1
print(f" [CharaDasha] MD={md_name} AD={ad_name} | 7宫相关={'' if cd_relevant else ''}")
except Exception as e:
print(f" [CharaDasha] ERROR: {e}")
score = len(signals)
if score >= 3: verdict = '✅强'
elif score == 2: verdict = '⚠️中'
elif score == 1: verdict = '⚠️弱'
else: verdict = '❌无'
print(f" >>> 综合: {verdict} ({score}/6) 信号={signals}")
results.append({
'name': name, 'marriage': date_str,
'signals': signals, 'score': score, 'verdict': verdict,
})
# 汇总
print(f"\n{'='*60}")
print(f"大规模验证汇总 ({total} 案例)")
print(f"{'='*60}")
strong = sum(1 for r in results if r['score'] >= 3)
medium = sum(1 for r in results if r['score'] == 2)
weak = sum(1 for r in results if r['score'] == 1)
none_c = sum(1 for r in results if r['score'] == 0)
print(f"\n综合评分分布:")
print(f" 强确认 (≥3信号): {strong}/{total} ({strong/total*100:.0f}%)")
print(f" 中等确认 (2信号): {medium}/{total} ({medium/total*100:.0f}%)")
print(f" 弱信号 (1信号): {weak}/{total} ({weak/total*100:.0f}%)")
print(f" 无确认 (0信号): {none_c}/{total} ({none_c/total*100:.0f}%)")
print(f"\n各功能命中率:")
print(f" Double Transit PAC+D9: {stats['dt']}/{total} ({stats['dt']/total*100:.0f}%)")
print(f" Transit LL/7L P5: {stats['p5']}/{total} ({stats['p5']/total*100:.0f}%)")
print(f" Transit LL/7L P8: {stats['p8']}/{total} ({stats['p8']/total*100:.0f}%)")
print(f" Parivartana 互换: {stats['pariv']}/{total} ({stats['pariv']/total*100:.0f}%)")
print(f" 行星聚集: {stats['cong']}/{total} ({stats['cong']/total*100:.0f}%)")
print(f" Vivah Saham 双星激活: {stats['vs']}/{total} ({stats['vs']/total*100:.0f}%)")
print(f" Chara Dasha 7宫相关: {stats['cd']}/{total} ({stats['cd']/total*100:.0f}%)")
avg_score = sum(r['score'] for r in results) / total
at_least_1 = sum(1 for r in results if r['score'] >= 1)
at_least_2 = sum(1 for r in results if r['score'] >= 2)
print(f"\n核心指标:")
print(f" 平均信号数: {avg_score:.1f}/6")
print(f" ≥1信号覆盖率: {at_least_1}/{total} ({at_least_1/total*100:.0f}%)")
print(f" ≥2信号覆盖率: {at_least_2}/{total} ({at_least_2/total*100:.0f}%)")
# 保存
out = os.path.join(os.path.dirname(__file__), 'test-data', 'verify-large-scale-results.json')
with open(out, 'w', encoding='utf-8') as f:
json.dump({'results': results, 'stats': stats, 'total': total}, f, ensure_ascii=False, indent=2)
print(f"\n结果已保存: {out}")
if __name__ == '__main__':
run()