v0.7 public API inventory
- Status: Finalized and maintainer-approved for v0.7.0 on 2026-07-23
- Baseline: v0.6.3
- Target: v0.7.0
- Baseline audit: issue #6, completed 2026-07-18
- Policy: API lifecycle and compatibility
- Plan: archived v0.7 development plan
This inventory is the authoritative v0.7 lifecycle contract for public imports, return routes, record schemas, defaults, and scientific semantics. It has been checked against the current source, tests, documentation, executed notebooks, and downstream-shaped regression assets. Release qualification must verify that the packaged artifacts preserve this contract.
How to maintain this inventory after finalization
For every v0.7 issue that changes public behavior:
- update the relevant row or section in the same change;
- distinguish the v0.6.3 baseline from the intended v0.7 state;
- record aliases, deprecations, and their removal releases;
- include defaults, result fields, record keys, units, and periodic conventions when they carry scientific meaning;
- leave uncertain new surfaces provisional rather than omitting them;
- do not mark a surface stable until its tests and documentation define the contract clearly.
Issue #16 finalizes the classifications below. Release review must verify that
__all__, docstrings, guides, reference pages, migration notes, and this
inventory remain synchronized.
Factual v0.6.3 baseline
This section records behavior observed in the v0.6.3 source tree before any
v0.7 public implementation. It was checked against package __all__ values,
call signatures, generated API reference pages, user guides, source notebooks,
and the existing tests. Focused executable checks live in
tests/test_v063_forward_baseline.py and
tests/test_v063_inverse_baseline.py.
“Baseline” does not make every current convenience stable forever. It identifies what the v0.7 compatibility routes must preserve deliberately and prevents a module move or result-default change from silently changing established behavior.
Current public namespaces, documented module routes, and __all__
The exact membership and absence of duplicates in the three package-root lists
and the documented pyvoro2.viz3d list are pinned by the baseline tests; export
ordering is not treated as a compatibility promise. The grouped contents below
are exhaustive for those lists. Documented direct module routes are recorded
separately so a later module move does not preserve only package-root imports.
pyvoro2 — 62 exports
| Group | Exact current exports |
|---|---|
| Domains and operations | Box, OrthorhombicCell, PeriodicCell, compute, locate, ghost_cells |
| Tessellation diagnostics | TessellationDiagnostics, TessellationIssue, TessellationError, analyze_tessellation, validate_tessellation |
| Normalization diagnostics | NormalizationDiagnostics, NormalizationIssue, NormalizationError, validate_normalized_topology |
| Duplicate handling | DuplicatePair, DuplicateError, duplicate_check |
| Geometry annotation | annotate_face_properties |
| Normalization | NormalizedVertices, NormalizedTopology, normalize_vertices, normalize_edges_faces, normalize_topology |
| Weight/radius transforms | radii_to_weights, weights_to_radii |
| Package metadata/namespaces | __version__, planar |
| Historical inverse surface | the exact 34-name compatibility list under Compatibility-only top-level inverse names |
The weight/radius transforms are implemented in pyvoro2.powerfit.transforms
in v0.6.3 but are listed separately because ADR 0004 assigns them neutral
ownership in v0.7.
pyvoro2.planar — 25 exports
Box
RectangularCell
PlanarComputeResult
compute
locate
ghost_cells
DuplicatePair
DuplicateError
duplicate_check
annotate_edge_properties
plot_tessellation
TessellationIssue
TessellationDiagnostics
TessellationError
analyze_tessellation
validate_tessellation
NormalizedVertices
NormalizedTopology
normalize_vertices
normalize_edges
normalize_topology
NormalizationIssue
NormalizationDiagnostics
NormalizationError
validate_normalized_topology
pyvoro2.powerfit — 42 exports
PairBisectorConstraints
resolve_pair_bisector_constraints
SquaredLoss
HuberLoss
Interval
FixedValue
SoftIntervalPenalty
ExponentialBoundaryPenalty
ReciprocalBoundaryPenalty
L2Regularization
FitModel
AlgebraicEdgeDiagnostics
ConstraintGraphDiagnostics
ConnectivityDiagnostics
ConnectivityDiagnosticsError
HardConstraintConflictTerm
HardConstraintConflict
PowerFitBounds
PowerFitPredictions
PowerFitObjectiveBreakdown
PowerFitProblem
PowerWeightFitResult
build_power_fit_problem
build_power_fit_result
RealizedPairDiagnostics
UnaccountedRealizedPair
UnaccountedRealizedPairError
build_fit_report
build_realized_report
build_active_set_report
dumps_report_json
write_report_json
ActiveSetOptions
ActiveSetIteration
ActiveSetPathSummary
PairConstraintDiagnostics
SelfConsistentPowerFitResult
fit_power_weights
match_realized_pairs
solve_self_consistent_power_weights
radii_to_weights
weights_to_radii
PowerFitBounds, PowerFitPredictions, PowerFitObjectiveBreakdown,
PowerFitProblem, build_power_fit_problem, and build_power_fit_result are
public from pyvoro2.powerfit but are not top-level pyvoro2 exports. v0.7
must not broaden the historical top-level surface while preserving the old
package.
pyvoro2.viz3d — 9 exports
VizStyle
make_view
add_axes
add_sites
add_vertices
add_domain_wireframe
add_cell_wireframe
add_tessellation_wireframe
view_tessellation
pyvoro2.viz2d has no explicit __all__; its documented public function is
plot_tessellation, which is the same object re-exported by
pyvoro2.planar. Importing either visualization module does not require its
optional rendering dependency until a rendering function is called.
Documented direct module routes
The generated v0.6.3 reference documents these direct module routes in addition to the package-root exports:
pyvoro2.api,domains,diagnostics,duplicates,edge_properties,face_properties,normalize,validation,viz2d, andviz3d;pyvoro2.planar.api,domains,diagnostics,normalize,result, andvalidation; andpyvoro2.powerfit.active,constraints,model,realize,report, andsolver.
Where a direct-module object is also exported from its package root, v0.6.3
uses the same object rather than a wrapper. The powerfit.model reference also
documents ScalarMismatch, HardConstraint, and ScalarPenalty directly;
these three base classes are not pyvoro2.powerfit package exports. The
documented submodule __all__ values are:
| Module | Exact __all__ |
|---|---|
pyvoro2.powerfit.report |
build_fit_report, build_realized_report, build_active_set_report, dumps_report_json, write_report_json |
pyvoro2.powerfit.solver |
fit_power_weights, ConnectivityDiagnosticsError |
Private underscore-prefixed helpers rendered nowhere in the public reference are not part of this baseline.
Current forward signatures and defaults
The domain constructors are:
pyvoro2.Box(bounds)
pyvoro2.OrthorhombicCell(bounds, periodic=(True, True, True))
pyvoro2.PeriodicCell(vectors, origin=(0.0, 0.0, 0.0))
pyvoro2.planar.Box(bounds)
pyvoro2.planar.RectangularCell(bounds, periodic=(True, True))
Documented domain conveniences, with annotations omitted, are:
pyvoro2.Box.from_points(points, padding=2.0)
pyvoro2.OrthorhombicCell.lattice_vectors
pyvoro2.OrthorhombicCell.remap_cart(
points, *, return_shifts=False, eps=None,
)
pyvoro2.PeriodicCell.from_params(
bx, bxy, by, bxz, byz, bz, *, origin=(0.0, 0.0, 0.0),
)
pyvoro2.PeriodicCell.to_internal_params()
pyvoro2.PeriodicCell.cart_to_internal(points)
pyvoro2.PeriodicCell.internal_to_cart(points_internal)
pyvoro2.PeriodicCell.remap_internal(
points_internal, *, return_shifts=False, eps=None,
)
pyvoro2.PeriodicCell.wrap_internal(points_internal)
pyvoro2.PeriodicCell.remap_cart(
points, *, return_shifts=False, eps=None,
)
pyvoro2.planar.Box.from_points(points, padding=2.0)
pyvoro2.planar.RectangularCell.lattice_vectors
pyvoro2.planar.RectangularCell.remap_cart(
points, *, return_shifts=False, eps=None,
)
The exact spatial operation signatures, with annotations omitted here for readability, are:
compute(
points, *, domain, ids=None,
duplicate_check='off', duplicate_threshold=1e-5,
duplicate_wrap=True, duplicate_max_pairs=10,
block_size=None, blocks=None, init_mem=8,
mode='standard', radii=None,
return_vertices=True, return_adjacency=True, return_faces=True,
return_face_shifts=False, face_shift_search=2, include_empty=False,
validate_face_shifts=True, repair_face_shifts=False, face_shift_tol=None,
return_diagnostics=False, tessellation_check='none',
tessellation_require_reciprocity=None,
tessellation_volume_tol_rel=1e-8,
tessellation_volume_tol_abs=1e-12,
tessellation_plane_offset_tol=None,
tessellation_plane_angle_tol=None,
)
locate(
points, queries, *, domain, ids=None,
duplicate_check='off', duplicate_threshold=1e-5,
duplicate_wrap=True, duplicate_max_pairs=10,
block_size=None, blocks=None, init_mem=8,
mode='standard', radii=None, return_owner_position=False,
)
ghost_cells(
points, queries, *, domain, ids=None,
duplicate_check='off', duplicate_threshold=1e-5,
duplicate_wrap=True, duplicate_max_pairs=10,
block_size=None, blocks=None, init_mem=8,
mode='standard', radii=None, ghost_radius=None,
return_vertices=True, return_adjacency=True, return_faces=True,
include_empty=True,
)
The exact planar operation signatures are:
compute(
points, *, domain, ids=None,
duplicate_check='off', duplicate_threshold=1e-5,
duplicate_wrap=True, duplicate_max_pairs=10,
block_size=None, blocks=None, init_mem=8,
mode='standard', radii=None,
return_vertices=True, return_adjacency=True, return_edges=True,
return_edge_shifts=False, edge_shift_search=2, include_empty=False,
validate_edge_shifts=True, repair_edge_shifts=False, edge_shift_tol=None,
return_diagnostics=False, return_result=False, normalize='none',
normalization_tol=None, tessellation_check='none',
tessellation_require_reciprocity=None,
tessellation_area_tol_rel=1e-8,
tessellation_area_tol_abs=1e-12,
tessellation_line_offset_tol=None,
tessellation_line_angle_tol=None,
)
locate(
points, queries, *, domain, ids=None,
duplicate_check='off', duplicate_threshold=1e-5,
duplicate_wrap=True, duplicate_max_pairs=10,
block_size=None, blocks=None, init_mem=8,
mode='standard', radii=None, return_owner_position=False,
)
ghost_cells(
points, queries, *, domain, ids=None,
duplicate_check='off', duplicate_threshold=1e-5,
duplicate_wrap=True, duplicate_max_pairs=10,
block_size=None, blocks=None, init_mem=8,
mode='standard', radii=None, ghost_radius=None,
return_vertices=True, return_adjacency=True, return_edges=True,
return_edge_shifts=False, edge_shift_search=2, include_empty=True,
validate_edge_shifts=True, repair_edge_shifts=False, edge_shift_tol=None,
)
radii are required when mode='power'; planar and spatial power ghost calls
also require ghost_radius. There is no v0.6.3 forward weights= argument.
Supporting forward call defaults are also part of the observed surface:
| Call | Current optional parameters and defaults |
|---|---|
spatial analyze_tessellation(cells, domain, ...) |
expected_ids=None, mode=None, volume_tol_rel=1e-8, volume_tol_abs=1e-12, check_reciprocity=True, check_plane_mismatch=True, plane_offset_tol=None, plane_angle_tol=None, mark_faces=True |
spatial validate_tessellation(cells, domain, ...) |
expected_ids=None, mode=None, level='basic', require_reciprocity=None, volume tolerances 1e-8/1e-12, plane tolerances None, mark_faces=None |
planar analyze_tessellation(cells, domain, ...) |
expected_ids=None, mode=None, area_tol_rel=1e-8, area_tol_abs=1e-12, check_reciprocity=True, check_line_mismatch=True, line_offset_tol=None, line_angle_tol=None, mark_edges=True |
planar validate_tessellation(cells, domain, ...) |
expected_ids=None, mode=None, level='basic', require_reciprocity=None, area tolerances 1e-8/1e-12, line tolerances None, mark_edges=None |
spatial/planar duplicate_check(points, ...) |
threshold=1e-5, domain=None, wrap=True, mode='raise', max_pairs=10 |
spatial normalize_vertices(cells, ...) |
required domain; tol=None, require_face_shifts=True, copy_cells=True |
spatial normalize_edges_faces(normalized_vertices, ...) |
required domain; tol=None, copy_cells=True |
spatial normalize_topology(cells, ...) |
required domain; tol=None, require_face_shifts=True, copy_cells=True |
planar normalize_vertices(cells, ...) |
required domain; tol=None, require_edge_shifts=True, copy_cells=True |
planar normalize_edges(normalized_vertices, ...) |
required domain; tol=None, copy_cells=True |
planar normalize_topology(cells, ...) |
required domain; tol=None, require_edge_shifts=True, copy_cells=True |
spatial validate_normalized_topology(normalized, domain, ...) |
level='basic', all four checks enabled, max_examples=10 |
planar validate_normalized_topology(normalized, domain, ...) |
level='basic', all four checks enabled, max_examples=10 |
weights_to_radii(weights, ...) |
r_min=0.0, weight_shift=None; returns (radii, applied_shift) |
radii_to_weights(radii) |
no optional parameters; returns squared radii |
Current visualization signatures and defaults
The documented planar visualization entry point is:
pyvoro2.viz2d.plot_tessellation(
cells, *, ax=None, domain=None, show_sites=False, annotate_ids=False,
)
The optional spatial visualization surface is:
VizStyle(
background='0xffffff', site_color='0x777777', site_radius=0.093,
site_label_color='0x000000', site_label_background='0xffffff',
site_label_font_size=8, edge_color='0x1f77b4', edge_line_width=2.5,
domain_color='0x000000', domain_line_width=2.5,
vertex_color='0xff7f0e', vertex_radius=0.04,
vertex_label_color='0x000000', vertex_label_background='0xffffff',
vertex_label_font_size=7, axes_line_width=2.0,
axes_label_font_size=12, axes_color_x='0xff0000',
axes_color_y='0x00aa00', axes_color_z='0x0000ff',
)
make_view(*, width=640, height=480, background='0xffffff')
add_axes(
view, *, origin=(0.0, 0.0, 0.0), length=1.0, line_width=2.0,
label_font_size=12, color_x='0xff0000', color_y='0x00aa00',
color_z='0x0000ff',
)
add_sites(
view, points, *, labels=None, color='0x777777', radius=0.093,
label_color='0x000000', label_background='0xffffff',
label_font_size=8,
)
add_vertices(
view, vertices, *, labels=None, color='0xff7f0e', radius=0.04,
label_color='0x000000', label_background='0xffffff',
label_font_size=7,
)
add_domain_wireframe(view, domain, *, color='0x000000', line_width=2.5)
add_cell_wireframe(view, cell, *, color='0x1f77b4', line_width=2.5)
add_tessellation_wireframe(
view, cells, *, color='0x1f77b4', line_width=2.5, cell_ids=None,
)
view_tessellation(
cells, *, domain=None, show_sites=True, show_site_labels=True,
max_site_labels=200, show_domain=True, show_axes=True, axes_length=None,
wrap_cells=False, cell_ids=None, show_vertices=False,
show_vertex_labels='auto', max_vertex_labels=200, style=None,
width=640, height=480, zoom=True,
)
Characterized v0.6.3 forward return matrix
| Namespace/request | v0.6.3 return |
|---|---|
| spatial default | raw list[dict] |
spatial return_diagnostics=True |
(cells, TessellationDiagnostics) tuple |
spatial tessellation_check='diagnose'|'warn'|'raise' without return_diagnostics |
raw list after the requested check; diagnostics are not returned |
| planar default | raw list[dict] |
planar return_diagnostics=True, with no result/normalization request |
(cells, TessellationDiagnostics) tuple |
planar return_result=True |
PlanarComputeResult |
planar normalize='vertices'|'topology' |
PlanarComputeResult, even when return_result=False |
planar result/normalization plus return_diagnostics=True |
one PlanarComputeResult carrying diagnostics, never a tuple |
planar tessellation_check='diagnose'|'warn'|'raise' without a result or return_diagnostics request |
raw list after the requested check; diagnostics are not returned |
PlanarComputeResult is a frozen, slotted outer dataclass with fields
cells, tessellation_diagnostics=None, normalized_vertices=None, and
normalized_topology=None. Its exact documented conveniences are the
has_tessellation_diagnostics, has_normalized_vertices,
has_normalized_topology, global_vertices, and global_edges properties and
the require_tessellation_diagnostics(), require_normalized_vertices(), and
require_normalized_topology() methods. Its nested raw cell records remain
mutable. There is no spatial counterpart in v0.6.3.
Current raw record schemas and ordering
| Operation | Required/base keys | Optional keys |
|---|---|---|
spatial compute cell |
id, volume, site |
vertices, adjacency, faces; inserted hidden cells also have empty=True |
| spatial face | adjacent_cell, vertices |
adjacent_shift; diagnostic flags orphan, reciprocal_missing, reciprocal_mismatch; annotation fields centroid, normal, area, other_site, intersection, intersection_inside, intersection_centroid_dist, intersection_edge_min_dist |
planar compute cell |
id, area, site |
vertices, adjacency, edges; inserted hidden cells also have empty=True |
| planar edge | adjacent_cell, vertices |
adjacent_shift; diagnostic flags orphan, reciprocal_missing, reciprocal_mismatch; annotation fields midpoint, tangent, normal, length, other_site |
spatial locate |
found, owner_id arrays |
owner_pos when requested |
planar locate |
found, owner_id arrays |
owner_pos when requested |
| spatial ghost cell | normal spatial cell keys plus id=-1, empty, query_index, query |
requested geometry keys |
| planar ghost cell | normal planar cell keys plus id=-1, empty, query_index |
requested geometry keys; unlike spatial ghost records, no query key |
Geometry keys are omitted, not set to None, when the corresponding
return_* switch is false. Wall neighbors retain negative backend IDs.
Nonnegative cell and neighbor IDs are remapped to user ids after computation;
locate.owner_id is remapped in the same way. site remains the generator
coordinate used by the computation and is not replaced by the external ID.
Raw compute output follows backend cell iteration. The characterized ordinary
case returns cells in input/internal-ID order, but consumers should not treat a
raw list position as the public site lookup mechanism. If hidden cells are
actually inserted by include_empty=True, the wrapper sorts by internal site
index before remapping external IDs, yielding a full input-aligned list. With
include_empty=False, hidden power cells are absent and the list is shorter.
For a hidden power cell, include_empty=True inserts id, empty=True, zero
volume/area, site, and empty lists only for requested geometry. Nonempty
records do not gain empty=False. Spatial compute applies its reinsertion
helper whenever include_empty=True; planar compute invokes it only in power
mode. Standard diagrams ordinarily have no hidden cells, so this asymmetry has
no normal observable effect but is part of the implementation baseline.
Spatial normalized result fields are NormalizedVertices(global_vertices,
cells) and NormalizedTopology(global_vertices, global_edges, global_faces,
cells). Planar fields are NormalizedVertices(global_vertices, cells) and
NormalizedTopology(global_vertices, global_edges, cells).
Current forward diagnostic fields
| Type | Exact dataclass fields |
|---|---|
spatial TessellationIssue |
code, severity, message, examples |
spatial TessellationDiagnostics |
domain_volume, sum_cell_volume, volume_ratio, volume_gap, volume_overlap, n_sites_expected, n_cells_returned, missing_ids, empty_ids, face_shift_available, reciprocity_checked, n_faces_total, n_faces_orphan, n_faces_mismatched, issues, ok_volume, ok_reciprocity, ok |
planar TessellationIssue |
code, severity, message, examples |
planar TessellationDiagnostics |
domain_area, sum_cell_area, area_ratio, area_gap, area_overlap, n_sites_expected, n_cells_returned, missing_ids, empty_ids, edge_shift_available, reciprocity_checked, n_edges_total, n_edges_orphan, n_edges_mismatched, issues, ok_area, ok_reciprocity, ok |
spatial NormalizationDiagnostics |
n_cells, n_global_vertices, n_global_edges, n_global_faces, is_periodic_domain, fully_periodic_domain, has_wall_faces, n_vertex_face_shift_mismatch, n_face_vertex_set_mismatch, n_vertices_low_incidence, n_edges_low_incidence, n_cells_bad_euler, issues, ok_vertex_face_shift, ok_face_vertex_sets, ok_incidence, ok_euler, ok |
planar NormalizationDiagnostics |
n_cells, n_global_vertices, n_global_edges, is_periodic_domain, fully_periodic_domain, has_wall_edges, n_vertex_edge_shift_mismatch, n_edge_vertex_set_mismatch, n_vertices_low_incidence, n_cells_bad_polygon, issues, ok_vertex_edge_shift, ok_edge_vertex_sets, ok_incidence, ok_polygon, ok |
Current inverse signatures and constructor defaults
The high-level and advanced call defaults are:
| Call | Required inputs; current keyword defaults |
|---|---|
resolve_pair_bisector_constraints(points, constraints, ...) |
measurement='fraction', domain=None, ids=None, index_mode='index', image='nearest', image_search=1, confidence=None, allow_empty=False |
fit_power_weights(points, constraints, ...) |
resolver defaults above except allow_empty is internal; model=None, r_min=0.0, weight_shift=None, solver='auto', max_iter=2000, rho=1.0, tol_abs=1e-6, tol_rel=1e-5, connectivity_check='warn' |
build_power_fit_problem(constraints, ...) |
model=None |
build_power_fit_result(problem, weights, ...) |
solver='external', status='optimal', status_detail=None, converged=True, n_iter=0, warnings=(), canonicalize_gauge=True, r_min=0.0, weight_shift=None |
match_realized_pairs(points, ...) |
required keyword-only domain, radii, constraints; return_boundary_measure=False, return_cells=False, return_tessellation_diagnostics=False, tessellation_check='diagnose', unaccounted_pair_check='diagnose' |
solve_self_consistent_power_weights(points, constraints, ...) |
required keyword-only domain; resolver defaults; model=None, active0=None, options=None, r_min=0.0, weight_shift=None, fit_solver='auto', fit_max_iter=2000, fit_rho=1.0, fit_tol_abs=1e-6, fit_tol_rel=1e-5, all four return switches False, tessellation_check='diagnose', connectivity_check='warn', unaccounted_pair_check='warn' |
build_fit_report(result, constraints, ...) |
use_ids=False |
build_realized_report(diagnostics, constraints, ...) |
use_ids=False |
build_active_set_report(result, ...) |
use_ids=False |
dumps_report_json(report, ...) |
indent=2, sort_keys=False |
write_report_json(report, path, ...) |
indent=2, sort_keys=False |
The objective/model constructors are:
SquaredLoss()
HuberLoss(delta=1.0)
Interval(lower, upper)
FixedValue(value)
SoftIntervalPenalty(lower, upper, strength)
ExponentialBoundaryPenalty(
lower=0.0, upper=1.0, margin=0.02,
strength=1.0, tau=0.01,
)
ReciprocalBoundaryPenalty(
lower=0.0, upper=1.0, margin=0.05,
strength=1.0, epsilon=1e-6,
)
L2Regularization(strength=0.0, reference=None)
FitModel(
mismatch=SquaredLoss(), feasible=None, penalties=(),
regularization=L2Regularization(),
)
ActiveSetOptions(
add_after=1, drop_after=2, relax=1.0, max_iter=25,
cycle_window=8, weight_step_tol=1e-8,
)
Current inverse result fields
The primary containers have the following exact dataclass fields:
| Type | Fields |
|---|---|
PairBisectorConstraints |
n_points, i, j, shifts, target, confidence, measurement, distance, distance2, delta, target_fraction, target_position, input_index, explicit_shift, ids, warnings |
PowerFitProblem |
constraints, model, alpha, beta, z_obs, edge_weight, regularization_strength, regularization_reference, offset_identifying_constraint_mask, bounds, connectivity, hard_feasible, hard_conflict |
PowerWeightFitResult |
status, hard_feasible, weights, radii, weight_shift, measurement, target, predicted, predicted_fraction, predicted_position, residuals, rms_residual, max_residual, used_shifts, solver, n_iter, converged, conflict, warnings, status_detail, connectivity, edge_diagnostics, objective_breakdown |
RealizedPairDiagnostics |
realized, unrealized, realized_same_shift, realized_other_shift, realized_shifts, endpoint_i_empty, endpoint_j_empty, boundary_measure, cells, tessellation_diagnostics, unaccounted_pairs, warnings |
PairConstraintDiagnostics |
site_i, site_j, shift, target, confidence, predicted, predicted_fraction, predicted_position, residuals, active, realized, realized_same_shift, realized_other_shift, realized_shifts, endpoint_i_empty, endpoint_j_empty, boundary_measure, toggle_count, realized_toggle_count, first_realized_iter, last_realized_iter, marginal, status |
SelfConsistentPowerFitResult |
constraints, fit, realized, diagnostics, active_mask, n_outer_iter, converged, termination, cycle_length, marginal_constraints, rms_residual_all, max_residual_all, tessellation_diagnostics, history, path_summary, warnings, connectivity |
PowerFitProblem.offset_identifying_constraint_mask retains its historical
field name and values for numerical compatibility. It is the model-coupling
mask used to decompose solver subproblems: positive-confidence rows are
included, and hard restrictions or penalties make their affected rows part of
the same numerical subproblem. It is not the informative observation mask and
does not claim data identification or unique objective selection.
Supporting fields are exact as follows:
| Type | Fields |
|---|---|
PowerFitBounds |
measurement_lower, measurement_upper, difference_lower, difference_upper |
PowerFitPredictions |
difference, fraction, position, measurement |
PowerFitObjectiveBreakdown |
total, mismatch, penalties_total, penalty_terms, regularization, hard_constraints_satisfied, hard_max_violation |
AlgebraicEdgeDiagnostics |
alpha, beta, z_obs, z_fit, residual, edge_weight, weighted_l2, weighted_rmse, rmse, mae |
ConstraintGraphDiagnostics |
n_points, n_constraints, n_edges, isolated_points, connected_components, fully_connected; property n_components |
ConnectivityDiagnostics |
unconstrained_points, candidate_graph, effective_graph, active_graph=None, active_effective_graph=None, candidate_offsets_identified_by_data=False, active_offsets_identified_by_data=None, offsets_identified_in_objective=False, gauge_policy='', messages=() |
HardConstraintConflictTerm |
constraint_index, site_i, site_j, relation, bound_value |
HardConstraintConflict |
component_nodes, cycle_nodes, terms, message; property constraint_indices |
UnaccountedRealizedPair |
site_i, site_j, realized_shifts, boundary_measure=None |
ActiveSetIteration |
iteration, n_active, n_realized, n_added, n_removed, rms_residual_all, max_residual_all, weight_step_norm, n_active_fit, fit_active_graph_n_components, fit_active_effective_graph_n_components, fit_active_offsets_identified_by_data, n_unaccounted_pairs |
ActiveSetPathSummary |
n_iterations, ever_fit_active_graph_disconnected, ever_fit_active_effective_graph_disconnected, ever_fit_active_offsets_unidentified_by_data, ever_unaccounted_pairs, max_fit_active_graph_components, max_fit_active_effective_graph_components, max_n_unaccounted_pairs, first_fit_active_graph_disconnected_iter, first_fit_active_effective_graph_disconnected_iter, first_unaccounted_pairs_iter |
The public inverse dataclasses are generally frozen and slotted.
PairBisectorConstraints, PowerFitProblem, PowerFitBounds,
PowerFitPredictions, and AlgebraicEdgeDiagnostics copy their owned arrays
into read-only arrays. PowerWeightFitResult, realization diagnostics, and
active-set result containers do not deep-freeze every contained array; callers
must not infer deep immutability from the frozen outer dataclass.
Issue #13 preserves those exact dataclass fields and adds the following provisional, non-copying access paths:
| Layer | Access path | Existing data exposed |
|---|---|---|
| Fitted state | SeparatorFitResult.state |
weights as mathematical_weights, backend radii, and compatibility weight_shift as global_representation_shift |
| Identification | SeparatorFitResult.identification |
informative positive-confidence components, global-gauge identification (False for separator data), observational component-offset identification, conservative objective selection, component-alignment policy, sites isolated in the informative graph as unconstrained_sites, and connectivity (whose compatibility unconstrained_points remains candidate-based) |
| Observations | SeparatorFitResult.observation_view(observations) |
measurement targets, confidence from the supplied resolved observations, predictions in all existing forms, residuals/summaries, and requested shifts; the supplied set must be the originating or a fully equivalent resolved set |
| Objective | SeparatorFitResult.objective |
existing objective_breakdown object |
| Algebraic diagnostics | SeparatorFitResult.algebraic |
existing edge_diagnostics and connectivity objects; no graph-operator representation |
| Fixed solver termination | SeparatorFitResult.solver_termination |
status/detail, backend, iterations, convergence, hard feasibility, conflict, and warnings |
| Requested-image matching | RealizedPairDiagnostics.requested_image_matching |
any/same-shift/other-shift realization, realized shifts, and unrealized indices |
| Realized geometry | RealizedPairDiagnostics.geometry |
empty endpoints, optional boundary measure/cells/tessellation diagnostics, unaccounted pairs, and warnings |
| Active-set organization | SelfConsistentPowerFitResult.inner_fit, .final_realization, .candidate_diagnostics, .outer_termination, .path |
existing final objects, outer termination, active mask, marginals, history, and path summary |
Issue #14 preserves the exact SeparatorFitProblem dataclass fields and adds
two provisional computed properties:
| Mathematical layer | Access path | Contract |
|---|---|---|
| Observation multigraph | SeparatorFitProblem.observation_graph |
SeparatorObservationGraphView with site count, distinct observation rows, oriented endpoints, input indices, requested shifts, shared alpha, beta, z_obs, and rho arrays, a positive-confidence informative mask, existing connectivity, and dense/optional-SciPy incidence conversion |
| Quadratic normal operator | SeparatorFitProblem.quadratic_operator |
SeparatorQuadraticOperatorView with matrix-free and dense/optional-SciPy observation Laplacian and L2-regularized normal operators, observation_rhs, regularized_normal_rhs, regularization data, hard-bound metadata, and component/nullity interpretation |
The incidence matrix has shape (n_sites, n_observations) and column r
equal to +1 at site_i[r] and -1 at site_j[r]. Every resolved row is a
column, including repeats, periodic parallel observations, and zero-confidence
rows. The latter have informative_mask[r] == False and rho[r] == 0, so they
do not connect informative components or contribute to the observation
Laplacian and right-hand side.
The quadratic view is available only for SquaredLoss with no scalar
penalties. Optional L2 regularization is included exactly. Hard interval or
equality restrictions may coexist but remain visible through problem.bounds;
the view reports that unconstrained normal equations do not characterize a
constrained fit in general. Huber mismatch and models with scalar penalties
retain the graph view but reject quadratic_operator rather than presenting a
partial system as the full objective. Sparse conversion imports SciPy lazily;
SciPy is neither a runtime dependency nor a solver backend in issue #14.
The canonical component_alignment_policy view value is the same stored string
as compatibility-facing ConnectivityDiagnostics.gauge_policy; only the access
name is clarified. global_representation_shift is the compatibility
weight_shift value used for backend-radius conversion: it selects a backend
representation within the global geometric gauge, is distinct from independent
component offsets, and is not information recovered from observations. All
array-valued views share the arrays already owned by their result or
resolved-observation source.
The connectivity effective_graph and active_effective_graph contain only
positive-confidence rows. The corresponding *_identified_by_data fields are
true exactly when their informative graph is connected. The compatibility
field offsets_identified_in_objective is conservative: it is true when the
relevant informative graph is connected or positive L2 regularization
guarantees selection of otherwise free offsets. Hard restrictions and scalar
penalties do not make these fields true. An exact hard equality can fix an
offset in a particular problem, but that separate constraint-identifiability
case is outside the current view rather than generalized prematurely.
The private originating-observation association used by observation_view(...)
survives shallow and deep copying, pickle round trips, and
dataclasses.replace(...). It is an init-only implementation detail rather
than an additional public dataclass field. To let dataclasses.replace(...)
carry it, inspect.signature(SeparatorFitResult) includes the optional private
keyword-only parameter _originating_observations_init=None; every established
public parameter, default, positional call, and dataclasses.fields(...) entry
is unchanged. Results constructed directly through the existing public field
arguments, without that association, cannot safely combine unknown observation
metadata with fitted predictions, so the accessor raises ValueError.
The generated reference also documents these result/problem conveniences:
PairBisectorConstraints.pair_labels(*, use_ids=False)
PairBisectorConstraints.to_records(*, use_ids=False)
PairBisectorConstraints.subset(mask)
PowerFitProblem.observation_graph
PowerFitProblem.quadratic_operator
PowerFitProblem.canonicalize_gauge(weights)
RealizedPairDiagnostics.to_records(constraints, *, use_ids=False)
RealizedPairDiagnostics.unaccounted_records(*, ids=None)
RealizedPairDiagnostics.to_report(constraints, *, use_ids=False)
PairConstraintDiagnostics.to_records(*, ids=None)
SelfConsistentPowerFitResult.to_records(*, use_ids=False)
SelfConsistentPowerFitResult.to_report(*, use_ids=False)
UnaccountedRealizedPair.to_record(*, ids=None)
Current inverse record schemas
Record order follows constraint order. use_ids=True substitutes external site
labels where the relevant container has ids.
| Producer | Exact keys |
|---|---|
PairBisectorConstraints.to_records() |
constraint_index, site_i, site_j, shift, target, confidence, measurement, distance, target_fraction, target_position, input_index, explicit_shift |
PowerWeightFitResult.to_records(...) |
constraint_index, site_i, site_j, shift, measurement, target, predicted, predicted_fraction, predicted_position, residual, alpha, beta, z_obs, z_fit, algebraic_residual, edge_weight |
RealizedPairDiagnostics.to_records(...) |
constraint_index, site_i, site_j, shift, realized, realized_same_shift, realized_other_shift, realized_shifts, endpoint_i_empty, endpoint_j_empty, boundary_measure |
PairConstraintDiagnostics.to_records(...) / active result |
constraint_index, site_i, site_j, shift, target, confidence, predicted, predicted_fraction, predicted_position, residual, active, realized, realized_same_shift, realized_other_shift, realized_shifts, endpoint_i_empty, endpoint_j_empty, boundary_measure, toggle_count, realized_toggle_count, first_realized_iter, last_realized_iter, marginal, status |
HardConstraintConflictTerm.to_record() |
constraint_index, site_i, site_j, relation, bound_value |
UnaccountedRealizedPair.to_record() |
site_i, site_j, realized_shifts, boundary_measure |
Measurement-space residual and algebraic z_obs - z_fit are distinct.
Periodic shifts are integer tuples of the resolved dimension. A confidence-zero
row remains in candidate records but never identifies an informative graph
edge. Configured hard restrictions or penalties may still constrain the row's
predicted separator value; that model coupling is separate from observational
identification.
Current inverse report schemas
| Report | Exact top-level keys | Exact summary keys |
|---|---|---|
| fit | kind, summary, constraints, fit_records, edge_diagnostics, objective_breakdown, weights, radii, weight_shift, used_shifts, warnings, conflict, connectivity |
status, is_optimal, is_infeasible, hard_feasible, solver, measurement, n_constraints, n_points, converged, status_detail, n_iter, rms_residual, max_residual, conflicting_constraint_indices |
| realized | kind, summary, records, unrealized, unaccounted_pairs, warnings, tessellation_diagnostics |
n_constraints, n_realized, n_same_shift, n_other_shift, n_unrealized, n_unaccounted_pairs |
| active set | kind, summary, constraints, fit, realized, diagnostics, marginal_records, history, path_summary, tessellation_diagnostics, warnings, connectivity |
termination, converged, n_outer_iter, cycle_length, n_constraints, n_active_final, n_realized_final, rms_residual_all, max_residual_all, marginal_constraint_indices |
Nested fit edge_diagnostics uses the fields of
AlgebraicEdgeDiagnostics; objective_breakdown uses the fields of
PowerFitObjectiveBreakdown. Connectivity records contain
unconstrained_points, candidate/effective/active graph records, both
data-identification flags, offsets_identified_in_objective, gauge_policy,
and messages. Graph records contain n_points, n_constraints, n_edges,
isolated_points, connected_components, n_components, and
fully_connected.
Active history rows contain iteration, n_active, n_realized, n_added,
n_removed, rms_residual_all, max_residual_all, weight_step_norm,
n_active_fit, the two fit-active graph component counts,
fit_active_offsets_identified_by_data, and n_unaccounted_pairs. Path summary
records contain all ActiveSetPathSummary fields. Tessellation report records
provide dimension-neutral measure/boundary keys plus the corresponding 2D
area/edge or 3D volume/face aliases.
Issue #13 does not add, remove, or rename report keys. Existing fit report
state keys (weights, radii, weight_shift), connectivity, observation
records/summaries, objective_breakdown, edge_diagnostics, and solver
summary/conflict/warnings correspond respectively to the state,
identification, observations, objective, algebraic, and solver layers.
Realized records/unrealized describe requested-image matching, while
unaccounted pairs, optional record geometry, and tessellation diagnostics
describe realized geometry. Active fit, realized, diagnostics, summary,
history, and path_summary describe the final inner fit, final realization,
per-candidate diagnostics, outer termination, and active-set path.
Calls exercised by repository examples
The source notebooks use the raw spatial forward calls and the historical top-level inverse imports. In particular, the compatibility set needed to keep the current notebooks reproducible is:
Box, OrthorhombicCell, PeriodicCell, compute, locate, ghost_cells,
normalize_vertices, normalize_topology, annotate_face_properties,
resolve_pair_bisector_constraints, FitModel, SquaredLoss, Interval, FixedValue,
ExponentialBoundaryPenalty, fit_power_weights, match_realized_pairs,
ActiveSetOptions, solve_self_consistent_power_weights, dumps_report_json,
pyvoro2.viz3d.VizStyle, pyvoro2.viz3d.view_tessellation
They also call to_records(...), to_report(...), and conflict record helpers.
Notebook execution/output publication itself belongs to issue #20. This
baseline records the callable paths that issue #12 preserves while the current
source notebooks now use preferred v0.7 imports.
No manuscript program or paper environment is stored in this repository. The paper-style numerical regression subset is therefore deferred to issue #15, while the documented v0.6.3 algebraic formulas, periodic-image semantics, and top-level calls above remain the compatibility baseline. The unmilestoned manuscript figure/reference work remains issue #19.
Chemistry-neutral downstream requirements captured by the baseline
A chemvoro-shaped caller needs to be able to:
- keep arbitrary downstream metadata outside pyvoro2 while passing stable integer external IDs;
- resolve separator observations by those IDs and preserve explicit periodic image shifts;
- fit weights, distinguish measurement and algebraic residuals, and inspect component-offset identification;
- realize the fitted radii, detect empty endpoints and wrong/unaccounted realized pairs, and request boundary measure;
- export records/reports without importing private modules; and
- avoid relying on raw cell-list position as the mapping back to downstream objects.
These are requirements for the preferred v0.7 surfaces, not permission to add chemistry-specific models or metadata containers to pyvoro2.
Baseline reconciliation with accepted ADRs
The observed v0.6.3 baseline does not contradict ADR 0003, ADR 0004, or ADR 0005. It exposes transition conditions that those decisions already account for:
- current power computation is radius-first and the conversion implementation
is owned by
pyvoro2.powerfit, while ADR 0002 and ADR 0004 require mathematical weight semantics and neutral transform ownership in v0.7; - current separator implementation and broad imports live under
pyvoro2.powerfitand top-levelpyvoro2, while ADR 0004 deliberately keeps those paths as v0.7 compatibility shims during the ownership move; and - current spatial and planar compute calls return different raw/structured variants, while ADR 0005 deliberately changes the preferred default and preserves the characterized variants through explicit compatibility routes.
These are planned migrations rather than incompatible scientific meanings. No WP-01 stop condition was triggered, and dependent implementation may preserve the recorded baseline through the compatibility policy without reopening an accepted decision.
Current v0.7 implementation status
The current development tree owns the two weight/radius conversion
implementations in the private neutral module pyvoro2._weight_transforms.
Top-level pyvoro2, pyvoro2.powerfit, and
pyvoro2.powerfit.transforms expose the same function objects, with the latter
two retained as historical compatibility routes. Separator implementation code
imports the neutral module directly. Issue #7 changed ownership without
changing behavior. Issue #21 then hardened the shared numerical contract:
r_min must be finite and non-negative, and any non-finite intermediate or
result from squaring or applying the representation shift raises ValueError.
Signatures, defaults, global-shift behavior, and valid finite representable
results for those helpers remain the characterized v0.6.3 behavior above.
Issue #8 adds the keyword-only weights=None argument immediately before the
existing radii=None argument on pyvoro2.compute(...) and
pyvoro2.planar.compute(...). In power mode exactly one representation is
required. Weights must have shape (n,), must be finite, and may be positive,
zero, or negative; the required global shift and converted representation must
also remain finite and representable. They are converted with the default
weights_to_radii(weights) policy, which applies one common global
representation shift. Non-finite input, conversion overflow, supplying both
representations, supplying neither, or supplying weights in standard mode
raises ValueError before native tessellation. Standard mode also rejects every
non-None radii= argument before native tessellation rather than preserving
the v0.6.3 behavior of silently ignoring it. Valid radius-based power
computation remains numerically unchanged. Finite representability is
necessary for conversion but does not guarantee a numerically resolvable native
tessellation. Voro++ uses binary64 squared-radius arithmetic, so very large
absolute backend radii**2 values or genuine weight ranges relative to
squared coordinate/domain scales can lose geometric resolution. No universal
safe cutoff is promised; sensitivity depends on scale, geometry, platform, and
compiler, especially for periodic power tessellations.
The private dimension-neutral pyvoro2._power_input resolution path keeps the
validated input weights, resolved backend radii, and representation shift
together for later TessellationResult construction. It imports only the
neutral transform and input-validation helpers. The resolved radii feed native
2D, 3D box/orthorhombic, and 3D triclinic power calls, as well as periodic
edge/face shift inference. locate(...) and ghost_cells(...) signatures are
unchanged.
Issues #9 and #10 implement and wire the public structured result. Both
compute(...) functions expose keyword-only output='result'|'cells' and
return TessellationResult by default. The shared builder receives the final
user-visible raw cells and the exact resolved power input without repeating
native computation, diagnostics, normalization, or annotation. The explicit
raw route preserves the factual v0.6.3 list/tuple behavior above.
PlanarComputeResult is the identical class object as TessellationResult.
Explicit planar return_result= use emits DeprecationWarning and is resolved
through the compatibility matrix below.
Issue #11 now makes pyvoro2.inverse.separator the physical owner of the
existing separator implementation. Its active, constraints, model,
problem, realize, report, solver, and types modules contain the sole
implementations. Canonical modules import only canonical siblings and
neutral/shared pyvoro2 modules. pyvoro2.powerfit and all characterized
historical direct submodules forward explicitly to those canonical objects;
top-level historical separator exports also bind directly to the canonical
package. The weight/radius formulas remain solely in
pyvoro2._weight_transforms, including through the historical
pyvoro2.powerfit.transforms route.
Plain import pyvoro2 as pv retains the historical pv.powerfit attribute
through lazy module-level attribute resolution. The compatibility package is
not loaded until that attribute is accessed, and powerfit is deliberately not
added to pyvoro2.__all__.
This ownership move retains the exact issue-#6 historical names, signatures,
defaults, dataclass fields, pyvoro2.powerfit.__all__, reports, records, and
top-level export set. Canonical class and function __module__ values now name
pyvoro2.inverse.separator modules because there is only one implementation.
Issue #12 implements the accepted canonical terminology as primary class and
function definitions. Historical names are identity aliases to those objects,
so signatures, defaults, dataclass fields, isinstance behavior, numerical
results, records, reports, and tested historical pickle globals continue to
resolve through one implementation. The small pyvoro2.inverse convenience
surface and the larger pyvoro2.inverse.separator advanced surface are now
explicit. Loading pyvoro2.powerfit emits one ordinary hidden-by-default
DeprecationWarning that points to the canonical namespaces and states the
v0.8 removal fixed by ADR 0006.
Issue #13 adds provisional layered views to the existing fixed-fit,
realization, and experimental active-set result objects. It does not change
their dataclass fields, established public constructor parameters, numerical
values, records, report schemas, hard-conflict witnesses, or compatibility
aliases. SeparatorFitResult has the documented optional private keyword-only
init-only parameter used to retain observation identity through
dataclasses.replace(...). Reports now read the established values through the
same public layers where this is non-breaking. The new view type names are
exported only from
pyvoro2.inverse.separator; the small pyvoro2.inverse and historical
pyvoro2.powerfit export sets remain unchanged. Issue #14 adds the two
problem-owned provisional graph/operator views described above. Dense NumPy
and optional lazy SciPy conversion are public inspection paths. Issue #17 adds
solver='sparse' to the existing fixed-fit selector for the primary
unconstrained SquaredLoss workflow, including optional L2 regularization.
solver='auto' remains dense, so no automatic size policy or SciPy dependency
is introduced. The existing SeparatorFitResult.solver flat field and
solver_termination.backend view report sparse when that path is used.
Huber mismatch, hard restrictions, scalar penalties, and experimental
active-set refinement do not claim sparse support.
Issue #15 adds the repository-owned preferred-API integration and regression
assets used to validate this contract. The provisional
match_realized_pairs(...) interface now accepts exactly one of mathematical
weights= (preferred) or backend-compatible radii=. Existing radius calls
remain compatible. Weight input follows the same validated common-shift
conversion as forward compute(...); the shift remains representation
metadata rather than an inverse observation result. The integration workflow
resolves observations and exports records by external ID, retains arbitrary
downstream metadata in an ID-keyed sidecar, consumes structured forward arrays
and aligned boundaries, and never relies on raw backend record order.
Accepted v0.7 contract decisions
The following boundaries are already accepted:
pyvoro2.inverseis the canonical inverse namespace;- separator implementation is owned by
pyvoro2.inverse.separator; pyvoro2.powerfitand broad top-level separator exports are compatibility-only for v0.7, with removal in v0.8;- both forward
compute(...)functions returnpyvoro2.TessellationResultby default; output='cells'is the explicit supported raw-output route;PlanarComputeResultis a compatibility alias during v0.7;- deep immutability of nested raw records is not part of the v0.7 contract.
Lifecycle summary for the preferred v0.7 API
| Surface | v0.7 status | Notes |
|---|---|---|
| Domain classes and domain geometry semantics | Stable | Mature bounded and periodic behavior; capability differences remain explicit by dimension. |
pyvoro2.compute and pyvoro2.planar.compute |
Stable | Direct weight/radius behavior, the common structured default, and explicit raw output are implemented and tested. |
weights= and radii= mathematical meaning |
Stable | Mode-specific rejection/exclusivity, one global representation shift, finite and representable conversion, and empty-cell behavior are part of the contract. |
pyvoro2.TessellationResult core contract |
Stable | The shared class, private construction path, and both public compute integrations are implemented by issues #9 and #10. |
| Detailed optional result conveniences and raw geometry views | Provisional | Refine through implementation and chemvoro-shaped validation. |
pyvoro2.inverse preferred high-level separator workflow |
Stable | Validated normal observations/fit entry point for applications and chemvoro-shaped workflows. |
pyvoro2.inverse.separator advanced problem and operator views |
Provisional | Public for research use, but may evolve before v0.9 prescribed measures and v0.10 mixed problems. |
| Realization-aware active-set API | Experimental | Practical outer algorithm; no universal convergence claim. |
| Optional sparse quadratic backend | Provisional | Explicit solver='sparse' is validated for the primary static quadratic fit; auto remains dense and unsupported branches reject sparse selection. |
pyvoro2.powerfit |
Compatibility-only and deprecated | One-way shim during v0.7; removed in v0.8. |
Broad separator-specific exports from top-level pyvoro2 |
Compatibility-only and deprecated | New code imports from pyvoro2.inverse; removed in v0.8. |
| Native extension and solver-internal modules | Internal | No compatibility guarantee. |
Documented module-route status
Objects imported from these documented modules retain the lifecycle status assigned above. The module route itself has the following status:
| Module route | v0.7 status |
|---|---|
pyvoro2.api, domains, diagnostics, duplicates, face_properties, normalize, validation |
Stable |
pyvoro2.edge_properties |
Stable for its documented annotation helper |
pyvoro2.result |
Stable module route for TessellationResult; direct construction remains provisional |
pyvoro2.viz2d, pyvoro2.viz3d |
Provisional optional conveniences |
pyvoro2.planar.api, domains, diagnostics, duplicates, normalize, validation |
Stable |
pyvoro2.planar.result |
Compatibility-only and deprecated because it exposes PlanarComputeResult; removed in v0.8 |
pyvoro2.inverse |
Stable high-level route |
pyvoro2.inverse.separator and its non-active submodules |
Mixed route: stable high-level core names, provisional advanced objects, and compatibility-only historical aliases |
pyvoro2.inverse.separator.active |
Experimental |
pyvoro2.powerfit and its direct submodules |
Compatibility-only and deprecated; removed in v0.8 |
underscore-prefixed Python helpers and native _core/_core2d extensions |
Internal |
Spatial forward namespace: pyvoro2
Stable v0.7 surface
| Group | Names / behavior | v0.7 status |
|---|---|---|
| Domains | Box, OrthorhombicCell, PeriodicCell |
Stable |
| Operations | compute, locate, ghost_cells |
Stable |
| Structured result | TessellationResult |
Stable |
| Weight transforms | weights_to_radii, radii_to_weights |
Stable; neutral implementation requires finite inputs and finite representable results |
| Tessellation diagnostics | TessellationDiagnostics, TessellationIssue, TessellationError, analyze_tessellation, validate_tessellation |
Stable |
| Duplicate handling | DuplicatePair, DuplicateError, duplicate_check |
Stable |
| Geometry annotations | annotate_face_properties |
Stable |
| Normalization | NormalizedVertices, NormalizedTopology, normalization and validation helpers |
Stable |
| Package metadata | __version__, planar |
Stable |
Compatibility-only top-level inverse names
The following v0.6.3 exports remain available during v0.7 but are not preferred for new code:
PairBisectorConstraints
resolve_pair_bisector_constraints
SquaredLoss
HuberLoss
Interval
FixedValue
SoftIntervalPenalty
ExponentialBoundaryPenalty
ReciprocalBoundaryPenalty
L2Regularization
FitModel
AlgebraicEdgeDiagnostics
ConstraintGraphDiagnostics
ConnectivityDiagnostics
ConnectivityDiagnosticsError
HardConstraintConflictTerm
HardConstraintConflict
PowerWeightFitResult
RealizedPairDiagnostics
UnaccountedRealizedPair
UnaccountedRealizedPairError
build_fit_report
build_realized_report
build_active_set_report
dumps_report_json
write_report_json
ActiveSetOptions
ActiveSetIteration
ActiveSetPathSummary
PairConstraintDiagnostics
SelfConsistentPowerFitResult
fit_power_weights
match_realized_pairs
solve_self_consistent_power_weights
Removal: v0.8, fixed by ADR 0006.
Planar namespace: pyvoro2.planar
| Group | Names / behavior | v0.7 status |
|---|---|---|
| Domains | Box, RectangularCell |
Stable |
| Operations | compute, locate, ghost_cells |
Stable |
| Structured result | TessellationResult re-export |
Stable |
| Historical result name | PlanarComputeResult |
Compatibility-only and deprecated identity alias to TessellationResult; removed in v0.8 |
| Diagnostics and validation | Planar tessellation and normalization diagnostics | Stable |
| Duplicate handling and annotations | duplicate_check, annotate_edge_properties |
Stable |
| Normalization | Planar normalization helpers and result objects | Stable |
| Visualization | plot_tessellation |
Provisional optional convenience |
Canonical inverse namespace: pyvoro2.inverse
Preferred high-level separator API
Issue #12 implements this exact pyvoro2.inverse.__all__:
SeparatorObservations
resolve_separator_observations
SeparatorFitResult
fit_weights_from_separators
weights_to_radii
radii_to_weights
The preferred names have these final lifecycle assignments:
| Name | v0.7 status | Meaning |
|---|---|---|
SeparatorObservations |
Stable | Resolved pairwise separator observations, including periodic image labels and confidence. |
resolve_separator_observations |
Stable | Validate and resolve raw separator observations against sites and domain. |
SeparatorFitResult |
Stable | Existing flat fit contract plus layered state, observation, identification, objective, algebraic, and fixed-solver access. |
fit_weights_from_separators |
Stable | Preferred fixed-observation fit entry point. |
weights_to_radii, radii_to_weights |
Stable re-export where useful | Same neutral transforms as top-level pyvoro2. |
Advanced separator API
pyvoro2.inverse.separator.__all__ contains exactly the following 58 names:
SeparatorObservations
resolve_separator_observations
SeparatorFitProblem
SeparatorFitResult
fit_weights_from_separators
SeparatorFitStateView
SeparatorIdentificationView
SeparatorObservationView
SeparatorAlgebraicView
SeparatorSolverTerminationView
SeparatorObservationGraphView
SeparatorQuadraticOperatorView
PairBisectorConstraints
resolve_pair_bisector_constraints
SquaredLoss
HuberLoss
Interval
FixedValue
SoftIntervalPenalty
ExponentialBoundaryPenalty
ReciprocalBoundaryPenalty
L2Regularization
FitModel
AlgebraicEdgeDiagnostics
ConstraintGraphDiagnostics
ConnectivityDiagnostics
ConnectivityDiagnosticsError
HardConstraintConflictTerm
HardConstraintConflict
PowerFitBounds
PowerFitPredictions
PowerFitObjectiveBreakdown
PowerFitProblem
PowerWeightFitResult
build_power_fit_problem
build_power_fit_result
RequestedImageMatchView
RealizedGeometryView
RealizedPairDiagnostics
UnaccountedRealizedPair
UnaccountedRealizedPairError
build_fit_report
build_realized_report
build_active_set_report
dumps_report_json
write_report_json
ActiveSetOptions
ActiveSetIteration
ActiveSetPathSummary
ActiveSetTerminationView
ActiveSetPathView
PairConstraintDiagnostics
SelfConsistentPowerFitResult
fit_power_weights
match_realized_pairs
solve_self_consistent_power_weights
radii_to_weights
weights_to_radii
The canonical core and neutral transforms have the statuses assigned above. The objective model, problem construction/evaluation, fixed-fit and realization view types, realization, reporting, and diagnostic objects are initially provisional. The active-set outer workflow and its options, termination/path views, iteration, path, diagnostic, and result objects are experimental and separator-specific.
The exact v0.7 compatibility identity map is:
| Historical name | Canonical v0.7 name | Relationship and lifecycle |
|---|---|---|
PairBisectorConstraints |
SeparatorObservations |
Identity alias; historical name compatibility-only through v0.7 |
resolve_pair_bisector_constraints |
resolve_separator_observations |
Identity alias; historical name compatibility-only through v0.7 |
PowerFitProblem |
SeparatorFitProblem |
Identity alias; historical name compatibility-only through v0.7 |
PowerWeightFitResult |
SeparatorFitResult |
Identity alias; historical name compatibility-only through v0.7 |
fit_power_weights |
fit_weights_from_separators |
Identity alias; historical name compatibility-only through v0.7 |
The accepted provisional advanced surfaces include:
SeparatorFitProblemand problem-building/evaluation helpers;- problem-owned
SeparatorObservationGraphViewandSeparatorQuadraticOperatorView, including dense NumPy and optional lazy SciPy conversions; the explicit sparse solver consumes this operator through the separate fixed-fit entry point; - objective model pieces such as squared/Huber losses, hard intervals, penalties, and regularization;
- graph, connectivity, incidence, Laplacian, and objective-breakdown views;
- result packaging for externally computed weights;
- layered fixed-fit and realization views that reference existing result data;
- realization matching and record/report builders.
The realization matcher accepts weight-first and radius-representation inputs as mutually exclusive routes. New workflows use fitted mathematical weights; the radius route remains available for compatibility with existing advanced callers.
The active-set outer workflow and its path/result types remain experimental. The explicit SciPy sparse quadratic backend is provisional: it is supported for large static sparse quadratic graphs but does not extend to Huber, hard, penalty, or active-set branches.
pyvoro2.powerfit.__all__ remains the exact 42-name historical list recorded
in the v0.6.3 baseline section. It deliberately does not export the canonical
names and contains no implementation logic. The broad top-level historical
separator set likewise remains unchanged, and none of the five new canonical
names is added to top-level pyvoro2.
Forward return contract
Implemented common data contract
Issues #9 and #10 implement one frozen, slotted TessellationResult class and export
the identical class object as both pyvoro2.TessellationResult and
pyvoro2.planar.TessellationResult. Its private shared builder aligns cells by
final external ID, represents omitted empty cells explicitly in aligned
arrays, and does not invoke native computation, diagnostics, normalization, or
boundary annotation.
The stable fields are exact:
| Field | Lifecycle | Semantics |
|---|---|---|
dimension |
Stable | Explicit 2 or 3. |
domain |
Stable | Validated domain used by the computation. |
mode |
Stable | "standard" or "power". |
sites |
Stable | Read-only owned (n, dimension) copy of validated input coordinates in original input order. |
ids |
Stable | Read-only owned (n,) external-ID array in original input order; omitted IDs become np.arange(n, dtype=np.int64). |
cells |
Stable | Exact supplied raw-cell list after ID remapping; the list, dictionaries, and nested records are not copied or frozen. |
cell_measures |
Stable | Read-only owned (n,) construction-time snapshot of areas or volumes aligned with input order; hidden cells are zero. |
empty_mask |
Stable | Read-only owned boolean (n,) construction-time snapshot aligned with input order, including raw records omitted by include_empty=False. |
input_weights |
Stable | Read-only owned mathematical input weights for weight-first power input; otherwise None. |
backend_radii |
Stable | Read-only owned exact native power radii; None in standard mode. |
representation_shift |
Stable | Finite common additive shift for weight-first conversion; None for standard or direct-radius input. |
tessellation_diagnostics |
Stable | Existing dimension-specific diagnostics when computed; otherwise None. |
normalized_vertices |
Stable | Existing dimension-specific vertex normalization when computed; otherwise None. |
normalized_topology |
Stable | Existing dimension-specific topology normalization when computed; otherwise None. |
The following convenience surface remains provisional:
| Convenience | Lifecycle | Semantics |
|---|---|---|
measure_kind |
Provisional | "area" in 2D or "volume" in 3D. |
boundary_kind |
Provisional | "edges" in 2D or "faces" in 3D. |
has_tessellation_diagnostics, has_normalized_vertices, has_normalized_topology |
Provisional | Distinguish absent optional objects from present objects. |
has_boundaries, has_periodic_shifts |
Provisional | Report explicit builder capabilities, including available-but-empty geometry. |
require_tessellation_diagnostics(), require_normalized_vertices(), require_normalized_topology() |
Provisional | Return optional objects or raise a clear ValueError. |
require_boundaries() |
Provisional | Return input-order-aligned edge/face collections, using an empty collection for hidden sites, or raise when boundaries were unavailable. |
global_vertices, global_edges |
Provisional compatibility conveniences | Forward to available planar normalized objects, preserving the historical PlanarComputeResult access pattern; otherwise None. |
The outer object prevents field replacement. Its aligned arrays are copies and
are non-writeable, so construction never marks caller-owned arrays read-only.
The raw cells list and its nested dictionaries remain shared and mutable by
design. Later raw-record mutation does not update the cell_measures or
empty_mask snapshots. Boundary access revalidates mutable boundary record
types, current empty flags, required non-empty records, and periodic-shift
fields and raises if mutation made them inconsistent with the recorded
snapshots or capabilities. An empty cell cannot contain realized edge or face
records; both omitted and explicitly empty boundary collections remain valid.
Direct dataclass construction is provisional and validates raw IDs, measures,
empty state, representation metadata, and capability metadata against the
aligned fields. Weight-first metadata must satisfy the shared exact
weight/shift-to-radius transform. Boundary and periodic-shift availability are
private keyword-only construction state supplied by the shared builder;
keeping them as normal dataclass initialization fields preserves them through
dataclasses.replace() without adding stable public result fields. Deep copies
and pickle round trips preserve the exact existing snapshot state rather than
revalidating it against later permitted raw-record mutation; reconstructed
arrays remain owned and read-only, and capability state is preserved.
Preferred compute route
result = pyvoro2.compute(..., output='result')
result = pyvoro2.planar.compute(..., output='result')
Omitting output is equivalent to output='result'. Structured output is
always one TessellationResult, never a tuple. Diagnostics computed because of
return_diagnostics=True or tessellation_check='diagnose'|'warn'|'raise'
are stored in result.tessellation_diagnostics.
Raw output route
cells = pyvoro2.compute(..., output='cells')
cells = pyvoro2.planar.compute(..., output='cells')
This route preserves the established list/tuple behavior. Without
return_diagnostics=True it returns only the raw list, including when a
tessellation check computed diagnostics internally. With
return_diagnostics=True it returns (cells, diagnostics). Raw record schemas,
ordering, external IDs, requested geometry, and numerical behavior remain the
characterized baseline.
Planar compatibility selector matrix
The public compatibility parameter is return_result: bool | None = None.
None means that the selector was omitted and follows the output= contract.
Passing either boolean emits DeprecationWarning; output= is the replacement.
| Planar selection | Result |
|---|---|
| both selectors omitted | TessellationResult |
return_result=None |
same as omitted; no deprecation warning |
output='result' |
TessellationResult |
output='cells' |
historical raw list/tuple route |
return_result=True, output omitted |
TessellationResult |
explicit return_result=False, output omitted, no normalization |
historical raw list/tuple route |
explicit return_result=False, output omitted, normalization requested |
TessellationResult, preserving the historical normalization override |
equivalent explicit output and return_result |
requested route, plus warning |
conflicting explicit output and return_result |
ValueError, plus warning |
explicit output='cells' with normalization |
ValueError |
PlanarComputeResult from both pyvoro2.planar and
pyvoro2.planar.result is an identity alias to pyvoro2.TessellationResult.
Scientifically meaningful semantics to inventory explicitly
The following are API even when no dedicated Python class represents them:
- coordinate units are caller-defined but consistent within one computation;
- power weights have squared-coordinate units;
- positive, zero, and negative finite power weights are valid when the global shift and converted representation remain finite and representable;
- non-finite weight input or conversion overflow raises
ValueErrorbefore native computation; - finite representability does not guarantee a numerically resolvable native
tessellation; Voro++ uses binary64 squared-radius arithmetic, so very large
absolute backend
radii**2values or genuine weight ranges relative to squared coordinate/domain scales can lose geometric resolution. No universal safe cutoff is promised, and periodic power tessellations are particularly sensitive; - backend radii have coordinate units;
- one global additive weight shift leaves the complete power diagram unchanged;
- power-mode
compute(...)requires exactly one ofweights=orradii=, while standard mode rejects both arguments; - valid radius-based power computation remains numerically unchanged;
- direct
weights=input currently belongs to the twocompute(...)functions, not to every forward operation; - backend radii are a shifted representation and are not unique physical radii;
- disconnected separator-observation components have additional unidentified offsets that may change global realization;
- external IDs remain attached to original sites;
- periodic neighbor shifts identify the realized image and are not silently replaced by a nearest image;
- zero-confidence separator rows do not identify weight differences or enter the informative observation graph; hard restrictions and penalties may constrain their predicted values but remain separate from data identification;
- algebraic fit does not imply realized-boundary support;
- empty/hidden cells are represented deterministically according to the chosen output route;
- error/status behavior for infeasibility and wrong-image realization is part of the public scientific contract.
Deprecation and fixed removal schedule
| Surface | v0.7 | v0.8 action |
|---|---|---|
pyvoro2.powerfit |
Compatibility-only and deprecated; loading it emits one hidden-by-default DeprecationWarning naming the canonical namespaces and v0.8 horizon |
Remove |
| Broad top-level separator exports | Compatibility-only; no invasive attribute wrappers during v0.7; documented migration path | Remove from top-level |
| Five mapped historical core names | Compatibility-only and deprecated identity aliases; no per-use warnings | Remove from canonical separator exports |
PlanarComputeResult |
Compatibility-only and deprecated alias to TessellationResult |
Remove |
| Raw cell return | Available through output='cells' |
Continue as explicit route unless a later decision removes it |
Planar return_result= |
Compatibility-only and deprecated | Remove |
Final release review checklist
- [x] Every preferred public import is listed with a lifecycle category.
- [x] Every compatibility alias has a replacement and removal horizon.
- [x]
__all__matches the intended namespace policy. - [x] Forward output modes and diagnostic combinations are characterized.
- [x] Stable
TessellationResultfields and mutable contained values are documented. - [x] Raw record keys used by compatibility tests are listed or referenced.
- [x] Preferred separator names and exact historical aliases are complete.
- [x] Active-set behavior is labelled experimental; the included sparse quadratic backend is labelled provisional and narrowly scoped.
- [x] Default changes and scientific semantics appear in migration notes and release notes.
- [x] The chemvoro-shaped integration workflow uses only stable or deliberately provisional public surfaces.
- [x] The maintainer approved the final inventory on 2026-07-22.