Centenary Sequences with Raku
Part 4

Primes and Fibonacci

by Arne Sommer

Centenary Sequences with Raku - Part 4: Primes and Fibonacci

[100.4] Published 4. November 2020.

See also: The Introduction | Part 1: Raku Part 2: Arithmetic and Geometric Sequences | Part 3: Not True, or Not

Prime Numbers

033. Prime Numbers
Prime numbers are only divisible by 1 and the number itself.

Adding a grep clause using the is-prime method does the trick:

(1 ... Inf).grep( *.is-prime )                                          # 033
> say (1 ... Inf).grep( *.is-prime )[^20];
(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71)

Note that 1 is not a prime number.

034. Prime Number Length
The number of digits in the prime numbers, instead of the numbers themselves:

(1 ... Inf).grep( *.is-prime ).map( *.chars )                           # 034
> (1 ... Inf).grep( *.is-prime ).map( *.chars )[^30]
(1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3)

035. Prime Number Length Grouping
The number of prime numbers with the same number of digits:

> say (1 ... Inf).grep( *.is-prime ).map( *.chars )[^30].Bag;
Bag(1(4) 2(21) 3(5))

We have 4 primes with 1 digit, 21 with 2 digits and 5 with 3 digits - in the sample (of 30 values).

This works as we have chosen a selection (the 30 first values) of the infinite sequence. This will not work otherwise.

A Bag is a hash variety where the keys are the numbers we add, and the values are their frequency.

We can fix this with gather/take:

File: prime-number-length-grouping
unit sub MAIN (Int $start, Int $count = 8);                             # 035

my $pnl := (1 ... Inf).grep( *.is-prime ).map( *.chars );

my $pnlg := gather
{
  my $count   = 1;
  my $current = 1;

  for $pnl -> $value
  {
    if $value > $current
    {
      take $count;
      $count   = 1;
      $current = $value;
    }
    else
    {
      $count++;
    }
  }
}

put $pnlg[^$count];
$ ./prime-number-length-grouping 6
(5 21 143 1061 8363 68906)

036. Prime Number Difference
The difference between the prime numbers, instead of the actual numbers:

File: prime-number-difference
unit sub MAIN (Int $count = 20);                                        # 036

my $primes := (1 ... Inf).grep( *.is-prime );

my $pnd := gather
{
  my $prev    = 0;

  for $primes -> $current
  {
    take $current - $prev;
    $prev = $current;
  }
}

put $pnd[^$count];
$ ./prime-number-difference 30
2 1 2 2 4 2 4 2 4 6 2 6 4 2 4 6 6 2 6 4 2 6 4 6 8 4 2 4 2 4

037. Circular Primes

A Circular Prime is a prime number where all the cyclically permutations of the number (in base 10) are also primes. E.g. 1193 is a Circular Prime, since 1931, 9311 and 3119 all are also primes.

Raku does not have a builtin function for Cyclical Permutations, but it is easy to write one.

sub cyclical-permutations ($number)
{
  (1..$number.chars).map({ $number.comb.rotate($_).join });
}

Note that the original value is included at the end of the list.

(1..Inf).grep({ $_.is-prime &&                                          # 037a
   all( cyclical-permutations($_)>>.is-prime ) })
> say (1..Inf).grep({ $_.is-prime &&
   all( cyclical-permutations($_)>>.is-prime ) })[^20]
(2 3 5 7 11 13 17 31 37 71 73 79 97 113 131 197 199 311 337 373)

I have included the program «circular-primes» in the zip file.

We can inline the «cyclical-permutations» function:

(1..Inf).grep({ $_.is-prime &&                                          # 037b
  all( (1..$_.chars).map( -> $i { $_.comb.rotate($i).join })>>.is-prime ) })

We can skip the first part, as the original value is included in the Cyclical Permutations (and will be checked for primeness anyway).

(1..Inf).grep({                                                         # 037c
  all( (1..$_.chars).map( -> $i { $_.comb.rotate($i).join })>>.is-prime ) })

038. Sophie Germain Primes

A prime number p is a Sophie Germain Prime if the number 2p + 1 is also a prime:

(1..Inf).grep({ $_.is-prime &&  ($_ * 2 + 1).is-prime })                # 038
> say (1..Inf).grep({ $_.is-prime &&  ($_ * 2 + 1).is-prime })[^20];
(2 3 5 11 23 29 41 53 83 89 113 131 173 179 191 233 239 251 281 293)

