Transform numbers into 3D geometric paths.
A Python library for converting natural numbers into 3D geometric shapes (spatial polylines on an integer lattice).
We use a cellular-automaton scheme that produces a sequence of symbolic steps L/R/U/D, and then interpret these steps as local (orientation-dependent) moves in 3D.
Each number is represented as a 3D path on an integer lattice via a discrete step rule:
- We work with the binary representation MSB → LSB (left-to-right bits).
- Each bit is mapped to one of 4 symbols:
L/R/U/D. - Each symbol is then interpreted as a relative 3D move based on the current orientation (
forward/up/right), so the path is not constrained to a plane.
- First bit:
0→ first stepL1→ first stepR
- Each next bit (only previous step matters):
- if bit =
0:- if previous step was
L→ current stepD - otherwise →
L
- if previous step was
- if bit =
1:- if previous step was
R→ current stepU - otherwise →
R
- if previous step was
- if bit =
We maintain a local frame:
forward(where “go forward” points)up(local up)right = cross(forward, up)
Initial frame:
forward = (0, 0, 1)(along +Z)up = (0, 1, 0)(along +Y)
Step semantics (rotate if needed, then move 1 unit along the new forward):
R: move forwardL: yaw left aroundup, then move forwardU: pitch up aroundright, then move forwardD: pitch down aroundright, then move forward
So the path is built from (0,0,0) by applying these steps.
The representation is:
- Unique: Different numbers produce different paths
- Reversible: You can decode the path back to the original number
- Deterministic: Same number always produces same path
pip install bin2pathOr from source:
git clone https://github.com/Sett11/bin2path.git
cd bin2path
pip install -e .import bin2path
# Encode a number to 3D path
path = bin2path.encode(42)
# Get path data
print(path.vertices) # list of (x,y,z)
print(path.edges) # list of (from_idx, to_idx)
# Decode back to number
number = bin2path.decode(path) # 42
# Visualize
bin2path.visualize(path)
# Extract features for clustering / analysis
f = bin2path.features(path)
print(f['path_length']) # number of steps
print(f['turns']) # number of direction changes (zeros)
print(f['straightness']) # ratio of direct to path distanceimport bin2path
print(bin2path.encode(8).vertices)
# [(0, 0, 0), (0, 0, 1), (1, 0, 1), (1, -1, 1), (1, -1, 0)]encode(number: int) -> Path3D— Convert number to 3D pathdecode(path: Path3D) -> int— Convert path back to numberfeatures(path: Path3D) -> dict— Extract features for clusteringvisualize(path: Path3D, **kwargs)— Render 3D visualizationserialize(path) -> dict— Convert to JSON-serializable dictdeserialize(data) -> Path3D— Restore from dictto_json(path) -> str— Convert to JSON stringfrom_json(json_str) -> Path3D— Parse JSON stringcompare(path1, path2) -> dict— Compare similarity between pathsvalidate(path) -> (bool, list[str])— Validate path correctnessis_valid(path) -> bool— Quick validity checkbatch_encode(numbers) -> list[Path3D]— Encode multiple numbersbatch_decode(paths) -> list[int]— Decode multiple paths
@dataclass
class Path3D:
vertices: list[tuple[int, int, int]] # [(x,y,z), ...]
edges: list[tuple[int, int]] # [(from_idx, to_idx), ...]
metadata: PathMetadata # additional info
@dataclass
class PathMetadata:
original_number: int # original input number
bits_length: int # length of binary representation
first_one_pos: int # position of first 1-bit (MSB index)
step_positions: list[int] # positions of all 1-bits (MSB indices)
start_direction: tuple # starting forward direction (defaults to +Z)The features() function returns a dictionary with:
path_length: Number of edges/stepsturns: Approximate number of bit-0 transitions (bits_length - len(edges))direct_distance: Straight-line distance from start to endstraightness: Ratio of direct distance to path lengthcenter_x,center_y,center_z: Center of mass coordinatesbbox_x,bbox_y,bbox_z: Bounding box dimensionsdisplacement_x,displacement_y,displacement_z: Total displacementdirection_histogram: Count of steps in ±X/±Y/±Z directionsself_intersections: Number of vertex revisits
import bin2path
test_numbers = [0, 1, 2, 42, 100, 12345, 2**10, 999999]
for n in test_numbers:
path = bin2path.encode(n)
decoded = bin2path.decode(path)
assert decoded == n # Always True!import bin2path
path = bin2path.encode(42)
# Basic visualization
bin2path.visualize(path)
# Custom appearance
bin2path.visualize(
path,
figsize=(10, 8),
vertex_color="red",
edge_color="blue",
edge_linewidth=3,
vertex_size=50,
)
# Save to file
bin2path.visualize(path, save_path="my_path.png")
# Different viewing angle
bin2path.visualize(path, azim=45, elev=30)- Python >= 3.10
- matplotlib >= 3.7.0
- numpy >= 1.24.0
MIT License
See the project repository for the detailed specification of the scheme (including the local-orientation rules).