Get list of positive values in Prolog - list

So I'm trying to get list of positive elements from given list. So far I've come to this solution:
1 getPos([],[]).
2 getPos([], L).
3 getPos([Head|Tail], L):-
4 Head<0, getPos(Tail,L).
5 getPos([Head|Tail], L:-
6 Head>0, getPos(Tail, [Head|L]).
If I try getPos([1,-2,3], Result).
I get to fact number 2 with this result:
Call: getPos([], [3,1|_29])?
Exit: getPos([], [3,1|_29])?
After that I just quit out of recursion and end up with only "yes" answer.
My 2 quesstions are:
1. What should I do, so my program would stop at that 2nd fact and just return value of L
2. Is it possible to keep order of source list? (my version reverses source list)

You should use a third argument getPos(In, CurOut, Out), and when In is empty (e.g. [], you unify CurOut with Out.
so you get
getPos(In, Out) :-
getPos(In, [], Out).
getPos([],L, L).
% getPos_1([], L).
getPos([Head|Tail], CurL, L):-
Head<0, getPos(Tail,CurL, L).
getPos([Head|Tail], CurL, L):-
Head>0, getPos(Tail, [Head|CurL], L).
What do you do if a value is 0 ?
In SWI-Prolog you can use include/3
get_pos(In, Out) :-
include(>( 0), In, Out).
If you want to only use 2 args you can write
getPos1([], []).
getPos1([Head|Tail], L):-
Head<0, getPos1(Tail,L).
getPos1([Head|Tail], [Head|L]):-
Head>0,
getPos1(Tail, L).

Related

making a list of random integers on prolog

So my problem is this i have this predicate which is n_aleatorios(El,INF,SUP,L) in which El is the lenght of the list, INF is the lower limit value of the list, SUP is the upper limit value of the list, and L is a list.
The objective of this predicate is to create a list of random integers.
The problem is that this is giving true as a result instead of unifying and giving the list as the result.
auxiliar predicates:
/*Checks if a number isnt a member of a list*/
nao_membro(_, []).
nao_membro(X, [P | R]) :- X \== P,
nao_membro(X, R).
/*Joins an integer in a sorted list, in a sorted order*/
insere_ordenado(El,[],[El]).
insere_ordenado(El,[P|R],[P|L2]) :- El >= P,
insere_ordenado(El,R,L2).
insere_ordenado(El,[P|R],[El,P|R]) :- El < P.
/*Joins a random integer in a sorted list, in a sorted order*/
junta_novo_aleatorio(L1,INF,SUP,L2) :- random_between(INF, SUP, N),
nao_membro(N,L1),
insere_ordenado(N,L1,L2).
Program:
n_aleatorios(El,INF,SUP,L) :- n_aleatorios(El,INF,SUP,[],0).
n_aleatorios(El,_,_,L,El).
n_aleatorios(El,INF,SUP,L,AC) :- AC =< El,
junta_novo_aleatorio(L,INF,SUP,L2),
AC_num is AC +1,
n_aleatorios(El,INF,SUP,L2,AC_num).
My output:
?- n_aleatorios(3, 1, 5, Lst).
true ;
false.
Expected output (for example):
?- n_aleatorios(3, 1, 5, Lst).
Lst = [2,3,5]
Really any help would be appreciated.
Corrected code:
One slight improvement here:
nao_membro(X, [P | R]) :-
X =\= P,
nao_membro(X, R).
Use "arithmetic non-equivalence" =\= instead of "structural non-equivalence" \== if we can be assured that neither X nor P are fresh. Indeed, here they are always integers.
Fixed code:
junta_novo_aleatorio(L1,INF,SUP,L2) :-
random_between(INF, SUP, N),
nao_membro(N,L1),
insere_ordenado(N,L1,L2).
n_aleatorios(Count,INF,SUP,L) :-
n_aleatorios(Count,INF,SUP,[],L).
n_aleatorios(Count,_,_,L,L) :-
length(L,Count),!.
n_aleatorios(Count,INF,SUP,Lin,Lout) :-
length(Lin,Len), Len<Count,!,
junta_novo_aleatorio(Lin,INF,SUP,Lmid),
n_aleatorios(Count,INF,SUP,Lmid,Lout).
Problems are due to the fact that the list to be constructed is not "threaded" properly between the predicates calls. Here, Lin is the "input list". It is where information "flows into" the predicate. Lin is is used to construct a new list Lout, which appears again the in the predicate argument, but now information "flows out" of the predicate back to the caller.
I have also eliminated the counter, which is already implicit in the length of Lin.
Note that selection between the two clauses of n_aleatorios/5 occurs via a guard followed by a "cut" which commits to the execution path. The second "cut" is actually not needed, because there is no clause below, but makes things clear:
n_aleatorios(Count,_,_,L,L) :-
length(L,Count),!,...(we will never try any clause below)..
n_aleatorios(Count,INF,SUP,Lin,Lout) :-
length(Lin,Len), Len<Count,!,....(we will never try any clause below)..

How can I take input and make a list with it on Prolog?

I'm doing homework for Basic Artificial Intelligence, and the problem is, "Make a Prolog program that can read 2 lists of numeric values and
concatenate them", so I'm a total noob and I have no idea how to take a input from Prolog and put it on a list one by one
%I have only make the while func so that you
%put the total numbers you want on the list
p_while(0) :- !.
p_while(N) :-
N > 0,
N1 is N - 1,
read(Num),
p_while(N1).
There is a standard predicate called append/3. You can use it to read two lists of numerical values from the prompt and concatenate them, like this:
?- append([1,2], [3,4], L).
L = [1, 2, 3, 4].
You can use listing/1 to see how append/3 is defined:
?- listing(append/3).
lists:append([], L, L).
lists:append([H|T], L, [H|R]) :-
append(T, L, R).
true.

Prolog split list by predicate - how to check predicate's result?

I am trying to implement a predicate that splits a list of integers in two given another predicate as an argument. The definition is given as follows:
split(P, L, L1, L2),
where:
P - predicate to split upon
L - list to split
L1 - result list of integers that return true on predicate check
L2 - result list of integers that return false on predicate check
I am trying to modify this code, that splits the list with hardcoded check whether the integer in question is bigger / smaller or equal to X (this works):
split(X, [], [], []).
split(X, [H|T], [H|L1], L2) :- H=<X, split(X, T, L1, L2).
split(X, [H|T], L1, [H|L2]) :- H>X, split(X, T, L1, L2).
For testing purposes, I copied a predicate from RosettaCode to check if the number is even as follows:
even(N) :-
(between(0, inf, N); integer(N) ),
0 is N mod 2.
And here is my modification of the above code, but it returns "Syntax error: Operator expected" on last two lines:
split2(P, [], [], []).
split2(P, [H|T], [H|L1], L2) :- P(H), split2(P, T, L1, L2).
split2(P, [H|T], L1, [H|L2]) :- \+ P(H), split2(P, T, L1, L2).
I think my error is in checking whether the predicate returns true or false, but can't find the appropriate way of doing so.
EDIT: Forgot to add my call for this:
?- split2(even,[2,7,4,8,-1,5],L1,L2)
You can't call a predicate like this, you need to use call:
?- A = between(0,3,1), A. % OK, because A can be evaluated as it is
A = between(0, 3, 1).
?- A = between, A(0,3,1). % won't work
ERROR: Syntax error: Operator expected
ERROR: A = between,
ERROR: ** here **
ERROR: A(0,3,1) .
?- A = between, call(A, 0, 3, 1). % OK, using call
A = between.
?- A = between(0, 3), call(A, 1). % Partial application
A = between(0, 3).
Keep in mind that there are already library predicates that do exactly what you are after, see library(apply), esp. include/3. You should also take a look at the implementation, as it is slightly different from what you are doing and doesn't leave choice points behind.
PS: Rearranging the arguments so that the input list is at the front is the first step towards making this deterministic. You also need to get rid of the choice point caused by the two clauses, the one with call(P,H) and the one with \+ call(P,H). You can do this with a ->, as in the SWI-Prolog library.
Or maybe you are not bothered by the choice points, or want to make a more general predicate. I am sure that there are solutions here on Stackoverflow on the Prolog tag.

Remove unique elements only

There are many resources on how to remove duplicates and similar issues but I can't seem to be able to find any on removing unique elements. I'm using SWI-Prolog but I don't want to use built-ins to achieve this.
That is, calling remove_unique([1, 2, 2, 3, 4, 5, 7, 6, 7], X). should happily result in X = [2, 2, 7, 7].
The obvious solution is as something along the lines of
count(_, [], 0) :- !.
count(E, [E | Es], A) :-
S is A + 1,
count(E, Es, S).
count(E, [_ | Es], A) :-
count(E, Es, A).
is_unique(E, Xs) :-
count(E, Xs, 1).
remove_unique(L, R) :- remove_unique(L, L, R).
remove_unique([], _, []) :- !.
remove_unique([X | Xs], O, R) :-
is_unique(X, O), !,
remove_unique(Xs, O, R).
remove_unique([X | Xs], O, [X | R]) :-
remove_unique(Xs, O, R).
It should become quickly apparent why this isn't an ideal solution: count is O(n) and so is is_unique as it just uses count. I could improve this by failing when we find more than one element but worst-case is still O(n).
So then we come to remove_unique. For every element we check whether current element is_unique in O. If the test fails, the element gets added to the resulting list in the next branch. Running in O(n²), we get a lot of inferences. While I don't think we can speed it in the worst case, can we do better than this naïve solution? The only improvement that I can clearly see is to change count to something that fails as soon as >1 elements are identified.
Using tpartition/4 in tandem with
if_/3 and (=)/3, we define remove_unique/2 like this:
remove_unique([], []).
remove_unique([E|Xs0], Ys0) :-
tpartition(=(E), Xs0, Es, Xs),
if_(Es = [], Ys0 = Ys, append([E|Es], Ys, Ys0)),
remove_unique(Xs, Ys).
Here's the sample query, as given by the OP:
?- remove_unique([1,2,2,3,4,5,7,6,7], Xs).
Xs = [2,2,7,7]. % succeeds deterministically
As long as you don't know that the list is sorted in any way, and you want to keep the sequence of the non-unique elements, it seems to me you can't avoid making two passes: first count occurrences, then pick only repeating elements.
What if you use a (self-balancing?) binary tree for counting occurrences and look-up during the second pass? Definitely not O(n²), at least...

Getting vertical lists of lists of lists in prolog?

a List of Lists like
Lists=[ [1,2,3],
[4,5,6],
[7,8,3] ]
and i want to get in this case all vertical lists like
[1,4,7], [2,5,8], [3,6,3]
how to do that? i thought about 2 counters witch work together like two "for to do" repeats.
i need to check with "is_set" if [1,4,7] is a set or [3,6,3] witch of course is not.
like this:
el_at(Llist,Gl,1),
el_at(EList, Llist,1),
globalListVertikalCheck(ListVertikal),
addlist(Elist,ListVertikal,NewListVertikal),
el_at(Llist,Gl,2),
el_at(EList, Llist,2),
globalListVertikalCheck(ListVertikal),
addlist(Elist,ListVertikal,NewListVertikal),
thanks
A list of all vertical lists is known as a transposed matrix.
SWI's library(clpfd) contains such code.
I didn't fully understand the solution you propose, but I have another one. I will try to describe how it works and maybe than you can see what was wrong with your solution and why it didn't work.
Let's consider an example of [[1,2], [3,4]]. The idea is to go through the first sub-list [1,2] and create an incomplete result [[1],[2]], then go through the next one [3,4] and prepend (which is easier than append in Prolog) each item in it to the each sub-list in the result. We will end up with [[3,1], [4,1]]. The sub-lists are then reversed and we have the result [[1,3],[1,4]].
Now the implementation:
The vertical predicate is the core, it goes through the list of lists and the result is step by step accumulated in the Acc varible.
For each of the sublists, the vertical predicate calls the addfirst predicate, which takes each element of that sublist and prepends it to the list in which the previous results were accumulated.
vertical([X|Xs],Result):-
createempty(X, Acc),
vertical([X|Xs], Acc, ReversedResults),
reverseall(ReversedResults, Result).
reverseall([], []).
reverseall([X|Xs], [XReversed|Rest]):-
reverse(X, XReversed),
reverseall(Xs, Rest).
createempty([], []).
createempty([X|Xs], [[]|R]):-createempty(Xs,R).
vertical([], Result, Result).
vertical([X|Xs], Acc, Result):-
addfirst(X, Acc2, Acc),
vertical(Xs, Acc2, Result).
addfirst([], [], []).
addfirst(
[Y|Ys],
[[Y|YVerticalRest]|ResultRest],
[YVerticalRest|VerticalsRest]):-
addfirst(Ys, ResultRest, VerticalsRest).
Here goes a small implementation of transpose:
It works by taking the first element of every sublist. When it finishes, it recursively does the same but now with the next item of each list, and so on.
transpose(M, T):-
transpose(M, [], T).
transpose([], [], []).
transpose([], S, [[]|T]):-
S \= [] ->
(reverse(S, M), transpose(M, [], T)).
transpose([[]|MTail], S, T):-
transpose(MTail, S, T).
transpose([[Item|Tail]|MTail], S, [[Item|NTail]|T]):-
transpose(MTail, [Tail|S], [NTail|T]).
transpose([[]|_],[]) :- !.
transpose(L,[L1|R2]) :-
transpose(L,L2,L1),
transpose(L2,R2).
transpose([],[],[]) :- !.
transpose([[A|R1]|R2],[R1|R3],[A|R4]) :-
transpose(R2,R3,R4).