Prolog: random permutation - random

I'm trying to get random permutation with prolog. But the problem is
?- permutation([1,2,3,4],L).
gives always L = [1, 2, 3, 4] as first answer. I could fix this by using the query
?- L1=[1,2,3,4], permutation(L1,L2), dif(L1,L2).
But this gives me always L2 = [1, 2, 4, 3] as first answer.
How can I get a random permutation in SWI Prolog?

Isn't [1,2,3,4] random enough? Looks random to me!
But I know what you mean - you want a permutation which looks more random.
Why not roll your own? Just pick the next element out of an ever-shrinking "input list".
This is a bit laborious. Maybe there are more elegant ways?
look_random_dammit([],[]) :- !.
% note that [PickedElement|PermutedList] APPENDS "PickedElement"
% to list being constructed. Appending or prepending does not
% really make a difference here though:
look_random_dammit(ListRemainder,[PickedElement|PermutedList]) :-
ListRemainder \== [],
length(ListRemainder,Length),
succ(Max,Length),
% We are now leaving logicland and asking an oracle to give
% use a random number. "Buckle your seatbelt Dorothy, 'cause
% Kansas is going bye-bye!"
random_between(0,Max,PickedIndex),
nth0(PickedIndex,ListRemainder,PickedElement),
length(Prefix,PickedIndex),
% Constructing a remainder list is probably slow
append([Prefix,[PickedElement],Suffix],ListRemainder) ,
append(Prefix,Suffix,ListRemainderNext),
look_random_dammit(ListRemainderNext,PermutedList).
And so:
?- look_random_dammit([1,2,3,4],P).
P = [2,3,1,4] ;
false.
?- look_random_dammit([],P).
P = [] ;
false.
?- look_random_dammit([1,1,1,2,2],P).
P = [2,1,1,2,1] ;
false.
If we also retained the information about which elements was picked in equence, we could write a predicate that "reverses the permutation" because no information was lost while creating it.

You can try:
?- random_permutation([1,2,3,4], P).
P = [2, 1, 4, 3].

I am just giving an alternate method.
Using findall to get all possible permutations.
Getting the length of the List containing the permutations.
Using random to generate a random number between 0 and the length. This will be used as an index value.
Using nth1 to give us a permutation on the given index.
! (Cut) is used to give only one value. if you want more values then remove it.
Example:-
perm([H|T],Permutation):-
findall(A,permutation([H|T],A),List),
length(List,Length),
random(1,Length,Random),
nth1(Random,List,Permutation),!.
?- perm([1,2,3,4],Permutation).
Permutation = [1, 4, 3, 2]
?- perm([1,2,3,4],Permutation).
Permutation = [3, 1, 2, 4]
?- perm([1,2,3,4],Permutation).
Permutation = [3, 1, 4, 2]

Related

Prolog: obtain a list with two sublists, containing the odd position elements and the even position elements. How to Improve this code

