# Perl Weekly Challenge 148: eban vs cardano

It is sad that, after more than two years of me doing Raku, I still don’t have any production code project to work on. Therefore, in order to keep my coding and Raku-ing (is that a term?) knowdledge, I try to solve every Perl Weekly Challenge tasks.

In the following, the assigned tasks for Challenge 148.

And this week, as for the previous PWC, I had time to quickly implement the tasks also on PostgreSQL `plpgsql` language:

## PWC 148 - Task 1

This task was about finding out Eban numbers, those numbers that do not contain the letter `e` within their english name. I was not really inspired by this task, so I brutally created a set of arrays that contains the numbers that do not copntain an `e` in their english name, and I `grep` for those numbers:

``````sub MAIN() {

my @eban-units = 2, 4, 6;
my @eban-teens = 12;
my @eban-tens  = 3, 4, 5, 6;

\$_.say if @eban-units.grep( \$_ ) for 1 .. 10;
\$_.say if @eban-teens.grep( \$_ ) for 11 .. 19;
\$_.say if @eban-tens.grep( ( \$_ / 10 ).Int ) && @eban-units.grep( \$_ % 10 ) for 20 .. 100;

}

``````

## PWC 148 - Task 2

This has been a more difficult task, that required me to learn about the `=~=` almost equality operator. The task required to print out the first five Cardano numbers, those that solve a particular equation given three variables. First of all, I implemented a couple of functions that, given the three variables, provide me the result of the Cardano domain belonging:

``````multi sub is-cardano-triplet( \$a, \$b, \$c ) {

my \$left  = .sign * .abs**( 1 / 3 ) given ( \$a + \$b * \$c.sqrt );
my \$right = .sign * .abs**( 1 / 3 ) given ( \$a - \$b * \$c.sqrt );
return 1 =~= ( \$left + \$right );
}

multi sub is-cardano-triplet( @triplet ) {
return is-cardano-triplet( @triplet[ 0 ], @triplet[ 1 ], @triplet[ 2 ] );
}

``````

The second implementation of the `is-cardano-triplet` function is only a placeholder to simplify when I use an array, and this will become clearer later. However, I could have simply used the `|@triplet` flatting operator.
The `\$left` and `\$right` are computed as the parts of the equation. The `.sign` method provides `+1` or `-1` depending on the sign of the result (the part in the `given`) and then I computer the third root of the absolute value, thus providing the resulting signed value. I needed a little help here about the math.
However, I was expecting this resulted in an integer result, but instead the result was a `Rat`, thus requiring me to use the new (to me) `=~=` operator, that is almost equal operator (see the documentation).
With all in place, I used a nested loop to generate a triplet, and then I compared every single permutation of the triple to see if the result was good enough:

``````sub MAIN( Int \$limit = 5 ) {
my @triplets = lazy gather {
for 1 .. Inf -> \$a {
for 1 ..^ \$a -> \$b {
for 1 ..^ \$b -> \$c {
\$_.take if is-cardano-triplet( \$_ ) for ( \$a, \$b, \$c ).permutations;

}
}
}
};

@triplets[ 0 .. \$limit ].join( "\n" ).say;
}

``````

I used a `lazy gather` to stop the computation as soon as the end is reached, and in fact I print out only the first `\$limit` entries. This took near 7 seconds on my machine.

## PWC 148 - Task 1 in PostgreSQL

The implementation, bit to bit, of the Raku solution for this task:

``````SELECT v
FROM generate_series( 1, 10 ) v
WHERE
v IN ( 2, 4, 6 )

UNION

SELECT v
FROM generate_series( 11, 19 ) v
WHERE v IN ( 12 )

UNION

SELECT v
FROM generate_series( 20, 100 ) v
WHERE
v % 10 IN ( 2, 4, 6 )
AND ( v / 10 )::int  IN ( 3, 4, 5, 6 );

``````

A single query can do the trick.

## PWC 148 - Task 2 in PostgreSQL

A recursive CTE implementation of the Raku solution for this task, limiting the numbers to `30` to avoid too much joins. Note that I search for the triplets that provide a sum that is near `1` by a small value.

``````WITH RECURSIVE
triplets AS
(
SELECT a::numeric, b::numeric, c::numeric
FROM generate_series( 1, 30 ) a
, generate_series( 1, 30 ) b
, generate_series( 1, 30 ) c
ORDER BY a, b, c
)
, cardano_sum AS
(
SELECT a, b, c,
( a + b * sqrt( c ) )   AS l
,( a - b * sqrt( c ) )  AS r
FROM triplets
)
, cardano AS
(
SELECT a, b, c, l, r
, CASE WHEN l < 0 THEN -1 ELSE 1 END * pow( abs( l )::numeric, 1/3::numeric )
+ CASE WHEN r < 0 THEN -1 ELSE 1 END * pow( abs( r )::numeric, 1/3::numeric )
AS triplet_sum
FROM cardano_sum
)

SELECT *
FROM cardano
WHERE
abs( 1 - triplet_sum::numeric ) <= 0.0000000001
LIMIT 5
;

``````

It takes 54 seconds to complete, and is a lot more of the Raku implementation. Why? Because the above query performs the computation for every join available.

The article Perl Weekly Challenge 148: eban vs cardano has been posted by Luca Ferrari on January 19, 2022