# Perl Weekly Challenge 246: Brute Force Math!

This post presents my solutions to the Perl Weekly Challenge 246.
I keep doing the Perl Weekly Challenge in order to mantain my coding skills in good shape, as well as in order to learn new things, with particular regard to Raku, a language that I love.
This week, I solved the following tasks:
The PL/Perl implementations are very similar to a pure Perl implementation, even if the PostgreSQL environment could involve some more constraints. Similarly, the PL/PgSQL implementations help me keeping my PostgreSQL programming skills in good shape.

# Raku Implementations

## PWC 246 - Task 1 - Raku Implementation

The first task was about extracting six random numbers (without repetitions) less than 49.

sub MAIN() {

my @lottery;
while ( @lottery.elems < 6 ) {
@lottery.push: \$_ if ( ! @lottery.grep( \$_ ) ) given ( 49.rand.Int );
}

@lottery.join( "\n" ).say;
}

## PWC 246 - Task 2 - Raku Implementation

The second task was about finding out, given an input array of five integers, if the array represents a linear recurrence of second order. Since I’m not good at this kind of math, I implemented it with a brute force approach where I scan from 1 to infinity the possibiliies and exits as soon as I’m sure I’ve found an answer.

sub MAIN( *@nums where { @nums.elems == 5 && @nums.grep( * ~~ Int ).elems == @nums.elems }  ) {

for 2 ..^ @nums.elems {
# a[n] = p * a[n-2] + q * a[n-1] with n > 1

my \$ok = False;
for 1 .. Inf -> \$p {
for 1 .. Inf -> \$q {
if ( @nums[ \$_ ] == ( \$p * @nums[ \$_ - 2 ] + \$q * @nums[ \$_ - 1 ] )
|| @nums[ \$_ ] == ( \$p * -1 * @nums[ \$_ - 2 ] + \$q * @nums[ \$_ - 1 ] )
|| @nums[ \$_ ] == ( \$p * -1 * @nums[ \$_ - 2 ] + \$q * -1 * @nums[ \$_ - 1 ] )
|| @nums[ \$_ ] == ( \$p * @nums[ \$_ - 2 ] + \$q * -1 * @nums[ \$_ - 1 ] ) ) {
\$ok = True;
last;
}
}

last if \$ok;
}

'False'.say and exit if  ! \$ok;
}

'True'.say;
}

# PL/Perl Implementations

## PWC 246 - Task 1 - PL/Perl Implementation

Same approach as in Raku.

CREATE OR REPLACE FUNCTION
RETURNS SETOF int
AS \$CODE\$
my @lottery;

while ( @lottery < 6 ) {
my \$value = int ( rand( 49 ) );
if ( ! grep( { \$_ == \$value } @lottery ) ) {
push @lottery, \$value;
return_next( \$value );
}
}

return undef;
\$CODE\$
LANGUAGE plperl;

## PWC 246 - Task 2 - PL/Perl Implementation

Same brute force approach as in Raku. Note that I need to use a C-style for loop to simulate the infinity upper boundary, since inf from bigint is not usable in a range.

CREATE OR REPLACE FUNCTION
RETURNS bool
AS \$CODE\$
my ( \$nums ) = @_;

die "Need 5 numbers" if ( \$nums->@* != 5 );
my \$ok = 0;
my \$ko = \$nums->@* - 2;

for ( 2 .. \$nums->@* - 1 ) {
for ( my \$p = 1; ; \$p++ ) {
for ( my \$q = 1; ; \$q++ ) {
if ( \$nums->@[ \$_ ] == ( \$p * \$nums->[ \$_ - 2 ] + \$q * \$nums->[ \$_ - 1 ] )
|| \$nums->@[ \$_ ] == ( \$p * -1 * \$nums->[ \$_ - 2 ] + \$q * \$nums->[ \$_ - 1 ] )
|| \$nums->@[ \$_ ] == ( \$p * -1 * \$nums->[ \$_ - 2 ] + \$q * -1 * \$nums->[ \$_ - 1 ] )
|| \$nums->@[ \$_ ] == ( \$p * \$nums->[ \$_ - 2 ] + \$q * -1 * \$nums->[ \$_ - 1 ] ) ) {

\$ok = 1;
\$ko--;
last;
}
}

last if \$ok;
}
}

return ( \$ko == 0 );
\$CODE\$
LANGUAGE plperl;

# PostgreSQL Implementations

## PWC 246 - Task 1 - PL/PgSQL Implementation

