Skip to content

Latest commit

 

History

History
98 lines (68 loc) · 2.86 KB

File metadata and controls

98 lines (68 loc) · 2.86 KB

Coordinates

Every positive integer has a unique prime factorization. Binjamin exposes this as a coordinate system for multiscale analysis.

Factorization

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 origin

The result is a Coordinate: a dict mapping prime → exponent. This is the integer's position in prime-exponent space.

Reconstruction

bj.to_int({2: 3, 3: 2, 5: 1})  # 360
bj.to_int({})                    # 1

to_int(factorize(n)) == n for all positive integers.

Backend

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 switching

Results are cached. The cache grows as new integers are encountered.

Divisors

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.

Lattice members

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.

Smallest divisor above a floor

bj.smallest_divisor_gte(360, 50)   # 60
bj.smallest_divisor_gte(360, 1)    # 1
bj.smallest_divisor_gte(360, 360)  # 360

Used internally to snap grain to the nearest valid lattice member.

Vector arithmetic

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) = 200

vec_sub raises ValueError if b does not divide a.

The Coordinate type

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.