I would like to ask, if anyone knows how to improve (if it's not optimal) this code.
The idea, is that you have a list of elements, and I want to return a list, with two sublists inside it, the first sublist should contain the elements that are contained in the odd positions of the list, and the second sublist should contain, the elements that are contained in the even positions of the list.
Some examples:
?-evenAndOdd([1,2,3,4,5],[[1,3,5],[2,4]])
True.
?-evenAndOdd([a,b,c,d,e],[[a,c,e],[b,d]]).
True.
The code I have implemented is the next one:
evenAndOdd([],[]).
evenAndOdd([H|R],NL):-
evenAndOddRec([H|R], [[],[]],1,NL).
evenAndOddRec([], [LOdd,LEven],_,[LOdd,LEven]).
evenAndOddRec([H|R],[LOdd,LEven],Pos,NL):-
\+ even(Pos),
!,
NPos is Pos +1,
append(LOdd,[H],NLOdd),
evenAndOddRec(R,[NLOdd,LEven],NPos,NL).
evenAndOddRec([H|R],[LOdd,LEven],Pos,NL):-
NPos is Pos + 1,
append(LEven, [H], NLEven),
evenAndOddRec(R,[LOdd, NLEven],NPos,NL).
even(N):-
N mod 2 =:=0.
One symptom that the code is not optimal is that it will run off into the woods if you ask for an additional solution in the -,+,+ instantiation pattern:
?- evenAndOdd(X, [[1,3,5], [2,4,6]]).
X = [1, 2, 3, 4, 5, 6] ;
<time passes>
This kind of thing is a frequent occurrence when manually trying to match up lists with indexes in Prolog.
Stylistically, I would rather not give back a list containing exactly two lists when I could just have three arguments instead of two; this is, after all, a relationship between three lists, the combined list and the even and odd items.
Additionally, just eyeballing it, I'm not sure why any arithmetic or any cuts are needed here. This is how I would implement it:
evenAndOdd([], [], []).
evenAndOdd([O], [O], []).
evenAndOdd([O,E|Rest], [O|ORest], [E|ERest]) :- evenAndOdd(Rest, ORest, ERest).
This works with many instantiations:
?- evenAndOdd([1,2,3,4,5,6], O, E).
O = [1, 3, 5],
E = [2, 4, 6].
?- evenAndOdd([1,2,3,4,5], O, E).
O = [1, 3, 5],
E = [2, 4] ;
false.
?- evenAndOdd(X, [1,3,5], [2,4]).
X = [1, 2, 3, 4, 5] ;
false.
?- evenAndOdd(X, [1,3,5], [2,4,6]).
X = [1, 2, 3, 4, 5, 6].
?- evenAndOdd(X, [1,3,5], [2,4,6,8]).
false.
?- evenAndOdd([1,2,3,4,5,6], X, [2,4,6,8]).
false.
?- evenAndOdd([1,2,3,4,5,6], X, [2,4,6]).
X = [1, 3, 5].
You can implicitly determine even and odd values upon recursion, by taking two elements at a time (and taking into account when the has an odd number of elements):
evenAndOdd(L, [LOdd, LEven]):-
evenAndOdd(L, LOdd, LEven).
evenAndOdd([], [], []).
evenAndOdd([Odd], [Odd], []).
evenAndOdd([Odd,Even|Tail], [Odd|LOdd], [Even|LEven]):-
evenAndOdd(Tail, LOdd, LEven).

Prolog list of list n number with condition

I'm studying prolog language and i have an issue regarding this problem.
I've already created a program that, given a number N, returns a list with elements between 0 and N:
list2val(N,L):- list2val(0,N,L).
list2val(N,N,[N]).
list2val(C,N,[C|T]):-
C<N,
N1 is C+1,
list2val(N1,N,T).
?- list2val(5,X).
X = [0,1,2,3,4,5]
Now i'm trying to give an extension that, given a list, returns a list of lists in which every list is list2val only if the next number is greater than current number. In this case:
?- newFuction([1,5,2,3,9],L).
L = [[0,1],[0,1,2,],[0,1,2,3]]
My code is this, but somethings is wrong:
array(X):- array(X,_L).
array([],_L).
array([H|[T|Ts]],L1):-
H<T,
list2val(H,L2),
array([T|Ts],[L1|[L2]]).
array([T|Ts],L1).
Maybe could be too much difficult to understand but using a list L = [1,5,2,3,9] i do those steps:
check 1<5 so i create a 1 list2val until 1..in this case [0,1]
check 5<2 i dont create nothing.
check 2<3 i create list2val of 2 ...[0,1,2]
and so on...
I don't want use a standard predicates, by implement with standard terms.
A solution for your problem could be:
list2val(N,L):- list2val(0,N,L).
list2val(N,N,[N]):- !.
list2val(C,N,[C|T]):-
C<N,
N1 is C+1,
list2val(N1,N,T).
simulate([_],[]).
simulate([A,B|T],[H|T1]):-
( A < B ->
list2val(A,H),
simulate([B|T],T1);
simulate([B|T],[H|T1])
).
Using a predicate like simulate/2, you can solve your problem: it compares two numbers of the list and then create a new list in case the condition is satisfied.
?- simulate([1,5,2,3,9],LO).
LO = [[0, 1], [0, 1, 2], [0, 1, 2, 3]]
false

Prolog Permutations

I'm trying to get more into learning prolog as I'll be taking an AI class at school next semester. I've been able to get down the basics down and can do relation based stuff, however, I've been trying to learn permutations and combinatronics and they seem pretty straightforward, but it led me to a question that I can't figure out how to solve. Say I wanted to know the permutations of 1's and 0's with a certain condition that there must be atleast 4 1's in a row.
I have no idea where I would start to try and find a solution for this, but in the end I want the code to do something like this:
?- placeOnesAndZeros(9,X).
% where 9 is the length of the list/array and X is the permutations
[0,0,0,0,0,0,0,0,0]
[1,1,1,1,0,0,0,0,0]
[0,1,1,1,1,0,0,0,0]
[0,0,1,1,1,1,0,0,0]
[0,0,0,1,1,1,1,0,0]
[0,0,0,0,1,1,1,1,0]
[0,0,0,0,0,1,1,1,1]
[1,1,1,1,0,1,1,1,1]
[1,1,1,1,1,0,0,0,0]
[0,1,1,1,1,1,0,0,0]
[0,0,1,1,1,1,1,0,0]
[0,0,0,1,1,1,1,1,0]
[0,0,0,0,1,1,1,1,1]
[1,1,1,1,1,1,0,0,0]
[0,1,1,1,1,1,1,0,0]
[0,0,1,1,1,1,1,1,0]
[0,0,0,1,1,1,1,1,1]
[1,1,1,1,1,1,1,0,0]
[0,1,1,1,1,1,1,1,0]
[0,0,1,1,1,1,1,1,1]
[1,1,1,1,1,1,1,1,0]
[0,1,1,1,1,1,1,1,1]
[1,1,1,1,1,1,1,1,1]
Thank you in advance!
EDIT CODE:
printList([ ]).
printList([H|T]) :- print(H), nl, printList(T).
eval([],_).
eval([H|T],[1,0]):-member(H,[1,0]),eval(T,[1,0]).
placeOnesAndZeros(N, L):-length(L,N), eval(L,[1,0]).
Generate and test it's the name of the basic technique used to search a solution space. In Prolog, it's practically built in. Just provide a filter discarding what is not required:
?- placeOnesAndZeros(9,L),once(append(_,[1,1,1,1|_],L)).
once/1 is required, otherwise append/3 could succeed multiple times.
To check the correctness of the approach, here is how to count how many solutions we get:
?- aggregate(count,L^H^T^(placeOnesAndZeros(9,L),once(append(H,[1,1,1,1|T],L))),C).
C = 111.
The quantification on variables L,H,T (these last 2 being introduced only to aggregate) can be avoided using aggregate_all:
?- aggregate_all(count,(placeOnesAndZeros(9,L),once(append(_,[1,1,1,1|_],L))),C).
C = 111.
edit
As #lurker noted, my filter isn't correct. Try instead
atLeastFourOnes(L) :- memberchk(1,L), atLeastFourOnes_(L).
atLeastFourOnes_([]).
atLeastFourOnes_([0|L]) :- atLeastFourOnes_(L).
atLeastFourOnes_([1,1,1,1|L]) :- stripOnes(L,R), atLeastFourOnes_(R).
that yields
?- placeOnesAndZeros(9,L),atLeastFourOnes(L).
L = [1, 1, 1, 1, 1, 1, 1, 1, 1] ;
L = [1, 1, 1, 1, 1, 1, 1, 1, 0] ;
L = [1, 1, 1, 1, 1, 1, 1, 0, 0] ;
...
?- aggregate(count,L^(placeOnesAndZeros(9,L),atLeastFourOnes(L)),C).
C = 22.

Deep Reverse in PROLOG - Lists

Hey I'm trying to create a predicate for the generating of a deep reverse on nested Lists in PROLOG.
Currently I got this predicate
reverse(L,A) :- rev(L,[], A).
rev([],A,A).
rev([H|L],R,A) :- rev(L,[H|R],A).
The result looks like this:
reverse([1,2,3],A).
A = [3, 2, 1].
reverse([[0,1],2,3],A).
A = [3, 2, [0, 1]].
The problem is, that the inner List is not reversed. It should look like this:
reverse([[0,1],2,3],A).
A = [3, 2, [1, 0]].
reverse([1,2,[3,4,5,[6,7],8],[9,10],11,12],A).
A = [12,11,[10,9],[8,[7,6],5,4,3],2,1].
Thanks for any help.
The way you represent your data is called defaulty, because you need a default case when reasoning over it:
is it a list? &rightarrow; something holds
otherwise &rightarrow; something else holds.
Such a representation is a rich source of troubles. Consider for example my_reverse/2 from the other answer. The main problem with it is that it prematurely and incorrectly commits to one of the cases, although both cases are still possible:
?- my_reverse([X], Ls).
Ls = [X].
But this answer only holds for the case where X is not a list! This problem leads to the following strange behaviour of the predicate:
?- my_reverse([X], Ls), X = [1,2,3].
Ls = [[1, 2, 3]],
X = [1, 2, 3].
This mean that even though X is a list, its elements are not reversed!
You should always aim for cleaner representations to distinguish the cases that can arise.
For example, what would you say about the following way to represent your data:
list(Ls) represents the list Ls
n(N) represents the number N.
With such a representations, we can distinguish the cases symbolically. I leave this as the starting point for a more declarative solution.
To keep things as simple as possible, we could add a test if the current element being checked is a list or not. If it is indeed a list, then its elements should be reversed as well. So in code:
my_reverse(L,R) :- rev(L,[],R).
rev([],A,A).
rev([H|T],A,R) :-
( is_list(H) -> % If H is a list
rev(H,[],X), % then reverse H as well
rev(T,[X|A],R)
;
rev(T,[H|A],R)
).
Also, not that it really matters, just to try and avoid confusion, note how I used A and R for respectively Accumulator and Result. In your code they are currently swapped, which -for me personally- can be a bit confusing, especially when predicates become longer and more complex.
Anyway, let's look at the queries you provided:
?- my_reverse([[0,1],2,3],R).
R = [3, 2, [1, 0]].
?- my_reverse([1,2,[3,4,5,[6,7],8],[9,10],11,12],R).
R = [12, 11, [10, 9], [8, [7, 6], 5, 4, 3], 2, 1].
And some general queries:
?- my_reverse(L,R).
L = R, R = [] ;
L = R, R = [_G2437] ;
L = [_G2437, _G2443],
R = [_G2443, _G2437] ;
L = [_G2437, _G2443, _G2449],
R = [_G2449, _G2443, _G2437] ;
L = [_G2437, _G2443, _G2449, _G2455],
R = [_G2455, _G2449, _G2443, _G2437]
...
?- my_reverse([[X,Y]|T],R), member(a,T), length(X,2).
X = [_G2588, _G2591],
T = [a],
R = [a, [Y, [_G2588, _G2591]]]
;
X = [_G2594, _G2597],
T = [a, _G2588],
R = [_G2588, a, [Y, [_G2594, _G2597]]]
;
X = [_G2594, _G2597],
T = [_G2582, a],
R = [a, _G2582, [Y, [_G2594, _G2597]]]
...
Note however that using this predicate, no termination occurs after finding the first answer to the query:
?- my_reverse(X,[X]).
X = [X] ;
...
But since this wasn't a requirement/demand in OP's question, I assumed it to be okay.
EDIT:
Please read #mat's answer as a follow-up to this problem.
an additional solution for your problem is to use cut and the built-in predicate "is_list/1" to check if you treat a simple term or a list in the current call.
here is the code:
deepReverse(List,R):-deepReverseTail(List,[],R).
deepReverseTail([],Acc,Acc).
deepReverseTail([H|T],Acc,R):- % when H is a list
is_list(H), % check if it's a list.
!, % cut the process if not.
deepReverseTail(H,[],Hrev), % reverse this current list
deepReverseTail(T,[Hrev|Acc],R). % continue the general recursion
deepReverseTail([H|T],Acc,R):- deepReverseTail(T,[H|Acc],R). % when H is a simple term
the "cut" in the third line make sure you treat only list in this definition, while treating simple terms will be in the next definitions.
an output example:
7 ?- deepReverse([a,[d,f],[],[[k],g]],R)
R = [[g, [k]], [], [f, d], a].

Return the third to last elements of given list in Prolog

I am new in using Prolog, I want to write a program that compute the third to last element of a given list.
for instance
ThirdLast ([1, 2, 3, 4, 5] , Ans).
will give me:
Ans = [3, 4, 5]
I did this but is not working
len([],0).
len([_|T],N) :- len(T,X), N is X+1.
ThirdLast([ ],0)
ThirdLast([H|L1], X):-(len(L1,N)==2), X is H.
ThirdLast ([H|L1],X):-(len(L1,N)>2),ThirdLast (L1,X).
any ideas?
You can do it with a simple rule that ignores the first two elements:
tail3([_,_|T], T).
The first two elements get unified with _, and get thrown away. The rest of the list unifies with T, which is the result that we want to produce.
Demo.

Resources