A naturally occurring prime generator

42

8

There are quite a large number of prime generating functions. Pretty much all of them are constructed and are based on the sieve of Eratosthenes, the Möbius function or the Wilson's theorem and are generally infeasible to compute in practice. But there are also generators, that have a very easy structure and were found by accident.

In 2003 Stephen Wolfram explored a class of nested recurrence equations in a live computer experiment at the NKS Summer School. A group of people around Matthew Frank followed up with additional experiments and discovered an interesting property of the simply recurrence

a(n) = a(n-1) + gcd(n,a(n-1))

with the start value of a(1) = 7. The difference a(n) - a(n-1) = gcd(n,a(n-1)) always seemed to be 1 or a prime. The first few differences are (OEIS A132199):

1, 1, 1, 5, 3, 1, 1, 1, 1, 11, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 3, 1, 1, 
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 47, 3, 1, 5, 3, ...

If we only omit the 1s we get the following sequence (OEIS A137613):

5, 3, 11, 3, 23, 3, 47, 3, 5, 3, 101, 3, 7, 11, 3, 13, 233, 3, 467, 3, 5, 3, 
941, 3, 7, 1889, 3, 3779, 3, 7559, 3, 13, 15131, 3, 53, 3, 7, 30323, 3, ...

Eric S. Rowland proved the primeness of each element in this list a few years later. As you can see, the primes are mixed and some of them appear multiple times. It also has been proven, that the sequence includes infinitely many distinct primes. Furthermore it is conjectured, that all odd primes appear.

Because this prime generator was not constructed but simply found by accident, the prime generator is called "naturally occurring". But notice that in practice this generator is also quite infeasible to compute. As it turns out, a prime p appears only after (p–3)/2 consecutive 1s. Nevertheless implementing this prime generator will be your task.

Challenge:

Write a function or a program that prints the first n elements of the sequence A137613 (the sequence without the 1s). You can read the input number n >= 0 via STDIN, command-line argument, prompt or function argument. Output the first n elements in any readable format to STDOUT, or return an array or a list with these values.

This is code-golf. Therefore the shortest code wins.

Leaderboard:

Here is a Stack Snippet to generate both a regular leaderboard and an overview of winners by language. To make sure that your answer shows up, please start your answer with a headline, using the following Markdown template:

# Language Name, N bytes

where N is the size of your submission. If you improve your score, you can keep old scores in the headline, by striking them through. For instance:

# Ruby, <s>104</s> <s>101</s> 96 bytes

