Product of Prime factors of a number - algorithm

Given a number X , what would be the most efficient way to calculate the product of the prime factors of that number?
Is there a way to do this without actual factorisation ?
Note-The product of prime factors is needed (all to the power unity).

This answer addresses the second half of your question - i.e. is it possible to compute the product of the prime factors without factorising the number. This answer shows that it is possible to do, and shows a method that is more efficient than a naive method of factorisation. However, as noted in the comments, this proposed method is still not as efficient as factorising the number using a more advanced method.
Let k be the cube root of the number.
Check the number for all primes of size k or smaller and divide out any we find.
We now know that the resulting number is a product of primes larger than k, so it must either be 1, a single prime, or a product of 2 primes. (It cannot have more than 2 primes because k is the cube root of the number.)
We can detect whether it is a product of 2 primes by simply testing whether the number is a perfect square.
The results of this allow us to calculate the result in O(n^(1/3) / log(n)) assuming we have precomputed a list of primes.
EXAMPLE 1
Suppose we have the number 9409.
The cube root is 21.1 so we first check for divisibility by primes under 21.
None of them find a result so we compute the sqrt and find 9409== 97**2.
This means that the answer is 97.
EXAMPLE 2
Suppose we have the number 9797.
The cube root is 21.4 so we check for divisibility by primes under 21.
None of them find a result so we compute the sqrt and find 9797 is not a perfect square.
Therefore we conclude the answer is 9797. (Note that we have not determined the factorisation to work out this answer. In fact the factorisation is 97*101.)

Maple and Mathematica both calculate the squarefree kernel of a number by factoring and then multiplying back together just one copy of each prime (see https://oeis.org/A007947) so I doubt a better way is known.

Another approach is to start with the number itself. It is obviously a product of all its prime factors. You want to remove all the factors with power more than one. Hence, you don't mind if the number has a factor 2, but you do mind if it has a factor 4 (2^2). We can solve the problem by removing the extra factors.
Simple pseudocode:
method removeHigherPrimePowers(number)
temp <- number
primes <- [2, 3, 5, 7 ...]
for each p in primes
factor <- p * p // factor = 4, 9, 25, ...
while (temp MOD factor = 0)
temp <- temp / p // Remove extra factor of p
endwhile
endfor
return temp
endmethod
The number is being factorised, but the factorising is somewhat hidden. All those MOD statements do the same work. All that is being saved is a certain amount of accounting, keeping track of the factors found so far and multiplying them all together at the end.
As Peter says, you can test all primes up to the cube root, and then check if the number remaining is square.

Related

Number of positive integers in [1,1e18] that cannot be divided by any integers in [2,10]

I am having difficulty trying to solve the following problem:
For Q queries, Q <= 1e6, where each query is a positive integer N, N <= 1e18, find the number of integers in [1,N] that cannot be
divided by integers in [2,10] for each query.
I thought of using using a sieve method to filter out numbers in [1,1e18] for each query (similar to sieve of eratosthenes). However, the value of N could be very large. Hence, there is no way I could use this method. The most useful observation that I could make is that numbers ending with 0,2,4,5,6,8 are invalid. But that does not help me with this problem.
I saw a solution for a similar problem that uses a smaller number of queries (Q <= 200). But it doesn't work for this problem (and I don't understand that solution).
Could someone please advise me on how to solve this problem?
The only matter numbers in [2,10] are those primes which are 2, 3, 5, 7
So, Let say, the number cannot be divided by integers in [2,10] is the number cannot be divided by {2,3,5,7}
Which is also equalled to the total number between [1,n] minus all number that is divided by any combination of {2,3,5,7}.
So, this is the fun part: from [1,n] how many numbers that is divided by 2?
The answer is n/2 (why? simple, because every 2 number, there is one number divided by 2)
Similarly, how many numbers that is divided by 5? The answer is n/5
...
So, do we have our answer yet? No, as we found out that we have doubled count those numbers that divided by both {2, 5} or {2, 7} ..., so now, we need to minus them.
But wait, seems like we are double minus those that divided by {2,5,7} ... so we need to add it back
...
Keep doing this until all combinations are taken care of,
so there should be 2^4 combination, which is 16 in total, pretty small to deal with.
Take a look at Inclusion-Exclusion principle for some good understanding.
Good luck!
Here is an approach on how to handle this.
The place to start is to think about how you can split this into pieces. With such a problem, a place to start is the least common denominator (LCD) -- in this case 2,520 (the smallest number divisible by all the numbers less than 10).
The idea is that if x is not divisible by any number from 2-10, then x + 2,520 is also not divisible.
Hence, you can divide the problem into two pieces:
How many numbers between 1 and 2,520 are "relatively prime" to the numbers from 2-10?
How many times does 2,520 go into your target number? You need to take the remainder into account as well.

