Object Oriented Optimization
Author 
Message 
relaxmik #1 / 9

Object Oriented Optimization
Hi, I have the following problem with reusing a fortran 77 optimization method in the context of an objectoriented (more precisely object based) fortran 90 software. The goal of my message is to submit the solution that I found and the problem that I did not solve to the fortran gurus of the forum, especially fortran 90 objectbased gurus. The problem that I have is on how to design a reusable optimization method. I have an existing fortran 77 optimization method in which the user must provide a function which role is to compute the objective and the constraints. This function must follow a given template with a predefined name : double precision function fonc ( x , co , ifonc ) implicit none double precision, dimension (:), intent(in) :: x double precision, dimension (:), intent(out) :: co integer, intent(inout) :: ifonc end function fonc The array "x" is the parameter, the value of "fonc" is the objective, the array "co" is the constraints and ifonc is an error flag. This an overview of the call tree : client code  + f77_solver ()  + < ... bla ...>  + fonc The problem is that we have to use the same optimization method with several objectives and constraints. But if we put specific code in the function "fonc", we can only have one optimization problem available for one executable because all this is defined in a static way. One solution would have been to modify the optimization fortran 77 source code, so that the "solve" subroutine takes as an argument the "fonc" function. This would have been solved at compiletime to call the specific function. A template "solve" subroutine would be this one : subroutine f77_solver ( fonc_function ) implicit none interface double precision function fonc_function ( x , co , ifonc ) implicit none double precision, dimension (:), intent(in) :: x double precision, dimension (:), intent(out) :: co integer, intent(inout) :: ifonc end function fonc_function end interface ! Sometime later : obj = fonc_function ( x , co , ifonc ) end subroutine f77_solver In the client code, one pass the function to the optim_solve subroutine : call optim_solve ( myfonc1 ) call optim_solve ( myfonc2 ) etc... This method must not be confused with the function pointers, as they are defined in the C language. All this fortran source is defined in a static way, which is predefined at compiletime. It is not defined at runtime, as in can be in C. The problem is that the "optim_solve" subroutine does not do the resolution by itself. Instead, it uses a complex call tree in which the "fonc" function is called several times by several subroutines at different levels. This solution would imply to modify the complex fortran 77 source code, which would have been timeconsuming and which could have created (additional) bugs. Another solution to that problem is the "reverse communication" pattern. In that type of method, each time that the solver needs to compute the objective, the solver sets an output flag to a particular value, then returns. See Dongarra's article : http://www.***.com/ A sample use of reverse communication is NLPQL : http://www.***.com/ ~kschittkowski/nlpqlp... A discussion on reversecommunication has allready been done on comp.lang.fortran : http://www.***.com/ Depending on the returning value of flag of the solver, the client code knows the current situation :  the algorithm is finished (and, may be, converged),  one has to compute the objective. If one has to compute the objective, one does so and calls the solver again. This is an elegant method to create an optimization method which has no static link to the computation method. The optimization solver is, with reverse communication, really reusable, without any modification by the client code. But the problem is for us that we should modify the existing fortran 77 source code. The algorithm which is behind reverse communication seems to imply a lot of modifications, which is time consuming etc... I also thought about a preprocessing trick, based on macro definitions. But I haven't found anything simple with that idea. In fact, what we really need is a function pointer similar to what exist in C. This would allow to set the pointer before calling the solver, then call the solver which can evaluate the objective whenever and wherever it has to. But function pointers do not exist in fortran 77, 90, 95 (2000 ?) so I had to find another solution. I got to the following solution, where the function pointer is emulated by an integer flag. The idea is to define a unique external function "fonc", which then calls a function "optdrive_fonc" which is located in a fortran 90 module. The function "optdrive_fonc" changes its behaviour depending on the value of the integer flag (=the function pointer). See for example the function fonc calling the function optdrive_fonc : double precision function fonc ( x , co , ifonc ) use m_driver_optim, only : optdrive_fonc implicit none double precision, dimension (:), intent(in) :: x double precision, dimension (:), intent(out) :: co integer, intent(inout) :: ifonc fonc = optdrive_fonc ( x , co , ifonc ) end function fonc The function optdrive_fonc let us choose between several optimization functions where each one corresponds to a specific optimization problem. module m_driver_optim ! Objective function to optimize integer, public :: objective_function integer, parameter, public :: PB1 = 1 integer, parameter, public :: PB2 = 2 contains double precision function optdrive_fonc ( x , co , ifonc ) implicit none double precision, dimension (:), intent(in) :: x double precision, dimension (:), intent(out) :: co integer, intent(inout) :: ifonc external test_fonc double precision :: test_fonc external optm_fonc2 double precision :: optm_fonc2 select case ( objective_function ) case ( PB1 ) optdrive_fonc = test_fonc1 ( x , co , ifonc ) case ( PB2 ) optdrive_fonc = test_fonc2 ( x , co , ifonc ) case default ! TODO : generate an exception. end select end function optdrive_fonc end module m_driver_optim In the client of the optimization method, it is easy to configure the problem by a simple set of the objective_function variable. use m_driver_optim, only : objective_function, PB1, PB2 objective_function = PB1 call f77_solver () This solution is simple and efficient. But the problem which remains is that the evaluation of the objective cannot be done with the parameter array "x" by itself. Some additional data have to be provided. The traditional "fortran 77" way is to put additional data in a global variable, accessed with a COMMON. In Fortran 90, this can be done with a derivedtype. That derivedtype can be defined in the "test_fonc1" function or in the "m_driver_optim" module itself. For example : module m_driver_optim use m_fonc_module, only : test_fonc3, DATATYPE type ( DATATYPE ) , save :: mydata contains double precision function optdrive_fonc ( x , co , ifonc ) implicit none double precision, dimension (:), intent(in) :: x double precision, dimension (:), intent(out) :: co integer, intent(inout) :: ifonc external test_fonc double precision :: test_fonc select case ( objective_function ) case ( FONC1 ) optdrive_fonc = test_fonc1 ( x , co , ifonc ) case ( FONC3 ) optdrive_fonc = test_fonc3 ( mydata , x , co , ifonc ) case default ! TODO : generate an exception. end select end function optdrive_fonc end module m_driver_optim That solution is used in the context of an optimization fortran 90 module, developed following the ideas of objectbased programming. That module is based on personal ideas and external influences, but I recently discovered (!) that similar ideas have been presented in http://www.***.com/ or since at least 10 years : http://www.***.com/ or : http://www.***.com/ ~szymansk/oof90.html and that a discussion on this subject has taken place here : http://www.***.com/ While my message is not completely linked to that subject, it is not independent. I think that I am not alone to have these kinds of "how to reuse a fortran 77 code" problems. Any comments or suggestions are welcomed. Best regards, Micha?l

