Files
astrololo/tests/oracle/README.md
T
gitea aec3f84331
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m29s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m28s
Testy / Testy warstwy bazodanowej (ochrona baz) (pull_request) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 18s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 9s
build-render / build (push) Successful in 5m34s
build / build (push) Successful in 39s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m46s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m31s
Testy / Testy warstwy bazodanowej (ochrona baz) (push) Successful in 9m27s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 19s
Testy / Kontrola składni wszystkich warstw (push) Successful in 11s
feat(domy): topocentric zgodny co do zera — wybór gałęzi liczony, nie zgadywany
Topocentric był wycofany z powodu rozjazdu przy |φ| ≈ 89,9°. Ta diagnoza była
BŁĘDNA: opierała się wyłącznie na zestawie brzegowym, który próbkuje tylko wybrane
szerokości. Przemiał losowy pokazał prawdziwą skalę — błędy od ~70° w górę,
do 50% przypadków blisko biegunów, 6,5% całości. Nie dwa przypadki brzegowe.

Przyczyną nie była jednak konstrukcja, tylko wybór gałęzi: dwa koła wielkie
przecinają się w dwóch punktach antypodycznych. Kolejno zawiodły reguły „po której
stronie MC", „w łuku kwadrantu", „wschodnia połowa horyzontu" i śledzenie ciągłości
krokami (to ostatnie maskuje własną patologię — po korekcie do bliższej gałęzi
zmierzony skok ZAWSZE wychodzi ≤ 90°, więc detektor nigdy się nie zapala).

Wszystkie te reguły rozstrzygają lokalnie, a przy dużych szerokościach kolejność
domów potrafi się odwrócić: przy φ = −79,55° MC wypada na 306,8°, a dom 11 na
291,4°. To jest poprawne — wyrocznia zwraca to samo.

Rozwiązanie: nie wybierać w ogóle. Iloczyn wektorowy zenitu z biegunem ekliptyki
jest ciągłą funkcją parametru rodziny i sam niesie właściwy zwrot; dwuznaczność
wprowadza dopiero atan2. Zostajemy w wektorach, znak ustalamy raz — kotwicząc
rodzinę na MC górującym.

Wynik: 0,000000000° na 240 000 porównań, cała dziedzina, bez iteracji i bez
zawężania szerokości. Żadna granica dziedziny nie jest tu potrzebna, więc żadnej
nie udajemy — test pilnuje, że topocentric liczy się wszędzie i nie fallbackuje.

Morał do frameworka: zestaw brzegowy mówi, CZY system się psuje; dopiero przemiał
losowy mówi JAK BARDZO. Wniosek o skali wyciągnięty z samych brzegów był tu
zaniżony o trzy rzędy wielkości. Odnotowane w tests/oracle/README.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 22:24:40 +02:00

