Using Prolog to process a list - list

I have a problem in Prolog.
Consider a list where each element is referring to a position/location in the same list.
I want to write a program which returns true if I start with the same location that I end in. For example:
If I give it find-s([3,2,0,1],0)
It starts with 0 index which contains 3
then goes to the 3 index which contains 1
then the 1 index to find 2
finally to index 2 which contains 0 !
so it returns true in this case
I tried this but it didn't work
position([Head1| Tail1], Var1) :-
( Head1 == Var1,
Tail1 == Var1 ->
true
).

this should work
find_s(L, S) :- nth0(S, L, I), find_s(L, I, S).
find_s(_, S, S).
find_s(L, I, S) :- nth0(I, L, J), find_s(L, J, S).
but I think it could easily loop. So, instead of nth0/3, let's use nth0/4, after this consideration:
?- nth0(2,[a,b,c,d],X,Y).
X = c,
Y = [a, b, d].
?- nth0(2,L,$X,$Y).
L = [a, b, c, d].
for sake of readability, let's introduce a replace_nth0/4
replace_nth0(P, L, E, LrepE) :-
nth0(P, L, E, L_Without_E),
nth0(P, LrepE, -1, L_Without_E).
and then
find_s(L, S) :- nth0(S, L, I), find_s(L, I, S).
find_s(_, S, S).
find_s(L, I, S) :- I >= 0, replace_nth0(I, L, J, L_rep), find_s(L_rep, J, S).

Related

Splitting a list into two sublists with one having a predefined length

I'm new to Prolog and I have this code. I would like it to split a list into two lists or sublists where the first sublist/ list is of a predefined length and the other one contains the rest of the elements. Here's the code.
`
list_length([],0).
list_length([_|T],N):- list_length(T, N1), N is N1 + 1.
div(L, A, B, N) :-
append(A, B, L),
length(A, N),
length(B, N).
div(L, A, B, N) :-
append(A, B, L),
length(A, N),
N1 is N + 1,
length(B, N1).
div(L, A, B, N) :-
append(A, B, L),
length(A, N),
N1 is N - 1,
length(B, N1).
``
When I run my above code, it returns an error saying:
ERROR: Unknown procedure: (div)/4
ERROR: However, there are definitions for:
ERROR: (div)/3
false.
I would like the input to be this:
`?- div([44,55,23,86,49,94,30,77], L1, L2, 6).
L1 = [44,55,23,86,49,94]
L2 = [30,77]
Help me understand what I am doing wrong.
Help me understand what I am doing wrong.
You should be using length/2 and append/3, one after the other, like this:
div(L, A, B, N) :-
append(A, B, L),
length(A, N).
This is all.
Do not define your own length/2.
But you have not shown how you compile and evaluate your code. For example, I get:
?- [user].
|: div(L, A, B, N) :- append(A, B, L), length(A, N).
|: ^D% user://1 compiled 0.01 sec, 1 clauses
true.
?- div([a,b,c,d], A, B, 2).
A = [a, b],
B = [c, d] ;
false.
?- div([a,b,c,d], [X,Y], B, N).
X = a,
Y = b,
B = [c, d],
N = 2.
?- div([a,b,c,d], A, [X,Y,Z], N).
A = [a],
X = b,
Y = c,
Z = d,
N = 1 ;
false.
?- div([a,b], A, B, N).
A = [],
B = [a, b],
N = 0 ;
A = [a],
B = [b],
N = 1 ;
A = [a, b],
B = [],
N = 2 ;
false.
?- div(L, A, B, N).
L = B,
A = [],
N = 0 ;
L = [_A|B],
A = [_A],
N = 1 ;
L = [_A, _B|B],
A = [_A, _B],
N = 2 .
Since I made that mistake already, it is worth asking: Can you switch the order of append and length in the definition? What happens if you do?

Prolog - identify sublists of variables