Mon, 10 May 2010 23:03:45 GMT 


Reinhold Bade #2 / 9

Object Oriented Optimization
BEGIN PGP SIGNED MESSAGE Hash: SHA1 [snip] Quote: > But function pointers do not exist in fortran 77, 90, 95 (2000 ?) so I > had to > find another solution.
Pointers to procedures (including functions) are allowed by the Fortran 2003 standard, but not widely available in compilers yet. g95 does have a partial implementation, though. Quote: > Best regards, > Micha?l
Regards Reinhold BEGIN PGP SIGNATURE Version: GnuPG v1.4.2 (GNU/Linux) Comment: Using GnuPG with SUSE  http://enigmail.mozdev.org iD8DBQFHRZ3BFVLhKuD7VgsRAgi6AJsGF+CjTS3T/b2TZbK8lmDOo9h2SgCfQhh8 iMX/z2/40+gZVcLxnpZf9YQ= =4d7/ END PGP SIGNATURE

Mon, 10 May 2010 23:18:25 GMT 


Arjen Marku #3 / 9

Object Oriented Optimization
Quote: > One solution would have been to modify the optimization fortran 77 > source > code, so that the "solve" subroutine takes as an argument the "fonc" > function. This would have been solved at compiletime to call the > specific function. A template "solve" subroutine would be this one : > subroutine f77_solver ( fonc_function ) > implicit none > interface > double precision function fonc_function ( x , co , ifonc ) > implicit none > double precision, dimension (:), intent(in) :: x > double precision, dimension (:), intent(out) :: co > integer, intent(inout) :: ifonc > end function fonc_function > end interface > ! Sometime later : > obj = fonc_function ( x , co , ifonc ) > end subroutine f77_solver > In the client code, one pass the function to the optim_solve > subroutine : > call optim_solve ( myfonc1 ) > call optim_solve ( myfonc2 ) > etc... > This method must not be confused with the function pointers, as they > are > defined in the C language. All this fortran source is defined in a > static way, which is predefined at compiletime. It is not defined at > runtime, as in can be in C. > The problem is that the "optim_solve" subroutine does not do the > resolution by itself. Instead, it uses a complex call tree in which > the > "fonc" function is called several times by several subroutines at > different levels. This solution would imply to modify the complex > fortran 77 source code, which would have been timeconsuming and which > could have created (additional) bugs.
If you pass the name of the function around as a dummy argument, adding it to each subroutine and function that uses "fonc", I doubt this would introduce many bugs. It would actually be the simplest solution and compatible with FORTRAN 77 at that. But if, indeed, you can not change the source code for this reason or others, then an implementation with a runtime parameter that selects the actual function to do the work is the best you can achieve, IMHO. It is not a bad solution either, even though function pointers like Reinhold suggests are more elegant. One alternative, but do not take it too seriously, is to use something like this: ! Objective function A module optim_a contains double precision fonc( ... ) ... objective function A end function include 'sourceforoptimisation.f' end module ! Objective function B module optim_b contains double precision fonc( ... ) ... ojective function B end function include 'sourceforoptimisation.f' end module module optimise use optim_a, solver_a => solver use optim_b, solver_b => solver end module Then you can use solver_a to solve the problem with objective function A and solver_b to solve it with objective function B. Drawbacks are of course:  Your code must use "end subroutine" and "end function" instead of merely "end"  The source code must be available to any user who programs another objective function.  The program becomes larger than necessary due to all the copies of the optimisation code. But that is probably a very minor issue. Regards, Arjen

