Merging elements of tuples in a list in Prolog - list

I need to create a list from a knowledgebase that could look like this:
fact1(3,3).
fact1(2,3).
fact1(3,5).
fact1(2,2).
fact1(2,10).
fact1(3,1).
fact1(1,1).
fact1(1,6).
fact2(3,a,b)
fact2(2,c,d)
fact2(1,e,f)
That list needs to contain tuples with each containing the second and third Value of fact2, and the added numbers of fact2, whenever the first value of fact1 and fact2 match up.
Maybe it gets clearer when I show what I have so far.
Here is my predicate with the findall statement, which to me seems to get me the closest to where I need to get:
collect_items(List):-
findall((Out1,Out2,Nr),
(fact2(Val1,Out1,Out2),
fact1(Val1,Nr)),
List).
The List I receive from this, looks like this:
List = [(a,b,3),(a,b,5),(a,b,1),(c,d,3),(c,d,2),(c,d,10),(e,f,1),(e,f,6)]
But really I need the list to look like this:
List = [(a,b,9),(c,d,15),(e,f,7)]
Meaning that, whenever the first two elements of a tuple match up, the numbers, which are the third element of the tuple, should be added together.
I do not know however how to even approach something like this, as I have always read, that as soon as the list is set, it cannot be changed, since prolog is functional and declarative.
So I think I somehow need to match every element against the one before or after it (since the list will always be sortet by the Out1 and Out2 variables), and if they match, add the third value in the tuple together. The problem is, that I have no idea how.
To me it looks like this can not realy be done within the findall itself but would need to be done after the findall
I am a true beginner and would appreciate any help. In this case it would be best, if the solution was all in one predicate.

Here is another solution that uses more than one predicate:
collect_items(Result):-
findall([Out1,Out2,Nr],(fact2(Val1,Out1,Out2),fact1(Val1,Nr)),[[OutA, OutB, N]|B]),
sumElements([[OutA, OutB, N]|B], Result).
sumElements([],[]).
sumElements([[Out, Outt, N]|B], [[Out, Outt, SumLocal]|RestOfList]):-
findall([Out, Outt, X], member([Out, Outt, X], [[Out, Outt, N]|B]), SubList),
sumLocal(SubList, SumLocal),
subtract([[Out, Outt, N]|B], SubList, New),
sumElements(New, RestOfList).
sumLocal([],0).
sumLocal([[_,_,S]|B], T):-
sumLocal(B, R),
T is S + R.
output:
?- collect_items(Result).
Result = [[a, b, 9], [c, d, 15], [e, f, 7]].

with library aggregate:
collect_items(L) :-
setof((U,V,S),
K^aggregate((set(X/Y),sum(N)), (
fact2(K,X,Y),
fact1(K,N)
), ([U/V],S)), L).
we get
?- collect_items(L).
L = [(a, b, 9), (c, d, 15), (e, f, 7)].
You are not right here
since prolog is functional and declarative
Prolog is relational and declarative

Related

Counting how many elements in a list of lists satisfy a predicate

