Group Abstract Group Abstract

Message Boards Message Boards

A prime pencil: truncatable primes

Posted 7 years ago
POSTED BY: Roman Maeder
20 Replies
POSTED BY: Diego Ramos
POSTED BY: Roman Maeder

I also played around a bit, but focused on the large numbers, and to check my code I repeated some of you. Since we are making prime pencils, it is (for me) not about the highest number, but rather the largest (i.e. number of digits). So there can be multiple number which have the same number of digits. Here is a table (note I gave the final numbers in base 10 because I go above base 36):

enter image description here

And some plots

enter image description here

Red lines means: don't know yetÂ… Note that the length of the primes very nicely correlate with the amount of work that has to be done ;-)

Happy new years!

@Marco Thiel @Roman Maeder Perhaps we can give an update to Neil Sloane on this, a previous list also had question marks in it, so even a partial update would be useful I thinkÂ…

POSTED BY: Sander Huisman
POSTED BY: Roman Maeder
POSTED BY: Roman Maeder

If we allow for leading zeros ( meaning e.g. 013 is essentially 13 )

TruncatablePrimes[p_Integer?PrimeQ] := 
  With[{digits = IntegerDigits[p]}, {p, 
    TruncatablePrimes /@ (FromDigits /@ (Prepend[digits, #] & /@ {1, 
          2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 40, 50, 60, 70, 80, 
          90}))}];
TruncatablePrimes[p_Integer] := {}

gives more interesting results. See

TruncatablePrimes[3] // Flatten // Sort
POSTED BY: Hans Dolhaine

Usually, leading zeros are not considered. As they say in the paper referenced above:

It will be noted that we have excluded 0 as a leading digit. If we do not do this, the length of the longest left-truncatable prime becomes indeterminate since, for example, there are, with probability one, infinitely many primes of the form $10^k+3$.

So leading zeros can lead to trivial cases dominating the picture.

Best wishes,

Marco

POSTED BY: Marco Thiel

Very interesting discussion, is there some limit for base 10? can you have -say- a 200 digit truncatable prime? @Marco Thiel I guess it is time to set up some distributed computing :)

POSTED BY: Sander Huisman

Hi Sander,

no you cannot. In base 10 that is really the largest number. The scheme is such that it builds the primes up one step at a time; sometimes there are several digits that can be prepended and still give primes The algorithm follows all branches and interactively adds first digits. It turns out that after a finite number of steps all branches "die out", i.e. no other digit can be prepended.

That has of course something to do with the fact that prime numbers get sparse as we go to larger integers. The range that can be "searched" increases in higher bases, but the prime number density decreases. It turns out that the latter always wins.

In the range that we are discussing there are only two bases missing, base 24 and 30. It appears that we might be able to manage 24. Base 30 appears to more of a challenge. I have access to HPC facilities, but this algorithm needs huge speed improvements before it would make sense to attempt base 30.

It would be kind of cool if one could crowd source CPU time for such a thing. I think that this could be done similarly to the SETI project. Imagine Wolfram would be offering a scheme to donate CPU time that can be used by other people. That has all sorts of technical and legal issues, but would be cool.

Cheers,

Marco

POSTED BY: Marco Thiel

Thanks for clarifying. Looks quite a nice project! not sure if this can be sped up a lot? Primality testing is—i guess—been highly optimized in Mathematica, so going to C or so would probably not help…

What about right-truncatable primes? if you would print is 'upside down' and you 'eat' digits from the right?

Quite a cute problem!

POSTED BY: Sander Huisman

The number of right-truncatable primes for bases up to 42 is given in A076586 in OEIS. Their number is quite a bit smaller than the right-truncatable ones.

POSTED BY: Roman Maeder
POSTED BY: Marco Thiel

Hi everyone,

here is another update. My computer has been calculating for a couple of days now and here is what I've got:

bin = Databin["zR0oyN8c"]

results = SortBy[DeleteDuplicates[Flatten["Data" /. Normal[Get@bin], 1]], First]

Grid[Join[{{"base", "# sequences", "max length", "string"}}, results],Frame -> All]

enter image description here