What makes this prime factorization so efficient?

I've been doing some Project Euler problems to learn/practice Lua, and my initial quick-and-dirty way of finding the largest prime factor of nwas pretty bad, so I looked up some code to see how others were doing it (in attempts to understand different factoring methodologies).
I ran across the following (originally in Python - this is my Lua):
function Main()
local n = 102
local i = 2
while i^2 < n do
while n%i==0 do n = n / i end
i = i+1
end
print(n)
end
This factored huge numbers in a very short time - almost immediately. The thing I noticed about the algorithm that I wouldn't have divined:
n = n / i
This seems to be in all of the decent algorithms. I've worked it out on paper with smaller numbers and I can see that it makes the numbers converge, but I don't understand why this operation converges on the largest prime factor.
Can anyone explain?
In this case, i is the prime factor candidate. Consider, n is composed of the following prime numbers:
n = p1^n1 * p2^n2 * p3^n3
When i reaches p1, the statement n = n / i = n / p1 removes one occurrence of p1:
n / p1 = p1^(n-1) * p2^n2 * p3^n3
The inner while iterates as long as there are p1s in n. Thus, after the iteration is complete (when i = i + 1 is executed), all occurrences of p1 have been removed and:
n' = p2^n2 * p3^n3
Let's skip some iterations until i reaches p3. The remaining n is then:
n'' = p3^n3
Here, we find a first mistake in the code. If n3 is 2, then the outer condition does not hold and we remain with p3^2. It should be while i^2 <= n.
As before, the inner while removes all occurences of p3, leaving us with n'''=1. This is the second mistake. It should be while n%i==0 and n>i (not sure about the LUA syntax), which keeps the very last occurence.
So the above code works for all numbers n where the largest prime factor occurrs only once by successivley removing all other factors. For all other numbers, the mentioned corrections should make it work, too.
This eliminates all the known smaller prime factors off n so that n becomes smaller, and sqrt(n) can be reached earlier. This gives the performance boost, as you no longer need to run numbers to square root of original N, say if n is a million, it consists of 2's and 5's, and naive querying against all known primes would need to check against all primes up to 1000, while dividing this by 2 yields 15625, then dividing by 5 yields 1 (by the way, your algorithm will return 1! To fix, if your loop exits with n=1, return i instead.) effectively factoring the big number in two steps. But this is only acceptable with "common" numbers, that have a single high prime denominator and a bunch of smaller ones, but factoring a number n=p*q whiere both p and q are primes and are close won't be able to benefit from this boost.
The n=n/i line works because if you are seeking another prime than i you are currently found as a divisor, the result is also divisible by that prime, by definition of prime numbers. Read here: https://en.wikipedia.org/wiki/Fundamental_theorem_of_arithmetic . Also this only works in your case because your i runs from 2 upward, so that you first divide by primes then their composites. Otherwise, if your number would have a 3 as largest prime, is also divisible by 2 and you'd check against 6 first, you'd spoil the principle of only dividing by primes (say with 72, if you first divide by 6, you'll end up with 2, while the answer is 3) by accidentally dividing by a composite of a largest prime.
This algorithm (when corrected) takes O(max(p2,sqrt(p1))) steps to find the prime factorization of n, where p1 is the largest prime factor and the p2 is the second largest prime factor. In case of a repeated largest prime factor, p1=p2.
Knuth and Trabb Pardo studied the behavior of this function "Analysis of a Simple Factorization Algorithm" Theoretical Computer Science 3 (1976) 321-348. They argued against the usual analysis such as computing the average number of steps taken when factoring integers up to n. Although a few numbers with large prime factors boost the average value, in a cryptographic context what may be more relevant is that some of the percentiles are quite low. For example, 44.7% of numbers satisfy max(sqrt(p1),p2)<n^(1/3), and 1.2% of numbers satisfy max(sqrt(p1),p2)<n^(1/5).
A simple improvement is to test the remainder for primality after you find a new prime factor. It is very fast to test whether a number is prime. This reduces the time to O(p2) by avoiding the trial divisions between p2 and sqrt(p1). The median size of the second largest prime is about n^0.21. This means it is feasible to factor many 45-digit numbers rapidly (in a few processor-seconds) using this improvement on trial division. By comparison, Pollard-rho factorization on a product of two primes takes O(sqrt(p2)) steps on average, according to one model.

Generating prime numbers in poly-time

I am struggling to see how we can generate a list of J smallest primes in poly-time J, based on the fact that p'j is less than or equal to 2j * ln(j) for j > 2, where j indicates the j-th consecutive prime number. For instance, p1 = 2 for j=1, p2 = 3 for j = 2. p3 = 5 for j = 3, p4 = 7 for j = 4, p5 = 11 for j = 5, etc etc...
I just don't see how I can make use of this fact above. Any time I want to generate a prime, say the 7th, I will check by plugging in: 2(7)*ln(7) = 27.2427... But this is completely useless, as it turns out. This number is way bigger than the last generated prime in my array, which is logical. Hence I still have to resort to either brute force by checking the last prime+1 for mod0 with each of the primes in my array. The other option is to resort to already existing algorithms that reduce the time to polynomial time.
Can you show me how I can make use of that fact: p'j <= 2j*ln(j)? Thanks.
To show that I can generate a list of the first J primes in time polynomial in J, I need to work out the cost of however I am generating the list.
If I am generating the list by checking numbers one after the other and discarding non-primes, there are two parts to the cost of generating the list - how long it takes to check each number, and how many numbers I need to check.
If primes were vanishingly rare, then I couldn't afford to check every number from 2 on, because simply listing all those numbers would be too expensive. But if I know that the Jth prime is no larger than 2j*ln(j) I can at least list them all in polynomial time.
In fact, if I have to generate J primes, and I start by taking the first 2J*ln(J) numbers, and I decide to check each number for being prime by test dividing it by every prime found so far, I never have more than J primes on hand at any time, so I cannot end up doing more than 2J^2*ln(J) trial divisions. This won't win me any prize for efficiency or clever algorithms, or even sharp bounds for computational cost, but it is no worse than polynomial.
Maybe what's tripping you up is that you're thinking that the upper bound gives you a method to directly generate the jth prime, or the first j primes. It doesn't -- it just gives you a size limit on the set of numbers that you need to check with some method you already had lying around, e.g. trial division.
If I give you a list of the n-1 numbers 2, 3, ..., n and ask you to find all the primes in this list, you can do this using trial division in O(n^2) time:
For each pair of numbers x and y, just check whether x divides evenly into y, and cross y out if it does. This step is O(n^2), and requires O(n) space for keeping track of which numbers have been crossed out.
List out all the numbers that were not crossed out. This step is O(n).
Note that this finds all primes <= n in O(n^2) for any positive value of n. So in particular, if we are told some value of j, it will work for n = RoundDown(2j log j).
With n = RoundDown(2j log j), this algorithm runs in time O((2j log j)^2) = O(j^2 log^2 j), which is polynomial in j, and it must succeed in finding at least the first j primes, since the bound tells us that the jth prime can be at most RoundDown(2j log j), and we have included every number up to and including that one in our input list. (It may find even more primes, but we can discard them in linear time if need be.)
Exercise: Think about why we are allowed to round down here.

How can i make an array of integers all relatively prime by increasing each number in minimum steps?

How can i make an array of integers all relatively prime by increasing each number in minimum steps?
Till now, i have come up this kind of strategy:
1) divide by their common multiples (say k, then each step i perform will equal k afterwards)
2) incrementing the number which is "closest" to a prime
But, i am not sure the correctness of this strategy.
Does anyone has a better idea?
For example, a[5]={2,4,6,7,8}
the solution should be {2,5,9,7,11} in 7 moves.
You can use that gcd(n, n+1) = 1 for all integers n. Therefore, one possible strategy will be to take the two numbers with smallest absolute difference and make the smaller equal to the_value_of_the_bigger_one - 1.
By the way, I think your second strategy is incorrect. Imagine that the next prime is p. Then you can construct an array, in which all the numbers (besides that, which you are increasing) can have p as а factor. And when you increase it, the gcd of the array will be equal to p. Example array can be (24, 2, 48) -- current gcd is 2, but when you try your second strategy, the array will become (24, 3, 48), which has gcd equal to 3.

Create a random permutation of 1..N in constant space

I am looking to enumerate a random permutation of the numbers 1..N in fixed space. This means that I cannot store all numbers in a list. The reason for that is that N can be very large, more than available memory. I still want to be able to walk through such a permutation of numbers one at a time, visiting each number exactly once.
I know this can be done for certain N: Many random number generators cycle through their whole state space randomly, but entirely. A good random number generator with state size of 32 bit will emit a permutation of the numbers 0..(2^32)-1. Every number exactly once.
I want to get to pick N to be any number at all and not be constrained to powers of 2 for example. Is there an algorithm for this?
The easiest way is probably to just create a full-range PRNG for a larger range than you care about, and when it generates a number larger than you want, just throw it away and get the next one.
Another possibility that's pretty much a variation of the same would be to use a linear feedback shift register (LFSR) to generate the numbers in the first place. This has a couple of advantages: first of all, an LFSR is probably a bit faster than most PRNGs. Second, it is (I believe) a bit easier to engineer an LFSR that produces numbers close to the range you want, and still be sure it cycles through the numbers in its range in (pseudo)random order, without any repetitions.
Without spending a lot of time on the details, the math behind LFSRs has been studied quite thoroughly. Producing one that runs through all the numbers in its range without repetition simply requires choosing a set of "taps" that correspond to an irreducible polynomial. If you don't want to search for that yourself, it's pretty easy to find tables of known ones for almost any reasonable size (e.g., doing a quick look, the wikipedia article lists them for size up to 19 bits).
If memory serves, there's at least one irreducible polynomial of ever possible bit size. That translates to the fact that in the worst case you can create a generator that has roughly twice the range you need, so on average you're throwing away (roughly) every other number you generate. Given the speed an LFSR, I'd guess you can do that and still maintain quite acceptable speed.
One way to do it would be
Find a prime p larger than N, preferably not much larger.
Find a primitive root of unity g modulo p, that is, a number 1 < g < p such that g^k ≡ 1 (mod p) if and only if k is a multiple of p-1.
Go through g^k (mod p) for k = 1, 2, ..., ignoring the values that are larger than N.
For every prime p, there are φ(p-1) primitive roots of unity, so it works. However, it may take a while to find one. Finding a suitable prime is much easier in general.
For finding a primitive root, I know nothing substantially better than trial and error, but one can increase the probability of a fast find by choosing the prime p appropriately.
Since the number of primitive roots is φ(p-1), if one randomly chooses r in the range from 1 to p-1, the expected number of tries until one finds a primitive root is (p-1)/φ(p-1), hence one should choose p so that φ(p-1) is relatively large, that means that p-1 must have few distinct prime divisors (and preferably only large ones, except for the factor 2).
Instead of randomly choosing, one can also try in sequence whether 2, 3, 5, 6, 7, 10, ... is a primitive root, of course skipping perfect powers (or not, they are in general quickly eliminated), that should not affect the number of tries needed greatly.
So it boils down to checking whether a number x is a primitive root modulo p. If p-1 = q^a * r^b * s^c * ... with distinct primes q, r, s, ..., x is a primitive root if and only if
x^((p-1)/q) % p != 1
x^((p-1)/r) % p != 1
x^((p-1)/s) % p != 1
...
thus one needs a decent modular exponentiation (exponentiation by repeated squaring lends itself well for that, reducing by the modulus on each step). And a good method to find the prime factor decomposition of p-1. Note, however, that even naive trial division would be only O(√p), while the generation of the permutation is Θ(p), so it's not paramount that the factorisation is optimal.
Another way to do this is with a block cipher; see this blog post for details.
The blog posts links to the paper Ciphers with Arbitrary Finite Domains which contains a bunch of solutions.
Consider the prime 3. To fully express all possible outputs, think of it this way...
bias + step mod prime
The bias is just an offset bias. step is an accumulator (if it's 1 for example, it would just be 0, 1, 2 in sequence, while 2 would result in 0, 2, 4) and prime is the prime number we want to generate the permutations against.
For example. A simple sequence of 0, 1, 2 would be...
0 + 0 mod 3 = 0
0 + 1 mod 3 = 1
0 + 2 mod 3 = 2
Modifying a couple of those variables for a second, we'll take bias of 1 and step of 2 (just for illustration)...
1 + 2 mod 3 = 0
1 + 4 mod 3 = 2
1 + 6 mod 3 = 1
You'll note that we produced an entirely different sequence. No number within the set repeats itself and all numbers are represented (it's bijective). Each unique combination of offset and bias will result in one of prime! possible permutations of the set. In the case of a prime of 3 you'll see that there are 6 different possible permuations:
0,1,2
0,2,1
1,0,2
1,2,0
2,0,1
2,1,0
If you do the math on the variables above you'll not that it results in the same information requirements...
1/3! = 1/6 = 1.66..
... vs...
1/3 (bias) * 1/2 (step) => 1/6 = 1.66..
Restrictions are simple, bias must be within 0..P-1 and step must be within 1..P-1 (I have been functionally just been using 0..P-2 and adding 1 on arithmetic in my own work). Other than that, it works with all prime numbers no matter how large and will permutate all possible unique sets of them without the need for memory beyond a couple of integers (each technically requiring slightly less bits than the prime itself).
Note carefully that this generator is not meant to be used to generate sets that are not prime in number. It's entirely possible to do so, but not recommended for security sensitive purposes as it would introduce a timing attack.
That said, if you would like to use this method to generate a set sequence that is not a prime, you have two choices.
First (and the simplest/cheapest), pick the prime number just larger than the set size you're looking for and have your generator simply discard anything that doesn't belong. Once more, danger, this is a very bad idea if this is a security sensitive application.
Second (by far the most complicated and costly), you can recognize that all numbers are composed of prime numbers and create multiple generators that then produce a product for each element in the set. In other words, an n of 6 would involve all possible prime generators that could match 6 (in this case, 2 and 3), multiplied in sequence. This is both expensive (although mathematically more elegant) as well as also introducing a timing attack so it's even less recommended.
Lastly, if you need a generator for bias and or step... why don't you use another of the same family :). Suddenly you're extremely close to creating true simple-random-samples (which is not easy usually).
The fundamental weakness of LCGs (x=(x*m+c)%b style generators) is useful here.
If the generator is properly formed then x%f is also a repeating sequence of all values lower than f (provided f if a factor of b).
Since bis usually a power of 2 this means that you can take a 32-bit generator and reduce it to an n-bit generator by masking off the top bits and it will have the same full-range property.
This means that you can reduce the number of discard values to be fewer than N by choosing an appropriate mask.
Unfortunately LCG Is a poor generator for exactly the same reason as given above.
Also, this has exactly the same weakness as I noted in a comment on #JerryCoffin's answer. It will always produce the same sequence and the only thing the seed controls is where to start in that sequence.
Here's some SageMath code that should generate a random permutation the way Daniel Fischer suggested:
def random_safe_prime(lbound):
while True:
q = random_prime(lbound, lbound=lbound // 2)
p = 2 * q + 1
if is_prime(p):
return p, q
def random_permutation(n):
p, q = random_safe_prime(n + 2)
while True:
r = randint(2, p - 1)
if pow(r, 2, p) != 1 and pow(r, q, p) != 1:
i = 1
while True:
x = pow(r, i, p)
if x == 1:
return
if 0 <= x - 2 < n:
yield x - 2
i += 1

Resources