Difference between 2 consecutive elements in Prolog - prolog

So my problem sounds like this: Given a list of integer numbers, generate the list of permutations with the property that the absolute value of the difference between 2 consecutive values from the permutation is <=3.
For example : L=[2,7,5] ==> [[2,5,7], [7,5,2]].
So far I wrote this
domains
list=integer*
lista=list*
predicates
perm(list,list)
permutations(list,lista,integer)
delete(integer,list,list)
diff(list,integer)
clauses
perm([],[]).
perm(Y,[A|X]):-
delete(A,Y,Y1),
perm(Y1,X).
delete(A,[A|X],X).
delete(A,[B|X],[B|Y]):-
delete(A,X,Y).
perm_aux(L,X,3):-
perm(L,X),
diff(X,R),
abs(R)<=3.
diff([],0).
diff(???):-
??????
permutations(L,R,3):-
findall(X,perm_aux(L,X,3),R).
So I'm stuck in the part where I make the difference. I have no idea how to do it for every 2 consecutive elements. Please help me.

I wouldn't have diff return a difference, but rather give it the max difference you want and have it either fail as soon as it hits a difference that is too big, or it succeeds.
So diff(List, Max). And calling it, instead of:
diff(X,R),
abs(R)<=3. % Note that this should be =<
You'd have:
diff(X, 3).
Then your base cases are:
diff([], _). % Empty list always succeeds
diff([_], _). % Single element list always succeeds
And your recursive case would look like:
diff([X,Y|T], Max) :-
abs(X-Y) =< Max,
diff([Y|T], Max).
If you would like diff to provide a maximum absolute difference of consecutive values, you could define it as:
max_diff(X, Max) :-
max_diff(X, 0, Max).
max_diff([], M, M).
max_diff([_], M, M).
max_diff([X,Y|T], MaxSoFar, Max) :-
Diff is abs(X-Y),
( Diff > MaxSoFar
-> max_diff([Y|T], Diff, Max)
; max_diff([Y|T], MaxSoFar, Max)
).

Related

Finding sum of list in prolog shows factors of sum, not final sum result

I am trying to find the sum of a list in Prolog. Below is the total/sum code. It's close to working, however it returns the factors of the sum instead of just the sum. New to Prolog so I am not sure why this is happening.
sum([], 0).
sum([X|Tail],Sum):-
sum(Tail,Temp),
Sum=Temp+X.
Why does this result in the factors of the total being shown instead of the actual total value? The values add up to the correct answer, just not sure why it is displayed like this.
Input/Output:
Total = 0+3000.0+1900.0+1312.5+3000+1900+5000 ?
You're using term unification (=/2) instead of arithmetic evaluation (is/2) in the totalList/2 predicate:
totalList([], 0).
totalList([X|Tail],Total):-
totalList(Tail,Temp),
Total=Temp+X.
Rewrite as:
total_list([], 0).
total_list([X| Tail], Total):-
total_list(Tail, Temp),
Total is Temp + X.
The rename from totalList to total_list follows Prolog coding guidelines for predicate names.
Although not a bug, the performance of your predicate also suffers from not being tail-recursive. I.e. the recursive call in the second clauses is not the last goal in its body. Therefore, it will consume space proportional to the number of elements in the list. You can fix this problem by using an accumulator:
total_list(List, Sum) :-
total_list(List, 0, Sum).
total_list([], Sum, Sum).
total_list([X| Tail], Sum0, Sum):-
Sum1 is Sum0 + X,
total_list(Tail, Sum1, Sum).
This improved definition will run in constant space in most Prolog systems.

How do I find the least multiple of N in a list of numbers using Prolog?

