Taking from an element in a list prolog - prolog

Say I have a list
[5,4,6,9]
And I want to take away from the head of the list but return the rest of the list
so: -3
[2,4,6,9]
-2
[3,4,6,9]
And then I want to move on to the next element so,
-3
[5,1,6,9],
-2
[5,2,6,9]
How could I produce a prolog predicate for this,
so far I have
change([],[]).
change([Head|Tail], [Head1|Tail]):-
process(Head, Head1).
process([],[]).
process(Head, Head1):-
Head1 is Head-3,
Head1 >=0.
process(Head, Head1):-
Head1 is Head-2,
Head1 >=0.
I'm unsure what I'd return in my recursive call,
any help would be great thank you

The way your code is currently written it's attempting to change more than one list element in a given solution. However, the requirement appears to be to only change one list element. Using CLP(FD) will help with the arithmetic.
change([], []). % Nothing to change
change([X|T], [Y|T]) :- % Change only the head
Y #= X - 2 ; Y #= X - 3.
change([X|Xs], [X|Ys]) :- % Keep the head and change something later
change(Xs, Ys).
The potential problem with this solution is that it change(L, L). is true (the list isn't changed). To avoid that, you can change the base case to be for the single element list and force the others to be two elements:
change([X], [Y]) :- % Change only the last or single element
Y #= X - 2 ; Y #= X - 3.
change([X,X1|Xs], [Y,X1|Xs]) :- % Change only the head
Y #= X - 2 ; Y #= X - 3.
change([X,X1|Xs], [X,Y1|Ys]) :- % Keep the head and change something later
change([X1|Xs], [Y1|Ys]).

Related

Verify if an element is present in a matrix in ProLog

Good night everyone,
I'm in the middle of some busy days trying to deliver a small project for my Logic Programming classes, where the theme is based on operations on matrices.
Well, one of those asked operations was to verify if a certain element exists in a given matrix, and I'm having some issues with it as I usually have my mind set for imperative programming.
For now, i reached this:
isElemPresent(_, []) :- !.
isElemPresent(Elem, [M|Mt]) :- isElemPresent(Elem,Mt) ; isElemPresentRow(Elem,M).
isElemPresentRow(Elem, [Elem|_]).
isElemPresentRow(Elem, [_|T]) :- isElemPresentRow(Elem, T).
I would really appreciate if someone could guide to my goal, and if possible tell what lacks on my code.
% The element belongs to the list if it matches
% the head of the list
isElemPresent(X,[X|_]).
% The element belongs to the list if it is
% in the head (another array) of the list.
isElemPresent(X,[A|_]):- isElemPresent(X,A).
% The element belongs to the list if it is
% in the queue of the list.
isElemPresent(X,[_|R]):- isElemPresent(X,R).
For instance:
?- isElemPresent(4,[[1,2,5],[6,3,4]]).
Yes
is_elem_present(Elem, Matrix) :-
member(Row, Matrix),
member(Elem, Row).
?- is_elem_present(Elem, [[1,2,5],[6,3,4]]).
Elem = 1 ;
Elem = 2 ;
Elem = 5 ;
Elem = 6 ;
Elem = 3 ;
Elem = 4.
?- is_elem_present(2, [[1,2,5],[6,3,4]]).
true ;
false.
And here's how to do it with indexes:
is_elem_present(I, J, Elem, Matrix) :-
nth0(I, Matrix, Row),
nth0(J, Row, Elem).
?- forall(is_elem_present(I,J,Elem,[[1,2,5],[6,3,4]]), writeln([I,J]=Elem)).
[0,0]=1
[0,1]=2
[0,2]=5
[1,0]=6
[1,1]=3
[1,2]=4
true.

Display all list elements that greather than N - Prolog

I want to Display all list elements that larger than N, my code like
member2(X, [X|_]).
member2(X, [_|T]) :- member2(X,T), X > T, write(X).
Why would you state member2(X, [X|_]) ? Its not the last element yet. You should only stop when there are no more elements to check: member2(X,[]).
And generally:
member2(X,[Y|Ys]) :- (X >= Y -> display(Y), nl; true), member2(X,Ys).
This way you will display all the Ys that are smaller or equal to X.
In your code, T was a list of elements. You cannot compare it to a single elememt X.
You could use include/3 to perform the filtering. For example:
include(<(5),[7,3,2,6,4,5,8],Output).
will unify Output with [7,6,8] (the elements in the second argument that are greater than the number used in the first argument).

Prolog internal variable names

I have a large numbers of facts that are already in my file (position(M,P)), M is the name and P is the position of the player , I am asked to do a player_list(L,N), L is the list of players and N is the size of this list. I did it and it works the problem is that it gives the list without the names it gives me numbers and not names
player_list([H|T],N):- L = [H|T],
position(H,P),
\+ member(H,L),
append(L,H),
player_list(T,N).
what I get is:
?- player_list(X,4).
X = [_9176, _9182, _9188, _9194] .
so what should I do ?
You could use an additional list as an argument to keep track of the players you already have. This list is empty at the beginning, so the calling predicate calls the predicate describing the actual relation with [] as an additional argument:
player_list(PLs,L) :-
pl_l_(PLs,L,[]). % <- actual relation
The definition you posted is missing a base case, that is, if you already have the desired amount of players, you can stop adding others. In this case the number of players to add is zero otherwise it is greater than zero. You also have to describe that the head of the list (PL) is a player (whose position you don't care about, so the variable is preceded by an underscore (_P), otherwise the goal is just like in your code) and is not in the accumulator yet (as opposed to your code, where you check if PL is not in L) but in the recursive call it is in the accumulator. You can achieve the latter by having [PL|Acc0] in the recursive goal, so you don't need append/2. Putting all this together, your code might look something like this:
pl_l_([],0,_). % base case
pl_l_([PL|PLs],L1,Acc0) :-
L1 > 0, % number of players yet to add
L0 is L1-1, % new number of players to add
position(PL,_P), % PL is a player and
\+ member(PL,Acc0), % not in the accumulator yet
pl_l_(PLs,L0,[PL|Acc0]). % the relation holds for PLs, L0 and [PL|Acc0] as well
With respect to your comment, I assume that your code contains the following four facts:
position(zlatan,center).
position(rooney,forward).
position(ronaldo,forward).
position(messi,forward).
Then your example query yields the desired results:
?- player_list(X,4).
X = [zlatan,rooney,ronaldo,messi] ? ;
X = [zlatan,rooney,messi,ronaldo] ? ;
...
If you intend to use the predicate the other way around as well, I suggest the use of CLP(FD). To see why, consider the most general query:
?- player_list(X,Y).
X = [],
Y = 0 ? ;
ERROR at clause 2 of user:pl_l_/3 !!
INSTANTIATION ERROR- =:=/2: expected bound value
You get this error because >/2 expects both arguments to be ground. You can modify the predicate pl_l_/3 to use CLP(FD) like so:
:- use_module(library(clpfd)).
pl_l_([],0,_).
pl_l_([PL|PLs],L1,Acc0) :-
L1 #> 0, % <- new
L0 #= L1-1, % <- new
position(PL,_P),
\+ member(PL,Acc0),
pl_l_(PLs,L0,[PL|Acc0]).
With these modifications the predicate is more versatile:
?- player_list([zlatan,messi,ronaldo],Y).
Y = 3
?- player_list(X,Y).
X = [],
Y = 0 ? ;
X = [zlatan],
Y = 1 ? ;
X = [zlatan,rooney],
Y = 2 ?
...

Prolog Bubblesort

I'm trying to best understand everything about this code. This is how I currently perceive what's happening:
So I can see if X > Y we swap the elements, if not we recurse down the sublist until we find an X that X > Y, if we do not, then the list is sorted.
Problems I'm having is I don't really understand the base case, bubblesort(Sorted, Sorted). I thought you would need a base case for an empty list? I would really appreciate if someone could describe a sort of step by step description of this program.
bubblesort(List,Sorted) :-
swap(List,List1),
!,
bubblesort(List1,Sorted).
bubblesort(Sorted,Sorted).
swap([X,Y|Rest],[Y,X|Rest]) :- % swaps X with Y if gt(X,Y) is true.
gt(X,Y).
swap([Z|Rest],[Z|Rest1]) :- % calls swap on sublists excluding the heads.
swap(Rest,Rest1).
gt(X,Y) :- % true if X is greater than Y.
X > Y.

Prolog - sequence in list

We want to build a predicate that gets a list L and a number N and is true if N is the length of the longest sequence of list L.
For example:
?- ls([1,2,2,4,4,4,2,3,2],3).
true.
?- ls([1,2,3,2,3,2,1,7,8],3).
false.
For this I built -
head([X|S],X). % head of the list
ls([H|T],N) :- head(T,X),H=X, NN is N-1 , ls(T,NN) . % if the head equal to his following
ls(_,0) :- !. % get seq in length N
ls([H|T],N) :- head(T,X) , not(H=X) ,ls(T,N). % if the head doesn't equal to his following
The concept is simply - check if the head equal to his following , if so , continue with the tail and decrement the N .
I checked my code and it works well (ignore cases which N = 1) -
ls([1,2,2,4,4,4,2,3,2],3).
true ;
false .
But the true answer isn't finite and there is more answer after that , how could I make it to return finite answer ?
Prolog-wise, you have a few problems. One is that your predicate only works when both arguments are instantiated, which is disappointing to Prolog. Another is your style—head/2 doesn't really add anything over [H|T]. I also think this algorithm is fundamentally flawed. I don't think you can be sure that no sequence of longer length exists in the tail of the list without retaining an unchanged copy of the guessed length. In other words, the second thing #Zakum points out, I don't think there will be a simple solution for it.
This is how I would have approached the problem. First a helper predicate for getting the maximum of two values:
max(X, Y, X) :- X >= Y.
max(X, Y, Y) :- Y > X.
Now most of the work sequence_length/2 does is delegated to a loop, except for the base case of the empty list:
sequence_length([], 0).
sequence_length([X|Xs], Length) :-
once(sequence_length_loop(X, Xs, 1, Length)).
The call to once/1 ensures we only get one answer. This will prevent the predicate from usefully generating lists with sequences while also making the predicate deterministic, which is something you desired. (It has the same effect as a nicely placed cut).
Loop's base case: copy the accumulator to the output parameter:
sequence_length_loop(_, [], Length, Length).
Inductive case #1: we have another copy of the same value. Increment the accumulator and recur.
sequence_length_loop(X, [X|Xs], Acc, Length) :-
succ(Acc, Acc1),
sequence_length_loop(X, Xs, Acc1, Length).
Inductive case #2: we have a different value. Calculate the sequence length of the remainder of the list; if it is larger than our accumulator, use that; otherwise, use the accumulator.
sequence_length_loop(X, [Y|Xs], Acc, Length) :-
X \= Y,
sequence_length([Y|Xs], LengthRemaining),
max(Acc, LengthRemaining, Length).
This is how I would approach this problem. I don't know if it will be useful for you or not, but I hope you can glean something from it.
How about adding a break to the last rule?
head([X|S],X). % head of the list
ls([H|T],N) :- head(T,X),H=X, NN is N-1 , ls(T,NN) . % if the head equal to his following
ls(_,0) :- !. % get seq in length N
ls([H|T],N) :- head(T,X) , not(H=X) ,ls(T,N),!. % if the head doesn't equal to his following
Works for me, though I'm no Prolog expert.
//EDIT: btw. try
14 ?- ls([1,2,2,4,4,4,2,3,2],2).
true ;
false.
Looks false to me, there is no check whether N is the longest sequence. Or did I get the requirements wrong?
Your code is checking if there is in list at least a sequence of elements of specified length. You need more arguments to keep the state of the search while visiting the list:
ls([E|Es], L) :- ls(E, 1, Es, L).
ls(X, N, [Y|Ys], L) :-
( X = Y
-> M is N+1,
ls(X, M, Ys, L)
; ls(Y, 1, Ys, M),
( M > N -> L = M ; L = N )
).
ls(_, N, [], N).

Resources