Exact Symbolic Demonstrations

Runnable SymPy & geometor.model Verification Suites

In strict accordance with GEOMETOR’s separation of archival treatise text and executable code, all symbolic constructions, polynomial verifications, and CLI tables live in src/geometor/fibonacci/ and demos/ rather than inside the historical codex pages.

Run any demonstration directly from the repository root:

uv run --no-sync python3 demos/mensuration_demo.py
        uv run --no-sync python3 demos/divisions_demo.py
        uv run --no-sync python3 demos/polyhedra_golden_demo.py
        

1. Mensuration, Heron’s Incenter Proof & Circle Bounds

demos/mensuration_demo.py exercises geometor.fibonacci.mensuration across Distinctio I and Distinctio III:

  • Exact rational conversion across the Pisan pertica, pes, uncia, denarius, panorum, and stariorum ($66$ square perticae).

  • Symbolic verification over $\mathbb{Z}[x, y, z]$ and geometric Model construction of Fibonacci’s incenter proof of Heron’s formula on $(13, 14, 15)$ ($T = (6, 4)$, $r = 4$, $s = 21$, $\Delta = 84$).

  • Exact rational comparison of Fibonacci’s 96-gon bounds $\frac{6480}{2063} < \pi < \frac{7200}{2291}$ and $\pi_{\text{Fib}} = \frac{864}{275}$ against Archimedes’ $\frac{223}{71}$ and $\frac{22}{7}$.

  1"""Runnable demonstration of *Practica Geometriae* Distinctio I & III: Pisan Metrology, Heron's Proof & Circle Bounds."""
          2
          3from __future__ import annotations
          4
          5import sys
          6from pathlib import Path
          7
          8ROOT = Path(__file__).resolve().parents[1]
          9SRC = ROOT / "src"
         10if str(SRC) not in sys.path:
         11    sys.path.insert(0, str(SRC))
         12
         13import sympy as sp  # noqa: E402
         14from rich.console import Console  # noqa: E402
         15from rich.table import Table  # noqa: E402
         16
         17from geometor.fibonacci import (  # noqa: E402
         18    PisanLinearMeasure,
         19    construct_heron_incenter_proof,
         20    decompose_pisan_area,
         21    fibonacci_circle_bounds,
         22    heron_area_exact,
         23    multiply_pisan_lengths,
         24    verify_heron_polynomial_identity,
         25)
         26
         27
         28def main() -> None:
         29    console = Console()
         30
         31    # 1. Pisan Surveyor's Metrology (Introductoria & Distinctio I, Boncompagni pp. 3–5)
         32    t_metro = Table(title="Distinctio I — Pisan Surveyor's Metrology (1 Stariorum = 66 Perticae)")
         33    t_metro.add_column("Width", style="cyan")
         34    t_metro.add_column("Length", style="cyan")
         35    t_metro.add_column("Superficial Perticae", style="green")
         36    t_metro.add_column("Stariora / Panora / Perticae / Pedes / Unciae", style="gold1")
         37
         38    examples = [
         39        # Boncompagni p. 5: width = 7 perticae, length = 9 perticae, 2 pedes, 10 2/7 unciae -> 66 perticae = 1 stariorum
         40        (
         41            PisanLinearMeasure(perticae=7),
         42            PisanLinearMeasure(perticae=9, pedes=2, unciae=sp.Rational(72, 7)),
         43        ),
         44        (
         45            PisanLinearMeasure(perticae=12, pedes=3),
         46            PisanLinearMeasure(perticae=8, pedes=4, unciae=9),
         47        ),
         48        (
         49            PisanLinearMeasure(perticae=36),
         50            PisanLinearMeasure(perticae=44),
         51        ),
         52    ]
         53    for w, ln in examples:
         54        res = multiply_pisan_lengths(w, ln)
         55        t_metro.add_row(
         56            f"{w.perticae}p {w.pedes}ft {w.unciae}in",
         57            f"{ln.perticae}p {ln.pedes}ft {ln.unciae}in",
         58            str(res.total_perticae),
         59            f"{res.modiora} mod, {res.stariora} star, {res.panora} pan, "
         60            f"{res.perticae} pert, {res.pedes_superficiales} ped, {res.unciae_superficiales} unc",
         61        )
         62    console.print(t_metro)
         63    _ = decompose_pisan_area(66)
         64
         65    # 2. Heron's Formula & Incenter Proof (Distinctio III, Boncompagni pp. 40–41)
         66    poly_res = verify_heron_polynomial_identity()
         67    heron_proof = construct_heron_incenter_proof()
         68    s22, exc22, sq22, area22 = heron_area_exact(13, 11, 20)
         69
         70    t_heron = Table(title="Distinctio III — Heron's Formula & Geometric Incenter Proof")
         71    t_heron.add_column("Triangle / Check", style="cyan")
         72    t_heron.add_column("Semiperimeter s", style="white")
         73    t_heron.add_column("Excesses (s-a, s-b, s-c)", style="white")
         74    t_heron.add_column("Exact Area", style="green")
         75    t_heron.add_row(
         76        "Boncompagni p. 40 Numerical (13, 11, 20)",
         77        str(s22),
         78        str(exc22),
         79        f"sqrt({sq22}) = {area22}",
         80    )
         81    t_heron.add_row(
         82        "Geometric Incenter Model (13, 14, 15)",
         83        str(heron_proof.semiperimeter),
         84        str(heron_proof.excesses),
         85        f"r * s = {heron_proof.inradius} * {heron_proof.semiperimeter} = {heron_proof.area}",
         86    )
         87    t_heron.add_row(
         88        "Polynomial Identity Z[x,y,z] Residual",
         89        "-",
         90        "a=y+z, b=z+x, c=x+y",
         91        f"residual = {poly_res}",
         92    )
         93    console.print(t_heron)
         94
         95    # 3. Fibonacci's 96-gon Circle Measurement (Distinctio III, Boncompagni pp. 88–91)
         96    cb = fibonacci_circle_bounds()
         97    t_pi = Table(title="Distinctio III — Fibonacci's 96-gon Circle Bounds vs. Archimedes")
         98    t_pi.add_column("Quantity", style="cyan")
         99    t_pi.add_column("Exact Rational", style="green")
        100    t_pi.add_column("Decimal (10 d.p.)", style="gold1")
        101    t_pi.add_row("Archimedes Lower (3 + 10/71)", str(cb.archimedes_lower), f"{float(cb.archimedes_lower):.10f}")
        102    t_pi.add_row("Fibonacci 96-gon Inscribed (1440 / 458 4/9)", str(cb.fibonacci_lower), f"{float(cb.fibonacci_lower):.10f}")
        103    t_pi.add_row("True pi", "pi", f"{float(sp.pi.evalf()):.10f}")
        104    t_pi.add_row("Fibonacci Mean Ratio (1440 / 458 1/3)", str(cb.fibonacci_pi), f"{float(cb.fibonacci_pi):.10f}")
        105    t_pi.add_row("Fibonacci 96-gon Circumscribed (1440 / 458 1/5)", str(cb.fibonacci_upper), f"{float(cb.fibonacci_upper):.10f}")
        106    t_pi.add_row("Archimedes Upper (864 / (275 - 1/11))", str(cb.archimedes_upper), f"{float(cb.archimedes_upper):.10f}")
        107    console.print(t_pi)
        108
        109
        110if __name__ == "__main__":
        111    main()
        

