Switching arguments in Prolog - prolog

I have this little Prolog program. It multiplies two numbers only doing addition.
mult(0, _, 0).
mult(1, X, X).
mult(X, Y, R) :- X > 1, X1 is X - 1, mult(X1, Y, R1), R is Y+R1.
Now I thought of optimizing this by reordering the arguments, so that X is always the smaller of the two arguments and therefore doing less recursion, so I added this line:
mult(X, Y, R) :- X > Y, mult(Y, X, R).
This does not work and I don't really understand why. For example mult(3, 0, 0). answers with four times true and then false. I obviously just want to have it return true once and then false afterwards. There are also combinations which work fine like mult(0, 3, 0)..
Thanks in advance.

It works but yields redundant solutions.
The problem is that you have a single base case mult(0,_,0). that only check for the first argument to be 0, and not a base case that would give 0 whenever any of the first two arguments is 0. Also your second base case is really not needed.
When you add your "interchange arguments" clause you open the possibility of either interchange it when X > Y or just continue with the next clause, and that is why you end up with multiple solutions when the second argument was 0.
For example, the query mult(3,0, M). can either succeed by first exchanging 3 with 0, then calling mult(0,3, M). will succeed with M=0, o continue with the next clause that subtracts 1 to X and calls mult(2,0, M1). which again can yield a solution by first exchanging arguments or falling through the next clause until the first argument is 1 which guards against proceeding with the last clause.
You may fix it by renaming your procedure to something else and adding a wrapper which calls your procedure with the argument order of your like. e.g.:
mult(X, Y, R):-
X > Y -> mult1(Y, X, R) ; mult1(X, Y, R).
mult1(0, _, 0).
mult1(1, X, X).
mult1(X, Y, R) :- X > 1, X1 is X - 1, mult1(X1, Y, R1), R is Y+R1.

Related

Returning multiple values from a Prolog list

In this Prolog exercise, I'm trying to return the values from a list which are greater than a number N.
For example: greater_than([5,6,1,7], 5, X) should return X = 6 ; X = 7.
I tried to solve this by doing:
greater_than([],_,_). % to stop recursion when list is empty
greater_than([H|T],N,X) :-
H > N,
X is H,
greater_than(T,N,M). % if H>N return X=H
greater_than([H|T],N,X) :-
H =< N,
greater_than(T,N,X). % if H=<N just continue recursion.
My code works when there is only one result: greater_than([1,2,5], 2, X) returns X = 5.
But it doesn't work with multiple results: greater_than([1,2,5,7], 2, X) returns false.
I understood from this that X is already binded to a number and (X is H) for the second time returns false.
But I didn't know how to get multiple results.
I tried to change variables name:
greater_than([H|T],N,X) :-
H > N,
X is H,
greater_than(T,N,X1). % X1 for example
but that didn't work.
I understood from this that X is already binded to a number and (X is H) for the second time returns false.
Almost, but not quite because those happen in different calls so that could work on its own. Your code binds X=5 and then in the next call it binds M=7, and there's nowhere for you to see the value of M. The 7 is already used, when you search again, there's no more answers to find because it has found all the answers, reached the end of the list.
You are mixing up backtracking with recursion, two different ways of solving this.
A backtracking solution:
greater_than(List, Cutoff, X) :-
member(X, List),
X > Cutoff.
Then:
?- greater_than([1,2,5,7], 2, X).
X = 5 ;
X = 7
It finds one answer, and waits, then you ask for more, and it finds more.
A recursive solution walks the list in your code, instead of having Prolog do it, e.g. to build a list with all the answers:
greater_than([], _, []). % recursion base case. Empty list input, empty list output.
greater_than([H|T], Cutoff, [H|Result_T]) :-
H > Cutoff,
greater_than(T, Cutoff, Result_T).
greater_than([H|T], Cutoff, Result) :-
H =< Cutoff,
greater_than(T, Cutoff, Result).
Then:
?- greater_than([1,2,5], 2, X).
X = [5]