Tue, 11 May 2010 20:10:07 GMT 


alexzen #4 / 9

Object Oriented Optimization
Quote: > In fact, what we really need is a function pointer similar to what > exist in C. > This would allow to set the pointer before calling the solver, then > call the solver which can evaluate the objective whenever and wherever > it has to. > But function pointers do not exist in fortran 77, 90, 95 (2000 ?) so I > had to > find another solution. > Any comments or suggestions are welcomed. > Best regards, > Micha?l
I do not know what Fortran 90 compiler you use. But existing Fortran compilers (Compaq Visual Fortran, gfortran and other) allow to use integer pointers (or Cray Pointers). They are similar to pointers in C .(Fortran pointers and Cray pointers are different statement). They are not enclosed in standard Fortran 90 and are an Fortran compiler extension . The example of their use, as well as possible realization object oriented approach you may find in http://alexzenk.nightmail.ru Best Regards, Alex

Wed, 12 May 2010 04:28:01 GMT 


alexzen #5 / 9

Object Oriented Optimization
Quote:
> > In fact, what we really need is a function pointer similar to what > > exist in C. > > This would allow to set the pointer before calling the solver, then > > call the solver which can evaluate the objective whenever and wherever > > it has to. > > But function pointers do not exist in fortran 77, 90, 95 (2000 ?) so I > > had to > > find another solution. > > Any comments or suggestions are welcomed. > > Best regards, > > Micha?l > I do not know what Fortran 90 compiler you use. > But existing Fortran compilers (Compaq Visual Fortran, gfortran and > other) allow to use integer pointers (or Cray Pointers). They are > similar to pointers in C .(Fortran pointers and Cray pointers are > different statement). > They are not enclosed in standard Fortran 90 and are an Fortran > compiler extension . The example of their use, as well as possible > realization object oriented approach you may find inhttp://alexzenk.nightmail.ru
or http://groups.google.com/group/comp.lang.fortran/browse_thread/thread... Quote: > Best Regards, > Alex

Wed, 12 May 2010 04:46:57 GMT 


Richard Mai #6 / 9

Object Oriented Optimization
Quote:
> > In fact, what we really need is a function pointer similar to what > > exist in C. > But existing Fortran compilers (Compaq Visual Fortran, gfortran and > other) allow to use integer pointers (or Cray Pointers)... > They are not enclosed in standard Fortran 90 and are an Fortran > compiler extension .
And the details of the extension vary from one compiler to another, that being one of the probelms with such extensions. One particular detail that varies is in whether they can point to functions. Just because your compiler supports Cray pointers doesn't mean that it supports them pointing to functions. My understanding is that most implementations of Cray pointers have not allowed this. In fact, I have been told by people who should know that Cray pointers as implemented by Cray did not support pointing to functions.  Richard Maine  Good judgement comes from experience; email: last name at domain . net  experience comes from bad judgement. domain: summertriangle   Mark Twain

