feat: migrate precise Shadbala parity
This commit is contained in:
@@ -197,6 +197,15 @@ def build_pyjhora_sample(sample, *, node_mode='mean'):
|
||||
'sav': list(sav),
|
||||
},
|
||||
'shadbala': {name: float(shadbala[6][index]) for index, name in enumerate(['Sun', 'Moon', 'Mars', 'Mercury', 'Jupiter', 'Venus', 'Saturn'])},
|
||||
'shadbala_components': {
|
||||
name: {
|
||||
component: float(shadbala[row_index][index])
|
||||
for component, row_index in {
|
||||
'sthana': 0, 'kala': 1, 'dig': 2, 'chesta': 3, 'naisargika': 4, 'drik': 5,
|
||||
}.items()
|
||||
}
|
||||
for index, name in enumerate(['Sun', 'Moon', 'Mars', 'Mercury', 'Jupiter', 'Venus', 'Saturn'])
|
||||
},
|
||||
'dasha': dasha,
|
||||
}
|
||||
|
||||
@@ -276,6 +285,13 @@ def compare_one(sample_id, local, pyjhora):
|
||||
rows, sample_id, 'Shadbala', planet, 'total_virupas',
|
||||
local.get('shadbala', {}).get(planet), pyjhora.get('shadbala', {}).get(planet), tolerance=0.5,
|
||||
)
|
||||
for component in ['sthana', 'kala', 'dig', 'chesta', 'naisargika', 'drik']:
|
||||
compare_scalar(
|
||||
rows, sample_id, 'Shadbala_Component', planet, component,
|
||||
local.get('shadbala_components', {}).get(planet, {}).get(component),
|
||||
pyjhora.get('shadbala_components', {}).get(planet, {}).get(component),
|
||||
tolerance=0.5,
|
||||
)
|
||||
# PyJHora dasha is useful as external signal, but currently has different default starting convention/seed in some cases.
|
||||
# Keep fields in matrix, with generous date tolerance; differences are classified below in report.
|
||||
for field in ['mahadasha_lord', 'antardasha_lord']:
|
||||
|
||||
@@ -111,6 +111,17 @@ def canonicalize(sample, data):
|
||||
'sav': [safe_get(modules, 'ashtakavarga', 'sav', 'scores', sign) for sign in ['Aries', 'Taurus', 'Gemini', 'Cancer', 'Leo', 'Virgo', 'Libra', 'Scorpio', 'Sagittarius', 'Capricorn', 'Aquarius', 'Pisces']],
|
||||
},
|
||||
'shadbala': {name: safe_get(modules, 'shadbala', 'planets', name, 'total_virupas') for name in PLANETS[:7]},
|
||||
'shadbala_components': {
|
||||
name: {
|
||||
'sthana': safe_get(modules, 'shadbala', 'planets', name, 'sthana_bala', 'total'),
|
||||
'kala': safe_get(modules, 'shadbala', 'planets', name, 'kala_bala', 'total'),
|
||||
'dig': safe_get(modules, 'shadbala', 'planets', name, 'dig_bala'),
|
||||
'chesta': safe_get(modules, 'shadbala', 'planets', name, 'chesta_bala'),
|
||||
'naisargika': safe_get(modules, 'shadbala', 'planets', name, 'naisargika_bala'),
|
||||
'drik': safe_get(modules, 'shadbala', 'planets', name, 'drik_bala'),
|
||||
}
|
||||
for name in PLANETS[:7]
|
||||
},
|
||||
'dasha': {
|
||||
'mahadasha_lord': current.get('lord'),
|
||||
'mahadasha_start': current.get('start'),
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# Shadbala High-Rigor Migration Implementation Plan
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Port the reviewed `f3bae51` Shadbala component-formula correction and its public high-rigor parity evidence from research to the commercial backend without importing research worktree residue.
|
||||
|
||||
**Architecture:** Use the committed research tree at `f3bae51` as the only source. First add the precise-context regression to commercial and observe failure; then port the smallest calculation/API/engine changes needed for it. Public Steve Jobs artifacts and the parity manifest move only after privacy and hash checks.
|
||||
|
||||
**Tech Stack:** Python 3, pytest, existing Swiss Ephemeris/Jyotish engine, JSON evidence manifests.
|
||||
|
||||
### Task 1: Port formula regression first
|
||||
|
||||
**Files:**
|
||||
- Create: `tests/test_shadbala_precise_context.py`
|
||||
- Modify: `scripts/shadbala.py`
|
||||
- Modify: `scripts/jyotish_engine.py`
|
||||
- Modify: `scripts/jyotish_api_server.py`
|
||||
|
||||
- [ ] Copy the committed regression test from `f3bae51`; run it in commercial and observe failure.
|
||||
- [ ] Diff the source commit against its parent, then port only paths exercised by the failing test.
|
||||
- [ ] Run the precise-context test plus existing Shadbala tests.
|
||||
|
||||
### Task 2: Port public high-rigor evidence
|
||||
|
||||
**Files:**
|
||||
- Create: `references/oracle/artifacts/jyotishganit_steve_jobs_high_rigor_raw.json`
|
||||
- Create: `references/oracle/artifacts/local_steve_jobs_high_rigor_raw.json`
|
||||
- Modify: `references/oracle/three_engine_parity_replay_manifest.json`
|
||||
|
||||
- [ ] Verify artifacts have no secret/private input and are referenced by the committed parity manifest.
|
||||
- [ ] Copy exact committed public files, then run parity artifact-contract and replay-validator tests.
|
||||
|
||||
### Task 3: Verify and publish
|
||||
|
||||
**Files:**
|
||||
- Modify: `references/evidence_manifests/commercial_external_validation_release.v1.json` when public evidence is added to release scope
|
||||
|
||||
- [ ] Run focused Shadbala, parity, API, privacy, and release-hash gates.
|
||||
- [ ] Commit only reviewed migration files and push `codex/cross-project-contract`.
|
||||
@@ -93,6 +93,36 @@
|
||||
"path": "references/oracle/artifacts/vedastro_steve_jobs_contract_probe_run3.json",
|
||||
"sha256": "fb0e05704df9be5bece7bef3b42fc14e0cc4f254685f039b855b359da453c650",
|
||||
"scope": "third independent redacted VedAstro contract probe"
|
||||
},
|
||||
{
|
||||
"id": "high_rigor_local_raw",
|
||||
"path": "references/oracle/artifacts/local_steve_jobs_high_rigor_raw.json",
|
||||
"sha256": "8361cac2831404a005e6be5c927b9cd610cfc0787ca17a547e81ae9a4d601746",
|
||||
"scope": "public same-chart local high-rigor raw output"
|
||||
},
|
||||
{
|
||||
"id": "high_rigor_pyjhora_raw",
|
||||
"path": "references/oracle/artifacts/pyjhora_steve_jobs_high_rigor_raw.json",
|
||||
"sha256": "a0374c77f7d4c435a473871ca8bbd0dff45f314eb2d68f5e9b3106478b986508",
|
||||
"scope": "public same-chart PyJHora high-rigor raw output"
|
||||
},
|
||||
{
|
||||
"id": "high_rigor_jyotishganit_raw",
|
||||
"path": "references/oracle/artifacts/jyotishganit_steve_jobs_high_rigor_raw.json",
|
||||
"sha256": "5cbb85f6cd9210558d496c350b45aa1dc2785ab3f49a800a884b45c76c49e6a1",
|
||||
"scope": "public same-chart jyotishganit high-rigor raw output"
|
||||
},
|
||||
{
|
||||
"id": "high_rigor_vedastro_divisional_raw",
|
||||
"path": "references/oracle/artifacts/vedastro_steve_jobs_public_aa_divisional_raw.json",
|
||||
"sha256": "75da3fa79463e22801b4602ec96d55267fc1dd0ef134ca0c96249317b0db9ef9",
|
||||
"scope": "public VedAstro divisional and Shadbala raw evidence"
|
||||
},
|
||||
{
|
||||
"id": "pyjhora_extended_public_smoke",
|
||||
"path": "references/oracle/pyjhora_extended_parity_public_smoke_manifest.json",
|
||||
"sha256": "c86315d8e16338608409b9277f835f647f8b739c207e4bcca177fd5ea0e2c0c4",
|
||||
"scope": "public PyJHora extended parity smoke manifest"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,792 @@
|
||||
{
|
||||
"advanced": {
|
||||
"A10_Karma_Pada": {
|
||||
"degree": 117.9412,
|
||||
"distance_from_source": 7,
|
||||
"exception_applied": false,
|
||||
"formula": "A10: from house lord count the same distance from source house; apply 1/7 exception",
|
||||
"house": 12,
|
||||
"label": "A10_Karma_Pada",
|
||||
"meaning": "A10/Karma Pada/Rajya Pada:事业名声、职业可见度、社会身份与公众层面的职业结果",
|
||||
"sign": "Cancer",
|
||||
"sign_degree": 27.9412,
|
||||
"source_house": 10,
|
||||
"source_lord_sign": "Sagittarius",
|
||||
"source_sign": "Taurus"
|
||||
},
|
||||
"dasha_sandhi": {
|
||||
"orb_days": 90,
|
||||
"reference_date": "2026-07-17",
|
||||
"sandhi_windows": []
|
||||
},
|
||||
"pushkara_true": {
|
||||
"Jupiter": {
|
||||
"degree_in_sign": 27.2772,
|
||||
"pushkara_bhaga": false,
|
||||
"pushkara_bhaga_meta": {
|
||||
"delta": 3.2772,
|
||||
"element": "air",
|
||||
"orb": 1.0,
|
||||
"target_degree": 24
|
||||
},
|
||||
"pushkara_navamsa": true,
|
||||
"pushkara_navamsa_meta": {
|
||||
"element": "air",
|
||||
"range": [
|
||||
26.6667,
|
||||
30
|
||||
]
|
||||
},
|
||||
"sign": "Gemini",
|
||||
"sign_cn": "双子座"
|
||||
},
|
||||
"Rahu": {
|
||||
"degree_in_sign": 9.2743,
|
||||
"pushkara_bhaga": false,
|
||||
"pushkara_bhaga_meta": {
|
||||
"delta": 11.7257,
|
||||
"element": "fire",
|
||||
"orb": 1.0,
|
||||
"target_degree": 21
|
||||
},
|
||||
"pushkara_navamsa": true,
|
||||
"pushkara_navamsa_meta": {
|
||||
"element": "fire",
|
||||
"range": [
|
||||
6.6667,
|
||||
10
|
||||
]
|
||||
},
|
||||
"sign": "Sagittarius",
|
||||
"sign_cn": "射手座"
|
||||
},
|
||||
"Saturn": {
|
||||
"degree_in_sign": 27.932,
|
||||
"pushkara_bhaga": false,
|
||||
"pushkara_bhaga_meta": {
|
||||
"delta": 3.932,
|
||||
"element": "air",
|
||||
"orb": 1.0,
|
||||
"target_degree": 24
|
||||
},
|
||||
"pushkara_navamsa": true,
|
||||
"pushkara_navamsa_meta": {
|
||||
"element": "air",
|
||||
"range": [
|
||||
26.6667,
|
||||
30
|
||||
]
|
||||
},
|
||||
"sign": "Libra",
|
||||
"sign_cn": "天秤座"
|
||||
}
|
||||
},
|
||||
"vargottama_true": {
|
||||
"Jupiter": {
|
||||
"d1_sign": "Gemini",
|
||||
"d9_sign": "Gemini",
|
||||
"is_vargottama": true
|
||||
},
|
||||
"Venus": {
|
||||
"d1_sign": "Sagittarius",
|
||||
"d9_sign": "Sagittarius",
|
||||
"is_vargottama": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"ascendant": {
|
||||
"degree": 29.0606,
|
||||
"degree_in_sign": 29.0606,
|
||||
"degree_in_sign_raw": 149.06059920521156,
|
||||
"degree_raw": 149.0606,
|
||||
"lon": 149.0606,
|
||||
"lord": "Sun",
|
||||
"sign": "Leo",
|
||||
"sign_cn": "狮子座"
|
||||
},
|
||||
"ashtakavarga": {
|
||||
"bav": {
|
||||
"Jupiter": [
|
||||
7,
|
||||
5,
|
||||
3,
|
||||
3,
|
||||
4,
|
||||
7,
|
||||
4,
|
||||
5,
|
||||
4,
|
||||
6,
|
||||
5,
|
||||
3
|
||||
],
|
||||
"Lagna": [
|
||||
5,
|
||||
3,
|
||||
4,
|
||||
4,
|
||||
4,
|
||||
2,
|
||||
4,
|
||||
3,
|
||||
5,
|
||||
7,
|
||||
5,
|
||||
3
|
||||
],
|
||||
"Mars": [
|
||||
4,
|
||||
7,
|
||||
4,
|
||||
4,
|
||||
3,
|
||||
0,
|
||||
4,
|
||||
5,
|
||||
1,
|
||||
4,
|
||||
1,
|
||||
2
|
||||
],
|
||||
"Mercury": [
|
||||
5,
|
||||
5,
|
||||
5,
|
||||
4,
|
||||
4,
|
||||
2,
|
||||
6,
|
||||
5,
|
||||
5,
|
||||
8,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"Moon": [
|
||||
4,
|
||||
4,
|
||||
4,
|
||||
3,
|
||||
6,
|
||||
5,
|
||||
3,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
3,
|
||||
5
|
||||
],
|
||||
"Saturn": [
|
||||
1,
|
||||
5,
|
||||
3,
|
||||
0,
|
||||
6,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
3,
|
||||
3,
|
||||
3,
|
||||
3
|
||||
],
|
||||
"Sun": [
|
||||
3,
|
||||
7,
|
||||
4,
|
||||
3,
|
||||
3,
|
||||
2,
|
||||
6,
|
||||
7,
|
||||
4,
|
||||
4,
|
||||
3,
|
||||
2
|
||||
],
|
||||
"Venus": [
|
||||
4,
|
||||
3,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
5,
|
||||
5,
|
||||
5,
|
||||
6
|
||||
]
|
||||
},
|
||||
"sav": [
|
||||
28,
|
||||
36,
|
||||
28,
|
||||
21,
|
||||
29,
|
||||
24,
|
||||
31,
|
||||
33,
|
||||
26,
|
||||
35,
|
||||
22,
|
||||
24
|
||||
]
|
||||
},
|
||||
"birth": {
|
||||
"day": 24,
|
||||
"hour": 19,
|
||||
"lat": 37.7749,
|
||||
"lon": -122.4194,
|
||||
"minute": 15,
|
||||
"month": 2,
|
||||
"tz": -8.0,
|
||||
"year": 1955
|
||||
},
|
||||
"category": "public",
|
||||
"dasha": {
|
||||
"antardasha_end": "2027-11-30",
|
||||
"antardasha_lord": "Rahu",
|
||||
"antardasha_start": "2025-03-19",
|
||||
"mahadasha_end": "2043-03-20",
|
||||
"mahadasha_lord": "Rahu",
|
||||
"mahadasha_start": "2025-03-19"
|
||||
},
|
||||
"engine": "local_jyotish_skill_v6_0_4",
|
||||
"label": "Steve Jobs public AA",
|
||||
"module_health": {
|
||||
"empty_modules": [],
|
||||
"module_count": 55,
|
||||
"validation": {
|
||||
"checked": 11,
|
||||
"failed": 0,
|
||||
"passed": 11,
|
||||
"results": [
|
||||
{
|
||||
"detail": "SAV total = 337, expected 337",
|
||||
"name": "SAV总和=337",
|
||||
"passed": true,
|
||||
"rule": "R1"
|
||||
},
|
||||
{
|
||||
"detail": "Sun=48/48; Moon=49/49; Mars=39/39; Mercury=54/54; Jupiter=56/56; Venus=52/52; Saturn=39/39; Lagna=49/49",
|
||||
"name": "BAV行常数校验",
|
||||
"passed": true,
|
||||
"rule": "R2"
|
||||
},
|
||||
{
|
||||
"detail": "所有12星座 BAV列和 与 SAV分数一致 ✅",
|
||||
"name": "BAV列→SAV列校验",
|
||||
"passed": true,
|
||||
"rule": "R2b"
|
||||
},
|
||||
{
|
||||
"detail": "Mercury延伸角 = 21.39°, 阈值 28°",
|
||||
"name": "水星延伸角≤28°",
|
||||
"passed": true,
|
||||
"rule": "R3"
|
||||
},
|
||||
{
|
||||
"detail": "Venus延伸角 = 44.58°, 阈值 47°",
|
||||
"name": "金星延伸角≤47°",
|
||||
"passed": true,
|
||||
"rule": "R4"
|
||||
},
|
||||
{
|
||||
"detail": "Rahu=249.2743°, Ketu=69.2743°, 偏差=0.0000°",
|
||||
"name": "Rahu-Ketu 180°对冲",
|
||||
"passed": true,
|
||||
"rule": "R5"
|
||||
},
|
||||
{
|
||||
"detail": "所有行星逆行状态合法",
|
||||
"name": "逆行合法性",
|
||||
"passed": true,
|
||||
"rule": "R6"
|
||||
},
|
||||
{
|
||||
"detail": "Dasha year chain sum = 120",
|
||||
"name": "Dasha年限总和=120",
|
||||
"passed": true,
|
||||
"rule": "R7"
|
||||
},
|
||||
{
|
||||
"detail": "完整:9行星 + Ascendant",
|
||||
"name": "行星完整性",
|
||||
"passed": true,
|
||||
"rule": "R8"
|
||||
},
|
||||
{
|
||||
"detail": "所有行星度数在合法范围",
|
||||
"name": "星座度数范围",
|
||||
"passed": true,
|
||||
"rule": "R9"
|
||||
},
|
||||
{
|
||||
"detail": "1-12宫完整(12宫)",
|
||||
"name": "宫位连续性",
|
||||
"passed": true,
|
||||
"rule": "R10"
|
||||
}
|
||||
],
|
||||
"skipped": 0,
|
||||
"total_checks": 11,
|
||||
"valid": true
|
||||
}
|
||||
},
|
||||
"parameters": {
|
||||
"ayanamsa": "lahiri_assumed_by_skill",
|
||||
"house": "whole_sign_for_planet_house",
|
||||
"today": "2026-07-17",
|
||||
"zodiac": "sidereal"
|
||||
},
|
||||
"planets": {
|
||||
"Jupiter": {
|
||||
"degree_in_sign": 27.2772,
|
||||
"house": 11,
|
||||
"nakshatra": "Punarvasu",
|
||||
"nakshatra_pada": 3,
|
||||
"retrograde": true,
|
||||
"sign": "Gemini"
|
||||
},
|
||||
"Ketu": {
|
||||
"degree_in_sign": 9.2743,
|
||||
"house": 11,
|
||||
"nakshatra": "Ardra",
|
||||
"nakshatra_pada": 1,
|
||||
"retrograde": true,
|
||||
"sign": "Gemini"
|
||||
},
|
||||
"Mars": {
|
||||
"degree_in_sign": 5.8598,
|
||||
"house": 9,
|
||||
"nakshatra": "Ashwini",
|
||||
"nakshatra_pada": 2,
|
||||
"retrograde": false,
|
||||
"sign": "Aries"
|
||||
},
|
||||
"Mercury": {
|
||||
"degree_in_sign": 21.1311,
|
||||
"house": 6,
|
||||
"nakshatra": "Shravana",
|
||||
"nakshatra_pada": 4,
|
||||
"retrograde": true,
|
||||
"sign": "Capricorn"
|
||||
},
|
||||
"Moon": {
|
||||
"degree_in_sign": 14.5165,
|
||||
"house": 8,
|
||||
"nakshatra": "Uttara Bhadrapada",
|
||||
"nakshatra_pada": 4,
|
||||
"retrograde": false,
|
||||
"sign": "Pisces"
|
||||
},
|
||||
"Rahu": {
|
||||
"degree_in_sign": 9.2743,
|
||||
"house": 5,
|
||||
"nakshatra": "Mula",
|
||||
"nakshatra_pada": 3,
|
||||
"retrograde": true,
|
||||
"sign": "Sagittarius"
|
||||
},
|
||||
"Saturn": {
|
||||
"degree_in_sign": 27.932,
|
||||
"house": 3,
|
||||
"nakshatra": "Vishakha",
|
||||
"nakshatra_pada": 3,
|
||||
"retrograde": false,
|
||||
"sign": "Libra"
|
||||
},
|
||||
"Sun": {
|
||||
"degree_in_sign": 12.5175,
|
||||
"house": 7,
|
||||
"nakshatra": "Shatabhisha",
|
||||
"nakshatra_pada": 2,
|
||||
"retrograde": false,
|
||||
"sign": "Aquarius"
|
||||
},
|
||||
"Venus": {
|
||||
"degree_in_sign": 27.9412,
|
||||
"house": 5,
|
||||
"nakshatra": "Uttara Ashadha",
|
||||
"nakshatra_pada": 1,
|
||||
"retrograde": false,
|
||||
"sign": "Sagittarius"
|
||||
}
|
||||
},
|
||||
"privacy": "public",
|
||||
"sample_id": "steve_jobs_public_aa",
|
||||
"shadbala": {
|
||||
"Jupiter": null,
|
||||
"Mars": null,
|
||||
"Mercury": null,
|
||||
"Moon": null,
|
||||
"Saturn": null,
|
||||
"Sun": null,
|
||||
"Venus": null
|
||||
},
|
||||
"shadbala_components": {
|
||||
"Jupiter": {
|
||||
"chesta": null,
|
||||
"dig": null,
|
||||
"drik": null,
|
||||
"kala": null,
|
||||
"naisargika": null,
|
||||
"sthana": null
|
||||
},
|
||||
"Mars": {
|
||||
"chesta": null,
|
||||
"dig": null,
|
||||
"drik": null,
|
||||
"kala": null,
|
||||
"naisargika": null,
|
||||
"sthana": null
|
||||
},
|
||||
"Mercury": {
|
||||
"chesta": null,
|
||||
"dig": null,
|
||||
"drik": null,
|
||||
"kala": null,
|
||||
"naisargika": null,
|
||||
"sthana": null
|
||||
},
|
||||
"Moon": {
|
||||
"chesta": null,
|
||||
"dig": null,
|
||||
"drik": null,
|
||||
"kala": null,
|
||||
"naisargika": null,
|
||||
"sthana": null
|
||||
},
|
||||
"Saturn": {
|
||||
"chesta": null,
|
||||
"dig": null,
|
||||
"drik": null,
|
||||
"kala": null,
|
||||
"naisargika": null,
|
||||
"sthana": null
|
||||
},
|
||||
"Sun": {
|
||||
"chesta": null,
|
||||
"dig": null,
|
||||
"drik": null,
|
||||
"kala": null,
|
||||
"naisargika": null,
|
||||
"sthana": null
|
||||
},
|
||||
"Venus": {
|
||||
"chesta": null,
|
||||
"dig": null,
|
||||
"drik": null,
|
||||
"kala": null,
|
||||
"naisargika": null,
|
||||
"sthana": null
|
||||
}
|
||||
},
|
||||
"shadbala_method_variants": {
|
||||
"chesta": "bphs_bounded_surya_mean_motion_seeghrochcha",
|
||||
"chesta_source": "MIT jyotishganit structure plus public Surya Siddhanta revolution constants",
|
||||
"kala": "bphs_local_solar_events_ahargana_declination"
|
||||
},
|
||||
"varga": {
|
||||
"D10": {
|
||||
"Ascendant": {
|
||||
"degree_in_sign": 20.606,
|
||||
"lord": "Venus",
|
||||
"part_index": 9,
|
||||
"sign": "Taurus",
|
||||
"sign_idx": 1
|
||||
},
|
||||
"Jupiter": {
|
||||
"degree_in_sign": 2.7724,
|
||||
"lord": "Jupiter",
|
||||
"part_index": 9,
|
||||
"sign": "Pisces",
|
||||
"sign_idx": 11
|
||||
},
|
||||
"Ketu": {
|
||||
"degree_in_sign": 2.7429,
|
||||
"lord": "Mercury",
|
||||
"part_index": 3,
|
||||
"sign": "Virgo",
|
||||
"sign_idx": 5
|
||||
},
|
||||
"Mars": {
|
||||
"degree_in_sign": 28.5982,
|
||||
"lord": "Venus",
|
||||
"part_index": 1,
|
||||
"sign": "Taurus",
|
||||
"sign_idx": 1
|
||||
},
|
||||
"Mercury": {
|
||||
"degree_in_sign": 1.3107,
|
||||
"lord": "Mars",
|
||||
"part_index": 7,
|
||||
"sign": "Aries",
|
||||
"sign_idx": 0
|
||||
},
|
||||
"Moon": {
|
||||
"degree_in_sign": 25.1652,
|
||||
"lord": "Jupiter",
|
||||
"part_index": 4,
|
||||
"sign": "Pisces",
|
||||
"sign_idx": 11
|
||||
},
|
||||
"Rahu": {
|
||||
"degree_in_sign": 2.7429,
|
||||
"lord": "Jupiter",
|
||||
"part_index": 3,
|
||||
"sign": "Pisces",
|
||||
"sign_idx": 11
|
||||
},
|
||||
"Saturn": {
|
||||
"degree_in_sign": 9.3204,
|
||||
"lord": "Moon",
|
||||
"part_index": 9,
|
||||
"sign": "Cancer",
|
||||
"sign_idx": 3
|
||||
},
|
||||
"Sun": {
|
||||
"degree_in_sign": 5.1749,
|
||||
"lord": "Mercury",
|
||||
"part_index": 4,
|
||||
"sign": "Gemini",
|
||||
"sign_idx": 2
|
||||
},
|
||||
"Venus": {
|
||||
"degree_in_sign": 9.4123,
|
||||
"lord": "Mercury",
|
||||
"part_index": 9,
|
||||
"sign": "Virgo",
|
||||
"sign_idx": 5
|
||||
}
|
||||
},
|
||||
"D2": {
|
||||
"Ascendant": {
|
||||
"degree_in_sign": 28.1212,
|
||||
"lord": "Moon",
|
||||
"part_index": 1,
|
||||
"sign": "Cancer",
|
||||
"sign_idx": 3
|
||||
},
|
||||
"Jupiter": {
|
||||
"degree_in_sign": 24.5545,
|
||||
"lord": "Moon",
|
||||
"part_index": 1,
|
||||
"sign": "Cancer",
|
||||
"sign_idx": 3
|
||||
},
|
||||
"Ketu": {
|
||||
"degree_in_sign": 18.5486,
|
||||
"lord": "Sun",
|
||||
"part_index": 0,
|
||||
"sign": "Leo",
|
||||
"sign_idx": 4
|
||||
},
|
||||
"Mars": {
|
||||
"degree_in_sign": 11.7196,
|
||||
"lord": "Sun",
|
||||
"part_index": 0,
|
||||
"sign": "Leo",
|
||||
"sign_idx": 4
|
||||
},
|
||||
"Mercury": {
|
||||
"degree_in_sign": 12.2621,
|
||||
"lord": "Sun",
|
||||
"part_index": 1,
|
||||
"sign": "Leo",
|
||||
"sign_idx": 4
|
||||
},
|
||||
"Moon": {
|
||||
"degree_in_sign": 29.033,
|
||||
"lord": "Moon",
|
||||
"part_index": 0,
|
||||
"sign": "Cancer",
|
||||
"sign_idx": 3
|
||||
},
|
||||
"Rahu": {
|
||||
"degree_in_sign": 18.5486,
|
||||
"lord": "Sun",
|
||||
"part_index": 0,
|
||||
"sign": "Leo",
|
||||
"sign_idx": 4
|
||||
},
|
||||
"Saturn": {
|
||||
"degree_in_sign": 25.8641,
|
||||
"lord": "Moon",
|
||||
"part_index": 1,
|
||||
"sign": "Cancer",
|
||||
"sign_idx": 3
|
||||
},
|
||||
"Sun": {
|
||||
"degree_in_sign": 25.035,
|
||||
"lord": "Sun",
|
||||
"part_index": 0,
|
||||
"sign": "Leo",
|
||||
"sign_idx": 4
|
||||
},
|
||||
"Venus": {
|
||||
"degree_in_sign": 25.8825,
|
||||
"lord": "Moon",
|
||||
"part_index": 1,
|
||||
"sign": "Cancer",
|
||||
"sign_idx": 3
|
||||
}
|
||||
},
|
||||
"D4": {
|
||||
"Ascendant": {
|
||||
"degree_in_sign": 26.2424,
|
||||
"lord": "Venus",
|
||||
"part_index": 3,
|
||||
"sign": "Taurus",
|
||||
"sign_idx": 1
|
||||
},
|
||||
"Jupiter": {
|
||||
"degree_in_sign": 19.1089,
|
||||
"lord": "Jupiter",
|
||||
"part_index": 3,
|
||||
"sign": "Pisces",
|
||||
"sign_idx": 11
|
||||
},
|
||||
"Ketu": {
|
||||
"degree_in_sign": 7.0972,
|
||||
"lord": "Mercury",
|
||||
"part_index": 1,
|
||||
"sign": "Virgo",
|
||||
"sign_idx": 5
|
||||
},
|
||||
"Mars": {
|
||||
"degree_in_sign": 23.4393,
|
||||
"lord": "Mars",
|
||||
"part_index": 0,
|
||||
"sign": "Aries",
|
||||
"sign_idx": 0
|
||||
},
|
||||
"Mercury": {
|
||||
"degree_in_sign": 24.5243,
|
||||
"lord": "Moon",
|
||||
"part_index": 2,
|
||||
"sign": "Cancer",
|
||||
"sign_idx": 3
|
||||
},
|
||||
"Moon": {
|
||||
"degree_in_sign": 28.0661,
|
||||
"lord": "Mercury",
|
||||
"part_index": 1,
|
||||
"sign": "Gemini",
|
||||
"sign_idx": 2
|
||||
},
|
||||
"Rahu": {
|
||||
"degree_in_sign": 7.0972,
|
||||
"lord": "Jupiter",
|
||||
"part_index": 1,
|
||||
"sign": "Pisces",
|
||||
"sign_idx": 11
|
||||
},
|
||||
"Saturn": {
|
||||
"degree_in_sign": 21.7282,
|
||||
"lord": "Moon",
|
||||
"part_index": 3,
|
||||
"sign": "Cancer",
|
||||
"sign_idx": 3
|
||||
},
|
||||
"Sun": {
|
||||
"degree_in_sign": 20.0699,
|
||||
"lord": "Venus",
|
||||
"part_index": 1,
|
||||
"sign": "Taurus",
|
||||
"sign_idx": 1
|
||||
},
|
||||
"Venus": {
|
||||
"degree_in_sign": 21.7649,
|
||||
"lord": "Mercury",
|
||||
"part_index": 3,
|
||||
"sign": "Virgo",
|
||||
"sign_idx": 5
|
||||
}
|
||||
},
|
||||
"D9": {
|
||||
"Ascendant": {
|
||||
"degree_in_sign": 21.5454,
|
||||
"lord": "Jupiter",
|
||||
"pada": 9,
|
||||
"part_index": 8,
|
||||
"sign": "Sagittarius",
|
||||
"sign_idx": 8
|
||||
},
|
||||
"Jupiter": {
|
||||
"degree_in_sign": 5.4951,
|
||||
"lord": "Mercury",
|
||||
"pada": 9,
|
||||
"part_index": 8,
|
||||
"sign": "Gemini",
|
||||
"sign_idx": 2
|
||||
},
|
||||
"Ketu": {
|
||||
"degree_in_sign": 23.4686,
|
||||
"lord": "Jupiter",
|
||||
"pada": 3,
|
||||
"part_index": 2,
|
||||
"sign": "Sagittarius",
|
||||
"sign_idx": 8
|
||||
},
|
||||
"Mars": {
|
||||
"degree_in_sign": 22.7384,
|
||||
"lord": "Venus",
|
||||
"pada": 2,
|
||||
"part_index": 1,
|
||||
"sign": "Taurus",
|
||||
"sign_idx": 1
|
||||
},
|
||||
"Mercury": {
|
||||
"degree_in_sign": 10.1797,
|
||||
"lord": "Moon",
|
||||
"pada": 7,
|
||||
"part_index": 6,
|
||||
"sign": "Cancer",
|
||||
"sign_idx": 3
|
||||
},
|
||||
"Moon": {
|
||||
"degree_in_sign": 10.6487,
|
||||
"lord": "Mars",
|
||||
"pada": 5,
|
||||
"part_index": 4,
|
||||
"sign": "Scorpio",
|
||||
"sign_idx": 7
|
||||
},
|
||||
"Rahu": {
|
||||
"degree_in_sign": 23.4686,
|
||||
"lord": "Mercury",
|
||||
"pada": 3,
|
||||
"part_index": 2,
|
||||
"sign": "Gemini",
|
||||
"sign_idx": 2
|
||||
},
|
||||
"Saturn": {
|
||||
"degree_in_sign": 11.3884,
|
||||
"lord": "Mercury",
|
||||
"pada": 9,
|
||||
"part_index": 8,
|
||||
"sign": "Gemini",
|
||||
"sign_idx": 2
|
||||
},
|
||||
"Sun": {
|
||||
"degree_in_sign": 22.6574,
|
||||
"lord": "Saturn",
|
||||
"pada": 4,
|
||||
"part_index": 3,
|
||||
"sign": "Capricorn",
|
||||
"sign_idx": 9
|
||||
},
|
||||
"Venus": {
|
||||
"degree_in_sign": 11.4711,
|
||||
"lord": "Jupiter",
|
||||
"pada": 9,
|
||||
"part_index": 8,
|
||||
"sign": "Sagittarius",
|
||||
"sign_idx": 8
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,494 @@
|
||||
{
|
||||
"ascendant": {
|
||||
"degree_in_sign": 29.0556,
|
||||
"sign": "Leo"
|
||||
},
|
||||
"ashtakavarga": {
|
||||
"bav": {
|
||||
"Jupiter": [
|
||||
7,
|
||||
5,
|
||||
3,
|
||||
3,
|
||||
4,
|
||||
7,
|
||||
4,
|
||||
5,
|
||||
4,
|
||||
6,
|
||||
5,
|
||||
3
|
||||
],
|
||||
"Lagna": [
|
||||
5,
|
||||
3,
|
||||
4,
|
||||
4,
|
||||
4,
|
||||
2,
|
||||
4,
|
||||
3,
|
||||
5,
|
||||
7,
|
||||
5,
|
||||
3
|
||||
],
|
||||
"Mars": [
|
||||
4,
|
||||
7,
|
||||
4,
|
||||
4,
|
||||
3,
|
||||
0,
|
||||
4,
|
||||
5,
|
||||
1,
|
||||
4,
|
||||
1,
|
||||
2
|
||||
],
|
||||
"Mercury": [
|
||||
5,
|
||||
5,
|
||||
5,
|
||||
4,
|
||||
4,
|
||||
2,
|
||||
6,
|
||||
5,
|
||||
5,
|
||||
8,
|
||||
2,
|
||||
3
|
||||
],
|
||||
"Moon": [
|
||||
4,
|
||||
4,
|
||||
4,
|
||||
3,
|
||||
6,
|
||||
5,
|
||||
3,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
3,
|
||||
5
|
||||
],
|
||||
"Saturn": [
|
||||
1,
|
||||
5,
|
||||
3,
|
||||
0,
|
||||
6,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
3,
|
||||
3,
|
||||
3,
|
||||
3
|
||||
],
|
||||
"Sun": [
|
||||
3,
|
||||
7,
|
||||
4,
|
||||
3,
|
||||
3,
|
||||
2,
|
||||
6,
|
||||
7,
|
||||
4,
|
||||
4,
|
||||
3,
|
||||
2
|
||||
],
|
||||
"Venus": [
|
||||
4,
|
||||
3,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
5,
|
||||
5,
|
||||
5,
|
||||
6
|
||||
]
|
||||
},
|
||||
"sav": [
|
||||
28,
|
||||
36,
|
||||
28,
|
||||
21,
|
||||
29,
|
||||
24,
|
||||
31,
|
||||
33,
|
||||
26,
|
||||
35,
|
||||
22,
|
||||
24
|
||||
]
|
||||
},
|
||||
"dasha": {
|
||||
"antardasha_end": "2027-12-03",
|
||||
"antardasha_lord": "Rahu",
|
||||
"antardasha_start": "2025-03-22",
|
||||
"mahadasha_end": "2043-03-23",
|
||||
"mahadasha_lord": "Rahu",
|
||||
"mahadasha_start": "2025-03-22"
|
||||
},
|
||||
"engine": "PyJHora_4_8_6_lahiri_patched",
|
||||
"parameters": {
|
||||
"ayanamsa": "LAHIRI",
|
||||
"compat": "monkeypatch swisseph keyword API + missing constants; dummy timezonefinder only for import",
|
||||
"d10_method": "PyJHora divisional_chart chart_method=1",
|
||||
"d2_method": "PyJHora hora_chart chart_method=2 traditional_parasara",
|
||||
"d4_method": "PyJHora chaturthamsa_chart chart_method=1 traditional_parasara",
|
||||
"d9_method": "PyJHora divisional_chart chart_method=1",
|
||||
"dasha_year": "mean sidereal year",
|
||||
"license_note": "PyJHora is AGPL-3.0; used only as external benchmark, not vendored into skill.",
|
||||
"zodiac": "sidereal"
|
||||
},
|
||||
"planets": {
|
||||
"Jupiter": {
|
||||
"degree_in_sign": 27.2706,
|
||||
"nakshatra": "Punarvasu",
|
||||
"nakshatra_pada": 3,
|
||||
"sign": "Gemini"
|
||||
},
|
||||
"Ketu": {
|
||||
"degree_in_sign": 9.2693,
|
||||
"nakshatra": "Ardra",
|
||||
"nakshatra_pada": 1,
|
||||
"sign": "Gemini"
|
||||
},
|
||||
"Mars": {
|
||||
"degree_in_sign": 5.8623,
|
||||
"nakshatra": "Ashwini",
|
||||
"nakshatra_pada": 2,
|
||||
"sign": "Aries"
|
||||
},
|
||||
"Mercury": {
|
||||
"degree_in_sign": 21.1259,
|
||||
"nakshatra": "Shravana",
|
||||
"nakshatra_pada": 4,
|
||||
"sign": "Capricorn"
|
||||
},
|
||||
"Moon": {
|
||||
"degree_in_sign": 14.5117,
|
||||
"nakshatra": "Uttara Bhadrapada",
|
||||
"nakshatra_pada": 4,
|
||||
"sign": "Pisces"
|
||||
},
|
||||
"Rahu": {
|
||||
"degree_in_sign": 9.2693,
|
||||
"nakshatra": "Mula",
|
||||
"nakshatra_pada": 3,
|
||||
"sign": "Sagittarius"
|
||||
},
|
||||
"Saturn": {
|
||||
"degree_in_sign": 27.9274,
|
||||
"nakshatra": "Vishakha",
|
||||
"nakshatra_pada": 3,
|
||||
"sign": "Libra"
|
||||
},
|
||||
"Sun": {
|
||||
"degree_in_sign": 12.5182,
|
||||
"nakshatra": "Shatabhisha",
|
||||
"nakshatra_pada": 2,
|
||||
"sign": "Aquarius"
|
||||
},
|
||||
"Venus": {
|
||||
"degree_in_sign": 27.9421,
|
||||
"nakshatra": "Uttara Ashadha",
|
||||
"nakshatra_pada": 1,
|
||||
"sign": "Sagittarius"
|
||||
}
|
||||
},
|
||||
"sample_id": "steve_jobs_public_aa",
|
||||
"settings": {
|
||||
"ayanamsa": "lahiri",
|
||||
"node_mode": "mean"
|
||||
},
|
||||
"shadbala": {
|
||||
"Jupiter": 596.89,
|
||||
"Mars": 533.18,
|
||||
"Mercury": 363.24,
|
||||
"Moon": 562.89,
|
||||
"Saturn": 429.42,
|
||||
"Sun": 444.63,
|
||||
"Venus": 408.64
|
||||
},
|
||||
"shadbala_components": {
|
||||
"Jupiter": {
|
||||
"chesta": 74.0,
|
||||
"dig": 80.6,
|
||||
"drik": 6.89,
|
||||
"kala": 199.31,
|
||||
"naisargika": 34.29,
|
||||
"sthana": 201.8
|
||||
},
|
||||
"Mars": {
|
||||
"chesta": 98.58,
|
||||
"dig": 77.41,
|
||||
"drik": 13.49,
|
||||
"kala": 127.93,
|
||||
"naisargika": 17.14,
|
||||
"sthana": 198.63
|
||||
},
|
||||
"Mercury": {
|
||||
"chesta": 45.78,
|
||||
"dig": 12.64,
|
||||
"drik": -10.63,
|
||||
"kala": 121.78,
|
||||
"naisargika": 25.71,
|
||||
"sthana": 167.96
|
||||
},
|
||||
"Moon": {
|
||||
"chesta": 0.0,
|
||||
"dig": 95.48,
|
||||
"drik": 20.06,
|
||||
"kala": 149.58,
|
||||
"naisargika": 51.43,
|
||||
"sthana": 246.34
|
||||
},
|
||||
"Saturn": {
|
||||
"chesta": 36.36,
|
||||
"dig": 19.62,
|
||||
"drik": 9.49,
|
||||
"kala": 136.77,
|
||||
"naisargika": 8.57,
|
||||
"sthana": 218.61
|
||||
},
|
||||
"Sun": {
|
||||
"chesta": 0.0,
|
||||
"dig": 24.81,
|
||||
"drik": 1.74,
|
||||
"kala": 140.99,
|
||||
"naisargika": 60.0,
|
||||
"sthana": 217.09
|
||||
},
|
||||
"Venus": {
|
||||
"chesta": 31.08,
|
||||
"dig": 69.95,
|
||||
"drik": -2.75,
|
||||
"kala": 113.44,
|
||||
"naisargika": 42.86,
|
||||
"sthana": 154.06
|
||||
}
|
||||
},
|
||||
"varga": {
|
||||
"D10": {
|
||||
"Ascendant": {
|
||||
"degree_in_sign": 20.5556,
|
||||
"sign": "Taurus",
|
||||
"sign_idx": 1
|
||||
},
|
||||
"Jupiter": {
|
||||
"degree_in_sign": 2.7055,
|
||||
"sign": "Pisces",
|
||||
"sign_idx": 11
|
||||
},
|
||||
"Ketu": {
|
||||
"degree_in_sign": 2.6925,
|
||||
"sign": "Virgo",
|
||||
"sign_idx": 5
|
||||
},
|
||||
"Mars": {
|
||||
"degree_in_sign": 28.6233,
|
||||
"sign": "Taurus",
|
||||
"sign_idx": 1
|
||||
},
|
||||
"Mercury": {
|
||||
"degree_in_sign": 1.2589,
|
||||
"sign": "Aries",
|
||||
"sign_idx": 0
|
||||
},
|
||||
"Moon": {
|
||||
"degree_in_sign": 25.1168,
|
||||
"sign": "Pisces",
|
||||
"sign_idx": 11
|
||||
},
|
||||
"Rahu": {
|
||||
"degree_in_sign": 2.6925,
|
||||
"sign": "Pisces",
|
||||
"sign_idx": 11
|
||||
},
|
||||
"Saturn": {
|
||||
"degree_in_sign": 9.2738,
|
||||
"sign": "Cancer",
|
||||
"sign_idx": 3
|
||||
},
|
||||
"Sun": {
|
||||
"degree_in_sign": 5.182,
|
||||
"sign": "Gemini",
|
||||
"sign_idx": 2
|
||||
},
|
||||
"Venus": {
|
||||
"degree_in_sign": 9.4212,
|
||||
"sign": "Virgo",
|
||||
"sign_idx": 5
|
||||
}
|
||||
},
|
||||
"D2": {
|
||||
"Ascendant": {
|
||||
"degree_in_sign": 28.1111,
|
||||
"sign": "Cancer",
|
||||
"sign_idx": 3
|
||||
},
|
||||
"Jupiter": {
|
||||
"degree_in_sign": 24.5411,
|
||||
"sign": "Cancer",
|
||||
"sign_idx": 3
|
||||
},
|
||||
"Ketu": {
|
||||
"degree_in_sign": 18.5385,
|
||||
"sign": "Leo",
|
||||
"sign_idx": 4
|
||||
},
|
||||
"Mars": {
|
||||
"degree_in_sign": 11.7247,
|
||||
"sign": "Leo",
|
||||
"sign_idx": 4
|
||||
},
|
||||
"Mercury": {
|
||||
"degree_in_sign": 12.2518,
|
||||
"sign": "Leo",
|
||||
"sign_idx": 4
|
||||
},
|
||||
"Moon": {
|
||||
"degree_in_sign": 29.0234,
|
||||
"sign": "Cancer",
|
||||
"sign_idx": 3
|
||||
},
|
||||
"Rahu": {
|
||||
"degree_in_sign": 18.5385,
|
||||
"sign": "Leo",
|
||||
"sign_idx": 4
|
||||
},
|
||||
"Saturn": {
|
||||
"degree_in_sign": 25.8548,
|
||||
"sign": "Cancer",
|
||||
"sign_idx": 3
|
||||
},
|
||||
"Sun": {
|
||||
"degree_in_sign": 25.0364,
|
||||
"sign": "Leo",
|
||||
"sign_idx": 4
|
||||
},
|
||||
"Venus": {
|
||||
"degree_in_sign": 25.8842,
|
||||
"sign": "Cancer",
|
||||
"sign_idx": 3
|
||||
}
|
||||
},
|
||||
"D4": {
|
||||
"Ascendant": {
|
||||
"degree_in_sign": 26.2222,
|
||||
"sign": "Taurus",
|
||||
"sign_idx": 1
|
||||
},
|
||||
"Jupiter": {
|
||||
"degree_in_sign": 19.0822,
|
||||
"sign": "Pisces",
|
||||
"sign_idx": 11
|
||||
},
|
||||
"Ketu": {
|
||||
"degree_in_sign": 7.077,
|
||||
"sign": "Virgo",
|
||||
"sign_idx": 5
|
||||
},
|
||||
"Mars": {
|
||||
"degree_in_sign": 23.4493,
|
||||
"sign": "Aries",
|
||||
"sign_idx": 0
|
||||
},
|
||||
"Mercury": {
|
||||
"degree_in_sign": 24.5036,
|
||||
"sign": "Cancer",
|
||||
"sign_idx": 3
|
||||
},
|
||||
"Moon": {
|
||||
"degree_in_sign": 28.0467,
|
||||
"sign": "Gemini",
|
||||
"sign_idx": 2
|
||||
},
|
||||
"Rahu": {
|
||||
"degree_in_sign": 7.077,
|
||||
"sign": "Pisces",
|
||||
"sign_idx": 11
|
||||
},
|
||||
"Saturn": {
|
||||
"degree_in_sign": 21.7095,
|
||||
"sign": "Cancer",
|
||||
"sign_idx": 3
|
||||
},
|
||||
"Sun": {
|
||||
"degree_in_sign": 20.0728,
|
||||
"sign": "Taurus",
|
||||
"sign_idx": 1
|
||||
},
|
||||
"Venus": {
|
||||
"degree_in_sign": 21.7685,
|
||||
"sign": "Virgo",
|
||||
"sign_idx": 5
|
||||
}
|
||||
},
|
||||
"D9": {
|
||||
"Ascendant": {
|
||||
"degree_in_sign": 21.5,
|
||||
"sign": "Sagittarius",
|
||||
"sign_idx": 8
|
||||
},
|
||||
"Jupiter": {
|
||||
"degree_in_sign": 5.435,
|
||||
"sign": "Gemini",
|
||||
"sign_idx": 2
|
||||
},
|
||||
"Ketu": {
|
||||
"degree_in_sign": 23.4233,
|
||||
"sign": "Sagittarius",
|
||||
"sign_idx": 8
|
||||
},
|
||||
"Mars": {
|
||||
"degree_in_sign": 22.761,
|
||||
"sign": "Taurus",
|
||||
"sign_idx": 1
|
||||
},
|
||||
"Mercury": {
|
||||
"degree_in_sign": 10.133,
|
||||
"sign": "Cancer",
|
||||
"sign_idx": 3
|
||||
},
|
||||
"Moon": {
|
||||
"degree_in_sign": 10.6051,
|
||||
"sign": "Scorpio",
|
||||
"sign_idx": 7
|
||||
},
|
||||
"Rahu": {
|
||||
"degree_in_sign": 23.4233,
|
||||
"sign": "Gemini",
|
||||
"sign_idx": 2
|
||||
},
|
||||
"Saturn": {
|
||||
"degree_in_sign": 11.3465,
|
||||
"sign": "Gemini",
|
||||
"sign_idx": 2
|
||||
},
|
||||
"Sun": {
|
||||
"degree_in_sign": 22.6638,
|
||||
"sign": "Capricorn",
|
||||
"sign_idx": 9
|
||||
},
|
||||
"Venus": {
|
||||
"degree_in_sign": 11.4791,
|
||||
"sign": "Sagittarius",
|
||||
"sign_idx": 8
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"scope": "pyjhora_extended_parity_public_smoke",
|
||||
"status": "partial_verified",
|
||||
"tested": true,
|
||||
"birth_data_policy": "public_synthetic_smoke_only",
|
||||
"settings": {
|
||||
"ayanamsa": "lahiri",
|
||||
"node_mode": "mean"
|
||||
},
|
||||
"sample_count": 1,
|
||||
"sample_ids": [
|
||||
"smoke_beijing_1990_noon"
|
||||
],
|
||||
"comparison_rows": {
|
||||
"total": 239,
|
||||
"match": 232,
|
||||
"mismatch": 7
|
||||
},
|
||||
"covered_outputs": [
|
||||
"D2",
|
||||
"D4",
|
||||
"D9",
|
||||
"D10",
|
||||
"Ashtakavarga"
|
||||
],
|
||||
"partial_outputs": [
|
||||
"Shadbala"
|
||||
],
|
||||
"source_report": "docs/research/pyjhora_d2_d4_ashtakavarga_shadbala_parity_2026_07_15.md",
|
||||
"boundary": "D2, D4, BAV and SAV match for one public synthetic chart. Shadbala total virupas mismatch for all seven planets and remains outside verified coverage."
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6281,12 +6281,25 @@ class JyotishAPIHandler(BaseHTTPRequestHandler):
|
||||
birth_minute = self._get_float(body, 'birth_minute', body.get('minute', 0), 0, 59)
|
||||
birth_second = self._get_birth_second(body)
|
||||
birth_hour_decimal = self._birth_hour_decimal(birth_hour, birth_minute, birth_second)
|
||||
result = _load_local_module('shadbala').calc_shadbala(
|
||||
shadbala_module = _load_local_module('shadbala')
|
||||
context = None
|
||||
if all(key in body for key in ('year', 'month', 'day', 'lat', 'lon')):
|
||||
year = self._get_int(body, 'year', 1990, 1800, 2400)
|
||||
month = self._get_int(body, 'month', 6, 1, 12)
|
||||
day = self._get_int(body, 'day', 15, 1, 31)
|
||||
lat = self._get_float(body, 'lat', 0, -90, 90)
|
||||
lon = self._get_float(body, 'lon', 0, -180, 180)
|
||||
tz = self._parse_timezone(body, lat, lon, year, month, day, birth_hour, birth_minute, birth_second)
|
||||
jd = swe.julday(year, month, day, birth_hour_decimal - tz)
|
||||
context = shadbala_module.build_shadbala_context(jd, lat, lon, body.get('ayanamsa', 'lahiri'))
|
||||
result = shadbala_module.calc_shadbala(
|
||||
planets,
|
||||
SIGNS[asc_sign_idx],
|
||||
birth_hour_decimal,
|
||||
planet_lons['Sun'],
|
||||
planet_lons['Moon'],
|
||||
birth_minute,
|
||||
context=context,
|
||||
)
|
||||
advanced = self._compute_shadbala_advanced_layer(body, planets, result)
|
||||
return {
|
||||
|
||||
@@ -3356,7 +3356,7 @@ def cmd_shadbala(args):
|
||||
return {"error": "swisseph未安装"}
|
||||
try:
|
||||
sys.path.insert(0, SCRIPT_DIR)
|
||||
from shadbala import calc_shadbala
|
||||
from shadbala import build_shadbala_context, calc_shadbala
|
||||
except ImportError as e:
|
||||
return {"error": f"shadbala模块导入失败: {e}"}
|
||||
planets = chart.get("planets", {})
|
||||
@@ -3364,7 +3364,8 @@ def cmd_shadbala(args):
|
||||
birth_hour = _birth_hour_decimal(args.hour, args.minute, _arg_second(args))
|
||||
sun_lon = planets.get("Sun", {}).get("degree", 0)
|
||||
moon_lon = planets.get("Moon", {}).get("degree", 0)
|
||||
return calc_shadbala(planets, asc_sign, birth_hour, sun_lon, moon_lon)
|
||||
context = build_shadbala_context(jd, args.lat, args.lon, _current_ayanamsa_name(args))
|
||||
return calc_shadbala(planets, asc_sign, birth_hour, sun_lon, moon_lon, context=context)
|
||||
|
||||
|
||||
# ============================================================================
|
||||
@@ -3752,11 +3753,12 @@ def cmd_audit(args):
|
||||
# P9 Shadbala(六重力量)
|
||||
try:
|
||||
sys.path.insert(0, SCRIPT_DIR)
|
||||
from shadbala import calc_shadbala
|
||||
from shadbala import build_shadbala_context, calc_shadbala
|
||||
birth_hour = _birth_hour_decimal(args.hour, args.minute, _arg_second(args))
|
||||
sun_lon = planets.get('Sun', {}).get('degree', 0)
|
||||
moon_lon = planets.get('Moon', {}).get('degree', 0)
|
||||
shadbala = calc_shadbala(planets, asc_sign, birth_hour, sun_lon, moon_lon)
|
||||
context = build_shadbala_context(jd, args.lat, args.lon, _current_ayanamsa_name(args))
|
||||
shadbala = calc_shadbala(planets, asc_sign, birth_hour, sun_lon, moon_lon, context=context)
|
||||
report['audit']['P9_shadbala'] = {
|
||||
'summary': shadbala.get('summary', {}),
|
||||
'ishta_bala_ranking': shadbala.get('ishta_bala_ranking', []),
|
||||
@@ -5524,7 +5526,7 @@ def cmd_full_reading(args):
|
||||
birth_hour = _birth_hour_decimal(args.hour, args.minute, _arg_second(args))
|
||||
sun_lon = planet_lons.get('Sun', 0)
|
||||
moon_lon = planet_lons.get('Moon', 0)
|
||||
shadbala_result = calc_shadbala(planets, asc_sign, birth_hour, sun_lon, moon_lon)
|
||||
shadbala_result = calc_shadbala(planets, asc_sign, birth_hour, sun_lon, moon_lon, context=context)
|
||||
# 添加顶层汇总
|
||||
if isinstance(shadbala_result, dict):
|
||||
sb_planets = shadbala_result.get('planets', {})
|
||||
|
||||
+186
-51
@@ -20,6 +20,7 @@ v6.9.12 修复:
|
||||
"""
|
||||
|
||||
import math
|
||||
import swisseph as swe
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
@@ -118,11 +119,189 @@ SPECIAL_ASPECTS = {
|
||||
|
||||
# Virupas → Rupas 转换(60 Virupas = 1 Rupa)
|
||||
VIRUPAS_PER_RUPA = 60.0
|
||||
_DIG_POWERLESS_HOUSE = {"Sun": 3, "Moon": 9, "Mars": 3, "Mercury": 6, "Jupiter": 6, "Venus": 9, "Saturn": 0}
|
||||
_MOOLATRIKONA = {
|
||||
"Sun": (4, 0.0, 20.0), "Moon": (1, 4.0, 30.0), "Mars": (0, 0.0, 12.0),
|
||||
"Mercury": (5, 16.0, 20.0), "Jupiter": (8, 0.0, 10.0),
|
||||
"Venus": (6, 0.0, 15.0), "Saturn": (10, 0.0, 20.0),
|
||||
}
|
||||
|
||||
|
||||
def build_shadbala_context(jd_ut: float, lat: float, lon: float, ayanamsa: str = "lahiri") -> Dict:
|
||||
"""Build precise sidereal house context from standard birth inputs."""
|
||||
sid_mode = swe.SIDM_LAHIRI
|
||||
if str(ayanamsa).lower() in {"raman"}:
|
||||
sid_mode = swe.SIDM_RAMAN
|
||||
elif str(ayanamsa).lower() in {"kp", "krishnamurti"}:
|
||||
sid_mode = swe.SIDM_KRISHNAMURTI
|
||||
swe.set_sid_mode(sid_mode)
|
||||
cusps, _ = swe.houses_ex(float(jd_ut), float(lat), float(lon), b"P", swe.FLG_SIDEREAL)
|
||||
return {"jd_ut": float(jd_ut), "lat": float(lat), "lon": float(lon), "ayanamsa": str(ayanamsa), "house_midpoints": [float(value) % 360 for value in cusps]}
|
||||
|
||||
|
||||
def calc_dig_bala_precise(pname: str, planet_lon: float, house_midpoints: list[float]) -> float:
|
||||
"""Classical directional strength from the powerless bhava midpoint."""
|
||||
powerless = house_midpoints[_DIG_POWERLESS_HOUSE[pname]]
|
||||
return round(abs(float(powerless) - (float(planet_lon) % 360)) / 3.0, 2)
|
||||
|
||||
|
||||
def _planet_longitude(name: str, planets: Dict) -> float:
|
||||
data = planets[name]
|
||||
degree = float(data.get("degree", 0.0))
|
||||
if degree >= 30.0 or data.get("sign") not in SIGNS:
|
||||
return degree % 360.0
|
||||
return (SIGNS.index(data["sign"]) * 30.0 + degree) % 360.0
|
||||
|
||||
|
||||
def classify_drik_planets(planets: Dict) -> tuple[set[str], set[str]]:
|
||||
"""Classify the seven planets for Drik Bala from lunar phase and Mercury's company."""
|
||||
benefics = {name for name in ("Jupiter", "Venus") if name in planets}
|
||||
malefics = {name for name in ("Sun", "Mars", "Saturn") if name in planets}
|
||||
|
||||
if "Moon" in planets and "Sun" in planets:
|
||||
target = benefics if (_planet_longitude("Moon", planets) - _planet_longitude("Sun", planets)) % 360.0 <= 180.0 else malefics
|
||||
target.add("Moon")
|
||||
|
||||
if "Mercury" in planets:
|
||||
mercury_lon = _planet_longitude("Mercury", planets)
|
||||
mercury_sign = int(mercury_lon // 30)
|
||||
companions = [
|
||||
name for name in benefics | malefics
|
||||
if name != "Mercury" and int(_planet_longitude(name, planets) // 30) == mercury_sign
|
||||
]
|
||||
benefic_count = sum(name in benefics for name in companions)
|
||||
malefic_count = sum(name in malefics for name in companions)
|
||||
if benefic_count >= malefic_count and (benefic_count != malefic_count or not companions):
|
||||
benefics.add("Mercury")
|
||||
elif malefic_count > benefic_count:
|
||||
malefics.add("Mercury")
|
||||
else:
|
||||
nearest = min(companions, key=lambda name: abs(_planet_longitude(name, planets) - mercury_lon))
|
||||
(benefics if nearest in benefics else malefics).add("Mercury")
|
||||
|
||||
return benefics, malefics
|
||||
|
||||
|
||||
def _sphuta_drishti_virupas(angle: float, aspecting_planet: str) -> float:
|
||||
angle = round(float(angle) % 360.0, 2)
|
||||
if angle < 30.0:
|
||||
strength = 0.0
|
||||
elif angle < 60.0:
|
||||
strength = (angle - 30.0) / 2.0
|
||||
elif angle < 90.0:
|
||||
strength = angle - 45.0 + (45.0 if aspecting_planet == "Saturn" else 0.0)
|
||||
elif angle < 120.0:
|
||||
strength = (120.0 - angle) / 2.0 + 30.0 + (15.0 if aspecting_planet == "Mars" else 0.0)
|
||||
elif angle < 150.0:
|
||||
strength = 150.0 - angle + (30.0 if aspecting_planet == "Jupiter" else 0.0)
|
||||
elif angle < 180.0:
|
||||
strength = 2.0 * (angle - 150.0)
|
||||
elif angle < 300.0:
|
||||
strength = (300.0 - angle) / 2.0
|
||||
if aspecting_planet == "Mars" and 210.0 <= angle < 240.0:
|
||||
strength += 15.0
|
||||
elif aspecting_planet == "Jupiter" and 240.0 <= angle < 270.0:
|
||||
strength += 30.0
|
||||
elif aspecting_planet == "Saturn" and 270.0 <= angle < 300.0:
|
||||
strength += 45.0
|
||||
else:
|
||||
strength = 0.0
|
||||
return round(strength, 2)
|
||||
|
||||
|
||||
def calc_drik_bala_precise(pname: str, all_planets: Dict) -> float:
|
||||
"""Continuous Sphuta Drishti, quarter-weighted by natural benefic/malefic status."""
|
||||
if pname not in all_planets:
|
||||
return 0.0
|
||||
benefics, malefics = classify_drik_planets(all_planets)
|
||||
target_lon = _planet_longitude(pname, all_planets)
|
||||
total = 0.0
|
||||
for other_name in benefics | malefics:
|
||||
if other_name == pname:
|
||||
continue
|
||||
strength = _sphuta_drishti_virupas(target_lon - _planet_longitude(other_name, all_planets), other_name)
|
||||
total += strength if other_name in benefics else -strength
|
||||
return round(total / 4.0, 2)
|
||||
|
||||
|
||||
def _d30_sign(sign_idx: int, degree: float) -> int:
|
||||
ranges = (
|
||||
((5, 0), (10, 10), (18, 8), (25, 2), (30, 6))
|
||||
if sign_idx % 2 == 0 else
|
||||
((5, 1), (12, 5), (20, 11), (25, 9), (30, 7))
|
||||
)
|
||||
return next(sign for upper, sign in ranges if degree <= upper)
|
||||
|
||||
|
||||
def _saptavarga_signs(planets: Dict) -> Dict[int, Dict[str, int]]:
|
||||
result = {division: {} for division in (1, 2, 3, 7, 9, 12, 30)}
|
||||
for name in set(planets) & set(_MOOLATRIKONA):
|
||||
longitude = _planet_longitude(name, planets)
|
||||
sign_idx, degree = int(longitude // 30), longitude % 30.0
|
||||
result[1][name] = sign_idx
|
||||
result[2][name] = (4 if sign_idx % 2 == 0 else 3) if degree < 15.0 else (3 if sign_idx % 2 == 0 else 4)
|
||||
for division in (3, 7, 9, 12):
|
||||
result[division][name] = varga_map(sign_idx, min(division - 1, int(degree / (30.0 / division))), division)
|
||||
result[30][name] = _d30_sign(sign_idx, degree)
|
||||
return result
|
||||
|
||||
|
||||
def _compound_relation_score(planet: str, owner: str, d1_signs: Dict[str, int]) -> float:
|
||||
natural = "friend" if owner in FRIENDSHIP[planet]["friend"] else "enemy" if owner in FRIENDSHIP[planet]["enemy"] else "neutral"
|
||||
separation = (d1_signs[owner] - d1_signs[planet]) % 12
|
||||
temporary = "friend" if separation in {1, 2, 3, 9, 10, 11} else "enemy"
|
||||
return {
|
||||
("friend", "friend"): 22.5,
|
||||
("neutral", "friend"): 15.0,
|
||||
("enemy", "friend"): 7.5,
|
||||
("friend", "enemy"): 7.5,
|
||||
("neutral", "enemy"): 3.75,
|
||||
("enemy", "enemy"): 1.875,
|
||||
}[(natural, temporary)]
|
||||
|
||||
|
||||
def calc_sthana_bala_precise(pname: str, all_planets: Dict, house: int) -> Dict:
|
||||
longitude = _planet_longitude(pname, all_planets)
|
||||
degree = longitude % 30.0
|
||||
vargas = _saptavarga_signs(all_planets)
|
||||
scores = {}
|
||||
for division, positions in vargas.items():
|
||||
sign_idx = positions[pname]
|
||||
owner = SIGN_LORDS[SIGNS[sign_idx]]
|
||||
mt_sign, mt_start, mt_end = _MOOLATRIKONA[pname]
|
||||
if division == 1 and sign_idx == mt_sign and mt_start <= degree < mt_end:
|
||||
score = 45.0
|
||||
elif owner == pname:
|
||||
score = 30.0
|
||||
else:
|
||||
score = _compound_relation_score(pname, owner, vargas[1])
|
||||
scores[f"sapta_d{division}"] = score
|
||||
|
||||
offset = (longitude - DEBILITATION_DEG[pname]) % 360.0
|
||||
ucha_bala = round(min(offset, 360.0 - offset) / 3.0, 2)
|
||||
wants_even = pname in {"Moon", "Venus"}
|
||||
ojayugma = 15.0 * sum((vargas[division][pname] % 2 == 1) == wants_even for division in (1, 9))
|
||||
kendra_bala = 60.0 if house in (1, 4, 7, 10) else 30.0 if house in (2, 5, 8, 11) else 15.0
|
||||
drekkana_bala = 15.0 if (
|
||||
(pname in {"Sun", "Mars", "Jupiter"} and degree < 10.0)
|
||||
or (pname in {"Mercury", "Saturn"} and 10.0 <= degree < 20.0)
|
||||
or (pname in {"Moon", "Venus"} and degree >= 20.0)
|
||||
) else 0.0
|
||||
sapta_score = round(sum(scores.values()), 2)
|
||||
return {
|
||||
"ucha_bala": ucha_bala,
|
||||
**scores,
|
||||
"sapta_score": sapta_score,
|
||||
"ojayugma_bala": ojayugma,
|
||||
"kendra_bala": kendra_bala,
|
||||
"drekkana_bala": drekkana_bala,
|
||||
"total": round(ucha_bala + sapta_score + ojayugma + kendra_bala + drekkana_bala, 2),
|
||||
}
|
||||
|
||||
|
||||
def calc_shadbala(planets: Dict, asc_sign: str, birth_hour: float,
|
||||
sun_lon: float, moon_lon: float,
|
||||
birth_minute: float = 0.0) -> Dict:
|
||||
birth_minute: float = 0.0, context: Dict | None = None) -> Dict:
|
||||
"""
|
||||
计算 Shadbala 相对强弱参考(covered;外部绝对值校准前保留置信度上限)
|
||||
|
||||
@@ -152,8 +331,8 @@ def calc_shadbala(planets: Dict, asc_sign: str, birth_hour: float,
|
||||
retro = p.get('retrograde', False)
|
||||
speed = p.get('speed', 1.0)
|
||||
|
||||
sthana = calc_sthana_bala(pname, lon, sign, house)
|
||||
dig = calc_dig_bala(pname, house)
|
||||
sthana = calc_sthana_bala_precise(pname, planets, house)
|
||||
dig = calc_dig_bala_precise(pname, lon, context["house_midpoints"]) if context and context.get("house_midpoints") else calc_dig_bala(pname, house)
|
||||
kala = calc_kala_bala(pname, is_night, sun_northern, sun_lon, moon_lon, birth_hour, birth_minute)
|
||||
chesta = calc_chesta_bala(pname, retro, speed, sun_lon, moon_lon)
|
||||
naisargika = NAISARGIKA_BALA.get(pname, 30.0)
|
||||
@@ -176,8 +355,8 @@ def calc_shadbala(planets: Dict, asc_sign: str, birth_hour: float,
|
||||
retro = p.get('retrograde', False)
|
||||
speed = p.get('speed', 1.0)
|
||||
|
||||
sthana = calc_sthana_bala(pname, lon, sign, house)
|
||||
dig = calc_dig_bala(pname, house)
|
||||
sthana = calc_sthana_bala_precise(pname, planets, house)
|
||||
dig = calc_dig_bala_precise(pname, lon, context["house_midpoints"]) if context and context.get("house_midpoints") else calc_dig_bala(pname, house)
|
||||
kala = calc_kala_bala(pname, is_night, sun_northern, sun_lon, moon_lon, birth_hour, birth_minute)
|
||||
chesta = calc_chesta_bala(pname, retro, speed, sun_lon, moon_lon)
|
||||
naisargika = NAISARGIKA_BALA.get(pname, 30.0)
|
||||
@@ -737,52 +916,8 @@ def calc_yuddha_bala(planets: Dict) -> Dict:
|
||||
|
||||
def calc_drik_bala(pname: str, sign: str, house: int,
|
||||
all_planets: Dict) -> float:
|
||||
"""Drik Bala(相位力量),基于精确度数差(Sputa Drishti)计算。
|
||||
v6.1.13: 升级为基于精确角距离的Sputa Drishti(替代简化宫位差)"""
|
||||
drik = 0.0
|
||||
p_sign_idx = SIGNS.index(sign) if sign in SIGNS else 0
|
||||
p_degree_in_sign = (all_planets[pname].get('degree', 0) if pname in all_planets else 0) % 30
|
||||
p_lon = p_sign_idx * 30 + p_degree_in_sign
|
||||
|
||||
for other_name, other_data in all_planets.items():
|
||||
if other_name == pname or other_name == 'Rahu' or other_name == 'Ketu':
|
||||
continue
|
||||
|
||||
other_sign = other_data.get('sign', '')
|
||||
if other_sign not in SIGNS:
|
||||
continue
|
||||
other_sign_idx = SIGNS.index(other_sign)
|
||||
other_deg_in_sign = other_data.get('degree', 0) % 30
|
||||
other_lon = other_sign_idx * 30 + other_deg_in_sign
|
||||
|
||||
# 计算精确角度差
|
||||
diff = abs(p_lon - other_lon)
|
||||
if diff > 180:
|
||||
diff = 360 - diff
|
||||
|
||||
# 检查传统相位规则(7宫=180°冲,特殊相位=Mars4/8, Jupiter5/9, Saturn3/10)
|
||||
has_aspect = False
|
||||
house_diff = (p_sign_idx - other_sign_idx) % 12 + 1
|
||||
if house_diff == 7 or house_diff == 1:
|
||||
has_aspect = True
|
||||
if other_name in SPECIAL_ASPECTS:
|
||||
if house_diff in SPECIAL_ASPECTS[other_name]:
|
||||
has_aspect = True
|
||||
|
||||
if not has_aspect:
|
||||
continue
|
||||
|
||||
# 使用Sputa Drishti计算相位力量 (0-1) → 缩放为0-60 Virupas
|
||||
sputa_value = _get_sputa_drishti_value(diff, other_name)
|
||||
|
||||
if other_name in BENEFICS:
|
||||
drik += sputa_value * 60.0
|
||||
elif other_name in MALEFICS:
|
||||
drik -= sputa_value * 60.0
|
||||
else:
|
||||
drik += sputa_value * 30.0 # 中性行星
|
||||
|
||||
return max(-60.0, min(60.0, drik))
|
||||
"""Compatibility wrapper for the continuous Sphuta Drishti calculation."""
|
||||
return calc_drik_bala_precise(pname, all_planets)
|
||||
|
||||
|
||||
# ============================================================================
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build same-case D2/D4/D9/D10/AV/Shadbala parity artifacts."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
if str(ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(ROOT))
|
||||
SCRIPTS = ROOT / "scripts"
|
||||
if str(SCRIPTS) not in sys.path:
|
||||
sys.path.insert(0, str(SCRIPTS))
|
||||
|
||||
from benchmarks.jyotish.scripts.run_pyjhora_compare import build_pyjhora_sample
|
||||
from benchmarks.jyotish.scripts.run_skill_baseline import run_sample
|
||||
from scripts.three_engine_parity_runner import _capture_jyotishganit_raw
|
||||
|
||||
ORACLE = ROOT / "references" / "oracle"
|
||||
ARTIFACTS = ORACLE / "artifacts"
|
||||
PLANETS = ["Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn"]
|
||||
SIGNS = ["Aries", "Taurus", "Gemini", "Cancer", "Leo", "Virgo", "Libra", "Scorpio", "Sagittarius", "Capricorn", "Aquarius", "Pisces"]
|
||||
VED_VARGA_FIELDS = {"D2": "PlanetHoraD2Signs", "D4": "PlanetChaturthamshaD4Sign", "D9": "PlanetNavamshaD9Sign", "D10": "PlanetDashamamshaD10Sign"}
|
||||
VED_COMPONENT_FIELDS = {
|
||||
"sthana": "PlanetSthanaBala", "kala": "PlanetKalaBala", "dig": "PlanetDigBala",
|
||||
"chesta": "PlanetChestaBala", "naisargika": "PlanetNaisargikaBala", "drik": "PlanetDrikBala",
|
||||
}
|
||||
SAMPLE = {
|
||||
"id": "steve_jobs_public_aa", "label": "Steve Jobs public AA", "category": "public", "privacy": "public",
|
||||
"birth": {"year": 1955, "month": 2, "day": 24, "hour": 19, "minute": 15, "lat": 37.7749, "lon": -122.4194, "tz": -8.0},
|
||||
"today": "2026-07-17",
|
||||
}
|
||||
|
||||
|
||||
def _write(path: Path, value: Any) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(json.dumps(value, ensure_ascii=False, indent=2, sort_keys=True), encoding="utf-8")
|
||||
|
||||
|
||||
def _sha(path: Path) -> str:
|
||||
return hashlib.sha256(path.read_bytes()).hexdigest()
|
||||
|
||||
|
||||
def _jyotish_planet_signs(chart: dict[str, Any]) -> dict[str, str]:
|
||||
return {str(p["celestialBody"]): str(p["sign"]) for h in chart.get("houses", []) for p in h.get("occupants", []) if p.get("celestialBody") in PLANETS}
|
||||
|
||||
|
||||
def _jyotish_shadbala(raw: dict[str, Any]) -> tuple[dict[str, float], dict[str, dict[str, float]]]:
|
||||
totals: dict[str, float] = {}; components: dict[str, dict[str, float]] = {}
|
||||
for house in raw["d1Chart"]["houses"]:
|
||||
for p in house.get("occupants", []):
|
||||
name = p.get("celestialBody")
|
||||
if name not in PLANETS or "shadbala" not in p:
|
||||
continue
|
||||
s = p["shadbala"]
|
||||
totals[name] = float(s["Shadbala"]["Total"])
|
||||
components[name] = {"sthana": float(s["Sthanabala"]["Total"]), "kala": float(s["Kaalabala"]["Total"]), "dig": float(s["Digbala"]), "chesta": float(s["Cheshtabala"]), "naisargika": float(s["Naisargikabala"]), "drik": float(s["Drikbala"])}
|
||||
return totals, components
|
||||
|
||||
|
||||
def _ved_payload(raw: dict[str, Any]) -> dict[str, Any]:
|
||||
return raw["Payload"]["AllPlanetData"]
|
||||
|
||||
|
||||
def _ved_components(raw: dict[str, Any], chesta: Any | None = None) -> dict[str, float]:
|
||||
payload = _ved_payload(raw)
|
||||
values = {name: float(payload[field]) for name, field in VED_COMPONENT_FIELDS.items() if field in payload}
|
||||
if chesta is not None:
|
||||
values["chesta"] = float(chesta)
|
||||
return values
|
||||
|
||||
|
||||
def _status(values: dict[str, Any], tolerance: float | None = None) -> str:
|
||||
data = list(values.values())
|
||||
if tolerance is not None and all(isinstance(v, (int, float)) for v in data):
|
||||
return "match" if max(data) - min(data) <= tolerance else "mismatch"
|
||||
return "match" if len({json.dumps(v, sort_keys=True) for v in data}) == 1 else "mismatch"
|
||||
|
||||
|
||||
def build() -> dict[str, Any]:
|
||||
local_result = run_sample(SAMPLE)
|
||||
if not local_result.get("ok"):
|
||||
raise RuntimeError(local_result.get("error"))
|
||||
local = local_result["canonical"]
|
||||
local["shadbala_method_variants"] = {
|
||||
"kala": "bphs_local_solar_events_ahargana_declination",
|
||||
"chesta": "bphs_bounded_surya_mean_motion_seeghrochcha",
|
||||
"chesta_source": "MIT jyotishganit structure plus public Surya Siddhanta revolution constants",
|
||||
}
|
||||
pyjhora = build_pyjhora_sample(SAMPLE)
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
jyotish, _ = _capture_jyotishganit_raw(Path(tmp))
|
||||
ved_path = ARTIFACTS / "vedastro_steve_jobs_public_aa_divisional_raw.json"
|
||||
ved = json.loads(ved_path.read_text(encoding="utf-8"))
|
||||
|
||||
local_path = ARTIFACTS / "local_steve_jobs_high_rigor_raw.json"
|
||||
py_path = ARTIFACTS / "pyjhora_steve_jobs_high_rigor_raw.json"
|
||||
jy_path = ARTIFACTS / "jyotishganit_steve_jobs_high_rigor_raw.json"
|
||||
_write(local_path, local); _write(py_path, pyjhora); _write(jy_path, jyotish)
|
||||
|
||||
rows: list[dict[str, Any]] = []
|
||||
jy_d1 = _jyotish_planet_signs(jyotish["d1Chart"])
|
||||
for planet in PLANETS:
|
||||
values = {
|
||||
"local": local["planets"][planet]["sign"],
|
||||
"PyJHora_JHora": pyjhora["planets"][planet]["sign"],
|
||||
"VedAstro": _ved_payload(ved["raw_responses"][planet])["PlanetRasiD1Sign"]["Name"],
|
||||
"jyotishganit": jy_d1[planet],
|
||||
}
|
||||
rows.append({"section": "D1", "field": f"{planet}.sign", "local_value": values.pop("local"), "oracle_values": values, "status": _status({"local": local["planets"][planet]["sign"], **values})})
|
||||
for section, ved_field in VED_VARGA_FIELDS.items():
|
||||
jy_signs = _jyotish_planet_signs(jyotish["divisionalCharts"][section.lower()])
|
||||
for planet in PLANETS:
|
||||
values = {
|
||||
"local": local["varga"][section][planet]["sign"],
|
||||
"PyJHora_JHora": pyjhora["varga"][section][planet]["sign"],
|
||||
"VedAstro": _ved_payload(ved["raw_responses"][planet])[ved_field]["Name"],
|
||||
"jyotishganit": jy_signs[planet],
|
||||
}
|
||||
rows.append({"section": section, "field": f"{planet}.sign", "local_value": values.pop("local"), "oracle_values": values, "status": _status({"local": local["varga"][section][planet]["sign"], **values})})
|
||||
|
||||
ved_bav = ved["scalar_responses"]["ashtakavarga_bav"]["Payload"]["BhinnashtakavargaChart"]
|
||||
ved_sav = ved["scalar_responses"]["ashtakavarga_sav_chart"]["Payload"]["SarvashtakavargaChart"]["Sarvashtakavarga"]["Rows"]
|
||||
jy_av = jyotish["ashtakavarga"]
|
||||
for planet in PLANETS:
|
||||
values = {"local": local["ashtakavarga"]["bav"][planet], "PyJHora_JHora": pyjhora["ashtakavarga"]["bav"][planet], "VedAstro": ved_bav[planet]["Rows"], "jyotishganit": [jy_av[f"{planet.lower()}Bhav"][s] for s in SIGNS]}
|
||||
rows.append({"section": "ashtakavarga_bav", "field": planet, "local_value": values.pop("local"), "oracle_values": values, "status": _status({"local": local["ashtakavarga"]["bav"][planet], **values})})
|
||||
sav_values = {"local": local["ashtakavarga"]["sav"], "PyJHora_JHora": pyjhora["ashtakavarga"]["sav"], "VedAstro": ved_sav, "jyotishganit": [jy_av["sav"][s] for s in SIGNS]}
|
||||
rows.append({"section": "ashtakavarga_sav", "field": "12_sign_scores", "local_value": sav_values.pop("local"), "oracle_values": sav_values, "status": _status({"local": local["ashtakavarga"]["sav"], **sav_values})})
|
||||
|
||||
jy_totals, jy_components = _jyotish_shadbala(jyotish)
|
||||
for planet in PLANETS:
|
||||
total_values = {"local": local["shadbala"][planet], "PyJHora_JHora": pyjhora["shadbala"][planet], "VedAstro": float(_ved_payload(ved["raw_responses"][planet])["PlanetShadbalaPinda"]), "jyotishganit": jy_totals[planet]}
|
||||
rows.append({"section": "shadbala_total", "field": planet, "local_value": total_values.pop("local"), "oracle_values": total_values, "status": _status({"local": local["shadbala"][planet], **total_values}, 0.5)})
|
||||
ved_chesta = ved["component_responses"][f"{planet}.chesta"]["Payload"]["PlanetChestaBala"]
|
||||
ved_components = _ved_components(ved["raw_responses"][planet], ved_chesta)
|
||||
for component in VED_COMPONENT_FIELDS:
|
||||
values = {"local": local["shadbala_components"][planet][component], "PyJHora_JHora": pyjhora["shadbala_components"][planet][component], "VedAstro": ved_components[component], "jyotishganit": jy_components[planet][component]}
|
||||
row = {"section": "shadbala_components", "field": f"{planet}.{component}", "local_value": values.pop("local"), "oracle_values": values, "status": _status({"local": local["shadbala_components"][planet][component], **values}, 0.5)}
|
||||
if component == "chesta":
|
||||
row["method_conflict"] = "PyJHora unbounded; VedAstro/jyotishganit bounded; Sun/Moon treatment differs across engines."
|
||||
rows.append(row)
|
||||
|
||||
manifest = {
|
||||
"case_id": "steve_jobs_public_1955_lahiri", "birth_data_policy": "public_case_only", "blocked_reason": "none",
|
||||
"engines": {
|
||||
"VedAstro": {"status": "official_verified", "official_raw_response_path": "artifacts/" + ved_path.name, "artifact_hash": _sha(ved_path), "settings": ved["settings"]},
|
||||
"PyJHora_JHora": {"status": "imported", "raw_output_path": "artifacts/" + py_path.name, "artifact_hash": _sha(py_path), "settings": pyjhora["settings"]},
|
||||
"jyotishganit": {"status": "imported", "raw_output_path": "artifacts/" + jy_path.name, "artifact_hash": _sha(jy_path), "settings": {"ayanamsa": jyotish["ayanamsa"]}},
|
||||
},
|
||||
"comparison_rows": rows,
|
||||
"method_arbitration": {
|
||||
"kala": "local_vs_PyJHora_7_of_7_within_0.05_virupa",
|
||||
"chesta": "blocked_cross_engine_method_conflict",
|
||||
"chesta_local_variant": "bphs_bounded_surya_mean_motion_seeghrochcha",
|
||||
},
|
||||
"runtime_boundary": "Full same-case raw coverage; mismatches remain formula/method differences, not missing artifacts.",
|
||||
}
|
||||
_write(ORACLE / "three_engine_parity_replay_manifest.json", manifest)
|
||||
return manifest
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
result = build()
|
||||
print(json.dumps({"status": "built", "rows": len(result["comparison_rows"])}, indent=2))
|
||||
@@ -0,0 +1,56 @@
|
||||
from scripts.shadbala import (
|
||||
build_shadbala_context,
|
||||
calc_dig_bala_precise,
|
||||
calc_drik_bala_precise,
|
||||
calc_sthana_bala_precise,
|
||||
classify_drik_planets,
|
||||
)
|
||||
|
||||
|
||||
PLANET_LONGITUDES = {
|
||||
"Sun": 312.51819523181405,
|
||||
"Moon": 344.51168181221095,
|
||||
"Mars": 5.862334338243072,
|
||||
"Mercury": 291.12589362817465,
|
||||
"Jupiter": 87.27055150216494,
|
||||
"Venus": 267.94211928370015,
|
||||
"Saturn": 207.92738390514674,
|
||||
}
|
||||
PYJHORA_DIG = {"Sun": 24.81, "Moon": 95.48, "Mars": 77.41, "Mercury": 12.64, "Jupiter": 80.60, "Venus": 69.95, "Saturn": 19.62}
|
||||
PYJHORA_DRIK = {"Sun": 1.74, "Moon": 20.06, "Mars": 13.49, "Mercury": -10.63, "Jupiter": 6.89, "Venus": -2.75, "Saturn": 9.49}
|
||||
PYJHORA_STHANA = {"Sun": 217.09, "Moon": 246.34, "Mars": 198.63, "Mercury": 167.96, "Jupiter": 201.80, "Venus": 154.06, "Saturn": 218.61}
|
||||
|
||||
|
||||
def _planets() -> dict:
|
||||
return {
|
||||
planet: {
|
||||
"degree": longitude,
|
||||
"sign": ["Aries", "Taurus", "Gemini", "Cancer", "Leo", "Virgo", "Libra", "Scorpio", "Sagittarius", "Capricorn", "Aquarius", "Pisces"][int(longitude // 30)],
|
||||
}
|
||||
for planet, longitude in PLANET_LONGITUDES.items()
|
||||
}
|
||||
|
||||
|
||||
def test_precise_dig_bala_matches_pyjhora_same_chart() -> None:
|
||||
context = build_shadbala_context(2435163.6354166665, 37.7749, -122.4194, "lahiri")
|
||||
for planet, longitude in PLANET_LONGITUDES.items():
|
||||
assert calc_dig_bala_precise(planet, longitude, context["house_midpoints"]) == PYJHORA_DIG[planet]
|
||||
|
||||
|
||||
def test_drik_classification_matches_pyjhora_same_chart() -> None:
|
||||
benefics, malefics = classify_drik_planets(_planets())
|
||||
assert benefics == {"Moon", "Mercury", "Jupiter", "Venus"}
|
||||
assert malefics == {"Sun", "Mars", "Saturn"}
|
||||
|
||||
|
||||
def test_precise_drik_bala_matches_pyjhora_same_chart() -> None:
|
||||
planets = _planets()
|
||||
for planet, expected in PYJHORA_DRIK.items():
|
||||
assert abs(calc_drik_bala_precise(planet, planets) - expected) <= 0.02
|
||||
|
||||
|
||||
def test_precise_sthana_bala_matches_pyjhora_same_chart() -> None:
|
||||
planets = _planets()
|
||||
houses = {"Sun": 7, "Moon": 8, "Mars": 9, "Mercury": 6, "Jupiter": 11, "Venus": 5, "Saturn": 3}
|
||||
for planet, expected in PYJHORA_STHANA.items():
|
||||
assert calc_sthana_bala_precise(planet, planets, houses[planet])["total"] == expected
|
||||
@@ -0,0 +1,56 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from benchmarks.jyotish.scripts.run_skill_baseline import run_sample
|
||||
from benchmarks.jyotish.scripts.run_pyjhora_compare import build_pyjhora_sample, compare_one
|
||||
from scripts import three_engine_high_rigor_parity as parity
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def test_runner_imports_from_commercial_root() -> None:
|
||||
env = os.environ.copy()
|
||||
env["PYTHONPATH"] = str(ROOT)
|
||||
result = subprocess.run(
|
||||
[sys.executable, "-c", "import scripts.three_engine_high_rigor_parity"],
|
||||
cwd=ROOT,
|
||||
env=env,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
assert result.returncode == 0, result.stderr
|
||||
|
||||
|
||||
def test_public_sample_exposes_shadbala_components() -> None:
|
||||
result = run_sample(parity.SAMPLE)
|
||||
assert result["ok"] is True
|
||||
components = result["canonical"]["shadbala_components"]
|
||||
assert set(components["Sun"]) == set(parity.VED_COMPONENT_FIELDS)
|
||||
|
||||
|
||||
def test_pyjhora_sample_exposes_shadbala_components() -> None:
|
||||
sample = build_pyjhora_sample(parity.SAMPLE)
|
||||
assert set(sample["shadbala_components"]["Sun"]) == set(parity.VED_COMPONENT_FIELDS)
|
||||
|
||||
|
||||
def test_pyjhora_matrix_includes_shadbala_components() -> None:
|
||||
baseline = {
|
||||
"ascendant": {}, "planets": {}, "varga": {}, "ashtakavarga": {}, "shadbala": {}, "dasha": {},
|
||||
"shadbala_components": {"Sun": {name: 1.0 for name in parity.VED_COMPONENT_FIELDS}},
|
||||
}
|
||||
rows = compare_one("sample", baseline, baseline)
|
||||
assert {row["field"] for row in rows if row["section"] == "Shadbala_Component" and row["body"] == "Sun"} == set(parity.VED_COMPONENT_FIELDS)
|
||||
|
||||
|
||||
def test_jyotishganit_planet_map_reads_divisional_occupants() -> None:
|
||||
chart = {"houses": [{"occupants": [{"celestialBody": "Sun", "sign": "Leo"}]}]}
|
||||
assert parity._jyotish_planet_signs(chart) == {"Sun": "Leo"}
|
||||
|
||||
|
||||
def test_vedastro_components_read_six_raw_fields() -> None:
|
||||
raw = {"Payload": {"AllPlanetData": {field: index for index, field in enumerate(parity.VED_COMPONENT_FIELDS.values(), 1)}}}
|
||||
assert parity._ved_components(raw) == {name: index for index, name in enumerate(parity.VED_COMPONENT_FIELDS, 1)}
|
||||
Reference in New Issue
Block a user