Separate axis of coordinate inside list in Prolog - list

Let's say I have a list with its elements containing coordinates of a point like such [(4,4), (3,4), (2,4), (1,4)], and I want to check if a certain point is below or above a certain line or column
So for example the function
get_list_below_line([(4,4), (3,4), (2,4), (1,4)], 3, ResultList).
Will output:
ResultList = [(2,4), (1,4)]
My issue here is how do I isolate for example the X/Y axis on a given coordinate so I can arithmetically compare with the Line value? Being that each list element is in the format (Line,Column), how can I obtain only the Line value from inside that point?
Wouldn't for example using Head|Tails obtain a given full coordinate (2,4), how can I get 2 alone?

In SWI-Prolog (and others) you can use 'higher order' predicates with library(yall):
get_list_below_line(List, XMax, Below) :-
include({XMax}/[(X, _)] >> (X < XMax), List, Below).
or, something 'good old style'
get_list_below_line(List, XMax, Below) :-
findall((X, Y), (member((X, Y), List), X < XMax), Below).
Both approaches apply pattern matching to get the X element out of the pair of coords. BTW note that tuples (i.e. the pair) are just compound having comma (i.e. (,)/2) as functor. There is little to gain using them to structure large pieces of SW.

A recursive predicate, with one case for X < XMax, where the (X,Y) point is part of the Result, and another case for X >= XMax, where it is not:
get_list_below_line([], _, []).
get_list_below_line([(X,Y)|Points], XMax, [(X,Y)|Result]) :-
X < XMax,
get_list_below_line(Points, XMax, Result).
get_list_below_line([(X,Y)|Points], XMax, Result) :-
X >= XMax,
get_list_below_line(Points, XMax, Result).
Test:
?- get_list_below_line([(4,4), (3,4), (2,4), (1,4)], 3, ResultList).
ResultList = [(2, 4), (1, 4)] ;
false.

Related

How can I return a list of numbers from a given list that mod 0 a target number?