135 lines
6.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Porównanie domów z wyrocznią (Swiss Ephemeris)
Framework testowy do systemów domów. Liczenie cuspów traktujemy jako **funkcję**
parametrów `(RAMC, ε, φ)`, a **Swiss Ephemeris jako wyrocznię** — czyli niezależną
implementację, wobec której sprawdzamy naszą.
Powstał pod implementację systemów egzotycznych (Placidus, Koch, Regiomontanus,
Campanus…), gdzie błąd jest **cichy**: wykres wygląda poprawnie, tylko planety
siedzą w złych domach. Pojedyncze cuspy przepisane z internetu tego nie wyłapią —
tysiące porównań na całej dziedzinie tak.
## Dlaczego akurat tak
**Izolacja jednostki.** Obu implementacjom podajemy TE SAME wejścia przez
`swe_houses_armc`. Gdybyśmy porównywali „nasz horoskop" z „horoskopem swissepha",
różnica mogłaby wynikać z innego czasu gwiazdowego albo innego ε — czyli z czegoś,
co nie jest testowaną funkcją, i utonęlibyśmy w fałszywych alarmach. Czas gwiazdowy
i ε mają własny, osobny test (`asc/mc`).
**Kryterium, nie procent.** Raportujemy liczbę przypadków **powyżej tolerancji
(1″)**, **maksymalne odchylenie** i **miejsce** jego wystąpienia oraz histogram.
Sam procent zgodności ukrywa kształt błędu: „97%" nie odróżnia szumu
zmiennoprzecinkowego od jednego rogu dziedziny, w którym mylimy się o 30°.
**Granice liczone per data.** Koło podbiegunowe — granica dziedziny Placidusa
i Kocha — **nie jest stałą 66,56°**. Zależy od ε, które zmienia się z datą (23,75°
w 370 p.n.e., 23,44° dziś), więc w zakresie programu przesuwa się o ~0,3°.
**Zgodność co do dziedziny.** Gdy wyrocznia odmawia liczenia (poza dziedziną),
a my uważamy, że liczymy — to też jest błąd, zgłaszany osobno. Wyrocznia mówi nam
zatem nie tylko *jakie są wartości*, ale i *gdzie kończy się dziedzina*.
## Uruchomienie
```bash
LOGIC_PATH=../../services/logic python run.py --mode build
```
| Tryb | Co robi | Gdzie działa |
|---|---|---|
| `--mode build` | zestaw **brzegowy** + tyle samo przypadków z wnętrza | CI, **blokuje** build |
| `--mode sweep --count N --seed S` | wielki **losowy** przemiał | Job w klastrze, nie blokuje |
Kod wyjścia: `0` = zgodność w granicach tolerancji, `1` = przekroczenia albo
niezgodność dziedziny. Ziarno jest zawsze raportowane — każdy błąd da się
**odtworzyć** komendą wypisaną w raporcie.
## Co ten framework już znalazł
Uruchomiony na kodzie, który uchodził za poprawny (whole sign / equal / porphyry),
wykrył **dwa realne błędy** w pierwszym przebiegu:
1. **Ascendent o 180° za kołem podbiegunowym.** `atan2` wybierał niewłaściwy punkt
przecięcia ekliptyki z horyzontem — zwracaliśmy Descendent. Planety lądowały
w przeciwnych domach dla całej północnej Skandynawii (Tromsø, Rovaniemi,
Murmańsk). Dotyczyło ~11% przypadków na tych szerokościach.
2. **Niedeterminizm whole sign na granicy znaku.** Ascendent o włos od granicy
(359,999999999976 vs 1e-10 — ta sama wartość, różne strony) przerzucał dom I
o 30°. Ten sam horoskop na innej maszynie mógł dać inny wynik.
Oba mają teraz testy regresji w `services/logic/tests/test_houses.py`, więc są
łapane także bez swissepha.
## Stan systemów domów
Etap 1 — systemy o **zamkniętym wzorze** (bez iteracji). Każdy poniższy przeszedł
zarówno zestaw brzegowy (2520 porównań), jak i losowy przemiał 20 000 przypadków
(240 000 porównań na system):
| System | Konstrukcja | Maks. odchylenie |
|---|---|---|
| whole sign | podział ekliptyki | 0,000000000° |
| equal | podział ekliptyki | 0,000000000° |
| porphyry | podział kwadrantów po ekliptyce | 0,000000000° |
| vehlow | equal z Ascendentem w środku domu I | 0,000000000° |
| morinus | równik rzutowany wprost na ekliptykę | 0,000000000° |
| regiomontanus | podział równika, koła przez punkty N/S horyzontu | 0,000000000° |
| campanus | podział wertykału pierwszego | 0,000000000° |
| alcabitus | podział łuków dobowych po równiku | 0,000000000° |
| topocentric | ascendenty pod biegunami tan(P) = tan(φ)·k/3 | 0,000000000° |
Etap 2 — systemy **łuku dobowego**, jedyne z realną granicą dziedziny:
| System | Konstrukcja | Maks. odchylenie |
|---|---|---|
| placidus | trójdzielenie półłuków, iteracyjnie | 0,000001686° |
| koch | trójdzielenie CZASU od wschodu stopnia MC | 0,000000000° |
Placidus jest jedynym systemem bez wzoru zamkniętego: cusp jest zdefiniowany
warunkiem na samego siebie, więc szukamy go iteracyjnie do 1e-11°. Pozostałe
1,7e-6° to **próg zbieżności wyroczni**, nie nasz błąd — nasz cusp spełnia
definicję Placidusa z dokładnością 1e-12° (test `test_placidus_cusps_satisfy_
their_own_definition` sprawdza to bez swissepha).
Powyżej koła podbiegunowego oba **odmawiają liczenia** — i wyrocznia odmawia
dokładnie tych samych przypadków (5245 na 20 000 losowych, zero rozjazdów).
Warstwa aplikacyjna łapie tę odmowę i podstawia Porphyry'ego z **głośnym
komunikatem**, który idzie na ekran, w prompt do modelu i do PDF-a: po podmianie
kosmogram wygląda bezbłędnie, więc jest to jedyny sygnał dla astrologa.
### Topocentric — i czego nauczył
Topocentric był początkowo **wycofany** z powodu rozjazdu przy |φ| ≈ 89,9°.
Ta diagnoza była **błędna**, bo opierała się wyłącznie na zestawie brzegowym,
który próbkuje tylko wybrane szerokości. Przemiał losowy pokazał prawdziwą skalę:
błędy zaczynały się już od ~70° i sięgały 50% przypadków blisko biegunów —
**6,5% całości**, nie dwa przypadki brzegowe.
Przyczyną nie była jednak konstrukcja, tylko wybór gałęzi. Dwa koła wielkie
przecinają się w dwóch punktach antypodycznych i trzeba wskazać właściwy.
Kolejno zawiodły: „po której stronie MC", „w łuku kwadrantu", „wschodnia połowa
horyzontu" oraz śledzenie ciągłości krokami. Każda z nich rozstrzyga **lokalnie**,
a przy dużych szerokościach kolejność domów potrafi się odwrócić — przy φ = 79,55°
MC wypada na 306,8°, a dom 11 na 291,4°, czyli domy biegną wstecz. To jest poprawne
i wyrocznia zwraca dokładnie to samo.
Rozwiązaniem było **nie wybierać w ogóle**. Iloczyn wektorowy zenitu z biegunem
ekliptyki jest ciągłą funkcją parametru rodziny i sam niesie właściwy zwrot;
dwuznaczność wprowadza dopiero `atan2`. Zostając w wektorach i kotwicząc rodzinę
raz — na MC górującym — dostajemy zgodność **co do zera na całej dziedzinie**,
bez iteracji i bez zawężania szerokości.
Morał praktyczny: zestaw brzegowy mówi, **czy** system się psuje; dopiero przemiał
losowy mówi **jak bardzo**. Wniosek o skali wyciągnięty z samych brzegów był tu
zaniżony o trzy rzędy wielkości.
Większe jądro efemeryd (de441) — **odłożone, „nice to have"**: rozszerza tylko
zakres dat, nie poprawia niczego w obecnym.
## Licencja
Swiss Ephemeris jest na AGPL i jest tu **wyłącznie wyrocznią testową** — nie wchodzi
do ścieżki produkcyjnej ani do zależności produktu. Izolacja z LOG-27 zostaje
nienaruszona.