Prolog sum all the number in the list. - list

How to sum all odd positioned elements in a list
example [1,2,3,4,5,6,7,8,9] = 25
odd([],0].
odd([Z],Z).
odd([X,Y|T], Sum+1):- odd(T,Sum).
but it return me 1+3+5+7+9.

In prolog you have to use the is operator when you want to evaluate arithmetic expressions. Since you use the + symbol outside of an arithmetic scope it is not interpreted specially. This appears to be homework, so I'll give a simplified example:
add(A, B, C) :- C is A + B.
The code above adds A and B and stores the result in C.

What you construct when you write Sum+1 is a term with functor '+'/2 and arguments Sum and 1.
In Prolog, when you want to calculate a sum, you need to use the predicate is/2.
In your code, you should also add cuts to remove unnecessary choicepoints, and add X to the rest of the sum, not 1:
odd([],0) :- !.
odd([Z],Z) :- !.
odd([X,_|T],Sum):- odd(T,Sum0), Sum is Sum0+X.
Using an accumulator would allow you to make the code tail-recursive...

Get a list with the odd elements, then sum that list:
divide([], [], []).
divide([H|T], [H|L1], L2) :- divide(T, L2, L1).
sum(L, Sum) :- sum(L, 0, Sum).
sum([], Acu, Acu).
sum([H|T], Acu, Acu1) :-
Acu2 is Acu + H,
sum(T, Acu2, Acu1).
sum_odd(L, Sum) :-
divide(L, Odds, _),
sum(Odds, Sum).
:- sum_odd([1,2,5,6,8,9,1], Sum), writeln(Sum).

sum([],0).
sum([H|T],N) :-
sum(T,M), N is H + M.

Related

How to get prime numbers from list and put them in empty list

I want to get all prime numbers from a list of numbers and put it into another empty list.
My problem is that whenever the function isPrime is false, the program is terminated.
I'm very beginner in prolog, so if you have any feedback I'll appreciate the help.
Here is my code below:
check_prime(X):-
Xtemp is integer(X/2),
isPrime(X,Xtemp).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
isPrime(_,2).
isPrime(2,_).
isPrime(Num,Counter):-
X is Counter-1,
X \= 0,
X2 is mod(Num,X),
X2 \= 0,
isPrime(Num,X).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
prime_list([],Y).
prime_list([H|T],[H|T2]):-
check_prime(H),
prime_list(T,T2).
Your check_prime function will give true even for non-prime numbers.
Example: check_prime(4) will call isPrime(4, 2), which will unify with the first clause of isPrime.
An example of code that gives you the list of primes would be this:
% predicate to check if X has any divisors
divisible(X,Y) :- 0 is X mod Y, !.
divisible(X,Y) :- X > Y+1, divisible(X, Y+1).
%predicate to check if that number is prime by using the divisible predicate
isPrime(2) :- true,!.
isPrime(X) :- X < 2,!,false.
isPrime(X) :- not(divisible(X, 2)).
%predicate that returns the resulted list
primeList([], []). % stopping condition, when list empty
% we add current element to the resulting list if it is prime
primeList([H|T], [H|R]):- isPrime(H), !, primeList(T, R).
% otherwise, we just skip it
primeList([_|T], R):- primeList(T, R).
Query: ?-primeList([1,2,3,4,5,6,7,8,9], R). => R=[2,3,5,7]

How to simplify algebra equations represented as list of list

With Prolog I want to simplify algebra expression represented as as list of list:
algebra equation
f = 3x+2
list of list
[[3,1],[2,0]]
3 and 2 are coefficients
1 and 0 are exponents
That should be obvious.
I am looking for some tips or suggestions on how to code the simplifications for this example:
f = 3x+2x+1+2
[[3,1],[2,1],[1,0],[2,0]]
simplified:
f = 5x+3
[[5,1],[3,0]]
I have tried some built in functions but did not get the proper idea about how to use them.
One liner, similar to what's proposed by joel76:
simplify(I,O) :-
bagof([S,E],L^(bagof(C,member([C,E],I),L),sum_list(L,S)),O).
The inner bagof collects C (coefficients) given E (exponents), the resulting list L is summed into S, and paired with E becomes [S,E], an element (monomial) of O.
If you omit the universal quantification specifier (that is L^) you get single monomials on backtracking.
You can solve your problem in this way:
simplify(_,_,S,S,[]):- !.
simplify(L,I,Sum,NTot,[[I,S]|T]):-
Sum =< NTot,
findall(X,member([X,I],L),LO),
length(LO,N),
S1 is Sum + N,
sum_list(LO,S),
I1 is I+1,
simplify(L,I1,S1,NTot,T).
write_function([]).
write_function([[D,V]|T]):-
write(' + '),write(V),write('x^'),write(D),
write_function(T).
test:-
L = [[3,1],[2,1],[1,0],[2,0]],
length(L,N),
simplify(L,0,0,N,LO),
LO = [[D,V]|T],
write('f='),write(V),write('x^'),write(D),
write_function(T).
The main predicate is simplify/5 which uses findall/3 to find all the coefficients with the same degree and then sums them using sum_list/2. Then you can write the result in a fancy way using write_function/1.
In SWI-Prolog You can use aggregate :
pred(>, [_,X], [_,Y]) :- X > Y.
pred(<, [_,X], [_,Y]) :- X < Y.
pred(=, [_,X], [_,X]).
simplify(In, Out) :-
aggregate(set([S,X]), aggregate(sum(P), member([P,X], In), S), Temp),
predsort(pred, Temp, Out).
For example :
?- simplify([[3,1],[2,1],[1,0],[2,0]], Out).
Out = [[5, 1], [3, 0]] ;
false.

