user10843110
user10843110

Reputation:

Prolog - Max value in recursion

Hello I doing a work for school and I'm trying to get the max number that is returning by a recursion. Let me explain better with examples:

I have this predicate:

li(_, []).
li(NAME, [H|T]) :- 
   find(NAME, H, Occur),
   li(NAME, T).

li(NAME) :- 
   findall(T, pri(name(T), _, _, _), Info),
   li(NAME, Info).

The predicate in line 2 (find), what it does is, by giving a name and some other information it will return to me a number (Occur). What I'm trying to do is to know what is the highets number (Occur) in the whole recursion.

Bellow I tried to do some comparations but it is not working, it says that Highest is not defined, I know that is becouse it don't have any value associated with it but I have not idea how to do this.

li(_, [], 0).
li(NAME, [H|T], Highest) :- 
   find(NAME, H, Occur),
   li(NAME, T, Temp),
   Temp is Occur, 
   Highest < Temp,
   Highest is Temp.

li(NAME) :- 
   findall(T, pri(name(T), _, _, _), Info), 
   li(NAME, Info, Return), 
   write(Return).

The goal is to write the number in the end of line 3. Does anyone know what I can do to fix this? Thank you.

EDIT

I gave another try and done this:

li(_, [], 0).
li(NAME, [H|T], Highest) :- 
   find(NAME, H, Occur), 
   li(NAME, T, Temp), 
   Temp < Occur, 
   Temp is Occur,
   Highest is Temp.

li(NAME) :- 
   findall(T, pri(name(T), _, _, _), Info), 
   li(NAME, Info, Return), 
   write(Return).

It doens't trigger any errors but nothing happens, a false is returned and nothing is printed.

EDIT2

Thank to @David Tonhofer, I now can get the highst number. But what I realy want is the name that is associated with that hight number.

li(NAME, [H|T], Highest, X) :- 
   find(NAME, H, Occur), 
   li(NAME, T, Temp), 
   Highest is max(Temp,Occur), X = ??.

I was going step by step and first trying to get the highest number then get the name, but with the MAX now I don't think I can know that.

At first I thought something like this:

li(_, [], 0).
li(NAME, [H|T], Highest, X) :- 
   find(NAME, H, Occur), 
   li(NAME, T, Temp), 
   Temp < Occur, 
   Temp is Occur,
   Highest is Temp, X is NAME.

li(NAME) :- 
   findall(T, pri(name(T), _, _, _), Info), 
   li(NAME, Info, Return, X), 
   write(Return), write(X).

Upvotes: 1

Views: 397

Answers (2)

CapelliC
CapelliC

Reputation: 60034

In SWI-Prolog, library(aggregate) is meant to provide an SQL-like solution for your problem:

?- L=[a:1, b:2, c:3], aggregate(max(V,N),member(N:V,L),Max).
L = [a:1, b:2, c:3],
Max = max(3, c).

Upvotes: 1

David Tonhofer
David Tonhofer

Reputation: 15338

Here is a problem:

li(NAME, [H|T], Highest) :- 
   find(NAME, H, Occur), 
   li(NAME, T, Temp), 
   Temp < Occur, 
   Temp is Occur,
   Highest is Temp.

This means:

  • Make sure that Temp < Occur, backtrack to try something else if not.
  • Then unify the numeric values Occur and Temp. As Temp already contains some value, this is the same as testing whether Occur and Temp are the same value, and backtrack to try something else if not.
  • Then unify the numeric values Highest and Temp.

You seem to want Highest to take on the value of max(Occur,Temp).

In that case:

li(NAME, [H|T], Highest) :- 
   find(NAME, H, Occur), 
   li(NAME, T, Temp), 
   Highest is max(Temp,Occur).

This

  1. Computes the max(Temp,Occur) (works only if the values of Temp and Occur .are known at that point)
  2. Unifies the result with Highest. If Highest is still a fresh variable, this is similar to assignment. Otherwise, if Highest already contains something, it is similar to comparison.

Addendum

To get the "Name" that is associated with the maximum value obtained, you proceed the same way:

li(Name_max, [H|T], Temp_max) :- 
   find(Name_from_Head, H, Temp_from_Head),
   li(Name_from_Tail, T, Temp_from_Tail), 
   % let's just print what we have right now:
   format("From the Head, we get: Name = ~w, Temp = ~w", [Name_from_Head,Temp_from_Head]),
   format("From the Tail, we get: Name = ~w, Temp = ~w", [Name_from_Tail,Temp_from_Tail]),
   % now a little "helper predicate" can be used for clarity
   % we pass it the 4 logical variables containing names and temps
   % and the 2 logical variables that have been given to "li/3"
   % to fill in with the best data:
   select_max(Name_from_Tail, Temp_from_Tail,
              Name_from_Head, Temp_from_Head,
              Name_max, Temp_max),
    % and we are done; just a printing before returning for fun
   format("Our current max: Name = ~w, Temp = ~w", [Name_max,Temp_max]).


% The helper predicate has two clauses for the two 
% mutually exclusive alternatives
% (the "=:=" case is in the first clause, arbitrarily)

select_max(Name_from_Tail, Temp_from_Tail,
           Name_from_Head, Temp_from_Head,
           Name_from_Tail, Temp_from_Tail) :- 
   Temp_from_Tail >= Temp_from_Head.

select_max(Name_from_Tail, Temp_from_Tail,
           Name_from_Head, Temp_from_Head,
           Name_from_Head, Temp_from_Head) :- 
   Temp_from_Tail < Temp_from_Head.

For the helper predicate you could also write, perhaps more clearly:

select_max(Name_from_Tail, Temp_from_Tail,
           Name_from_Head, Temp_from_Head,
           Name_max, Temp_max) :- 
   Temp_from_Tail >= Temp_from_Head, % Guard
   Name_max = Name_from_Tail,        % Constrain variables to be equal!
   Temp_max = Temp_from_Tail.

select_max(Name_from_Tail, Temp_from_Tail,
           Name_from_Head, Temp_from_Head,
           Name_max, Temp_max) :- 
   Temp_from_Tail < Temp_from_Head,  % Guard
   Name_max = Name_from_Head,        % Constrain variables to be equal!
   Temp_max = Temp_from_Head.

Upvotes: 1

Related Questions