As you can see only the bases 24 and 30 are missing. Here is a graph of the behaviour - with these two bases missing:

ListLinePlot[results[[All, {1, 3}]], PlotTheme -> "Marketing", FrameLabel -> {"base", "max length"}, 
LabelStyle -> Directive[Bold, 16], ImageSize -> Large]

enter image description here

and

ListLogPlot[results[[All, {1, 2}]], PlotTheme -> "Marketing", FrameLabel -> {"base", "number strings"}, 
LabelStyle -> Directive[Bold, 16], ImageSize -> Large, PlotRange -> All, Joined -> True]

enter image description here

There are several observations here. Here is a little diagram with highlights:

ListLinePlot[results[[All, {1, 3}]], PlotTheme -> "Marketing", 
 FrameLabel -> {"base", "max length"}, 
 LabelStyle -> Directive[Bold, 16], ImageSize -> Large, 
 PlotRange -> {All, {0, 75}}, 
 Epilog -> {Red, Thickness[0.01], Line[{{0, 6}, {30, 73}}], Green, 
   Line[{{0, 0}, {35, 21}}], White, Opacity[0.4], 
   Rectangle[{12.5, 8}, {17.5, 28}], 
   Rectangle[{18.5, 10}, {23.5, 40}], 
   Rectangle[{24.5, 18}, {29.5, 48}], 
   Rectangle[{30.5, 19}, {35.5, 53}]}]

enter image description here

The green and red lines are to guide the eye and show estimates for lowest and highest values expected. The grey boxes indicate an M like structure. Left and right of which we expect particularly long sequences. The two values that are missing at 24 and 30 are exactly between two if these M like structures. So particularly high values occur at bases that are multiples of 6.

If this type of linear interpolation was correct we might expect string lengths of 58-60 for base 24 and something close to length 70 for base 30. It appears that the CPU time needed increases roughly exponentially with the length of the sequence, so we might have to wait for quite a bit for results on these bases.

Members of this Community have contacted me and have started to use more sophisticated methods to tackle these bases. I am convinced that they will beat me to it. I would love to see their results.

Also, I think that we all use PrimeQ. This uses heuristics for large prime numbers. It might be necessary to check whether these results are actually correct.

I have not found a list of left truncatable primes that has bases as large as the ones discussed here, so it is difficult to compare.

Also, we might want to start implementing something to be able to compute this for bases larger than 35 and perhaps think about mathematical arguments for the multiples of 6 observation. One thought is that this behaves a bit like the number of divisors of the respective base.

Cheers,

Marco

POSTED BY: Marco Thiel

Dear Roman,

after programming this I came across this video. They discuss truncation from the left and the right, both sides, and numbers where you can delete digits in some order and always make it a prime.

My computations are making some progress. Here is the current table:

bin = Databin["zR0oyN8c"];

results = 
 SortBy[DeleteDuplicates[Flatten["Data" /. Normal[Get@bin], 1]], First];

Grid[Join[{{"base", "# sequences", "max length", "string"}}, results],Frame -> All]

enter image description here

So it has already cracked base 18, for which the sequence has length 43. Here is the graph:

ListLinePlot[results[[All, {1, 3}]], PlotTheme -> "Marketing", 
 FrameLabel -> {"basis", "max length"}, 
 LabelStyle -> Directive[Bold, 16], ImageSize -> Large]

enter image description here

This behaves basically like the logarithm of the total number of sequences:

ListLogPlot[results[[All, {1, 2}]], PlotTheme -> "Marketing", 
 FrameLabel -> {"basis", "number strings"}, 
 LabelStyle -> Directive[Bold, 16], ImageSize -> Large, 
 PlotRange -> All, Joined -> True]

enter image description here

I am not sure if/when the full table will be done. The bases that are currently missing are: 24, 28, 30, 32 and 34. I am not very positive about the CPU times needed for the larger ones of those.

Cheers,

Marco

POSTED BY: Marco Thiel

Very nice to consider other bases.

I haven't seen a discussion of primes that are truncatable from the right. There aren't too many of these shrinkable primes:

Clear[ShrinkablePrimes];

ShrinkablePrimes[] := Sort[ShrinkablePrimes[Range[9]]];