I need to find the least multiple of N in a list of numbers.
leastMultiple/2
leastMultipleOfThree/2,
arg1= list of numbers,arg2= X (X is what we want to find, the least multiple of 3 in a list of numbers).
For example, find the least multiple of 3 in [7,9,15,22]. I have been staring at this for quite some time, and I'm not entirely sure where to begin. If you can simply help me wrap my head around the problem a bit, I'd be very thankful.
An earlier version of my answer was confused by the use of the word "least multiple." You want to find the multiples in the list, and retrieve the smallest. I understand now.
First we must detect a multiple of N. We can do this by dividing and looking at the remainder using the modulo operator, like this:
?- X is 7 mod 3.
X = 1.
?- X is 9 mod 3.
X = 0.
I will define a convenience method for this, is_multiple_of:
% multiple_of(X, N) is true if X is a multiple of N
multiple_of(X, N) :- 0 is X mod N.
Now we can simply say:
?- multiple_of(7, 3).
false.
?- multiple_of(9, 3).
true.
Now there are two ways to proceed. The efficient approach, which could easily be made tail recursive for greater performance, would be to walk the list once with an accumulator to hold the current minimum value. A less code-intensive approach would be to just filter the list down to all multiples and sort it. Let's look at both approaches:
% less code: using setof/3
leastMultipleOfThree(List, Result) :-
setof(X, (member(X, List), multiple_of(X, 3)), [Result|_]).
setof/3 evaluates its second term as many times as possible, each time retrieving the variable in its first term for inclusion in the result, the third term. In order to make the list unique, setof/3 sorts the result, so it happens that the smallest value will wind up in the first position. We're using member(X, List), multiple_of(X, 3) as a very simple generate-test pattern. So it's terse, but it doesn't read very well, and there are costs associated with building lists and sorting that mean it isn't optimal. But it is terse!
% more code: using an accumulator
leastMultipleOfThree(List, Result) :- leastMultipleOfThree(List, null, Result).
% helper
leastMultipleOfThree([], Result, Result) :- Result \= null.
leastMultipleOfThree([X|Xs], C, Result) :-
multiple_of(X, 3)
-> (C = null -> leastMultipleOfThree(Xs, X, Result)
; (Min is min(X, C),
leastMultipleOfThree(Xs, Min, Result)))
; leastMultipleOfThree(Xs, C, Result).
This is quite a bit more code, because there are several cases to be considered. The first rule is the base case where the list is extinguished; I chose null arbitrarily to represent the case where we haven't yet seen a multiple of three. The test on the right side ensures that we fail if the list is empty and we never found a multiple of three.
The second rule actually handles three cases. Normally I would break these out into separate predicates, but there would be a lot of repetition. It would look something like this:
leastMultipleOfThree([X|Xs], null, Result) :-
multiple_of(X, 3),
leastMultipleOfThree(Xs, X, Result).
leastMultipleOfThree([X|Xs], C, Result) :-
multiple_of(X, 3),
C \= null,
Min is min(X, C),
leastMultipleOfThree(Xs, Min, Result).
leastMultipleOfThree([X|Xs], C, Result) :-
\+ multiple_of(X, 3),
leastMultipleOfThree(Xs, C, Result).
This may or may not be more readable (I prefer it) but it certainly performs worse, because each of these rules creates a choice point that if/else conditional expressions within a rule do not. It would be tempting to use cuts to improve that, but you'll certainly wind up in a hellish labyrinth if you try it.
I hope it's fairly self-explanatory at this point. :)

Prolog - sequence in list

We want to build a predicate that gets a list L and a number N and is true if N is the length of the longest sequence of list L.
For example:
?- ls([1,2,2,4,4,4,2,3,2],3).
true.
?- ls([1,2,3,2,3,2,1,7,8],3).
false.
For this I built -
head([X|S],X). % head of the list
ls([H|T],N) :- head(T,X),H=X, NN is N-1 , ls(T,NN) . % if the head equal to his following
ls(_,0) :- !. % get seq in length N
ls([H|T],N) :- head(T,X) , not(H=X) ,ls(T,N). % if the head doesn't equal to his following
The concept is simply - check if the head equal to his following , if so , continue with the tail and decrement the N .
I checked my code and it works well (ignore cases which N = 1) -
ls([1,2,2,4,4,4,2,3,2],3).
true ;
false .
But the true answer isn't finite and there is more answer after that , how could I make it to return finite answer ?
Prolog-wise, you have a few problems. One is that your predicate only works when both arguments are instantiated, which is disappointing to Prolog. Another is your style—head/2 doesn't really add anything over [H|T]. I also think this algorithm is fundamentally flawed. I don't think you can be sure that no sequence of longer length exists in the tail of the list without retaining an unchanged copy of the guessed length. In other words, the second thing #Zakum points out, I don't think there will be a simple solution for it.
This is how I would have approached the problem. First a helper predicate for getting the maximum of two values:
max(X, Y, X) :- X >= Y.
max(X, Y, Y) :- Y > X.
Now most of the work sequence_length/2 does is delegated to a loop, except for the base case of the empty list:
sequence_length([], 0).
sequence_length([X|Xs], Length) :-
once(sequence_length_loop(X, Xs, 1, Length)).
The call to once/1 ensures we only get one answer. This will prevent the predicate from usefully generating lists with sequences while also making the predicate deterministic, which is something you desired. (It has the same effect as a nicely placed cut).
Loop's base case: copy the accumulator to the output parameter:
sequence_length_loop(_, [], Length, Length).
Inductive case #1: we have another copy of the same value. Increment the accumulator and recur.
sequence_length_loop(X, [X|Xs], Acc, Length) :-
succ(Acc, Acc1),
sequence_length_loop(X, Xs, Acc1, Length).
Inductive case #2: we have a different value. Calculate the sequence length of the remainder of the list; if it is larger than our accumulator, use that; otherwise, use the accumulator.
sequence_length_loop(X, [Y|Xs], Acc, Length) :-
X \= Y,
sequence_length([Y|Xs], LengthRemaining),
max(Acc, LengthRemaining, Length).
This is how I would approach this problem. I don't know if it will be useful for you or not, but I hope you can glean something from it.
How about adding a break to the last rule?
head([X|S],X). % head of the list
ls([H|T],N) :- head(T,X),H=X, NN is N-1 , ls(T,NN) . % if the head equal to his following
ls(_,0) :- !. % get seq in length N
ls([H|T],N) :- head(T,X) , not(H=X) ,ls(T,N),!. % if the head doesn't equal to his following
Works for me, though I'm no Prolog expert.
//EDIT: btw. try
14 ?- ls([1,2,2,4,4,4,2,3,2],2).
true ;
false.
Looks false to me, there is no check whether N is the longest sequence. Or did I get the requirements wrong?
Your code is checking if there is in list at least a sequence of elements of specified length. You need more arguments to keep the state of the search while visiting the list:
ls([E|Es], L) :- ls(E, 1, Es, L).
ls(X, N, [Y|Ys], L) :-
( X = Y
-> M is N+1,
ls(X, M, Ys, L)
; ls(Y, 1, Ys, M),
( M > N -> L = M ; L = N )
).
ls(_, N, [], N).