Wed, 12 May 2010 04:51:53 GMT 


Gary Scot #7 / 9

Object Oriented Optimization
Quote:
>>>In fact, what we really need is a function pointer similar to what >>>exist in C. >>But existing Fortran compilers (Compaq Visual Fortran, gfortran and >>other) allow to use integer pointers (or Cray Pointers)... >>They are not enclosed in standard Fortran 90 and are an Fortran >>compiler extension . > And the details of the extension vary from one compiler to another, that > being one of the probelms with such extensions. One particular detail > that varies is in whether they can point to functions. Just because your > compiler supports Cray pointers doesn't mean that it supports them > pointing to functions. My understanding is that most implementations of > Cray pointers have not allowed this. In fact, I have been told by people > who should know that Cray pointers as implemented by Cray did not > support pointing to functions.
The most widely used compiler does support pointing to functions, and others implementing this extension should take note and correct their deficiency.  Gary Scott
Fortran Library: http://www.fortranlib.com Support the Original G95 Project: http://www.g95.org OR Support the GNU GFortran Project: http://gcc.gnu.org/fortran/index.html If you want to do the impossible, don't hire an expert because he knows it can't be done.  Henry Ford

Wed, 12 May 2010 04:56:57 GMT 


relaxmik #8 / 9

Object Oriented Optimization
Thank you to all for these answers. In fact, it is true that Cray Pointers are supported in gfortran. This work is not completely new (2005 at least) : http://gcc.gnu.org/onlinedocs/gfortran/Craypointers.html This is a work from Asher Langton : http://coding.derkeiler.com/Archive/Fortran/comp.lang.fortran/200510... http://www.math.wisc.edu/~langton/ Last week, I was able to find a poster with some more informations, but now it seems that this pdf is not available anymore. Cray pointers are a great solution for my problem. It provides the last brick that I needed for the design of a generic framework to reuse an old fortran 77 optimization method into a OO fortran 90 code. With that, I was able to define the following derivedtype. It contains an integer "fonc_address" which is the address of the objective function of the problem. This is familiar to C developers. module m_optim type, public :: T_OPTIM private ! Number of variables (this is the "size" of the problem) integer :: nbvariables = 1 ! Other options are to be stored here ! double precision :: epsilon1, etc... ! default value set to 1, can be used to detect non initialized type ! Initial guess for the optimization process double precision, dimension(:), pointer :: initial_guess => NULL() ! Solution of the optimization problem double precision, dimension(:), pointer :: solution => NULL() ! Number of constraints integer :: nbconstraints ! Number of equality constraints integer :: nbconstraints_equality ! Number of inequality constraints integer :: nbconstraints_inequality ! value of the objective function after optimization double precision :: optimized_objective ! value of the constraints after optimization double precision, dimension(:), pointer :: optimized_constraints => NULL() ! If the optimization was fine, status = .true. (default). ! If the optimization went wrong, status = .false. logical :: status = .true. ! 1 : converged ! 0 : not converged ! State flag after optimization integer :: status_detailed =0 ! Display messages to the user logical :: display_messages = .false. ! Objective function address integer :: fonc_address end type T_OPTIM end module module m_optim Of course I do not detail the optim_new, optim_free, optim_set_initial_guess, etc... subroutines that come in the module m_optim to create, destroy, set and get the object. It is then easy to define one setter to configure the function to optimize. The client code gives a function as an input argument. The intrinsic "loc" function computes the address of the function, which is then stored in the "fonc_address". One can even check that the given function does corresponds with the expected interface. ! ! Set the objective function to optimize ! subroutine optim_set_objective_function ( this , new_objective_fonc ) implicit none type ( T_OPTIM ), intent(inout) :: this interface new_objective_fonc_interface double precision function new_objective_fonc ( x , co , ifonc ) implicit none double precision, dimension (1:), intent(in) :: x double precision, dimension (1:), intent(out) :: co integer, intent(inout) :: ifonc end function new_objective_fonc end interface new_objective_fonc_interface this % fonc_address = loc ( new_objective_fonc ) end subroutine optim_set_objective_function This setter can be used as in the following example. I suppose here that there is a function new_objective_fonc which interface is the same as the expected one. use m_optim, only : T_OPTIM , optim_set_objective_function type ( T_OPTIM ) :: myoptim call optim_set_objective_function ( myoptim, new_objective_fonc ) Now that the optimized objective is set, one can define an optimize function which is just a layer over the real function to evaluate. This allows to compute the real objective, but also to check that the objective has allready been defined. ! ! This fonction allows the generic module m_optim to compte the objective ! and the constraints. ! double precision function optim_fonc ( this , x , co , ifonc ) implicit none type ( T_OPTIM ), intent(inout) :: this double precision, dimension (1:), intent(in) :: x double precision, dimension (1:), intent(out) :: co integer, intent(inout) :: ifonc double precision :: fonc_pointee external fonc_pointee pointer ( fonc_pointer , fonc_pointee ) ! ! Check that there is a fonction pointer ! if (this % fonc_address == 0) then ! Raise your error ! endif ! ! Evaluate the objective ! fonc_pointer = this % fonc_address optim_fonc = fonc_pointee ( x , co , ifonc ) end function optim_fonc One can also think about counting the number of evaluations of that function, in order to measure the performance of the optimization method. One could also check that the size of the given x correspondinds with the number of variables of the problem. From that, it is easy to derive a specific optimize module from the general one. We must do that in that order, following the OO principles stating that the class must be created from the more general toward the more specific. module m_specific_optim [...] type, public :: T_OPTIMSPECIFIC private integer :: my_specific_variable ! ! A specific solver is a specialized kind of optim solver ! type (T_OPTIM) :: myoptim end type T_OPTIMSPECIFIC end module m_specific_optim I was able to define an external function named "fonc", with global scope, which is called from the old fortran 77 optimization method. In that function "fonc", it is easy to compute the objective function by calling the objective function defined in the module m_optim. double precision function fonc ( x , co , ifonc ) use m_optim, only : optim_fonc use m_optim_nlpgr, only : myoptim_function [...] fonc = optim_fonc ( myoptim_function , x , co , ifonc ) end function fonc The fact that the fortran 77 function does not provide the object "myoptim" is not a problem. One cas easily create a static optim member, called here "myoptim_function". The fortran "save" attribute allows to store the optim object from the time is is set to the time it is used. The small ugly thing is that it is public for the direct access from the fonc function. module m_specific_optim [...] type (T_OPTIM), save, public :: myoptim_function end module m_specific_optim In the module m_specific_optim, I defined a subroutine "specific_solve", which job is to run the oldfashioned fortran 77 optimization method. Just before the launch of the specific solve method, one stores the myoptim object for later reuse in the "fonc" function : subroutine specific_solve ( this ) implicit none type(T_OPTIMSPECIFIC), intent(inout) :: this myoptim_function = this % myoptim call my_old_fashioned_fortran77_code () end subroutine specific_solve I think that the current solution provides an extensible pattern for the development and use of an optimization method in fortran. I am opened to comments on that way of designing a fortran 90 optimization method. Best regards, Micha?l

