Find the Maximal Prime Powers

23

2

A prime power is a positive integer n that can be written in the form n = pk where p is a prime and k is a positive integer. For example, some prime powers are [2, 3, 5, 4, 9, 25, 8, 27, 125].

Next, consider prime powers of 2. These are [2, 4, 8, 16, ...] and can be written in the form 2k. They would all be included when considering prime powers beneath 20. However, 16 is the maximal prime power with a base prime of 2 in that range. A prime power pk is maximal in a range if it is the highest power of p in that range. We are only interested in the maximal prime power in each range so all lower prime powers must be excluded.

Your goal is to write a function or program that takes a positive integer n and outputs the maximal prime powers in the range [2, 3, 4, ..., n].

Thanks to @Peter Taylor for clarifying the definition of maximal prime power and more.

Rules

  • This is so make your code as short as possible.
  • The maximal prime powers may be output in any order but there must be no duplicates.

Test cases

n      result
1      []
2      [2]
3      [2, 3]
4      [3, 4]
5      [3, 4, 5]
6      [3, 4, 5]
7      [3, 4, 5, 7]
20     [5, 7, 9, 11, 13, 16, 17, 19]
50     [11, 13, 17, 19, 23, 25, 27, 29, 31, 32, 37, 41, 43, 47, 49]
100    [11, 13, 17, 19, 23, 25, 29, 31, 37, 41, 43, 47, 49, 53, 59, 61, 64, 67, 71, 73, 79, 81, 83, 89, 97]
10000  <1229 results>
       [101, 103, 107, 109, 113, 127, 131, 137, 139, 149, ..., 9887, 9901, 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973]

The full list of maximal prime powers for 10000 can be found here.

miles

Posted 2017-02-06T18:31:40.207

Reputation: 15 654

Answers

16

Jelly, 7 4 bytes

æḟÆR

Try it online!

How it works

æḟÆR  Main link. Argument: n

  ÆR  Prime range; yield all primes in [1, ..., n].
æḟ    Power floor; round n down to the nearest power of each prime in the range.

Dennis

Posted 2017-02-06T18:31:40.207

Reputation: 196 637

Oh so obvious once one sees it! – Jonathan Allan – 2017-02-07T00:48:31.563

15Power floor What the heck – JungHwan Min – 2017-02-07T06:22:16.517

1This post officially convinced me to learn Jelly. – Chandler Watson – 2017-02-07T06:44:28.707

10

Mathematica, 44 43 40 bytes

Saved 4 bytes thanks to miles and Martin Ender

n#^⌊#~Log~n⌋&/@Select[Range@n,PrimeQ]