2. Division of Planar Fields (De divisione camporum)

demos/divisions_demo.py exercises geometor.fibonacci.divisions on Distinctio IV (preserving Euclid’s On Divisions of Figures):

  • Straightedge-and-compass division of $\triangle ABG$ from an arbitrary point $D$ on side $[BG]$ in ratio $p : q$ via parallel transfer $[EZ] \parallel [AD]$ ($GZ = \frac{35}{3} = 11\frac{2}{3}$ when $BD = 5$, $p = q = 1$).

  • Semicircle mean-proportional construction ($AE^2 = \frac{p}{p+q} AB^2$) cutting $\triangle ABG$ parallel to base $[BG]$, reproducing Boncompagni p. 119 ($AE^2 = 50$, $AZ^2 = 72$, $EZ^2 = 98$ on sides $10, 14, 12$).

  • Concurrency of medians at centroid $D = X(2)$ in $2 : 1$ ratio, partitioning $\triangle ABG$ into three equal consort shares, plus root-mean-square trapezoid bisection on $(7, 17)$ yielding chord $13$ ($7^2, 13^2, 17^2$ in arithmetic progression).

 1"""Runnable demonstration of *Practica Geometriae* Distinctio IV (*De divisione camporum*)."""
         2
         3from __future__ import annotations
         4
         5import sys
         6from pathlib import Path
         7
         8ROOT = Path(__file__).resolve().parents[1]
         9SRC = ROOT / "src"
        10if str(SRC) not in sys.path:
        11    sys.path.insert(0, str(SRC))
        12
        13from rich.console import Console  # noqa: E402
        14from rich.table import Table  # noqa: E402
        15
        16from geometor.fibonacci import (  # noqa: E402
        17    construct_triangle_medians_centroid,
        18    construct_triangle_parallel_division,
        19    construct_triangle_side_point_division,
        20    trapezoid_parallel_division,
        21)
        22
        23
        24def main() -> None:
        25    console = Console()
        26
        27    # 1. Dividing Triangle ABG from a Point D on Side BG (Boncompagni p. 112)
        28    side_bisect = construct_triangle_side_point_division(p=1, q=1, d_offset_from_b=5)
        29    side_third = construct_triangle_side_point_division(p=1, q=2, d_offset_from_b=5)
        30
        31    t_side = Table(title="Distinctio IV — Dividing Triangle (13, 14, 15) from Point D on Side BG (BD = 5)")
        32    t_side.add_column("Target Ratio p : q", style="cyan")
        33    t_side.add_column("Base Point E", style="white")
        34    t_side.add_column("Cut Point Z on AG", style="white")
        35    t_side.add_column("Exact GZ", style="gold1")
        36    t_side.add_column("Share Areas (DZG : ABDZ)", style="green")
        37    for res in (side_bisect, side_third):
        38        t_side.add_row(
        39            f"{res.ratio_p} : {res.ratio_q}",
        40            str(res.pt_e),
        41            str(res.pt_z),
        42            str(res.gz_length),
        43            f"{res.area_dzg} : {res.area_abdz} (sum = {res.area_total})",
        44        )
        45    console.print(t_side)
        46
        47    # 2. Dividing Triangle Parallel to Base via Euclid VI.13 Mean Proportional (Boncompagni p. 119)
        48    par_101412 = construct_triangle_parallel_division(p=1, q=1, preset="10-14-12")
        49    par_131415 = construct_triangle_parallel_division(p=1, q=2, preset="13-14-15")
        50
        51    t_par = Table(title="Distinctio IV — Dividing Triangle Parallel to Base BG via Semicircle Mean Proportional")
        52    t_par.add_column("Triangle & Ratio", style="cyan")
        53    t_par.add_column("AE^2", style="gold1")
        54    t_par.add_column("AZ^2", style="gold1")
        55    t_par.add_column("EZ^2", style="gold1")
        56    t_par.add_column("Exact Areas (AEZ : EBGZ)", style="green")
        57    t_par.add_row(
        58        "(10, 14, 12), 1 : 1 (Boncompagni p. 119)",
        59        str(par_101412.ae_quadrance),
        60        str(par_101412.az_quadrance),
        61        str(par_101412.ez_quadrance),
        62        f"{par_101412.area_aez} : {par_101412.area_ebgz}",
        63    )
        64    t_par.add_row(
        65        "(13, 14, 15), 1 : 2",
        66        str(par_131415.ae_quadrance),
        67        str(par_131415.az_quadrance),
        68        str(par_131415.ez_quadrance),
        69        f"{par_131415.area_aez} : {par_131415.area_ebgz}",
        70    )
        71    console.print(t_par)
        72
        73    # 3. Medians Concurrency & Three-Consort Centroid Partition (Boncompagni pp. 112–113, 120)
        74    cent = construct_triangle_medians_centroid()
        75    # 4. Trapezoid Parallel Bisection & Three Squares in Arithmetic Progression (7^2, 13^2, 17^2)
        76    trap = trapezoid_parallel_division(top_base_a=7, bottom_base_b=17, height=10, p=1, q=1)
        77
        78    t_more = Table(title="Distinctio IV — Three-Consort Centroid & Trapezoid Root-Mean-Square Cut")
        79    t_more.add_column("Construction", style="cyan")
        80    t_more.add_column("Exact Invariants", style="green")
        81    t_more.add_row(
        82        "Three-Consort Centroid D = X(2) on (13, 14, 15)",
        83        f"D = {cent.centroid_d}, Area(DAB) = Area(DBG) = Area(DGA) = {cent.consort_area} (Total = {cent.total_area})",
        84    )
        85    t_more.add_row(
        86        "Trapezoid Parallel Bisection (a=7, b=17, h=10)",
        87        f"Chord c = {trap.dividing_chord_c} (7^2 + 17^2 = 2 * 13^2 = 338), Areas = {trap.upper_area} : {trap.lower_area}",
        88    )
        89    console.print(t_more)
        90
        91
        92if __name__ == "__main__":
        93    main()
        

