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
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;
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 more information, please refer to the 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 ]
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";
}
}
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 = @{$_[0]};
my @B = @{$_[1]};
my @answer;
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;
}
}
}
}
return \@answer;
}
The Perl version of printMatrix()
looks like this.
sub printMatrix {
my @matrix = @{$_[0]};
for my $row (@matrix) {
for my $col (@{$row}) {
printf '%2d ', $col;
}
print "\n";
}
}
printMatrix(kroneckerProduct(\@A, \@B));