Prolog Summing Fields in a Database - prolog

I am learning Prolog and I understand how to calculate the sum of a list but I can't figure out how to compute the sum of the fields of a database.
Sample database:
tastiness(bacon,100,200,300,400,500).
tastiness(lettuce,3,5,6,7,12).
Sample output
(bacon,1500).
(lettuce,33).

Here's how to sum the values of a list in standard Prolog:
sumlist([], 0).
sumlist([X|Xs], Sum) :-
sumlist(Xs, SumTail),
Sum is X + SumTail.
If you have something like
bacon(100).
bacon(200).
bacon(300).
bacon(400).
bacon(500).
you could then use the findall predicate. The findall predicate works as follows: If you want Z = [100, 200, 300, 400, 500] (the list of all bacon numbers) you write findall(X, bacon(X), Z).
Here's how to sum all bacon numbers:
| ?- findall(X, bacon(X), AllBacon), sumlist(AllBacon, SumBacon).
AllBacon = [100,200,300,400,500]
SumBacon = 1500
yes

As a side note, the sum computation proposed by #aioobe is not optimal because on a very large list, you will run out of call stack memory.
A particular technique is to put the recursive call of the predicate as the last element of your predicate. This way, all preceding things being already computed, Prolog can flush the current context of the predicate while making the recursive call. On a list with 1M elements, that means than you will run with 1 context being kept instead of up to one million.
While it may not seem important to you for this particular exercise, the tail call optimization is what makes recursion as powerful as iteration, if you take space consumption into consideration. It's worth learning!
Here is a version on which Tail Call Optimization is performable:
sumlist(List, Result) :-
sumlist(List, 0, Result).
sumlist([], Acc, Acc).
sumlist([Item|List], Acc, Result) :-
NewAcc is Acc + Item.
sumlist(List, NewAcc, Result).
It makes use of an idiom you will encounter a lot in declarative programming: an accumulator (here named Acc). Its purpose is to hold the resulting value "up until now" during the recursion.

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 can I verify if a coordinate is in a list

