Hybrid Blossom-Greedy approach for constructing Eulerian tours on real road graphs.
Project description
Bloomr
Solve the Mixed Chinese Postman Problem on real road networks. Find the shortest route that traverses every street at least once, handling both one-way and two-way streets.
Installation
pip install bloomr
Quick Start
from bloomr import solve_cpp
# Download road network and solve CPP
result = solve_cpp("Monaco")
# View solution
print(result.summary()) # Distance efficiency, route metrics
print(f"GPX route: {result.gpx_path}")
How It Works
Bloomr downloads road networks from OpenStreetMap, identifies degree imbalances caused by one-way streets, and computes near-optimal routes using a hybrid Blossom-Greedy matching approach:
- Blossom algorithm finds optimal pairings for ~98% of imbalanced nodes
- Greedy fallback handles remaining nodes when graph disconnectivity prevents full matching
- Eulerian circuit generates the final route traversing all streets
This hybrid strategy preserves optimality where possible while gracefully handling real-world road network constraints.
API
solve_cpp()
solve_cpp(
place: str = None,
*,
graphml_path: Path = None,
output_dir: Path = None,
network_type: str = "drive_service",
simplify: bool = False,
method: str = "blossom",
verbose: bool = False,
visualize: bool = True
)
Arguments:
place: Location name (e.g., "Jersey, Channel Islands")graphml_path: Path to existing GraphML file (alternative to place)output_dir: Directory for output files (default:solutions/{region})network_type: OSMnx network type -"drive","drive_service","walk","bike", or"all"simplify: Simplify graph topology (default: False)method:"blossom"(optimal, default) or"greedy"(fast approximation)verbose: Enable detailed logging from Rust solvervisualize: Generate route visualization map (requires matplotlib, contextily)
Returns: CPPResult with gpx_path, metrics, and solution files
download_graph()
download_graph(
place: str,
*,
output_dir: Path = None,
network_type: str = "drive_service",
simplify: bool = False,
force: bool = False
) -> Path
Arguments:
place: Location name for OSMnx (e.g., "San Francisco, California")output_dir: Directory for GraphML file (default:graphml_data)network_type: OSMnx network type -"drive","drive_service","walk","bike", or"all"simplify: Simplify graph topology (default: False)force: Force re-download even if cached (default: False)
Returns: Path to saved GraphML file
Example:
from bloomr import download_graph
graph_path = download_graph("San Francisco, California")
result = solve_cpp(graphml_path=graph_path)
Output
Solutions are saved to solutions/{region}/:
{region}_cpp_route.gpx- GPS-ready route file{region}_metrics.json- Efficiency metrics and statistics
Metrics:
distance_efficiency- Proportion of route that's useful coverage (not duplicated)duplication_ratio- Average times each street is traverseddeadhead_percentage- Percentage of route spent repeating streets
Architecture
- Python: OSMnx integration, API, visualization
- Rust: Graph algorithms (Blossom, shortest paths, Eulerian circuits)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file bloomr-0.1.2.tar.gz.
File metadata
- Download URL: bloomr-0.1.2.tar.gz
- Upload date:
- Size: 2.7 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
18b6729b335f2bf090315d89be576cb846216319aafab06090132adfa7582c56
|
|
| MD5 |
21c16ba5d124f7297bb0062e13dd2c58
|
|
| BLAKE2b-256 |
801f8f1fe09491dd65f3c25c08a7493c19f2faff631f2da58ce853e18b8e983c
|
Provenance
The following attestation bundles were made for bloomr-0.1.2.tar.gz:
Publisher:
release.yml on gnathoi/bloomr
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bloomr-0.1.2.tar.gz -
Subject digest:
18b6729b335f2bf090315d89be576cb846216319aafab06090132adfa7582c56 - Sigstore transparency entry: 693363657
- Sigstore integration time:
-
Permalink:
gnathoi/bloomr@7688663a23f7b14ba62382264d6814019fb5574e -
Branch / Tag:
refs/heads/main - Owner: https://github.com/gnathoi
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@7688663a23f7b14ba62382264d6814019fb5574e -
Trigger Event:
pull_request
-
Statement type:
File details
Details for the file bloomr-0.1.2-py3-none-any.whl.
File metadata
- Download URL: bloomr-0.1.2-py3-none-any.whl
- Upload date:
- Size: 2.7 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
df507db684a568c908a4491ba6aa0c67688bfaa2d222ef4895be4ab54e90caaf
|
|
| MD5 |
8c0c23358891803fef36ffef977c0075
|
|
| BLAKE2b-256 |
0a23085f2be623fff1eed308816731c2f044211be61e4f4b4e79c8c3e30b7222
|
Provenance
The following attestation bundles were made for bloomr-0.1.2-py3-none-any.whl:
Publisher:
release.yml on gnathoi/bloomr
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bloomr-0.1.2-py3-none-any.whl -
Subject digest:
df507db684a568c908a4491ba6aa0c67688bfaa2d222ef4895be4ab54e90caaf - Sigstore transparency entry: 693363691
- Sigstore integration time:
-
Permalink:
gnathoi/bloomr@7688663a23f7b14ba62382264d6814019fb5574e -
Branch / Tag:
refs/heads/main - Owner: https://github.com/gnathoi
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@7688663a23f7b14ba62382264d6814019fb5574e -
Trigger Event:
pull_request
-
Statement type: