Perfect Power Predicate
March 13, 2012
A number n is a perfect power if there exists a b and e for which be = n. For instance 216 = 63 = 23 · 33 is a perfect power, but 72 = 23 · 32 is not. Testing for perfect powers is similar to other powering predicates we have seen, and is useful in some factoring algorithms.
The trick to determining if a number is a perfect power is to know that, if the number is a perfect power, then the exponent e must be less than log2 n, because if e is greater then 2e will be greater than n. Further, it is only necessary to test prime es, because if a number is a perfect power to a composite exponent it will also be a perfect power to the prime factors of the composite component; for instance, 215 = 32768 = 323 = 85 is a perfect cube root and also a perfect fifth root.
Your task is to write a function to determine if a number is a perfect power. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.
Here’s the smart-ass J version:
isPerfectPower=: 3 : ‘1<+./#/.~q:y'
It feels like cheating when your language has a "prime factors of" primitive.
Or you could say that you have chosen the right tool for the job.
For those of us who don’t speak J, could you provide an explanation?
Sure.
“q:” returns the prime factors of a number. “q: 216” returns “2 2 2 3 3 3”, “q: 700” returns “2 2 5 5 7”.
“#/.~” returns the counts of the unique items. “#/.~q: 216” is “3 3”. “#/.~q: 700” is “2 2 1”.
“+.” is gcd. “+./” is “foldr gcd”. So “+./#/.~q: 216” is “3”. “+/#/.~q: 700” is “1”.
And if the gcd of the counts of all the prime factors is greater than 1, it’s a perfect power. (Unless my brain is being very slow this morning.)
“foo=: 3 : ‘blah'” is just function-definition boilerplate.
The details of that inscrutable-looking “#/.~” are interesting, at least to me. “#” is count. “~” is reflexive call: “f~ x” is “x f x”. “/.” is a “keyed operation”. Given “x f/.y”, the unique items of x (the “key”) are used to break y into groups, then the function f is applied to each group. So, here we’re using the list of factors to classify itself, then we’re counting the number of values in each group. It’s an interesting higher-order function that I’ve not seen in too many places. The rather terse J documentation on it is here: http://jsoftware.com/help/dictionary/d421.htm.
Okay, one more J version, then I’m done.
ilog=: <.@^.
iroot=: : _1 p: y’
isPerfectPower=: 3 : ‘+./(primesTo 2 ilog y) isEvenRoot y’
“@” is composition, “:” is 1+, “i.” is integers-up-to.
Diving into “isEvenRoot”, we have the equivalent of:
(define (left x y) x) ; [
(define (right x y) y) ; ]
(define (fork f g h) (lambda (x y) (g (f x y) (h x y)) ; implicit
(define isEvenRoot (fork right = (fork iroot expt left))
Python code equivalent to Johanns’
Note: utils is my collection of handy functions from solving other Praxis problems
Johann and Mike: Those functions work if you can factor n. But if n is the product of two large primes, it’s unlikely that you will get an answer any time soon. You could assume that if you can’t factor n in some reasonable time, it’s not a perfect power, but if n is the square of two large primes, you’re in trouble. For instance, is 148675665359980297048795508874724049089546782584077934753925649 a perfect power?
Here is an iterative solution.
Basically, start with the smallest base and the largest exponent. If b**e is too large decrease the exponent. If b**e is too small increase the base. Repeat until b**e == n or all the exponents have been tried.
i think the best i can do is this
perfect power
All positive integers satisfy this definition of a perfect power, you need to add the condition e > 1.
Basically the same algorithm as Mike’s, except with a bunch of re-invented wheels.
OP: Factoring is difficult, but won’t the prime sieve also suffer from a time/memory issue if the input is a large prime squared? Sieving all primes up to 12193263113702594790275394159593 (to match your example (thanks wolframalpha)) would take a lot of memory and time… Once you had this table though, your root search seems to be the most efficient of anyone’s posted.
My algorithm also chokes horribly on very large input (greater than 64 bit integers). I even tried integrating perl’s arbitrary precision library, but I failed miserably
Oops, disregard me, you only need to generate the primes up to log2(n) =)
WordPress formatting ate my previous attempt to post a version that handles large numbers gracefully.
pastebin
This works for 148675665359980297048795508874724049089546782584077934753925649, saying that, yes, it’s a perfect square.
This is the least I can do for now. The function displays all b and e where b^e = n.
A version in Perl that runs much faster than the Perl version above, and handles bigints. Given that the *reason* for a is_perfect_power function is typically as an initial step in factoring or primality testing (e.g. SQUFOF, AKS), using factoring to answer the question is a non-starter.
Doing just the bigint part (the is_perfect_power_simple function) is simpler, isolated from quirks of the C library and some old Perl (pre 5.8.8) screwiness with 64-bit numbers, and still reasonably fast. The native ints/floats method is ~400x faster on my computer so worth thinking about.
For perfect square testing (e.g. for HOLF or SQUFOF), I’ve found the first one or two bloom filters from http://mersenneforum.org/showpost.php?p=110896 works better than anything else I’ve seen. E.g. for non-bigints:
His full sequence is really meant to speed up the test for bigints, trying to avoid a bigint sqrt, but it still helps a bit for native computations.
[…] There is further discussion of the perfect power predicate at my blog. […]