# RabbitFarm

### 2020-11-08

# Command Line Arguments with SWI_Prolog’s library(optparse)

SWI-Prolog has a nice library which allows you to pass arguments on the command line to your Prolog programs. Here are a couple of example of it’s use done with the two parts of Perl Weekly Challenge 085 implemented in Prolog.

## Part 1

*You are given an array of real numbers greater than zero. Write a script to find if there exists a triplet (a,b,c) such that 1 < a+b+c < 2. Print 1 if you succeed otherwise 0.*

### Solution

```
:- use_module(library(optparse)).
/*
You are given an array of real numbers greater than zero.
Write a script to find if there exists a triplet (a,b,c)
such that 1 < a+b+c < 2. Print 1 if you succeed otherwise 0.
*/
opts_spec(
[
[opt(numbers),
default([1.2, 0.4, 0.1, 2.5]),
longflags([numbers])]
]).
ch_1(L):-
member(A, L),
member(B, L),
member(C, L),
A =\= B,
B =\= C,
A =\= C,
D is A + B + C,
D > 1,
D < 2,
writeln(1).
ch_1(_):-
writeln(0).
main:-
opts_spec(OptsSpec),
opt_arguments(OptsSpec, [numbers(N)], _AdditionalArguments),
ch_1(N),
halt.
```

### Sample Run

```
$ swipl -s ch-1.p -g main --numbers="[1.0, 0.2, 3.4, 0.1]"
1
$ swipl -s ch-1.p -g main --numbers="[1.0, 1.2, 3.4, 0.1]"
0
```

### Notes

You can see from the Sample Run that we are passing a Prolog list as a command line argument. To avoid conflicts with the shell trying to interpret our square brackets and commas we put the list itself in quotes. But how does Prolog know what `--numbers`

means?

To use `library(optparse)`

you must define a specification for each of your command line arguments that you expect to take. Here we just have one. The line `opt(numbers)`

specifies the term that will be used to obtain the value in your program, `default([1.2, 0.4, 0.1, 2.5])`

provides a default value if the argument is not used on the command line. `longflags([numbers])`

indicates that to look for a flag of the form `--numbers`

. we could have also used `shortflags([numbers])`

instead if we would prefer to use `-numbers`

. I don’t know of any strong arguments for either one but find, personally, that the long form is more intuitive.

The values passed on the command line are extracted using `opt_arguments`

which will follow the specification you’ve provided. `_AdditionalArguments`

refers to any arguments passed on the command line without dashes but here we do not have any. `[numbers(N)]`

is a list of the parsed key(value) pairs from the command line. So for this example `N`

is the list value we entered on the command line and it is then used as needed.

## Part 2

*You are given a positive integer $N. Write a script to find if it can be expressed as a ** b where a > 0 and b > 1. Print 1 if you succeed otherwise 0.*

### Solution

```
:- use_module(library(clpfd)).
:- use_module(library(optparse)).
/*
You are given a positive integer $N.
Write a script to find if it can be expressed
as a ^ b where a > 0 and b > 1.
Print 1 if you succeed otherwise 0.
*/
opts_spec(
[
[opt(number),
default(0),
longflags([number])]
]).
/*
Ok, I'll admit, this is a pretty silly use of clpfd when
a simple logarithm calculation would do the job! Still clpfd
is more fun.
*/
ch_2(N) :-
N0 is N -1,
A in 0 .. N0,
B in 1 .. N0,
N #= A ^ B,
label([A,B]),
writeln(1).
ch_2(_) :-
writeln(0).
main:-
opts_spec(OptsSpec),
opt_arguments(OptsSpec, [number(N)], _AdditionalArguments),
ch_2(N),
halt.
```

### Sample Run

```
$ swipl -s ch-2.p -g main --number=7
0
$ swipl -s ch-2.p -g main --number=8
1
```

### Notes

For an extra bit of fun I decided to use`library(clpfd)`

for this although it is most definitely a bit of over engineering! This can be done rather simply using logarithms. Here we see the same pattern as done in Part 1: define the specification, extract the values from the command line, and then use the values. Here the single argument is just a single value and so there is no need to wrap the value in quotes, however, if you add quotes anyway it will have no effect. For example:
```
$ swipl -s ch-2.p -g main --number="100"
1
```

## Reference

posted at: 17:11 | path: /prolog | permanent link to this entry

#### Perl Weekly Challenge 085

## Part 1

*You are given an array of real numbers greater than zero. Write a script to find if there exists a triplet (a,b,c) such that 1 < a+b+c < 2. Print 1 if you succeed otherwise 0.*

### Solution

```
use strict;
use warnings;
##
# You are given an array of real numbers greater than zero.
# Write a script to find if there exists a triplet (a,b,c)
# such that 1 < a+b+c < 2. Print 1 if you succeed otherwise 0.
##
use boolean;
use Math::Combinatorics;
sub build_constraints{
my @constraints;
my $a_not_equal_b = sub { $_[0] != $_[1] };
my $a_not_equal_c = sub { $_[0] != $_[2] };
my $b_not_equal_c = sub { $_[1] != $_[2] };
my $sum_greater_than_1 = sub { 1 < ($_[0] + $_[1] + $_[2]) };
my $sum_less_than_2 = sub { 2 > ($_[0] + $_[1] + $_[2]) };
return (
$a_not_equal_b,
$a_not_equal_c,
$b_not_equal_c,
$sum_greater_than_1,
$sum_less_than_2
);
}
MAIN:{
my $combinations = Math::Combinatorics->new(
count => 3,
data => [@ARGV],
);
my $found;
while(my @combination = $combinations->next_combination()){
$found = true;
for my $constraint (build_constraints()){
if(!$constraint->(@combination)){
$found = false;
last;
}
}
do{ print "1\n"; last; } if($found);
}
print "0\n" if(!$found);
}
```

### Sample Run

```
$ perl perl/ch-1.pl 0.1 1.2 3.4 0.2
1
$ perl perl/ch-1.pl 1.1 1.2 3.4 0.2
0
```

### Notes

I decided to try a *constraint programming* approach for this. While there are several modules for doing this available on CPAN I didn’t want to quite go so deep down that rabbithole. Instead I took the simpler path of implementing each constraint as a subroutine stored in an array. For each candidate combination the constraints are tests. Since all constraints must be satisfied if any one returns a false value then we can move immediately to the next combination.

## Part 2

*You are given a positive integer $N. Write a script to find if it can be expressed as a ** b where a > 0 and b > 1. Print 1 if you succeed otherwise 0.*

### Solution

```
use strict;
use warnings;
##
# You are given a positive integer $N.
# Write a script to find if it can be expressed
# as a ^ b where a > 0 and b > 1.
# Print 1 if you succeed otherwise 0.
##
use boolean;
sub log_a{
my($a, $n) = @_;
return log($n)/log($a);
}
MAIN:{
my $N = $ARGV[0];
my $found = false;
for my $a (2 .. $N){
my $b = log_a($a, $N);
if($b =~ /^[-]?\d+$/ && $b > 1){
print "1\n";
$found = true;
last;
}
}
print "0\n" if(!$found);
}
```

### Sample Run

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

### Notes

I was tempted to repeat roughly the same design as Part 1 and use constraints but that really would be over engineering it! Instead here we just loop over all possible values `$a`

and test using logarithms to see if `$b`

holds an integer value. There seems to be a number of ways to do the test to determine if a scalar holds an integer but a regex seems maybe the most idiomatically Perlish way.

posted at: 16:20 | path: /perl | permanent link to this entry