This is my response to The Weekly Challenge #170.
10 Primorial Numbers
.
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.
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"
.
#! /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.