passing functions with variable number of arguments as procedure arguments 
Author Message
 passing functions with variable number of arguments as procedure arguments

I have been trying to figure out how to use procedures as arguments to
other procedures, and this is a simple example of what i think is the
solution:

I have a module containing some testfunctions:

http://www.*-*-*.com/ ~bartv/downloads/test_proc_arguments/mod...

(Note that for now, all these testfunctions only have one argument x and
are not parameterized.  I would like to change this...)

I have another module which contains a function that takes one of these
testfunctions as an argument, together with the single argument x for the
testfunction:

http://www.*-*-*.com/ ~bartv/downloads/test_proc_arguments/mod...

Last but not least i have my main program which uses both these modules:

http://www.*-*-*.com/ ~bartv/downloads/test_proc_arguments/tes...

(Again, note that for now, all functions have a single argument and are not
parameterized)

In my application, the testfunctions are just a collection of
testfunctions for numerical integration.  The module that uses these
testfunctions has the routine simulate_monte_carlo(myfunction, x, ...) and
of course I want to be able to pass any function to this routine.

In my main program, I can then call simulate_monte_carlo and pass it
whatever function I want...

But there's one problem I do not know how to solve: the testfunctions I
want to pass each have a set of parameters they can use.  The number of
parameters and the meaning of the parameters is different for each
function.

So basically in test_proc_arguments.f95 i want to be able to say
something like:

print *, applyfunction(f1, x, param1, param2)

with param1 and param2 being specific parameters that define a specific
instance of the kind of functions f1, with a certain type of the difficulty.

To evaluate f1 in x, using parameters param1 and param2, but for another
function f2 i might want to say:

print *, applyfunction(f2, x, param1, param2, param3, param4)

Where the paramX parameters are totally different from the parameters
for function f1.

I have a Matlab background, and in Matlab this was possible via
something that is called 'variable argument lists' (the varargin
feature).

The only way to do it for now that I can think of is the following:

* check each of my testfunctions, and count how many parameters they need
* take the biggest number of parameters, and add so many parameters to
  the interface of my function to be passed as an argument
* give each of my testfunctions this maximum number of parameters, and
  in my main program do something like:

  print *, applyfunction(f1, x, param1=foo, param2=bar)
  print *, applyfunction(f2, x, param1=foo, param2=bar, param3=boo, param4=far)

Still... i have the feeling this is not the cleanest way of doing
things...

Is there a way to pass functions that have a variable number of parameters as
arguments to other procedures?

A minimalistic code example would be of great help here I guess...

Thanks,
Bart

--
        "Share what you know.  Learn what you don't."



Sun, 05 Aug 2007 00:12:11 GMT  
 passing functions with variable number of arguments as procedure arguments

Quote:

> I have been trying to figure out how to use procedures as arguments to
> other procedures, and this is a simple example of what i think is the
> solution:

> I have a module containing some testfunctions:

...

Quote:
> I have a Matlab background, and in Matlab this was possible via
> something that is called 'variable argument lists' (the varargin
> feature).

fortran does not allow variable argument lists, so you will
have to work your way around that limitation.

Quote:
> The only way to do it for now that I can think of is the following:

> * check each of my testfunctions, and count how many parameters they need
> * take the biggest number of parameters, and add so many parameters to
>   the interface of my function to be passed as an argument
> * give each of my testfunctions this maximum number of parameters, and
>   in my main program do something like:

>   print *, applyfunction(f1, x, param1=foo, param2=bar)
>   print *, applyfunction(f2, x, param1=foo, param2=bar, param3=boo, param4=far)

> Still... i have the feeling this is not the cleanest way of doing
> things...

> Is there a way to pass functions that have a variable number of parameters as
> arguments to other procedures?

> A minimalistic code example would be of great help here I guess...

Other ways you might want to explore:
1. Use an assumed-shape array of parameters, rather than a variable list
of arguments
2. Use a derived type to hold all the parameters, similar to the first
alternative,
   but now you can store different types and you can access them by name
3. Use data from a module. I am not sure that this is a very clean
solution
   either, but here is a sketch of the code:

   module parameters
       real :: foo, bar, baz
   end module

   real function f1(x)
      use parameters
      f1 = x**2 + foo + bar*x
   end function

Regards,

Arjen



Sun, 05 Aug 2007 16:13:32 GMT  
 passing functions with variable number of arguments as procedure arguments

Quote:

> Fortran does not allow variable argument lists, so you will
> have to work your way around that limitation.

OK.  Good to know :-)

Quote:
> Other ways you might want to explore:
> 1. Use an assumed-shape array of parameters, rather than a variable list
> of arguments

The parameters can also be vectors, so if I'm correct, this solution
would not work that well since I can't have a vector to be an element of
the assumed-shape array?  This solution would only work well if the
parameters are scalars I guess?

Quote:
> 2. Use a derived type to hold all the parameters, similar to the first
> alternative, but now you can store different types and you can access them
> by name

Hmmm... this might indeed be something to look at...

Quote:
> 3. Use data from a module. I am not sure that this is a very clean
> solution

I also don't think this is the best way...

I think I will check out the following two possibilities:

