I am trying to compute arithmetic calculations and store the results in a new list in Prolog.
The function prototype goes as follows:
calculation(List1, ListofLists, ResultList)
for the first argument I provide a list, for the second argument a list of lists and third the result list. I compute the first argument list with each list of list of lists and store the result in the resulting list.
So can somebody tell me how can I store results in the resulting (empty) list?
With library lambda you can write:
:- use_module(library(lambda)).
:- use_module(library(clpfd)).
calculation(L1, L2, Compute, L) :-
maplist([L2,Compute] +\X^Y^call(Compute,L2, X, Y), L1, L).
% my_compute succeeds when R is the list of all the products
% of the numbers component of L with the number V
my_compute(L, V, R) :-
maplist(V +\X^Y^maplist(V +\Z^T^(T #= Z * V), X, Y), L, R).
Here is an example:
?- calculation([1,2,3], [[4,5],[6,7]], my_compute, Zss).
Zss = [[[4, 5], [6, 7]], [[8, 10], [12, 14]], [[12, 15], [18, 21]]].
?- Zss = [[[4,5],[6,7]],[[8,10],[12,14]],[[12,15],[18,21]]],
calculation(Xs, [[4,5],[6,7]], my_compute, Zss).
Xs = [1, 2, 3].
?- Zss = [[[4,5],[6,7]],[[8,10],[12,14]],[[12,15],[18,21]]],
calculation([1,2,3], Xss, my_compute, Zss).
Xss = [[4, 5], [6, 7]].
calculation([], [], []).
calculation([X|Xs], [Y|Ys], [Z|Zs]) :-
calculate(X, Y, Z),
calculation(Xs, Ys, Zs).
which is identical to:
calculation(X, Y, Z) :-
maplist(calculate, X, Y, Z).
either way, you need a predicate calculate/3 that takes a first argument, a list of lists as the second argument, and calculates a result. For example, summing the list in the second argument and multiplying it to the first argument:
calculate(X, Ys, Z) :-
list_sum(Ys, S),
Z is X * S.
If I understood correctly, you want to do some computation on List1 and every member of ListofLists, and get a list of results.
You can do this using findall:
calculation(List1, ListofLists, ResultList) :-
findall(Result, (
member(List2, ListofLists),
your_computation(List1, List2, Result)
), ResultList).
For example, if you replace your_compuation with append, you get:
?- calculation([a,b],[[c,d],[e,f,g],[h]],X).
X = [[a, b, c, d], [a, b, e, f, g], [a, b, h]].
Related
I am trying to create a list as output for a binary tree in prolog here is my code so far.
preorder(node(R, empty, empty),[R]).
preorder(node(R,Lb,Rb),[R|Ys]) :- preorder(Lb, Ys).
preorder(node(R,Lb,Rb),[R|Ys]) :-preorder(Rb, Ys).
My thought being that you traverse the tree and add the R to the rest list Ys.
it doesnt work as intendet though
?- preorder(node(1,node(2,empty,empty),node(3,empty,empty)),Z).
Z = [1, 2] ;
Z = [1, 3] ;
false.
This is the query I try to run and what I get. Prolog gives me all possible ways to the leafs, but I want just one list with all values in preorder, so basically the 2 lists combined([1,2,3]).
You can use the following code:
preorder(T, L) :-
preorder(T, [], L).
preorder(empty, L, L).
preorder(node(R, Lb, Rb), L0, [R|L2]) :-
preorder(Rb, L0, L1),
preorder(Lb, L1, L2).
Examples:
?- preorder(node(1,node(2,empty,empty),node(3,empty,empty)), L).
L = [1, 2, 3].
?- preorder(empty, L).
L = [].
?- preorder(node(1, empty, empty), L).
L = [1].
?- preorder(node(1,node(2,node(3,empty,empty),node(4,empty,empty)),node(5,empty,empty)), L).
L = [1, 2, 3, 4, 5].
The following Prolog program defines a predicate sorted/2 for sorting by permutation (permutation sort) in ascending order a list passed in first argument, which results in the list passed in second argument:
sorted(X, Y) :-
permuted(X, Y),
ordered(Y).
permuted([], []).
permuted(U, [V|W]) :-
permuted(X, W),
deleted(V, U, X).
deleted(X, [X|Y], Y).
deleted(U, [V|W], [V|X]) :-
deleted(U, W, X).
ordered([]).
ordered([_]).
ordered([X, Y|Z]) :-
ordered([Y|Z]), X =< Y.
How to solve the following issues?
The program duplicates solutions for queries in which a list with duplicate elements is passed in second argument:
?- sorted(X, [1, 1, 2]).
X = [1, 1, 2]
; X = [1, 1, 2]
; X = [1, 2, 1]
; X = [1, 2, 1]
; X = [2, 1, 1]
; X = [2, 1, 1]
; false.
The program exhausts resources for queries in which a free variable is passed in second argument:
?- sorted([2, 1, 1], Y).
Y = [1, 1, 2]
; Y = [1, 1, 2]
;
Time limit exceeded
The Prolog program is based on the Horn clause program given at section 11 of Robert Kowalski’s famous paper Predicate Logic as Programming Language:
To solve non-termination, you can add same_length/2 to sorted/2 as #false suggested:
sorted(X, Y) :-
same_length(X, Y),
permuted(X, Y),
ordered(Y).
same_length([], []).
same_length([_|Xs], [_|Ys]) :-
same_length(Xs, Ys).
Or you may embed it into permuted/2 by adding a new argument:
sorted(X, Y) :-
permuted(X, X, Y),
ordered(Y).
permuted([], [], []).
permuted(U, [_|L1], [V|W]) :-
permuted(X, L1, W),
deleted(V, U, X).
The program will still return duplicates as it only sees one item at a time.
To solve duplication, you can either generate all permutations and discard the repeated ones (which is not efficient), or only generate distinct permutations. The following modification does the latter by taking the idea of the recursive procedure permuted/2 + deleted/2 which for each item puts it at the beginning of the list and does a recursive call on the remaining list, and changes it to another recursive procedure permuted_all/2 + deleted_all/2 which for each group of same items puts them at the beginning of the list and does a recursive call on the remaining list. This program uses difference lists for better efficiency:
sorted(X, Y) :-
same_length(X, Y),
permuted_all(X, Y),
ordered(Y).
permuted_all([], []).
permuted_all(U, [V|W]) :-
deleted_all(V, U, X, n-T, [V|W]),
permuted_all(X, T).
% deleted_all(Item, List, Remainder, n-T, Items|T)
deleted_all(_, [], [], y-[X|Xs], [X|Xs]).
deleted_all(X, [V|Y], [V|Y1], y-[X|Xs], Xs1) :-
dif(X, V),
deleted_all(X, Y, Y1, y-[X|Xs], Xs1).
deleted_all(X, [X|Y], Y1, _-Xs, Xs1) :-
deleted_all(X, Y, Y1, y-[X|Xs], Xs1).
deleted_all(U, [V|W], [V|X], n-T, Xs) :-
dif(U, V),
deleted_all(U, W, X, n-T, Xs).
Sample runs:
?- sorted(X, [1, 1, 2]).
X = [1, 2, 1]
; X = [1, 1, 2]
; X = [2, 1, 1]
; false.
?- sorted([2, 1, 1], Y).
Y = [1, 1, 2]
; false.
As per OPs comment asking for a version which does not use difference lists, here goes one which instead obtains the remainder using same_length/2 + append/3 and with added comments:
permuted_all([], []).
permuted_all(U, [V|W]) :-
deleted_all(V, U, X, n, [V|W]),
same_length(X, T), % the remaining list X has the same length as T
append(_, T, [V|W]), % T corresponds to the last items of [V|W]
permuted_all(X, T). % T is a permutation of X
% deleted_all(Item, List, Remainder, n, Items|_)
deleted_all(_, [], [], y, _). % base case
deleted_all(X, [V|Y], [V|Y1], y, Xs1) :-
% recursive step when the current item is not the one we are gathering
dif(X, V),
deleted_all(X, Y, Y1, y, Xs1).
deleted_all(X, [X|Y], Y1, _, [X|Xs1]) :-
% recursive step when the current item is the one we are gathering
deleted_all(X, Y, Y1, y, Xs1).
deleted_all(U, [V|W], [V|X], n, Xs) :-
% recursive step when we have not selected yet the item we will be gathering
dif(U, V),
deleted_all(U, W, X, n, Xs).
Your second problem can by solved by replacing first line with
sorted(X, Y) :-
permuted(X, Y),
ordered(Y),
!.
or
sorted(X, Y) :-
permuted(X, Y),
ordered(Y),
length(X, Z),
length(Y, Z).
The first one is not so easy to solve because of the implementation of this algorithm. Both 1st [1, 1, 2] and 2nd [1, 1, 2] are valid permutations since your code that generated permutations generates all permutations not unique permutations.
I am trying to get a set of elements from a list in prolog, such that a query:
get_elems([1, 2, 4, 10], [a, b, c, d, e], X).
yields:
X = [a, b, d]
I would like to implement it without using the built in predicate nth.
I have tried using the following, but it does not work:
minus_one([], []).
minus_one([X|Xs], [Y|Ys]) :- minus_one(Xs, Ys), Y is X-1.
get_elems([], _, []).
get_elems(_, [], []).
get_elems([1|Ns], [A|As], Z) :- get_elems(Ns, As, B), [A|B] = Z.
get_elems(Ns, [_|As], Z) :- minus_one(Ns, Bs), get_elems(Bs, As, Z).
Edit: The list of indices is guaranteed to be ascending, also I want to avoid implementing my own version of nth.
Give this a go:
get_elems(Xs,Ys,Zs) :- get_elems(Xs,1,Ys,Zs).
get_elems(Xs,_,Ys,[]) :- Xs = []; Ys = [].
get_elems([N|Xs],N,[H|Ys],[H|Zs]) :- !, N1 is N + 1, get_elems(Xs,N1,Ys,Zs).
get_elems(Xs,N,[_|Ys],Zs) :- N1 is N + 1, get_elems(Xs,N1,Ys,Zs).
This just keeps counting up and when the head of the second term is equal to the current index it peels off the head and makes it the head of the current output term. If it doesn't match it just discards the head and keeps going.
I want to write a prolog predicate with the following output:
?- all_match([1,2,3,2,3,1,2],L).
L = [[], [1], [1, 2], [2], [2, 3], [3]].
?- all_match([1,1,1,2],L).
L = [[], [1], [1, 1]].
The purpose is to find the sublists that repeat more than once.
So far I found the solution to find all sublists in a list-
subSet(_, []).
subSet(L, [S|T]) :- append(_, L2,L), append([S|T], _, L2).
But I can't figure out how to repeat the search for every element.
Thanks in advance.
This code is a little different from your requirements, in that all_match/2 will omit the empty sequence and fail if there where no repeated subsequences in the input.
repeated(List, Sublist) :-
% For all prefixes, suffixes:
append(Sublist, Tail, List), Sublist \= [],
% For all suffixes of the former suffixes:
append(_, TailTail, Tail),
% Is the head of the latter suffix equal to the head of the input?
append(Sublist, _, TailTail).
repeated([_|List], Sublist) :-
% Strip leading character and continue
repeated(List, Sublist).
all_match(List, Lists) :-
% Aggregate all repeated sequences or fail if there weren't any.
setof(L, repeated(List, L), Lists).
A sketch of the idea of the first clause of repeated/2:
|----------------List------------------| repeated(List, Sublist)
|--Sublist--|------------Tail----------| append(Sublist, Tail, List)
|--Sublist--| |-----TailTail-----| append(_, TailTail, Tail)
|--Sublist--| |--Sublist--| | append(Sublist, _, TailTail)
Result:
?- all_match([1,2,3,2,3,1,2],L).
L = [[1], [1, 2], [2], [2, 3], [3]].
Update to allow overlapping sequences:
repeated([H|List], Sublist) :-
append(Sublist, _, [H|List]), Sublist \= [],
append(_, Tail, List),
append(Sublist, _, Tail).
repeated([_|List], Sublist) :-
repeated(List, Sublist).
I like Kay's answer (+1). Here a variation on thema
all_match(L, M) :-
take(L, M, R),
take(R, M, _).
take(L, [A|B], R) :- % use [A|B] to remove empties
append(_, T, L),
append([A|B], R, T).
yields
?- setof(L,all_match([1,2,3,2,3,1,2],L),R).
R = [[1], [1, 2], [2], [2, 3], [3]].
How do you get the product of a list from left to right?
For example:
?- product([1,2,3,4], P).
P = [1, 2, 6, 24] .
I think one way is to overload the functor and use 3 arguments:
product([H|T], Lst) :- product(T, H, Lst).
I'm not sure where to go from here.
You can use library(lambda) found here : http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/lambda.pl
Quite unreadable :
:- use_module(library(lambda)).
:- use_module(library(clpfd)).
product(L, R) :-
foldl(\X^Y^Z^(Y = []
-> Z = [X, [X]]
; Y = [M, Lst],
T #= X * M,
append(Lst, [T], Lst1),
Z = [T, Lst1]),
L, [], [_, R]).
Thanks to #Mike_Hartl for his advice, the code is much simple :
product([], []).
product([H | T], R) :-
scanl(\X^Y^Z^( Z #= X * Y), T, H, R).
seems like a list copy, just multiplying by last element handled. Let's start from 1 for the leftmost element:
product(L, P) :-
product(L, 1, P).
product([X|Xs], A, [Y|Ys]) :-
Y is X * A,
product(Xs, Y, Ys).
product([], _, []).
if we use library(clpfd):
:- [library(clpfd)].
product([X|Xs], A, [Y|Ys]) :-
Y #= X * A,
product(Xs, Y, Ys).
product([], _, []).
it works (only for integers) 'backward'
?- product(L, [1,2,6,24]).
L = [1, 2, 3, 4].
Probably very dirty solution (I am new to Prolog):
product([ListHead|ListTail], Answer) :-
product_acc(ListTail, [ListHead], Answer).
product_acc([ListHead|ListTail], [AccHead|AccTail], Answer) :-
Product is ListHead * AccHead,
append([Product, AccHead], AccTail, TempList),
product_acc(ListTail, TempList, Answer).
product_acc([], ReversedList, Answer) :-
reverse(ReversedList, Answer).
So basically at the beginning we call another predicate which has
extra "variable" Acc which is accumulator list.
So we take out head (first number) from original list and put it in
to Accumulator list.
Then we always take head (first number) from original list and
multiply it with head (first number) from accumulator list.
Then we have to append our new number which we got by multiplying
with the head from accumulator and later with the tail
Then we call same predicate again until original list becomes empty
and at the end obviously we need to reverse it.
And it seems to work
?- product([1,2,3,4], L).
L = [1, 2, 6, 24].
?- product([5], L).
L = [5].
?- product([5,4,3], L).
L = [5, 20, 60].
Sorry if my explanation is not very clear. Feel free to comment.