I don't know how to stop this from going into a loop - prolog

The question was to create a replace/4 predicate that would replace a certain element (X) from the first list with another element (Y) like x and finally store it into the last argument, a new list. I know there is obviously something wrong with my base case (?), but I can't seem to figure it out. When I trace this code, it starts of normal, but after the first list is empty, it starts adding anonymous variables. Please have mercy, I'm new to Prolog.
replace([], _, _, []).
replace([H|T], X, Y, N):-
H = X,
append(N, [Y], NL),
replace(T, X, Y, NL).
replace([H|T], X, Y, N):-
H \= X,
append(N, [H], NL),
replace(T, X, Y, NL).

A simple more efficient solution without append/3 would be:
replace([], _, _, []).
replace([X|T], X, Y, [Y|T1]):-replace(T, X, Y, T1).
replace([H|T], X, Y, [H|T1]):-dif(X,H), replace(T, X, Y, T1).
Note that it is much better to use predicate dif/2 instead of \= operator (it has more relational behavior: Just test dif(X,Y). and X\=Y. with X,Y unbound variables to see the difference).
Example:
?- replace([2,4,5,7,8,2,3,4],2,12,L).
L = [12, 4, 5, 7, 8, 12, 3, 4] ;
false.
Another solution would be using DCG:
replace([],_,_) -->[].
replace([X|T],X,Y) --> [Y],replace(T,X,Y).
replace([H|T],X,Y) --> [H],{dif(H,X)},replace(T,X,Y).
final_replace(In_L,X,Y,Out_L):- phrase(replace(In_L,X,Y),Out_L).
Example:
?- final_replace([2,4,5,7,8,2,3,4],2,12,L).
L = [12, 4, 5, 7, 8, 12, 3, 4] ;
false.

Related

How to fix this permutation sort?

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.

Can use a head variable as a functor name in a body?

Prolog lets us unify compound terms to variables:
token(1,2,3).
token(4,5,6).
token_term(Term, X, Y, Z) :- Term=token(X, Y, Z).
? token_term(Term, 1,2,3).
T = token(1, 2, 3).
How can we make a more general version for any functor name:
? term(Term, token, 1,2,3).
T = token(1, 2, 3).
It seems the following is not allowed syntax:
term(Term, F, X, Y, Z) :- Term=F(X, Y, Z).
Why do you need this in the first place? In many situations you do not want to construct a compound term, instead, you might want to construct a goal. So instead of
term(Term, F, X, Y, Z) :- Term=F(X, Y, Z).
you may say:
term(call(F,X,Y,Z), F, X, Y, Z).
The resulting term will be callable in precisely that way, the compound term would be called.
?- term(G_0, token, 1, 2, 3).
G_0 = call(token, 1, 2, 3).
There is no difference between this term and token(1, 2, 3) when you just call then,
Thanks #GuyCoder
% Convert F, [X_0, X_1, ....] into a term
% if a match can be made.
% e.g. term(T, tok, [1,2,3]) --> tok(1,2,3) IFF tok(1,2,3)
find_term(Term, F, X) :- Term =.. [F|X], Term.
% Term constructor
term(Term, F, X) :- Term =.. [F|X].
?- assertz(token(4,5,6)).
true.
?- assertz(token(1,2,3)).
true.
?- find_term(T, token, [1,_,_]).
T = token(1, 2, 3).
?- find_term(T, token, [_,_,_]).
T = token(4, 5, 6) ;
T = token(1, 2, 3).

Storing results in a list in Prolog

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]].

Getting the product of a list from left to right

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.

Prolog predicate check divisibility of numbers in a list

example
divisible([L1],X) :-
L1 mod X =:= 0.
query
divisible([4,6,8,7],2).
response
[4,6,8]
Any guidance?
divisible([], _, []).
divisible([H|T], X, [H|T1]) :- H mod X =:= 0, divisible(T, X, T1).
divisible([H|T], X, T1) :- H mod X =\= 0, divisible(T, X, T1).
You are going to need a three-argument predicate (input list, value to test for divisibility, and output list). After that, think about the three cases: input list is empty, first element is not divisible by number, and first element is divisible by number. You should be able to write three clauses, one for each of those, and get a correct predicate.
SWI-Prolog has a nice predicate include/3 which you can use like this:
?- include(divides(2), [4, 6, 8, 7], L).
L = [4, 6, 8].
given that you have defined divides/2:
% Succeeds if X divides Y
divides(X, Y) :-
Y mod X =:= 0.
Use meta-predicate tfilter/3 in tandem with the reified test predicate divisor_of_t/3:
?- tfilter(divisor_of_t(2),[4,6,8,7],Zs).
Zs = [4, 6, 8].
Based on clpfd and bool01_truth/2, we can define divisor_of_t/3 as follows:
:- use_module(library(clpfd)).
divisor_of_t(Y,X,Truth) :- X mod Y #= 0 #<==> B, bool01_truth(B,Truth).

Resources