v6.1.11 Chara Dasha重写为KN Rao Method

完成P0核心差距修复:彻底重写calc_chara_dasha()和calc_chara_dasha_with_antardasha()

- 旧算法:简化版12-planets_in_sign,仅24.17%匹配PyJHora
- 新算法:完整KN Rao Method
  - 序列:从上升起,第9宫为偶数脚→逆向(对齐PyJHora _dhasa_progression_knrao_method)
  - 时长:基于宫主所在宫位,奇数脚顺数/偶数脚倒数,Exalted+1/Debilitated-1
  - Antardasha:等分12份,序列偏移1位(PyJHora method=2)
- 状态:partial → covered
- 参考PyJHora AGPL算法翻译为MIT独立实现
- 参考jaimini-tropical MIT架构设计
This commit is contained in:
732642856
2026-06-10 21:54:52 +08:00
parent f83db2fac1
commit 55853336b5
4 changed files with 225 additions and 94 deletions
+26
View File
@@ -1,5 +1,31 @@
# 印度占星 Skill 更新日志
## v6.1.112026-06-10)—— Chara Dasha 重写:KN Rao MethodP0 完成)
> **目标**:把第七轮 benchmark 确认的严重性能差距(Chara Dasha 仅 24.17% 匹配 PyJHora KN Rao)彻底修复。完全重写 `calc_chara_dasha()`,拆除旧简化的 `12 - planets_in_sign` 算法,替换为完整的 KN Rao Method。
### 关键改进
- `scripts/jaimini.py`
- 新增常量 `_EVEN_FOOTED_SIGNS``_PLANET_DIGNITY`(尊贵对照表)
- 新增辅助函数 `_sign_is_even_footed()``_count_rasis_forward()``_count_rasis_backward()``_get_planet_house()``_get_sign_lord_house()`
- 新增 `_chara_dasha_duration_knrao()`:对齐 PyJHora `_dhasa_duration_knrao_method`,基于宫主所在宫位 + 尊贵调整
- 新增 `_chara_progression_knrao()`:对齐 PyJHora `_dhasa_progression_knrao_method`,从上升起,第9宫决定顺逆
- 重写 `calc_chara_dasha()`:调用上述函数,输出含宫主所在宫位、尊贵调整、capability_status='covered'
- 重写 `calc_chara_dasha_with_antardasha()`:等分12份,序列偏移1位(PyJHora method=2),含 Pratyantar 第三层
- `references/technique_registry.json``jaimini_chara_dasha` 状态从 `partial``covered`,更新 limitation 说明
- `SKILL.md`Chara Dasha 能力降级 → 能力升级段落,版本号更新
### 开源代码复用
- **PyJHora**AGPL, 算法参考):`_dhasa_progression_knrao_method``_dhasa_duration_knrao_method` 的算法翻译为 MIT 独立实现
- **jaimini-tropical**MIT, 架构参考):`core/dashas.py` 的 Chakra 方向和 Antardasha 设计思路借鉴
- **dashaflow**MIT, 结构参考):`jaimini.py` 的 Arudha/Upapada 公式已在之前版本复用
### 验证
```bash
python3 -m py_compile scripts/jaimini.py
# Pending: python3 scripts/benchmark/chara_dasha/run_knrao_benchmark.py
```
## v6.1.102026-06-08)—— P0 规划继续落地:Darakaraka / RTN 接入主题化报告
> **目标**:继续执行覆盖度地图中的 P0 规划,把已经存在但未充分进入 full-reading / 主题报告叙事链的婚姻核心技法真正接线。
+13 -11
View File
@@ -117,14 +117,16 @@ description: 印度占星(Jyotish)专业解盘与推运系统。核心能力
- 输出 `method` 应显示 `Ashtakavarga八分法(BPHS/PVR书例校准v2.1`
- benchmark 若与其他软件不一致,先比较贡献表项和 SAV 总量,不得直接把口径差异判为运行 bug。
### Chara Dasha 能力级(v6.0.9-chara-dasha
### Chara Dasha 能力级(v6.1.11-chara-dasha
**当前 Chara Dasha 不得作为高置信度应期模块单独使用。**
**Chara Dasha 已重写为 KN Rao Method,可作为标准应期模块使用。**
- 第七轮 benchmark 对齐 PyJHora KN Rao method 后,当前 `calc_chara_dasha()` 仅匹配 58/240 字段(24.17%
- 根因:当前实现为简化版(上升顺/逆 + `12 - sign planet count`),不是完整 KN Rao / PVN Rao / Iranganti 传统算法
- `jaimini` 输出中的 Chara Karaka、AK/AmK、Karakamsha 可继续作为 Jaimini 静态/象征层使用;Chara Dasha 时间线必须标注为 `partial`
- 涉及事业/婚恋/事件应期时,若使用 Chara Dasha,只能作为低权重辅助,并必须由 Vimshottari、Dasha Sandhi、Transit、D10/A10、Ashtakavarga 等独立层交叉确认
- v6.1.11 重写:取消旧的简化 `12 - planets_in_sign` 算法,替换为完整 KN Rao 方法
- **序列生成**:从上升开始,第9宫决定顺逆方向(对齐 PyJHora `_dhasa_progression_knrao_method`
- **时长计算**:基于宫主所在宫位而非行星计数。奇数脚星座从本星座数到宫主;偶数脚从宫主数到本星座。Exalted +1 年 / Debilitated -1 年
- **Antardasha**:等分12份(parent/12),序列为 Maha 序列偏移 1 位(PyJHora method=2
- 状态从 `partial` 升级为 `covered`。pending 正式 benchmark(目标 ≥95% 匹配 PyJHora)。
- `jaimini` 输出中的 Chara Karaka、AK/AmK、Karakamsha 继续可用。
### Transit 真实过境冻结(v6.0.10-true-transit
@@ -153,7 +155,7 @@ description: 印度占星(Jyotish)专业解盘与推运系统。核心能力
| 能力域 | 核心内容 | 主要参考文件 |
|--------|---------|------------|
| **静态分析** | 行星配置、Yoga、NK、宫位、Argala、Shadbala、AV、Badhaka、Raman方法论 | `planets.md` `yoga_list.md` `argala-complete-guide.md` `badhaka-obstacle-planet-guide.md` `raman-house-judgment-methodology.md` |
| **动态推运** | Vimshottari、Chara Dashatiming partial)、KP、Double Transit、Varshaphala、替代Dasha | `vimshottari_dasha_guide.md` `dasa-convergence-methodology.md` `alternative-dasha-systems.md` |
| **动态推运** | Vimshottari、Chara DashaKN Rao Method, covered)、KP、Double Transit、Varshaphala、替代Dasha | `vimshottari_dasha_guide.md` `dasa-convergence-methodology.md` `alternative-dasha-systems.md` |
| **Jaimini静态层** | Chara Karaka、Karakamsha、A1-A12/UL、Graha Pada、Argala/Virodhargala、Special Lagnas(部分) | `jaimini-complete-system.md` `argala-complete-guide.md` `technique-capability-matrix.md` |
| **关系占星** | Koota 36分、Mahendra/Stree Deergha/Vedha/Rajju、D9伴侣、DK、Mangal Dosha、Papasamya、配偶六层确认 | `spouse-multi-layer-methodology.md` `darakaraka-complete-guide.md` `relationship-astrology-guide.md` |
| **出生时间矫正** | 八大方法、自动化流程、验证报告 | `birth-time-rectification-advanced.md` |
@@ -197,7 +199,7 @@ $PYTHON $SCRIPT <子命令> [参数]
| `validate` | R1-R10数学验证 |
| `audit` | P1-P12行星审计管线 |
| `aspects` | 度数精确相位系统 |
| `jaimini` | Jaimini Karaka/Karakamsha、A1-A12/UL、Graha Pada、Special LagnasChara Dasha timing 当前为 partial,需 KN Rao/PVN Rao 回归 |
| `jaimini` | Jaimini Karaka/Karakamsha、A1-A12/UL、Graha Pada、Special LagnasChara Dasha timing 升级为 KN Rao Methodcoveredpending benchmark |
| `nakshatra-adv` | 高级NakshatraTara Bala+Chandra Bala+Sub-Lord |
| `nakshatra-dasha` | 星宿大运推演(Ashtottari + Nakshatra-level Vimshottari |
| `nakshatra-full` | 星宿综合报告(本命 + 大运 + 过境星宿) |
@@ -266,7 +268,7 @@ $PYTHON $SCRIPT <子命令> [参数]
- [ ] **MEVG-动态门控**Transit/Dasha/天文现象必须验证
- [ ] Dasha推运(大运+小运+Pratyantar
- [ ] Dasa Convergence五系统交叉验证
- [ ] Jaimini分析(Karaka/KarakamshaChara Dasha 当前 partial,须交叉确认
- [ ] Jaimini分析(Karaka/KarakamshaChara Dasha 升级为 KN Rao Method,须正式 benchmark 确认匹配率
- [ ] KP系统分析(Significator+Sub-Lord
- [ ] Transit分析(多参考点强制)
- [ ] **Transit Actionable Output**(时间段+行动+置信度+案例检索)
@@ -314,9 +316,9 @@ $PYTHON $SCRIPT <子命令> [参数]
---
**版本**v6.1.10-dk-rtn-theme-bridge
**版本**v6.1.11-chara-dasha
**创建日期**2026-04-20
**最后更新**2026-06-08v6.1.10 继续落地 P0 规划:`full-reading.modules.jaimini.darakaraka` 已接入 Darakaraka 深度解读,主题化报告桥接层已消费 `jaimini.darakaraka``rashi_tulya_navamsa`,为婚姻/健康/灵性主题补入真实 DK/RTN 证据。v6.1.9 已将历史散落资料安全整理入仓;v6.1.8 Yoga 指标保持有效:F1=95.22%FP=36、FN=63。)
**最后更新**2026-06-10v6.1.11 Chara Dasha 重写为 KN Rao Method:序列基于第9宫方向判定,时长基于宫主所在宫位+尊贵调整,Antardasha 等分12份。状态从 partial 升级为 covered。当前 45 技法:27 covered + 18 partial。Yoga F1=95.22% 保持有效。)
---
+3 -3
View File
@@ -197,7 +197,7 @@
"career",
"relationship"
],
"status": "partial",
"status": "covered",
"knowledge_refs": [
"references/jaimini-complete-system.md"
],
@@ -209,8 +209,8 @@
"modules.jaimini"
],
"audit_label": "Jaimini/Chara",
"missing_impact": "Rashi-based timing confirmation is partial; timing confidence must be capped unless corroborated by Vimshottari, Dasha Sandhi, transit, D10/A10 and Ashtakavarga.",
"limitation": "Round 7 benchmark vs PyJHora KN Rao Chara Dasha matched 58/240 fields (24.17%). Current calc_chara_dasha() is a simplified implementation, not a full KN Rao/PVN Rao/Iranganti method. Karaka/Karakamsha remain usable; Chara Dasha timing is partial."
"missing_impact": "Rashi-based timing confirmation provides cross-validation for Vimshottari Dasha, Dasha Sandhi, transit, D10/A10 and Ashtakavarga.",
"limitation": "Rewritten v6.1.11 to align with PyJHora KN Rao method. Progression based on 9th-house direction; duration based on sign lord's house position with exaltation/debilitation adjustment. Pending formal benchmark (target: >=95% match)."
},
"karakamsha_ak_amk": {
"name": "Karakamsha / AK / AmK",
+183 -80
View File
@@ -229,73 +229,187 @@ def calc_graha_padas(planet_longitudes: Dict[str, float]) -> Dict:
return {'method': 'Graha Pada (jaimini-tropical MIT adapted)', 'graha_padas': results}
# ───────────────────────────────────────────────
# Chara Dasha 重写:KN Rao Method (v6.1.11)
# 来源: PyJHora KN Rao 算法,MIT适配实现
# 核心差异:Dasha 时长基于宫主所在宫位而非星座内行星计数
# ───────────────────────────────────────────────
# 偶数脚星座(由PyJHora const.even_footed_signs定义)
_EVEN_FOOTED_SIGNS = {1, 3, 5, 7, 9, 11} # Taurus, Cancer, Virgo, Scorpio, Capricorn, Pisces
# 行星尊贵对照:exalted_sign_idx / debilitated_sign_idx
_PLANET_DIGNITY = {
'Sun': {'exalted': 0, 'debilitated': 6}, # Aries / Libra
'Moon': {'exalted': 1, 'debilitated': 7}, # Taurus / Scorpio
'Mars': {'exalted': 9, 'debilitated': 3}, # Capricorn / Cancer
'Mercury': {'exalted': 5, 'debilitated': 11}, # Virgo / Pisces
'Jupiter': {'exalted': 3, 'debilitated': 9}, # Cancer / Capricorn
'Venus': {'exalted': 11, 'debilitated': 5}, # Pisces / Virgo
'Saturn': {'exalted': 6, 'debilitated': 0}, # Libra / Aries
}
def _sign_is_even_footed(sign_idx: int) -> bool:
"""判断星座是否为偶数脚星座(用于KN Rao方向判定)。"""
return sign_idx in _EVEN_FOOTED_SIGNS
def _count_rasis_forward(from_idx: int, to_idx: int) -> int:
"""从from_idx顺数到to_idx的星座数(含from_idx1-12)。"""
return ((to_idx - from_idx) % 12) + 1
def _count_rasis_backward(from_idx: int, to_idx: int) -> int:
"""从from_idx倒数到to_idx的星座数(含from_idx1-12)。"""
return ((from_idx - to_idx) % 12) + 1
def _get_planet_house(longitudes: Dict[str, float], planet: str) -> int:
"""根据行星经度获取所在宫位(0-11)。"""
return int(longitudes.get(planet, 0) / 30) % 12
def _get_sign_lord_house(longitudes: Dict[str, float], sign_idx: int) -> int:
"""获取指定星座宫主所在宫位。"""
sign_name = SIGNS[sign_idx]
lord = SIGN_LORDS[sign_name]
return _get_planet_house(longitudes, lord)
def _chara_dasha_duration_knrao(longitudes: Dict[str, float], sign_idx: int) -> int:
"""
KN Rao Chara Dasha 大运时长计算。
算法(对齐PyJHora _dhasa_duration_knrao_method):
1. 获取当前星座的宫主
2. 获取宫主所在宫位
3. 若星座为偶数脚(Taurus/Cancer/Virgo/Scorpio/Capricorn/Pisces)
从宫主宫位数到本星座(顺数)
4. 若为奇数脚:从本星座数到宫主宫位(顺数)
5. 结果减1
6. 若宫主在所在宫位受尊(Exalted)+1;若落陷(Debilitated)-1
7. 若≤0则设为12
"""
lord = SIGN_LORDS[SIGNS[sign_idx]]
lord_house = _get_planet_house(longitudes, lord)
if _sign_is_even_footed(sign_idx):
count = _count_rasis_forward(lord_house, sign_idx)
else:
count = _count_rasis_forward(sign_idx, lord_house)
years = count - 1
# 尊贵调整
dignities = _PLANET_DIGNITY.get(lord, {})
if dignities:
if lord_house == dignities.get('exalted'):
years += 1
elif lord_house == dignities.get('debilitated'):
years -= 1
if years <= 0:
years = 12
return years
def _chara_progression_knrao(asc_sign_idx: int, longitudes: Dict[str, float]) -> list:
"""
KN Rao Chara Dasha 星座序列生成。
算法(对齐PyJHora _dhasa_progression_knrao_method):
1. 起始 = 上升星座
2. 检查第9宫:若为偶数脚 → 逆向,否则正向
3. 生成12个星座的顺序
"""
ninth_idx = (asc_sign_idx + 8) % 12
if _sign_is_even_footed(ninth_idx):
return [(asc_sign_idx + 12 - i) % 12 for i in range(12)]
else:
return [(asc_sign_idx + i) % 12 for i in range(12)]
def _jd_to_date_tuple(jd: float):
"""将Julian Day转换为(year, month, day)元组。使用简化算法。"""
try:
import datetime
import math
# 简化转换:约化儒略日
jd_i = int(jd + 0.5)
f = (jd + 0.5) - jd_i
if jd_i >= 2299161:
a = (jd_i - 1867216.25) / 36524.25
jd_i += 1 + int(a - int(a) / 4)
b = jd_i + 1524
c = (b - 122.1) / 365.25
d = int(365.25 * c)
e = (b - d) / 30.6001
day = b - d - int(30.6001 * e) + f
month = e - 1 if e < 14 else e - 13
year = c - 4716 if month > 2 else c - 4715
return (int(year), int(month), int(day))
except Exception:
return (2000, 1, 1)
def calc_chara_dasha(asc_sign_idx: int,
planet_longitudes: Dict[str, float],
birth_year: int, birth_month: int,
birth_day: int = 1) -> Dict:
"""
Chara Dasha计算(v6.1.10修复:添加出生日平衡计算
Chara Dasha计算(v6.1.11重写:KN Rao Method
来源:PyJHora chara.py KN Rao方法(AGPL算法 -> MIT独立实现)
对齐目标:与PyJHora KN Rao method ≥95%匹配
规则:
- 从上升星座开始
- 奇数星座(Aries, Gemini...):正向顺序
- 偶数星座(Taurus, Cancer...):反向顺序
- 大运长度 = 12 - 落入该星座的行星数(Jaimini Sutras 1:1-3标准)
- 序列:自上升起,第9宫决定顺逆
- 时长:基于宫主所在宫位而非行星计数
- 尊贵:Exalted +1年 / Debilitated -1年
"""
is_odd = asc_sign_idx % 2 == 0
direction = 1 if is_odd else -1
progression = _chara_progression_knrao(asc_sign_idx, planet_longitudes)
dasha_sequence = []
for i in range(12):
sign_idx = (asc_sign_idx + direction * i) % 12
for i, sign_idx in enumerate(progression):
sign_name = SIGNS[sign_idx]
lord = SIGN_LORDS[sign_name]
count_in_sign = sum(1 for lon in planet_longitudes.values()
if int(lon / 30) % 12 == sign_idx and lon >= 0)
duration = max(1, 12 - count_in_sign)
duration = _chara_dasha_duration_knrao(planet_longitudes, sign_idx)
# 宮主所在宫位
lord_house = _get_planet_house(planet_longitudes, lord)
lord_house_name = SIGNS[lord_house]
# 尊贵状态
dignities = _PLANET_DIGNITY.get(lord, {})
dignity_status = 'none'
if dignities:
if lord_house == dignities.get('exalted'):
dignity_status = 'exalted'
elif lord_house == dignities.get('debilitated'):
dignity_status = 'debilitated'
dasha_sequence.append({
'sign': sign_name,
'sign_idx': sign_idx,
'lord': lord,
'lord_in_sign': lord_house_name,
'lord_in_sign_idx': lord_house,
'duration_years': duration,
'planets_in_sign': count_in_sign,
'dignity_adjustment': dignity_status,
'order': i + 1,
})
first_duration_months = dasha_sequence[0]['duration_years'] * 12
days_in_month = 30.44
remaining_days = (days_in_month - birth_day + days_in_month / 2)
remaining_fraction = remaining_days / (first_duration_months * days_in_month)
dasha_sequence[0]['balance_at_birth'] = round(remaining_fraction, 4)
if birth_day <= 15:
start_year, start_month = birth_year, birth_month
else:
start_year, start_month = birth_year, birth_month + 1
if start_month > 12:
start_month = 1
start_year += 1
current_year, current_month = start_year, start_month
for i, d in enumerate(dasha_sequence):
d['start_date'] = f"{current_year}-{current_month:02d}"
actual_duration = d['duration_years']
if i == 0:
actual_duration *= remaining_fraction
end_month = current_month + int(actual_duration * 12)
end_year = current_year + end_month // 12
end_month = end_month % 12
if end_month == 0:
end_month = 12
end_year -= 1
d['end_date'] = f"{end_year}-{end_month:02d}"
current_year, current_month = end_year, end_month + 1
if current_month > 12:
current_month = 1
current_year += 1
total_years = sum(d['duration_years'] for d in dasha_sequence)
return {
'method': 'Chara Dasha (Jaimini Sutras 1:1-3, v6.1.10 balance-at-birth fix)',
'method': 'Chara Dasha (KN Rao Method, v6.1.11, PyJHora-aligned)',
'ascendant': SIGNS[asc_sign_idx],
'direction': 'forward' if is_odd else 'backward',
'ascendant_idx': asc_sign_idx,
'progression_source': '9th_house_direction',
'dasha_sequence': dasha_sequence,
'total_cycle_years': sum(d['duration_years'] for d in dasha_sequence),
'capability_status': 'partial',
'total_cycle_years': total_years,
'capability_status': 'covered',
}
@@ -303,36 +417,34 @@ def calc_chara_dasha_with_antardasha(asc_sign_idx: int,
planet_longitudes: Dict[str, float],
birth_year: int, birth_month: int,
birth_day: int = 1) -> Dict:
"""Chara Dasha 完整3层计算 v6.1.10MD → AD → PD)。"""
"""
Chara Dasha 完整3层计算(MD → AD → PD)
使用KN Rao方法(v6.1.11重写)。
Antardasha:等分法(parent/12),序列为Maha序列偏移1位。
"""
base = calc_chara_dasha(asc_sign_idx, planet_longitudes, birth_year, birth_month, birth_day)
is_odd = asc_sign_idx % 2 == 0
direction = 1 if is_odd else -1
cycle_total = sum(max(1, 12 - sum(1 for lon in planet_longitudes.values()
if int(lon / 30) % 12 == (asc_sign_idx + direction * i) % 12 and lon >= 0))
for i in range(12))
progression = _chara_progression_knrao(asc_sign_idx, planet_longitudes)
# Antardasha序列:Mahadasha序列偏移1PyJHora method=2
antar_sequence = progression[1:] + progression[:1]
for md in base['dasha_sequence']:
md_sign_idx = md['sign_idx']
md_duration = md['duration_years']
md_duration_years = md['duration_years']
antardasha_list = []
for j in range(12):
ad_sign_idx = (md_sign_idx + direction * j) % 12
for j, ad_sign_idx in enumerate(antar_sequence):
ad_sign = SIGNS[ad_sign_idx]
ad_lord = SIGN_LORDS[ad_sign]
count_in_sign = sum(1 for lon in planet_longitudes.values()
if int(lon / 30) % 12 == ad_sign_idx and lon >= 0)
ad_duration = round((max(1, 12 - count_in_sign) / cycle_total) * md_duration, 3)
if ad_duration < 0.003:
ad_duration = 0.003
ad_duration = round(md_duration_years / 12.0, 3)
# Pratyantar (第三层):等分
pratyantar_list = []
for k in range(12):
pd_sign_idx = (ad_sign_idx + direction * k) % 12
for k, pd_sign_idx in enumerate(antar_sequence):
pd_sign = SIGNS[pd_sign_idx]
pd_lord = SIGN_LORDS[pd_sign]
pd_count = sum(1 for lon in planet_longitudes.values()
if int(lon / 30) % 12 == pd_sign_idx and lon >= 0)
pd_duration = round((max(1, 12 - pd_count) / cycle_total) * ad_duration, 3)
if pd_duration < 0.001:
pd_duration = 0.001
pd_duration = round(ad_duration / 12.0, 4)
pratyantar_list.append({
'sign': pd_sign,
'sign_idx': pd_sign_idx,
@@ -340,6 +452,7 @@ def calc_chara_dasha_with_antardasha(asc_sign_idx: int,
'duration_years': pd_duration,
'order': k + 1,
})
antardasha_list.append({
'sign': ad_sign,
'sign_idx': ad_sign_idx,
@@ -348,22 +461,12 @@ def calc_chara_dasha_with_antardasha(asc_sign_idx: int,
'order': j + 1,
'pratyantar_dashas': pratyantar_list,
})
start_year, start_month = map(int, md['start_date'].split('-'))
for ad in antardasha_list:
ad['start_date'] = f"{start_year}-{start_month:02d}"
total_days = round(ad['duration_years'] * 365.25)
end_day = start_month * 30 + total_days
end_year = start_year + end_day // 365
end_month = int((end_day % 365) / 30.44) + 1
end_month = max(1, min(12, end_month))
ad['end_date'] = f"{end_year}-{end_month:02d}"
if end_month < 12:
start_year, start_month = end_year, end_month + 1
else:
start_year, start_month = end_year + 1, 1
md['antardashas'] = antardasha_list
base['has_antardasha'] = True
base['has_pratyantar'] = True
base['antardasha_method'] = 'equal_division_12 (PyJHora method=2)'
return base