Given a list of lists of integers, e.g. [[3,10],[3,10,2],[5],[5,2],[5,3],[5,3,2],[5,3,10]], I want to go over each sublist and count how many of them sum to 15. In this case that would be 1, for the sublist [3,10,2].
I am aware of the predicate aggregate_all/3, but I'm having trouble writing a predicate to check each element of the list, what I have now is something like
fifteens([X|Xs]) :-
sum_list(X, 15),
fifteens(Xs).
and within another predicate I have:
aggregate_all(count, fifteens(Combinations), Value).
where Combinations is the list of lists of integers in question.
I know my fifteens predicate is flawed since it's saying that all elements of the nested list must sum to 15, but to fix this how do I take out each element of Combinations and check those individually? Do I even need to? Thanks.
First of all your fifteens/2 predicate has no because for empty list and thus it will always fails because due to the recursion eventually fifteens([]) will be called and fail.
Also you need to change completely the definition of fifteens, currently even if you add base case, it says check ALL elements-sublists to see if they sum to 15. That's Ok but I don't see how you could use it with aggregate.
To use aggregate/3 you need to express with fifteens/2, something like: for every part of my combinations list check separately each sublist i.e each member:
ifteens(L) :-
member(X,L),
sum_list(X, 15).
Now trying:
?- aggregate_all(count, ifteens([[3,10],[3,10,2],[5],[5,2],[5,3],[5,3,2],[5,3,10]]), Value).
Value = 1.
This is a job for ... foldl/4. Functional programming idioms in logic programming languages? Yes, we can!
First, summing the summable values of a list:
sum_them(List,Sum) :-
foldl(sum_goal,List,0,Sum).
sum_goal(Element,FromLeft,ToRight) :-
must_be(number,Element),
must_be(number,FromLeft),
ToRight is Element+FromLeft.
Then, counting the ones that sum to 15:
count_them(List,Count) :-
foldl(count_goal,List,0,Count).
count_goal(Element,FromLeft,ToRight) :-
must_be(list(number),Element),
must_be(number,FromLeft),
sum_them(Element,15) -> succ(FromLeft,ToRight) ; FromLeft = ToRight.
Does it work? Let's write some unit tests:
:- begin_tests(fifteen_with_foldl).
test("first test",true(R==1)) :-
count_them([[3,10],[3,10,2],[5],[5,2],[5,3],[5,3,2],[5,3,10]],R).
test("test on empty",true(R==0)) :-
count_them([],R).
test("test with 2 hist",true(R==2)) :-
count_them([[15],[],[1,1,1,1,1,10]],R).
:- end_tests(fifteen_with_foldl).
And so:
% PL-Unit: fifteen_with_foldl ... done
% All 3 tests passed
true.

Reverse every second list of lists in Prolog

I have a list containing lists and I want to reverse every second list in it. I tried something but if I have odd number of elements in the list the last list element is lost... So the best solution would be to put the odd lists first and the even lists second till every second list is reversed.
I can't use any libraries. I need to do it recursively or split them and append them again. The best thing I made so far was to reverse only the first even list and append the first odd and even list in a new list.
I tried to do this:
reverselist(List, [List]).
reverselist([X,Y|Rest], [SnakeList|Rest2]):-
append(X, [], Odd),
reverse(Y, EvenList),
append(Odd, EvenList, SnakeList),
reverselist(Rest, Rest2).
And this:
reverselist(List1, List2).
reverselist([H|Ts], [Odd|R]):-
not(0 is H mod 2),
append(H, [], Odd),
reverselist(Ts, R).
reverselist([H|Ts], [Even|R]):-
0 is H mod 2,
reverse(H, Even),
reverselist(Ts, R).
Sample query:
?- reverselist([[a,b,c],[d,a,b],[c,d,o],[b,c,d],[e,e,d]], List).
I want the result to be:
List = [ [a,b,c],[b,a,d],[c,d,o],[d,c,b],[e,e,d] ].
You can also write mutual recursion:
reverselist([],[]).
reverselist([H|T],[H|T1]):-reverselist2(T,T1).
reverselist2([],[]).
reverselist2([H|T],[H1|T1]):-reverse(H,H1), reverselist(T,T1).
You were pretty close with your first variant.
Instead of your
reverselist(List, [List]).
reverselist([X,Y|Rest], [SnakeList|Rest2]):-
append(X, [], Odd),
reverse(Y, EvenList),
append(Odd, EvenList, SnakeList),
reverselist(Rest, Rest2).
just tweak it as
reverselist([], []). % additional clause
reverselist([List], [List]).
reverselist([X,Y|Rest], [X,EvenList|Rest2]):-
reverse( Y, EvenList),
reverselist( Rest, Rest2).
All three clauses are mutually exclusive and together they are exhaustive, i.e. they cover every possibility.
I believe this definition to be the most immediate and close representation of your problem. In Prolog, to formulate the problem means to have the solution for it.
We need to create another predicate with one more argument to keep track of odd or even position:
reverselist(InList,OutList):- reverselist(InList,OutList, 0).
reverselist([],[],_). %base case
%case of even position
reverselist([H|T],[H|T1], 0):- reverselist(T,T1,1).
%case of odd position
reverselist([H|T],[H1|T1], 1):- reverse(H1,H), reverselist(T,T1,0).

