Getting the minimum value of a list - list

I am trying to find the minimum value of a list (as a learning experience, so without min).
My approach is the following:
minimo([X], X).
minimo([X,Y|Tail], N):-
(X > Y, minimo([Y,Tail], Y));
(X <= Y, minimo([X,Tail], X)).
This gives me the following error:
Syntax error: Operator expected
So my questions are:
What is causing the syntax error?
I will try it myself once that is fixed if it actually gives the correct value back, but would this actually be a correct approach?
Thanks in advance.

There are several bugs in your program:
as pointed out by Joe Lehmann, there is no '<='/2. It must be '=<'/2.
when you call minimo/2 recursively, you construct the lists wrong. Instead of [Y,Tail] use [Y|Tail]. Otherwise, you get a list with a list as second element.
you bind the second argument of the recursive call of minimo/2 to Y or X. Instead it must be bound to N. Otherwise, your N will never be instantiated.
You can improve your program further by adding cuts or using if-then-else ('->' + ;):
minimo([X], X) :- !.
minimo([X,Y|Tail], N):-
( X > Y ->
minimo([Y|Tail], N)
;
minimo([X|Tail], N)
).

In addition to the other versions posted already, consider also a version without if-then-else, and using a more descriptive name for the relation (which relates a list to its minimum):
list_min([L|Ls], Min) :- list_min(Ls, L, Min).
list_min([], Min, Min).
list_min([L|Ls], Min0, Min) :-
Min1 is min(L, Min0),
list_min(Ls, Min1, Min).
Such a pattern is called a fold (from the left), and we can write it equivalently using `foldl/4:
list_min([L|Ls], Min) :- foldl(min_, Ls, L, Min).
min_(A, B, Min) :- Min is min(A, B).
Example query:
?- list_min([1,0,2], Min).
Min = 0.
Note though that this is not a true relation and cannot be used in all directions due to the use of low-level arithmetic. For example, if we try to use it in the other direction, we get:
?- list_min([X,Y], 3).
ERROR: is/2: Arguments are not sufficiently instantiated
To make it a true solution, use constraints like clpfd and clpq. For example, for a solution over integers:
:- use_module(library(clpfd)).
list_min([L|Ls], Min) :- foldl(min_, Ls, L, Min).
min_(A, B, Min) :- Min #= min(A, B).
This works in all directions:
?- list_min([X,Y], 3).
X in 3..sup,
3#=min(Y, X),
Y in 3..sup.

The syntax error is, because less or equal in Prolog is =<, not <=.
I think the approach will work, but you really should avoid ; in a clause. Just split it up into two clauses.
Also I think that you want to do something like [X|Tail] in the recursion rather than [X,Tail]

min([H|T], Min) :- min(T, H, Min).
min([], Min, Min).
min([H|T], Min, Min1) :-
( H < Min
-> min(T, H, Min1)
; min(T, Min, Min1) ).

Related

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

Prolog program won't compute variable answer?

This should be an easy fix, but I can't seem to tackle this, and it's getting frustrating. I've coded a program which computes or verifies that two lists are related because the elements of the second list are all incremented by one from the elements of the first list. This works when two lists are given, but not when it needs to compute a list.
Code is as follows:
inc([], []).
inc([X|XS],[Y|YS]) :-
Y =:= X+1,
inc(XS,YS).
ERROR: =:=/2: Arguments are not sufficiently instantiated
Any help would be greatly appreciated!
Your problem is essentially that =:=/2 is for testing rather than establishing bindings, though is/2 still doesn't really do what you want. For instance, while 2 is 1 + 1 is true, 2 is X+1 will not result in X being bound to 1, because is/2 expects there to be just one variable or value on the left and one expression on the right, and it does not behave "relationally" like the rest of Prolog. If you want arithmetic that behaves this way, you should check out clpfd; looking at the complexity it adds is a good explanation for why things are the way they are.
Fortunately, you don't need all of arithmetic to solve your problem. The succ/2 builtin will do exactly what you need, and bonus, you get a one line solution:
inc(X, Y) :- maplist(succ, X, Y).
In use:
?- inc([1,2,3], [2,3,4]).
true.
?- inc([1,2,3], X).
X = [2, 3, 4].
?- inc(X, [1,2,3]).
X = [0, 1, 2].
Your code also works fine if you use succ/2 instead of =:=/2:
inc([], []).
inc([X|XS],[Y|YS]) :-
succ(X, Y),
inc(XS,YS).
This must be the "easy fix" you suspected. :)
I'm not sure what #mbratch is referring to about there being "too many variables" for one predicate. I suspect this is a misunderstanding of Prolog on their part, perhaps a holdover from other languages where a function can return one value or something. There is no technical limitation here; predicates can take as many ground or nonground arguments and bind as many of them as you want; the limiting factor is your creativity.
Similarly, I don't think "asymmetry" is a meaningful concept here. It's quite normal to define predicates that have just a single instantiation pattern, but it's also normal and preferable to make predicates that are flexible about instantiation—you can't know ahead of time what uses may be needed in the future. You might think to yourself that an instantiation pattern that destroys information might preclude the inverse instantiation pattern, but in practice, frequently you can turn it into a generator instead.
To give a trite example, append/3's name seems to imply this pattern:
?- append([1,2], [3,4], X).
X = [1,2,3,4]
That's a perfectly good use, but so is:
?- append(X, Y, [1,2,3,4]).
This is a non-deterministic instantiation pattern and will produce five solutions:
X = [], Y = [1,2,3,4]
X = [1], Y = [2,3,4]
X = [1,2], Y = [3,4]
X = [1,2,3], Y = [4]
X = [1,2,3,4], Y = []
This seems to stand in contradiction to some of #mbratch's ideas, but there's no explicit testing for ground/nonground in the usual definition of append/3, because it isn't necessary, and likewise with the second calling pattern you get two "return values" from one input. SWI source:
append([], L, L).
append([H|T], L, [H|R]) :-
append(T, L, R).
Edit: Negative numbers. I forgot that succ/2 is defined only on positive integers. We can apply #mbratch's technique and still get a tidy solution with the desired properties:
isucc(X, Y) :- var(X), X is Y-1.
isucc(X, Y) :- Y is X+1.
inc(X, Y) :- maplist(isucc, X, Y).
In action:
?- inc(X, [-1,2]).
X = [-2, 1] ;
false.
Edit: Using clp(fd) (via #mat):
fdsucc(X,Y) :- Y #= X + 1.
inc(X, Y) :- maplist(fdsucc, X, Y).
This generates even for the most general query:
?- inc(X, Y).
X = Y, Y = [] ;
X = [_G467],
Y = [_G476],
_G467+1#=_G476 ;
X = [_G610, _G613],
Y = [_G622, _G625],
_G610+1#=_G622,
_G613+1#=_G625 ;
X = [_G753, _G756, _G759],
Y = [_G768, _G771, _G774],
_G753+1#=_G768,
_G756+1#=_G771,
_G759+1#=_G774
...
The utility of this is questionable, but presumably since you're using clp(fd) you'll eventually impose other constraints and get something useful.
inc([],[]).
inc([X|XS],[Y|YS]) :-
nonvar(X),
Z is X + 1,
Y = Z,
inc(XS,YS), !.
inc([X|XS],[Y|YS]) :-
nonvar(Y),
Z is Y - 1,
X = Z,
inc(XS,YS), !.
Here we need to get a real computation for the addition, then attempt instantiation with =. The predicate had to be split to deal with the case where X was not instantiated, versus when Y wasn't. The ! at the end of each is to prevent it from trying for more solutions after it has found one through one of the two similar paths.

Prolog-Multiplying a list with a list of lists

I'm trying to simulate a product of a matrix with a vector using these two predicates:
eva([], [], []).
eva([A|A1], [W], [Res|R1]) :-
vectormultiplication(A, W, Res),
eva(A1, W, R1).
vectormultiplication([A], [W], [A*W]).
vectormultiplication([A|A1], [W|W1], [A*W|Out1]) :-
vectormultiplication(A1, W1, Out1).
Where the [A|A1] in eva is a matrix (or a list of lists), [W] is a vector (a list),and [Res|R1] is the resulting product. vectormultiplication is supposed to go multiply each list in the list with the vector W. However, this strategy just produces a false response. Is there anything apparent that I'm doing wrong here that prevents me from getting the desired product? I'm currently using SWI Prolog version 5.10
you have 2 other problems apart that evidenced by Daniel (+1): here a cleaned up source
eva([], _, []). % here [] was wrong
eva([A|A1], W, [Res|R1]) :- % here [W] was wrong
vectormultiplication(A, W, Res),
eva(A1, W, R1).
vectormultiplication([A], [W], [M]) :-
M is A*W.
vectormultiplication([A|A1], [W|W1], [M|Out1]) :-
M is A*W,
vectormultiplication(A1, W1, Out1).
test:
?- eva([[1,2],[3,5]],[5,6],R).
R = [[5, 12], [15, 30]]
when handling lists, it's worth to use maplist if available
eva(A, W, R) :-
maplist(vectormultiplication1(W), A, R).
vectormultiplication1(W, A, M) :-
maplist(mult, A, W, M).
mult(A, W, M) :-
M is A*W.
Note I changed the order of arguments of vectormultiplication1, because the vector is a 'constant' in that loop, and maplist append arguments to be 'unrolled'.
Well, your first problem is that you think A*W is going to do anything by itself. In Prolog, that's just going to create the expression A*W, no different from *(A,W) or foo(A, W)--without is/2 involved, no actual arithmetic reduction will take place. That's the only real problem I see in a quick glance.

Prolog sum all the number in the 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.

Prolog, find minimum in a list

in short: How to find min value in a list? (thanks for the advise kaarel)
long story:
I have created a weighted graph in amzi prolog and given 2 nodes, I am able to retrieve a list of paths. However, I need to find the minimum value in this path but am unable to traverse the list to do this. May I please seek your advise on how to determine the minimum value in the list?
my code currently looks like this:
arc(1,2).
arc(2,3).
arc(3,4).
arc(3,5).
arc(3,6).
arc(2,5).
arc(5,6).
arc(2,6).
path(X,Z,A) :-
(arc(X,Y),path(Y,Z,A1),A is A1+1;arc(X,Z), A is 1).
thus, ' keying findall(Z,path(2,6,Z),L).' in listener allows me to attain a list [3,2,2,1].
I need to retrieve the minimum value from here and multiply it with an amount. Can someone please advise on how to retrieve the minimum value? thanks!
It is common to use a so-called "lagged argument" to benefit from first-argument indexing:
list_min([L|Ls], Min) :-
list_min(Ls, L, Min).
list_min([], Min, Min).
list_min([L|Ls], Min0, Min) :-
Min1 is min(L, Min0),
list_min(Ls, Min1, Min).
This pattern is called a fold (from the left), and foldl/4, which is available in recent SWI versions, lets you write this as:
list_min([L|Ls], Min) :- foldl(num_num_min, Ls, L, Min).
num_num_min(X, Y, Min) :- Min is min(X, Y).
Notice though that this cannot be used in all directions, for example:
?- list_min([A,B], 5).
is/2: Arguments are not sufficiently instantiated
If you are reasoning about integers, as seems to be the case in your example, I therefore recommend you use CLP(FD) constraints to naturally generalize the predicate. Instead of (is)/2, simply use (#=)/2 and benefit from a more declarative solution:
:- use_module(library(clpfd)).
list_min([L|Ls], Min) :- foldl(num_num_min, Ls, L, Min).
num_num_min(X, Y, Min) :- Min #= min(X, Y).
This can be used as a true relation which works in all directions, for example:
?- list_min([A,B], 5).
yielding:
A in 5..sup,
5#=min(B, A),
B in 5..sup.
This looks right to me (from here).
min_in_list([Min],Min). % We've found the minimum
min_in_list([H,K|T],M) :-
H =< K, % H is less than or equal to K
min_in_list([H|T],M). % so use H
min_in_list([H,K|T],M) :-
H > K, % H is greater than K
min_in_list([K|T],M). % so use K
%Usage: minl(List, Minimum).
minl([Only], Only).
minl([Head|Tail], Minimum) :-
minl(Tail, TailMin),
Minimum is min(Head, TailMin).
The second rule does the recursion, in english "get the smallest value in the tail, and set Minimum to the smaller of that and the head". The first rule is the base case, "the minimum value of a list of one, is the only value in the list".
Test:
| ?- minl([2,4,1],1).
true ?
yes
| ?- minl([2,4,1],X).
X = 1 ?
yes
You can use it to check a value in the first case, or you can have prolog compute the value in the second case.
This program may be slow, but I like to write obviously correct code when I can.
smallest(List,Min) :-
sort(List,[Min|_]).
SWI-Prolog offers library(aggregate). Generalized and performance wise.
:- [library(aggregate)].
min(L, M) :- aggregate(min(E), member(E, L), M).
edit
A recent addition was library(solution_sequences). Now we can write
min(L,M) :- order_by([asc(M)], member(M,L)), !.
max(L,M) :- order_by([desc(M)], member(M,L)), !.
Now, ready for a surprise :) ?
?- test_performance([clpfd_max,slow_max,member_max,rel_max,agg_max]).
clpfd_max:99999996
% 1,500,000 inferences, 0.607 CPU in 0.607 seconds (100% CPU, 2470519 Lips)
slow_max:99999996
% 9,500,376 inferences, 2.564 CPU in 2.564 seconds (100% CPU, 3705655 Lips)
member_max:99999996
% 1,500,009 inferences, 1.004 CPU in 1.004 seconds (100% CPU, 1494329 Lips)
rel_max:99999996
% 1,000,054 inferences, 2.649 CPU in 2.648 seconds (100% CPU, 377588 Lips)
agg_max:99999996
% 2,500,028 inferences, 1.461 CPU in 1.462 seconds (100% CPU, 1710732 Lips)
true
with these definitions:
```erlang
:- use_module(library(clpfd)).
clpfd_max([L|Ls], Max) :- foldl([X,Y,M]>>(M #= max(X, Y)), Ls, L, Max).
slow_max(L, Max) :-
select(Max, L, Rest), \+ (member(E, Rest), E #> Max).
member_max([H|T],M) :-
member_max(T,N), ( \+ H#<N -> M=H ; M=N ).
member_max([M],M).
rel_max(L,M) :-
order_by([desc(M)], member(M,L)), !.
agg_max(L,M) :-
aggregate(max(E), member(E,L), M).
test_performance(Ps) :-
test_performance(Ps,500 000,_).
test_performance(Ps,N_Ints,Result) :-
list_of_random(N_Ints,1,100 000 000,Seq),
maplist({Seq}/[P,N]>>time((call(P,Seq,N),write(P:N))),Ps,Ns),
assertion(sort(Ns,[Result])).
list_of_random(N_Ints,L,U,RandomInts) :-
length(RandomInts,N_Ints),
maplist({L,U}/[Int]>>random_between(L,U,Int),RandomInts).
clpfd_max wins hands down, and to my surprise, slow_max/2 turns out to be not too bad...
SWI-Prolog has min_list/2:
min_list(+List, -Min)
True if Min is the smallest number in List.
Its definition is in library/lists.pl
min_list([H|T], Min) :-
min_list(T, H, Min).
min_list([], Min, Min).
min_list([H|T], Min0, Min) :-
Min1 is min(H, Min0),
min_list(T, Min1, Min).
This is ok for me :
minimumList([X], X). %(The minimum is the only element in the list)
minimumList([X|Q], M) :- % We 'cut' our list to have one element, and the rest in Q
minimumList(Q, M1), % We call our predicate again with the smallest list Q, the minimum will be in M1
M is min(M1, X). % We check if our first element X is smaller than M1 as we unstack our calls
Similar to andersoj, but using a cut instead of double comparison:
min([X], X).
min([X, Y | R], Min) :-
X < Y, !,
min([X | R], Min).
min([X, Y | R], Min) :-
min([Y | R], Min).
Solution without "is".
min([],X,X).
min([H|T],M,X) :- H =< M, min(T,H,X).
min([H|T],M,X) :- M < H, min(T,M,X).
min([H|T],X) :- min(T,H,X).
thanks for the replies. been useful. I also experimented furthur and developed this answer:
% if list has only 1 element, it is the smallest. also, this is base case.
min_list([X],X).
min_list([H|List],X) :-
min_list(List,X1), (H =< X1,X is H; H > X1, X is X1).
% recursively call min_list with list and value,
% if H is less than X1, X1 is H, else it is the same.
Not sure how to gauge how good of an answer this is algorithmically yet, but it works! would appreciate any feedback nonetheless. thanks!
min([Second_Last, Last], Result):-
Second_Last < Last
-> Result = Second_Last
; Result = Last, !.
min([First, Second|Rest], Result):-
First < Second
-> min([First|Rest], Result)
; min([Second|Rest], Result).
Should be working.
This works and seems reasonably efficient.
min_in_list([M],M).
min_in_list([H|T],X) :-
min_in_list(T,M),
(H < M, X = H; X = M).
min_list(X,Y) :- min_in_list(X,Y), !.
smallest(List,X):-
sort(List,[X|_]).
% find minimum in a list
min([Y],Y):-!.
min([H|L],H):-min(L,Z),H=<Z.
min([H|L],Z):-min(L,Z),H>=Z.
% so whattaya think!