Interface mismatch in dummy procedure 'f' when passing a function to a subroutine

梦想与她 提交于 2019-12-22 12:19:39

问题


I am trying to write a subroutine (for minimisation) that has two arguments:

  • an array x of any length
  • a function f that takes an array of that length and returns a scalar

example module:

module foo

contains

  subroutine solve(x, f)
    real, dimension(:), intent(inout) :: x
    interface
      real pure function f(y)
        import x
        real, dimension(size(x)), intent(in) :: y
      end function
    end interface

    print *, x
    print *, f(x)
  end subroutine

end module

and test program:

use foo

real, dimension(2) :: x = [1.0, 2.0]

call solve(x, g)

contains

  real pure function g(y)
    real, dimension(2), intent(in) :: y

    g = sum(y)
  end function

end

gfortran fails on:

call solve(x, g)
              1
Error: Interface mismatch in dummy procedure 'f' at (1): Shape mismatch in dimension 1 of argument 'y'

If I change size(x) => 2 then it compiles (and runs) fine. It also works fine if I change : => 2. But neither of these solutions gets me what I want.

Any ideas on how I can achieve this?


回答1:


How about:

interface
  real pure function f(y)
    real, dimension(:), intent(in) :: y
  end function
end interface

When you pass the argument of solve to the function, the size of the array will automatically be passed. You don't need to make this part of the interface.




回答2:


If you want to gain safety as indicated in your comment of M.S.B's solution, you should use -fcheck=bounds and the compiler will generate run-time checks for assumed and deferred shape arrays. See the gfortran man page for more info on -fcheck. However, you will lose some speed.




回答3:


You have the solution, but for what its worth an explanation... if the dummy argument has an explicit interface (which it does here) then there is a requirement that the characteristics of a procedure passed as an actual argument must match those of the dummy argument, with some exceptions around pureness and elemental intrinsics. The characteristics of a procedure include the characteristics of its dummy arguments, amongst other things.

The characteristics of a dummy argument include its shape, amongst other things. If that shape is not a constant expression - the characteristics include "the exact dependence [of the shape] on the entities in the expression".

The interface block for the dummy argument f declares the array to be of size SIZE(x). x is a host associated assumed shape variable - its size can vary at runtime, so SIZE(x) is not a constant. Hence that expression and the entities in it becomes a characteristic of the dummy argument.

The module procedure g declares the array to be of size 2. That is clearly a constant.

Regardless of the value of the non-constant expression for the size of the dummy argument of f, those array size characteristics (some sort of expression vs a constant) don't match - hence the error.

When you replace SIZE(x) with the constant 2 the characteristics obviously match. When you change the assumed shape x to be a constant size 2 - then SIZE(x) becomes a constant expression of value 2 - because it is a constant expression all that is relevant is its value - hence the characteristics of the two arguments then match. When you change both the dummy argument of f and the dummy argument of g to be assumed shape (:), the characteristics match.




回答4:


Here is a demo to show how to pass allocatable array.

Some tips:

  • Use modules to avoid cumbersome interface.
  • Add extra matrix size information when pass array to the actual function. For example f(y, sizeinfo) so that inside your actual function you can declare the size of the input matrix correctly. The allocatable array can be passed to subroutine solve, so the size can be obtained using size(mat) in your subroutine solve.

So a corrected version looks like:

module foo

contains

  subroutine solve(x, f)
    real, dimension(:), intent(inout) :: x
    real,external::f
        integer::sizeinfo

    print *,'x=', x
    sizeinfo = size(x)
    print *, 'f(x)=',f(x,sizeinfo)
  end subroutine

    real function g(y,sizeinfo)
    integer::sizeinfo
    real, dimension(sizeinfo) :: y

    g = sum(y)
  end function
end module

Here is main program:

program main
use foo

real, dimension(2) :: x = (/1.0, 2.0/)

call solve(x, g)

end program

And the result is :

x=   1.000000       2.000000    
f(x)=   3.000000 


来源:https://stackoverflow.com/questions/15926727/interface-mismatch-in-dummy-procedure-f-when-passing-a-function-to-a-subroutin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!