Average of a student using prolog - prolog

I know this looks a bit silly, but I'm trying to find the average of a given student using Prolog, here's my piece of code:
score( jason , math101 , 90 ).
score( sami , math102 , 67 ).
score( smith , phys101 , 82 ).
score( sami , chem101 , 88 ).
do(X,S,I) :-
score(X,_,B) ,
write(B) ,
S is S+B ,
I is I+1 ,
write(I) ,
fail.
start :-
read(X) ,
do(X,0,0)
.
I'm trying to do it using recursion, the problem is that I (stands for index) and S(stands for sum) wont increment ! what did I do wrong? thanks !

You code has some problems:
Expressions like S is S+B don't work in prolog. Once a variable is unified with a term (assigned a value), it ceases to be variable: it becomes that with which it was unified. Hence the name unification.
Your do/3 predicate will always fail. It looks like you are forcing backtracking via fail/0 and expecting your counters to be incremented as you go. Prolog doesn't work like that: As you backtrack, unification is undone, so even if you'd managed to increment your S and B variables, the increment would have been rolled back as you backtracked through it.
You are invoking your do/3 predicate with S and B already unified to a value (0). So your is/2 expressions are the exact equivalent of this:
0 is 0+B , % S is S+B ,
0 is 0+1 , % I is I+1 ,
You can see how that won't work.
What you need to do is collect the scores for each student as a list. Since you can only get them one at a time via backtracking, building that list is a little difficult. If you tried to build that list via recursion, on each recursion you find yourself starting over from ground zero. Conveniently, Prolog offers a set of predicates for collecting data from all solutions to a goal as a list:
setof/3 finds the set of all solutions to a goal, presenting them as a list.
findall/3 finds the bag of all solutions to a goal, presenting them as a list.
bagof/3 finds the bag of all solutions to a goal, presenting them as a list.
Notes: findall/3 and bagof/3 are similar but different: to quote the docs, "findall/3 is equivalent to bagof/3 with all free variables bound with the existential operator ^". You'll probably need to play with it a bit to grok just what that means. The difference between set and bag is that by definition, sets are unique and have no duplicates. Bags, on the other hand are not necessarily unique and may contain duplicates.
At any rate, you're interested in bagof/3.
The first thing to do is decompose your problem into simple pieces. The first thing you need to do is compute the average score for a single student. to do that you need:
The student's name,
The list of individual scores for that student, and
a way to compute the arithmetic mean from a list of numbers.
So, let's tackle each of this in turn. The 1st two problems are solved with bagof/3. This:
bagof(Score,score(Student,_,Score),Scores) .
will find the list of scores for a student, unifying Student with the student's name and Scores with the list of individual scores. On backtracking it will successively do the same for all students.
That takes care of the first two simple problems. The 3rd problem isn't much more difficult. Here we will introduce two concepts that are integral to prolog: recursion and the use of accumulators to develop a value. we have to do this because as noted, in Prolog, all variables are local and can only be assigned a value once. So to develop a value, we have to recursively carry the state around that we need. A common idiom is the use of helper predicates that do all the work and are invoked by the "public" predicate that the user actually uses.
We can compute the arithmetic mean of a list of numbers like this:
compute_mean( Ns, M ) :- % to compute the mean of a list of numbers,
compute_mean( Ns , 0 , 0 , M ) % - just invoke the helper with the counters seeded as zero.
. % Also easy!
compute_mean( [] , S , N , M ) :- % if the source list is exhausted,
N > 0 , % - and we have a non-zero N (division by zero being undefined),
M is float(S) / float(N) % - compute the arithmetic mean, casting both counters to floats
. % otherwise...
compute_mean( [X|Xs] , S , N , M ) :- % if the source list isn't yet exhausted,
S1 is S+X , % - add the data point to the running total,
N1 is N+1 , % - increment the count of data points,
compute_mean(Xs,S1,N1,M) % - and recurse down on the tail of the list.
. % Easy!
That's all we need to compute the average score for a student, and on backtracking, successively do so for all students. Just put the two things together:
mean_score( Student , Mean ) :- % to compute the mean score for a student,
bagof( Mean , score(Student,_,Score) , Scores ) , % - get the bag of the scores for the student
compute_mean( Scores , Mean ) % - and then compute the mean score
. % Easy!
Once you have that, you could then just say something like this:
list_mean_scores_for_all_students :-
mean_score(Student,Mean) ,
write( Student:Mean) , nl ,
fail .
list_mean_scores_for_all_students .
The problem with the above is that list_mean_scores_for_all_students/0 will always succeed, even if something untowards happened. So, you might want to use findall/3 to collect them all at once and then process them.
Then we can say:
list_mean_scores_for_all_students :-
findall( Student:Mean , mean_score(Student,Mean) , Results ) ,
log_results(Results)
.
log_results( [] ) .
log_results( [S:M|Xs] ) :-
write(S:M),nl ,
log_results(Xs)
.
If something fails, list_means_scores_for_all_students/0 will fail.

Related

Checking if the second list is half the size of first list

I am a noob prolog programmer and facing a difficulty with one of the basic problems that have been given in the book where I am learning from. The question. The question basically asks us to write down a Prolog procedure that takes two lists as arguments, and succeeds if the first list is twice the size of the second list and the two lists start with the same element. The procedure should return false if the two lists are empty.
For example it should return true if we pass the query:
a2b([a,a,a,a],[a,b]).
and would fail with a query like:
a2b([a,a],[a,b,b,b]).
I don't know how to solve this problem recursively, any help would be appreciated. Thanks!
First, the request about lengths:
/* empty list fulfills request */
a2b_length([],[]).
/* non-empty: discard two elements of first list,
one of second list, and verify
remainder */
a2b_length([_,_|Q1],[_|Q2]) :-
a2b_length(Q1,Q2).
Now, we can add the requirement "starts by the same term and are non empty", and write the last clause:
a2b([X,_|Q1],[X|Q2]) :-
a2b_length(Q1,Q2).
Cute problem. It can be solved using the following code:
% fail of the first element of each list don't unify
% or if one or both lists are empty
a2b([First| List1], [First| List2]) :-
% calculate the length of the second list
% while traversing both lists in parallel
a2b_first(List2, 1, N, List1, Rest1),
% check that the length of the rest of the first
% list is equal to the length of the second list
a2b_second(Rest1, N).
a2b_first([], N, N, Tail1, Tail1).
a2b_first([_| Tail2], N0, N, [_| Tail1], Rest1) :-
N1 is N0 + 1,
a2b_first(Tail2, N1, N, Tail1, Rest1).
a2b_second([], 0).
a2b_second([_| Tail1], N) :-
M is N - 1,
a2b_second(Tail1, M).
Of course, there's a simpler (but not as fun to code!) solution:
% fail of the first element of each list don't unify
% or if one or both lists are empty
a2b([First| List1], [First| List2]) :-
length([First| List1], N1),
length([First| List2], N2),
N1 is 2 * N2.
The length/2 predicate is usually available either as a built-in predicate or as a library predicate.
For learning Prolog, studying the first solution is interesting. For example, it exemplifies how to take advantage of first-argument indexing and how to use accumulators for writing predicates that are tail-recursive (and thus space efficient).
Also, the first solution can be more efficient than the second solution. In the second solution, we always traverse both lists to the end to find their lengths. But, in the first solution, that is not always necessary.
Don't overthink things: just describe the solution and let Prolog sort it out.
The solution doesn't require counting or predicates other than its trivial self. It's all pattern matching. We have a special (terminating case), asserting that a list of length 2 is twice as long as a list of length 1 (which should be pretty obvious):
is_twice_as_long_as( [_,_] , [_] ) .
Then there is the general case, which asserts that given two lists of arbitrary length, the left is twice as long as the right IF we can (A) remove 2 items from the left, (B) remove 1 item from right, and recursively assert that their respective remainders are likewise twice as long:
is_twice_as_long_as( [_,_|A] , [_|B] ) :- is_twice_as_long_as( A , B ) .
Giving us the finished product:
is_twice_as_long_as( [_,_] , [_] ) .
is_twice_as_long_as( [_,_|A] , [_|B] ) :- is_twice_as_long_as( A , B ) .
Easy!
Edited to note the requirement that the two lists begin with the same element:
Depending on how that is interpreted...
this requires that the lists have a common head on each iteration:
is_twice_as_long_as( [A,_] , [A] ) .
is_twice_as_long_as( [A,_|L] , [A|R] ) :- is_twice_as_long_as( L , R ) .
this does the check for a common head just once::
is_twice_as_long_as( [A|As] , [A|Bs] ) :-
is_2x([A|As],[A|Bs]) .
is_2x( [_,_] , [_] ) .
is_2x( [_,_|L] , [_|R] ) :- is_2x( L , R ) .