Inserting value into the begining of each sublist

I'm currently writing a predicate that will run through a list of lists and insert a value I have calculated onto the beginning of the list
Step one is easy, just perform the calculation for each list and unify variable N with it.
checkthrough([]).
checkthrough([H|T]):-
count_validentries(H,N),
checkthrough(T).
What I'm trying to achieve now is to put that variable N onto the beginning of each of my sublists, so each list begins with the count of valid entries.
I have attempted to do this using an accumulator. Attempting to start with an empty list, and to every time add the new value N and the head of the list to it:
checkthrough([],Sofar,Lastone).
checkthrough([H|T],Sofar,Lastone):-
count_validentries(H,N),
Newsofar is [N,H|Sofar],
checkthrough(T,Newsofar,Lastone).
I'm quite sure I'm making a really stupid mistake somewhere along the lines. This is not valid Prolog syntax, failing with Arithmetic:' [2 internal variables]' is not a function.
Does anyone have any tips please?
Using meta-predicate maplist/3 and Prolog lambda simply write:
?- use_module(library(lambda)).
?- maplist(\Es^[N|Es]^count_validentries(Es,N), Ess, Xss).
Also, I'd guess that you're really looking for (-)/2 pairs which is how key-value pairs are commonly represented—by library predicates and the built-in predicate keysort/2. Consider:
?- Ess = [[a,b,c],[d,e],[],[f]],
maplist(\Es^(N-Es)^length(Es,N), Ess, Xss),
keysort(Xss, Yss).
Ess = [ [a,b,c], [d,e], [], [f]],
Xss = [3-[a,b,c], 2-[d,e], 0-[], 1-[f]],
Yss = [0-[], 1-[f], 2-[d,e], 3-[a,b,c]].
Maybe
checkthrough([],Sofar,Sofar).
checkthrough([H|T],Sofar,Lastone):-
count_validentries(H,N),
checkthrough(T,[[N|H]|Sofar],Lastone).
but you'll end up with the list reversed. Keeping it simpler will help
checkthrough([],[]).
checkthrough([H|T],[[N|H]|Rest]):-
count_validentries(H,N),
checkthrough(T,Rest).
or better, if you're running a recent version of SWI-Prolog:
checkthrough(L,L1) :-
maplist([E,E1]>>(count_validentries(E,N),E1=[N|E]), L,L1).

Get longest list as goal in prolog

