prolog lists and list manipulation - prolog

i am trying to write a binary predicate to take one list, compute mod 5 for each element and then put it in another list. so far, i have done this,
mod5(X,L):- R = [], modhelper(R,L), write(R).
modhelper(X,L):- memb(E,L), mod2(E,Z), addtolist(Z,X,X), modhelper(X,L).
%Get an element from the list L.
memb(E,[E|_]).
memb(E,[_|V]):- memb(E,V).
%If element is integer, return that integer mod 5 else return as is.
mod2(N,Z):- isInt(N) -> Z is N mod 5 ; Z = N.
%add this modified element to the output list.
addtolist(Y,[],[Y]).
addtolist(Y,[H|T],[H|N]):- addtolist(Y,T,N).
memb,mod2, addtolist work as expected but I'm doing something wrong in modhelper which I'm not able to figure out.
Any help is appreciated.

In SWI-Prolog:
mod5(X, Y) :-
Y is X mod 5.
apply_mod5_to_list(L1, L2) :-
maplist(mod5, L1, L2).
Usage:
?- apply_mod5_to_list([2, 4, 6, 8], L2).
L2 = [2, 4, 1, 3].
?- apply_mod5_to_list([2, 4.1, 6, 8], L2).
ERROR: mod/2: Type error: `integer' expected, found `4.1'
?- apply_mod5_to_list([2, not_number, 6, 8], L2).
ERROR: is/2: Arithmetic: `not_number/0' is not a function
You can easily modify this code if you want a slightly different behavior, e.g. if you want to tolerate non-integers (why do you want that btw?).
In case you cannot use maplist, you can implement it yourself, at least a more specialized version of it, e.g. something like this:
partition_the_list_into_first_and_rest([X | Xs], X, Xs).
% The result on an empty list is an empty list
apply_mod5_to_list([], []).
% If the input list contains at least one member
apply_mod5_to_list(L1, L2) :-
partition_the_list_into_first_and_rest(L1, X, Xs),
call(mod5, X, Y),
partition_the_list_into_first_and_rest(L2, Y, Ys),
apply_mod5_to_list(Xs, Ys).
To this code you can still apply a lot of syntactic simplification, which you should probably do to turn it into an acceptable homework solution...

Related

Prolog decimal number to list of numbers

I am new to this page, but hopefully, I'll get the help that I need. I need to code a program that gives a list of numbers from 0-9 from a given bigger number. I don't know how to explain it better, so I add the example:
numbertolist(Number,List).
?- numbertolist(1456,List).
List = [1,4,5,6].
The main thing, that I can't use number_chars/2, number_codes/2 functions, which would give this result easily, I should implement all the functions.
number_codes(123456,X), maplist(plus(48),Y,X).
gives
Y = [1,2,3,4,5,6]
A solution without calling number_codes/2 is straight
forward, using the accumulator programming pattern:
number_digits(N, L) :-
number_digits(N, [], L).
number_digits(0, L, L) :- !.
number_digits(N, L, R) :-
D is N rem 10,
M is N // 10,
number_digits(M, [D|L], R).
The Prolog program gives:
?- number_digits(1454, X).
X = [1, 4, 5, 4].

Prolog - dividing list into n-elements sections

I have a predict which gets first N elements:
nfirst(N, _, Lnew) :- N =< 0, Lnew = [].
nfirst(_, [], []).
nfirst(N, [X|Y], [X|Y1]) :- N1 is N - 1, nfirst(N1, Y, Y1).
It works:
% nfirst(3,[1,2,3,4,5,6],X).
% X = [1, 2, 3]
I need a predict for divide list like below:
% divide([a,b,c,d,e,f,g,h],[3,2,1,2],X).
% X = [[a,b,c],[d,e],[f],[g,h]]
The best way is using nfirst.
Very similar question to the one I answered here. Again, the trick is to use append/3 plus length/2 to "bite off" a chunk of list, per my comment above:
split_at(N, List, [H|[T]]) :- append(H, T, List), length(H, N).
If you run that, you'll see this:
?- split_at(4, [1,2,3,4,5,6,7,8], X).
X = [[1, 2, 3, 4], [5, 6, 7, 8]] ;
So this is the backbone of your program, and now you just need the usual recursive stuff around it. First, the base case, which says, if I'm out of list, I should be out of split locations, and thus out of result:
divide([], [], []).
Note that explicit base cases like this make your program more correct than something like divide([], _, _) because they will cause you to fail if you get too many split locations for your list size.
Now the recursive case is not difficult, but because split_at/3 puts two things together in a list (probably a bad choice, you could make split_at/4 as an improvement) you have to take them out, and it clouds the logic a bit here while making (IMO) a nicer API on its own.
divide(List, [Split|Splits], [Chunk|Rest]) :-
split_at(Split, List, [Chunk, Remainder]),
divide(Remainder, Splits, Rest).
This should be fairly straightforward: we're just taking a Split location, using it to chop up the List, and repeating the processing on what's left over. It seems to work as you expect:
?- divide([a,b,c,d,e,f,g,h],[3,2,1,2],X).
X = [[a, b, c], [d, e], [f], [g, h]] ;
false.
Hope this helps! Compare to the other answer, it may illuminate things.

Predicate to filter non constants from a list

I'm working on a predicate only_atoms/2(List+, Result-) that I'd like to filter non atoms.
For example :
only_atoms([1, 2, X, h(Y), 'aba'], Result).
should return
Result = [1, 2, 'aba'].
I do not care about the order.
Here is the piece of code I came up with :
only_atoms([], []) :- !.
only_atoms([Head | Tail], [Head | Result]) :-
atom(Head),
!,
only_atoms(Tail, Result).
only_atoms([_ | Tail], Result) :-
only_atoms(Tail, Result).
I thought this was the right kind of reasoning to handle such a problem but seem to be wrong since it yields me [](edit : it actually yields [aba], see precisions below, my bad !) no matter what. I'd appreciate some help !
A first hint: for 1 and 2, atom returns false.
By the way, I was looking for the filter predicate, in the standard library it happens to be called include, it's usually better if you use what the language already provides ;-)
?- include(atom, [1, 2, X, h(Y), 'aba'], Result).
Result = [aba].
or if you wanted just to filter out variables:
?- exclude(var, [1, 2, X, h(Y), 'aba'], Result).
Result = [1, 2, h(Y), aba].
Another by the way, one curious difference between your only_atoms and using include(atom, ...) is that yours will unify variables in the first list with atoms in the second list, whereas the include won't.
?- only_atoms([1, x, 2, Y], [x, y]).
Y = y.
?- include(atom, [1, x, 2, Y], [x, y]).
false.
Those subtleties of Prolog always astonish me (I guess that's because I didn't pay enough attention at the university xD).
You probably need to force the Head not to be an atom on the alternate clause, otherwise it is an option for atoms as well.
This returns Result = ['aba'] for me.
only_atoms([], []).
only_atoms([Head | Tail], [Head | Result]) :- atom(Head), !, only_atoms(Tail, Result).
only_atoms([Head | Tail], Result) :- \+atom(Head), !, only_atoms(Tail, Result).
Alternatively, you could try using findall/3.
atoms_list(List, Result) :- findall(Item, (member(Item, List), atom(Item)), Result).

How to create a list of numbers that add up to a specific number

I need some help writing a predicate in Prolog that, given a number as input, returns a list of lists with numbers that add up to it.
Let's call the predicate addUpList/2, it should work like this:
?- addUpList(3,P).
P = [[1,2], [2,1], [1,1,1]]. % expected result
I'm having so much trouble figuring this out I'm beginning to think it's impossible. Any ideas? Thanks in advance.
Try this:
condense([], Rs, Rs).
condense([X|Xs], Ys, Zs) :-
condense(Xs, [X|Ys], Zs).
condense([X, Y|Xs], Ys, Zs) :-
Z is X + Y,
condense([Z|Xs], Ys, Zs).
condense(Xs, Rs) :-
condense(Xs, [], Rs).
expand(0, []).
expand(N, [1|Ns]) :-
N > 0,
N1 is N - 1,
expand(N1, Ns).
addUpList(N, Zs) :-
expand(N, Xs),
findall(Ys, condense(Xs, Ys), Zs).
Let me know what marks I get. :-)
The rule num_split/2 generates ways of splitting a number into a list, where the first element X is any number between 1 and N and the rest of the list is a split of N-X.
num_split(0, []).
num_split(N, [X | List]) :-
between(1, N, X),
plus(X, Y, N),
num_split(Y, List).
In order to get all such splits, just call findall/3 on num_split/2.
add_up_list(N, Splits) :-
findall(Split, num_split(N, Split), Splits).
Usage example:
?- add_up_list(4, Splits).
Splits =
[[1, 1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 3], [2, 1, 1], [2, 2], [3, 1], [4]].
See also the post by #hardmath which gives the same answer with a bit more explanation.
The example given in the Question suggests that compositions (ordered partitions) of any positive integer N &leq; 10 are wanted. Note however that the solution [3] for N=3 seems to have been omitted/overlooked. The number of compositions of N is 2^(N-1), so N=10 gives a long list but not an unmanageable one.
It is also desired to collect all such solutions into a list, something that findall/3 can do generically after we write a predicate composition/2 that generates them.
The idea is to pick the first summand, anything between 1 and N, subtract it from the total and recurse (stopping with an empty list when the total reaches zero). SWI-Prolog provides a predicate between/3 that can generate those possible first summands, and Amzi! Prolog provides a similar predicate for/4. For the sake of portability we write our own version here.
summand(Low,High,_) :-
Low > High,
!,
fail.
summand(Low,High,Low).
summand(Low,High,Val) :-
Now is Low + 1,
summand(Now,High,Val).
composition(0,[ ]).
composition(N,[H|T]) :-
summand(1,N,H),
M is N - H,
composition(M,T).
Given the above Prolog source code, compiled or interpreted, a list of all solutions can be had in this way:
?- findall(C,composition(3,C),L).
C = H126
L = [[1, 1, 1], [1, 2], [2, 1], [3]]
Of course some arrangement of such a list of solutions or the omission of the singleton list might be required for your specific application, but this isn't clear as the Question is currently worded.
There are plenty of great answers to this question already, but here is another solution to this problem for you to consider. This program differs from the others in that it is very efficient, and generates non-redundant solutions of lists which are assumed to represent sets of integers which add up to the specified number.
gen(N, L) :-
gen(N-1, N, N, FL),
dup_n(FL, L).
gen(C-F, M, M, [C-F]).
gen(C-F, S, M, [C-F|R]) :-
S < M, C > 1,
C0 is C - 1,
F0 is floor(M / C0),
S0 is S + (C0 * F0),
gen(C0-F0, S0, M, R).
gen(C-F, S, M, R) :-
F > 0,
F0 is F - 1,
S0 is S - C,
gen(C-F0, S0, M, R).
dup_n([], []).
dup_n([_-0|R], L) :-
!, dup_n(R, L).
dup_n([V-F|R], [V|L]) :-
F0 is F - 1,
dup_n([V-F0|R], L).
Your implementation of addUpList/2 can be achieved by:
addUpList(N, P) :-
findall(L, gen(N, L), P).
Which should give you the following behaviour:
?- addUpList(4,L).
L = [[4], [3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]].
Note that the list containing one 2 and two 1s only appears once in this result set; this is because gen/4 computes unique sets of integers which add up to the specified number.
This answer is somewhere between
#Kaarel's answer and
#sharky's "efficient" answer.
Like #sharky's code, we impose an ordering relation between adjacent list items to restrict the size of the solution space---knowing how to inflate it if we ever need to. So the solution sets of break_down/2 and gen/2 by #sharky are equal (disregarding list reversal).
And as for performance, consider:
?- time((break_down(40,_),false)).
% 861,232 inferences, 0.066 CPU in 0.066 seconds (100% CPU, 13127147 Lips)
false.
?- time((gen(40,_),false)).
% 8,580,839 inferences, 0.842 CPU in 0.842 seconds (100% CPU, 10185807 Lips)
false.

prolog program for determining whether any two pairs in a list have the same sum

How can I write a relation in prolog that determines if there are any two pairs in a list with the same sum. The relation should fail if there exist no pairs whose sums are equal. The relation should also fail if the list contains less than four elements.
list([1 2 3]) fails since it only has 3 elements
list([2 3 4 1]) succeeds since 2+3=4+1
list([3 1 2 4 5 6]) succeds since 5+1=2+4
list([1 8 20 100]) fails since there are no pairs with equal sums
How about this algorithm: take any two pairs of numbers, and see if they match. Here is the code for it:
has_equal_sums(List) :-
select(A, List, List2),
select(B, List2, List3),
select(C, List3, List4),
select(D, List4, _),
A+B =:= C+D.
If you want to make sure it works, or for debug purpose, you can display the two selected pairs as an output:
has_equal_sums(List, [[A, B], [C, D]]) :-
select(A, List, List2),
select(B, List2, List3),
select(C, List3, List4),
select(D, List4, _),
A+B =:= C+D.
Here are a few examples of usage:
?- has_equal_sums([1, 2, 3, 6, 5], X).
X = [[1,6],[2,5]] ? ;
X = [[2,6],[3,5]] ?
?- has_equal_sums([1, 2, 3, 5], X).
no
?- has_equal_sums([1, 2, 3], X).
no
So I checked with my professor and since our deadline has passed, he is OK with me posting my solution to this problem. This is probably not the most succinct way to solve the problem, and I'm leaning on my Scheme a bit, but it appears to work:
%car operations
car([],null).
car([X|_],X).
cadr([_|L],R) :-
car(L,R).
caddr([_|L],R) :-
cadr(L,R).
%cdr operations
cdr([],[]).
cdr([_|L],L).
cddr([_|L],R) :-
cdr(L,R).
cdddr([_|L],R) :-
cddr(L,R).
%two-pair operation
% This algorithm is based on the provided example
% solution for CSC388FA09HW4.
long-enough(L,_) :-
length(L,X),
X>3.
too-long(L,_) :-
length(L,X),
X>4.
two-pair([Head|Tail]) :-
long-enough([Head|Tail],_),
(
(car(Tail,N2),cadr(Tail,N3),caddr(Tail,N4),Head+N2=:=N3+N4);
(cadr(Tail,N2),car(Tail,N3),caddr(Tail,N4),Head+N2=:=N3+N4);
(caddr(Tail,N2),car(Tail,N3),cadr(Tail,N4),Head+N2=:=N3+N4)
);
too-long([Head|Tail],_),
(
two-pair(Tail);
cdr(Tail,N2),two-pair([Head|N2]);
car(Tail,N2),cddr(Tail,N3),two-pair([Head|[N2|N3]]);
car(Tail,N2),cadr(Tail,N3),cdddr(Tail,N4),two-pair([Head|[N2|[N3|N4]]])).

Resources