How to compare lists length Prolog

I'm new at Prolog and i was trying to solve some exercises and I found this one twice_as_long(L1,L2) that succeeds if the list L2 is twice as long as the list L1.
Do NOT compute the lengths of the lists.
twice_as_long([],[]).
true.
?- twice_as_long([a],[1,2]).
true.
?- twice_as_long([a,b],X).
X = [_G328, _G331, _G334, _G337] ;
false
I want some hint please cuz i don't want to compare lengths like what they said .
We can generalize your second example as a rule:
twice_as_long([_],[_,_]).
But we can do better:
twice_as_long([_|T1], [_,_|T2]) :- twice_as_long(T1,T2).
That, with the base case from you first example, will do the job.
With respect to Prolog conventions, given a predicate of the form type_of_relationship(X,Y), it's pretty customary to read it as a declaration of fact along the lines of
X has a type_of_relationship with Y.
So, let's flip the order of the arguments: twice_as_long(X,Y) asserts that X is twice as long as Y.
Given that, and amplifying the answer from #ScottHunter, Let's break things down into simple cases.
First, your example shows a case that should fail as succeeding.
twice_as_long([],[]).
asserts that the empty list is twice as long as itself, something that is manifestly untrue: the empty list is of length zero and twice zero is still..zero. So that case should be discarded.
There is, however, the simplest case possible:
twice_as_long( [_,_] , [_] ) .
an assertion that a list of length 2 is twice as long as a list of length 1.
Then, there is the generic case:
twice_as_long( [_,_|Xs] , [_|Ys] ) :-
twice_as_long(Xs,Ys) .
in which we say that a list of 2 or more items is twice as long as a list of 1 or more items...
IF, the remainder of the first list is twice as long as the remainder of the second list, where the remainders are obtained by removing the first 2 items from the first list and just 1 item from the second list.
That gives us this as the solution:
twice_as_long( [_] , [_,_] ) .
twice_as_long( [_|Xs] , [_,_|Ys] ) :- twice_as_long(Xs,Ys) .
The predicate will succeed when you get to the simple base case, and fail otherwise.

Prolog Picking from a list and Summing specific Values