I use a couple of tricks here, that surely do not make this solution a good one given that I need only six values, but allows me to explain some capabilities of PostgreSQL.

CREATE OR REPLACE FUNCTION
RETURNS SETOF INT
AS \$CODE\$
DECLARE
counting int;
current_value int;
BEGIN
CREATE TEMPORARY TABLE IF NOT EXISTS lottery( v int, CHECK( v <= 49 ), PRIMARY KEY( v ) );
TRUNCATE lottery;

counting := 0;
WHILE counting < 6 LOOP
current_value := ( random() * 100 )::int;

IF current_value <= 49 THEN
INSERT INTO lottery( v )
VALUES( current_value )
ON CONFLICT ( v ) DO NOTHING;
END IF;

SELECT count(*)
INTO counting
FROM lottery;

END LOOP;

RETURN QUERY
SELECT * FROM lottery;
END
\$CODE\$
LANGUAGE plpgsql;

I use a temporary table lottery to store unique values that I’m going to generate randomly. The idea is while counting, that contains the number of rows in the temporary table, is less than 6, I’m going to generate a new random value by means of random (multiplied by 100 to ensure it gives me a number between 1 and 100). If the genrrated value if less than 49 I insert it into the temporary table, skipping the insert in the case the number is already there! Once the table has been filled with six rows, I can return all of them with a simple query.

## PWC 246 - Task 2 - PL/PgSQL Implementation

Same brute force approach shown before. Note that here I simulate a quite infinity upper boud with a 99999 fixed value, but it would be possible to use an always increasing loop.

CREATE OR REPLACE FUNCTION
pwc246.task2_plpgsql( nums int[] )
RETURNS bool
AS \$CODE\$
DECLARE
current_index int;
p int;
q int;
ok bool := false;
ko int;
BEGIN

ko := array_length( nums, 1 ) - 3 + 1;

FOR current_index IN 3 .. array_length( nums, 1 ) LOOP
ok := false;

FOR p IN 1 .. 99999 LOOP
FOR q IN 1 .. 9999 LOOP
IF nums[ current_index ] = ( p * nums[ current_index - 2 ] + q * nums[ current_index - 1 ] )
OR nums[ current_index ] = ( p * -1 * nums[ current_index - 2 ] + q * nums[ current_index - 1 ] )
OR nums[ current_index ] = ( p * -1 * nums[ current_index - 2 ] + q * -1 *nums[ current_index - 1 ] )
OR nums[ current_index ] = ( p * nums[ current_index - 2 ] + q * -1 * nums[ current_index - 1 ] ) THEN
ok := true;
ko := ko - 1;
EXIT;
END IF;
END LOOP;

IF ok THEN
EXIT;
END IF;

END LOOP;
END LOOP;

RETURN ko = 0;
END
\$CODE\$
LANGUAGE plpgsql;

# Python Implementations

## PWC 246 - Task 1 - Python Implementation

A very simple implementation, using the random generation and an array to store the values so that I can check if I’ve already got a value before.

import sys
import random

def main( argv ):
values = []
while len( values ) < 6:
current_value = random.randint( 1, 49 )
if not current_value in values:
values.append( current_value )

print( "\n".join( map( str, values ) ) )

# invoke the main without the command itself
if __name__ == '__main__':
main( sys.argv[ 1: ] )

## PWC 246 - Task 2 - Python Implementation

Another brute force approach. This time I use count to simulate the infinity upper bound.

import sys
from itertools import count

def main( argv ):
nums = list( map( int, argv ) )
ko = len( nums ) - 2

for current_index in range( 2, len( nums ) ):
for p in count( start = 1 ):
for q in count( start = 1 ):
if nums[ current_index ] == ( p * nums[ current_index - 2 ] + q * nums[ current_index - 1 ] ) \
or nums[ current_index ] == ( p * -1 * nums[ current_index - 2 ] + q * nums[ current_index - 1 ] ) \
or nums[ current_index ] == ( p * -1 * nums[ current_index - 2 ] + q * -1 * nums[ current_index - 1 ] ) \
or nums[ current_index ] == ( p * nums[ current_index - 2 ] + q * -1 *  nums[ current_index - 1 ] ):
ok = True
ko = ko - 1
break

if ok:
break

if ko == 0:
print( 'True' )
else:
print( 'False' )

# invoke the main without the command itself
if __name__ == '__main__':
main( sys.argv[ 1: ] )

The article Perl Weekly Challenge 246: Brute Force Math! has been posted by Luca Ferrari on December 4, 2023