×
INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Contact US

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

pointer of array-valued functions
2

pointer of array-valued functions

pointer of array-valued functions

(OP)
Hello everybody,
I am starting this thread because I encounter a problem with the pointers in Fortran.
I want to use a pointer of an array-valued function, but I get a segmentation fault error during execution (compilation is ok with gfortran).

Everything works well when the pointer aims at a function returning a real. But it fails when the function returns an array of reals. I guess there is a problem in the definition of my pointer, but I don't know what to do.
Here is a small code to illustrate my problem :

CODE --> Fortran

program main
  implicit none
  real*8, external, pointer   :: p

  p => f1
  print*,p(1.0D0)    !this is ok
  p => f2
  print*,p(1.0D0)    !I get a segmentation fault
  
  contains
    function f1(x)
    implicit none
    real*8             :: f1
    real*8, intent(in) :: x
    f1 = x+2
    end function f1
    
    function f2(x)
    implicit none
    real*8              :: f2(2)
    real*8, intent(in)  :: x
    f2(1) = x+1
    f2(2) = x-1
    end function f2
  end program main 

Any help would be appreciated.
Thanks.

RE: pointer of array-valued functions

Two suggestions.

First, I don't think you can use the same pointer to point to the two functions...if one of them is an array, I would suggest to create another pointer to point to f2, like this:

real*8, pointer :: ap(:)

I called it 'ap' for 'array pointer'

If that alone does not work, I wonder if you should turn your f2 into a pointer itself and THEN return it:

function f2(x)
implicit none
real*8, pointer :: f2(:)
real*8, intent(in) :: x
allocate(f2(2))
f2(1) = x+1
f2(2) = x-1
end function f2





RE: pointer of array-valued functions

As far as I know - but I cannot check now cause I am waz from home - you cannot use pointers to point to functions, at least f90 / 95, you can have them point at variables only (do not know about constants).

Any pointer in fortran is dereferenced at once. You decalred your pointer to point at a variable of typa real*8. A pointer to an array must be delared as array like

real*8, dimension (:), pointer :: ap



Norbert

The optimist believes we live in the best of all possible worlds - the pessimist fears this might be true.

RE: pointer of array-valued functions

Don't know why you want to use pointers on functions - but maybe it's only, because you want to use several functions in the same computation, like this:
p => f1
result = compute_something(p)
p => f2
res = compute_something(p)

In this case you can rather use functions as arguments of other functions, i.e.:
result = compute_something(f1)
result = compute_something(f2)

RE: pointer of array-valued functions

(OP)
Thank you for your answers.
Here are my comments to all of your recommendations.