039. Safe Primes

The primes we get from 2p + 1 in the «Sophie Germain Primes» (see above):

(1..Inf).grep({ $_.is-prime &&  ($_ * 2 + 1).is-prime }).map(* * 2 +1)  # 039
> say (1..Inf)
  .grep({ $_.is-prime &&  ($_ * 2 + 1).is-prime })
  .map(* * 2 +1)[^20];
(5 7 11 23 47 59 83 107 167 179 227 263 347 359 383 467 479 503 563 587)

Fibonacci and Friends

040. Fibonacci Numbers (0 based)

The Fibonacci Numbers is this sequence:

(0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233 ...)

Raku is not capable of detecting the pattern, which is: The first value is 0, the second is 1, and all the other values are the sum of the two values to the left of it.

We can specify the rule like this:

(0, 1, * + * ... Inf)                                                   # 040a
> say (1, 1, * + * ... Inf).grep( *.is-prime )[^20];
(0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181)

If you don't like the * placeholders, named positional parameters can be used instead - inside a {} block:

(0, 1, { $^a + $^b } ... Inf)                                           # 040b

041. Fibonacci Numbers (1 based)
The first value (0) in the sequence is sometimes skipped. We can do that like this:

(1, 1, * + * ... Inf)                                                   # 041
> say (1, 1, * + * ... Inf)[^10];
(1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765)

042. Fibonacci Primes

The Fibonacci Primes are the Fibonacci Numbers that are primes.

(1, 1, * + * ... Inf).grep( *.is-prime )                                # 042
> say (1, 1, * + * ... Inf).grep( *.is-prime )[^10];
(2 3 5 13 89 233 1597 28657 514229 433494437)

043. Leonardo Numbers

The Leonardo Numbers are similar to the Fibonacci Numbers. The first two values are 1, and after that the value is the sum of the two values to the left of it - in addition to 1.

(1, 1, ( * + * +1 ) ... Inf)                                            # 043
> say (1, 1, ( * + * +1 ) ... Inf)[^20];
(1 1 3 5 9 15 25 41 67 109 177 287 465 753 1219 1973 3193 5167 8361 13529)

044. Leonardo vs Fibonacci

We can compute the difference between the Leonardo and Fibonacci (1 based) Numbers; for each index, we take Leonardo - Fibonacci.

File: leonardo-vs-fibonacci
unit sub MAIN (Int $count = 10);                                        # 044

my $fib := (1, 1, * + * ... Inf);
my $leo := (1, 1, ( * + * +1 ) ... Inf);

my $diff := gather
{
  my $count = 0;

  loop
  {
    take $leo[$count] - $fib[$count];
    $count++;
  }
}

say $diff[^$count];
$ ./leonardo-vs-fibonacci 20
(0 0 1 2 4 7 12 20 33 54 88 143 232 376 609 986 1596 2583 4180 6764))  

045. Lucas Numbers

The Lucas Numbers are also similar to the Fibonacci Numbers. The first two values are 2 and 1, and after that the value is the sum of the two values to the left of it.

(2, 1, ( * + * ) ... Inf)                                               # 045
> say (2, 1, ( * + * ) ... Inf)[^20];
(2 1 3 4 7 11 18 29 47 76 123 199 322 521 843 1364 2207 3571 5778 9349)

046. Lucas vs Fibonacci

The difference between the Lucas and Fibonacci Numbers:

File: lucas-vs-fibonacci
unit sub MAIN (Int $count = 10);                                        # 046

my $fib := (1, 1, * + * ... Inf);
my $luc := (2, 1, * + * ... Inf);

my $diff := gather
{
  my $count = 0;

  loop
  {
    take $luc[$count] - $fib[$count];
    $count++;
  }
}

say $diff[^$count];
$ ./lucas-vs-fibonacci 20
(1 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584)

047. Lucas vs Leonardo

The difference between the Lucas and Leonardo Numbers:

File: leonardo-vs-lucas
unit sub MAIN (Int $count = 10);                                        # 047

my $leo := (1, 1, ( * + * +1 ) ... Inf);
my $luc := (2, 1, * + * ... Inf);