Tue, 25 May 2010 20:32:17 GMT 


glen herrmannsfeld #9 / 9

Object Oriented Optimization
Quote:
> In fact, it is true that Cray Pointers are supported in gfortran.
(snip) Quote: > Cray pointers are a great solution for my problem. > It provides the last brick that I needed for the design of > a generic framework to reuse an old fortran 77 optimization > method into a OO fortran 90 code. > With that, I was able to define the following derivedtype. > It contains an integer "fonc_address" which is the address of the > objective function of the problem. This is familiar to > C developers.
Yes, function pointers didn't appear until Fortran 2003. I would hope that they would be a better solution to your problem, but until they are available, I suppose Cray pointers are fine. Fortran 2003 also has C pointers, I believe including function pointers, but they might also not be available yet. (The ability to pass a subroutine or function name as an actual argument, and call that function from the called routine has been part of Fortran probably since the beginning of user written functions. The ability to store that in a variable, unfortunately, took a little longer.) Quote: > Of course I do not detail the optim_new, optim_free, > optim_set_initial_guess, etc... subroutines that come > in the module m_optim to create, destroy, set and get > the object.
(snip) Quote: > I think that the current solution provides an extensible > pattern for the development and use of an optimization method > in fortran. > I am opened to comments on that way of designing a fortran 90 > optimization method.
I would hope that when Fortran 2003 function pointers are available you would find those an even better, and more standard, solution.  glen

Tue, 25 May 2010 20:54:40 GMT 


