Find any nontrivial factor of a number
(c) Daniel Strano and the Qrack contributors 2017-2025. All rights reserved.
From PyPi:
pip3 install FindAFactor
From Source: install pybind11, then
pip3 install .
in the root source directory (with setup.py).
Windows users might find Windows Subsystem Linux (WSL) to be the easier and preferred choice for installation.
from FindAFactor import find_a_factor, FactoringMethod
to_factor = 1000
factor = find_a_factor(
to_factor,
method=FactoringMethod.PRIME_PROVER,
node_count=1, node_id=0,
gear_factorization_level=23,
wheel_factorization_level=13,
sieving_bound_multiplier=1.0,
smoothness_bound_multiplier=1.0,
gaussian_elimination_row_offset=3,
check_small_factors=False,
wheel_primes_excluded=[]
)The find_a_factor() function should return any nontrivial factor of to_factor (that is, any factor besides 1 or to_factor) if it exists. If a nontrivial factor does not exist (i.e., the number to factor is prime), the function will return 1 or the original to_factor.
method(default value:PRIME_PROVER/0):PRIME_PROVER/0will prove that a number is prime (by failing to find any factors with wheel and gear factorization).FACTOR_FINDER/1is optimized for the assumption that the number has at least two nontrivial factors.node_count(default value:1):FindAFactorcan perform factorization in a distributed manner, across nodes, without network communication! Whennode_countis set higher than1, the search space for factors is segmented equally per node. If the number to factor is semiprime, and brute-force search is used instead of congruence of squares, for example, all nodes except the one that happens to contain the (unknown) prime factor less than the square root ofto_factorwill ultimately return1, while one node will find and return this factor. For best performance, every node involved in factorization should have roughly the same CPU throughput capacity. ForFACTOR_FINDERmode, this splits the sieving range between nodes, but it does not actually coordinate Gaussian elimination rows between nodes.node_id(default value:0): This is the identifier of this node, when performing distributed factorization withnode_counthigher than1.node_idvalues start at0and go as high as(node_count - 1).gear_factorization_level(default value:23): This is the value up to which "wheel (and gear) factorization" are applied to "brute force." A value of23includes all prime factors of23and below and works well forPRIME_PROVER, though significantly higher might be preferred in certain cases. InFACTOR_FINDER, one probably wants to avoid setting a different gear level than wheel level.wheel_factorization_level(default value:13): "Wheel" vs. "gear" factorization balances two types of factorization wheel ("wheel" vs. "gear" design) that often work best when the "wheel" is only a few prime number levels lower than gear factorization. ForPRIME_PROVER, optimized implementation for wheels is only available up to17; forFACTOR_FINDER, wheels are constructed programmatically while avoidingwheel_primes_excludedentries, so there is no fixed ceiling. The primes above "wheel" level, up to "gear" level, are the primes used specifically for "gear" factorization. ForFACTOR_FINDERmethod, wheel factorization is applied to map the sieving interval onto non-multiples on the wheel, if the level is set above1.sieving_bound_multiplier(default value:1.0): This controls the sieving bound and is calibrated such that it linearly multiplies the number to factor minus its square root (for a full1.0increment, which is maximum). While this might be a huge bound, remember that sieving termination is primarily controlled by whengaussian_elimination_row_multiplieris exactly satisfied.smoothness_bound_multiplier(default value:1.0): This controls smoothness bound and is calibrated such that it linearliy multipliespow(exp(0.5 * sqrt(log(N) * log(log(N)))), sqrt(2.0)/4)forNbeing the number to factor (for each1.0increment). This was a heuristic suggested by Elara (an OpenAI custom GPT).gaussian_elimination_row_offset(default value:1): This controls the number of rows greater than the count of smooth primes that are sieved before Gaussian elimination. Basically, for each increment starting with1, the chance of finding at least one solution in Gaussian elimination goes like(1 - 2^(-m))for a setting value ofm:1value is a 50% chance of success, and the chance of failure is halved for each unit of1added. So long as this setting is appropriately low enough,sieving_bound_multipliercan be set basically arbitrarily high.check_small_factors(default value:False):Trueperforms initial-phase trial division up to the smoothness bound, andFalseskips it.wheel_primes_excluded(default value:[]): If usingFACTOR_FINDERmethod, these specific primes are excluded from wheel and gear factorization (up towheel_factorization_levelandgear_factorization_level). (Seewheel_tuner.pyin the project root for guidance on which primes to exclude and include, based empirically upon a sample list of smooth numbers for your particular number to factor.)
All variables defaults can also be controlled by environment variables:
FINDAFACTOR_METHOD(integer value)FINDAFACTOR_NODE_COUNTFINDAFACTOR_NODE_IDFINDAFACTOR_GEAR_FACTORIZATION_LEVELFINDAFACTOR_WHEEL_FACTORIZATION_LEVELFINDAFACTOR_SIEVING_BOUND_MULTIPLIERFINDAFACTOR_SMOOTHNESS_BOUND_MULTIPLIERFINDAFACTOR_GAUSSIAN_ELIMINATION_ROW_OFFSETFINDAFACTOR_CHECK_SMALL_FACTORS(Trueif set at all, otherwiseFalse)FINDAFACTOR_WHEEL_PRIMES_EXCLUDED(comma-separated prime numbers)
This library was originally called "Qimcifa" and demonstrated a (Shor's-like) "quantum-inspired" algorithm for integer factoring. It has since been developed into a general factoring algorithm and tool.
Special thanks to OpenAI GPT "Elara," for help with indicated region of contributed code!