my $diff := gather
{
  my $count = 0;

  loop
  {
    take $leo[$count] - $luc[$count];
    $count++;
  }
}

say $diff[^$count];
./leonardo-vs-lucas 20
(-1 0 0 1 2 4 7 12 20 33 54 88 143 232 376 609 986 1596 2583 4180)

048. Fibonacci vs Lucas vs Leonardo

The difference between the Fibonacci, Lucas and Leonardo Numbers:

File: fibonacci-lucas-leonardo
unit sub MAIN (Int $count = 10);                                        # 048

my $fib := (1, 1, * + * ... Inf);
my $luc := (2, 1, * + * ... Inf);
my $leo := (1, 1, ( * + * +1 ) ... Inf);

my $diff := gather
{
  my $count = 0;

  loop
  {
    take $fib[$count] + $luc[$count] - $leo[$count];
    $count++;
  }
}

say $diff[^$count];
$ ./fibonacci-lucas-leonardo 20
(2 1 2 2 3 4 6 9 14 22 35 56 90 145 234 378 611 988 1598 2585)

049. Tribonacci Numbers

The Tribonacci Numbers start with the numbers 0,0,1. After that the numbers are the sum of the three numbers to the left of it:

(0, 0, 1, { $^a + $^b + $^c } ... Inf)                                  # 049

Placeholder * does not work here, but we can use named placeholders.

> say (0, 0, 1, { $^a + $^b + $^c } ... Inf)[^20];
(0 0 1 1 2 4 7 13 24 44 81 149 274 504 927 1705 3136 5768 10609 19513)

050. Padovan Sequence

The Padovan Sequence has 1 as the first three values, and after that the values are the sum of the two numbers before the number to the left of the current one (i.e. skipping on number)

We have to access a third named placeholder, so that the first two get the correct values. We are ignoring the third one, by multiplying it with zero:

(1, 1, 1, { $^a + $^b + 0 * $^c } ... Inf)                              # 050
> say (1, 1, 1, { $^a + $^b + 0 * $^c } ... Inf)[^25];
(1 1 1 2 2 3 4 5 7 9 12 16 21 28 37 49 65 86 114 151 200 265 351 465 616)

Fibonacci Inspired Sequences (FIS)

The plus sign (+) in the middle can be exchanged for any other binary operator.

051. FIS: Multiplication
Multiplication (*) looks nice. Or perhaps not...

(1, 2, * * * ... Inf)                                                   # 051
> say (1, 2, * * * ... Inf)[^11];
(1 2 2 4 8 32 256 8192 2097152 17179869184 36028797018963968)

052. FIS: Exponentiation
Exponentiation (**) turns out to be a disappointment:

(1, 2, * ** * ... Inf)                                                  # 052
> say (1, 2, * ** * ... Inf)[^25];
(1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1)

053. FIS: Subtraction
Subtraction (-) gives a strange looking sequence:

(0, 1, { $^a - $^b }... Inf)                                            # 053
> say (1, 1, { $^a - $^b } ... Inf)[^20];
(1 1 0 1 -1 2 -3 5 -8 13 -21 34 -55 89 -144 233 -377 610 -987 1597)

054. FIS: Reverse Subtraction
We can swap the values, so that we subtract the first value from the second one:

(0, 1, { $^b - $^a }... Inf)                                            # 054

The repeating pattern looks nice:

> say (1, 1, { $^b - $^a } ... Inf)[^20];
(1 1 0 -1 -1 0 1 1 0 -1 -1 0 1 1 0 -1 -1 0 1 1)

055. The Highest Number
We can use binary operators with names as well:

> (1, 2, * max * ... Inf)                                               # 055

The definition looks more impressive than the result:

> say (1, 2, * max * ... Inf)[^10];
(1 2 2 2 2 2 2 2 2 2)

056. In Two Directions (at Once)
We can use divison to set up a sequence where every other value goes off in a different direction:

(1, 2, * / * ... Inf)                                                  # 056
> say (1, 2, * / * ... Inf)[^10]
(1, 2, 0.5, 4, 0.125, 32, 0.003906, 8192, 0.00000048, 17179869184)

This essentially gives us two sequences; the values with even indices are counting down towards zero, and the ones with odd indices are counting up towards infinity. But the values depend on each other, so we cannot split the sequence in two.

The Next Part

Part 5: Divisors and Factors.