In my function modded(X,Y,Z), a list is generated based off of a given number Y and a given list of numbers Z. What I am trying to do is go through the list Z for each of its values and see if the current value in the list will cleanly divide Y, (Y/Zz == 0). I am a bit confused on how to access each of Z's values since Prolog does not have traditional iterators.
Expected behavior would be for modded(X,16,[2,3,4,5,7,8]) to return a list of [2,4,8]. Only complete divisors are allowed.
modded([],Y,Z):-
% X is the generated list, Y is the number, Z is a list of given numbers.
%Base case: Z is empty
Z =:= [],
X =:= Z.
modded([Zz|T],Y,[H|T]):-
%Recursive is Y > 1, Zz is an element of Z
0 is Y mod Zz,
Y =< Z - 1,
Zz is Z + 1,
% Want to add to a if Y mod Zz == 0
modded(T,Y,Zz).
modded([], _, []).
modded([Zz|T], Y, [Zz|Z]) :- % Case where Zz is a divisor of Y.
0 =:= Y mod Zz,
modded(T, Y, Z).
modded(T, Y, [Zz|Z]) :- % Case where Zz is not a divisor of Y.
0 =\= Y mod Zz,
modded(T, Y, Z).
Then
?- modded(X,16,[2,3,4,5,7,8]).
X = [2, 4, 8]
The base case holds for an empty list of input and output.
The middle case holds if Zz is a divisor and is added to the result list [Zz|T].
The last case holds if Zz is not a divisor and is not added to the result list T.
Both calculating cases recurse down the remaining Z list to fill in the remaining T of results.
If you weren't forced to use recursion, you might write:
modded(X, Y, Z) :-
findall(Zz, (member(Zz, Z), 0 =:= Y mod Zz), X).
"Find all the Zzs which are members of Z and divisors of Y, and store them in X".
or
num_divisor(Y, Zz) :-
0 =:= Y mod Zz.
modded(X, Y, Z) :-
include(num_divisor(Y), Z, X).
Comments you may need to hear but likely won't care about:
If you are using SWI Prolog then https://swish.swi-prolog.org/ is a brilliant tool you can try bits of code instantly without the edit/saving/reload. Try putting some of your bits of code into it:
Z =:= []
Type error: `evaluable' expected, found `[]' (an empty_list)
That line is never going to work. Nor is the next line:
X =:= Z.
Arguments are not sufficiently instantiated
In:
[1] _1722=:=_1724
In the line modded([Zz|T],Y,[H|T]) by using T in those to places, you're saying that the tail of both lists must be the same. One of those lists is the input, one is the filtered output. That can't work.
In the line 0 is Y mod Zz it says Zz divides Y. Weren't the arguments to modded supposed to be (Result, Number, Input)? So with modded([Zz|T],Y,[H|T]) wouldn't that be H dividing into Y, not Zz which has no value yet?
In the line 0 is Y mod Zz it says Zz divides Y. But if it did work and the input got to 3 this line would be false, because 3 doesn't divide 16 evenly, so the whole program would fail. There's no handling for what to do if a number isn't a divisor.
The line Y =< Z - 1 doesn't work like other languages either, =< will not calculate Z - 1. Which is almost lucky because Z has no value here in the code. (And even if it had, didn't you say it was the input list? What is Y =< [2,3,4,5,7,8] - 1 going to be?)
Zz is Z + 1 Z also has no value here, but if it had it would fail because Zz is bound at the top with modded([Zz and it
modded(T,Y,Zz) wasn't the last argument of modded the input list, why is it now a divisor? And the first argument was the result, now it's the tail of the input list?
Yes you are confused, you need to get familiar with the basics before trying to build on them.
Unification and proof search
Recursing down lists at LearnPrologNow.

Prolog - average predicate: Arguments not sufficiently instantiated

I have a list of cars (auto in german), where the first Variable is the license-plate and the second one the speed:
[auto(eu-ts884, 69), auto(dn-gh184, 64), auto(ac-lj123, 72)].
Now I try to write an average predicate but it fails with the error message:
ERROR: Arguments are not sufficiently instantiated
My code so far:
durchschnitt([], 0, 0).
durchschnitt([auto(_, X)|Tail], L, Y):-
Y is S/L,
L > 0,
cardinal([auto(_, X)|Tail], L),
sumKilometer([auto(_, X)|Tail], S).
sumKilometer([], 0).
sumKilometer([auto(_, X)|Tail], Sum) :-
sumKilometer(Tail, N),
Sum is N + X.
cardinal([], 0).
cardinal([_|Tail], Result) :-
cardinal(Tail, N),
Result is N + 1.
My code is quite equivalent to that post, although I cannot make out my mistake.
Note: sumKilometer and cardinal are working fine.
You write:
durchschnitt([], 0, 0).
durchschnitt([auto(_, X)|Tail], L, Y):-
Y is S/L,
L > 0,
cardinal([auto(_, X)|Tail], L),
sumKilometer([auto(_, X)|Tail], S).
The first problem is that when you call durchschnitt([auto(foo,2)],L,Y), L is a free variable. As a result, you cannot calculate Y is S/L since both S and L are unknown here.
You can however use:
durchschnitt([], 0, 0).
durchschnitt([auto(_, X)|Tail], L, Y):-
cardinal([auto(_, X)|Tail], L),
sumKilometer([auto(_, X)|Tail], S),
Y is S/L.
So here you calculate the average after both L and S are known. Furthermore you do not unify the list with [auto(_,X)|Tail], etc. A simple check like A = [_|_] is sufficient:
durchschnitt([], 0, 0).
durchschnitt(A, L, Y):-
A = [_|_],
cardinal(A, L),
sumKilometer(A, S),
Y is S/L.
This will also reduce the amount of time spent packing and unpacking.
Sum, Length and Average all concurrently
You can construct a predicate that calculates the three all at the same time (so without looping twice over the list). You can simply use accumulators, like:
durchschnitt(A,L,Y) :-
durchschnitt(A,0,0,L,Y).
Here the second and third element are the running sum and length respectively.
Now for durchschnitt/5, there are two cases. In the first case we have reached the end of the list, and we thus have to calculate the average and return it, like:
durchschnitt([],S,L,L,Y) :-
(L \= 0
-> Y is S/L
; Y = 0).
So we use an if-then-else to check if the length is something different than 0 (in the case there are no autos in the list, we return 0 as average.
In the recursive case, we simple increment the running length and update the running sum, like:
durchschnitt([auto(_,Si)|T],RS,RL,L,Y) :-
RSN is RS+Si,
L1 is L+1,
durchschnitt(T,RSN,L1,L,Y).
Or putting it together:
durchschnitt(A,L,Y) :-
durchschnitt(A,0,0,L,Y).
durchschnitt([],S,L,L,Y) :-
(L \= 0
-> Y is S/L
; Y = 0).
durchschnitt([auto(_,Si)|T],RS,RL,L,Y) :-
RSN is RS+Si,
L1 is L+1,
durchschnitt(T,RSN,L1,L,Y).

Prolog list elements editing

I need to write a predicate that will take a list of numbers and a number X, and then from X elements from this list (staring from the first one) it will subtract 1.
It may seem easy but I am new to this language and I cannot write it properly.
Here is what I got for now:
sub([H|T], X):-NEWH is H-1, NEWX is X-1, sub(T, NEWX).
but how can I end this reccursion? Like this?
sub([H|T], 0).
And how to avoid errors when X is larger than the number of elements in list?
You need to do four things:
Add a parameter for the result - your rule manufactures a new list, there needs to be an extra parameter there.
Add a base case for when X is zero - your sub([H|T], 0). could be further simplified as sub(_, 0). To make sure that you accept negative X, you could even make it sub(_,X) :- X =< 0.
Add another base case for when the list is empty - this would let you handle situations when X is too large: sub([], _).
Make sure that the recursive clause does not apply when X is zero - all you need to do is to add a check X > 0 to your recursive clause.
Here is how the resultant rules would look:
sub(L,X,L) :- X =< 0.
sub([], _,[]).
sub([H|T], X, [NEWH|NEWT]) :- X > 0, NEWH is H-1, NEWX is X-1, sub(T, NEWX, NEWT).
Demo.
I want to remove zeros from the list
You need to add another clause for that:
sub(L,X,L) :- X =< 0.
sub([], _,[]).
sub([H|T], X, [NEWH|NEWT]) :- X > 0, NEWH is H-1, NEWH > 0, NEWX is X-1, sub(T, NEWX, NEWT).
sub([H|T], X, NEWT) :- X > 0, NEWH is H-1, NEWH =< 0, NEWX is X-1, sub(T, NEWX, NEWT).
Demo.
Prolog is declarative. That means that once an object is created, it can't be modified (this is not strictly true for most Prolog systems, but it is in many cases unwise to perform such hacking).
What you thus need is a predicate, that takes as input the first list, and generates a new list. For your example this is for instance:
sub([],_,[]). %base case: you reached the end of the list, return an empty list as well
sub(L,0,L). %base case: you reached zero, no more editing, return the list.
sub([H|T],X,[NewH|newT]) :- %recursive case, subtract one from the head and from X and perform recursion.
NewH is H-1,
NewX is X-1,
sub(T,NewX,newT).
Note there are two base cases:
sub([],_,[]): you reached the end of the list, an possibly X has not reached zero yet. Then return an empty list as well.
sub(L,0,L): X reached zero, then you stop editing and return the list L untoched.
1) Your code doesn't do anything, since your NEWH is not returned anywhere.
2) Your code should return the full list, with modified elements, so your recursion should stop either by:
a) Comparing X to zero and appending the rest of the list
or
b) Recurring until the end of the list and compare X to 0 everytime.
The first approach is simple:
sub(L, 0, L).
sub([H|T], X, [H1 | Res]) :-
H1 is H-1,
X1 is X-1,
sub(T, X1, Res).
Then calling:
>>> sub([1,2,3,4,5,6,7], 4, L).
L = [0, 1, 2, 3, 5, 6, 7]