3. Regular Polyhedra, Extreme & Mean Ratio, Flos & Liber Abaci

demos/polyhedra_golden_demo.py exercises geometor.fibonacci.polyhedra_golden across Distinctio VI–VIII, Flos (1225), and Liber Abaci Ch. 12:

  • Simultaneous planar construction of all five Platonic solid edges in a sphere of diameter $6$ ($e_4^2 = 24$, $e_8^2 = 18$, $e_6^2 = 12$, $e_{12}^2 = 18 - 6\sqrt{5}$, $e_{20}^2 = 18 - \frac{18}{5}\sqrt{5}$) and Hypsicles’ Book XIV theorem $V_{12}/V_{20} = e_6/e_{20} = \sqrt{\frac{5 + \sqrt{5}}{6}}$.

  • Inscription of the regular pentagon and decagon in diameter $10$ via Euclid XIII.9–10 and Ptolemy’s census census quartic $x^4 + 3125 = 125x^2$.

  • Verification of John of Palermo’s congruum triple $(\frac{31}{12}, \frac{41}{12}, \frac{49}{12})$, the Flos sexagesimal cubic root $1;22,7,42,33,4,40 = \frac{39931699}{29160000}$, and the twelve-month rabbit ratio convergents $F_{n+1}/F_n \to \phi$.

  1"""Runnable demonstration of *Practica Geometriae* Dist. VI–VIII, *Flos* (1225), and *Liber Abaci* Ch. 12."""
          2
          3from __future__ import annotations
          4
          5import sys
          6from pathlib import Path
          7
          8ROOT = Path(__file__).resolve().parents[1]
          9SRC = ROOT / "src"
         10if str(SRC) not in sys.path:
         11    sys.path.insert(0, str(SRC))
         12
         13import sympy as sp  # noqa: E402
         14from rich.console import Console  # noqa: E402
         15from rich.table import Table  # noqa: E402
         16
         17from geometor.fibonacci import (  # noqa: E402
         18    PHI,
         19    construct_dodecahedron_golden_chord,
         20    construct_pentagon_decagon_in_circle,
         21    construct_sphere_polyhedra_section,
         22    fibonacci_rabbit_convergents,
         23    flos_congruum_squares,
         24    flos_sexagesimal_cubic,
         25    polyhedra_in_sphere,
         26    solve_pentagon_ptolemy_quartic,
         27    verify_cassini_identity,
         28    verify_hypsicles_xiv_ratio,
         29)
         30
         31
         32def main() -> None:
         33    console = Console()
         34
         35    # 1. Five Regular Polyhedra in a Sphere of Diameter d = 6 (Distinctio VI, pp. 190–202)
         36    solids = polyhedra_in_sphere(6)
         37    section = construct_sphere_polyhedra_section()
         38    chord = construct_dodecahedron_golden_chord()
         39    xiv_ratio = verify_hypsicles_xiv_ratio(6)
         40
         41    t_poly = Table(title="Distinctio VI — Five Regular Polyhedra in a Sphere of Diameter d = 6")
         42    t_poly.add_column("Polyhedron", style="cyan")
         43    t_poly.add_column("Exact Edge e", style="white")
         44    t_poly.add_column("Embadum e^2", style="gold1")
         45    t_poly.add_column("Face r_f^2", style="white")
         46    t_poly.add_column("Insphere r_in^2", style="white")
         47    t_poly.add_column("Volume", style="green")
         48    for key, s in solids.items():
         49        assert sp.simplify(section.quadrances[key] - s.edge_sq) == 0
         50        t_poly.add_row(
         51            s.name,
         52            str(s.edge),
         53            str(s.edge_sq),
         54            str(s.face_circumradius_sq),
         55            str(s.insphere_radius_sq),
         56            str(sp.simplify(s.volume)),
         57        )
         58    console.print(t_poly)
         59    console.print(
         60        f"[bold green]Golden Chord BG[/bold green] = {chord.golden_major}, "
         61        f"[bold green]Hypsicles Book XIV Ratio V_12 / V_20[/bold green] = {xiv_ratio}\n"
         62    )
         63
         64    # 2. Pentagon & Decagon in Diameter 10 (Distinctio VIII, pp. 207–208) + Flos (1225)
         65    pent = construct_pentagon_decagon_in_circle()
         66    alg_side, alg_diag = solve_pentagon_ptolemy_quartic(10)
         67    cubic = flos_sexagesimal_cubic()
         68    cong_a, cong_x, cong_b = flos_congruum_squares()
         69
         70    t_sub = Table(title="Distinctio VIII & Flos (1225) — Algebraic & Geometric Subtleties")
         71    t_sub.add_column("Problem", style="cyan")
         72    t_sub.add_column("Exact Symbolic Result", style="green")
         73    t_sub.add_row(
         74        "Decagon & Pentagon in d = 10 (Euclid XIII.9–10)",
         75        f"s_10 = {pent.decagon_side}, s_5 = {pent.pentagon_side} (Ptolemy quartic diag/side = {sp.simplify(alg_diag / alg_side)})",
         76    )
         77    t_sub.add_row(
         78        "Flos Congruum Challenge x^2 +/- 5 = square",
         79        f"(a, x, b) = ({cong_a}, {cong_x}, {cong_b}) => x^2 - 5 = {cong_a**2}, x^2 + 5 = {cong_b**2}",
         80    )
         81    t_sub.add_row(
         82        "Flos Cubic x^3 + 2x^2 + 10x = 20",
         83        f"1;22,7,42,33,4,40 = {cubic.rational_root}, |x_Fib - x_exact| = {float(cubic.abs_root_error.evalf()):.3e}",
         84    )
         85    console.print(t_sub)
         86
         87    # 3. Liber Abaci Ch. 12 Rabbit Recurrence -> Golden Ratio phi
         88    verify_cassini_identity(15)
         89    t_rab = Table(title=f"Liber Abaci Ch. 12 — Twelve-Month Rabbit Convergents to phi = {PHI}")
         90    t_rab.add_column("Month", justify="right", style="cyan")
         91    t_rab.add_column("Pairs F_{m+2}", justify="right", style="white")
         92    t_rab.add_column("Ratio F_{m+2}/F_{m+1}", style="green")
         93    t_rab.add_column("Cassini Det", justify="right", style="gold1")
         94    t_rab.add_column("|Ratio - phi|", style="magenta")
         95    for row in fibonacci_rabbit_convergents(12):
         96        t_rab.add_row(
         97            str(row.month),
         98            str(row.pairs),
         99            f"{row.ratio_to_prev} ({float(row.ratio_to_prev):.8f})",
        100            f"{int(row.cassini_determinant):+d}",
        101            f"{float(row.phi_error_abs.evalf()):.3e}",
        102        )
        103    console.print(t_rab)
        104
        105
        106if __name__ == "__main__":
        107    main()