What is the bottleneck in this primes related predicate?

So here it is : I'm trying to calculate the sum of all primes below two millions (for this problem), but my program is very slow. I do know that the algorithm in itself is terribly bad and a brute force one, but it seems way slower than it should to me.
Here I limit the search to 20,000 so that the result isn't waited too long.
I don't think that this predicate is difficult to understand but I'll explain it anyway : I calculate the list of all the primes below 20,000 and then sum them. The sum part is fine, the primes part is really slow.
problem_010(R) :-
p010(3, [], Primes),
sumlist([2|Primes], R).
p010(20001, Primes, Primes) :- !.
p010(Current, Primes, Result) :-
(
prime(Current, Primes)
-> append([Primes, [Current]], NewPrimes)
; NewPrimes = Primes
),
NewCurrent is Current + 2,
p010(NewCurrent, NewPrimes, Result).
prime(_, []) :- !.
prime(N, [Prime|_Primes]) :- 0 is N mod Prime, !, fail.
prime(ToTest, [_|Primes]) :- prime(ToTest, Primes).
I'd like some insight about why it is so slow. Is it a good implementation of the stupid brute force algorithm, or is there some reason that makes Prolog fall?
EDIT : I already found something, by appending new primes instead of letting them in the head of the list, I have primes that occur more often at start so it's ~3 times faster. Still need some insight though :)
First, Prolog does not fail here.
There are very smart ways how to generate prime numbers. But as a cheap start simply accumulate the primes in reversed order! (7.9s -> 2.6s) In this manner the smaller ones are tested sooner. Then, consider to test only against primes up to 141. Larger primes cannot be a factor.
Then, instead of stepping only through numbers not divisible by 2, you might add 3, 5, 7.
There are people writing papers on this "problem". See, for example this paper, although it's a bit of a sophistic discussion what the "genuine" algorithm actually was, 22 centuries ago when the latest release of the abacus was celebrated as Salamis tablets.
Consider using for example a sieve method ("Sieve of Eratosthenes"): First create a list [2,3,4,5,6,....N], using for example numlist/3. The first number in the list is a prime, keep it. Eliminate its multiples from the rest of the list. The next number in the remaining list is again a prime. Again eliminate its multiples. And so on. The list will shrink quite rapidly, and you end up with only primes remaining.
First of all, appending at the end of a list using append/3 is quite slow. If you must, then use difference lists instead. (Personally, I try to avoid append/3 as much as possible)
Secondly, your prime/2 always iterates over the whole list when checking a prime. This is unnecessarily slow. You can instead just check id you can find an integral factor up to the square root of the number you want to check.
problem_010(R) :-
p010(3, 2, R).
p010(2000001, Primes, Primes) :- !.
p010(Current, In, Result) :-
( prime(Current) -> Out is In+Current ; Out=In ),
NewCurrent is Current + 2,
p010(NewCurrent, Out, Result).
prime(2).
prime(3).
prime(X) :-
integer(X),
X > 3,
X mod 2 =\= 0,
\+is_composite(X, 3). % was: has_factor(X, 3)
is_composite(X, F) :- % was: has_factor(X, F)
X mod F =:= 0, !.
is_composite(X, F) :-
F * F < X,
F2 is F + 2,
is_composite(X, F2).
Disclaimer: I found this implementation of prime/1 and has_factor/2 by googling.
This code gives:
?- problem_010(R).
R = 142913828922
Yes (12.87s cpu)
Here is even faster code:
problem_010(R) :-
Max = 2000001,
functor(Bools, [], Max),
Sqrt is integer(floor(sqrt(Max))),
remove_multiples(2, Sqrt, Max, Bools),
compute_sum(2, Max, 0, R, Bools).
% up to square root of Max, remove multiples by setting bool to 0
remove_multiples(I, Sqrt, _, _) :- I > Sqrt, !.
remove_multiples(I, Sqrt, Max, Bools) :-
arg(I, Bools, B),
(
B == 0
->
true % already removed: do nothing
;
J is 2*I, % start at next multiple of I
remove(J, I, Max, Bools)
),
I1 is I+1,
remove_multiples(I1, Sqrt, Max, Bools).
remove(I, _, Max, _) :- I > Max, !.
remove(I, Add, Max, Bools) :-
arg(I, Bools, 0), % remove multiple by setting bool to 0
J is I+Add,
remove(J, Add, Max, Bools).
% sum up places that are not zero
compute_sum(Max, Max, R, R, _) :- !.
compute_sum(I, Max, RI, R, Bools) :-
arg(I, Bools, B),
(B == 0 -> RO = RI ; RO is RI + I ),
I1 is I+1,
compute_sum(I1, Max, RO, R, Bools).
This runs an order of magnitude faster than the code I gave above:
?- problem_010(R).
R = 142913828922
Yes (0.82s cpu)
OK, before the edit the problem was just the algorithm (imho).
As you noticed, it's more efficient to check if the number is divided by the smaller primes first; in a finite set, there are more numbers divisible by 3 than by 32147.
Another algorithm improvement is to stop checking when the primes are greater than the square root of the number.
Now, after your change there are indeed some prolog issues:
you use append/3. append/3 is quite slow since you have to traverse the whole list to place the element at the end.
Instead, you should use difference lists, which makes placing the element at the tail really fast.
Now, what is a difference list? Instead of creating a normal list [1,2,3] you create this one [1,2,3|T]. Notice that we leave the tail uninstantiated. Then, if we want to add one element (or more) at the end of the list we can simply say T=[4|NT]. awesome?
The following solution (accumulate primes in reverse order, stop when prime>sqrt(N), difference lists to append) takes 0.063 for 20k primes and 17sec for 2m primes while your original code took 3.7sec for 20k and the append/3 version 1.3sec.
problem_010(R) :-
p010(3, Primes, Primes),
sumlist([2|Primes], R).
p010(2000001, _Primes,[]) :- !. %checking for primes till 2mil
p010(Current, Primes,PrimesTail) :-
R is sqrt(Current),
(
prime(R,Current, Primes)
-> PrimesTail = [Current|NewPrimesTail]
; NewPrimesTail = PrimesTail
),
NewCurrent is Current + 2,
p010(NewCurrent, Primes,NewPrimesTail).
prime(_,_, Tail) :- var(Tail),!.
prime(R,_N, [Prime|_Primes]):-
Prime>R.
prime(_R,N, [Prime|_Primes]) :-0 is N mod Prime, !, fail.
prime(R,ToTest, [_|Primes]) :- prime(R,ToTest, Primes).
also, considering adding the numbers while you generate them to avoid the extra o(n) because of sumlist/2
in the end, you can always implement the AKS algorithm that runs in polynomial time (XD)