Prolog check value in list of lists

I am programming a board game and I want to check if a move is possible. To do that, I need to check if the position player is moving to is empty or has a possible value.
However, I don't know how can I do that without returning true or false.
Example:
Imagine you have this matrix, which represents a board:
[ [vv,vv,vv,vv,p1]
[vv,aa,vv,vv,vv]
[vv,vv,aa,vv,vv]
[vv,p2,aa,vv,vv] ]
I want to move p2 to aa, which is not empty but it is a possible move. How can I check if it's a possible move? I have a procedure to get the element at a specific position, and I am trying to implement the procedure that checks if position I am moving at is a possible one.
Current code:
elementAt(Line, 1, Y, Element):- nth0(Y, Line, Element).
elementAt([Line|Tail], X, Y, Element) :-
Y > 1,
Y1 is Y-1,
elementAt(Tail, X, Y, Element).
checkPosition(Board, X, Y):-
elementAt(Board, X, Y, Element),
Now, at checkPosition, I want to check if Element equals to vv or aa. How can I do that?
% It is true, if
% 1. X is the first element of the listoflists
% 2. X is not first element of the listoflists,
% however, it is a member of the first list in listoflists
% 3. X is a member of any other element in the listoflists
memberlist(X, [X|Xs]).
memberlist(X, [Y|Ys]) :- memberlist(X, Y).
memberlist(X, [Y|Ys]) :- memberlist(X, Ys).
I know this is posted 4 years later, hope it will be helpful to whomever runs into this answer.

Prolog program won't compute variable answer?

