### Perl Weekly Challenge: Week 170

#### Challenge 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)
``````

This can be computed in Raku as a one-liner.

``````my \$n = 1; (1, |(0 .. *).grep({ .is-prime })[^9]).map({ \$n *= \$_ }).join(q{, }).say
``````

(Full code on Github.)

First we set up a variable `\$n` which will hold the current running total of multiplied primes (i.e. the current primorial number.)

Then we set up an list primed (haha! get it?) with 1 because apparently 1 is the first primorial number even though it isn't a prime by most definitions.

`(0 .. *).grep({ .is-prime })[^9]` uses a lazy list to give us the next 9 prime numbers. The `|` before this is to flatten the results so we can add them as individual elements to our primorial list.

`.map({ \$n *= \$_ })` takes `\$n` and multiplies it by each member of the list which gives us a list of 10 primorials.

Then the standard `.join(q{, }).say` is used to print out the results in a nice way.

For Perl I had to break out my veteran `isPrime()` and `nextPrime()` functions and instead of `grep()` and `map()`, I used a loop to create the list of Primorials.

``````my @primorials = (1);
my \$n = 1;

until (scalar @primorials == 10) {
push @primorials, \$n *= nextPrime();
}

say join q{, }, @primorials;
``````

(Full code on Github.)

In case you wanted to know, the first 10 primorials are 1, 2, 6, 30, 210, 2310, 30030, 510510, 9699690 and 223092870.

#### Challenge 2:

Kroneker Product

You are given 2 matrices.

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

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 ]
``````

Lucky for me, my daughter Shailaja has taken linear algebra recently enough that she still remembers this stuff. Once I was up to speed, this was rather easy in Raku. Even so, I hard-coded the two matrices from the example rather than allowing for arbitrary input.

``````printMatrix((@A X @B).map({ [X*] \$_ }));
``````

`@A X @B` gives the cross product of the two arrays. In orther words it produces an array where each element is an array consisting of one element from `@A` and one element from `@B`. Then `.map({ [X*] \$_ })` multiplies the elements of each of those arrays together. The result is a matrix that contains the Kroneker Product of `@A` and `@B`.

`printMatrix()` is just a small function to pretty-print a two-dimensional array of integers like our matrices.

``````sub printMatrix(@matrix) {
for @matrix -> @row {
for @row -> \$col {
\$col.fmt('%2d ').print;
}
print "\n";
}
}
``````

(Full code on Github.)

I am not that happy with my Perl version. For a start, deprived of all those fancy Raku operators, it uses 4-level nested loops which can't be good with large matrices from an efficiency point of view. It works well enough for the sample input though.

``````sub kroneckerProduct {
my @A = @{\$_};
my @B = @{\$_};

for my \$a (0 .. scalar @A - 1) {
for my \$aa (@{\$A[\$a]}) {
for my \$b (0 .. scalar @B - 1) {
for my \$bb (@{\$B[\$b]}) {
``````

Also the line below for ensuring the results get put in the right place in the output matrix feels hacky to me. If I had a 3 x 3 matrix, would it be enough to change it to `\$a * 3` or would some more complex calculation be needed? Again, what I have works for the task at hand but one day I really should try and generalize this.

``````                    push @{\$answer[\$a * 2 + \$b]}, \$aa * \$bb;
}
}
}
}

}
``````

The Perl version of `printMatrix()` looks like this.

``````sub printMatrix {
my @matrix =  @{\$_};
for my \$row (@matrix) {
for my \$col (@{\$row}) {
printf '%2d ', \$col;
}
print "\n";
}
}

printMatrix(kroneckerProduct(\@A, \@B));
``````

(Full code on Github.)