I have an assignment in which I must accomplish the following - given a list such as:
List = [_, _, $, _, _, _, _, $, _, $].
I have to write a predicate pred/2 with pred(List, Sub) such that it is true if and only if Sub is a sublist of size >= 2 with no adjacent variables in which none of the members is a $. Examples:
List = [X, Y, $, P, Q, R, S, $, A, $], pred(List, [X, Y]) should succeed.
List = [X, Y, $, P, Q, R, S, $, A, $], pred(List, [P, Q, R]) should not succeed because S is adjacent to P, Q, R.
List = [X, Y, $, P, Q, R, S, $, A, $], pred(List, [P, Q, R, S]) should succeed.
List = [X, Y, $, P, Q, R, S, $, A, $], pred(List, [A, $]) should not succeed because it includes a $.
I have written the following code, which according to a bit of testing does that I want:
pred(List, Sub) :- pred(List, Sub, []).
pred([], Sub, Sub) :- length(Sub, Len),
Len >= 2.
pred([H|T], Sub, Aux) :- H \== $, !,
append(Aux, [H], New),
pred(T, Sub, New).
pred([$|_], Sub, Sub):- length(Sub, Len), Len >= 2.
pred([$|T], Sub, _) :- pred(T, Sub, []).
However, I feel like this solution is janky. While I am aware StackOverflow is, in general, for things that people can't do, I really feel like I've come up with a rather complicated solution to a simple problem and would like to know of a better way to accomplish what I want.
Thank you in advance!
append/2 is an handy predicate from library(lists). It allows an easier implementation of the requirements:
pred(L, S) :-
append([X, S, Y], L),
length(S, C), C >= 2,
maplist(\==($), S),
( X = [] ; last(X, X_), X_ == $ ),
( Y = [] ; Y = [Y_|_], Y_ == $ ).

how to make a list of lists with a certain width

