From: ercolessi@uimrl3.mrl.uiuc.edu (furio ercolessi)
Subject: Re: "Minimize any function, as long as it is named FUNC"
Reply-To: ercolessi@uimrl3.mrl.uiuc.edu (furio ercolessi)
Organization: MRL - UIUC
Date: Sat, 9 Jan 1993 23:32:08 GMT

In article <C0K4Hx.110@news.cso.uiuc.edu>, I wrote:
|>In the Fortran edition of Numerical Recipes that I have (1989), they
|>have implemented multidimensional minimization routines that
|>can minimize any function, provided that it is called FUNC.
|> [...]
|>Now, I am bothered by this because I need to minimize many
|>different, unrelated functions in the same program.
|> [...]
|>They have done this stupid thing because of an interface routine
|>between multi- and one- dimensional minimization, called LINMIN
|>and minimizing the original function on a line between two points
|>in N-space. This is in turn done by using the ordinary one variable
|>optimization on a function they call F1DIM, which internally calls
|>the user's function, but it cannot gather its name from outside
|>because the argument list must contain only the coordinate and
|>nothing else in order to be used successfully by the lower layers.
|>And of course a function address cannot be placed into a common block.

Many people pointed to me by e-mail that a way to solve the problem
could be:
   to add a function argument to the appropriate numerical
   recipes subroutines and their calls, and then to pass the function to
   the top numerical recipes subroutine as an argument.
I thank you all, but yes, I considered this and this is not an elegant
solution.  If it were, they would have done it already.

I attempt to explain below in more detail what the problem is.
It is quite entangled and technical, so if you are not interested
skip now.

* They have implemented a one-variable minimization package.
   This is well done: it accepts the user's function as an argument.
   The function is called BRENT and goes like that:
      FUNCTION BRENT(....,F,....)
      ...
      code that looks for the minimum of F(x).
      F is the user function, passed from outside.
      ...

* So far, so good. Then they consider multidimensional minimization.
   There are a number of routines using different strategies.
   Many of them require internally to execute one-dimensional
   minimizations.  Typically, along one line connecting two points
   in N-dimensional space.  So they want to do it with the BRENT
   above.  But now, the function to minimize is not the user's function,
   which is N-dimensional.  It's an auxiliary function defined from the
   user function, projecting it onto a line.  They call this function F1DIM,
   and this is the function that will be fed to BRENT.

*  *Here the trouble arises*.  BRENT expects a F(x), NOT a F(x,.....).
   In fact, when you use BRENT to minimize a 1-dimensional function,
   there is no need to have any extra argument.  So, this F1DIM must
   be F1DIM(x) and nothing else.  But this F1DIM projects the user's
   function onto a line, so it needs to know the user's function as well
   as the two extremes of the line.  While the latter can be (and are)
   passed through an internal COMMON, there is nothing you can do
   for the function name.  So they hardcoded the infamous FUNC into it.
   At this point this constraint propagates down to the user interface
   of the N-dimensional routines, which do not have the function name
   in the argument list.

The solutions are:
1) Rewrite the one-dimensional minimization routines, to work on
   an axis embedded in N-space instead of on the x axis.  This
   complicates them considerably.  This is the solution that *they*
   suggest (on page 300 of my 1989 edition). I was hoping someone
   actually did it already ...
2) Modify BRENT so that it takes TWO functions in the argument
   list, the 1-dim one and the N-dim one.  The N-dim one is then
   internally passed as an additional argument to the 1-dim one,
   which should know what do with it.  If your user function is 1-dim,
   you can then still use BRENT and pass a dummy as the second
   function.  You function must have this function in the argument
   list but will do nothing with it.  When BRENT is called by the
   N-dimensional routines, it will receive instead F1DIM and the
   user function.  This is in practice what some of you suggested.
   As you can see, it is not very elegant in this case, but can
   certainly be done.
3) Exploit non-standard POINTER variables that some compilers
   have.  Perhaps, I can pass the function name to F1DIM inside
   a COMMON, which is not allowed by the standard.
4) Do it dirty and write a FUNC that calls my real functions
   by means of an internal switch operated by COMMON or by
   an ENTRY.     

None of them is elegant, but I guess I will pick up one ...
--
Furio Ercolessi
Materials Research Laboratory           |   Intl School for Advanced Studies
Univ. of Illinois at Urbana-Champaign   |   Trieste, Italy
furio@uiuc.edu                          |   furio@sissa.it