Every positive integer has a unique prime factorization. Binjamin exposes this as a coordinate system for multiscale analysis.
import binjamin as bj
bj.factorize(360) # {2: 3, 3: 2, 5: 1} — 360 = 2³ × 3² × 5
bj.factorize(12) # {2: 2, 3: 1} — 12 = 2² × 3
bj.factorize(7) # {7: 1} — prime
bj.factorize(1) # {} — the originThe result is a Coordinate: a dict mapping prime → exponent. This is the integer's position in prime-exponent space.
bj.to_int({2: 3, 3: 2, 5: 1}) # 360
bj.to_int({}) # 1to_int(factorize(n)) == n for all positive integers.
Default: 6k±1 wheel trial division. All primes > 3 are 1 or 5 mod 6, so only those candidates are tested, up to √n.
bj.set_factorization_backend("sympy") # for large integers
bj.set_factorization_backend(my_fn) # custom: fn(n) -> dict[int, int]
bj.clear_factorization_cache() # clear after switchingResults are cached. The cache grows as new integers are encountered.
bj.divisors(12) # (1, 2, 3, 4, 6, 12)
bj.divisors(1) # (1,)
bj.divisors(360) # (1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 18, 20, 24, 30, 36, 40, 45, 60, 72, 90, 120, 180, 360)All positive divisors in ascending order. In lattice terms: all integers whose coordinate is <= the coordinate of n.
bj.lattice_members(360, 10) # (10, 20, 30, 40, 60, 90, 120, 180, 360)Divisors of horizon that are multiples of cbin. These are the valid window sizes.
bj.smallest_divisor_gte(360, 50) # 60
bj.smallest_divisor_gte(360, 1) # 1
bj.smallest_divisor_gte(360, 360) # 360Used internally to snap grain to the nearest valid lattice member.
Coordinate vectors support arithmetic that mirrors integer operations:
| Operation | Integers | Coordinates |
|---|---|---|
| Multiply | a * b |
vec_add(a, b) |
| Divide | a / b |
vec_sub(a, b) |
| Divisibility | a | b |
vec_le(a, b) |
| GCD | gcd(a, b) |
vec_min(a, b) |
| LCM | lcm(a, b) |
vec_max(a, b) |
bj.vec_add({2: 1}, {3: 1}) # {2: 1, 3: 1} — 2 × 3 = 6
bj.vec_sub({2: 2, 3: 1}, {2: 1}) # {2: 1, 3: 1} — 12 / 2 = 6
bj.vec_le({2: 1}, {2: 2, 3: 1}) # True — 2 | 12
bj.vec_min({2: 3}, {2: 1, 5: 2}) # {2: 1} — gcd(8, 50) = 2
bj.vec_max({2: 3}, {2: 1, 5: 2}) # {2: 3, 5: 2} — lcm(8, 50) = 200vec_sub raises ValueError if b does not divide a.
from binjamin import Coordinate
# Coordinate = Dict[int, int] — prime → exponent
c: Coordinate = {2: 3, 3: 2, 5: 1}The empty dict {} is the coordinate of 1 — the origin of the lattice.