How can I avoid nontermination with an integer base case?

I want to write a predicate that recurses until 0, but it consistently fails to terminate. I used failure-slicing to narrow it down to this:
f(a, 0).
f(b, 0).
f(X, Y) :- false.
When I load the file as swipl -f test.pl, then run f(X, 0). in the prompt, I get the output X = a but I don't see X = b or get a new prompt. I expect it to act like A is 1 + 1, where I get A = 2. with a period and a new ?- prompt.
I was able to get it working with something like this, but it doesn't seem clean:
f(X, 0) :- X = x.
f(X, Y) :- Y == 0 -> false; (NewY is Y - 1, f(X, NewY)).
For a list, I could write the more general case as f(X, [A|B]) to ensure that it only applies when the list has at least one element. Is there something similar I can do to ensure that the more general case here only applies when Y is not 0?
I've looked at this question, and while it hints at the right direction, this doesn't work either:
:- use_module(library(clpfd)).
int_int_prod(_, 0, 0).
int_int_prod(Num1, Num2, Result) :-
Num2 #> 0,
NewNum2 #= Num2 - 1,
int_int_prod(Num1, NewNum2, NewResult),
Result #= Num1 + NewResult.
?- int_int_prod(0, 0, X).
Running f(X,0), you get X = a back. Notice the white space. The system awaits your command.
If you press ; on the keyboard, it responds with X = b . Is this something you don't want to happen? (another option is: pressing .). After all, your definition does admit two solutions to that query, X=a and X=b. Why should Prolog skip the second one? It shouldn't.
Another thing is, it still waits (tested in SWI, loaded from the prompt via [user]) for the user response after the second result. To eliminate that, just remove the third clause. It is entirely superfluous anyway: failing explicitly achieves the same affect as failing when no more matching clauses can be found.
Without the third clause, f(X,Y) :- false., the termination improves:
6 ?- f(X,0).
X = a ;
X = b.
% ^^ no white space, no waiting, immediate termination.

prolog - confusing behaviour of prolog code (beginner)

Here is my code.
equals2(X,Y,N,I):- X is Y,I is N+1; I is N.
elemNum(X,[],0).
elemNum(X,[Y|Ys],N) :- elemNum(X,Ys,N1),equals2(X,Y,N1,I),N is I.
lemNum first argument is element from array, second is array. It counts the number of elements in array.
Then in console
| ?- elemNum(1,[1,2,3,1,1],N),N<2.
N = 1 ?
yes
I am sure than my function elemNum works just fine. How its possible that in console this assertion returns 1?
Thanks for help
Non sure to understand what do you want ... but I suppose that you want count the number of element in the list (second argument of elemNum/3) that are equals to the first argument.
If so, you should modify equals2/4 as follows
equals2(X,Y,N,I):- X is Y,I is N+1; X \== Y, I is N.
or better (IMHO) split it in 2 different clauses
equals2(X,X,N,I):- I is N+1.
equals2(X,Y,N,N):- X \== Y.
With your equal2/4, the second or case (I is N) is executed (in backtracking) even when X is equal to Y so elemNum(1,[1,2,3,1,1],N) unifiy N with 3, 2, 2 again, 1, 2, 1, 1 again and 0.
Regarding elemNum/3, works but you can semplify it (avoiding a warning) as
elemNum(_,[],0).
elemNum(X,[Y|Ys],I) :- elemNum(X,Ys,N1), equals2(X,Y,N1,I).
or you can rewrite it, avoiding the use of equals2/4 as
elemNum(_, [], 0).
elemNum(X, [X | Ys], I) :- elemNum(X, Ys, I0), I is I0+1.
elemNum(X, [Y | Ys], I) :- X \== Y, elemNum(X, Ys, I).

What does this wildcard do in this prolog scenario?

