×
INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Log In

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!

*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Students Click Here

Passing user-defined function as argument

Passing user-defined function as argument

Passing user-defined function as argument

(OP)
Hello,
Here is my main program:
...
use func
use mult
...
print*, my_function(func,dfunc)
...

Both func and dfunc are defined in module func:
...
function func(x)
real :: func
...
endfunction func

function dfunc
real, dimension(2) :: dfunc
...
endfunction dfunc

Also, my_function is defined in module mult likewise:
...
function my_function(func,dfunc)
real, external :: func
real, external :: dfunc
...
endfunction my_function

I get this error at compile-time:
"The shape matching rules of actual arguments and dummy arguments have been violated" referring to dfunc, which is an array of size 2.
What should I do?

Thanks!!

RE: Passing user-defined function as argument

Don't think the Fortran rules allow you to return an array as the result of a function.  It is better to make this a subroutine and possibly pass an allocatable array to it.

RE: Passing user-defined function as argument

If you name the function func in module func you get the error:
"MODULE attribute conflicts with PROCEDURE attribute"

RE: Passing user-defined function as argument

Yoo can define a function which return an array - see the function MatrixVector here:
http://www.tek-tips.com/viewthread.cfm?qid=1516435&page=8

And you can pass function name as an argument to other function - see here the functions trapezoid_rule and simpson_rule, which get as an argumement the function f which should be integrated:
http://www.tek-tips.com/viewthread.cfm?qid=1570169&page=1

Hovever passing the vector function as an argument to other function is problematic, because when I try to declare

CODE

  real function my_function(foo, bar, x, v)
    real, intent(in) :: x
    real, dimension(2), intent(in) :: v
    real :: foo
    real, dimension(2) :: reslt, bar
    integer :: i
    reslt = bar(v)
    ...
  end function
then g95 says

CODE

$ g95 funcargs.f95 -o funcargs
In file funcargs.f95:26

    reslt = bar(v)
                1
Error: Array index at (1) must be of INTEGER type

So you can only call the vector function in your function without passing it as an argument.
Hovever when the called function dfunc is declared in another module (funcs) than the caller function my_function (mult) then you need to declare use funcs in the module mult. Here is the complete example

funcargs.f95

CODE

module funcs
  implicit none
contains
  real function func(x)
    real, intent(in) :: x
    func = x*x
  end function func

  function dfunc(v)
    real, dimension(2), intent(in) :: v
    real, dimension(2) :: dfunc
    ! return
    dfunc(1) = v(1)
    dfunc(2) = v(2)
  end function dfunc
end module funcs

module mult
  use funcs
  contains
  real function my_function(foo, x, v)
    real, intent(in) :: x
    real, dimension(2), intent(in) :: v
    real :: foo
    real, dimension(2) :: reslt, bar
    integer :: i
    reslt = dfunc(v)
    my_function = foo(x) + reslt(1) + reslt(2)
  endfunction my_function
end module mult

program funcargs
  !use funcs
  use mult
  implicit none
  real :: x
  real, dimension(2) :: v
  x = 2
  v = (/3, 4/)
  write (*, *) my_function(func, x, v)
end program funcargs
Output:

CODE

$ g95 funcargs.f95 -o funcargs
$ funcargs
 11.

RE: Passing user-defined function as argument

(OP)
not that I dont like your answer but I really knew it. the problem is that I have many different "dfunc", not just one, so Id like not to have to change "my_function" everytime I need a different "dfunc"!

RE: Passing user-defined function as argument

Quote (hugochief):


not that I dont like your answer but I really knew it
lol When you knew the answer, why have you asked?

Quote (hugochief):


the problem is that I have many different "dfunc", not just one, so Id like not to have to change "my_function" everytime I need a different "dfunc"!
When you are so clever, then this could not be a problem for you.
Instead of one dfunc which returns 2D-vector, define 2 functions - for each component one: dfunc_x and dfunc_y. Then define your function my_function wit such argument list:

CODE

real function my_function(foo, f_x, f_y, x, v)
  ...
end function my_function(foo, f_x, f_y, x, v)
and call it in the main program with

CODE

write (*, *) my_function(func, dfunc_x, dfunc_y, x, v)
 

RE: Passing user-defined function as argument

I had a feeling that there is a better way ... and then I reminded me of this thread, where I defined my own datatype for permutations:
http://www.tek-tips.com/viewthread.cfm?qid=1546213&page=5

Yes, this is the point, how you can pass the vector function into argument list of other function. When you wrap the array into your own datatype, you can cheat the fortran compiler.

So, I defined one module for the datatype, second for user defined fuctions func and dfunc and third for computational methods.
Here is the solution.
funcargs.f95

CODE

module datatypes
  type vector2D
    real, dimension(2) :: values
  end type vector2D
end module datatypes

module funcs
  use datatypes
  implicit none
contains
  real function func(x)
    real, intent(in) :: x
    func = x*x
  end function func

  function dfunc1(v)
    type(vector2D), intent(in) :: v
    type(vector2D) :: dfunc1
    ! return
    dfunc1%values(1) = v%values(1)
    dfunc1%values(2) = v%values(2)
  end function dfunc1

  function dfunc2(v)
    type(vector2D), intent(in) :: v
    type(vector2D) :: dfunc2
    ! return
    dfunc2%values(1) = v%values(1) + v%values(2)
    dfunc2%values(2) = v%values(1) - v%values(2)
  end function dfunc2