Prolog - average predicate: Arguments not sufficiently instantiated

I have a list of cars (auto in german), where the first Variable is the license-plate and the second one the speed:
[auto(eu-ts884, 69), auto(dn-gh184, 64), auto(ac-lj123, 72)].
Now I try to write an average predicate but it fails with the error message:
ERROR: Arguments are not sufficiently instantiated
My code so far:
durchschnitt([], 0, 0).
durchschnitt([auto(_, X)|Tail], L, Y):-
Y is S/L,
L > 0,
cardinal([auto(_, X)|Tail], L),
sumKilometer([auto(_, X)|Tail], S).
sumKilometer([], 0).
sumKilometer([auto(_, X)|Tail], Sum) :-
sumKilometer(Tail, N),
Sum is N + X.
cardinal([], 0).
cardinal([_|Tail], Result) :-
cardinal(Tail, N),
Result is N + 1.
My code is quite equivalent to that post, although I cannot make out my mistake.
Note: sumKilometer and cardinal are working fine.
You write:
durchschnitt([], 0, 0).
durchschnitt([auto(_, X)|Tail], L, Y):-
Y is S/L,
L > 0,
cardinal([auto(_, X)|Tail], L),
sumKilometer([auto(_, X)|Tail], S).
The first problem is that when you call durchschnitt([auto(foo,2)],L,Y), L is a free variable. As a result, you cannot calculate Y is S/L since both S and L are unknown here.
You can however use:
durchschnitt([], 0, 0).
durchschnitt([auto(_, X)|Tail], L, Y):-
cardinal([auto(_, X)|Tail], L),
sumKilometer([auto(_, X)|Tail], S),
Y is S/L.
So here you calculate the average after both L and S are known. Furthermore you do not unify the list with [auto(_,X)|Tail], etc. A simple check like A = [_|_] is sufficient:
durchschnitt([], 0, 0).
durchschnitt(A, L, Y):-
A = [_|_],
cardinal(A, L),
sumKilometer(A, S),
Y is S/L.
This will also reduce the amount of time spent packing and unpacking.
Sum, Length and Average all concurrently
You can construct a predicate that calculates the three all at the same time (so without looping twice over the list). You can simply use accumulators, like:
durchschnitt(A,L,Y) :-
durchschnitt(A,0,0,L,Y).
Here the second and third element are the running sum and length respectively.
Now for durchschnitt/5, there are two cases. In the first case we have reached the end of the list, and we thus have to calculate the average and return it, like:
durchschnitt([],S,L,L,Y) :-
(L \= 0
-> Y is S/L
; Y = 0).
So we use an if-then-else to check if the length is something different than 0 (in the case there are no autos in the list, we return 0 as average.
In the recursive case, we simple increment the running length and update the running sum, like:
durchschnitt([auto(_,Si)|T],RS,RL,L,Y) :-
RSN is RS+Si,
L1 is L+1,
durchschnitt(T,RSN,L1,L,Y).
Or putting it together:
durchschnitt(A,L,Y) :-
durchschnitt(A,0,0,L,Y).
durchschnitt([],S,L,L,Y) :-
(L \= 0
-> Y is S/L
; Y = 0).
durchschnitt([auto(_,Si)|T],RS,RL,L,Y) :-
RSN is RS+Si,
L1 is L+1,
durchschnitt(T,RSN,L1,L,Y).

Multiplying two lists in prolog

I am currently working with prolog and want to multiply two lists together but in a certian way. For example:
[1,2,3] and [4,5,6] are my two lists.
I want to preform the following actions:
(1*4)+(2*5)+(3*6) = 32
Such that the first element of each list is multiplied to each other then added with the second elements multiplied together etc.
Is this possible to go in Prolog?
I know in other languages you can do a recursive function with takes the head of the list and the tail (the rest of the entries). This allows for a simple multiplication but I do not think that is possible in prolog?
Using built-ins:
mult(X, Y, Z) :- Z is X * Y.
sum_prod(A, B, SumProd) :-
maplist(mult, A, B, Prods),
sumlist(Prods, SumProd). % In GNU Prolog this is sum_list
Using simple recursion:
sum_prod([A|As], [B|Bs], SumProd) :-
sum_prod(As, Bs, SP),
SumProd is SP + A*B.
sum_prod([], [], 0).
Using tail recursion:
sum_prod(A, B, SumProd) :-
sum_prod(A, B, 0, SumProd).
sum_prod([A|As], [B|Bs], Acc, SumProd) :-
Acc1 is Acc + A*B,
sum_prod(As, Bs, Acc1, SumProd).
sum_prod([], [], Acc, Acc).
If all items of your lists are integers and your Prolog implementation offers clpfd, you can simply use the
clpfd built-in predicate scalar_product/4, like this:
?- scalar_product([1,2,3],[4,5,6],#=,Product).
Product = 32.
Edit:
You may also be interested in the related question "Prolog: Multiplying 2 lists with 1 of them not instantiated?", particularly in this answer.
as an alternative to 'hand coded' loops, using library(aggregate) and nth1/3:
sum_prod(A,B,S) :-
aggregate(sum(M), I^X^Y^(nth1(I,A,X), nth1(I,B,Y), M is X*Y), S).

Arithmetic on Two Lists Prolog

So I have a HW problem I've been working on for a couple days and I'm stuck on the last part. In Prolog, I'm supposed to write a function that takes in two lists
((x1, x2, …, xn), (y1, y2, …yn) )
and finds the distance between both. The output is the result of the math done on the list.
Formula: sqrt((x1-y1)(x1-y1) + (x2-y2)(x2-y2) + … + (xn-yn)*(xn-yn))
Here's what I have so far:
distance([],[], 0).
distance([Ha|Ta],[Hb|Tb], Sum) :-
distance(Ta,Tb, Rest),
Sum is sqrt( (Ha-Hb)*(Ha-Hb)) + Rest.
Prolog has lists, not arrays.
Your code doesn't implement the formula shown, because sqrt must be computed after the sum of products. In the code below, I introduce also an accumulator, making the loop tail recursive (more efficient).
distance(Xs, Ys, Dist) :-
distance(Xs, Ys, 0, Dist).
distance([], [], Acc, Dist) :-
Dist is sqrt(Acc).
distance([X|Xs], [Y|Ys], Acc, Dist) :-
Sum is (Y-X)*(Y-X) + Acc,
distance(Xs, Ys, Sum, Dist).
Depending on your Prolog library, the code could be simpler:
distance(Xs, Ys, Dist) :-
foldl(distpoint, Xs, Ys, 0, Sq),
Dist is sqrt(Sq).
distpoint(X, Y, S, D) :- D is S+(Y-X)*(Y-X).
It is quite near. Off the top of my head, just sum the squares (distance_aux) and then return the square root of the accumulated sum:
distance(L1, L2, D) :-
distance_aux(L1, L2, SQSUM),
D is sqrt(SQSUM).
distance_aux([],[],0).
distance_aux([Ha|Ta],[Hb|Tb], Sum) :-
distance_aux(Ta,Tb, Rest),
Sum is (Ha-Hb)*(Ha-Hb) + Rest.
You can also add the simplified rule distance([], [], 0)., although it is not necessary.
The formula you have given squares the entire summation, rather than squaring each individual couple - which is what you are doing in your code. Using an auxiliary solves that issue:
distance_sum([], [], 0).
distance_sum([Ha|Ta], [Hb|Tb], Sum) :-
distance_sum(Ta, Tb, Rest),
Sum is ((Ha-Hb) * (Ha-Hb)) + Rest.
distance(A, B, Sum) :- distance_sum(A, B, DSum), Sum is sqrt(DSum).
So an example would be:
distance([1,2,3], [4,5,6], Sum).
Sum = 5.196152422706632.
Working:
sqrt( (1-4)*(1-4) + (2-5)*(2-5) + (3-6)*(3-6) )
sqrt( 3*3 + 3*3 + 3*3 )
sqrt( 27 )
5.19615