Metadata-Version: 2.2
Name: pyvoro2
Version: 0.7.0
Summary: Python bindings for Voro++ with 2D/3D Voronoi and power/Laguerre tessellations, periodic topology utilities, and inverse power fitting.
Author-Email: "Ivan Yu. Chernyshov" <ivan.chernyshoff@gmail.com>
License:                    GNU LESSER GENERAL PUBLIC LICENSE
                                Version 3, 29 June 2007
         
          Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
          Everyone is permitted to copy and distribute verbatim copies
          of this license document, but changing it is not allowed.
         
         
           This version of the GNU Lesser General Public License incorporates
         the terms and conditions of version 3 of the GNU General Public
         License, supplemented by the additional permissions listed below.
         
           0. Additional Definitions.
         
           As used herein, "this License" refers to version 3 of the GNU Lesser
         General Public License, and the "GNU GPL" refers to version 3 of the GNU
         General Public License.
         
           "The Library" refers to a covered work governed by this License,
         other than an Application or a Combined Work as defined below.
         
           An "Application" is any work that makes use of an interface provided
         by the Library, but which is not otherwise based on the Library.
         Defining a subclass of a class defined by the Library is deemed a mode
         of using an interface provided by the Library.
         
           A "Combined Work" is a work produced by combining or linking an
         Application with the Library.  The particular version of the Library
         with which the Combined Work was made is also called the "Linked
         Version".
         
           The "Minimal Corresponding Source" for a Combined Work means the
         Corresponding Source for the Combined Work, excluding any source code
         for portions of the Combined Work that, considered in isolation, are
         based on the Application, and not on the Linked Version.
         
           The "Corresponding Application Code" for a Combined Work means the
         object code and/or source code for the Application, including any data
         and utility programs needed for reproducing the Combined Work from the
         Application, but excluding the System Libraries of the Combined Work.
         
           1. Exception to Section 3 of the GNU GPL.
         
           You may convey a covered work under sections 3 and 4 of this License
         without being bound by section 3 of the GNU GPL.
         
           2. Conveying Modified Versions.
         
           If you modify a copy of the Library, and, in your modifications, a
         facility refers to a function or data to be supplied by an Application
         that uses the facility (other than as an argument passed when the
         facility is invoked), then you may convey a copy of the modified
         version:
         
            a) under this License, provided that you make a good faith effort to
            ensure that, in the event an Application does not supply the
            function or data, the facility still operates, and performs
            whatever part of its purpose remains meaningful, or
         
            b) under the GNU GPL, with none of the additional permissions of
            this License applicable to that copy.
         
           3. Object Code Incorporating Material from Library Header Files.
         
           The object code form of an Application may incorporate material from
         a header file that is part of the Library.  You may convey such object
         code under terms of your choice, provided that, if the incorporated
         material is not limited to numerical parameters, data structure
         layouts and accessors, or small macros, inline functions and templates
         (ten or fewer lines in length), you do both of the following:
         
            a) Give prominent notice with each copy of the object code that the
            Library is used in it and that the Library and its use are
            covered by this License.
         
            b) Accompany the object code with a copy of the GNU GPL and this license
            document.
         
           4. Combined Works.
         
           You may convey a Combined Work under terms of your choice that,
         taken together, effectively do not restrict modification of the
         portions of the Library contained in the Combined Work and reverse
         engineering for debugging such modifications, if you also do each of
         the following:
         
            a) Give prominent notice with each copy of the Combined Work that
            the Library is used in it and that the Library and its use are
            covered by this License.
         
            b) Accompany the Combined Work with a copy of the GNU GPL and this license
            document.
         
            c) For a Combined Work that displays copyright notices during
            execution, include the copyright notice for the Library among
            these notices, as well as a reference directing the user to the
            copies of the GNU GPL and this license document.
         
            d) Do one of the following:
         
                0) Convey the Minimal Corresponding Source under the terms of this
                License, and the Corresponding Application Code in a form
                suitable for, and under terms that permit, the user to
                recombine or relink the Application with a modified version of
                the Linked Version to produce a modified Combined Work, in the
                manner specified by section 6 of the GNU GPL for conveying
                Corresponding Source.
         
                1) Use a suitable shared library mechanism for linking with the
                Library.  A suitable mechanism is one that (a) uses at run time
                a copy of the Library already present on the user's computer
                system, and (b) will operate properly with a modified version
                of the Library that is interface-compatible with the Linked
                Version.
         
            e) Provide Installation Information, but only if you would otherwise
            be required to provide such information under section 6 of the
            GNU GPL, and only to the extent that such information is
            necessary to install and execute a modified version of the
            Combined Work produced by recombining or relinking the
            Application with a modified version of the Linked Version. (If
            you use option 4d0, the Installation Information must accompany
            the Minimal Corresponding Source and Corresponding Application
            Code. If you use option 4d1, you must provide the Installation
            Information in the manner specified by section 6 of the GNU GPL
            for conveying Corresponding Source.)
         
           5. Combined Libraries.
         
           You may place library facilities that are a work based on the
         Library side by side in a single library together with other library
         facilities that are not Applications and are not covered by this
         License, and convey such a combined library under terms of your
         choice, if you do both of the following:
         
            a) Accompany the combined library with a copy of the same work based
            on the Library, uncombined with any other library facilities,
            conveyed under the terms of this License.
         
            b) Give prominent notice with the combined library that part of it
            is a work based on the Library, and explaining where to find the
            accompanying uncombined form of the same work.
         
           6. Revised Versions of the GNU Lesser General Public License.
         
           The Free Software Foundation may publish revised and/or new versions
         of the GNU Lesser General Public License from time to time. Such new
         versions will be similar in spirit to the present version, but may
         differ in detail to address new problems or concerns.
         
           Each version is given a distinguishing version number. If the
         Library as you received it specifies that a certain numbered version
         of the GNU Lesser General Public License "or any later version"
         applies to it, you have the option of following the terms and
         conditions either of that published version or of any later version
         published by the Free Software Foundation. If the Library as you
         received it does not specify a version number of the GNU Lesser
         General Public License, you may choose any version of the GNU Lesser
         General Public License ever published by the Free Software Foundation.
         
           If the Library as you received it specifies that a proxy can decide
         whether future versions of the GNU Lesser General Public License shall
         apply, that proxy's public statement of acceptance of any version is
         permanent authorization for you to choose that version for the
         Library.
         
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Scientific/Engineering :: Mathematics
Classifier: Topic :: Scientific/Engineering :: Physics
Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
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: Programming Language :: C++
Project-URL: Homepage, https://github.com/DeloneCommons/pyvoro2
Project-URL: Documentation, https://delonecommons.github.io/pyvoro2/
Project-URL: Repository, https://github.com/DeloneCommons/pyvoro2
Project-URL: Issues, https://github.com/DeloneCommons/pyvoro2/issues
Requires-Python: >=3.10
Requires-Dist: numpy<2,>=1.23; python_version < "3.11"
Requires-Dist: numpy<3,>=1.23; python_version >= "3.11"
Provides-Extra: sparse
Requires-Dist: scipy>=1.8; extra == "sparse"
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Requires-Dist: scipy>=1.8; extra == "test"
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: scipy>=1.8; extra == "dev"
Requires-Dist: flake8; extra == "dev"
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Requires-Dist: tomli; python_version < "3.11" and extra == "dev"
Provides-Extra: docs
Requires-Dist: mkdocs>=1.6; extra == "docs"
Requires-Dist: mkdocs-material>=9.5; extra == "docs"
Requires-Dist: mkdocstrings[python]>=0.27; extra == "docs"
Requires-Dist: pymdown-extensions>=10.0; extra == "docs"
Requires-Dist: mkdocs-section-index>=0.3.9; extra == "docs"
Provides-Extra: notebooks
Requires-Dist: nbformat>=5.1; extra == "notebooks"
Requires-Dist: nbclient>=0.7; extra == "notebooks"
Requires-Dist: ipykernel>=6; extra == "notebooks"
Provides-Extra: viz2d
Requires-Dist: matplotlib; extra == "viz2d"
Provides-Extra: viz
Requires-Dist: matplotlib; extra == "viz"
Requires-Dist: py3Dmol; extra == "viz"
Provides-Extra: all
Requires-Dist: pytest; extra == "all"
Requires-Dist: flake8; extra == "all"
Requires-Dist: build; extra == "all"
Requires-Dist: twine; extra == "all"
Requires-Dist: mkdocs>=1.6; extra == "all"
Requires-Dist: mkdocs-material>=9.5; extra == "all"
Requires-Dist: mkdocstrings[python]>=0.27; extra == "all"
Requires-Dist: pymdown-extensions>=10.0; extra == "all"
Requires-Dist: mkdocs-section-index>=0.3.9; extra == "all"
Requires-Dist: nbformat>=5.1; extra == "all"
Requires-Dist: nbclient>=0.7; extra == "all"
Requires-Dist: ipykernel>=6; extra == "all"
Requires-Dist: matplotlib; extra == "all"
Requires-Dist: py3Dmol; extra == "all"
Requires-Dist: scipy>=1.8; extra == "all"
Requires-Dist: tomli; python_version < "3.11" and extra == "all"
Description-Content-Type: text/markdown

