The Primorial Soup
A Raku Product

by Arne Sommer

The Primorial Soup - a Raku Product

[189] Published 25. June 2022.

This is my response to The Weekly Challenge #170.

Challenge #170.1: Primorial Numbers

Write a script to generate first 10 Primorial Numbers.

Primorial numbers are those formed by multiplying successive prime numbers.

For Example:
P(0) = 1    (1)
P(1) = 2    (1x2)
P(2) = 6    (1x2×3)
P(3) = 30   (1x2×3×5)
P(4) = 210  (1x2×3×5×7)

Note that 1 is not a prime, so the sequence should arguably start with P(1) = 2. Wikipedia supports both views.

File: primorial-numbers
#! /usr/bin/env raku

unit sub MAIN (Int $count where $count > 0 = 10);  # [1]

my $primes := (1 .. *).grep( *.is-prime );         # [2]

my $primorial := gather                            # [3]
{
  take my $prev = 1;                               # [4]

  for $primes -> $prime                            # [5]
  {
    take $prev = $prev * $prime;                   # [5a]
  }
}

say $primorial[^$count].join(", ");                # [6]

[1] The number of elements to print, with 10 as default.

[2] The Prime sequence.

[3] Using gather/take to set up the main (Primorial) sequence is ideal here.

See my Raku Gather, I Take article or docs.raku.org/syntax/gather take for more information about gather/take.

[4] This is the very first value in the sequence, and must be hard coded as it is not a prime. Note the usage of the $prev variable to hold the previous value in sequence.

[5] Iterate over the primes. We get the new value in the sequence by multiplying the previous one with the next unused prime [5a]. Note the assignment.

[6] (Compute and) print the required number of values.

Running it:

$ ./primorial-numbers 
1, 2, 6, 30, 210, 2310, 30030, 510510, 9699690, 223092870

Looking good.

Challenge #170.2: Kronecker Product

You are given 2 matrices.

Write a script to implement Kronecker Product on the given 2 matrices.

For more information, please refer wikipedia page.

For Example:
A = [ 1 2 ]
    [ 3 4 ]

B = [ 5 6 ]
    [ 7 8 ]

A x B = [ 1 x [ 5 6 ]   2 x [ 5 6 ] ]
        [     [ 7 8 ]       [ 7 8 ] ]
        [ 3 x [ 5 6 ]   4 x [ 5 6 ] ]
        [     [ 7 8 ]       [ 7 8 ] ]

      = [ 1x5 1x6 2x5 2x6 ]
        [ 1x7 1x8 2x7 2x8 ]
        [ 3x5 3x6 4x5 4x6 ]
        [ 3x7 3x8 4x7 4x8 ]

      = [  5  6 10 12 ]
        [  7  8 14 16 ]
        [ 15 18 20 24 ]
        [ 21 24 28 32 ]

We need a way of specifying the matrices. Spaces to separate the values, and vertical bars (|) to separate the rows seems reasonable. The example can be expressed like this: "1 2 | 3 4" and "5 6 | 7 8".

File: kronecker-product
#! /usr/bin/env raku

unit sub MAIN (Str $A, Str $B);

my @A = $A.split("|")>>.words>>.List;  # [1]
my @B = $B.split("|")>>.words>>.List;  # [1]

my $A-rows = @A.elems;                 # [2]
my $A-cols = @A[0].elems;              # [2]
my $B-rows = @B.elems;                 # [2]
# my $B-cols = @B[0].elems;            # [2a]

my @C;                                 # [3]

for ^$A-rows -> $Ar                    # [4]
{
  for ^$B-rows -> $Br                  # [5]
  {
    my @row;                           # [6]
    for ^$A-cols -> $Ac                # [7]
    {
      @row.append: (@B[$Br]).map({ $_ * @A[$Ar][$Ac] });  # [8]
    }

    @C.push: @row;                     # [9]
  }
}

@C.map: *.say;                         # [10]

[1] Turn the the string into a two-dimentional array. The postfix >>.List ensures that each row are evaluated up front, as we would have gotten (lazy) sequences if not.

[2] We need these values in the loops, so here they are. Note that the last one [2a] is not needed.

[3] The result (also a matrix) will end up here.

[4] First we iterate over the rows in A (the indices).

[5] Each of the rows in A shall result in as many rows as in B, so we iterate over that one as well.

[6] This block is where we compute the actual rows (ending up in C), one at a time, so we set up a local variable here.

[7] Then we iterate over the columns in A. Each one will add to the row.

[8] Add (with append, so that we get the values appended one at a time) the partial data. We use map to get the actual values.

[9] Add the new row to C. Here we do want a new row, so push is appropriate.

See docs.raku.org/routine/append for more information about append.

See docs.raku.org/routine/push for more information about push.

[10] Print the matrix, one sublist (i.e. matrix row) at a time.

Running it:

$ ./kronecker-product "1 2 | 3 4" "5 6 | 7 8"
[5 6 10 12]
[7 8 14 16]
[15 18 20 24]
[21 24 28 32]

Looking good. (Except for the missing tabulation and extra spaces used in the challenge, but that is a minor issue.)

And that's it.