From: Alex Mizrahi
Subject: argmax
Date: 
Message-ID: <47c6fbf2$0$90267$14726298@news.sunsite.dk>
coding armax functionality each time from scratch have bored me to hell, so 
i've decided to make a macro for this. i.e. simple case:

CL-USER> (with-find-optimal (check >)
           (loop for i from 1 to 100
                 do (check i)))
100
100

with key being a function:

CL-USER> (with-find-optimal (check > -)
           (loop for i from 1 to 100
                 do (check (cons i i))))
1
-1


with key being custom code:

CL-USER> (with-find-optimal (check >
                             (lambda (cons) (* (car cons) (cdr cons))))
           (loop for i from 1 to 100
                 do (check (cons i i))))
(100 . 100)
10000

i suspect i'm not the only one doing such macro, but i'm not able to find 
any of them, and don't even know how it could be called..
something tells me that fancy LOOP substitutions like ITERATE have this 
built-in, but it would be overkill to use ITERATE just for this thing.
also, with my macro CHECK is lexical function, so it can be used in fairly 
complex cases -- passed to other functions etc.

here's my code. i don't really like it (nor i like interface), but it seems 
to work..

(defmacro with-find-optimal ((check compare &optional key) &body body)
  (unless key (setf key 'identity))
  (with-gensyms (option optimal optimal-value initialized option-value)
    `(let (,optimal ,optimal-value ,initialized)
      (flet ((,check (,option)
        (let ((,option-value (,key ,option)))
   (if ,initialized
       (when (,compare ,option-value ,optimal-value)
         (setf ,optimal ,option
        ,optimal-value ,option-value))
       (setf ,optimal ,option
      ,optimal-value ,option-value
      ,initialized t)))))
 ,@body
 (values ,optimal ,optimal-value))))) 

From: Maciej Katafiasz
Subject: Re: argmax
Date: 
Message-ID: <fq725p$q74$2@news.net.uni-c.dk>
Den Thu, 28 Feb 2008 20:22:33 +0200 skrev Alex Mizrahi:

> i suspect i'm not the only one doing such macro, but i'm not able to
> find any of them, and don't even know how it could be called.. something
> tells me that fancy LOOP substitutions like ITERATE have this built-in,
> but it would be overkill to use ITERATE just for this thing. also, with
> my macro CHECK is lexical function, so it can be used in fairly complex
> cases -- passed to other functions etc.

Indeed, ITERATE has MAXIMIZING/MINIMIZING clauses just for that. I 
wouldn't say that switching is an overkill -- I find ITERATE much more 
readable (thanks to more lispy syntax), and in general, a bit more 
predictable than LOOP. It's also extensible, so you could add a new 
clause, say, OPTIMIZING expr BY, so that it'd work like all built-in 
clauses.

Cheers,
Maciej
From: Alan Crowe
Subject: Re: argmax
Date: 
Message-ID: <86ve46p96i.fsf@cawtech.freeserve.co.uk>
"Alex Mizrahi" <········@users.sourceforge.net> writes:

> coding armax functionality each time from scratch have bored me to hell, so 
> i've decided to make a macro for this. i.e. simple case:
> 
.
.
.
> CL-USER> (with-find-optimal (check > -)
>            (loop for i from 1 to 100
>                  do (check (cons i i))))
> 1
> -1

This example doesn't work

Argument N is not a NUMBER: (1 . 1).
   [Condition of type SIMPLE-TYPE-ERROR]

> here's my code. i don't really like it (nor i like interface), but it seems 
> to work..

I agree about the interface. It feels much more natural to
me to have the function take two arguments, the arg and the
value eg

(defmacro arg-max ((name &optional (test '>) (key 'identity)) &body code)
           (with-gensyms (initialized best-value-so-far 
                                      best-arg-so-far)
             `(let (,initialized
                    ,best-value-so-far
                    ,best-arg-so-far)
               (flet ((,name (arg value)
                        (if ,initialized
                            (when (,test (,key value)
                                         (,key ,best-value-so-far))
                              (setf ,best-value-so-far value
                                    ,best-arg-so-far arg))
                            (setf ,initialized t
                                  ,best-value-so-far value
                                  ,best-arg-so-far arg))))
                 ,@code
                 (unless ,initialized
                   (error "arg-max of empty set"))
                 (values ,best-arg-so-far
                         ,best-value-so-far)))))

CL-USER> (arg-max (hunt-pi <)
           (loop for x from 2.5l0 to 3.5 by 0.001 do (hunt-pi x (cos x))))
3.1420000304933637d0
-0.9999999170220304d0

Alan Crowe
Edinburgh
Scotland