to Salgerman (post #1):
The problem is that I do not to point at a variable, but at a function. Therefore, I cannot declare my pointer with

CODE --> fortran

real*8, pointer :: ap(:) 
What I tried to do is to use the following declaration :

CODE --> fortran

real*8, external, pointer :: ap(:) 
but in that case I get the following error during the compilation :

CODE --> fortran

Error: EXTERNAL attribute conflicts with DIMENSION attribute 
However, here I do not want to declare an array of pointers, but a pointer that points to an array-valued function, which is different.
As a consequence, your second option does not work neither.

to gummibaer :
pointer of functions have been introduced in Fortran 2003. It works well when the functions are returning a single value, but I have some problems when an array is returned.

I finally found how to do this, using 2 different pointers (p and ap) and an explicit interface. Here is my code :

CODE --> fortran

module m

  contains
    function f1(x)
    implicit none
    real*8             :: f1
    real*8, intent(in) :: x
    f1 = x+2
    end function f1
    
    function f2(x)
    implicit none
    real*8              :: f2(2)
    real*8, intent(in)  :: x
    f2(1) = x+1
    f2(2) = x-1
    end function f2
  end module m



  program prog

  use m

  implicit none

  real*8, external, pointer   :: p

  pointer                     :: ap
  interface
    function ap(x)
      real*8             :: ap(2)
      real*8, intent(in) :: x
    end function ap
  end interface

  p => f1
  print*,p(1.0D0)

  ap => f2
  print*,ap(1.0D0)

  end program prog 

to Salgerman (post #2):
You are right, this is exactly what I want to do, but I don't know how to declare the type of the function f passed as argument in the function 'compute_something', that returns a real*8 for f1 but an array of size 2 of real*8 for f2. I initially thought it would be easier using pointers of functions, but it appears it is not.

Here is an illustration of what I want to do, and the problem I get when calling the subroutine 'compute_something' with 2 different functions types as argument (f1 returns a real*8, f2 returns an array of real*8) :

CODE --> fortran

module m2
  contains
    subroutine compute_something(f)
    implicit none
    real*8, external    :: f
    print*,f(1.0D0)
    end subroutine compute_something
end module m2

module m1
  contains
    function f1(x)
    implicit none
    real*8             :: f1
    real*8, intent(in) :: x
    f1 = x+2
    end function f1
    
    function f2(x)
    implicit none
    real*8              :: f2(2)
    real*8, intent(in)  :: x
    f2(1) = x+1
    f2(2) = x-1
    end function f2

    subroutine m1_subroutine()
    use m2
    implicit none
    call compute_something(f1)
!    call compute_something(f2)   !compilation error for this line
    end subroutine m1_subroutine

end module m1


program main
  use m1
  implicit none

  call m1_subroutine()
  
  end program main 

the compilation error for the line "call compute_something(f2)" is :

CODE --> fortran

call compute_something(f2)
                           1
Error: Type/rank mismatch in argument 'f' at (1) 

ps : I used two modules, m1 and m2, because I get a compilation error when including m1 in the contains part of the main program. I don't undertand why, anyway...

RE: pointer of array-valued functions

(OP)
You links seem to contain interesting information.
I will look at them with great attention and come back later to tell if it works for my case.
Thank you !

RE: pointer of array-valued functions

I think you need something more special. Maybe you want one function which will operate with both types of arguments: scalars and vectors.

Simply said, I want only one function my_function with 2 arguments and I want to apply the function on scalar arguments (real function and real number) and on vector arguments (vector function and vector vector). This is possible in fortran too - we can implement function overloading suing generic interface.
Here is an example
overloading.f95

CODE

module functions
  implicit none
contains
  ! scalar functions 
  real function sf1(x)
    real, intent(in) :: x
    sf1 = x*x
  end function sf1

  real function sf2(x)
    real, intent(in) :: x
    sf2 = x + 3
  end function sf2

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

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

module methods
  ! function overloading with generic interface
  interface my_function
    module procedure my_function_with_scal_args, &
                     my_function_with_vec_args
  end interface my_function

contains
  real function my_function_with_scal_args(scal_f, x)
    ! interface for functional arguments
    interface
      function scal_f(x)
        real, intent(in) :: x
        real :: scal_f
      end function scal_f
    end interface
    real, intent(in) :: x

    ! compute double of the function result
    my_function_with_scal_args = 2 * scal_f(x)
  end function my_function_with_scal_args

  real function my_function_with_vec_args(vec_f, x)
    ! interface for functional arguments
    interface
      function vec_f(x)
        real, dimension(2), intent(in) :: x
        real, dimension(2) :: vec_f
      end function vec_f
    end interface
    real, dimension(2), intent(in) :: x
    real, dimension(2) :: reslt
    
    ! compute value of the vector function applied on the vector argument
    reslt = vec_f(x)

    ! double the sum of vector components
    my_function_with_vec_args = 2 * (reslt(1) + reslt(2))
  end function my_function_with_vec_args
end module methods

program overloading
  use functions
  use methods

  implicit none
  real :: x
  real, dimension(2) :: v
  x = 5
  v = (/3, 4/)

  write(*,*) 'Overloading Example:'

  ! using my_function with scalar arguments
  write(*,*) 'my_function (sf1, x) = ', my_function (sf1, x)
  write(*,*) 'my_function (sf2, x) = ', my_function (sf2, x)

  ! using my_function with vector arguments
  write(*,*) 'my_function (vf1, v) = ', my_function (vf1, v)
  write(*,*) 'my_function (vf2, v) = ', my_function (vf2, v)
end program overloading 

You see, I need write the function my_function_with_scal_args with scalar arguments and the function my_function_with_vec_args with vector arguments.
Then implement the overloading mechanism via generic interface my_function.

Now it compiles and runs:

CODE

$ gfortran overloading.f95 -o overloading

$ overloading
 Overloading Example:
 my_function (sf1, x) =    50.000000    
 my_function (sf2, x) =    16.000000    
 my_function (vf1, v) =    14.000000    
 my_function (vf2, v) =    12.000000 

RE: pointer of array-valued functions

(OP)
Thank you, this is exactly what I was looking for ! I tried with my own example and it works very well.
One last question : to avoid the use of the function overloading with the general interface, I was wondering if it was possible to define, in the interface for the function passed as argument, the arguments as assumed-shape arrays. In that way, I define only once my function, that combines both 'my_function_with_scal_args' and 'my_function_with_vec_args', by writing the interface in a way like this one :

CODE --> fortran

inteface
  function vec_f(x)
    real, dimension(2), intent(in) :: x
    real, dimension(:) :: vec_f           !assumed-shape array
  end function vec_f
end interface 

With my (simplified) previous code, it writes :

CODE --> fortran

module m2
  contains
    subroutine compute_something(f)
    implicit none
    interface
      function f(x)
        real*8, intent(in)  :: x
!	real*8              :: f(2)    !works
        real*8              :: f(:)    !does not work
      end function f      
    end interface
    print*,f(1.0D0)
    end subroutine compute_something
end module m2

module m1
  contains
    function f2(x)
    implicit none
    real*8              :: f2(2)
    real*8, intent(in)  :: x
    f2(1) = x+1
    f2(2) = x-1
    end function f2

    subroutine m1_subroutine()
    use m2
    implicit none
    call compute_something(f2)
    end subroutine m1_subroutine

end module m1


program main
  use m1
  implicit none

  call m1_subroutine()
  
  end program main 

unfortunately, if it compiles without problem, I got a segmentation fault error when the line 'print*,f(1.0D0)' in the subroutine 'compute_something' is executed.
Is it possible to do such a thing ? It would be very interesting for me because, with such an approach, I can write a single function that computes, for instance, the Jacobian matrix (size m*n) of a vectorial function for any values of m and n. By using the function overloading and the general interface, I would have to write the m*n functions !

RE: pointer of array-valued functions

I cannot simply answer your questions, it would be best when you try it self.
For example look at this thread
http://www.tek-tips.com/viewthread.cfm?qid=1546213
The function multiply_permutations has 2 arguments, i.e. arrays without defined dimension and returns allocatable array...

RE: pointer of array-valued functions

Here is other example
http://www.tek-tips.com/viewthread.cfm?qid=1516435
Look at the function MatrixVector(M, x) in module vector_functions. It has 2 input arguments

real, dimension(:,:), intent(in) :: M
real, dimension(:), intent(in) :: x

and returns a vector

real, dimension(n) :: MatrixVector

which size depends on input argument / n=SIZE(x) /

RE: pointer of array-valued functions

(OP)
Thank you for your help. I am going to look at those links and post my answer with, I hope, the solution as soon as possible.

RE: pointer of array-valued functions

(OP)
I had a look on the links you provided, mikrom, but unfortunately they deal with with simple assumed-shape arrays, and not assumed-shape arrays of functions, and are helpless for my case.

Let me sum up my problem, for the readers of the forum.
I have the code given below. In this code, the function f returns an array (dimension 2) of reals. This function is passed as argument to the subroutine mysub.
What I would like to do is to be able to pass any function that returns an array of dimension n >= 1 to mysub. I tried modifying the line

CODE --> fortran

real              :: f(2) 
to

CODE --> fortran

real              :: f(:) 
in the interface inside mysub, to act as an assumed-shape array, but I get a segmentation fault during execution (using gfortran or f95).
Does anyone know the solution of my problem ? I searched for a long time on the Internet but didn't find any similar thing.

CODE --> fortran

module m
  contains
  subroutine mysub(f)
  implicit none
  interface
    function f(x)
      real              :: f(2)
      real, intent(in)  :: x
    end function f
  end interface
  print*,f(1.0)
  end subroutine mysub
end module m


program main
  use m
  implicit none
  interface
    function f(x)
      real              :: f(2)
      real, intent(in)  :: x
    end function f
  end interface

  call mysub(f)
  
end program main
  
function f(x)
  implicit none
  real              :: f(2)
  real, intent(in)  :: x
  f(1) = x+1.0
  f(2) = x-1.0
end function f 

RE: pointer of array-valued functions

I don't quite understand if what you are trying to do is to take on any one-dimensional function of any length or any-dimensional.

The code below works for me and uses mysub to take on 2 one-dimensional functions of different lengths.

CODE

module m
        contains
        subroutine mysub(f)
        implicit none
        interface
          function f(x)
            real, allocatable, dimension(:) :: f
            real, intent(in)  :: x
          end function f
        end interface
        print*,f(1.0)
        end subroutine mysub
      end module m

      program main
        use m
        implicit none
        interface
          function f2(x)
            real, allocatable, dimension(:) :: f2
            real, intent(in)  :: x
          end function f2
          function f5(x)
            real, allocatable, dimension(:) :: f5
            real, intent(in)  :: x
          end function f5
        end interface

        call mysub(f2)
        call mysub(f5)
        
      end program main
  
      function f2(x)
        implicit none
        real, allocatable, dimension(:) :: f2
        real, intent(in)  :: x
        allocate(f2(2))
        f2(1) = x+1.0
        f2(2) = x-1.0
      end function f2 
      function f5(x)
        implicit none
        real, allocatable, dimension(:) :: f5
        real, intent(in)  :: x
        allocate(f5(2))
        f5(1) = x+1.0
        f5(2) = x-1.0
        f5(2) = 3.0
        f5(2) = 4.0
        f5(2) = 5.0
      end function f5 

RE: pointer of array-valued functions

typo!!! Sorry....need to change "allocate(f5(2))" to "allocate(f5(5))" !!!

RE: pointer of array-valued functions

and the indices (2) (2) (2) to (3) (4) (5) ...

RE: pointer of array-valued functions

What you want is possible.

I modified a little bit the program:
Now the function vf1() takes a vector argument of any dimebnsion and returns the vector of the same dimesion as the input argument.
The function my_function_with_vec_args() accepts now arguments like vf1()

overloading2.f95

CODE

module functions
  implicit none
contains
  ! scalar functions 
  real function sf1(x)
    real, intent(in) :: x
    sf1 = x*x
  end function sf1

  real function sf2(x)
    real, intent(in) :: x
    sf2 = x + 3
  end function sf2

  ! vector fuctions
  function vf1(v)
    real, dimension(:), intent(in) :: v
    integer :: n, j
    real, dimension(n) :: vf1
    n=size(v)

    ! return
    do j=1, n
      vf1(j) = 3*v(j)
    end do  
  end function vf1

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

module methods
  ! function overloading with generic interface
  interface my_function
    module procedure my_function_with_scal_args, &
                     my_function_with_vec_args
  end interface my_function

contains
  real function my_function_with_scal_args(scal_f, x)
    ! interface for functional arguments
    interface
      function scal_f(x)
        real, intent(in) :: x
        real :: scal_f
      end function scal_f
    end interface
    real, intent(in) :: x

    ! compute double of the function result
    my_function_with_scal_args = 2 * scal_f(x)
  end function my_function_with_scal_args

  real function my_function_with_vec_args(vec_f, x)
    ! interface for functional arguments
    interface
      function vec_f(x)
        real, dimension(:), intent(in) :: x
        real, dimension(:) :: vec_f
      end function vec_f
    end interface
    real, dimension(:), intent(in) :: x
    integer :: n
    real, dimension(:), allocatable :: reslt
    
    n = size(x)
    allocate(reslt(n))
    ! compute value of the vector function applied on the vector argument
    reslt = vec_f(x)

    ! double the sum of vector components
    my_function_with_vec_args = 2 * sum(reslt)
  end function my_function_with_vec_args
end module methods

program overloading2
  use functions
  use methods

  implicit none
  real :: x
  real, dimension(2) :: v
  real, dimension(5) :: w
  x = 5
  v = (/3, 4/)
  w = (/1, 2, 3, 4, 5/)

  write(*,*) 'Overloading Example:'

  ! using my_function with scalar arguments
  write(*,*) 'my_function (sf1, x) = ', my_function (sf1, x)
  write(*,*) 'my_function (sf2, x) = ', my_function (sf2, x)

  ! using my_function with vector arguments
  write(*,*) 'vector v and vector function vf1() have dimension = 2'
  write(*,*) 'my_function (vf1, v) = ', my_function (vf1, v)
  write(*,*) 'my_function (vf2, v) = ', my_function (vf2, v)
  !
  write(*,*) 'vector w and vector function vf1() have dimension = 5'
  write(*,*) 'my_function (vf1, w) = ', my_function (vf1, w) 
end program overloading2 

The program a vector of length 2 and 5, the function vf1() returns in that cases a vector of length 2 or 5.

CODE

$ gfortran overloading2.f95 -o overloading2

$ overloading2
 Overloading Example:
 my_function (sf1, x) =    50.000000    
 my_function (sf2, x) =    16.000000    
 vector v and vector function vf1() have dimension = 2
 my_function (vf1, v) =    42.000000    
 my_function (vf2, v) =    12.000000    
 vector w and vector function vf1() have dimension = 5
 my_function (vf1, w) =    90.000000 

But I must say you, that what I have done is compiler dependent. It compiles with gfortran, but it doesn't compile with g95, which doesn't like this declaration:

CODE

function vf1(v)
    real, dimension(:), intent(in) :: v
    integer :: n, j
    real, dimension(n) :: vf1
    n=size(v)
.... 
and throws this error:

CODE

$ g95 overloading2.f95 -o overloading2
In file overloading2.f95:19

    real, dimension(n) :: vf1
                    1
Error: Variable 'n' cannot appear in restricted expression at (1) 

RE: pointer of array-valued functions

(OP)
That you for your answer, both showing what I want to do with different methods.

salgerman, you understood my problem welle, I wanted to take on any one-dimensional function. I am just surprised I get a segmentation fault if I do not declare f2 and f5 as allocatables. Anyway, by declaring them as allocatable it works fine and that is what I will do in the future.

mikrom, I am very impressed by your solution, where it not not necessary do declare the functions with allocatables. I need a bit more time to understand clearly what it does exactly. I tried to reproduce my example with your solution but encountered some errors. I guess I need to reread your code carefully to fully understand it.

anyway, thanks very much to both of you for your help. It is greatly appreciated.
Best regards.

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