I've come across this code:
connectRow(_,_,0).
connectRow([spot(_,R,_,_)|Spots],R,K) :- K1 is K-1, connectRow(Spots,R,K1).
/*c*/
connectRows([]).
connectRows(Spots) :-
connectRow(Spots,_,9),
skip(Spots,9,Spots1),
connectRows(Spots1).
How does the wildcard in the connectRow(Spots,_,9) work? How does it know which values to check and how does it know that it checked all the possible values?
Edit: I think I understand why this works but I'd like it if someone could verify this for me:
When I "call" the connectRow with the wildcard it matches the wildcard with the "R" in the connectRow predicate. Could this be it?
The _ is just like any other variable, except that each one you see is treated as a different variable and Prolog won't show you what it unifies with. There's no special behavior there; if it confuses you about the behavior, just invent a completely new variable and put it in there to see what it does.
Let's talk about how Prolog deals with variables. Here's an experiment you can follow along with that should undermine unhelpful preconceived notions if you happen to have them.
?- length([2,17,4], X)
X = 3.
A lot of Prolog looks like this and it's easy to fall into the trap of thinking that there are designated "out" variables that work like return values and designated "in" variables that work like parameters. After all:
?- length([2,17,4], 3).
true.
?- length([2,17,4], 5).
false.
Here we begin to see that something interesting is happening. A faulty intuition would be that Prolog is somehow keeping track of the input and output variables and "checking" in this case. That's not what's happening though, because unification is more general than that. Observe:
?- length(X, 3).
X = [_G2184, _G2187, _G2190].
We've now turned the traditional parameter/return value on its head: Prolog knows that X is a list three items long, but doesn't know what the items actually are. Believe it or not, this technique is frequently used to generate variables when you know how many you need but you don't need to have them individually named.
?- length(X, Y).
X = [],
Y = 0 ;
X = [_G2196],
Y = 1 ;
X = [_G2196, _G2199],
Y = 2 ;
X = [_G2196, _G2199, _G2202],
Y = 3
It happens that the definition of length is very general and Prolog can use it to generate lists along with their lengths. This kind of behavior is part of what makes Prolog so good at "generate and test" solutions. You define your problem logically and Prolog should be able to generate logically sound values to test.
All of this variation springs from a pretty simple definition of length:
length([], 0).
length([_|Rest], N1) :-
length(Rest, N0),
succ(N0, N1).
The key is to not read this like a procedure for calculating length but instead to see it as a logical relation between lists and numbers. The definition is inductive, relating the empty list to 0 and a list with some items to 1 + the length of the remainder of the list. The engine that makes this work is called unification.
In the first case, length([2,17,4], X), the value [17,4] is unified with Rest, N0 with 2 and N1 with 3. The process is recursive. In the final case, X is unified with [] and Y with 0, which leads naturally to the next case where we have some item and Y is 1, and the fact that the variable representing the item in the list doesn't have anything in particular to unify with doesn't matter because the value of that variable is never used.
Looking at your problem we see the same sort of recursive structure. The predicates are quite complex, so let's take them in pieces.
connectRow(_, _, 0).
This says connectRow(X, Y, 0) is true, regardless of X and Y. This is the base case.
connectRow([spot(_, R, _, _)|Spots], R, K) :-
This rule is matching a list of spots of a particular structure, presuming the first spot's second value (R) matches the second parameter.
K1 is K-1, connectRow(Spots, R, K1).
The body of this clause is essentially recurring on decrementing K, the third parameter.
It's clear now that this is basically going to generate a list that looks like [spot(_, R, _, _), spot(_, R, _, _), ... spot(_, R, _, _)] with length = K and no particular values in the other three positions for spot. And indeed that's what we see when we test it:
?- connectRow(X, Y, 0).
true ;
(infinite loop)^CAction (h for help) ? abort
% Execution Aborted
?- connectRow(X, Y, 2).
X = [spot(_G906, Y, _G908, _G909), spot(_G914, Y, _G916, _G917)|_G912] ;
(infinite loop)^CAction (h for help) ? abort
So there seem to be a few bugs here; if I were sure these were the whole story I would say:
The base case should use the empty list rather than matching anything
We should stipulate in the inductive case that K > 0
We should use clpfd if we want to be able to generate all possibilities
Making the changes we get slightly different behavior:
:- use_module(library(clpfd)).
connectRow([], _, 0).
connectRow([spot(_, R, _, _)|Spots], R, K) :-
K #> 0, K1 #= K-1, connectRow(Spots, R, K1).
?- connectRow(X, Y, 0).
X = [] ;
false.
?- connectRow(X, Y, 1).
X = [spot(_G906, Y, _G908, _G909)] ;
false.
?- connectRow(X, Y, Z).
X = [],
Z = 0 ;
X = [spot(_G918, Y, _G920, _G921)],
Z = 1 ;
X = [spot(_G918, Y, _G920, _G921), spot(_G1218, Y, _G1220, _G1221)],
Z = 2
You'll note that in the result we have Y standing in our spot structures, but we have weird looking automatically generated variables in the other positions, such as _G918. As it happens, we could use _ instead of Y and see a similar effect:
?- connectRow(X, _, Z).
X = [],
Z = 0 ;
X = [spot(_G1269, _G1184, _G1271, _G1272)],
Z = 1 ;
X = [spot(_G1269, _G1184, _G1271, _G1272), spot(_G1561, _G1184, _G1563, _G1564)],
Z = 2
All of these strange looking variables are there because we used _. Note that all of the spot structures have the exact same generated variable in the second position, because Prolog was told it had to unify the second parameter of connectRow with the second position of spot. It's true everywhere because R is "passed along" to the next call to connectRow, recursively.
Hopefully this helps explain what's going on with the _ in your example, and also Prolog unification in general.
Edit: Unifying something with R
To answer your question below, you can unify R with a value directly, or by binding it to a variable and using the variable. For instance, we can bind it directly:
?- connectRow(X, 'Hello, world!', 2).
X = [spot(_G275, 'Hello, world!', _G277, _G278), spot(_G289, 'Hello, world!', _G291, _G292)]
We can also bind it and then assign it later:
?- connectRow(X, R, 2), R='Neato'.
X = [spot(_G21, 'Neato', _G23, _G24), spot(_G29, 'Neato', _G31, _G32)],
R = 'Neato'
There's nothing special about saying R=<foo>; it unifies both sides of the expression, but both sides can be expressions rather than variables:
?- V = [2,3], [X,Y,Z] = [1|V].
V = [2, 3],
X = 1,
Y = 2,
Z = 3.
So you can use R in another predicate just as well:
?- connectRow(X, R, 2), append([1,2], [3,4], R).
X = [spot(_G33, [1, 2, 3, 4], _G35, _G36), spot(_G41, [1, 2, 3, 4], _G43, _G44)],
R = [1, 2, 3, 4] ;
Note that this creates opportunities for backtracking and generating other solutions. For instance:
?- connectRow(X, R, 2), length(R, _).
X = [spot(_G22, [], _G24, _G25), spot(_G30, [], _G32, _G33)],
R = [] ;
X = [spot(_G22, [_G35], _G24, _G25), spot(_G30, [_G35], _G32, _G33)],
R = [_G35] ;
X = [spot(_G22, [_G35, _G38], _G24, _G25), spot(_G30, [_G35, _G38], _G32, _G33)],
R = [_G35, _G38] ;
Hope this helps!