1) Work with OPTIONAL arguments
2) Use a derived type to hold all the parameters, and in a specific
function only use the parameters that i need

2) has the advantage I only have to pass 1 extra argument to the
function... so i might want to use that solution...

Thanks,
Bart

--
        "Share what you know.  Learn what you don't."



Sun, 05 Aug 2007 16:45:13 GMT  
 passing functions with variable number of arguments as procedure arguments

Quote:
> > 1. Use an assumed-shape array of parameters, rather than a variable
list
> > of arguments

> The parameters can also be vectors, so if I'm correct, this solution
> would not work that well since I can't have a vector to be an element
of
> the assumed-shape array?  This solution would only work well if the
> parameters are scalars I guess?

provided you're willing to take some uglyness, it is possible.
element 1 of the assumed size array would tell you how many vectors you
have (N)
element 1+1 ... 1+N gives you the length of each vector (L_i)
element 1+1+N+1+SUM(L_1...L_(i-1))...1+1+N+1+SUM(L_1..L_i) [?] is data.

Things would become a little less ugly if you write some
functions/subroutines that extract this info from the array:
get/set_number_of_vectors(a,N)
get/set_length_of_vector(a,i,L)
get/set_vector(a,i,v)

Joost



Sun, 05 Aug 2007 16:58:57 GMT  
 passing functions with variable number of arguments as procedure arguments

Quote:

> I think I will check out the following two possibilities:

> ...
> 2) Use a derived type to hold all the parameters, and in a specific
> function only use the parameters that i need

I am trying to implement this, but i come across a problem in
compiling... I currently have:

module mod_monte_carlo

use mod_datatypes

implicit none

type functionparams
  real(dp), dimension(:)              :: a, u, r, t
end type functionparams

contains

  subroutine sim_mc(x, func, params, exact, res, abs_err, rel_err)

    real(dp), intent(in)            :: x(:,:)
    interface
      function func(x, fparams) result (y)
        real(dp)                    :: x(:,:)
        type(functionparams)        :: fparams
        real(dp)                    :: y(size(x,dim=2))
      end function func
    end interface
    type(functionparams)            :: params

    .... and so on, not relevant enymore

When y try compiling this, I get the following error:

 FPARAMS is of undefined derived type FUNCTIONPARAMS

and

  Derived type FUNCTIONPARAMS used but not defined

Why am I getting this error?  I am declaring the derived type in the beginning of my module, so it should be known in the interface i declare, shouldn't it?

Regards,
Bart

--
        "Share what you know.  Learn what you don't."



Sun, 05 Aug 2007 17:34:36 GMT  
 passing functions with variable number of arguments as procedure arguments


Vandewoestyne >

Quote:
> Why am I getting this error?  I am declaring the derived type in the

beginning of my >module, so it should be known in the interface I declare,
shouldn't it?

No. Host association does not extend to interface blocks. But nor can you
reference the module from within the interface block since a module cannot
contain a reference to itself. This is exactly the example given on p. 91 of
"Fortran 90/95 Explained" (or p. 88 of "Fortran 95/203 Explained"). You need
to put the type definition in a separate module.

Regards,

Mike Metcalf



Sun, 05 Aug 2007 18:15:05 GMT  
 passing functions with variable number of arguments as procedure arguments

Quote:



........
> module mod_monte_carlo

> use mod_datatypes

> implicit none

> type functionparams
>   real(dp), dimension(:)              :: a, u, r, t
> end type functionparams

> contains

>   subroutine sim_mc(x, func, params, exact, res, abs_err, rel_err)

>     real(dp), intent(in)            :: x(:,:)
>     interface
>       function func(x, fparams) result (y)
>         real(dp)                    :: x(:,:)
>         type(functionparams)        :: fparams
>         real(dp)                    :: y(size(x,dim=2))
>       end function func
>     end interface
>     type(functionparams)            :: params

>     .... and so on, not relevant enymore

> When y try compiling this, I get the following error:

>  FPARAMS is of undefined derived type FUNCTIONPARAMS

> and

>   Derived type FUNCTIONPARAMS used but not defined

The usage you describe is not allowed in F95. This is detailed in M&R
Fortran 95/2003, section 18.4 when they describe a new statement
(import) in F2003 introduced just for this reason. Until you get a
Fortran 2003 compiler, your best option (I think) is to move the
declarations of type functionparams inside mod_datatypes
(and put a use for it in the subroutine interface).

Hope this helps
Salvatore Filippone



Sun, 05 Aug 2007 18:22:56 GMT  
 
 [ 7 post ] 

 Relevant Pages 

1. Argument parsing in C module with variable number of arguments

2. Variable number of arguments to procedures

3. passing by reference to variable argument functions

4. function with variable number of arguments

5. Character variable variable passed as a subroutine argument

6. F77-C: Passing Fortran FUNCTION as an argument for a C Function

7. Passing array valued functions as argument to function.

8. Procedures as arguments - set dummy arguments

9. Requiring arguments to be passed as keyword arguments

10. Multiple arguments, structured arguments [ LONG ] (was Re: dyadic functions)

11. HOw to pass stems as procedure arguments

12. Pass Procedure as Argument?

 

 
Powered by phpBB® Forum Software