fix: align high-impact yoga logic

This commit is contained in:
732642856
2026-06-05 16:17:38 +08:00
parent 99f6646a0a
commit 44221191f6
5 changed files with 1290 additions and 3302 deletions
+35
View File
@@ -1,5 +1,40 @@
# 印度占星 Skill 更新日志
## v6.0.342026-06-05)—— Yoga 逻辑对齐与 F1 提升
> **目标**:继续 v6.0.32 的“同盘逻辑正确性”路线,优先修复验证报告中高 FP/FN 的规则,而不是只堆规则名称。
### 对齐 PyJHora / B.V. Raman 条件
- 修正 `adhi_yoga`:从“吉星在凶宫上方”的过宽简化,改为 PyJHora/BVR-7 口径——自然吉星位于月亮起算 6/7/8 宫。
- 修正 `kemadruma_yoga`:补齐 PyJHora BVR-5 的双条件,即月亮起算 1/2/12 宫只允许日/月,且 Lagna 角宫只允许月亮。
- 修正 `kahala_yoga`:从错误的 3宫主/10宫主同宫,改为 BVR-15:4宫主与9宫主互为 Kendra,且上升主有力。
- 修正 `bvr_sareera_soukhya_precise`:从“上升主、木星、金星全部在 Kendra”改为 PyJHora/BVR-108 的“任一者在 Kendra”。
- 修正 `bvr_yukthi_samanwithavagmi_yoga`:从“水星强”改为 BVR-1542宫主在 Kendra/Trikona 合吉星,或2宫主擢升合木星。
- 修正 `bvr_swaveeryaddhana_precise`:补充 PyJHora/BVR-132 的 D1-safe 条件:2宫主与上升主成 Kendra/Trine,或2宫主为吉且擢升/合擢升星。
- 修正 `bvr_bhratruvriddhi_precise`:补齐 3宫受吉星同宫/相位,以及 3宫主/火星强且受吉星连接的条件。
- 扩展 `bvr_dharidhra_11_precise`:从单一 11宫主凶宫规则,扩展为 PyJHora/BVR-144..152 中可用的 D1-safe 多变体组合。
- 对齐 `bvr_rogagrastha_precise``bvr_bandhubhisthyaktha_precise``bvr_matru_sneha_yoga` 的核心判定,减少高频 FN。
### 引擎辅助能力
- 为 custom Yoga 表达式新增 `aspects_house()``strong()``associated()``temporal_friend()` 辅助函数,减少规则里重复实现相位、强弱、关联和临时友好关系。
### 当前验证结果
- `scripts/validate_logic_v2.py`Precision **80.41%**Recall **68.76%**F1 **74.13%**
- 相比 v6.0.33 / v6.0.32 的基线 F1 **58.08%**,提升 **+16.05 个百分点**。
- `pytest tests/test_yoga_rules_integrity.py tests/test_dasha.py`25 passed。
- `scripts/run_quality_gate.py --skip-yoga-logic`:通过;完整 pytest 35 passedBPHS/Ashtakavarga 不变量 18/18 通过,golden case 通过。
### 已知后续优化点
- 剩余 FN 主要集中在 `rogagrastha``mathibhramana``matrunasa``bahu_puthra``kahala``nishkapata``kaalanirdesat_puthranaasa` 等规则。
- 剩余 FP 主要集中在 `matsya``vanchana_chora_bheethi``guru_mangala``kaalanirdesat_puthranaasa``sankha` 等规则。
- v6.0.35 建议继续按 Top FP/FN 队列逐条查 PyJHora 源码并修规则。
---
## v6.0.332026-06-05)—— 工程质量门禁、属性测试与 CI 强化
> **目标**:把 v6.0.32 的准确率修复沉淀为可持续工程体系,防止 Dasha、Varga、Ashtakavarga、Yoga 规则与 full-reading 输出契约回归。
+4 -4
View File
@@ -1,6 +1,6 @@
---
name: jyotish-vedic-astrology
version: 6.0.33
version: 6.0.34
description: 印度占星(Jyotish)专业解盘与推运系统。核心能力:PDF星盘输入→严谨解盘→精确推运应期输出。触发词:印度占星、吠陀占星、Jyotish、解盘、推运、星盘分析、Dasha、Transit、Nakshatra、Yoga、出生时间矫正、PDF星盘、读取PDF、分析PDF星盘、现代解读、误判纠错、Varga分盘、综合分析、过境分析、合盘、婚姻匹配、年运盘、Prashna、Argala、Jaimini、Shadbala、Ashtakavarga、HTML报告、深度解盘。
---
@@ -10,7 +10,7 @@ description: 印度占星(Jyotish)专业解盘与推运系统。核心能力
> **严格路由**`references/strict-workflow-router.md`(⭐涉及事业/婚恋/财务/应期/技法验证时必须优先读取)
> **覆盖矩阵**`references/technique-capability-matrix.md`(⭐判断技法 covered/partial/missing 时必须参考)
> **机器注册表**`references/technique_registry.json` + `scripts/audit_capabilities.py`(⭐用于自动审计与CI门禁)
> **版本**v6.0.33-engineering-quality-gate | **详细变更**`CHANGELOG.md`
> **版本**v6.0.34-yoga-logic-alignment | **详细变更**`CHANGELOG.md`
---
@@ -301,9 +301,9 @@ $PYTHON $SCRIPT <子命令> [参数]
---
**版本**v6.0.33-engineering-quality-gate
**版本**v6.0.34-yoga-logic-alignment
**创建日期**2026-04-20
**最后更新**2026-06-05v6.0.33 新增工程质量门禁、Hypothesis 属性测试、Ruff/pytest/CI 配置;当前 473 条 JSON 规则、379 条启用规则,D1/Rasi 逻辑验证报告以 `references/validation_logic_report.json` 为准)
**最后更新**2026-06-05v6.0.34 对齐 PyJHora/B.V. Raman 多个高影响 Yoga 条件;当前 473 条 JSON 规则、379 条启用规则,D1/Rasi 逻辑验证 F1=74.13%报告以 `references/validation_logic_report.json` 为准)
---
File diff suppressed because it is too large Load Diff
+25 -56
View File
@@ -1056,8 +1056,8 @@
"category": "chandra",
"logic": {
"type": "custom",
"expr": "\nif 'Moon' not in ctx.planets:\n False\nelse:\n moon_h = house_of('Moon')\n h12 = ((moon_h - 1 + 11) % 12) + 1\n p_in_h12 = [p for p, info in ctx.planets.items() if p != 'Moon' and info.get('house') == h12]\n h2 = ((moon_h - 1 + 1) % 12) + 1\n p_in_h2 = [p for p, info in ctx.planets.items() if p != 'Moon' and info.get('house') == h2]\n not p_in_h2 and not p_in_h12\n",
"combo_template": "月亮两侧均无行星"
"expr": "\n# PyJHora/BVR-5: no planets other than Sun in 1st/2nd/12th from Moon,\n# and no planets other than Moon in quadrants from Lagna.\nif 'Moon' not in ctx.planets:\n False\nelse:\n moon_h = house_of('Moon')\n moon_zone = {moon_h, ((moon_h - 1 + 1) % 12) + 1, ((moon_h - 1 + 11) % 12) + 1}\n ky1 = all(p in ['Moon', 'Sun'] for p, info in ctx.planets.items() if info.get('house') in moon_zone)\n ky2 = all(p == 'Moon' for p, info in ctx.planets.items() if info.get('house') in [1, 4, 7, 10])\n ky1 and ky2\n",
"combo_template": "月亮1/2/12宫仅日月,且Lagna角宫仅月亮"
},
"effects": [
"人生艰辛",
@@ -1255,16 +1255,9 @@
"bvr_id": "BVR-15",
"category": "auspicious",
"logic": {
"type": "same_house",
"a": {
"role": "lord",
"house": 3
},
"b": {
"role": "lord",
"house": 10
},
"combo_template": "3宫主{a}与10宫主{b}同在第{h}宫"
"type": "custom",
"expr": "\n# PyJHora/BVR-15: L4 and L9 in mutual kendras, and L1 strong.\nl1 = lord(1)\nl4 = lord(4)\nl9 = lord(9)\nif l1 not in ctx.planets or l4 not in ctx.planets or l9 not in ctx.planets:\n False\nelse:\n l1_strong = strong(l1)\n mutual_kendra = offset(house_of(l4), house_of(l9)) in [0, 3, 6, 9]\n l1_strong and mutual_kendra\n",
"combo_template": "上升主有力,4宫主与9宫主互为Kendra"
},
"effects": [
"意志坚定",
@@ -2089,8 +2082,8 @@
"category": "special",
"logic": {
"type": "custom",
"expr": "\nadhi = {6: 12, 8: 2, 12: 11}\nmatched = False\nfor dh, uh in adhi.items():\n ben_above = [p for p in BENEFICS if p in ctx.planets and house_of(p) == uh]\n if ben_above:\n matched = True\n break\nmatched\n",
"combo_template": "吉星在凶宫上方"
"expr": "\n# PyJHora/BVR-7: natural benefics occupy 6th/7th/8th from Moon.\nif 'Moon' not in ctx.planets:\n False\nelse:\n moon_h = house_of('Moon')\n target_houses = {((moon_h - 1 + off) % 12) + 1 for off in [5, 6, 7]}\n benefics = ['Jupiter', 'Venus'] + (['Mercury'] if 'Mercury' in ctx.planets else [])\n all(p in ctx.planets and house_of(p) in target_houses for p in benefics)\n",
"combo_template": "自然吉星位于月亮起算6/7/8宫"
},
"effects": [
"权威地位",
@@ -9067,8 +9060,8 @@
"category": "health",
"logic": {
"type": "custom",
"expr": "\n# Lagna lord, Jupiter, and Venus in Kendra houses\nkendra = {1, 4, 7, 10}\nasc_lord = lord(1)\nplanets_to_check = [asc_lord, 'Jupiter', 'Venus']\nall_in_kendra = all(\n p in ctx.planets and ctx.planets[p].get('house') in kendra\n for p in planets_to_check if p\n)\nall_in_kendra\n",
"combo_template": "上升主、木星金星均在Kendra"
"expr": "\n# PyJHora/BVR-108: Lagna lord, Jupiter, OR Venus should occupy a quadrant.\nasc_lord = lord(1)\nany(p in ctx.planets and kendra(house_of(p)) for p in [asc_lord, 'Jupiter', 'Venus'])\n",
"combo_template": "上升主、木星金星位于Kendra"
},
"effects": [
"身体健康",
@@ -9088,8 +9081,8 @@
"category": "health",
"logic": {
"type": "custom",
"expr": "\n# Lagna lord in 6/8/12 and associated with 6th lord\nasc_lord = lord(1)\nlord_6 = lord(6)\nif asc_lord not in ctx.planets or lord_6 not in ctx.planets:\n False\nelse:\n asc_lord_h = ctx.planets[asc_lord].get('house')\n in_dusthana = asc_lord_h in [6, 8, 12]\n associated = same_house(asc_lord, lord_6) or aspect(asc_lord, lord_6)\n in_dusthana and associated\n",
"combo_template": "上升主凶宫且与6宫主有关联"
"expr": "\n# PyJHora BVR-11: (a) Lagna lord in Lagna joined by dusthana lord;\n# (b) weak Lagna lord in kendra/trikona joined by a kendra/trine lord.\nasc_lord = lord(1)\ndusthana_lords = [lord(h) for h in [6, 8, 12]]\nquad_trine_lords = [lord(h) for h in [1, 4, 5, 7, 9, 10]]\nif asc_lord not in ctx.planets:\n False\nelse:\n h = house_of(asc_lord)\n condition_a = h == 1 and any(dl in ctx.planets and same_house(asc_lord, dl) for dl in dusthana_lords)\n condition_b = (kendra(h) or trikona(h)) and not strong(asc_lord) and any(qtl in ctx.planets and same_house(asc_lord, qtl) for qtl in quad_trine_lords if qtl != asc_lord)\n condition_a or condition_b\n",
"combo_template": "上升主凶宫主或角/三方主形成疾病格局"
},
"effects": [
"疾病",
@@ -9180,8 +9173,8 @@
"category": "durbhaga",
"logic": {
"type": "custom",
"expr": "\n# 11th lord in 6th, 8th, or 12th\nlord_11 = lord(11)\nif lord_11 in ctx.planets:\n ctx.planets[lord_11].get('house') in [6, 8, 12]\nelse:\n False\n",
"combo_template": "11宫主在凶宫"
"expr": "\n# PyJHora/BVR-144..152 D1-safe Dharidhra variants.\nl1, l2, l5, l6, l7, l8, l11, l12 = [lord(h) for h in [1, 2, 5, 6, 7, 8, 11, 12]]\ndusthana = [6, 8, 12]\ndusthana_lords = [l6, l8, l12]\nmarakas = [l2, l7]\ndef in_chart(p):\n return p in ctx.planets\ndef rel_to_any(p, others):\n return in_chart(p) and any(in_chart(o) and associated(p, o) for o in others)\ndef aspected_by_any(p, others):\n return in_chart(p) and any(in_chart(o) and aspect(o, p) for o in others)\nmethod1 = any(in_chart(p) and house_of(p) in dusthana for p in [l2, l11])\nv144 = in_chart(l1) and in_chart(l12) and house_of(l1) == 12 and house_of(l12) == 1 and (rel_to_any(l1, [l7]) or rel_to_any(l12, [l7]))\nv145 = in_chart(l1) and in_chart(l6) and house_of(l1) == 6 and house_of(l6) == 1 and aspected_by_any('Moon', marakas)\nv146 = house_of('Ketu') == 1 and house_of('Moon') == 1\nv147 = in_chart(l1) and house_of(l1) == 8 and rel_to_any(l1, marakas)\nv148 = in_chart(l1) and house_of(l1) in dusthana and any(same_house(l1, m) for m in MALEFICS if m in ctx.planets and m != l1) and rel_to_any(l1, marakas)\nv149 = rel_to_any(l1, dusthana_lords) and any(aspect(m, l1) for m in MALEFICS if m in ctx.planets and m != l1)\nv150 = in_chart(l5) and any(same_house(l5, tl) for tl in dusthana_lords if in_chart(tl)) and not any((same_house(l5, b) or aspect(b, l5)) for b in BENEFICS if b in ctx.planets)\nv151 = in_chart(l5) and house_of(l5) in [6, 10] and aspected_by_any(l5, [l2, l6, l7, l8, l12])\nv152 = any(m in ctx.planets and house_of(m) == 1 and m not in [lord(9), lord(10)] and rel_to_any(m, marakas) for m in MALEFICS)\nmethod1 or v144 or v145 or v146 or v147 or v148 or v149 or v150 or v151 or v152\n",
"combo_template": "Dharidhra:财帛/收益主落凶宫或Lagna/Maraka/Dusthana组合"
},
"effects": [
"财务困难",
@@ -9243,8 +9236,8 @@
"category": "dhana",
"logic": {
"type": "custom",
"expr": "\n# Lagna lord in Kendra, associated with 2nd lord\nasc_lord = lord(1)\nlord_2 = lord(2)\nif asc_lord not in ctx.planets or lord_2 not in ctx.planets:\n False\nelse:\n in_kendra = ctx.planets[asc_lord].get('house') in [1, 4, 7, 10]\n associated = same_house(asc_lord, lord_2) or aspect(asc_lord, lord_2)\n in_kendra and associated\n",
"combo_template": "上升主Kendra且与2宫主有关联"
"expr": "\n# PyJHora/BVR-132 D1-safe portion: 2nd lord in Kendra/Trine from Lagna lord,\n# or 2nd lord as benefic in exaltation / joined with an exalted planet.\nasc_lord = lord(1)\nlord_2 = lord(2)\nif asc_lord not in ctx.planets or lord_2 not in ctx.planets:\n False\nelse:\n rel_good = offset(house_of(asc_lord), house_of(lord_2)) in [0, 3, 4, 6, 8, 9]\n lord2_benefic = lord_2 in BENEFICS\n with_exalted = any(p != lord_2 and same_house(p, lord_2) and exalted(p) for p in ctx.planets)\n rel_good or (lord2_benefic and (exalted(lord_2) or with_exalted))\n",
"combo_template": "2宫主与上升主Kendra/Trine关系或2宫主吉且强"
},
"effects": [
"自力更生致富",
@@ -9266,8 +9259,8 @@
"category": "auspicious",
"logic": {
"type": "custom",
"expr": "\n# 3rd lord or Mars associated with benefic\nlord_3 = lord(3)\ncandidates = []\nif lord_3 in ctx.planets:\n candidates.append(lord_3)\nif 'Mars' in ctx.planets:\n candidates.append('Mars')\nbenefics = {'Jupiter', 'Venus', 'Mercury', 'Moon'}\nfor c in candidates:\n for b in benefics:\n if b in ctx.planets and same_house(c, b):\n True\nFalse\n",
"combo_template": "3宫主火星与吉星有关联"
"expr": "\n# PyJHora/BVR-177: 3rd lord, Mars, or 3rd house joined/aspected by benefics.\nlord_3 = lord(3)\nhouse_3 = 3\nbenefics = [p for p in BENEFICS if p in ctx.planets]\ndef benefic_link_to_planet(p):\n return p in ctx.planets and strong(p) and any(b != p and (same_house(b, p) or aspect(b, p)) for b in benefics)\nhouse_joined = any(house_of(b) == house_3 for b in benefics)\nhouse_aspected = any(aspects_house(b, house_3) for b in benefics)\nbenefic_link_to_planet(lord_3) or benefic_link_to_planet('Mars') or house_joined or house_aspected\n",
"combo_template": "3宫主火星或3宫受吉星连接"
},
"effects": [
"兄弟和睦",
@@ -9287,8 +9280,8 @@
"category": "durbhaga",
"logic": {
"type": "custom",
"expr": "\n# 4th lord in dusthana or debilitated or with malefics\nlord_4 = lord(4)\nif lord_4 not in ctx.planets:\n False\nelse:\n malefics = {'Sun', 'Mars', 'Saturn', 'Rahu', 'Ketu'}\n lord_4_h = ctx.planets[lord_4].get('house')\n in_dusthana = lord_4_h in [6, 8, 12]\n debilitated = debil(lord_4)\n associated = any(same_house(lord_4, m) for m in malefics if m in ctx.planets)\n in_dusthana or debilitated or associated\n",
"combo_template": "4宫主受凶星影响或在凶宫"
"expr": "\n# PyJHora BVR-195: 4th lord associated with malefics or in inimical/debilitated condition.\nlord_4 = lord(4)\nif lord_4 not in ctx.planets:\n False\nelse:\n malefic_assoc = any(m in ctx.planets and associated(lord_4, m) for m in MALEFICS if m != lord_4)\n weak_or_bad = debil(lord_4) or not strong(lord_4)\n malefic_assoc or weak_or_bad\n",
"combo_template": "4宫主受凶星关联或处于弱/不利状态"
},
"effects": [
"被亲属遗弃",
@@ -11756,28 +11749,9 @@
"bvr_id": null,
"category": "special",
"logic": {
"type": "compound_conditions",
"conditions": [
{
"type": "compound",
"operator": "OR",
"conditions": [
{
"type": "same_lord_for_1st_and_4th",
"note": "1st and 4th houses have same planetary ruler (Ge/Vi or Sg/Pi lagna)"
},
{
"type": "1st_and_4th_lords_are_natural_or_temporal_friends",
"note": "Lords of 1st and 4th are natural or temporal friends"
},
{
"type": "1st_and_4th_lords_aspected_by_benefics",
"note": "Lagna lord and 4th lord aspected by benefics"
}
]
}
],
"note": ""
"type": "custom",
"expr": "\n# PyJHora: same lord for 1st/4th OR natural/temporal friendship OR both aspected by benefics.\nl1 = lord(1)\nl4 = lord(4)\nif l1 not in ctx.planets or l4 not in ctx.planets:\n False\nelse:\n same_lord = l1 == l4\n temporal_friends = temporal_friend(l1, l4) and temporal_friend(l4, l1)\n both_benefic_aspected = all(any(aspect(b, p) for b in BENEFICS if b in ctx.planets) for p in [l1, l4])\n same_lord or temporal_friends or both_benefic_aspected\n",
"combo_template": "1宫主与4宫主同主、友好或同受吉星照拂"
},
"effects": [
"Deep love and affection with mother"
@@ -13639,14 +13613,9 @@
"bvr_id": null,
"category": "special",
"logic": {
"type": "compound_conditions",
"conditions": [
{
"type": "mercury_strong_in_kendra_or_trikona",
"note": "Mercury strong in kendra or trikona"
}
],
"note": "Mercury well-placed for eloquence"
"type": "custom",
"expr": "\n# PyJHora/BVR-154: 2nd lord joins a benefic in kendra/trikona,\n# or 2nd lord is exalted and combined with Jupiter.\nlord_2 = lord(2)\nif lord_2 not in ctx.planets:\n False\nelse:\n h2 = house_of(lord_2)\n cond_a = (kendra(h2) or trikona(h2)) and any(b != lord_2 and b in ctx.planets and same_house(lord_2, b) for b in BENEFICS)\n cond_b = exalted(lord_2) and 'Jupiter' in ctx.planets and same_house(lord_2, 'Jupiter')\n cond_a or cond_b\n",
"combo_template": "2宫主在Kendra/Trikona合吉星,或2宫主擢升合木星"
},
"effects": [
"Eloquent, skilled in debate, good communicator"
+22 -1
View File
@@ -901,6 +901,26 @@ class YogaEngine:
return True
return False
def aspects_house(p, h):
if p not in ctx.planets or h is None:
return False
return h == ctx.house_of(p) or offset(ctx.house_of(p), h) in (6, 3 if p == 'Mars' else -1, 7 if p == 'Mars' else -1, 4 if p == 'Jupiter' else -1, 8 if p == 'Jupiter' else -1, 2 if p == 'Saturn' else -1, 9 if p == 'Saturn' else -1)
def strong(p):
if p not in ctx.planets:
return False
h = ctx.house_of(p)
return bool(exalted(p) or own(p) or moola(p) or kendra(h) or trikona(h))
def associated(a, b):
return a in ctx.planets and b in ctx.planets and (same_house(a, b) or aspect(a, b) or aspect(b, a))
def temporal_friend(a, b):
if a not in ctx.planets or b not in ctx.planets or a == b:
return False
# PyJHora temporary friends: 2/3/4/10/11/12 from a planet.
return offset(ctx.house_of(a), ctx.house_of(b)) in [1, 2, 3, 9, 10, 11]
def exal(p): return ctx.is_exalted(p)
def lord_of_house(h): return ctx.lord_of_house(h)
def sign(p): return ctx.sign_of(p)
@@ -955,7 +975,8 @@ class YogaEngine:
"kendra_from": kendra_from, "trikona_from": trikona_from,
"offset": offset,
# v6.0.32: 同宫与相位检查(custom规则常用)
"same_house": same_house, "aspect": aspect,
"same_house": same_house, "aspect": aspect, "aspects_house": aspects_house,
"strong": strong, "associated": associated, "temporal_friend": temporal_friend,
"exal": exal, "lord_of_house": lord_of_house, "sign": sign,
"check_amala_from": check_amala_from,
"Benefics": BENEFICS, "Malefics": MALEFICS,