List building problems

For my program I need to make a list of lists, with each sublist containing 2 numbers, X and Y along with the sum and product of these 2 numbers.
So far I have the following:
genList(95, X,[]):-!.
genList(N, X,[[X,Y,Sum,Product]|Xs]):-
Y is N+1,
Sum is X+Y,
Sum<101,
Product is X*Y,
N1 is N+1,
genList(N1, X,Xs).
This works just fine for my test case of genList(5,5,Q).
However, I'm having trouble making it work for any starting number.
The goal is to find every pair of numbers where sum<= 100. So running through the above for one starting value, X would find every pair 1 < X < Y, where sum<=100, and running through it with all numbers 2-N would give a complete list of possible pairs.
For those interested, the problem I'm working through is the sum/product problem, described here (Second on the page)
If anyone could help with this it would be greatly appreciated!
Also, no built in prolog predicates are able to be used, hence the complicated way of doing this rather than with a findall.
A small extract of the output produced by this predicated is as follows:
[[5,6,11,30],[5,7,12,35],[5,8,13,40],[5,9,14,45],[5,10,15,50],[5,11,16,55],[5,12,17,60],[5,13,18,65],[5,14,19,70],[5,15,20,75],[5,16,21,80],[5,17,22,85],[5,18,23,90],[5,19,24,95],[5,20,25,100],[5,21,26,105],[5,22,27,110], ...
EDIT:
Ok, so after some editing, here is the latest version of my code.
I think it's very close, but there's still something not quite right.
It cycles through number pairs, but requires the use of ";" to view all the answers, which isn't what I want. Additionally, it returns false after all the answers are exhausted. I just can't figure it out.
Also, it gives a complete answer in the middle, but then removes a sublist each time until I'm left with only the last set of pairs.
E.g. genList(0,48,48,Q). gives me:
[[48,49,97,2352],[48,50,98,2400],[48,51,99,2448],[48,52,100,2496]]
[[48,49,97,2352],[48,50,98,2400],[48,51,99,2448],[48,52,100,2496],[49,50,99,2450],[49,51,100,2499]]
[[48,49,97,2352],[48,50,98,2400],[48,51,99,2448],[49,50,99,2450],[49,51,100,2499]]
[[48,49,97,2352],[48,50,98,2400],[49,50,99,2450],[49,51,100,2499]]
[[48,49,97,2352],[49,50,99,2450],[49,51,100,2499]]
[[49,50,99,2450],[49,51,100,2499]]
false.
As you can see, a sublist gets removed each time, I just can't see why!
You can exploit Prolog backtracking here. Just state what you want. For example you could say:
I want X to be between 1 and 100.
I want Y to be between 1 and min(100 - X, X).
then I want their pair
Let's look at what a validPair/1 predicate would look like:
validPair(X-Y) :-
between(1, 100, X),
Limit is min(100 - X, X),
between(1, Limit, Y).
You can just call it with
?- validPair(X).
and browse results with ;, or build a list of all the matching pairs with findall/3.
Edit: even with recursion, we can keep our statements:
I want X to be between 1 and 100.
I want Y to be between 1 and min(100 - X, X).
then I want their pair
So, an idea to do it would be to set up a worker predicate:
validPair(Result) :-
validPair(0, 0, Result).
validPair(X, Y, R) :-
...
then set up the base case:
validPair(101, _Y, []) :- !.
and in the worker predicate, to implement the statements we made with some conditions:
validPair(X, Y, [SomeStuff|R]) :-
X =< 100,
Limit is min(100 - X, X),
Y =< Limit,
!,
% we can go on and increment Y once we're finished
validPair(X, NextY, R).
validPair(X, Y, R) :-
% if we come here that means that Y is finished growing and
% we have to increment X
NextX is X + 1,
validPair(NextX, 0, R).
I have a feeling you're tackling the problem the wrong way; I must admit I don't really understand what your predicate is doing.
The goal is to find every pair of numbers where sum<= 100.
Assuming you mean unordered pairs of non-negative integers, that's
between(0, 100, Sum),
between(0, Sum, X),
Y is Sum - X,
X =< Y.
The set of all such pairs (as a list) can then be constructed with findall/3.
You could also do this using CLP(fd):
use_module(library(clpfd)).
[X, Y, Sum] ins 0..100,
X #=< Y,
X + Y #= Sum,
label([X,Y,Sum]).

Resources