Handle a failed house iteration
A requested house convention does not guarantee that its iteration succeeds. The engine still returns twelve boundaries when Placidus fails: it divides the four angle-to-angle spans into thirds. We will calculate that replacement and follow what the public result tells its caller.
Before this lesson
Read “Iterate the Placidus cusps.” We reuse Asc, MC and their half-turn opposites. All examples are synthetic. A fallback changes the house subdivision; it does not repair or independently validate the preceding chart angles.
What you will learn
Trisect wrapped quadrant spans, assemble the Porphyry list, and explain why a returned cusp array alone does not establish Placidus convergence.
Dotted-underlined terms open a definition beside the text. Select one to read more, then close it to continue.
Each step has its own check. Pass every step to complete the lesson. Your answers and checked steps are saved in this browser, so you can continue after leaving or reloading.
1. Divide each angle-to-angle span into thirds
The Ascendant, lower meridian angle, Descendant and midheaven mark four successive spans around the ecliptic. These are called quadrants here because four angles delimit them; they need not each be 90° wide. Porphyry subdivision puts two additional boundaries inside each span, one third and two thirds of the way along it.
Start with an invented span from 350° to 80°. Ordinary subtraction gives −270°, but the forward span crosses zero and measures 90°. Wrap the subtraction to remove that backward full-turn ambiguity. One third is 30°, so the three returned boundaries are 350°, 20° and 50°. The end at 80° is omitted because it becomes the next quadrant’s starting boundary.
span = wrap(end − start)
trisect(start, end) = [start, wrap(start + span/3), wrap(start + 2 × span/3)]
For the full invented chart, let Asc = 350° and MC = 260°. Then IC = 80° and Desc = 170°. The four source calls are Asc → IC, IC → Desc, Desc → MC and MC → Asc. Every span happens to be 90° in this example, giving [350, 20, 50, 80, 110, 140, 170, 200, 230, 260, 290, 320] degrees. Its agreement with Equal is a feature of these toy angles, not a general identity.
Now keep Asc = 350° but choose MC = 290°. IC becomes 110° and Desc stays 170°. The spans are 120°, 60°, 120° and 60°, so their subdivisions are respectively 40°, 20°, 40° and 20°. Concatenating the four triples produces [350, 30, 70, 110, 130, 150, 170, 210, 250, 290, 310, 330] degrees. This time the boundaries are not uniformly 30° apart.
What the name establishes
Swiss Ephemeris describes the Porphyry convention as division of each ecliptic quadrant into thirds. The source used here does not establish an original inventor or the origin of this repository’s helper. We retain the conventional name without assigning an unsupported biography.
trisect_quadrant returns its supplied start directly; the other two entries are normalized. The normal caller supplies angles from compute_angles and their wrapped opposites. If end equals start, wrap gives a zero span rather than a full 360° span. There is no separate geometry-validity test in this helper, so a twelve-entry result by itself does not certify a nondegenerate chart.
See the teaching TypeScript
const wrap = (x: number): number => { const r = x % 360; return r < 0 ? r + 360 : r; };
const trisectQuadrant = (start: number, end: number): number[] => {
const span = wrap(end - start);
return [start, wrap(start + span / 3), wrap(start + 2 * span / 3)];
};
const porphyryCusps = (asc: number, mc: number): number[] => {
const desc = wrap(asc + 180), ic = wrap(mc + 180);
return [...trisectQuadrant(asc, ic), ...trisectQuadrant(ic, desc),
...trisectQuadrant(desc, mc), ...trisectQuadrant(mc, asc)];
};Finite, correctly labeled inputs are assumed. This demonstrates the arithmetic; it does not fetch data or replace the engine.
Connect this step to the source
src/astro/houses.rs
trisect_quadrant; porphyry_cusps
Paths refer to the astrology-engine repository. Examples use invented inputs; a successful exercise is not an astronomical-accuracy test.
Sources for this section
Apply this step
Answer every part, then check. You can retry as often as you like.
2. Follow a failed iteration through the interface
The Placidus routine attempts all four cusp iterations and then checks their results together. If any one returns None, the routine immediately replaces the entire cusp set with porphyry_cusps(Asc, MC). It does not mix three successful Placidus cusps with one Porphyry cusp, and it does not retry the failed iteration with a looser tolerance.
Failure can happen when the inverse-cosine argument leaves [−1, 1], or when 200 attempts pass without a change smaller than 10⁻¹² degrees. For a concrete synthetic domain failure, take α = 60°, φ = 60° and ε = 45°. Cusp 11 starts at r = 90°, making q = −sin 90° × tan 60° × tan 45° = −√3 ≈ −1.732. Its first attempt returns None before acos. These are deliberately simplified inputs, not a real date or a claim that every high-latitude case fails.
any missing cusp iteration → complete Porphyry array
The internal placidus_cusps_with_fallback helper returns (cusps, true) in that case, and (cusps, false) when all iterations succeed. The public placidus_cusps function takes only the first tuple element. house_set therefore retains system: Placidus and returns Some(cusps), even when those values were made by Porphyry division. calculate_chart copies only the cusps into ChartValues; that public result has neither a fallback flag nor a returned system field.
Imagine three iterations succeeded and the fourth failed, with separately supplied synthetic Asc = 350° and MC = 290°. The replacement is the complete twelve-entry list [350, 30, 70, 110, 130, 150, 170, 210, 250, 290, 310, 330] from the preceding step. The intermediate HouseSet still says Placidus. Merely seeing twelve finite boundaries in the final chart does not tell us which calculation supplied them.
A familiar fallback with a different reporting contract
Swiss Ephemeris also documents a Porphyry fallback for certain house-calculation failures, and reports an error code. That is useful comparison context. This engine’s public chart path discards its internal boolean and supplies no equivalent fallback indicator; we must read its own interface rather than assume the external one.
Connect this step to the source
src/astro/houses.rs
placidus_cusps; house_set
Paths refer to the astrology-engine repository. Examples use invented inputs; a successful exercise is not an astronomical-accuracy test.
Sources for this section
Apply this step
Answer every part, then check. You can retry as often as you like.
Your lesson checks
0 of 2 steps passed.
Use the feedback beside each check to retry any unfinished step.