(x=Prime@Range@PrimePi@#)^⌊x~Log~#⌋&

and are the 3 byte characters U+230A and U+230B representing \[LeftFloor] and \[RightFloor], respectively.

Explanation:

enter image description here

Pure function. # is short for Slot[1] which represents the first argument to the Function. PrimePi@# counts the number of primes less or equal to #, Range@PrimePi@# is the list of the first PrimePi[#] positive integers, and so Prime@Range@PrimePi@# is the list of primes less than or equal to # (this is one byte shorter than Select[Range@#,PrimeQ]). The symbol x is Set equal to this list, then raised to the Power ⌊x~Log~#⌋, which is the list of Floor[Log[n,#]] for each n in x. In Mathematica, raising a list to the Power of another list of the same length results in the list of the powers of their corresponding elements.

ngenisis

Posted 2017-02-06T18:31:40.207

Reputation: 4 600

I thought Range@#~Select~PrimeQ would be shorter than Prime@Range@PrimePi@# ... but it's a tie – Greg Martin – 2017-02-06T20:08:18.373

That's a nice figure. Was it generated using a builtin or created manually? – miles – 2017-02-06T21:00:37.463

@miles It was generated using TreeForm

– ngenisis – 2017-02-06T21:01:27.467

Thanks. I don't remember ever seeing it, but evidently it's been around forever. – miles – 2017-02-06T21:04:39.880

7

MATL, 13 bytes

ZqG:!^tG>~*X>

Try it Online!

Explanation

        % Implicitly grab the input as a number (N)
Zq      % Get an array of all primes below N
G:!     % Create an array from [1...N]
^       % Raise each prime to each power in this array which creates a 2D matrix
        % where the powers of each prime are down the columns
tG>~    % Create a logical matrix that is TRUE where the values are less than N
*       % Perform element-wise multiplication to force values > N to zero
X>      % Compute the maximum value of each column
        % Implicitly display the resulting array

Suever

Posted 2017-02-06T18:31:40.207

Reputation: 10 257

7

Jelly, 8 bytes

ÆR*ÆE€»/

Try it online!

How it works

ÆR*ÆE€»/  Main link. Argument: n

ÆR        Prime range; yield all primes in [1, ..., n].
   ÆE€    Prime exponents each; yield the exponents of 2, 3, 5, ... of the prime
          factorization of each k in [1, ..., n].
          For example, 28 = 2² × 3⁰ × 5⁰ × 7¹ yields [2, 0, 0, 1].
  *       Exponentiation; raise the elements of the prime range to the powers
          of each of the exponents arrays.
      »/  Reduce the columns by maximum.

Dennis

Posted 2017-02-06T18:31:40.207

Reputation: 196 637

6

Jelly, 12 9 bytes

RÆEz0iṀ$€

Try it online! (method is too slow for the 10000 case).

How?

Builds the list of pk in order of p.

RÆEz0iṀ$€ - Main link: n                      e.g. 7
R         - range(n)                          [1 ,2  ,3    ,4  ,5      ,6    ,7]
 ÆE       - prime factor vector (vectorises)  [[],[1],[0,1],[2],[0,0,1],[1,1],[0,0,0,1]]
   z0     - transpose with filler 0           [[0,1,0,2,0,1,0],[0,0,1,0,0,1,0],[0,0,0,0,1,0,0],[0,0,0,0,0,0,1]]
       $€ - la$t two links as a monad, for €ach       ^             ^                   ^                   ^
     i    -     first index of                        4             3                   5                   7
      Ṁ   -     maximum                       [4,3,5,7]

Jonathan Allan

Posted 2017-02-06T18:31:40.207

Reputation: 67 804

5

Pyth, 13 bytes

m^ds.lQdfP_TS

Try it here!

        f   S -  filter(v, range(1, input))
         P_T  -   is_prime(T)
m             - map(v, ^)
    .lQd      -    log(input, d)
   s          -   int(^)
 ^d           -  d ** ^

I haven't played with Pyth in a while so any golfing tips are appreciated.

Blue

Posted 2017-02-06T18:31:40.207

Reputation: 26 661

5

I couldn't get a shorter Mathematica solution than ngenisis's solution, but I thought I'd offer a couple of (hopefully interesting) alternative approaches.

Mathematica, 65 bytes

#/#2&@@@({#,#}&/@Range@#~Select~PrimeQ//.{a_,b_}/;a<=#:>{b a,b})&

First we use {#,#}&/@Range@#~Select~PrimeQ to build a list of all primes in the appropriate range, but with ordered pairs of each prime, like { {2,2}, {3,3}, ...}. Then we operate on that list repeatedly with the replacement rule {a_,b_}/;a<=#:>{b a,b}, which multiplies the first element of the ordered pair by the second until the first element exceeds the input. Then we apply #/#2&@@@ to output, for each ordered pair, the first element divided by the second. (They end up sorted by the underlying prime: an example output is {16, 9, 5, 7, 11, 13, 17, 19}.)

Mathematica, 44 bytes

Values@Rest@<|MangoldtLambda@#->#&~Array~#|>&

The von Mangoldt function Λ(n) is an interesting number theory function: it equals 0 unless n is a prime power pk, in which case it equals log p (not log n). (These are natural logs, but it won't matter.) Thus MangoldtLambda@#->#&~Array~# creates an array of rules { 0->1, Log[2]->2, Log[3]->3, Log[2]->4, Log[5]->5, 0->6, ... } whose length is the input integer.

We then turn this list of rules into an "association" using <|...|>. This has the effect of retaining only the last rule with any given left-hand value. In other words, it will throw away Log[2]->2 and Log[2]->4 and Log[2]->8 and keep only Log[2]->16 (assuming that the input is between 16 and 31 for this example). Therefore the only remaining right-hand sides are the maximal prime powers—except for the one remaining rule 0->n, where n is the largest non-prime-power up to the input integer. But Rest throws that undesired rule away, and Values extracts the right-hand sides from the rules in the association. (They end up sorted as above.)

A slightly longer (46 bytes) version, which counts the number of appearances of each log p and then exponentiates to convert to the maximal prime powers:

E^(1##)&@@@Rest@Tally[MangoldtLambda~Array~#]&

Greg Martin

Posted 2017-02-06T18:31:40.207

Reputation: 13 940

1Neat use of associations. They've been out since 2014 but I don't think they've seen much use in golfing. Very useful to know it replaces identical keys with values from left to right. – miles – 2017-02-06T21:16:07.543

4

CJam, 21 20 bytes

Saved 1 byte thanks to Martin Ender

ri_){mp},f{\1$mLi#}p

Try it online!

Explanation

ri                    e# Read an integer from input (let's call it n)
  _                   e# Duplicate it
   ){mp},             e# Push the array of all prime numbers up to and including n
         f{           e# Map the following block to each prime p:
           \          e#   Swap the top two elements of the stack
            1$        e#   Copy the second element down in the stack. Stack is now [p n p]
              mL      e#   Take the base-p logatithm of n
                i     e#   Cast to int (floor)
                 #    e#   Raise p to that power
                  }   e# (end of map block)
                   p  e# Print

Business Cat

Posted 2017-02-06T18:31:40.207

Reputation: 8 927

4

Brachylog, 24 21 19 bytes

3+2 bytes saved thanks to Fatalize!

This is my first time using Brachylog, and I know some things could have been done in shorter ways, but I'm happy that it even works :D

{≥.~^ℕ₁ᵐhṗ:.≜×>?∧}ᶠ

Try it online! (Return values are ordered by their base primes)

Explanation:

{................}ᶠ           #Find all possible results of what's inside.
 ≥.                           #Input is >= than the output.
  .~^ℕ₁ᵐ                      #Output can be calculated as A^B, where A and B are
                              #Natural numbers >=1.
        hṗ                    #The first of those numbers (A) is prime
          :.≜×>?              #That same element (A), multiplied by the output
                              #is greater than the input - This means 
                              #that B is the maximal exponent for A.
                ∧             #No more restrictions on the output.

Leo

Posted 2017-02-06T18:31:40.207

Reputation: 8 482

1Great! You can save two bytes by using the specific variable names ? and . for Input and Output, instead of I and X, as such: {≥N~^.hṗ:N×>?∧0<~t}ᶠ^ᵐ – Fatalize – 2017-02-08T09:43:44.907

1You can also save another byte by removing 0<~t and stating that each element of the Output . is in ℕ₁ = [1, ..., +inf) as such: {≥N~^.ℕ₁ᵐhṗ:N×>?∧}ᶠ^ᵐ – Fatalize – 2017-02-08T09:56:13.963

@Fatalize thank you! I'll update the solution with your suggestions :) By the way, do you know why a solution like {≥.~^ℕ₁ᵐhṗ:.×>?∧}ᶠ (using N directly as output) doesn't work? I tried first something like this, but then had to resort to using X and applying ^ over it – Leo – 2017-02-08T10:34:19.160

2I actually wondered the same thing; this is possibly due to the implicit labelization step that occurs at the end of the predicate in {...}ᶠ which causes weird behavior. I intend to change that and I will look specifically into why this program does not work the same way as the one above. – Fatalize – 2017-02-08T10:51:07.623

1It actually works if you do it like this: {≥.~^ℕ₁ᵐhṗ:.≜×>?∧}ᶠ That way you get correct labelization. (A change was made to the specs in the meantime but does not actually change the behavior of this particular program, so it does not make it non-competing). This saves 2 bytes – Fatalize – 2017-02-08T15:01:37.897

4

Brachylog, 15 bytes

⟧{ḋ=}ˢ⊇Xhᵐ≠∧X×ᵐ

Try it online!

This outputs the powers from biggest to smallest.

This is very inefficient.

Explanation

⟧                   The Range [Input, Input - 1, ..., 1, 0]
 {  }ˢ              Select:
  ḋ=                  The elements of that range whose prime decompositions are lists of the
                      same element (e.g. [3,3,3]); output is those prime decompositions
      ⊇X            X is an ordered subset of that list of prime decompositions
       Xhᵐ≠         All first elements of the prime decompositions are different (that is,
                      X contains prime decompositions with different primes each times)
           ∧
            X×ᵐ     Output is the result of mapping multiplication to each element of X

This will find the biggest prime decompositions for each prime first because of the way works: from left to right and from biggest to smallest subsets.

Fatalize

Posted 2017-02-06T18:31:40.207

Reputation: 32 976

3

05AB1E, 15 12 bytes

ƒNpiN¹N.nïm,

Try it online!

Explanation

ƒ             # for N in [0 ... input]
 Npi          # if N is prime
    N         # push N
     ¹N.n     # push log_N(input)
         ï    # convert to int
          m   # raise N to this power
           ,  # print

Emigna

Posted 2017-02-06T18:31:40.207

Reputation: 50 798

3

Bash + GNU utilities, 74 bytes

seq $1|factor|sed "s@.*: \(\w*\)\$@\1;l($1);l(\1);print \"/^p\"@"|bc -l|dc

Try it online!

The input number is passed as an argument. The output is printed to stdout. (As is customary, stderr is ignored.)

Sample output:

./maximalprimepowers 100 2>/dev/null
64
81
25
49
11
13
17
19
23
29
31
37
41
43
47
53
59
61
67
71
73
79
83
89
97

./maximalprimepowers 10000 2>/dev/null | wc -l
1229

Here's how it works:

Call the argument N.

seq generates all the numbers from 1 to N, and factor factors them all.

The regex in the call to sed identifies those lines where the number is a prime P, and replaces those lines with lines that are of the form `

P;l(N);l(P);print "/^p"

(where P and N are replaced by their actual numerical values, and everything else is copied literally, even the quotes and semicolons, and the string print).

These lines are fed as input to bc -l; bc prints the values of the three indicated numbers, each followed by a newline, and then prints the characters /^p . (In bc, l(x) denotes the natural logarithm of x.) JK K

The strings that bc prints are then fed as input to dc; dc prints the value of each P^(log(N)/log(P)) using integer arithmetic (truncating); that's the greatest power of P that is <= N.

One thing that's glossed over above is what happens to lines that are produced by factors that don't correspond to primes. Those lines don't match the regex in the call to sed, so no replacement is done on those. As a result, those lines start with a number followed by a colon, which generates an error when fed as input to bc. But bc just prints to stderr then, which we ignore; it doesn't print anything to stdout. By default, stderr is ignored on PPCG.

Mitchell Spector

Posted 2017-02-06T18:31:40.207

Reputation: 3 392

3

Haskell, 73 67 66 bytes

p n=[last[x^i|i<-[1..n],x^i<=n]|x<-[2..n],all((>0).mod x)[2..x-1]]

Try it online! Usage:

Prelude> p 50
[32,27,25,49,11,13,17,19,23,29,31,37,41,43,47]

Edit: 6 bytes off thanks to Zgarb!

Explanation:

p n=[... x|x<-[2..n]                         ] -- list of all x in the range 2 to n
p n=[... x|x<-[2..n],        mod x<$>[2..x-1]] -- where the remainders of x mod the numbers 2 to x-1
p n=[... x|x<-[2..n],all(>0)$mod x<$>[2..x-1]] -- are all greater 0. This yields all primes in the range.

p n=[    [x^i|i<-[1..n]       ]|...] -- for each of those x generate the list of all x^i with i in the range 1 to n
p n=[last[x^i|i<-[1..n],x^i<=n]|...] -- where x^i is smaller or equal to n
p n=[last[x^i|i<-[1..n],x^i<=n]|...] -- and take the last (that is the largest) element

Laikoni

Posted 2017-02-06T18:31:40.207

Reputation: 23 676

1I think the left side can be last[x^i|i<-[1..n],x^i<=n]. – Zgarb – 2017-02-10T13:44:36.837

@Zgarb Thanks! It's always the list comprehensions, isn't it ... – Laikoni – 2017-02-10T14:24:01.923

2

JavaScript (ES6), 118 120 119 114 112 105 bytes

(n,r)=>(r=k=>[...Array(k-1)].map((_,i)=>i+2),r(n).filter(q=>r(q).every(d=>q%d|!(d%(q/d)*(q/d)%d)&q*d>n)))

Suggestions welcome. This is kind of long, but it seemed worth posting because it does all the divisibility testing explicitly rather than using built-ins related to primes.

Notes:

  • A natural number q is a prime power <=> all of q's divisors are powers of the same prime <=> for any d which divides q, one of d and q/d is a divisor of the other.
  • If q is a power of p, q is maximal <=> q * p > n <=> q * d > n for every nontrivial divisor d of q.

Micah

Posted 2017-02-06T18:31:40.207

Reputation: 121

2

Jelly, 9 bytes

Ræl/ÆF*/€

One byte longer than my other answer, but finishes for input 10,000 is a couple of seconds.

Try it online!

How it works

Ræl/ÆF*/€  Main link. Argument: n

R          Range; yield [1, ..., n].
 æl/       Reduce by least common multiple.
    ÆF     Factor the LCM into [prime, exponent] pairs.
      */€  Reduce each pair by exponentiation.

Dennis

Posted 2017-02-06T18:31:40.207

Reputation: 196 637

There is also a 7 byte version in Jelly that finishes quickly. – miles – 2017-02-07T00:13:04.830

I'll see your 7 and raise you 4. :P – Dennis – 2017-02-07T00:42:05.177

Wow, I did not know that was a builtin too. That takes the cake. – miles – 2017-02-07T00:47:42.830

2

Sage, 43 bytes

lambda i:[x^int(ln(i,x))for x in primes(i)]

Maps each prime in the range primes(i) to its maximal prime power. ln is just an alias of log so it accepts alternate bases although its name suggests it can only use base e.

busukxuan

Posted 2017-02-06T18:31:40.207

Reputation: 2 728

Thought this was python at first, saw the primes function and got really excited. Never trusting stackoverflow again. – sagiksp – 2017-02-19T10:59:29.710

@sagiksp I don't get it, what does it have to do with StackOverflow? – busukxuan – 2017-02-19T11:01:17.713

2

Haskell, 110 90 bytes

s[]=[];s(x:t)=x:s[y|y<-t,y`rem`x>0];f n=[last.fst.span(<=n).scanl1(*)$repeat x|x<-s[2..n]]

--updated per Laikoni's feedback

brander

Posted 2017-02-06T18:31:40.207

Reputation: 111

This throws a Exception: Prelude.last: empty list for f 2 and f 3. – Laikoni – 2017-02-08T17:18:30.500

1Also f 4 returns [2,3] instead of [4,3], I think your takeWhile(<n) needs to be takeWhile(<=n). However using fst.span instead of takeWhile is one byte shorter. – Laikoni – 2017-02-08T17:20:21.577

2

Haskell, 70 bytes

f n=[k|k<-[2..n],p:q<-[[d|d<-[2..k],mod k d<1]],k==p*p^length q,p*k>n]

Defines a function f. Try it online!

Explanation

The idea is to filter the range [2..n] for those numbers k that satisfy k == p^length(divisors k) and p*k > n, where p is the smallest prime divisor of k.

f n=                -- Define f n as
 [k|                -- the list of numbers k, where
  k<-[2..n],        -- k is drawn from [2..n],
  p:q<-[            -- the list p:q is drawn from
   [d|              -- those lists of numbers d where
    d<-[2..k],      -- d is drawn from [2..k] and
    mod k d<1]      -- d divides k
   ],               -- (so p:q are the divisors of k except 1, and p is the smallest one),
  k==p*p^length q,  -- k equals p to the power of the divisor list's length
                    -- (so it's in particular a prime power), and
  p*k>n]            -- p*k, the next power of p, is not in the range [2..n].

Zgarb

Posted 2017-02-06T18:31:40.207

Reputation: 39 083

1

PHP, 101 93 91 88 bytes

just a little bit of real maths ...

for($n=$argv[$i=1];$n>$j=$i++;$j?:$r[$p=$i**~~log($n,$i)]=$p)for(;$i%$j--;);print_r($r);

breakdown

for($n=$argv[$i=1];     // loop $i from 2 to $n
    $n>$j=$i++;             // 0.: init $j to $i-1
    $j?:                    // 2. if $i is prime
        $r[$p=$i**~~log($n,$i)]=$p) // 3. add maximum power to results
    for(;$i%$j--;);         // 1. prime check (if $i is prime, $j will be 0)
print_r($r);            // print results

Titus

Posted 2017-02-06T18:31:40.207

Reputation: 13 814

1

JavaScript ES7, 93 bytes

Recursively iterate i from 0 up to and including n. If i is prime raise it to the highest floored exponent that makes it <= n (i ^ floor(log(n) / log(i)))

F=(n,i=n)=>i?[...((P=j=>i%--j?P(j):1==j)(i)?[i**((l=Math.log)(n)/l(i)|0)]:[]),...F(n,--i)]:[]

George Reith

Posted 2017-02-06T18:31:40.207

Reputation: 2 424