I have more possible list as goal,but i need only one longest list.Is this possible to get first longest list?
li-->[a]|[b]|[c].
int-->['1']|['2']|['3'].
num-->int,num_nl.
num_nl-->num|[].
list1-->num,li.
classify(L,S,R):-list1(S,[]),extract(S,L,R).
extract(S,L1,L2):-append(L11,L22,L1),append(S,L3,L22),append(L11,L3,L2).
Here ERROR: Out of local stack.I want only longest list as goal:
?-classify([c,'1','1',a,f],S,R).
S = ['1', '1', a], R = [c, f] ;
false.
?-classify([c,'1','2','3',a,f,'1','1','2','3',b],S,R).
S = ['1','2','3',a], R = [c, f,'1','1','2','3',b] ;
false.`
You don't provide any detail on how classify/1 is implemented; it could be that you can define it so that it only gives you the longest list.
Your other option is to collect all results, using either findall/3 or bagof/3 or setof/3, then make pairs with the list length as the first element, then sort these pairs and pick the last.
For example:
?- bagof(X, classify(X), Xs),
maplist(length, X, Lengths),
pairs_keys_values(Ps, Lengths, Xs),
keysort(Ps, Sorted),
last(_-Longest, Sorted).
It uses pairs_keys_values/3 and last/2 as defined in the SWI-Prolog standard libraries.
This approach will work, even though it has several problems. It is difficult to discuss those without any knowledge of what classify/1 does.
I used at least once a convoluted variant of Boris' answer
?- R=[_-S|_],setof(L-X,T^(classify(X),length(X,T),L is -1*T),R).

Removing heads from lists in Prolog

I'm trying to write a predicate to remove the head from every list in list of lists and add the tails to a new list. The resulting list should be returned as the second parameter.
Here's the attempt:
construct_new(S,New) :-
New = [],
new_situation(S,New).
new_situation([],_).
new_situation([H|T], New) :-
chop(H, H1),
new_situation(T, [H1|New]).
chop([_|T], T).
You would call it like this:
construct_new([[x,x],[b,c],[d,e,f]],S).
This, however, only produces output true..
Step-by-step execution
Your query is construct_new(Input,Output), for some instanciated Input list.
The first statement in construct_new/2 unifies Output (a.k.a. New) with the empty list. Where is the returned list supposed to be available for the caller? Both arguments are now unified.
You call new_situation(Input,[])
You match the second clause new_situation([H|T],[]), which performs its task recursively (step 4, ...), until ...
You reach new_situation([],_), which successfully discards the intermediate list you built.
Solutions
Write a simple recursive predicate:
new_situation([],[]).
new_situation([[_|L]|T],[L|R]) :-
new_situation(T,R).
Use maplist:
construct_new(S,R) :-
maplist(chop,S,R).
Remark
As pointed out by other answers and comments, your predicates are badly named. construct_new is not a relation, but an action, and could be used to represent almost anything. I tend to like chop because it clearly conveys the act of beheading, but this is not an appropriate name for a relation. repeat's list_head_tail(L,H,T) is declarative and associates variables to their roles. When using maplist, the other predicate (new_situation) doesn't even need to exist...
...even though guillotine/3 is tempting.
This could be done with a DCG:
owth(Lists, Tails) :-
phrase(tails(Tails), Lists).
tails([]) --> [].
tails([T|Tails]) --> [[_|T]], tails(Tails).
Yielding these queries:
| ?- owth([[x,x],[b,c],[d,e,f]], T).
T = [[x],[c],[e,f]] ? ;
no
| ?- owth(L, [[x],[c],[e,f]]).
L = [[_,x],[_,c],[_,e,f]]
yes
(owth = Off with their heads! or, if used the other direction, On with their heads!)
If you also want to capture the heads, you can enhance it as follows:
owth(Lists, Heads, Tails) :-
phrase(tails(Heads, Tails), Lists).
tails([], []) --> [].
tails([H|Hs], [T|Tails]) --> [[H|T]], tails(Hs, Tails).
We use meta-predicate maplist/[3-4] with one of these following auxiliary predicates:
list_tail([_|Xs],Xs).
list_head_tail([X|Xs],X,Xs).
Let's run some queries!
?- maplist(list_head_tail,[[x,x],[b,c],[d,e,f]],Heads,Tails).
Heads = [x,b,d],
Tails = [[x],[c],[e,f]].
If you are only interested in the tails, use maplist/4 together with list_head_tail/3 ...
?- maplist(list_head_tail,[[x,x],[b,c],[d,e,f]],_,Tails).
Tails = [[x],[c],[e,f]].
... or, even simpler, maplist/3 in tandem with list_tail/2:
?- maplist(list_tail,[[x,x],[b,c],[d,e,f]],Tails).
Tails = [[x],[c],[e,f]].
You can also use the somewhat ugly one-liner with findall/3:
?- L = [[x,x],[b,c],[d,e,f]],
findall(T, ( member(M, L), append([_], T, M) ), R).
R = [[x], [c], [e, f]].
(OK, technically a two-liner. Either way, you don't even need to define a helper predicate.)
But definitely prefer the maplist solution that uses chop as shown above.
If you do the maplist expansion by hand, and name your chop/2 a bit better, you would get:
lists_tails([], []).
lists_tails([X|Xs], [T|Ts]) :-
list_tail(X, T),
lists_tails(Xs, Ts).
And since you can do unification in the head of the predicate, you can transform this to:
lists_tails([], []).
lists_tails([[_|T]|Xs], [T|Ts]) :-
lists_tails(Xs, Ts).
But this is identical to what you have in the other answer.
Exercise: why can't we say:
?- maplist(append([_]), R, [[x,x],[b,c],[d,e,f]]).