# RabbitFarm

### 2022-03-20

#### Persnickety Pernicious and Weird

*The examples used here are from The Weekly Challenge problem statement and demonstrate
the working solution.*

## Part 1

*Write a script to generate the first 10 Pernicious Numbers.*

### Solution

```
use strict;
use warnings;
use Math::Primality qw/is_prime/;
sub count_bits{
my($n) = @_;
my $total_count_set_bit = 0;
while($n){
my $b = $n & 1;
$total_count_set_bit++ if $b;
$n = $n >> 1;
}
return $total_count_set_bit;
}
sub first_n_pernicious{
my($n) = @_;
my @pernicious;
my $x = 1;
do{
my $set_bits = count_bits($x);
push @pernicious, $x if is_prime($set_bits);
$x++;
}while(@pernicious < $n);
return @pernicious;
}
MAIN:{
print join(", ", first_n_pernicious(10)) . "\n";
}
```

### Sample Run

```
$ perl perl/ch-1.pl
3, 5, 6, 7, 9, 10, 11, 12, 13, 14
```

### Notes

Number Theory was one of my favorite classes as an undergraduate. This sort of challenge is fun, especially if you dive into the background of these sequences and try to learn more about them. Computing them is fairly straightforward, especially here where the two functions are largely drawn from past TWCs.

## Part 2

*You are given number, $n > 0. Write a script to find out if the given number is a Weird
Number.*

### Solution

```
use strict;
use warnings;
use boolean;
use Data::PowerSet q/powerset/;
sub factor{
my($n) = @_;
my @factors = (1);
foreach my $j (2 .. sqrt($n)){
push @factors, $j if $n % $j == 0;
push @factors, ($n / $j) if $n % $j == 0 && $j ** 2 != $n;
}
return @factors;
}
sub is_weird{
my($x) = @_;
my @factors = factor($x);
my $sum = unpack("%32I*", pack("I*", @factors));
for my $subset (@{powerset(@factors)}){
return false if unpack("%32I*", pack("I*", @{$subset})) == $x;
}
return boolean($sum > $x);
}
MAIN:{
print is_weird(12) . "\n";
print is_weird(70) . "\n";
}
```

### Sample Run

```
$ perl perl/ch-2.pl
0
1
```

### Notes

This task kind of bothered me, not because of the complexity of the task itself; the code
was overall not extremely demanding. Rather anytime when I want to make use of
*Data::PowerSet* I get a bit anxious that there may be a far more elegant way of
proceeding! After coming up blank on alternatives I just went with this, but I'll probably
still have this in the back of my mind for a few more days.

## References

posted at: 18:29 by: Adam Russell | path: /perl | permanent link to this entry

#### The Weekly Challenge 156 (Prolog Solutions)

*The examples used here are from the weekly challenge problem statement and demonstrate
the working solution.*

## Part 1

*Write a script to generate the first 10 Pernicious Numbers.*

### Solution

```
pernicious(_) --> [].
pernicious(Seen) --> [X], x(Seen, X), {set_bits(X, Bits), fd_prime(Bits)}, pernicious([X|Seen]).
x(Seen, X) --> {between(1, 100, X), \+ member(X, Seen)}.
set_bits(N, X):-
set_bits(N, 0, X).
set_bits(0, X, X).
set_bits(N, X_Acc, X):-
B is N /\ 1,
X0 is X_Acc + B,
N0 is N >> 1,
set_bits(N0, X0, X), !.
```

### Sample Run

```
$ gprolog --consult-file prolog/ch-1.p
| ?- length(Pernicious, 10), phrase(pernicious([]), Pernicious).
Pernicious = [3,5,6,7,9,10,11,12,13,14] ?
(115 ms) yes
| ?- phrase(pernicious([]), [3, 5, 6]).
true ?
(95 ms) yes
```

### Notes

DCGs are great aren't they? The ability to have two modes, one to test and the other to create is a joy! The logic here is pretty straightforward and more or less follows straight fromt he definition.

## Part 2

*Write a script to compute the first 10 distinct Padovan Primes.*

### Solution

```
weird(_) --> [].
weird(Seen) --> [X], x(Seen, X), {
findall(F, factor(X, F), Factors), flatten([1, Factors], FlatFactors),
sum_list(FlatFactors, FactorSum),
FactorSum > X,
powerset(FlatFactors, FactorSets),
maplist(sum_list, FactorSets, FactorSetSums),
\+ member(X, FactorSetSums)
},
weird([X|Seen]).
x(Seen, X) --> {between(1, 1000, X), \+ member(X, Seen)}.
powerset(X,Y):- bagof(S, subseq(S,X), Y).
subseq([], []).
subseq([], [_|_]).
subseq([X|Xs], [X|Ys] ):- subseq(Xs, Ys).
subseq([X|Xs], [_|Ys] ):- append(_, [X|Zs], Ys), subseq(Xs, Zs).
factor(N, Factors):-
S is round(sqrt(N)),
fd_domain(X, 2, S),
R #= N rem X,
R #= 0,
Q #= N // X,
Q #\= X,
fd_labeling([Q, X]),
Factors = [Q, X].
factor(N, Factors):-
S is round(sqrt(N)),
fd_domain(X, 2, S),
R #= N rem X,
R #= 0,
Q #= N // X,
Q #= X,
fd_labeling([Q]),
Factors = [Q].
```

### Sample Run

```
$ gprolog --consult-file prolog/ch-2.p
| ?- phrase(weird([]), [70]).
true ?
yes
| ?- length(Weird, 1), phrase(weird([]), Weird).
Weird = [70] ?
(4 ms) yes
```

### Notes

This solution follows the same *generate and test* approach I used in the
Perl Solution, as far as the
testing of the powerset of divisors is concerned anyway. (I'll admit I was too lazy to
write my own powerset code so I grabbed someone else's. See the references for a link to
the source.)

In my ongoing attempts to improve my DCG skills I implemented this as a DCG which is a bit of overkill for this problem, but it is always nice to be able to generate the sequence as well as validate.

## References

posted at: 18:26 by: Adam Russell | path: /prolog | permanent link to this entry