sumPicker([[]|_], Y, Z).
sumPicker([X|X1], Y, Z):-
downList(Y, X, Sum),
Total is Z,
Z is Total + Sum,
sumPicker(X1,Y, Z).
downList([Z|_], 1, Z).
downList([_|B],Count, Number):- Count > 1,
SendCount is Count - 1,
downList(B, SendCount, Number).
So this code is basically suppose to take in Two lists sumPicker([3,5], [1,2,3,4,5,6], X). The program then takes the first list and depending on the value of the number, so in this case 3, it will find the third number in the second list then it will find the 5th number of the second list and add them together.
ERROR: is/2: Arguments are not sufficiently instantiated is what i am getting
I'm assuming that your instructor would like you to work out the recursion yourself, rather than using built-in list operations. To that end, you could approach it something like this, using no built-ins at all.
A common prolog idiom is to have a simple "public" predicate that invokes a "helper" predicate that carries state (in this case, the current position in the list and the running sum). Often, that "helper" predicate will have the same functor (name) as the public predicate, with a higher arity (number of arguments).
So, first we have the public predicate, sum_of_desired/3:
sum_of_desired( Indices , Numbers , Sum ) :- % to sum certain list elements,
sum_of_desired( Indices , Numbers , 0 , Sum ) - % invoke the helper
. %
All it does is invoke the helper, sum_of_desired/4. This helper predicate carries an extra argument that is its state: an accumulator that contains the running sum. When it succeeds, that running sum is unified with the final total. This is because, in Prolog, you can't change the value of a variable: once you assign a value to a variable, it ceases to be variable. It become that with which it was unified (that's it's called unification). The only way to undo that assignment is via backtracking.
Typically, a recursive problem has a few special cases and a more general case. So, here, our helper predicate has 2 clauses:
The first clause is the special case: the list of desired indices is empty, in which case the finally sum is the current value of the accumulator (0 initially).
the second clause is the recursive general case: here we find the desired list item, add it to the running total and recurse down, moving on to the next item in the list of desired list items.
sum_of_desired( [] , _ , S , S ) . % the list of desired indices is empty: unify the accumulator with the result.
sum_of_desired( [I|Is] , L , T , S ) :- % otherwise...
get_nth_item(I,L,N) , % - get the nth item from the list
T1 is T+N , % - add it to the running total
sum_of_desired(Is,T1,S) % - and recurse down
. %
Finally, this predicate, get_nth_item/3, simple recursively walks the list, looking for the nth item in the list, where n is relative to 1 (e.g., the first item in the list is at index 1). When it finds it, it's returned as the 3rd argument of the predicate.
Again, here you will note that we have a single terminating special case and the more general recursive special case:
get_nth_item( 1 , [X|_] , X ) . % found it!
get_nth_item( N , [_|Xs] , R ) :- % otherwise...
N > 1 , % - if N > 1 ,
N1 is N-1 , % - decrement N
nth_item( N1 , Xs , R ) % - recurse down.
. % - easy!

Prolog - solving problems with lists

