Metadata-Version: 2.4
Name: impossible-figures
Version: 0.1.0
Summary: Detect, measure, localize, generate and render impossible figures via the cohomology of depth offsets.
Project-URL: Homepage, https://github.com/aditya-raj-arora/impossible-figures
Project-URL: Issues, https://github.com/aditya-raj-arora/impossible-figures/issues
Project-URL: Changelog, https://github.com/aditya-raj-arora/impossible-figures/blob/main/CHANGELOG.md
Author-email: Aditya Raj Arora <adityarajarora123@gmail.com>
License-Expression: MIT
License-File: LICENSE
Keywords: cohomology,escher,geometry,impossible-figures,penrose,svg
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Mathematics
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: networkx>=3.0
Requires-Dist: numpy>=1.23
Provides-Extra: dev
Requires-Dist: mypy; extra == 'dev'
Requires-Dist: pytest-cov; extra == 'dev'
Requires-Dist: pytest>=7; extra == 'dev'
Requires-Dist: ruff; extra == 'dev'
Provides-Extra: release
Requires-Dist: build; extra == 'release'
Requires-Dist: twine; extra == 'release'
Description-Content-Type: text/markdown

# 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

```bash
pip install impossible-figures
```

Requires Python ≥ 3.10. Runtime dependencies: `numpy`, `networkx`.

## Quickstart

```python
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):

```python
from impossible_figures import penrose_triangle, to_svg

svg = to_svg(penrose_triangle())
open("penrose_triangle.svg", "w").write(svg)
```

See [examples/](examples/) for runnable scripts and sample images.

Generate a figure with a prescribed paradox (the measure, inverted):

```python
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

```bash
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](LICENSE).