ShrinkablePrimes[ps_List] := Join @@ (ShrinkablePrimes /@ ps);

With[{appendDigits = Append /@ Range[9]},
  ShrinkablePrimes[p_Integer?PrimeQ] :=
   Prepend[ShrinkablePrimes[FromDigits /@ Through[appendDigits[IntegerDigits[p]]]], p]
  ];

ShrinkablePrimes[p_Integer] := {}

What's nice is that now all single-digit primes get a chance to contribute:

In[13]:= ShrinkablePrimes[]

Out[13]= {2, 3, 5, 7, 23, 29, 31, 37, 53, 59, 71, 73, 79, 233, 239,
293, 311, 313, 317, 373, 379, 593, 599, 719, 733, 739, 797, 2333,
2339, 2393, 2399, 2939, 3119, 3137, 3733, 3739, 3793, 3797, 5939,
7193, 7331, 7333, 7393, 23333, 23339, 23399, 23993, 29399, 31193,
31379, 37337, 37339, 37397, 59393, 59399, 71933, 73331, 73939,
233993, 239933, 293999, 373379, 373393, 593933, 593993, 719333,
739391, 739393, 739397, 739399, 2339933, 2399333, 2939999, 3733799,
5939333, 7393913, 7393931, 7393933, 23399339, 29399999, 37337999,
59393339, 73939133}

So the largest one is 73939133, which makes for a rather short pencil. Given the upcoming holiday season, one could consider printing it on the side of a prime candle.

POSTED BY: Roman Maeder

...and here is the intersection of the two sets, so you can sharpen your pencil from either end:

{2, 3, 5, 7, 23, 37, 53, 73, 313, 317, 373, 797, 3137, 3797, 739397}

but you have to make up your mind: you cannot change directions once you start chipping away digits.

POSTED BY: Roman Maeder

I have now slightly updated the program and am running it on a multi core machine - I haven't actually tried to speed up the code in any intelligent way.

On one multi-core machine I am defining as before:

digitrange = Join[CharacterRange["1", "9"], CharacterRange["a", "z"]];

