Files
Jyotisha/benchmarks/jyotish/scripts/run_shadbala_compare.py
T

125 lines
4.8 KiB
Python

#!/usr/bin/env python3
"""
Shadbala Benchmark v1.0
比较 v6.1.13 yinduzhanxing Shadbala 与 PyJHora 实现。
依赖: pip install jhora numpy
"""
import sys, json, os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'scripts')))
from shadbala import calc_shadbala, NAISARGIKA_BALA
# PyJHora
from jhora import const, utils
from jhora.panchanga import drik
from jhora.horoscope.chart import charts
from jhora.horoscope.chart import strength as pj_strength
TEST_CASES = [
{"id": "beijing_1990_noon", "year":1990, "month":6, "day":15, "hour":12, "minute":0, "lat":39.9, "lon":116.4, "tz":8},
{"id": "newyork_1985_morning", "year":1985, "month":3, "day":22, "hour":9, "minute":30, "lat":40.7, "lon":-74.0, "tz":-5},
{"id": "london_1970_evening", "year":1970, "month":9, "day":12, "hour":19, "minute":0, "lat":51.5, "lon":-0.1, "tz":0},
{"id": "delhi_2000_midnight", "year":2000, "month":1, "day":1, "hour":0, "minute":0, "lat":28.6, "lon":77.2, "tz":5.5},
{"id": "sydney_1999_afternoon", "year":1999, "month":8, "day":7, "hour":15, "minute":45, "lat":-33.9, "lon":151.2, "tz":10},
]
PLANET_NAMES = ['Sun', 'Moon', 'Mars', 'Mercury', 'Jupiter', 'Venus', 'Saturn']
SIGNS = ['Aries', 'Taurus', 'Gemini', 'Cancer', 'Leo', 'Virgo',
'Libra', 'Scorpio', 'Sagittarius', 'Capricorn', 'Aquarius', 'Pisces']
def run_benchmark():
total_planets = 0
within_10pct = 0
within_20pct = 0
details = []
for case in TEST_CASES:
dob = drik.Date(case["year"], case["month"], case["day"])
tob = (case["hour"], case["minute"], 0)
place = drik.Place(f'test_{case["id"]}', case["lat"], case["lon"], case["tz"])
jd = utils.julian_day_number(dob, tob)
pp = charts.divisional_chart(jd, place, divisional_chart_factor=1)[:const._pp_count_upto_ketu]
# 提取行星位置
asc_sign_idx = pp[0][1][0]
sun_sign = pp[const.SUN_ID + 1][1][0]
moon_sign = pp[const.MOON_ID + 1][1][1]
sun_lon = sun_sign * 30 + pp[const.SUN_ID + 1][1][1]
moon_lon = moon_sign
planets = {}
for pid, pname in {const.SUN_ID: 'Sun', const.MOON_ID: 'Moon',
const.MARS_ID: 'Mars', const.MERCURY_ID: 'Mercury',
const.JUPITER_ID: 'Jupiter', const.VENUS_ID: 'Venus',
const.SATURN_ID: 'Saturn'}.items():
sign = pp[pid + 1][1][0]
deg = pp[pid + 1][1][1]
house = (sign - asc_sign_idx) % 12 + 1
retro = pp[pid + 1][4] if len(pp[pid + 1]) > 4 else False
speed = pp[pid + 1][3] if len(pp[pid + 1]) > 3 else 1.0
planets[pname] = {
'sign': SIGNS[sign],
'degree': sign * 30 + deg,
'house': house,
'retrograde': retro,
'speed': speed,
}
# 我们的Shadbala
our = calc_shadbala(planets, SIGNS[asc_sign_idx],
case["hour"] + case["minute"] / 60,
sun_lon, moon_lon, case["minute"])
# PyJHora Shadbala
try:
pj_total_rupas = pj_strength.shad_bala(jd, place)[7]
except:
print(f" PyJHora shadbala failed for {case['id']}")
continue
case_match = 0
case_total = 0
case_details = []
for pname in PLANET_NAMES:
if pname not in planets or pname not in our['planets']:
continue
our_rupas = our['planets'][pname]['total_rupas']
pj_rupas = pj_total_rupas[PLANET_NAMES.index(pname)]
total_planets += 1
if pj_rupas > 0:
diff_pct = abs(our_rupas - pj_rupas) / pj_rupas * 100
if diff_pct <= 10:
within_10pct += 1
if diff_pct <= 20:
within_20pct += 1
case_details.append(f"{pname}: us={our_rupas:.2f}, pj={pj_rupas:.2f} ({diff_pct:.1f}%)")
details.append({
'case': case['id'],
'planets': case_details,
})
print("=" * 80)
print("Shadbala Benchmark v1.0")
print(f"Total planets: {total_planets}")
print("=" * 80)
print(f"Within 10% of PyJHora: {within_10pct}/{total_planets} = {within_10pct/total_planets*100:.1f}%" if total_planets else "N/A")
print(f"Within 20% of PyJHora: {within_20pct}/{total_planets} = {within_20pct/total_planets*100:.1f}%" if total_planets else "N/A")
for d in details:
print(f"\n{d['case']}:")
for pd in d['planets']:
print(f" {pd}")
if within_20pct / total_planets >= 0.8 if total_planets else False:
print("\n✅ PASS (≥80% within 20%)")
else:
print("\n⚠️ NEEDS IMPROVEMENT")
if __name__ == "__main__":
run_benchmark()