Python API for the OPF (Optimum-Path Forest) library (C++/pybind11 backend)
Project description
opfppy — OPF Pretty Python
opfppy (OPF Pretty PYthon) is a high-level Python API for the
Optimum-Path Forest classifier/clusterer, backed by a C++20/pybind11 extension
(opfpy).
Python Layer Naming Convention
This project has three Python-facing layers, each with a distinct purpose:
| Layer | Package / module | Full name | Purpose |
|---|---|---|---|
| C++ extension | opfpy |
OPF Python | Raw pybind11 bindings — thin bridge to C++; no Python utilities |
| Cython wrapper | opfpy_cython |
OPF Python (Cython) | Typed Cython classes over opfpy; low-level, no high-level helpers |
| Python shim | opfppy |
OPF Pretty PYthon | Full Python API: pretty repr, DistanceMetric enum, high-level workflows |
What opfppy adds over the raw opfpy / opfpy_cython layers
The opfpy and opfpy_cython layers expose only what the C++ binding
provides directly. opfppy adds:
| Feature | opfpy / opfpy_cython |
opfppy |
|---|---|---|
Pretty __repr__ for Node, Subgraph, OPF |
❌ raw <opfpy.Node object …> |
✅ human-readable, head/tail truncation |
DistanceMetric enum (EUCLIDEAN, MANHATTAN, …) |
❌ integer ids only | ✅ named constants + string resolver |
resolve_distance(name/enum/int) |
❌ | ✅ "manhattan", "L1", DistanceMetric.MANHATTAN, 3 all accepted |
register_distance(name, id) |
❌ | ✅ extension point for custom metrics |
| High-level workflow functions | ❌ | ✅ train_and_classify, learn_and_classify, cluster_and_propagate, semi_supervised, … |
| Utility helpers | ❌ | ✅ load, split, merge, normalize, accuracy, info, k_fold, compute_distance_matrix, write/read_distance_matrix |
| Windows DLL setup | ❌ (must be done manually) | ✅ automatic on import opfppy |
| Single bootstrap import | ❌ requires sys.path manipulation |
✅ import opfppy is enough |
Requirements
| Tool | Version |
|---|---|
| Python | ≥ 3.11 |
| C++ compiler | GCC/Clang with C++20 (MSYS2 UCRT64 on Windows) |
| CMake | ≥ 3.16 |
| Conan | 2.x |
| plyfile | ≥ 1.0 |
Building the Extension
# From the project root, inside the MSYS2 UCRT64 shell:
bash ./build_opfpy.sh
The compiled module (opfpy.pyd / opfpy.so) is placed in pythonlib/bin/.
See build_opfpy.md for step-by-step details.
Quick Start
import opfppy # single import — DLL setup done automatically
data = opfppy.Subgraph.from_original_file("../data/boat.dat")
train_sg, test_sg = opfppy.split_subgraph(data, 0.5)
from opfppy.supervised import train_and_classify
acc = train_and_classify(train_sg, test_sg)
print(f"Accuracy: {acc:.2%}")
Package Layout
opfppy/
__init__.py # package root; bootstrap (sys.path, DLL dirs), re-exports
node.py # Node shim class — pretty repr, wrap(), register()
subgraph.py # Subgraph shim class — pretty repr, factory class-methods
opf_class.py # OPF shim class — pretty repr, wrap(), register()
distance.py # DistanceMetric enum, resolve(), register()
ply_adapter.py # SplatSubGraph class, encode/decode SH, PLY loading
utils.py # I/O, split/merge/normalize, accuracy, distance matrix
supervised.py # train, classify, learn, prune helpers
unsupervised.py # cluster, knn_classify, semi_supervised helpers
examples/
example1_supervised.py # supervised OPF, no learning
example2_learning.py # supervised OPF with learning
example3_precomputed_distances.py # distance matrix I/O + supervised OPF
example4_normalization.py # feature normalization + supervised OPF
example5_unsupervised.py # unsupervised clustering + k-NN classify
example6_semi_supervised.py # semi-supervised OPF
example7_ply_subgraph.py # basic PLY → Subgraph conversion
example8_splat_subgraph.py # advanced PLY → SplatSubGraph with metadata
API Reference
opfppy top-level (shim classes)
| Symbol | Description |
|---|---|
Node |
Shim over opfpy.Node — inherits all C++ properties + pretty __repr__ |
Subgraph |
Shim over opfpy.Subgraph — factory class-methods return opfppy.Subgraph |
OPF |
Shim over opfpy.OPF — inherits all C++ methods + pretty __repr__ |
DistanceMetric |
IntEnum: EUCLIDEAN=1 … BRAY_CURTIS=7 |
resolve_distance(x) |
Resolve string / enum / int → integer id |
register_distance(name, id) |
Register a custom metric name |
All opfpy free functions are also re-exported directly from opfppy:
split_subgraph, read_subgraph, write_subgraph, propagate_cluster_labels,
eucl_dist, chi_squared_dist, manhattan_dist, canberra_dist,
squared_chord_dist, squared_chi_squared_dist, bray_curtis_dist,
subgraph_info, k_fold, merge_subgraphs, compute_distance_matrix,
write_distance_matrix, hello.
opfppy.distance
| Symbol | Description |
|---|---|
DistanceMetric |
IntEnum with named constants for all 7 built-in metrics |
resolve(x) |
Accept int, str (case-insensitive, aliases: l1, l2, chi2, bray, …), or DistanceMetric → int |
register(name, id) |
Add a custom metric string alias |
opfppy.ply_adapter
| Symbol | Description |
|---|---|
SplatSubGraph |
Subclass of Subgraph with persistent PLY metadata + import/export |
from_ply_file(path, profile) |
Load Gaussian-splat PLY and return (Subgraph, metadata) dict |
encode_sh_params(l, m) |
Pack SH (l, m) into one byte using offset convention |
decode_sh_params(byte) |
Unpack byte back into (l, m) |
SH Encoding scheme (3 bits degree + 5 bits index with offset):
- Packing:
byte = (l << 5) | ((m + 16) & 0x1F) - Unpacking:
l = (byte >> 5) & 0x07,m = (byte & 0x1F) - 16 - Valid range: l ∈ [0, 7], m ∈ [-16, 15]
- Examples: f_dc_0 → 16 (00010000), f_rest_44 → 115 (01110011)
Profile options:
'full': All 62 Gaussian properties (x, y, z, nx, ny, nz, f_dc_, f_rest_, opacity, scale_, rot_)'compact': 14 essential properties (geometry + DC color + opacity + scale + rotation)
Benchmark results (1000 vertices):
| Metric | Full | Compact | Savings |
|---|---|---|---|
| Load time | 98 ms | 55 ms | 44% faster |
| Features per node | 62 | 14 | 77.4% reduction |
| Access speed (500 nodes) | 4.23 ms | 2.90 ms | 1.46× faster |
opfppy.utils
| Function | Description |
|---|---|
load(path) |
Load subgraph from LibOPF .dat file (original format) |
read(path) |
Read subgraph from OPF training binary format |
write(path, sg) |
Write subgraph to OPF training binary format |
split(sg, pct) |
Label-stratified split into two subgraphs |
merge(sg1, sg2) |
Merge two subgraphs |
k_fold(sg, k) |
Stratified k-fold partition |
normalize(sg) |
Z-score feature normalization in-place |
accuracy(sg) |
Accuracy from label vs truelabel |
info(sg) |
Dict with nnodes, nlabels, nfeats |
load_ply(path, feature_profile) |
Load Gaussian-splat PLY into (Subgraph, metadata) |
compute_distance_matrix(sg, distance) |
Pairwise distance matrix — accepts int / str / DistanceMetric |
write_distance_matrix(mat, path) |
Write binary distance matrix |
read_distance_matrix(path) |
Read binary distance matrix |
Distance IDs / names: 1/"euclidean" · 2/"chi_squared" · 3/"manhattan" ·
4/"canberra" · 5/"squared_chord" · 6/"squared_chi_squared" · 7/"bray_curtis".
Aliases: l1 → manhattan, l2 → euclidean, chi2 → chi_squared, bray → bray_curtis, etc.
opfppy.supervised
| Function | Description |
|---|---|
train(sg_train) |
Train supervised OPF in-place |
classify(sg_train, sg_test) |
Classify test nodes in-place |
train_and_classify(sg_train, sg_test) |
Train + classify; returns accuracy |
learn_and_classify(train, eval, test, n_iter) |
Iterative learning + classify; returns accuracy |
prune(sg_train, sg_eval, tolerance) |
Iterative pruning; returns pruning rate |
opfppy.unsupervised
| Function | Description |
|---|---|
cluster_and_propagate(sg, k) |
Cluster in-place and propagate labels |
create_arcs(sg, k) |
Build k-NN adjacency + node radius in native C++ (opf_CreateArcs) |
compute_pdf(sg) |
Compute Gaussian PDF density on a subgraph with adjacency set (opf_PDF) |
bestk_min_cut(sg, kmin, kmax) |
Run native best-k selection (opf_BestkMinCut) then prepare arcs/PDF |
knn_classify(sg_train, sg_test) |
k-NN classify using stored radii |
semi_supervised(labeled, unlabeled, eval?) |
Semi-supervised learning; returns merged graph |
Low-level C++ extension (opfpy) and Cython wrapper (opfpy_cython)
opfpy is the raw pybind11 binding — the C++ extension module. It exposes
Node, Subgraph, and OPF as plain C-extension types with no Python
utilities. opfpy_cython wraps these in typed Cython classes.
Neither layer provides:
- pretty
__repr__(objects print as<opfpy.Node object at 0x…>) DistanceMetricenum or string distance resolutionresolve_distance/register_distance- workflow helpers (
train_and_classify,normalize,accuracy, etc.) - Windows DLL directory setup
- single-import bootstrap (
sys.pathmust be set manually)
Use opfppy for all application code. Access opfppy._opfpy only when you
need the raw C-extension objects for performance-critical inner loops.
| Symbol | Type | Description |
|---|---|---|
Node |
class | Single graph node with all OPF fields |
Subgraph |
class | Container of nodes + graph metadata |
OPF |
class | Classifier / learner methods (train, classify, learn, create_arcs, destroy_arcs, bestk_min_cut, compute_pdf, cluster, knn_classify, semi_supervised, normalize, accuracy, pruning) |
read_subgraph / write_subgraph |
functions | Binary I/O |
split_subgraph |
function | Stratified split |
propagate_cluster_labels |
function | Label propagation |
eucl_dist, chi_squared_dist, … |
functions | Distance metrics (integer id only) |
subgraph_info |
function | Metadata dict |
k_fold |
function | k-fold partition |
merge_subgraphs |
function | Merge |
compute_distance_matrix |
function | Pairwise distances (integer id only) |
write_distance_matrix / read_distance_matrix |
functions | Distance matrix I/O |
Running the Tests
cd pythonlib
# activate .venv first
python -m unittest discover -v
Expected: 80 tests, OK across Phases 1–6 plus PLY adapter tests.
Running the Examples
cd pythonlib
python examples/example1_supervised.py
python examples/example2_learning.py
python examples/example3_precomputed_distances.py
python examples/example4_normalization.py
python examples/example5_unsupervised.py
python examples/example6_semi_supervised.py
python examples/example7_ply_subgraph.py ../../tools/bridge-server/sample.ply full
python examples/example8_splat_subgraph.py ../../tools/bridge-server/sample.ply
Running the Benchmarks
cd pythonlib
# activate .venv first
python -m unittest test_ply_benchmark.TestPlyBenchmark -v
Expected output: Performance comparison of full vs compact profiles on synthetic 1000-vertex PLY.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file opfppy-0.6.0-cp312-cp312-manylinux_2_35_x86_64.whl.
File metadata
- Download URL: opfppy-0.6.0-cp312-cp312-manylinux_2_35_x86_64.whl
- Upload date:
- Size: 362.7 kB
- Tags: CPython 3.12, manylinux: glibc 2.35+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
27698bbd6bcdde2b336520ab759223933f3b97a9c0f54a7dd3d4c0d35e1558f6
|
|
| MD5 |
f21918177e63b323214cacc1b415287e
|
|
| BLAKE2b-256 |
c8d9fc0a29083cb7a20b5668ce3dfb826588fb4767dbbd7b8d586ba58eebe680
|