create a list from a list of lists

I need to do the following: given a list of lists I need to find all possible combinations of the lists such that if some of these lists belong in such a combination, then they have no elements in common and the list created by appending the lists in the combination has a given length. Any ideas?
Example:
Say P= [[1,2,3],[4,5,6],[2,5],[7,9],[7,10],[8],[10]].
N a given number, say N=10. I need to search through P in order to find appropriate lists, with no elements in common, and add them in a list L such that the length of the union of L is 10. So in the above example :
L=[[1,2,3],[4,5,6],[7,9],[8],[10]]. It might be very easy but I'm new in Prolog
Given nobody's answered, and it's been quite a while since I've written anything in Prolog and I figured I needed the practice, here's how you'd do it.
First, to make generating the combinations easier, we create a term to preprocess the lists to pair them with their lengths to avoid having to get the lengths multiple times. The cut avoids needless backtracking:
with_lengths([], []) :- !.
with_lengths([H|T1], [(Len, H)|T2]) :-
length(H, Len),
with_lengths(T1, T2).
Here's the comb/3 predicate, which you use for generating the combinations:
comb(L, R, Max) :-
with_lengths(L, L1),
comb1(L1, R, Max).
comb1/3 does the actual work. The comments explain what's going on:
% Combination works.
comb1([], [], 0).
% Try combining the current element with the remainder.
comb1([(Len, Elem)|T1], [Elem|T2], Max) :-
NewMax is Max - Len,
comb1(T1, T2, NewMax).
% Alternatively, ignore the current element and try
% combinations with the remainder.
comb1([_|T1], T2, Max) :-
comb1(T1, T2, Max).

Resources