# pyvoro2

[![CI](https://github.com/DeloneCommons/pyvoro2/actions/workflows/ci.yml/badge.svg)](https://github.com/DeloneCommons/pyvoro2/actions/workflows/ci.yml) [![Docs](https://github.com/DeloneCommons/pyvoro2/actions/workflows/docs.yml/badge.svg)](https://github.com/DeloneCommons/pyvoro2/actions/workflows/docs.yml) [![PyPI](https://img.shields.io/pypi/v/pyvoro2.svg)](https://pypi.org/project/pyvoro2/) [![Python Versions](https://img.shields.io/pypi/pyversions/pyvoro2.svg)](https://pypi.org/project/pyvoro2/) [![License](https://img.shields.io/pypi/l/pyvoro2.svg)](https://github.com/DeloneCommons/pyvoro2/blob/main/LICENSE)

**Documentation:** https://delonecommons.github.io/pyvoro2/


---

**pyvoro2** is a scientific Python package for computing **2D and 3D Voronoi
and power/Laguerre tessellations**, with particular support for periodic
topology and inverse fitting of power weights from partial geometric data.

> **v0.7.0 documentation:** this site describes the v0.7.0 transition release,
> distributed through the `v0.7.0` Git tag and PyPI. The archived v0.6.3 release
> remains the software baseline
> cited by the current separator-inverse manuscript. By maintainer decision,
> v0.7.0 has no GitHub Release or Zenodo record; the next full GitHub/Zenodo
> archival release is planned for v0.8.0.

v0.7.0 provides:

- standard Voronoi tessellations;
- power/Laguerre tessellations directly from mathematical weights, with the
  existing radius representation retained;
- a dedicated `pyvoro2.planar` namespace for 2D rectangular domains;
- bounded, partially periodic, and triclinic periodic 3D domains;
- explicit periodic neighbor-image shifts;
- diagnostics, validation, topology normalization, and visualization helpers;
- separator-based inverse fitting in 2D and 3D, including graph/connectivity
  diagnostics, hard-constraint witnesses, realized-boundary matching, and an
  optional realization-aware active-set loop.

The package is evolving toward a stable architecture for **forward and inverse
weighted tessellations**. v0.8 is a cleanup-only compatibility-removal release.
Prescribed cell measures move to v0.9 and mixed separator-plus-measure fitting
to v0.10; none of those later capabilities is part of v0.7.

pyvoro2 is designed to be explicit and predictable:

- it vendors and wraps upstream Voro++ sources, including a small numeric
  robustness fix already accepted upstream for power/Laguerre pruning;
- 3D and planar APIs remain separate where their backends and domain support
  differ;
- power **weights** are the mathematical quantities, while Voro++ **radii** are
  a backend representation;
- algebraic inverse fit and realized geometry are reported as separate layers;
- numerical and topological failure modes are exposed through diagnostics
  rather than hidden fallback.

**License note:** pyvoro2-authored code is released under **LGPLv3+** starting
with version 0.6.0. Earlier versions were released under MIT. Vendored
third-party code remains under its own licenses.

## Quickstart

### 1) Standard Voronoi in a 3D box

For 3D visualization, install the optional dependency with
`pip install "pyvoro2[viz]"`.

```python
import numpy as np
import pyvoro2 as pv
from pyvoro2.viz3d import view_tessellation

points = np.random.default_rng(0).uniform(-1.5, 1.5, size=(10, 3))
box = pv.Box(((-2, 2), (-2, 2), (-2, 2)))
result = pv.compute(points, domain=box, mode='standard')

view_tessellation(
    result.cells,
    domain=box,
    show_vertices=False,
)
```

<img src="https://raw.githubusercontent.com/DeloneCommons/pyvoro2/main/docs/assets/quickstart_box.png" width="50%" alt="Voronoi tessellation in a box" />

### 2) Planar periodic workflow

```python
import numpy as np
import pyvoro2.planar as pv2

points2d = np.array([
    [0.2, 0.2],
    [0.8, 0.25],
    [0.4, 0.8],
], dtype=float)

cell2d = pv2.RectangularCell(
    ((0.0, 1.0), (0.0, 1.0)),
    periodic=(True, True),
)
result2d = pv2.compute(
    points2d,
    domain=cell2d,
    return_diagnostics=True,
    normalize='topology',
)

diagnostics2d = result2d.require_tessellation_diagnostics()
topology2d = result2d.require_normalized_topology()
```

### 3) Power/Laguerre tessellation

The forward `compute(...)` APIs accept mathematical power weights directly:

```python
weights = np.linspace(-0.2, 0.2, len(points))

result = pv.compute(
    points,
    domain=box,
    mode='power',
    weights=weights,
    include_empty=True,
)
```

The power function is `||x - p_i||^2 - w_i`: weights have squared-length
units, may be negative, and are converted to non-negative backend radii using
one common global shift. Adding the same constant to every weight leaves the
complete diagram unchanged. Existing `radii=` calls remain available, but the
resulting length-unit radii are a non-unique backend representation rather than
necessarily physical radii. Supply exactly one of `weights=` or `radii=` in
power mode. Finite representability is necessary for conversion but does not
guarantee a numerically resolvable native tessellation. Voro++ evaluates radical
geometry with binary64 squared-radius arithmetic, so very large absolute
`radii**2` values or genuine weight ranges relative to squared coordinate/domain
scales can lose geometric resolution. There is no universal safe cutoff: the
onset depends on scale, geometry, platform, and compiler, and periodic power
tessellations are a particularly sensitive regime. See
[Power diagrams](https://delonecommons.github.io/pyvoro2/theory/power-diagrams/) for the precise distinction.

### 4) Periodic crystal cell with neighbor image shifts

```python
cell = pv.PeriodicCell(
    vectors=(
        (10.0, 0.0, 0.0),
        (2.0,  9.0, 0.0),
        (1.0,  0.5, 8.0),
    )
)

result = pv.compute(points, domain=cell, return_face_shifts=True)

# result.require_boundaries() returns faces aligned with input-site order.
# Each face can include:
#   adjacent_cell  (neighbor site id)
#   adjacent_shift (which periodic image produced the face)
```

### 5) Fit weights from separator observations

```python
import pyvoro2.inverse as inverse
import pyvoro2.inverse.separator as separator

points_pair = np.array([
    [0.0, 0.0, 0.0],
    [2.0, 0.0, 0.0],
])
pair_box = pv.Box(((-5, 5), (-5, 5), (-5, 5)))

observations = inverse.resolve_separator_observations(
    points_pair,
    [(0, 1, 0.25)],
    measurement='fraction',
    domain=pair_box,
)

fit = inverse.fit_weights_from_separators(
    points_pair,
    observations,
    model=separator.FitModel(mismatch=separator.SquaredLoss()),
)
```

The small `pyvoro2.inverse` surface is the normal fixed-observation route.
Advanced models, realized-boundary checks, reports, and the experimental
active-set workflow are available explicitly from
`pyvoro2.inverse.separator`.

## Numerical safety notes

Voro++ uses fixed absolute tolerances internally, including a hard
near-duplicate check around approximately `1e-5` in container distance units.
Very small or very large coordinate systems can therefore cause process
termination inside the backend or loss of geometric accuracy.

pyvoro2 does not silently rescale coordinates. Rescale explicitly when using
unusual units.

A Python-side near-duplicate precheck can run before the native call:

```python
result = pv.compute(points, domain=cell, duplicate_check='raise')
```

For stricter post-hoc checks, see:

- `pyvoro2.validate_tessellation(..., level='strict')`;
- `pyvoro2.validate_normalized_topology(..., level='strict')`;
- `pyvoro2.planar.validate_tessellation(..., level='strict')`;
- `pyvoro2.planar.validate_normalized_topology(..., level='strict')`.

The vendored Voro++ snapshot includes the upstream robustness fix for radical
pruning in power mode. This avoids rare cross-platform cases where fully
periodic power tessellations could produce a non-reciprocal face/neighbor graph
under aggressive floating-point code generation.

## Why use pyvoro2?

Voro++ is fast and mature, but its low-level C++ interface does not provide all
of the Python-side contracts needed in scientific workflows. pyvoro2 adds:

- triclinic periodic cells and coordinate mapping in 3D;
- partially periodic orthorhombic cells for slabs and wires;
- explicit planar support through `pyvoro2.planar`;
- periodic image-labelled faces and edges for graph construction;
- diagnostics and normalization for reproducible topology;
- owner lookup with `locate(...)`;
- non-inserting probe cells with `ghost_cells(...)`;
- separator-based inverse fitting with inspectable graph, feasibility,
  realization, and active-set diagnostics.

## Documentation overview

| Section | What it contains |
|---|---|
| [Choosing an API](https://delonecommons.github.io/pyvoro2/guide/choosing-api/) | Preferred forward and inverse entry points, lifecycle status, result layers, and the static scalability contract. |
| [Concepts](https://delonecommons.github.io/pyvoro2/guide/concepts/) | A concise user introduction to Voronoi and power/Laguerre tessellations. |
| [Glossary](https://delonecommons.github.io/pyvoro2/guide/glossary/) | Power weights, backend radii, gauge, separator observations, realization, and active-set terminology. |
| [Domains (3D)](https://delonecommons.github.io/pyvoro2/guide/domains/) | `Box`, `OrthorhombicCell`, and `PeriodicCell`. |
| [Planar (2D)](https://delonecommons.github.io/pyvoro2/guide/planar/) | The planar namespace, rectangular periodicity, diagnostics, normalization, and plotting. |
| [Operations](https://delonecommons.github.io/pyvoro2/guide/operations/) | Forward tessellation, owner lookup, and ghost-cell workflows. |
| [Topology and graphs](https://delonecommons.github.io/pyvoro2/guide/topology/) | Periodic image-labelled adjacency and normalized topology. |
| [Separator fitting](https://delonecommons.github.io/pyvoro2/guide/powerfit/) | Current inverse API, result diagnostics, realization matching, and active-set refinement. |
| [v0.7 migration](https://delonecommons.github.io/pyvoro2/guide/migration-v0.7/) | Exact v0.6.3-to-v0.7 changes and the fixed v0.8 removal horizon. |
| [Theory](https://delonecommons.github.io/pyvoro2/theory/) | API-independent definitions of power diagrams, weights, gauge, and separator inversion. |
| [Development](https://delonecommons.github.io/pyvoro2/development/) | Architecture, workflow, documentation conventions, release plans, API lifecycle, and decision records. |
| [Visualization](https://delonecommons.github.io/pyvoro2/guide/visualization/) | Optional `py3Dmol` and `matplotlib` helpers. |
| [Examples](https://delonecommons.github.io/pyvoro2/guide/notebooks/) | Executable notebook workflows. |
| [API reference](https://delonecommons.github.io/pyvoro2/reference/) | Exact signatures and docstring reference for spatial, planar, and separator-fitting APIs. |
| [Roadmap](https://delonecommons.github.io/pyvoro2/project/roadmap/) | v0.7 stabilization, v0.8 cleanup, v0.9 prescribed measures, v0.10 mixed fitting, 1.0, and future research. |

## Installation

Most users should install a prebuilt wheel:

```bash
pip install pyvoro2
```

Optional extras:

- `pyvoro2[sparse]` for optional SciPy sparse-direct static quadratic
  separator fitting;
- `pyvoro2[viz]` for 3D `py3Dmol` and 2D plotting;
- `pyvoro2[viz2d]` for 2D matplotlib plotting only;
- `pyvoro2[all]` for the full local notebook, docs, lint, test, and release
  validation stack.

Source builds require Python 3.10+, a C++17 compiler, CMake 3.20 or newer,
and Python development headers. Ninja is recommended because the build backend
uses CMake efficiently with it. Typical toolchains are GCC or Clang on Linux,
Xcode Command Line Tools on macOS, and Visual Studio Build Tools with the
"Desktop development with C++" workload on Windows. These are source-build
requirements, not pyvoro2 runtime dependencies.

For an editable runtime-only build:

```bash
python -m pip install --upgrade pip
python -m pip install -e .
```

For local repository development and all validation tools:

```bash
python -m pip install --upgrade pip
python -m pip install -e ".[all]"
```

See [Contributing](https://github.com/DeloneCommons/pyvoro2/blob/main/CONTRIBUTING.md)
for platform notes and clean-environment verification.

## Testing

The default deterministic suite is:

```bash
pip install -e ".[test]"
pytest -q
```

Additional opt-in groups:

```bash
# Randomized property/fuzz checks
pytest -m fuzz --fuzz-n 100

# Independent wrapper cross-checks; requires pyvoro
pip install pyvoro
pytest -m pyvoro --fuzz-n 100
```

For a complete local publishability pass:

```bash
python tools/release_check.py
```

## Project status and support

pyvoro2 is currently **beta**. v0.7.0 is the current transition release,
distributed through the `v0.7.0` Git tag and PyPI, and contains the common
forward/result contract and preferred separator API. The archived v0.6.3 release remains the software baseline cited by the
separator-inverse manuscript. No GitHub Release or Zenodo archive was created
for v0.7.0; v0.8 removes the bounded compatibility layer and is intended to be
the next full GitHub/Zenodo archival release before new inverse families begin
in v0.9. The
[archived v0.7 development plan](https://delonecommons.github.io/pyvoro2/development/plans/archive/v0.7/) records the
delivered scope, accepted decisions, qualification evidence, and deferrals.

Reproducible bugs and focused feature proposals are welcome through GitHub
issues. Development is currently led by one maintainer, so support is
best-effort. Contribution and decision policies are described in
[`CONTRIBUTING.md`](https://github.com/DeloneCommons/pyvoro2/blob/main/CONTRIBUTING.md).

## AI-assisted development

The project has used the latest Chat and Codex models available at the time of
development for planning, implementation support, testing, and documentation.
The maintainer reviews and validates all integrated changes and remains
responsible for the software and scientific claims.

See [AI-assisted development](https://delonecommons.github.io/pyvoro2/project/ai/) for details.

## License

- pyvoro2-authored code is **LGPLv3+** starting with version 0.6.0;
- versions before 0.6.0 were released under MIT;
- vendored Voro++ code remains under its upstream license.

---

*This README is auto-generated from the MkDocs sources in `docs/`.*
To update it, edit the docs pages and re-run: `python tools/gen_readme.py`.