This should be an easy fix, but I can't seem to tackle this, and it's getting frustrating. I've coded a program which computes or verifies that two lists are related because the elements of the second list are all incremented by one from the elements of the first list. This works when two lists are given, but not when it needs to compute a list.
Code is as follows:
inc([], []).
inc([X|XS],[Y|YS]) :-
Y =:= X+1,
inc(XS,YS).
ERROR: =:=/2: Arguments are not sufficiently instantiated
Any help would be greatly appreciated!
Your problem is essentially that =:=/2 is for testing rather than establishing bindings, though is/2 still doesn't really do what you want. For instance, while 2 is 1 + 1 is true, 2 is X+1 will not result in X being bound to 1, because is/2 expects there to be just one variable or value on the left and one expression on the right, and it does not behave "relationally" like the rest of Prolog. If you want arithmetic that behaves this way, you should check out clpfd; looking at the complexity it adds is a good explanation for why things are the way they are.
Fortunately, you don't need all of arithmetic to solve your problem. The succ/2 builtin will do exactly what you need, and bonus, you get a one line solution:
inc(X, Y) :- maplist(succ, X, Y).
In use:
?- inc([1,2,3], [2,3,4]).
true.
?- inc([1,2,3], X).
X = [2, 3, 4].
?- inc(X, [1,2,3]).
X = [0, 1, 2].
Your code also works fine if you use succ/2 instead of =:=/2:
inc([], []).
inc([X|XS],[Y|YS]) :-
succ(X, Y),
inc(XS,YS).
This must be the "easy fix" you suspected. :)
I'm not sure what #mbratch is referring to about there being "too many variables" for one predicate. I suspect this is a misunderstanding of Prolog on their part, perhaps a holdover from other languages where a function can return one value or something. There is no technical limitation here; predicates can take as many ground or nonground arguments and bind as many of them as you want; the limiting factor is your creativity.
Similarly, I don't think "asymmetry" is a meaningful concept here. It's quite normal to define predicates that have just a single instantiation pattern, but it's also normal and preferable to make predicates that are flexible about instantiation—you can't know ahead of time what uses may be needed in the future. You might think to yourself that an instantiation pattern that destroys information might preclude the inverse instantiation pattern, but in practice, frequently you can turn it into a generator instead.
To give a trite example, append/3's name seems to imply this pattern:
?- append([1,2], [3,4], X).
X = [1,2,3,4]
That's a perfectly good use, but so is:
?- append(X, Y, [1,2,3,4]).
This is a non-deterministic instantiation pattern and will produce five solutions:
X = [], Y = [1,2,3,4]
X = [1], Y = [2,3,4]
X = [1,2], Y = [3,4]
X = [1,2,3], Y = [4]
X = [1,2,3,4], Y = []
This seems to stand in contradiction to some of #mbratch's ideas, but there's no explicit testing for ground/nonground in the usual definition of append/3, because it isn't necessary, and likewise with the second calling pattern you get two "return values" from one input. SWI source:
append([], L, L).
append([H|T], L, [H|R]) :-
append(T, L, R).
Edit: Negative numbers. I forgot that succ/2 is defined only on positive integers. We can apply #mbratch's technique and still get a tidy solution with the desired properties:
isucc(X, Y) :- var(X), X is Y-1.
isucc(X, Y) :- Y is X+1.
inc(X, Y) :- maplist(isucc, X, Y).
In action:
?- inc(X, [-1,2]).
X = [-2, 1] ;
false.
Edit: Using clp(fd) (via #mat):
fdsucc(X,Y) :- Y #= X + 1.
inc(X, Y) :- maplist(fdsucc, X, Y).
This generates even for the most general query:
?- inc(X, Y).
X = Y, Y = [] ;
X = [_G467],
Y = [_G476],
_G467+1#=_G476 ;
X = [_G610, _G613],
Y = [_G622, _G625],
_G610+1#=_G622,
_G613+1#=_G625 ;
X = [_G753, _G756, _G759],
Y = [_G768, _G771, _G774],
_G753+1#=_G768,
_G756+1#=_G771,
_G759+1#=_G774
...
The utility of this is questionable, but presumably since you're using clp(fd) you'll eventually impose other constraints and get something useful.
inc([],[]).
inc([X|XS],[Y|YS]) :-
nonvar(X),
Z is X + 1,
Y = Z,
inc(XS,YS), !.
inc([X|XS],[Y|YS]) :-
nonvar(Y),
Z is Y - 1,
X = Z,
inc(XS,YS), !.
Here we need to get a real computation for the addition, then attempt instantiation with =. The predicate had to be split to deal with the case where X was not instantiated, versus when Y wasn't. The ! at the end of each is to prevent it from trying for more solutions after it has found one through one of the two similar paths.