var QUESTION_ID=55272;function answersUrl(e){return"http://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),e.has_more?getAnswers():process()}})}function shouldHaveHeading(e){var a=!1,r=e.body_markdown.split("\n");try{a|=/^#/.test(e.body_markdown),a|=["-","="].indexOf(r[1][0])>-1,a&=LANGUAGE_REG.test(e.body_markdown)}catch(n){}return a}function shouldHaveScore(e){var a=!1;try{a|=SIZE_REG.test(e.body_markdown.split("\n")[0])}catch(r){}return a}function getAuthorName(e){return e.owner.display_name}function process(){answers=answers.filter(shouldHaveScore).filter(shouldHaveHeading),answers.sort(function(e,a){var r=+(e.body_markdown.split("\n")[0].match(SIZE_REG)||[1/0])[0],n=+(a.body_markdown.split("\n")[0].match(SIZE_REG)||[1/0])[0];return r-n});var e={},a=1,r=null,n=1;answers.forEach(function(s){var t=s.body_markdown.split("\n")[0],o=jQuery("#answer-template").html(),l=(t.match(NUMBER_REG)[0],(t.match(SIZE_REG)||[0])[0]),c=t.match(LANGUAGE_REG)[1],i=getAuthorName(s);l!=r&&(n=a),r=l,++a,o=o.replace("{{PLACE}}",n+".").replace("{{NAME}}",i).replace("{{LANGUAGE}}",c).replace("{{SIZE}}",l).replace("{{LINK}}",s.share_link),o=jQuery(o),jQuery("#answers").append(o),e[c]=e[c]||{lang:c,user:i,size:l,link:s.share_link}});var s=[];for(var t in e)e.hasOwnProperty(t)&&s.push(e[t]);s.sort(function(e,a){return e.lang>a.lang?1:e.lang<a.lang?-1:0});for(var o=0;o<s.length;++o){var l=jQuery("#language-template").html(),t=s[o];l=l.replace("{{LANGUAGE}}",t.lang).replace("{{NAME}}",t.user).replace("{{SIZE}}",t.size).replace("{{LINK}}",t.link),l=jQuery(l),jQuery("#languages").append(l)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",answers=[],page=1;getAnswers();var SIZE_REG=/\d+(?=[^\d&]*(?:&lt;(?:s&gt;[^&]*&lt;\/s&gt;|[^&]+&gt;)[^\d&]*)*$)/,NUMBER_REG=/\d+/,LANGUAGE_REG=/^#*\s*([^,]+)/;
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"><div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table></div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table></div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody></table><table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody></table>

Jakube

Posted 2015-08-25T06:31:23.077

Reputation: 21 462

1While the prime generator is not constructed, you're effectively implementing a trial division using the recursion. – orlp – 2015-08-25T06:48:01.490

If a(1) = 7, why doesn't the sequence begin with 7? – feersum – 2015-08-25T06:54:38.740

3@feersum because the sequence we are concerned with is a(n)-a(n-1) – Maltysen – 2015-08-25T06:55:28.473

Can n be zero? – Sp3000 – 2015-08-25T07:50:04.600

Is it valid to install a PHP extension to make my code work? – jrenk – 2015-08-25T08:11:39.040

@Sp3000 Yes, I'll update the specifications. – Jakube – 2015-08-25T08:12:27.107

@jrenk Yes, if you want. Just make sure you include the 'call extension/include extension' part to the byte-count. – Jakube – 2015-08-25T08:17:44.760

@Jakube I just need to uncomment one line in the php.ini. How should I count that? – jrenk – 2015-08-25T08:19:15.297

1@jrenk Not sure. Maybe count it as 2 bytes (since you're removing 2 chars //) and explain it in your submission. If anyone disagrees with you, you can always edit your post. – Jakube – 2015-08-25T08:22:55.050

You have an error in your list from A312199. According to the link you provide (and my programs output), there should be a 23 and 3 between 11, 3 and 47, 3. The list from A137613 also shows 23 and 3. – Corey Ogburn – 2015-08-25T17:23:48.463

@CoreyOgburn Thanks. Updated the question. No idea how I lost these two numbers. – Jakube – 2015-08-25T19:19:35.193

You sent me back to the drawing board for half an hour wondering how I pulled that off. – Corey Ogburn – 2015-08-25T19:23:35.753

Answers

19

Pyth, 14 13 bytes

meaYhP+sY-5dQ

Uses a(n) = Lpf(6 - n + sum(a(i) for i in range(1, n)) where Lpf means least prime factor.

Try it here online.

orlp

Posted 2015-08-25T06:31:23.077

Reputation: 37 067

7

Python 3.5.0b1+, 95 93 bytes

Link to Python 3.5.0b1+ release

import math
def f(k,n=2,a=7,L=[]):x=math.gcd(n,a);return k and f(k-1%x,n+1,a+x,L+1%x*[x])or L

A direct implementation of the recurrence, featuring:

  • Our good friend 1%x, and
  • math.gcd, as opposed to fractions.gcd.

Sp3000

Posted 2015-08-25T06:31:23.077

Reputation: 58 729

What does 1%x do? Side question: where do I find documentation of the revision history of Python that includes betas? Edit: Nevermind, found it at the bottom of the revision history.

– mbomb007 – 2015-08-27T04:33:33.130

@mbomb007 Since x >= 1, 1%x returns 0 if x == 1, 1 otherwise (used to decide whether to add x to the list) – Sp3000 – 2015-08-27T04:42:30.777

5

Julia, 110 bytes

n->(a(n)=(n≥1&&(n==1?7:a(n-1)+gcd(n,a(n-1))));i=2;j=0;while j<n x=a(i)-a(i-1);x>1&&(j+=1;println(x));i+=1end)

Ungolfed:

function a(n::Int)
    n ≥ 1 && (n == 1 ? 7 : a(n-1) + gcd(n, a(n-1)))
end

function f(n::Int)
    i = 2;
    j = 0;
    while j < n
        x = a(i) - a(i-1)
        if x > 1
            j += 1
            println(x)
        end
        i += 1
    end
end

Alex A.

Posted 2015-08-25T06:31:23.077

Reputation: 23 761

Wow, a perfect 8k, nice :D – Beta Decay – 2015-08-25T09:52:19.300

1Use n<2 instead of n==1. Also, if you look forwards instead of backwards, you can use i=1 and x=a(i)-a(i+=1), and then println(-x) and -x>1 to correct for the negativeness, thereby avoiding the need for a separate increment of i. And is three bytes, while >= is two... but then, you can use n<1||() rather than n>=1&&()... and yet, it's not even necessary in the first place (drop the conditional, n will never be less than 1). You also don't need the outermost brackets when defining a(n). With these changes, you should at least get down to 97 bytes. – Glen O – 2015-08-25T11:11:31.807

5

PHP, 101 96 99 98 77 72 bytes

<?for(;2>$t=gmp_strval(gmp_gcd(~++$i,7+$e+=$t))or$argv[1]-=print"$t ";);


Usage:
Call the Script with an argument: php -d error_reporting=0 script.php 30
If you want to test it you need to uncomment ;extension=php_gmp.dll in your php.ini
--> extension=php_gmp.dll
Should I add the extension to my byte count? Any thoughts?


Log:
Saved 3 bytes thanks to Ismael Miguel.
Saved 26 bytes thanks to primo.

jrenk

Posted 2015-08-25T06:31:23.077

Reputation: 451

1You can shorten your opening tag to <? and remove the definition of $j. – Ismael Miguel – 2015-08-25T19:26:59.483

@IsmaelMiguel should the tag also count? – jrenk – 2015-08-25T19:32:51.213

1Yes, it counts. But you can remove that newline. Which will save 1-2 bytes, depending on how you counted your code size. – Ismael Miguel – 2015-08-25T19:36:27.850

@IsmaelMiguel Thanks for the Help! – jrenk – 2015-08-25T19:38:35.670

You're welcome. You still have an useless whitespace after the <?. – Ismael Miguel – 2015-08-25T19:40:55.863

@IsmaelMiguel Now I'm with you! Didn't know I could do that thanks! – jrenk – 2015-08-25T19:43:39.520

1

Minor improvements: Use < in $j<=$argv[1] (prints one too many) (-1). Leave $e uninitialized, use $e+7 instead (-3). Use for(;;) instead of while(), making use of the pre- and post-expressions (-2). Replace echo$t.' ';$j++ with $j+=print"$t ", drop the brackets (-3). Replace if($t>1) with 2>$t|| (-2). Combine the assignment to $t with the conditional, switch || for or, drop the brackets (-5). Move $argv[1] to the $j increment, move the entire expression to the for conditional (-2). Change >=$j+=print to -=print (-3). Step by step: http://codepad.org/s6LNSPSM

– primo – 2015-08-26T07:45:10.410

1@primo thanks for the nice explanation! Didn't know I could do all that. – jrenk – 2015-08-26T07:51:35.233

1

A few more: Combine $e+7 with $e+=$t (-2). Leave $i uninitialized, use ~++$i instead (-3). http://codepad.org/fDIImajp

– primo – 2015-08-26T08:03:20.133

@primo You are actually my hero now! Thanks – jrenk – 2015-08-26T08:08:04.697

1Rule of thumb for php: if you program doesn't look like <?for(;...;);, you're not done golfing ;) – primo – 2015-08-26T08:09:02.263

4

Pyth, 30 bytes

Very badly golfed, can be considerably reduced. Defines recursive function at front, filters .first-n, and then maps the difference.

L?tb+KytbibK7m-yhdyd.ft-yhZyZQ

Try it here online.

Maltysen

Posted 2015-08-25T06:31:23.077

Reputation: 25 023

This gives the wrong output for n = 0 – Sp3000 – 2015-08-25T08:16:11.720

2@Sp3000 that is a bug in Pyth. I'll put in a pull request. – Maltysen – 2015-08-25T08:19:42.713

Bug found and fixed - patch will be implemented once github stops being DDoS'd. – isaacg – 2015-08-25T11:49:35.303

Bug fixed - DDoS is slowly going away. – isaacg – 2015-08-25T12:30:45.327

@isaacg: This reminds me of a Meta page where someone wanted to know whether PCG has achieved anything external, but I can't find the question. – Thomas Weller – 2015-08-25T21:25:46.313

1

Here it is: http://meta.codegolf.stackexchange.com/questions/5318/what-contributions-has-ppcg-made-to-the-fields-of-math-or-computer-science. Personally I'd consider bug fixes in programming languages as an answer

– Thomas Weller – 2015-08-25T21:28:54.277

2@ThomasWeller It kind of achieved the whole language ... – isaacg – 2015-08-26T02:42:33.333

Perl 5.8 is quite possibly the most golfed language in history. Consequently, 5.10 had a lot of bug fixes. – primo – 2015-08-26T13:12:34.277

4

Julia, 69 67 bytes

n->(i=1;a=7;while n>0 x=gcd(i+=1,a);a+=x;x>1&&(n-=1;println(x))end)

This is a simple iterative solution to the problem. x is the difference (which is the gcd), and then I update a by adding x.

Glen O

Posted 2015-08-25T06:31:23.077

Reputation: 2 548

I think it prints A231900.

– alephalpha – 2015-08-27T07:56:33.333

@alephalpha - I think I see the error. Easily fixed. Even shaved two bytes off in the process. – Glen O – 2015-08-27T12:07:11.507

4

Haskell, 51 bytes

d=zipWith gcd[2..]$scanl(+)7d
f=($filter(>1)d).take

Note that f is a function that will return the first n elements.

Rather than computing the a(n) and then working out the differences, we compute the differences d(n) and sum them together to get a(n). (Those unfamiliar with Haskell may protest that we need a(n) first in order to get d(n), but of course lazy evaluation gets us around this problem!)

Ungolfed:

a = scanl (+) 7 d        -- yielding a(n) = 7 + d(1) + d(2) + ... + d(n-1)
d = zipWith gcd [2..] a  -- yielding d(n) = gcd(n+1, a(n))

f n = take n $ filter (> 1) d -- get rid of 1s and take the first n

Artelius

Posted 2015-08-25T06:31:23.077

Reputation: 421

3

JavaScript (ES6), 91

Recursive gcd, iterative main function. Not so fast.

Usual note: test running the snippet on any EcmaScript 6 compliant browser (notably not Chrome not MSIE. I tested on Firefox, Safari 9 could go)

F=m=>{
  for(G=(a,b)=>b?G(b,a%b):a,o=[],p=7,n=1;m;d>1&&(o.push(d),--m))
    p+=d=G(++n,p);
  return o
}

O.innerHTML=F(+I.value)
<input id=I value=10><button onclick='O.innerHTML=F(+I.value)'>-></button>
<pre id=O></pre>

edc65

Posted 2015-08-25T06:31:23.077

Reputation: 31 086

3

Haskell, 74 71 66 bytes

f=($filter(>1)$tail>>=zipWith(-)$scanl(\x->(x+).gcd x)7[2..]).take

Used the trick here: https://codegolf.stackexchange.com/a/39730/43318, and made point-free.

(Previous: 71 bytes)

a=scanl(\x->(x+).gcd x)7[2..]
f m=take m$filter(>1)$zipWith(-)(tail a)a

First make the sequence of a's, and then take the differences.

(Previous: 74 bytes)

f m=take m$filter(>1)$map snd$scanl(\(x,d)->(\y->(x+y,y)).gcd x)(7,1)[2..]

Standard list functions, plus clever use of lambda function. Note this is 1 byte shorter than the more obvious

g m=take m$filter(>1)$map snd$scanl(\(x,d)n->(x+gcd x n,gcd x n))(7,1)[2..]

If we don't count imports, I can get this down to 66.

import Data.List
h m=take m$filter(>1)$snd$mapAccumL(\x->(\y->(x+y,y)).gcd x)7[2..]

Holden Lee

Posted 2015-08-25T06:31:23.077

Reputation: 131

3

PARI/GP, 60 bytes

a(n)=a=7;i=1;while(n,if(1<d=gcd(i+=1,a),n-=1;print(d));a+=d)

Taken more or less straight from the definition a(n) - a(n-1) = gcd(n, a(n-1))

Output for a(20):

5
3
11
3
23
3
47
3
5
3
101
3
7
11
3
13
233
3
467
3

primo

Posted 2015-08-25T06:31:23.077

Reputation: 30 891

2

C++, 193 182 180 172 bytes

Thanks @Jakube - saved 8 bytes on output.

int g(int a,int b){return a==b?a:a>b?g(b,a-b):g(a,b-a);}void f(int *r,int n){int m=1,i=0,a=7,b;while(i<n){b=g(a,++m);if(b>1){r[i]=b;++i;}a+=b;}}int main(){int r[6];f(r,6);}

EvgeniyZh

Posted 2015-08-25T06:31:23.077

Reputation: 141

You can probably save a few bytes by defining a function f, that returns an array with the results. This way you can remove the include, the scanf and the print. – Jakube – 2015-08-27T07:24:24.767

2

Mathematica, 59 bytes

For[i=j=1;a=7,i<=#,,d=GCD[++j,a];If[d>1,Print@d;i++];a+=d]&

alephalpha

Posted 2015-08-25T06:31:23.077

Reputation: 23 988