Detect, measure, localize, generate and render impossible figures via the cohomology of depth offsets.
Project description
impossible-figures
A Python library for the geometry of impossible figures — the Penrose triangle, Reutersvärd bars, Escher-style staircases, and friends.
It can:
- detect whether a figure is geometrically realizable,
- measure how impossible it is with a principled index in
[0, 1], - localize which loops cause the paradox,
- generate new impossible figures with a target holonomy, and
- render them to SVG.
Honest positioning
The mathematics here is classical, not new: it is the cohomology of impossible figures (Penrose, Pictures of Impossible Worlds and the Cohomology of Pictures, 1992 — building on Penrose & Penrose, 1958). This library implements that theory cleanly; it does not invent it.
What is actually missing in the Python ecosystem — and what this package provides — is a single, maintained library that bundles detection, an impossibility measure, paradox localization, generation, and rendering together. The existing Python material is mostly one-off educational scripts. This is that library, not a "first ever" anything.
Install
pip install impossible-figures
Requires Python ≥ 3.10. Runtime dependencies: numpy, networkx.
Quickstart
from impossible_figures import penrose_triangle, consistent_triangle
fig = penrose_triangle()
print(fig.impossibility_index()) # 1.0 -> maximally impossible
print(fig.is_possible()) # False
for cycle, holonomy in fig.offending_cycles():
print(cycle, "closes with offset", holonomy) # ['A', 'B', 'C'] ... 3.0
ok = consistent_triangle()
print(ok.impossibility_index()) # 0.0
depths, residual = ok.realize_depths()
print(depths) # a consistent 3D depth per part
Render the tribar to SVG (the occlusion is driven by the depth offsets, so the loop comes out impossible on its own):
from impossible_figures import penrose_triangle, to_svg
svg = to_svg(penrose_triangle())
open("penrose_triangle.svg", "w").write(svg)
See examples/ for runnable scripts and sample images.
Generate a figure with a prescribed paradox (the measure, inverted):
from impossible_figures import generate
fig = generate(holonomy=2.0, index=0.5) # target loop sum and impossibility
print(fig.impossibility_index()) # 0.5
The math
A figure is a set of parts (faces or bars) joined at junctions. Local
occlusion in the drawing tells us, at each junction, the relative depth offset
between two parts: w(u → v) = depth(v) − depth(u).
Model this as a directed graph (nodes = parts, edges = junctions). A globally
consistent 3D interpretation exists iff there is a depth d(part) for every part
with d(v) − d(u) = w(u → v) on every junction — equivalently, iff the offsets
sum to zero around every cycle.
The offsets form a 1-cochain w. It is realizable iff it is a coboundary
(w = grad d); the obstruction lives in H¹, the cycle space (cokernel of the
oriented incidence operator). The figure is impossible exactly when w has a
non-zero component there, and the size of that component — ‖residual‖ / ‖w‖ — is
the impossibility index in [0, 1]. The non-zero cycles are the loops
that witness the paradox.
Roadmap
This is an incremental build. Available now:
- the math core (detection, impossibility index, offending-cycle localization),
- the catalogue (
penrose_triangle,consistent_triangle,reutersvard,penrose_staircase,waterfall,impossible_cube), - SVG rendering (
to_svg) with occlusion driven by the depth offsets, - target-holonomy / target-index generation (
generate).
Coming next:
- renderable geometry for more of the catalogue,
- generation of multi-loop figures (several prescribed offending cycles).
Development
python -m venv .venv
.venv/Scripts/python -m pip install -e ".[dev]" # Windows
# source .venv/bin/activate && pip install -e ".[dev]" # POSIX
ruff check src tests # lint
ruff format --check src tests
mypy src # types (strict)
pytest # tests + coverage
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file impossible_figures-0.1.0.tar.gz.
File metadata
- Download URL: impossible_figures-0.1.0.tar.gz
- Upload date:
- Size: 21.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
766bfc15b960755665d8a4bd36535d68e9d952c361a76207ab6f7e42f02f074a
|
|
| MD5 |
94df6e399e48b2f99dd9b2d7473c87ea
|
|
| BLAKE2b-256 |
7395885b0bb704fab7bba01dd6e442520d20f944ef3dd4c6b71ffbe33c189430
|
File details
Details for the file impossible_figures-0.1.0-py3-none-any.whl.
File metadata
- Download URL: impossible_figures-0.1.0-py3-none-any.whl
- Upload date:
- Size: 19.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
86e9b1994558229f6ca47a8050361e08c809f9176b3bce34a4dbaf80d3e4c2c9
|
|
| MD5 |
f62d79add349275b5a2f55b5b39d29f0
|
|
| BLAKE2b-256 |
904d123e42333012b5b318d588cb9513616e7fb036cd36936b9a62aacb6529a4
|