Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Passing user-defined function as argument 1

Status
Not open for further replies.

hugochief

Programmer
Oct 6, 2009
3
CA
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!!
 
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.
 
If you name the function func in module func you get the error:
"MODULE attribute conflicts with PROCEDURE attribute
 
Yoo can define a function which return an array - see the function MatrixVector here:

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:

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:
[COLOR=#a020f0]module[/color] funcs
  [COLOR=#2e8b57][b]implicit[/b][/color] [COLOR=#2e8b57][b]none[/b][/color]
[COLOR=#a020f0]contains[/color]
[COLOR=#2e8b57][b]  real[/b][/color] [COLOR=#a020f0]function[/color] func(x)
[COLOR=#2e8b57][b]    real[/b][/color], [COLOR=#2e8b57][b]intent[/b][/color]([COLOR=#2e8b57][b]in[/b][/color]) :: x
    func [COLOR=#804040][b]=[/b][/color] x[COLOR=#804040][b]*[/b][/color]x
  [COLOR=#a020f0]end function[/color] func

  [COLOR=#a020f0]function[/color] dfunc(v)
[COLOR=#2e8b57][b]    real[/b][/color], [COLOR=#2e8b57][b]dimension[/b][/color]([COLOR=#ff00ff]2[/color]), [COLOR=#2e8b57][b]intent[/b][/color]([COLOR=#2e8b57][b]in[/b][/color]) :: v
[COLOR=#2e8b57][b]    real[/b][/color], [COLOR=#2e8b57][b]dimension[/b][/color]([COLOR=#ff00ff]2[/color]) :: dfunc
    [COLOR=#0000ff]! return[/color]
    dfunc([COLOR=#ff00ff]1[/color]) [COLOR=#804040][b]=[/b][/color] v([COLOR=#ff00ff]1[/color])
    dfunc([COLOR=#ff00ff]2[/color]) [COLOR=#804040][b]=[/b][/color] v([COLOR=#ff00ff]2[/color])
  [COLOR=#a020f0]end function[/color] dfunc
[COLOR=#a020f0]end module[/color] funcs

[COLOR=#a020f0]module[/color] mult
  [COLOR=#a020f0]use[/color] funcs
  [COLOR=#a020f0]contains[/color]
[COLOR=#2e8b57][b]  real[/b][/color] [COLOR=#a020f0]function[/color] my_function(foo, x, v)
[COLOR=#2e8b57][b]    real[/b][/color], [COLOR=#2e8b57][b]intent[/b][/color]([COLOR=#2e8b57][b]in[/b][/color]) :: x
[COLOR=#2e8b57][b]    real[/b][/color], [COLOR=#2e8b57][b]dimension[/b][/color]([COLOR=#ff00ff]2[/color]), [COLOR=#2e8b57][b]intent[/b][/color]([COLOR=#2e8b57][b]in[/b][/color]) :: v
[COLOR=#2e8b57][b]    real[/b][/color] :: foo 
[COLOR=#2e8b57][b]    real[/b][/color], [COLOR=#2e8b57][b]dimension[/b][/color]([COLOR=#ff00ff]2[/color]) :: reslt, bar
    [COLOR=#2e8b57][b]integer[/b][/color] :: i
    reslt [COLOR=#804040][b]=[/b][/color] dfunc(v)
    my_function [COLOR=#804040][b]=[/b][/color] foo(x) [COLOR=#804040][b]+[/b][/color] reslt([COLOR=#ff00ff]1[/color]) [COLOR=#804040][b]+[/b][/color] reslt([COLOR=#ff00ff]2[/color])
  [COLOR=#a020f0]endfunction[/color] my_function
[COLOR=#a020f0]end module[/color] mult

[COLOR=#a020f0]program[/color] funcargs
  [COLOR=#0000ff]!use funcs[/color]
  [COLOR=#a020f0]use[/color] mult
  [COLOR=#2e8b57][b]implicit[/b][/color] [COLOR=#2e8b57][b]none[/b][/color]
[COLOR=#2e8b57][b]  real[/b][/color] :: x
[COLOR=#2e8b57][b]  real[/b][/color], [COLOR=#2e8b57][b]dimension[/b][/color]([COLOR=#ff00ff]2[/color]) :: v
  x [COLOR=#804040][b]=[/b][/color] [COLOR=#ff00ff]2[/color]
  v [COLOR=#804040][b]=[/b][/color] ([COLOR=#804040][b]/[/b][/color][COLOR=#ff00ff]3[/color], [COLOR=#ff00ff]4[/color][COLOR=#804040][b]/[/b][/color])
  [COLOR=#804040][b]write[/b][/color] ([COLOR=#804040][b]*[/b][/color], [COLOR=#804040][b]*[/b][/color]) my_function(func, x, v)
[COLOR=#a020f0]end program[/color] funcargs
Output:
Code:
$ g95 funcargs.f95 -o funcargs
$ funcargs
 11.
 
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"!
 
hugochief said:
not that I dont like your answer but I really knew it
[lol] When you knew the answer, why have you asked?
hugochief said:
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)
 
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:

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:
[COLOR=#a020f0]module[/color] datatypes
  [COLOR=#2e8b57][b]type[/b][/color] vector2D
[COLOR=#2e8b57][b]    real[/b][/color], [COLOR=#2e8b57][b]dimension[/b][/color]([COLOR=#ff00ff]2[/color]) :: values 
  [COLOR=#2e8b57][b]end type[/b][/color] vector2D
[COLOR=#a020f0]end module[/color] datatypes

[COLOR=#a020f0]module[/color] funcs
  [COLOR=#a020f0]use[/color] datatypes
  [COLOR=#2e8b57][b]implicit[/b][/color] [COLOR=#2e8b57][b]none[/b][/color]
[COLOR=#a020f0]contains[/color]
[COLOR=#2e8b57][b]  real[/b][/color] [COLOR=#a020f0]function[/color] func(x)
[COLOR=#2e8b57][b]    real[/b][/color], [COLOR=#2e8b57][b]intent[/b][/color]([COLOR=#2e8b57][b]in[/b][/color]) :: x
    func [COLOR=#804040][b]=[/b][/color] x[COLOR=#804040][b]*[/b][/color]x
  [COLOR=#a020f0]end function[/color] func

  [COLOR=#a020f0]function[/color] dfunc1(v)
    [COLOR=#2e8b57][b]type[/b][/color](vector2D), [COLOR=#2e8b57][b]intent[/b][/color]([COLOR=#2e8b57][b]in[/b][/color]) :: v
    [COLOR=#2e8b57][b]type[/b][/color](vector2D) :: dfunc1
    [COLOR=#0000ff]! return[/color]
    dfunc1%values([COLOR=#ff00ff]1[/color]) [COLOR=#804040][b]=[/b][/color] v%values([COLOR=#ff00ff]1[/color])
    dfunc1%values([COLOR=#ff00ff]2[/color]) [COLOR=#804040][b]=[/b][/color] v%values([COLOR=#ff00ff]2[/color])
  [COLOR=#a020f0]end function[/color] dfunc1

  [COLOR=#a020f0]function[/color] dfunc2(v)
    [COLOR=#2e8b57][b]type[/b][/color](vector2D), [COLOR=#2e8b57][b]intent[/b][/color]([COLOR=#2e8b57][b]in[/b][/color]) :: v
    [COLOR=#2e8b57][b]type[/b][/color](vector2D) :: dfunc2
    [COLOR=#0000ff]! return[/color]
    dfunc2%values([COLOR=#ff00ff]1[/color]) [COLOR=#804040][b]=[/b][/color] v%values([COLOR=#ff00ff]1[/color]) [COLOR=#804040][b]+[/b][/color] v%values([COLOR=#ff00ff]2[/color])
    dfunc2%values([COLOR=#ff00ff]2[/color]) [COLOR=#804040][b]=[/b][/color] v%values([COLOR=#ff00ff]1[/color]) [COLOR=#804040][b]-[/b][/color] v%values([COLOR=#ff00ff]2[/color])
  [COLOR=#a020f0]end function[/color] dfunc2
[COLOR=#a020f0]end module[/color] funcs

[COLOR=#a020f0]module[/color] mult
  [COLOR=#a020f0]use[/color] datatypes
  [COLOR=#2e8b57][b]implicit[/b][/color] [COLOR=#2e8b57][b]none[/b][/color]
[COLOR=#a020f0]contains[/color]  
[COLOR=#2e8b57][b]  real[/b][/color] [COLOR=#a020f0]function[/color] my_function(foo, bar, x, v)
[COLOR=#2e8b57][b]    real[/b][/color], [COLOR=#2e8b57][b]intent[/b][/color]([COLOR=#2e8b57][b]in[/b][/color]) :: x
    [COLOR=#0000ff]!real, dimension(2)[/color]
    [COLOR=#2e8b57][b]type[/b][/color](vector2D), [COLOR=#2e8b57][b]intent[/b][/color]([COLOR=#2e8b57][b]in[/b][/color]) :: v
[COLOR=#2e8b57][b]    real[/b][/color] :: foo 
    [COLOR=#2e8b57][b]type[/b][/color](vector2D) :: reslt, bar
    reslt [COLOR=#804040][b]=[/b][/color] bar(v)
    my_function [COLOR=#804040][b]=[/b][/color] foo(x) [COLOR=#804040][b]+[/b][/color] reslt%values([COLOR=#ff00ff]1[/color]) [COLOR=#804040][b]+[/b][/color] reslt%values([COLOR=#ff00ff]2[/color])
    [COLOR=#a020f0]endfunction[/color] my_function
[COLOR=#a020f0]end module[/color] mult

[COLOR=#a020f0]program[/color] funcargs
  [COLOR=#a020f0]use[/color] datatypes
  [COLOR=#a020f0]use[/color] funcs
  [COLOR=#a020f0]use[/color] mult
  [COLOR=#2e8b57][b]implicit[/b][/color] [COLOR=#2e8b57][b]none[/b][/color]
[COLOR=#2e8b57][b]  real[/b][/color] :: x
  [COLOR=#0000ff]!real, dimension(2) :: v[/color]
  [COLOR=#2e8b57][b]type[/b][/color](vector2D) :: v
  x [COLOR=#804040][b]=[/b][/color] [COLOR=#ff00ff]2[/color]
  v%values [COLOR=#804040][b]=[/b][/color] ([COLOR=#804040][b]/[/b][/color][COLOR=#ff00ff]3[/color], [COLOR=#ff00ff]4[/color][COLOR=#804040][b]/[/b][/color])
  [COLOR=#0000ff]! This should deliver 2*2 + 3 + 4 = 4 + 3 + 4 = 11[/color]
  [COLOR=#804040][b]write[/b][/color] ([COLOR=#804040][b]*[/b][/color], [COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'my_function(func, dfunc1, 2, (3,4)) = '[/color], [highlight #ffff00][COLOR=#0000ff]&[/color][/highlight]
                my_function(func, dfunc1, x, v)
  [COLOR=#0000ff]! This should deliver 2*2 + (3 + 4) + (3 - 4) = 4 + 7 - 1 = 10[/color]
  [COLOR=#804040][b]write[/b][/color] ([COLOR=#804040][b]*[/b][/color], [COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'my_function(func, dfunc2, 2, (3,4)) = '[/color], [highlight #ffff00][COLOR=#0000ff]&[/color][/highlight]
                my_function(func, dfunc2, x, v)
[COLOR=#a020f0]end program[/color] 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"!
:)
 
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
 
I didn't know about using interfaces in procedures, I though they are only for modules. :-(
Now I tried it as hugochief suggested:

funcargs.f95
Code:
[COLOR=#a020f0]module[/color] funcs
  [COLOR=#2e8b57][b]implicit[/b][/color] [COLOR=#2e8b57][b]none[/b][/color]
[COLOR=#a020f0]contains[/color]
[COLOR=#2e8b57][b]  real[/b][/color] [COLOR=#a020f0]function[/color] func(x)
[COLOR=#2e8b57][b]    real[/b][/color], [COLOR=#2e8b57][b]intent[/b][/color]([COLOR=#2e8b57][b]in[/b][/color]) :: x
    func [COLOR=#804040][b]=[/b][/color] x[COLOR=#804040][b]*[/b][/color]x
  [COLOR=#a020f0]end function[/color] func

  [COLOR=#a020f0]function[/color] dfunc1(v)
[COLOR=#2e8b57][b]    real[/b][/color], [COLOR=#2e8b57][b]dimension[/b][/color]([COLOR=#ff00ff]2[/color]), [COLOR=#2e8b57][b]intent[/b][/color]([COLOR=#2e8b57][b]in[/b][/color]) :: v
[COLOR=#2e8b57][b]    real[/b][/color], [COLOR=#2e8b57][b]dimension[/b][/color]([COLOR=#ff00ff]2[/color]) :: dfunc1
    [COLOR=#0000ff]! return[/color]
    dfunc1([COLOR=#ff00ff]1[/color]) [COLOR=#804040][b]=[/b][/color] v([COLOR=#ff00ff]1[/color])
    dfunc1([COLOR=#ff00ff]2[/color]) [COLOR=#804040][b]=[/b][/color] v([COLOR=#ff00ff]2[/color])
  [COLOR=#a020f0]end function[/color] dfunc1

  [COLOR=#a020f0]function[/color] dfunc2(v)
[COLOR=#2e8b57][b]    real[/b][/color], [COLOR=#2e8b57][b]dimension[/b][/color]([COLOR=#ff00ff]2[/color]), [COLOR=#2e8b57][b]intent[/b][/color]([COLOR=#2e8b57][b]in[/b][/color]) :: v
[COLOR=#2e8b57][b]    real[/b][/color], [COLOR=#2e8b57][b]dimension[/b][/color]([COLOR=#ff00ff]2[/color]) :: dfunc2
    [COLOR=#0000ff]! return[/color]
    dfunc2([COLOR=#ff00ff]1[/color]) [COLOR=#804040][b]=[/b][/color] v([COLOR=#ff00ff]1[/color]) [COLOR=#804040][b]+[/b][/color] v([COLOR=#ff00ff]2[/color])
    dfunc2([COLOR=#ff00ff]2[/color]) [COLOR=#804040][b]=[/b][/color] v([COLOR=#ff00ff]1[/color]) [COLOR=#804040][b]-[/b][/color] v([COLOR=#ff00ff]2[/color])
  [COLOR=#a020f0]end function[/color] dfunc2
[COLOR=#a020f0]end module[/color] funcs

[COLOR=#a020f0]module[/color] mult
  [COLOR=#2e8b57][b]implicit[/b][/color] [COLOR=#2e8b57][b]none[/b][/color]
[COLOR=#a020f0]contains[/color]  
[COLOR=#2e8b57][b]  real[/b][/color] [COLOR=#a020f0]function[/color] my_function(func, dfunc, x, v)
[COLOR=#2e8b57][b]    real[/b][/color] :: func
    [COLOR=#0000ff]! for the vector function we need this interface  [/color]
    [COLOR=#a020f0]interface[/color]
      [COLOR=#a020f0]function[/color] dfunc(v)
[COLOR=#2e8b57][b]        real[/b][/color], [COLOR=#2e8b57][b]dimension[/b][/color]([COLOR=#ff00ff]2[/color]), [COLOR=#2e8b57][b]intent[/b][/color]([COLOR=#2e8b57][b]in[/b][/color]) :: v
[COLOR=#2e8b57][b]        real[/b][/color], [COLOR=#2e8b57][b]dimension[/b][/color]([COLOR=#ff00ff]2[/color]) :: dfunc
      [COLOR=#a020f0]end function[/color] dfunc
    [COLOR=#a020f0]end interface[/color]
[COLOR=#2e8b57][b]    real[/b][/color], [COLOR=#2e8b57][b]intent[/b][/color]([COLOR=#2e8b57][b]in[/b][/color]) :: x
[COLOR=#2e8b57][b]    real[/b][/color], [COLOR=#2e8b57][b]dimension[/b][/color]([COLOR=#ff00ff]2[/color]), [COLOR=#2e8b57][b]intent[/b][/color]([COLOR=#2e8b57][b]in[/b][/color]) :: v
[COLOR=#2e8b57][b]    real[/b][/color], [COLOR=#2e8b57][b]dimension[/b][/color]([COLOR=#ff00ff]2[/color]) :: reslt, bar
    reslt [COLOR=#804040][b]=[/b][/color] dfunc(v)
    my_function [COLOR=#804040][b]=[/b][/color] func(x) [COLOR=#804040][b]+[/b][/color] reslt([COLOR=#ff00ff]1[/color]) [COLOR=#804040][b]+[/b][/color] reslt([COLOR=#ff00ff]2[/color])
    [COLOR=#a020f0]endfunction[/color] my_function
[COLOR=#a020f0]end module[/color] mult

[COLOR=#a020f0]program[/color] funcargs
  [COLOR=#a020f0]use[/color] funcs
  [COLOR=#a020f0]use[/color] mult
  [COLOR=#2e8b57][b]implicit[/b][/color] [COLOR=#2e8b57][b]none[/b][/color]
[COLOR=#2e8b57][b]  real[/b][/color] :: x
[COLOR=#2e8b57][b]  real[/b][/color], [COLOR=#2e8b57][b]dimension[/b][/color]([COLOR=#ff00ff]2[/color]) :: v
  x [COLOR=#804040][b]=[/b][/color] [COLOR=#ff00ff]2[/color]
  v [COLOR=#804040][b]=[/b][/color] ([COLOR=#804040][b]/[/b][/color][COLOR=#ff00ff]3[/color], [COLOR=#ff00ff]4[/color][COLOR=#804040][b]/[/b][/color])
  [COLOR=#0000ff]! This should deliver 2*2 + 3 + 4 = 4 + 3 + 4 = 11[/color]
  [COLOR=#804040][b]write[/b][/color] ([COLOR=#804040][b]*[/b][/color], [COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'my_function(func, dfunc1, 2, (3,4)) = '[/color], [highlight #ffff00][COLOR=#0000ff]&[/color][/highlight]
                my_function(func, dfunc1, x, v)
  [COLOR=#0000ff]! This should deliver 2*2 + (3 + 4) + (3 - 4) = 4 + 7 - 1 = 10[/color]
  [COLOR=#804040][b]write[/b][/color] ([COLOR=#804040][b]*[/b][/color], [COLOR=#804040][b]*[/b][/color]) [COLOR=#ff00ff]'my_function(func, dfunc2, 2, (3,4)) = '[/color], [highlight #ffff00][COLOR=#0000ff]&[/color][/highlight]
                my_function(func, dfunc2, x, v)
[COLOR=#a020f0]end program[/color] 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!
:)
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top