I'm generating random coordinates and adding on my list, but first I need verify if that coordinate already exists. I'm trying to use member but when I was debugging I saw that isn't working:
My code is basically this:
% L is a list and Q is a count that define the number of coordinate
% X and Y are the coordinate members
% check if the coordniate already exists
% if exists, R is 0 and if not, R is 1
createCoordinates(L,Q) :-
random(1,10,X),
random(1,10,Y),
convertNumber(X,Z),
checkCoordinate([Z,Y],L,R),
(R is 0 -> print('member'), createCoordinates(L,Q); print('not member'),createCoordinates(L,Q-1).
checkCoordinate(C,L,R) :-
(member(C,L) -> R is 0; R is 1).
% transforms the number N in a letter L
convertNumber(N,L) :-
N is 1, L = 'A';
N is 2, L = 'B';
...
N is 10, L = 'J'.
%call createCoordinates
createCoordinates(L,20).
When I was debugging this was the output:
In this picture I'm in the firts interation and L is empty, so R should be 1 but always is 0, the coordinate always is part of the list.
I have the impression that the member clause is adding the coordinate at my list and does'nt make sense
First off, I would recommend breaking your problem down into smaller pieces. You should have a procedure for making a random coordinate:
random_coordinate([X,Y]) :-
random(1, 10, XN), convertNumber(XN, X),
random(1, 10, Y).
Second, your checkCoordinate/3 is converting Prolog's success/failure into an integer, which is just busy work for Prolog and not really improving life for you. memberchk/2 is completely sufficient to your task (member/2 would work too but is more powerful than necessary). The real problem here is not that member/2 didn't work, it's that you are trying to build up this list parameter on the way out, but you need it to exist on the way in to examine it.
We usually solve this kind of problem in Prolog by adding a third parameter and prepending values to the list on the way through. The base case then equates that list with the outbound list and we protect the whole thing with a lower-arity procedure. In other words, we do this:
random_coordinates(N, Coordinates) :- random_coordinates(N, [], Coordinates).
random_coordinates(0, Result, Result).
random_coordinates(N, CoordinatesSoFar, FinalResult) :- ...
Now that we have two things, memberchk/2 should work the way we need it to:
random_coordinates(N, CoordinatesSoFar, FinalResult) :-
N > 0, succ(N0, N), % count down, will need for recursive call
random_coordinate(Coord),
(memberchk(Coord, CoordinatesSoFar) ->
random_coordinates(N, CoordinatesSoFar, FinalResult)
;
random_coordinates(N0, [Coord|CoordinatesSoFar], FinalResult)
).
And this seems to do what we want:
?- random_coordinates(10, L), write(L), nl.
[[G,7],[G,3],[H,9],[H,8],[A,4],[G,1],[I,9],[H,6],[E,5],[G,8]]
?- random_coordinates(10, L), write(L), nl.
[[F,1],[I,8],[H,4],[I,1],[D,3],[I,6],[E,9],[D,1],[C,5],[F,8]]
Finally, I note you continue to use this syntax: N is 1, .... I caution you that this looks like an error to me because there is no distinction between this and N = 1, and your predicate could be stated somewhat tiresomely just with this:
convertNumber(1, 'A').
convertNumber(2, 'B').
...
My inclination would be to do it computationally with char_code/2 but this construction is actually probably better.
Another hint that you are doing something wrong is that the parameter L to createCoordinates/2 gets passed along in all cases and is not examined in any of them. In Prolog, we often have variables that appear to just be passed around meaninglessly, but they usually change positions or are used multiple times, as in random_coordinates(0, Result, Result); while nothing appears to be happening there, what's actually happening is plumbing: the built-up parameter becomes the result value. Nothing interesting is happening to the variable directly there, but it is being plumbed around. But nothing is happening at all to L in your code, except it is supposedly being checked for a new coordinate. But you're never actually appending anything to it, so there's no reason to expect that anything would wind up in L.
Edit Notice that #lambda.xy.x solves the problem in their answer by prepending the new coordinate in the head of the clause and examining the list only after the recursive call in the body, obviating the need for the second list parameter.
Edit 2 Also take a look at #lambda.xy.x's other solution as it has better time complexity as N approaches 100.
Since i had already written it, here is an alternative solution: The building block is gen_coord_notin/2 which guarantees a fresh solution C with regard to an exclusion list Excl.
gen_coord_notin(C, Excl) :-
random(1,10,X),
random(1,10,Y),
( memberchk(X-Y, Excl) ->
gen_coord_notin(C, Excl)
;
C = X-Y
).
The trick is that we only unify C with the new result, if it is fresh.
Then we only have to fold the generations into N iterations:
gen_coords([], 0).
gen_coords([X|Xs], N) :-
N > 0,
M is N - 1,
gen_coords(Xs, M),
gen_coord_notin(X, Xs).
Remark 1: since coordinates are always 2-tuples, a list representation invites unwanted errors (e.g. writing [X|Y] instead of [X,Y]). Traditionally, an infix operator like - is used to seperate tuples, but it's not any different than using coord(X,Y).
Remark 2: this predicate is inherently non-logical (i.e. calling gen_coords(X, 20) twice will result in different substitutions for X). You might use the meta-level predicates var/1, nonvar/1, ground/1, integer, etc. to guard against non-sensical calls like gen_coord(1-2, [1-1]).
Remark 3: it is also important that the conditional does not have multiple solutions (compare member(X,[A,B]) and memberchk(X,[A,B])). In general, this can be achieved by calling once/1 but there is a specialized predicate memberchk/2 which I used here.
I just realized that the performance of my other solutions is very bad for N close to 100. The reason is that with diminishing possible coordinates, the generate and test approach will take longer and longer. There's an alternative solution which generates all coordinates and picks N random ones:
all_pairs(Ls) :-
findall(X-Y, (between(1,10,X), between(1,10,Y)), Ls).
remove_index(X,[X|Xs],Xs,0).
remove_index(I,[X|Xs],[X|Rest],N) :-
N > 0,
M is N - 1,
remove_index(I,Xs,Rest,M).
n_from_pool(_Pool, [], 0).
n_from_pool(Pool, [C|Cs], N) :-
N > 0,
M is N - 1,
length(Pool, L),
random(0,L,R),
remove_index(C,Pool,NPool,R),
n_from_pool(NPool, Cs, M).
gen_coords2(Xs, N) :-
all_pairs(Pool),
n_from_pool(Pool, Xs, N).
Now the query
?- gen_coords2(Xs, 100).
Xs = [4-6, 5-6, 5-8, 9-6, 3-1, 1-3, 9-4, 6-1, ... - ...|...] ;
false.
succeeds as expected. The error message
?- gen_coords2(Xs, 101).
ERROR: random/1: Domain error: not_less_than_one' expected, found0'
when we try to generate more distinct elements than possible is not nice, but better than non-termination.

Prolog Assigning integer to a variable

I'm new to Prolog, and using GNU Prolog, so no clp(fd) allowed. What I'm trying to do is for a given integer N, generate a list with elements of 1 ~ N. So set(3,T). will output T = [1,2,3].
Here is what I have so far:
set(0,[]).
set(N,T):-set(N-1,T1),append(T1,[N],T).
When I try set(2,T), it crashes. I debugged with trace, and find out that it's not evaluating N-1, but rather doing N-1-1-1...
Anyone can tell me how to solve this?
Thank you.
n_ups(N, Xs) :-
length(Xs, N),
numbered_from(Xs, 1).
numbered_from([], _).
numbered_from([I0|Is], I0) :-
I1 is I0+1,
numbered_from(Is, I1).
In fact, the complexity is hidden within length/2.
It should be:
set(N,T):- N2 is N-1, set(N2,T1), append(T1,[N],T).
Arithmetic operations are performed by using is/2. N-1 is a shorthand for -(N,1) (just like N2 is N-1 is shorthand for is(N2, N-1)), so you were just creating infinite tree -(-(-(-(...),1),1,1,1).
Little educational note:
If you want set/2 to be proper relation so it can answer queries like set(3,X), set(X, [1,2,3]) and set(X,Y) without error then you should write this predicate that way:
set(0, []).
set(Value, List) :-
length(List, Value),
append(ShorterList, [Value], List),
ValueMinusOne is Value - 1,
set(ValueMinusOne, ShorterList).
That way result of arithmetic operation is always possible to obtain because input value (lenght of the list) is either explicitly given or generated from length/1.

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. :)

Does any version of Prolog support higher order abstraction of accumulators?

I was wondering about a Prolog that could include a built-in call like this:
accum(generator, filter, accumulator)
Calculates all solutions to generator.
For each one, if filter can be proved, accumulator is proved.
Backtracks to find all solutions to filter and generator.
Accumulator may backtrack internally, but multiple proofs of accumulator are
conjoined, not backtracked.
So, for example, to sum a list without using recursion you could write:
X is 0, accum(member(Val,List), True, X is X + Val).
Is there any Prolog with this construct or an equivalent? Bear in mind that I am a bit of a newbie at Prolog and may be missing something obvious.
SWI-Prolog library(aggregate) has a powerful interface, for instance
aggregate_all(sum(Val), member(Val,List), Sum)
the (apparently simple) sharing of the variables among aggregation and generation is obtained with a predicate, foreach/2, that could interest you.
In SWI-Prolog you can do ?- edit(library(aggregate)). to study the internals...
library(aggregate) is relatively inefficient, but coupled with SWI-Prolog nb_ (non backtrackable) data structures should do its job very well...
About non backtrackable data structures: here is an example of my 'self built' accumulator, implemented by means of nb_setarg/3.
I assume you mean without explicit recursion? If so, you can use an implementation of the high-order predicate list fold left, together with a lambda expression to avoid the need of an auxiliary predicate. Using Logtalk as an example you can write:
?- Sum0 is 0, meta::fold_left([X,Y,Z]>>(Z is Y+X), Sum0, [1,2,3], Sum).
Sum0 = 0,
Sum = 6.
Logtalk can use as a backend compiler most Prolog implementations (http://logtalk.org/). You can also use Ulrich's lambda library (http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/ISO-Hiord.html) with a supported Prolog compiler together with a Prolog library providing the fold left predicate for the same result. Using now YAP as an example:
$ yap
...
?- use_module(library(lambda)).
...
?- use_module(library(maplist)).
...
?- Sum0 is 0, foldl(\X^Y^Z^(Z is Y+X), [1,2,3], Sum0, Sum).
Sum = 6,
Sum0 = 0.
Briefly, the fold left predicate iterates over a list, recursively applying the closure in its first argument to a list element and the accumulator, returning the final accumulator value.
In Mercury's standard library the "solutions" module provides functionality like this.
Note that X is X + Val does not assign a new value to X. It is a statement that is true if Val is zero, and false if it is any other number, which is probably not what you mean. Accumulators like this are typically expressed as a relation between the initial and final value.
In Mercury, your example could be written as:
:- import_module solutions.
...
sumlist(List, Sum) :-
Generator = (pred(Val::out) is nondet :- member(Val, List), true),
Accumulator = (pred(X::in, Y::in, Z::out) is det :- Z = X + Y),
aggregate(Generator, Accumulator, 0, Sum).
There is no need for a separate filter argument, as it can be included as part of the generator.

Resources