end module funcs

module mult
  use datatypes
  implicit none
contains  
  real function my_function(foo, bar, x, v)
    real, intent(in) :: x
    !real, dimension(2)
    type(vector2D), intent(in) :: v
    real :: foo
    type(vector2D) :: reslt, bar
    reslt = bar(v)
    my_function = foo(x) + reslt%values(1) + reslt%values(2)
    endfunction my_function
end module mult

program funcargs
  use datatypes
  use funcs
  use mult
  implicit none
  real :: x
  !real, dimension(2) :: v
  type(vector2D) :: v
  x = 2
  v%values = (/3, 4/)
  ! This should deliver 2*2 + 3 + 4 = 4 + 3 + 4 = 11
  write (*, *) 'my_function(func, dfunc1, 2, (3,4)) = ', &
                my_function(func, dfunc1, x, v)
  ! This should deliver 2*2 + (3 + 4) + (3 - 4) = 4 + 7 - 1 = 10
  write (*, *) 'my_function(func, dfunc2, 2, (3,4)) = ', &
                my_function(func, dfunc2, x, v)
end program funcargs
It compiles fine fith g95 and gfortran:

CODE

$ g95 funcargs.f95 -o funcargs

$ funcargs
 my_function(func, dfunc1, 2, (3,4)) =  11.
 my_function(func, dfunc2, 2, (3,4)) =  10.

$ gfortran funcargs.f95 -o funcargs

$ funcargs
 my_function(func, dfunc1, 2, (3,4)) =    11.000000    
 my_function(func, dfunc2, 2, (3,4)) =   10.0000000    
I think this way with the user defined datatype is the only way how to do it in fortran. There is probably not a simpler way.

hugochief, How you can see, I call my_function once with dfunc1 and second with dfunc2.
So be happy, you don't need to change "my_function" everytime you need a different "dfunc"!
smile
 

RE: Passing user-defined function as argument

(OP)
you are overkilling the problem man:) i found a simplest solution that really does what i wanted:

function my_function(func,dfunc)

interface
  function func(x)
    real, dimension(2), intent(in) :: x
    real :: func
  endfunction func
  function dfunc(x)
    real, dimension(2), intent(in) :: x
    real, dimension(2) :: dfunc
  endfunction dfunc
endinterface

...
this way i dont have to bother splitting dfunc in two dfunc_x and dfunc_y nor use nasty derived data types
thx for the discussion though
   

RE: Passing user-defined function as argument

I didn't know about using interfaces in procedures, I though they are only for modules. sad
Now I tried it as hugochief suggested:

funcargs.f95

CODE

module funcs
  implicit none
contains
  real function func(x)
    real, intent(in) :: x
    func = x*x
  end function func

  function dfunc1(v)
    real, dimension(2), intent(in) :: v
    real, dimension(2) :: dfunc1
    ! return
    dfunc1(1) = v(1)
    dfunc1(2) = v(2)
  end function dfunc1

  function dfunc2(v)
    real, dimension(2), intent(in) :: v
    real, dimension(2) :: dfunc2
    ! return
    dfunc2(1) = v(1) + v(2)
    dfunc2(2) = v(1) - v(2)
  end function dfunc2
end module funcs

module mult
  implicit none
contains  
  real function my_function(func, dfunc, x, v)
    real :: func
    ! for the vector function we need this interface  
    interface
      function dfunc(v)
        real, dimension(2), intent(in) :: v
        real, dimension(2) :: dfunc
      end function dfunc
    end interface
    real, intent(in) :: x
    real, dimension(2), intent(in) :: v
    real, dimension(2) :: reslt, bar
    reslt = dfunc(v)
    my_function = func(x) + reslt(1) + reslt(2)
    endfunction my_function
end module mult

program funcargs
  use funcs
  use mult
  implicit none
  real :: x
  real, dimension(2) :: v
  x = 2
  v = (/3, 4/)
  ! This should deliver 2*2 + 3 + 4 = 4 + 3 + 4 = 11
  write (*, *) 'my_function(func, dfunc1, 2, (3,4)) = ', &
                my_function(func, dfunc1, x, v)
  ! This should deliver 2*2 + (3 + 4) + (3 - 4) = 4 + 7 - 1 = 10
  write (*, *) 'my_function(func, dfunc2, 2, (3,4)) = ', &
                my_function(func, dfunc2, x, v)
end program funcargs
Output:

CODE

$ g95 funcargs.f95 -o func_args

$ func_args
 my_function(func, dfunc1, 2, (3,4)) =  11.
 my_function(func, dfunc2, 2, (3,4)) =  10.

hugochief , you are right!
It's simply and it wworks great - it's the best solution!
smile

Red Flag This Post

Please let us know here why this post is inappropriate. Reasons such as off-topic, duplicates, flames, illegal, vulgar, or students posting their homework.

Red Flag Submitted

Thank you for helping keep Tek-Tips Forums free from inappropriate posts.
The Tek-Tips staff will check this out and take appropriate action.

Reply To This Thread

Posting in the Tek-Tips forums is a member-only feature.

Click Here to join Tek-Tips and talk with other members! Already a Member? Login

Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close