TruncatablePrimes[p_String, basis_Integer] := 
  With[{digits = Characters[p]}, h = FromDigits[p, basis];
   If[PrimeQ[h], {p, 
     TruncatablePrimes[ToString[#], 
        basis] & /@ (StringJoin[#] & /@ (Flatten[
            Prepend[digits, #]] & /@ (List /@ 
            digitrange[[1 ;; basis - 1]])))}, {}]];

generateAllStrings[basis_Integer] := 
 DeleteDuplicates[
  SortBy[
   Flatten[
    TruncatablePrimes[#, basis] & /@ 
     Flatten[(List /@ 
        Select[digitrange[[1 ;; basis - 1]], 
         PrimeQ[FromDigits[#, basis]] &])]], StringLength[#] &]]

I then create a data bin:

CreateDatabin[]

bin = Databin["zR0oyN8c"]

I also set the permissions public so you should be able to access the databin. I then launch my kernels:

LaunchKernels[]

and execute

results = {}; ParallelDo[
 AppendTo[
  results, {k, Length[#], StringLength[#[[-1]]], #[[-1]]} &@
   generateAllStrings[k]]; DatabinAdd[bin, results];, {k, 3, 35}]

From a second computer I can now check the progress:

bin = Databin["zR0oyN8c"]

results = 
SortBy[DeleteDuplicates[Flatten["Data" /. Normal[Get@bin], 1]], First];

Grid[results, Frame -> All]

which gives

enter image description here

I can now plot the length of the string vs the base:

ListLinePlot[results[[All, {1, 3}]], PlotTheme -> "Marketing", 
 FrameLabel -> {"base", "max length"}, 
 LabelStyle -> Directive[Bold, 16], ImageSize -> Large]

enter image description here

I will try to update this once I have some of the outstanding bases.

Cheers,

Marco

POSTED BY: Marco Thiel

Dear Roman,

thank you very much for that fantastic post. I'll definitely have to get one of those pencils from somewhere. There is of course the following on question which is: What happens if we use different bases for our number system, i.e. binary numbers etc.

There is an obvious extension to all bases up to 10:

TruncatablePrimesbasis[p_Integer, basis_Integer] := 
With[{digits = IntegerDigits[p]}, 
h = FromDigits[ToString[p], basis]; 
If[PrimeQ[h], {p, TruncatablePrimesbasis[#, basis] & /@ (FromDigits /@ (Prepend[digits, #] & /@ 
Range[basis - 1]))}, {}]];

We can then generate all such strings for any base (up to 10):

generateAllStrings[basis_Integer] := 
DeleteDuplicates[SortBy[Flatten[TruncatablePrimesbasis[#, basis] & /@ (FromDigits /@ (List /@ 
Select[Range[basis - 1], PrimeQ]))], Length[IntegerDigits[#]] &]]

The following generates the table for the first few bases.

Transpose[Table[{k, generateAllStrings[k]}, {k, 2, 5}]] // Grid[#, Frame -> All] &

enter image description here

Note that for the binary system there is no such pencil/sequence. That is basically because the first prime is already two digits long, i.e. 10, and if I delete the first of the two digits I am left with 0 which is not prime.

It turns out that base 6 leads to a long list of strings (of course this contains all substrings of the same that are contained in longer strings), but basis 7 is surprisingly short:

generateAllStrings[7]
(*{2, 3, 5, 23, 25, 32, 43, 52, 65, 443, 452, 623, 625, 632, 652, 2452, \
2623, 6625, 6652, 42623, 642623, 6642623}*)

So, why did we stop at base 10. The issue is that for larger bases we need letters as digits. And we will probably need the function FromDigits that can transform an appropriate string into a number to any base up to 35 (which probably is because we then run out of letters in the alphabet). If we want to go to larger basis we have to work with strings rather than numbers. The updated program looks like this:

digitrange = Join[CharacterRange["1", "9"], CharacterRange["a", "z"]];

TruncatablePrimes[p_String, basis_Integer] := 
With[{digits = Characters[p]}, h = FromDigits[p, basis]; 
If[PrimeQ[h], {p, TruncatablePrimes[ToString[#], basis] & /@ (StringJoin[#] & /@ (Flatten[Prepend[digits, #]] & /@ (List /@ digitrange[[1 ;; basis - 1]])))}, {}]];

generateAllStrings[basis_Integer] := 
DeleteDuplicates[SortBy[Flatten[TruncatablePrimes[#, basis] & /@ 
Flatten[(List /@ Select[digitrange[[1 ;; basis - 1]], PrimeQ[FromDigits[#, basis]] &])]], StringLength[#] &]]

We can try this out like this:

Here is the longest string for base 11:

generateAllStrings[11][[-1]]

which gives a68822827.

FromDigits["a68822827", 11]

shows that this is 2276005673 which is prime. (Try PrimeQ). We can now slice off one digit by one:

Table[FromDigits[StringTake[#, -k], 11] & @"a68822827", {k, 9, 1, -1}]

and get

{2276005673, 132416863, 15493837, 1321349, 32941, 3659, 997, 29, 7}

all of which are prime. It turns out that for some bases the strings are much longer than for others ( I haven't finished calculating for basis 18 for example!). Here is what we can do:

Monitor[data = Table[{k, Length[#], StringLength[#[[-1]]], #[[-1]]} &@generateAllStrings[k], {k, 3, 17}], k]

So we save the base, the total number of sequences, the longest string length (not necessarily a unique string), and the longest string. Here is the table:

enter image description here

This shows the length of the longest sequence vs base:

enter image description here

I will try to calculate the sequences for some larger bases. As I said 18 has not finished yet. 19 is fast and short. 20 seems to take long, too. In fact, I think that it might be possible to speed this program up quite a bit, which I might want to do first....

Thanks a lot for this very nice post.

Cheers,

Marco

POSTED BY: Marco Thiel
Posted 7 years ago

Very Good - I particularly like the recursive routine you came up with.

POSTED BY: BJ Miller

enter image description here - Congratulations! This post is now a Staff Pick as distinguished by a badge on your profile! Thank you, please keep it coming!

POSTED BY: EDITORIAL BOARD
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard