# Perl Weekly Challenge 171.

My solutions (task 1 and task 2 ) to the The Weekly Challenge - 171.

``````Submitted by: Mohammad S Anwar
Write a script to generate first 20 Abundant Odd Numbers.

According to wikipedia,

A number n for which the sum of divisors σ(n) > 2n, or,
equivalently, the sum of proper divisors (or aliquot sum) s(n)
> n.

For example, 945 is the first Abundant Odd Number.

Sum of divisors:
1 + 3 + 5 + 7 + 9 + 15 + 21 + 27 + 35 + 45 + 63 + 105 + 135 + 189 + 315 = 975
``````

A straightforward solution is to check all odd numbers from 3 upwards, find all their proper divisors, and check if their sum is larger than the number, until enough abundant numbers are found. Using the Perl Data Language (PDL) yields a oneliner:

``````perl -MPDL -E '\$n=1; \$N=shift; while(\$N){\$n+=2; \$s=1+sequence(\$n/2); \$d=\$s->where(\$n%\$s==0);
\$a=\$d->sum; \$N--, say "\$n: Divisors: \$d. Sum: \$a" if \$a>\$n; }' 20|fmt -w 62 -t
``````

Results:

``````945: Divisors: [1 3 5 7 9 15 21 27 35 45 63 105 135 189
315]. Sum: 975
1575: Divisors: [1 3 5 7 9 15 21 25 35 45 63 75 105 175
225 315 525]. Sum: 1649
2205: Divisors: [1 3 5 7 9 15 21 35 45 49 63 105 147 245
315 441 735]. Sum: 2241
2835: Divisors: [1 3 5 7 9 15 21 27 35 45 63 81 105 135
189 315 405 567 945]. Sum: 2973
3465: Divisors: [1 3 5 7 9 11 15 21 33 35 45 55 63 77 99
105 165 231 315 385 495 693 1155]. Sum: 4023
4095: Divisors: [1 3 5 7 9 13 15 21 35 39 45 63 65 91 105
117 195 273 315 455 585 819 1365]. Sum: 4641
4725: Divisors: [1 3 5 7 9 15 21 25 27 35 45 63 75 105 135
175 189 225 315 525 675 945 1575]. Sum: 5195
5355: Divisors: [1 3 5 7 9 15 17 21 35 45 51 63 85 105 119
153 255 315 357 595 765 1071 1785]. Sum: 5877
5775: Divisors: [1 3 5 7 11 15 21 25 33 35 55 75 77 105
165 175 231 275 385 525 825 1155 1925]. Sum: 6129
5985: Divisors: [1 3 5 7 9 15 19 21 35 45 57 63 95 105 133
171 285 315 399 665 855 1197 1995]. Sum: 6495
6435: Divisors: [1 3 5 9 11 13 15 33 39 45 55 65 99 117
143 165 195 429 495 585 715 1287 2145]. Sum: 6669
6615: Divisors: [1 3 5 7 9 15 21 27 35 45 49 63 105 135
147 189 245 315 441 735 945 1323 2205]. Sum: 7065
6825: Divisors: [1 3 5 7 13 15 21 25 35 39 65 75 91 105
175 195 273 325 455 525 975 1365 2275]. Sum: 7063
7245: Divisors: [1 3 5 7 9 15 21 23 35 45 63 69 105 115
161 207 315 345 483 805 1035 1449 2415]. Sum: 7731
7425: Divisors: [1 3 5 9 11 15 25 27 33 45 55 75 99 135
165 225 275 297 495 675 825 1485 2475]. Sum: 7455
7875: Divisors: [1 3 5 7 9 15 21 25 35 45 63 75 105 125
175 225 315 375 525 875 1125 1575 2625]. Sum: 8349
8085: Divisors: [1 3 5 7 11 15 21 33 35 49 55 77 105 147
165 231 245 385 539 735 1155 1617 2695]. Sum: 8331
8415: Divisors: [1 3 5 9 11 15 17 33 45 51 55 85 99 153
165 187 255 495 561 765 935 1683 2805]. Sum: 8433
8505: Divisors: [1 3 5 7 9 15 21 27 35 45 63 81 105 135
189 243 315 405 567 945 1215 1701 2835]. Sum: 8967
8925: Divisors: [1 3 5 7 15 17 21 25 35 51 75 85 105 119
175 255 357 425 525 595 1275 1785 2975]. Sum: 8931
``````

The full code is:

`````` 1  # Perl weekly challenge 171
2  # Task 1: Abundant number
3  #
5  use v5.12;
6  use warnings;
7  use PDL;
8  die "Usage ./ch-1.pl N\nto obtain the first N abundant odd numbers" unless @ARGV;
9  my \$count=shift; # How many abundants are desired
10  my \$candidate=1;
11  while(\$count){
12      \$candidate+=2; # only test odd numbers
13      my \$potential_divisors=1+sequence(\$candidate/2);
14      my \$divisors=\$potential_divisors->where(\$candidate%\$potential_divisors==0);
15      my \$sum=\$divisors->sumover;
16      \$count--, say "\$candidate: Divisors: \$divisors. Sum: \$sum." if \$sum>\$candidate;
17  }
``````

Example:

``````./ch-1.pl 20|fmt -w 62 -t
``````

Results:

``````945: Divisors: [1 3 5 7 9 15 21 27 35 45 63 105 135 189
315]. Sum: 975.
1575: Divisors: [1 3 5 7 9 15 21 25 35 45 63 75 105 175
225 315 525]. Sum: 1649.
2205: Divisors: [1 3 5 7 9 15 21 35 45 49 63 105 147 245
315 441 735]. Sum: 2241.
2835: Divisors: [1 3 5 7 9 15 21 27 35 45 63 81 105 135
189 315 405 567 945]. Sum: 2973.
3465: Divisors: [1 3 5 7 9 11 15 21 33 35 45 55 63 77 99
105 165 231 315 385 495 693 1155]. Sum: 4023.
4095: Divisors: [1 3 5 7 9 13 15 21 35 39 45 63 65 91 105
117 195 273 315 455 585 819 1365]. Sum: 4641.
4725: Divisors: [1 3 5 7 9 15 21 25 27 35 45 63 75 105 135
175 189 225 315 525 675 945 1575]. Sum: 5195.
5355: Divisors: [1 3 5 7 9 15 17 21 35 45 51 63 85 105 119
153 255 315 357 595 765 1071 1785]. Sum: 5877.
5775: Divisors: [1 3 5 7 11 15 21 25 33 35 55 75 77 105
165 175 231 275 385 525 825 1155 1925]. Sum: 6129.
5985: Divisors: [1 3 5 7 9 15 19 21 35 45 57 63 95 105 133
171 285 315 399 665 855 1197 1995]. Sum: 6495.
6435: Divisors: [1 3 5 9 11 13 15 33 39 45 55 65 99 117
143 165 195 429 495 585 715 1287 2145]. Sum: 6669.
6615: Divisors: [1 3 5 7 9 15 21 27 35 45 49 63 105 135
147 189 245 315 441 735 945 1323 2205]. Sum: 7065.
6825: Divisors: [1 3 5 7 13 15 21 25 35 39 65 75 91 105
175 195 273 325 455 525 975 1365 2275]. Sum: 7063.
7245: Divisors: [1 3 5 7 9 15 21 23 35 45 63 69 105 115
161 207 315 345 483 805 1035 1449 2415]. Sum: 7731.
7425: Divisors: [1 3 5 9 11 15 25 27 33 45 55 75 99 135
165 225 275 297 495 675 825 1485 2475]. Sum: 7455.
7875: Divisors: [1 3 5 7 9 15 21 25 35 45 63 75 105 125
175 225 315 375 525 875 1125 1575 2625]. Sum: 8349.
8085: Divisors: [1 3 5 7 11 15 21 33 35 49 55 77 105 147
165 231 245 385 539 735 1155 1617 2695]. Sum: 8331.
8415: Divisors: [1 3 5 9 11 15 17 33 45 51 55 85 99 153
165 187 255 495 561 765 935 1683 2805]. Sum: 8433.
8505: Divisors: [1 3 5 7 9 15 21 27 35 45 63 81 105 135
189 243 315 405 567 945 1215 1701 2835]. Sum: 8967.
8925: Divisors: [1 3 5 7 15 17 21 25 35 51 75 85 105 119
175 255 357 425 525 595 1275 1785 2975]. Sum: 8931.
``````

``````Submitted by: Mohammad S Anwar
Create sub compose(\$f, \$g) which takes in two parameters \$f
and \$g as subroutine refs and returns subroutine ref
i.e. compose(\$f, \$g)->(\$x) = \$f->(\$g->(\$x))

e.g.

\$f = (one or more parameters function)
\$g = (one or more parameters function)

\$h = compose(\$f, \$g)
\$f->(\$g->(\$x,\$y, ..)) == \$h->(\$x, \$y, ..) for any \$x, \$y, ...
``````

I assume that @ARGV has the code for the two functions f and g as strings (i.e., “sub{…}”) to be (unsafely) eval’ed, followed by the arguments to feed g, whose output feeds f. This yields a oneliner solution:

``````perl -E '\$f=eval shift or die \$@; \$g=eval shift or die \$@; \$h=sub{\$f->(\$g->(@_))}; say \$h->(@ARGV)
' 'sub(\$x){log(\$x)/log(10)}' 'sub(\$x){\$x**2}' 10
perl -E '\$f=eval shift or die \$@; \$g=eval shift or die \$@; \$h=sub{\$f->(\$g->(@_))}; say \$h->(@ARGV)
' 'sub(\$x, \$y){sqrt(\$x**2+\$y**2)}' 'sub(\$x1, \$y1, \$x2, \$y2){(\$x1+\$x2, \$y1+\$y2)}' 1 1 2 3
perl -E '\$f=eval shift or die \$@; \$g=eval shift or die \$@; \$h=sub{\$f->(\$g->(@_))}; say \$h->(@ARGV)
' 'sub(\$x){sin(\$x)}' 'sub(\$x, \$y){atan2(\$y, \$x)}' 1 1
``````

Results:

``````2
5
0.707106781186547
``````

In the first example f calculates the log10 of its argument and g squares the argument. Thus, f∘g(10)=log10(102)=2. In the second example f calculates the euclidean size of a 2D vector while g adds two 2D vectors. Thus f∘g(1,1,2,3)=f(1+2,1+3)=f(3,4)=sqrt(9+16)=5. In the third example f calculates the sine of an angle while g calculates the direction of a 2D vector x,y with respect to the x-axis, thus f∘g(1,1)=sin(π/4)=1/√2=0.707…. I’m using Perl 5.36, so that -E enables signatures.

I didn’t write a compose function above, for brevity, but I do so in the full code is below:

`````` 1  # Perl weekly challenge 171
2  # Task 2: First class function
3  #
5  use v5.36;
6  die <<END unless @ARGV>=2;
7  Usage: .ch-2.pl "sub{...}" "sub{...}" arg1 arg2...
8  to compose two functions and apply them to the given arguments
9  END
10  my (\$f, \$g)=map {eval \$_ or die \$@} my (\$fs, \$gs)=(shift, shift);
11  my \$h=compose(\$f, \$g);
12  say "\$fs ∘ \$gs : ", join(", ", @ARGV), " ↦ ", \$h->(@ARGV);
13
14  sub compose(\$f, \$g){
15      sub {\$f->(\$g->(@_))};
16  }
``````

Examples:

``````./ch-2.pl 'sub(\$x){log(\$x)/log(10)}' 'sub(\$x){\$x**2}' 10
./ch-2.pl 'sub(\$x, \$y){sqrt(\$x**2+\$y**2)}' 'sub(\$x1, \$y1, \$x2, \$y2){(\$x1+\$x2, \$y1+\$y2)}' 1 1 2 3
./ch-2.pl 'sub(\$x){sin(\$x)}' 'sub(\$x, \$y){atan2(\$y, \$x)}' 1 1
``````

Results:

``````sub(\$x){log(\$x)/log(10)} ∘ sub(\$x){\$x**2} : 10 ↦ 2
sub(\$x, \$y){sqrt(\$x**2+\$y**2)} ∘ sub(\$x1, \$y1, \$x2, \$y2){(\$x1+\$x2, \$y1+\$y2)} : 1, 1, 2, 3 ↦ 5
sub(\$x){sin(\$x)} ∘ sub(\$x, \$y){atan2(\$y, \$x)} : 1, 1 ↦ 0.707106781186547
``````

Here, I used the compose ∘ and the yields ↦ symbols.

Written on June 27, 2022