Adding two lists representing numbers in prolog - prolog

The task says: the numbers are represented by lists (e.g. 123 = [1, 2, 3]), write a predicate which adds two such numbers. (e.g. sum([4, 5, 6], [9], [4, 6, 5])).
I have been thinking how to express this recursively but what trips me up is when the sizes of the arrays vary. It seems, that this would be simple if the arrays were reverted, so that HEAD is actually the last element. Because the problem for me is that my sum looks like that that:
[4, 5, 6]
+
[9]
instead of
[4, 5, 6]
+
[9]
What could be the proper way to write such predicate? I need some pointers or reference for help...

Here is my implementation:
sum(L1,L2,OutL):-
reverse(L1,List1),reverse(L2,List2),
add_lists(List1,List2,0,List3),
reverse(List3,OutL).
add_lists([],[],0,[]).
add_lists([],[],1,[1]).
add_lists([],[H|T],C,[H1|T]):-H1 is H+C.
add_lists([H|T],[],C,[H1|T]):-H1 is H+C.
add_lists([H|T],[H1|T1],C,[H2|T2]):-NH is H1+H,
(NH > 10 -> NC is 1,H2 is NH+C-10; H2 is NH+C,NC is 0),
add_lists(T,T1,NC,T2).
The idea is to reverse lists in order to add right positions and avoid the problem you referred. Also you just keep a carry which is 1 if an addition is greater than 10 where you reduce 10.
Example:
?- sum([4, 5, 6], [9], L).
L = [4, 6, 5] ;
false.

Related

What is the most efficient way to split an array of numbers, such that sum of each subset is as close to a target as possible, without exceeding it?

I am faced with this optimization challenge:
Take for example the array, [1, 2, 4, 3, 3, 6, 2, 1, 6, 7, 4, 2]
I want to split this into multiple sub-arrays, such that their sums are as close to a target sum. Say, 7.
The only condition I have is the sums cannot be more that the target sum.
Using a greedy approach, I can split them as
[1, 2, 4], [3, 3, 1], [6], [2, 4], [6], [7], [2]
The subset sums are 7, 7, 6, 6, 6, 7 and 2.
Another approach I tried is as follows:
Sort the array, in reverse.
Set up a running total initialized to 0, and an empty subset.
If the list is empty, proceed to Step 6.
Going down the list, pick the first number, which when added to the running total does not exceed the target sum. If no such element is found, proceed to Step 6, else proceed to Step 5.
Remove this element from the list, add it to the subset, and update running total. Repeat from step 3.
Print the current subset, clear the running total and subset. If the list isn't empty, repeat from Step 3. Else proceed to Step 7.
You're done!
This approach produced the following split:
[7], [6, 1], [6, 1], [4, 3], [4, 3], [2, 2, 2]
The subset sum was much more even: 7, 7, 7, 7, 7 and 6.
Is this the best strategy?
Any help is greatly appreciated!
I think you should use the terms "subset" and "sub-array" carefully. What you are looking for is "subset".
The best strategy here would be to write the recursive solution that tries each possibility of forming a subset so that the sum remains <= maximum allowed sum.
If you carefully understand what the recursion does, you'll understand that some sub-problems are being solved again and again. So, you can (memoize) store the solutions to the sub-problems and re-use them. Thus, reading about dynamic programming will help you.

Prolog doesn't return a value

I have the following code:
pair_list([X,Y],[[X,Y]]).
pair_list([E,Z|X],[K|Y]):- [E,Z]==K, pair_list(X,Y).
When I run it, it gives correct output for
?- pair_list([1, 2, 3, 4, 5, 6], [[1, 2], [3, 4], [5, 6]]).
true ;
but when I run
?- pair_list([1,2, 3, 4, 5, 6], X).
I just get false.
My question is why don't I get X=[[1, 2], [3, 4], [5, 6]]
You are almost there: all you need to do is moving [E,Z] into the head, eliminating K:
pair_list([X,Y],[[X,Y]]).
pair_list([E,Z|X],[[E,Z]|Y]) :- pair_list(X,Y).
Demo 1.
Note that the base clause can be replaced with one based on empty lists:
pair_list([], []).
pair_list([E,Z|X],[[E,Z]|Y]) :- pair_list(X,Y).
Demo 2.
Also note that your program is not going to work with a list that has an odd number of items. In order to fix this, add a separate base clause that handles a list with a single item either by dropping the item, making a pair with some fixed atom, or doing something else that you find useful in this case.

Prolog - sort sublists of a list