Hello I have to solve some prolog problems with lists but i can't figure it out how these work.
I have to add "1" after every even element in a list, and to make the difference of 2 lists.
I know this seems easy, in other language like java or c# i would make it very easy, but prolog it's giving me headaches.
Please help me :|
Edited to note the clarified problem statement ("even item" meaning the item's value is even (rather than the item's ordinal position within the list):
insert_one_after_even_items( [] , [] ). % if the source list is exhaused, we're done.
insert_one_after_even_items( [X|Xs] , [X,1|Ys] ) :- % otherwise,
0 is X mod 2 , % - if the number is even, prepend it and a 1 to the result list, and
insert_one_after_even_items( Xs , Ys ) % - recurse down.
. %
insert_one_after_even_items( [X|Xs] , [X|Ys] ) :- % otherwise,
1 is X mod 2 , % - if the number is odd, prepend it to the result list, and
insert_one_after_even_items( Xs , Ys ) % - recurse down.
. % Easy!
For your second problem, producing the difference between two lists, are you talking about set differences? If so, given two sets A and B, are you talking about the relative difference (all elements of A that do not exist in B), or the absolute difference (all elements of either A or B that do not exist in both sets)?
To solve the relative set difference problem (Find all members of A that do not also exist in B), you can use the built-in member/2 predicate:
relative_difference( [] , _ , [] ) . % if the source list is exhausted, we're done
relative_difference( [A|As] , Bs , R ) :- % if the source list is non-empty, and
member(A,Bs) , % - the current A is an element of B,
! , % - we insert a deterministic cut (no backtracking)
relative_difference( As , Bs , R ) % - and recurse down, discarding the current A
. %
relative_difference( [A|As] , Bs , [A|R] ) :- % if the source list is non-empty (and A is not an element of B due to the cut inserted earlier)
relative_difference( As , Bs , R ) % we simply add A to the result list and recurse down.
.
One thing you will note here: we are building the result list in all of these examples is built from a variable. The tail of the list is unbound (and passed as the new result to the next recursive call, where it either become a new list node or, at the very end, the empty list.
This has the effect of
building the list in order (rather than in reverse order).
if the result was bound on the initial call, unification against the expected result occurs item by item as the recursion proceeds, which means
execution is short-circuited when the first unification failure occurs.
If your prolog implementation doesn't have member/2 as a built in, it's easy enough to implement. Something like this ought to do it:
member(X,[X|T]) :- ! . % A hit! cut and succeed.
member(X,[_|T]) :- member(X,T) . % ... and a miss. Just recurse down on the tail.

Sum of a list in prolog

I'm reading 'the art of prolog' book and I found an exercise that reads 'Define the relation sum(ListOfIntegers,Sum) which holds if Sum is the sum of the ListOfIntegers, without using any auxiliary predicate' .I came up with this solution:
sum([],Sum).
sum([0|Xs], Sum):-sum(Xs, Sum).
sum([s(X)|Xs], Sum):-sum([X|Xs],s(Sum)).
Which does not work exactly as I would want it to.
?- sum([s(s(0)),s(0),s(s(s(0)))],X).
true ;
false.
I was expecting X to be
s(s(s(s(s(s(0))))))
I thought that the problem is that I have to 'initialize' Sum to 0 in the first 'iteration' but that would be very procedural and unfortunately I'm not quite apt in prolog to make that work.
Any ideas or suggestions?
Your first clause should read
sum([], 0).
With that change, the vacuous true return goes away and you're left with one problem: the third clause reverses the logic of summation. It should be
sum([s(X)|Xs], s(Sum)) :- sum([X|Xs], Sum).
because the number of s/1 terms in the left argument to sum/2 should be equal to the number of them in the right argument.
The best way to localize the problem is to first simplify your query:
?- sum([0],S).
true.
?- sum([],S).
true.
Even for those, you get as an answer that any S will do. Like
?- sum([],s(s(0))).
true.
Since [] can only be handled by your fact, an error must lie in that very fact.
You stated:
sum([], Sum).
Which means that the sum of [] is just anything. You probably meant 0.
Another error hides in the last rule... After fixing the first error, we get
?- sum([0],Sum).
Sum = 0.
?- sum([s(0)],Sum).
false.
Here, the last clause is responsible. It reads:
sum([s(X)|Xs], Sum):-sum([X|Xs],s(Sum)).
Recursive rules are relatively tricky to read in Prolog. The simplest way to understand them is to look at the :- and realize that this should be an arrow ← (thus a right-to-left arrow) meaning:
provided, that the goals on the right-hand side are truewe conclude what is found on the left-hand side
So, compared to informal writing, the arrows points into the opposite direction!
For our query, we can consider the following instantiation substituting Xs with [] and X with 0.
sum([s(0)| [] ], Sum) :- sum([0| []],s(Sum)).
So this rule now reads right-to-left: Provided, sum([0],s(Sum)) is true, ... However, we do know that only sum([0],0) holds, but not that goal. Therefore, this rule never applies! What you intended was rather the opposite:
sum([s(X)|Xs], s(Sum)):-sum([X|Xs],Sum).
I'm not really following your logic, what with all the seemingle extraneous s(X) structures floating about.
Wouldn't it be easier and simpler to do something like this?
First, define your solution in plain english, thus:
The sum of an empty list is 0.
The sum of a non-empty list is obtained by adding the head of the list to the sum of the tail of the list.
From that definition, the prolog follows directly:
sum( [] , 0 ) . % the sum of an empty list is 0.
sum( [X|Xs] , T ) :- % the sum of an non-empty list is obtained by:
sum( Xs , T1 ) , % - first computing the sum of the tail
T is X + T1 % - and then, adding that the to head of the list
. % Easy!

Resources