i want to implement a function that make a list of sublists with a certain width. For example :
?- list_to_llists([w,w,w,w],2,LL). %1
LL = [[w, w], [w, w]] ;
false.
?- list_to_llists([w,w,c,l,r,w,c,c,w,w,w,w],3,LL). %2
LL = [[w, w, c], [l, r, w], [c, c, w], [w, w, w]] ;
false.
?- list_to_llists([w,w,w,w],3,LL). %3
LL = [[w, w, w]] ;
false.
sublist(I1,I2,L,Sub) :-
sublist2(I1,I2,L,[],Sub).
sublist2(I1,I2,L,Sub,Sub):-
length(Sub,N),
N\=0,
I1>I2.
sublist2(I1,I2,L,Sub,Sub2):-
I1<I2,
nth0(I1,L,X),
I3 is I1+1,
append(Sub,[X],Z),
sublist2(I3,I2,L,Z,Sub2).
sublist2(A,B,L,Sub,Sub2):-
B=A,
nth0(A,L,X),
NewA is A+1,
append(Sub,[X],Z),
sublist2(NewA,B,L,Z,Sub2).
list_to_llists(L,W,LLists):-
length(L,X),
X=<W,
LLists=[L].
list_to_llists2([],W,LLists,A):- LLists=A .
list_to_llists2(L,W,LLists,A):-
P is W-1 ,
sublist(0,P,L,Result),
append([Result],A,U),
append(Result,K,L),
list_to_llists2(K,W,LLists,U).
list_to_llists(L,W,F):-
list_to_llists2(L,W,R,[[]]).
but case 2 and 3 don't work at all
secondly, i want to implement a function that takes certain facts and put them in L where L is a list but i have to use list_to_lists to make L kind of list of lists list (it's a map)
for example (test cases):
?- length(L,100),ensure_hints(L, [at(3, 5, c), at(5, 0, w), at(9, 6, c)],10,10).
L = [_G1699, _G1702, _G1705, _G1708, _G1711, w, _G1717, _G1720, _G1723, _G1726,
_G1729, _G1732, _G1735, _G1738, _G1741, _G1744, _G1747, _G1750, _G1753, _G1756,
_G1759, _G1762, _G1765, _G1768, _G1771, _G1774, _G1777, _G1780, _G1783, _G1786,
_G1789, _G1792, _G1795, _G1798, _G1801, _G1804, _G1807, _G1810, _G1813, _G1816,
_G1819, _G1822, _G1825, _G1828, _G1831, _G1834, _G1837, _G1840, _G1843, _G1846,
_G1849, _G1852, _G1855, c, _G1861, _G1864, _G1867, _G1870, _G1873, _G1876,
_G1879,_G1882, _G1885, _G1888, _G1891, _G1894, _G1897, _G1900, _G1903, c,
_G1909, _G1912,_G1915, _G1918, _G1921, _G1924, _G1927, _G1930, _G1933, _G1936,
_G1939, _G1942, _G1945, _G1948, _G1951, _G1954, _G1957, _G1960, _G1963, _G1966,
_G1969,_G1972, _G1975, _G1978, _G1981, _G1984, _G1987, _G1990, _G1993, _G1996];
false
?- length(L,9),ensure_hints(L, [at(1, 2, c), at(0, 1, l)],3,3).
L = [_G1589, _G1592, _G1595, l, _G1601, _G1604, _G1607, c, _G1613] ;
false.
?- length(L,9),ensure_hints(L, [at(1, 2, c), at(0, 5, l)],3,3).
false.
but it doesn't work for me
my code :
ensure_hints(L,Hints,W,H):-
list_to_llists(L,W,C),
Hints=[H|T],
H=at(X,Y,O),
nth0(X,L,Z),
nth0(Y,Z,O),
ensure_hints(L,T,W,H).
Here is a simple solution:
list_to_llists(List, Len, [H|T]) :-
length(H, Len),
append(H, Rest, List),
!,
list_to_llists(Rest, Len, T).
list_to_llists(_, _, []).
It simple removes sublists of length Len until there is no complete sublist left (it seems you want to ignore incomplete sublists).
You can play with it on http://swish.swi-prolog.org/p/OqfzwRoe.pl

minimum in list of lists in prolog

hello i have a list like this:
[[3,[a,b,c,d]],[2,[a,b,d]],[5,[d,e,f]]]
list of lists...
i want to find the minimum number on inner list
in this case i want to return D=2 and L=[a,b,d]
i tried this code:
minway([[N|L]],N,L).
minway([[M|L1]|L2],D,_):- M<D, minway(L2,M,L1).
minway([[M|_]|L2],D,L):- M>=D, minway(L2,D,L).
but i got error:
</2: Arguments are not sufficiently instantiated
Exception: (8) minway([[3,[a,b,c,d]],[2,[a,b,d]],[5,[d,e,f]]], _G7777, _G7778) ?
creep
for this run sentence:
minway([[3,[a,b,c,d]],[2,[a,b,d]],[5,[d,e,f]]],D,L).
the result need to be:
D=2.
L=[a,b,d].
where my problem?
and how to fix it?
tnx a lot
First, switch to a better data representation: Instead of [Key,Value], use Key-Value!
Then, define minway_/3 based on
iwhen/2,
ground/1,
keysort/2, and
member/2, like so:
minway_(Lss, N, Ls) :-
iwhen(ground(Lss), (keysort(Lss,Ess), Ess = [N-_|_], member(N-Ls, Ess))).
Sample query using SICStus Prolog 4.5.0:
| ?- minway_([3-[a,b,c,d],2-[a,b,d],5-[d,e,f],2-[x,t,y]], N, Ls).
N = 2, Ls = [a,b,d] ? ;
N = 2, Ls = [x,t,y] ? ;
no
There are a couple of fundamental issues.
One is in your problem lies in your representation of a list. Your predicates seem to assume that, for example, [3, [a,b,c]] is represented as [3 | [a,b,c]] but it is not. The list [3 | [a,b,c]] is the list with 3 as the head, and [a,b,c] as the rest of the list or the tail. In other words, [3 | [a,b,c]] is [3, a, b, c].
And, so, your base case would be:
minway([[N,L]], N, L).
The second issue is in your other predicate clauses. There's no starting point for D. In other words, it's never given a value to start with, so you get an instantiation error. You cannot compare N > D if one of the variables doesn't have a value.
When doing a minimum or maximum from scratch, a common approach is to start by assuming the first element is the candidate result, and then replace it if you find a better one on each step of the recursion. It also means you need to carry with you the last candidate at each recursive call, so that adds extra arguments:
minway([[N,L]|T], D, R) :-
minway(T, N, L, D, R).
minway([], D, R, D, R). % At the end, so D, R is the answer
minway([[N,L]|T], Dm, Rm, D, R) :-
( N < Dm
-> minway(T, N, L, D, R) % N, L are new candidates if N < Dm
; minway(T, N, Dm, Rm, D, R) % Dm, Rm are still best candidate
).
In Prolog, you can simplify this a little since Prolog has a more general term comparison operator, #<, #>, etc, which is smart about comparing more complex terms. For example, [2, [d,e,f]] #< [3, [a,b,c]] is true since 2 < 3 is true. We can then write:
minway([H|T], D, R) :-
minway(T, H, D, R).
minway([], [D, R], D, R).
minway([H|T], M, D, R) :-
( H #< M
-> minway(T, H, D, R)
; minway(T, M, D, R)
).
You can do this by using the minimum predicate. Findall can be very helpful.
min([X],X).
min([H|T],Min):-
min(T,TMin),
H>TMin,
Min is TMin.
min([H|T],Min):-
min(T,TMin),
H=<TMin,
Min is H.
minway(List,D,L):-
findall(Value,member([Value,_],List),VList),
min(VList,Min),
D=Min,
findall(EList,member([Min,EList],List),L).
?-minway([[3,[a,b,c,d]],[2,[a,b,d]],[5,[d,e,f]]],D,L).
D = 2,
L = [[a, b, d]]
Try library(aggregate):
?- aggregate_all(min(X,Y),
member([X,Y], [[3,[a,b,c,d]],
[2,[a,b,d]],
[5,[d,e,f]]]),
min(D,L)).
D = 2,
L = [a, b, d].
See also here:
Aggregation operators on backtrackable predicates
https://www.swi-prolog.org/pldoc/man?section=aggregate

Prolog - Filter List

So I have this homework due tommorow. I have to filter every nth element of a list and return it as a list. So for example:
?- everyNth(3,[a,b,c,d,e,f],Rs).
Rs = [c,f].
My Idea was basically:
everynth(N, [X|Xs], L) :- everynth(N, [X|Xs], N, L).
everynth(N, [], C, L).
everynth(N, [X|Xs], 0, [X]) :- everynth(N, Xs, N, [X]).
everynth(N, [X|Xs], C, L) :- C1 is C -1,
everynth(N,Xs,C1,L).
But it does not work this way, because in the third row it tries to match X and the return X and the Count 0 the second time it goes there.
You are almost there. Check these modifications:
everynth(N, L, NL) :- everynth(N, L, N, NL).
everynth(_, [], _, []).
everynth(N, [X|Xs], 1, [X|NXs]) :- everynth(N, Xs, N, NXs).
everynth(N, [_|Xs], C, NXs) :- C1 is C-1, C1>0,
everynth(N,Xs,C1,NXs).
The first clause of everynth/4 is the termination of the recursion. It should give an empty list when there are no more items in the input list.
The second clause of everynth/4 deals with the nth item, it has to put the input item in the output list and keep processing the remaining items restarting your item counter.
And the third clause of everynth/4 deals with items which are not the nth element, so you have to skip the item, decrement the counter and continue with the remaining items.
everynth(_, _, [], R, R).
everynth(1, M, [X|Xs], Z, R) :- append(Z, [X], Z1), everynth(M, M, Xs, Z1, R).
everynth(N, M, [_|Xs], Z, R) :- N > 1, N1 is N - 1, everynth(N1, M, Xs, Z, R).
?- everynth(3, 3, [a,b,c,d,e,f], [], Rs).
Rs = [c, f] .