I want to sort the sublists of a list which contains integers eliminating the duplicates. Example:
[1, 2, [4, 1, 4], 3, 6, [7, 10, 1, 3, 9], 5, [1, 1, 1], 7]
=>>>
[1, 2, [1, 4], 3, 6, [1, 3, 7, 9, 10], 5, [1], 7].
I know that i have to work with functor s(but i didn't really get it).
Here is my code : (the (insert+sorting) function works in a simple list of integers,but don't work here. i'm getting red false everytime)
insert(E,[],[E]).
insert(E,[H|T],[H|L]):-
E>H,
insert(E,T,L).
insert(E,[H|T],[H|T]):-
E=H,
!.
insert(E,[H|T],[E|[H|T]]):-
E<H,
!.
sort([],[]).
sort([i(H)|T],L):-
sort(T,L1),
insert(i(H),L1,L).
You could try a solution like this, it uses the the sort/2 predicate to sort sublists:
sort_sublists([], []).
sort_sublists([X|Xs], List) :-
(integer(X) ->
List = [X | List1]
;
sort(X, Sorted),
List = [Sorted | List1]
),
sort_sublists(Xs, List1).
Example call:
?- set_prolog_flag(answer_write_options,[max_depth(0)]).
true.
?- sort_sublists([1, 2, [4, 1, 4], 3, 6, [7, 10, 1, 3, 9], 5, [1, 1, 1], 7], X).
X = [1,2,[1,4],3,6,[1,3,7,9,10],5,[1],7].
#Eduard Adrian it's hard to answer in comments, so first thing you need to do is to remove duplicates from the nested lists.
Here i tried that and you can see different cases that you need to handle. One example:(Head of your list can be a list but it's tail will be empty this happends if last element of your list is a list) in that case you need to define another predicate which will match your recursive call.
Once you have removed duplicates you can use simple sorting algorithm but you have to check if the head is a list then you sort innner list first and place it to the same place otherwise call sort predicate.
As you asked how check if an element is_list or integer, for that you can always use built-in because those predicates you can't write by yourself.

How to permute in Prolog the elements of a list composed of sub-list and atoms

Let us consider lists such as L=[[7,3,4],9,[4,5],[1,3,5],4] where components could be lists or atoms. How to produce this type of permutation results:
R = [[7, 3, 4], 9, [4, 5], [1, 3, 5], 4]
R = [[7, 4, 3], 9, [5, 4], [1, 3, 5], 4]
R = [[7, 4, 3], 9, [4, 5], [1, 5, 3], 4]
....
In fact, we would like to have all the possible permutations of the sub-lists of L while the atom should remain unchanged.
I wrote a classical predicate permutation(OriginalList,PermutedList), and an allperm predicate that apply the maplist function to this permutation predicate:
permutation([],[]).
permutation(L,[T|Q]) :-
select(T,L,L1),
permutation(L1,Q).
/*L is the list to permute, R the result*/
allperm(L,R) :-
maplist(permutation,L,R).
It functions only in the special case where L is composed of lists and doesn't function when L is heterogeneous (atoms and lists).
Could you provide hints or elements of solution to do the right permutation?
The following modification should do:
permutation(X,X).
permutation(L,[T|Q]) :-
dif(L,[T|Q]),
select(T,L,L1),
permutation(L1,Q).
allperm(L,R) :-
maplist(permutation,L,R).
We extend the “identity” permutation to any Prolog term (first clause of permutation) and disallow it in the second clause (which can only be applied to lists anyway).

prolog list keeps expanding when semi colon is pressed

Hi I am creating a predicate list from, which if used gives you the numbers between a certain range. So say for instance
list_from(1,5,X).
would give you
X=[1,2,3,4,5].
However I got my predicate to work, but the list just keeps expanding, so it keeps increasing my one and I do not want it to. This is what is happening.
?- list_from(1,7,X).
X = [1, 2, 3, 4, 5, 6, 7] ;
X = [1, 2, 3, 4, 5, 6, 7, 8] ;
X = [1, 2, 3, 4, 5, 6, 7, 8, 9] ;
X = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
X = [1, 2, 3, 4, 5, 6, 7, 8, 9|...]
How do I get this to stop?
Here is my code
list_from(M,N,[]):- M > N.
list_from(M,N,[M|T]):- Mplusone is M + 1, list_from(Mplusone,N,T).
if I remove Mplusone and just M instead I get an error "Out of global stack"
Your two clauses are not mutually exclusive. You have a "guard" in the first clause saying that M > N, but you don't have the opposite condition, M =< N, in the second clause. If you trace the execution you should get an idea of what happens with your current definition.
You might also try to look at the definition of numlist/3 in SWI-Prolog's library(lists). It takes a different approach: first, make sure that the arguments make sense; then, under the condition that the initial Low is indeed lower than High (and both are integers), generate a list.
Semicolon means that you want Prolog to show you more options (that you are not satisfied with the answer). A full stop '.' will stop Prolog from providing you with alternatives.
You could also invoke list_from/3 using once/1. (Credit to #mat)

Resources