Perl Weekly Challenge 108.
My solutions (task 1 and task 2) to the The Weekly Challenge - 108.
Task 1: Locate Memory
Submitted by: Mohammad S Anwar
Write a script to declare a variable or constant and print it’s location in the memory.
If I understand correctly, when you print a reference you get the
location within parenthesis. Thus, it seems that all that is
required is to remove the parenthesis. I try it below with a few my
and our
variables, with a subroutine and with a constant (which is actually a function):
# Perl weekly challenge 108
# Task 1: Locate Memory
#
# See https://wlmb.github.io/2021/04/12/PWC108/#task-1-locate-memory
use strict;
use warnings;
use v5.12;
use constant PI=>3.14;
sub X {}
my ($x, @x, %x);
our ($X, @X, %X);
my %map=('$x'=>\$x, '@x'=>\@x, '%x'=>\%x, '$X'=>\$X, '@X'=>\@X, '%X'=>\%X, '&X'=>\&X, 'PI'=>\&PI);
foreach (sort keys %map){
my $r=$map{$_};
$r=~/\((.*)\)/;
say "$_=>$1";
}
Run it:
./ch-1.pl
Results:
$X=>0x5582b0a0e710
$x=>0x5582b09e0da0
%X=>0x5582b0a03f98
%x=>0x5582b0a0e8f0
&X=>0x5582b0a0e860
@X=>0x5582b0a0e8a8
@x=>0x5582b09e0cc8
PI=>0x5582b0a0e170
Task 2: Bell Numbers
Submitted by: Mohammad S Anwar
Write a script to display top 10 Bell Numbers. Please refer to wikipedia page for more informations.
Example:
B0: 1 as you can only have one partition of zero element set B1: 1 as you can only have one partition of one element set {a}. B2: 2 {a}{b} {a,b} B3: 5 {a}{b}{c} {a,b}{c} {a}{b,c} {a,c}{b} {a,b,c} B4: 15 {a}{b}{c}{d} {a,b,c,d} {a,b}{c,d} {a,c}{b,d} {a,d}{b,c} {a,b}{c}{d} {a,c}{b}{d} {a,d}{b}{c} {b,c}{a}{d} {b,d}{a}{c} {c,d}{a}{b} {a}{b,c,d} {b}{a,c,d} {c}{a,b,d} {d}{a,b,c}
One can obtain partitions of n+1
elements by either adding a set {z}
to the previous partitions, where z
is the n+1-th
element, or
creating new partitions from old partitions by adding the element z
to one of the previous sets. This is easily done recursively.
I make a routine bell($n)
that returns a ref to an array with all
partitions of $n elemens
. Each partition is a ref to an array of
sets. Each set is a ref to an array of elements. The Bell number may
be obtained from the number of partitions.
# Perl weekly challenge 108
# Task 2: Bell numbers
# Complete enumeration.
#
# See https://wlmb.github.io/2021/04/12/PWC108/#task-2-bell-numbers
use warnings;
use strict;
use v5.12;
use Memoize;
memoize('bell');
my $last=shift @ARGV;
die "Usage: ./ch-2a.pl last\n to generate Bell numbers up to last>=0"
unless defined $last and $last >=0;
foreach(0..$last){
my $partitions=bell($_);
my $bell=@$partitions;
say "\nbell($_)=$bell";
foreach my $p(@$partitions){
print "\t";
foreach(@$p){
print "{", join(",", @$_), "}";
}
say "";
}
}
sub bell {
my $n=shift;
die "Argument of Bell should be non-negative" if $n<0;
return [[[]]] if $n==0;
return [[[1]]] if $n==1;
my $previous=bell($n-1);
my @with_new_set=map {[@$_, [$n]]} @$previous;
my @with_new_element=map {
my @sets=@$_; map {[@sets[0..$_-1], [@{$sets[$_]}, $n], @sets[$_+1..@sets-1]]}
(0..@sets-1)} @$previous;
my @current=(@with_new_set, @with_new_element);
return [@current];
}
Example
./ch-2a.pl 4
Results:
bell(0)=1
{}
bell(1)=1
{1}
bell(2)=2
{1}{2}
{1,2}
bell(3)=5
{1}{2}{3}
{1,2}{3}
{1,3}{2}
{1}{2,3}
{1,2,3}
bell(4)=15
{1}{2}{3}{4}
{1,2}{3}{4}
{1,3}{2}{4}
{1}{2,3}{4}
{1,2,3}{4}
{1,4}{2}{3}
{1}{2,4}{3}
{1}{2}{3,4}
{1,2,4}{3}
{1,2}{3,4}
{1,3,4}{2}
{1,3}{2,4}
{1,4}{2,3}
{1}{2,3,4}
{1,2,3,4}
The problem with the approach above is that the listing of all partitions rapidly becomes too large. If it is not needed and only the Bell numbers are required, I could add a flag to avoid printing the partitions, but a better, simpler and more efficient alternative would be to use an algorithm such as the triangle algorithm to compute the Bell numbers.
# Perl weekly challenge 108
# Task 2: Bell numbers
# Triangle solution without enumeration.
#
# See https://wlmb.github.io/2021/04/12/PWC108/#task-2-bell-numbers
use strict;
use warnings;
use strict;
use v5.12;
my $last=shift @ARGV;
die "Usage: ./ch-2.pl last\n to generate Bell numbers up to last>=0"
unless defined $last and $last >=0;
my @triangle=([1], [1]);
for my $row(1..$last-1){
for my $col(1..$row){
$triangle[$row][$col]=$triangle[$row-1][$col-1]+$triangle[$row][$col-1];
}
$triangle[$row+1][0]=$triangle[$row][$row];
}
my @bell=map {$triangle[$_][0]} (0..$last);
say "Bell($_)=$bell[$_]" for 0..$last;
Example:
./ch-2.pl 10
Results:
Bell(0)=1
Bell(1)=1
Bell(2)=2
Bell(3)=5
Bell(4)=15
Bell(5)=52
Bell(6)=203
Bell(7)=877
Bell(8)=4140
Bell(9)=21147
Bell(10)=115975