INTELLIGENT WORK FORUMS FOR COMPUTER PROFESSIONALS
Come Join Us!
Are you a Computer / IT professional? Join Tek-Tips now!
- 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.
Partner With Us!
"Best Of Breed" Forums Add Stickiness To Your Site

(Download This Button Today!)
Feedback
"...Your site was well structured and I found what I was looking for in about 2 minutes. I am looking forward to participating with you in the future..."
Geography
Where in the world do Tek-Tips members come from?
|
pointer of array-valued functions (2)
|
|
|
mazkime (TechnicalUser) |
1 Aug 12 9:27 |
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 --> Fortranprogram 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.
|
|
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
|
|
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. |
|
|
mikrom (Programmer) |
2 Aug 12 4:41 |
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)
|
|
|
mazkime (TechnicalUser) |
2 Aug 12 6:53 |
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 --> fortranreal*8, pointer :: ap(:)
What I tried to do is to use the following declaration :
CODE --> fortranreal*8, external, pointer :: ap(:)
but in that case I get the following error during the compilation :
CODE --> fortranError: 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 --> fortranmodule 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 --> fortranmodule 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 --> fortrancall 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...
|
|
|
mikrom (Programmer) |
2 Aug 12 7:26 |
|
|
mazkime (TechnicalUser) |
2 Aug 12 7:46 |
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 ! |
|
|
mikrom (Programmer) |
2 Aug 12 9:04 |
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
CODEmodule 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
|
|
|
mazkime (TechnicalUser) |
2 Aug 12 12:09 |
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 --> fortraninteface
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 --> fortranmodule 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 ! |
|
|
mikrom (Programmer) |
2 Aug 12 13:24 |
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... |
|
|
mikrom (Programmer) |
2 Aug 12 15:34 |
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) / |
|
|
mazkime (TechnicalUser) |
2 Aug 12 16:08 |
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. |
|
|
mazkime (TechnicalUser) |
3 Aug 12 8:14 |
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 --> fortranreal :: f(2)
to
CODE --> fortranreal :: 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 --> fortranmodule 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
|
|
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.
CODEmodule 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 |
|
typo!!! Sorry....need to change "allocate(f5(2))" to "allocate(f5(5))" !!! |
|
and the indices (2) (2) (2) to (3) (4) (5) ... |
|
mikrom (Programmer) |
3 Aug 12 9:30 |
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
CODEmodule 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:
CODEfunction 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) |
|
|
mazkime (TechnicalUser) |
3 Aug 12 11:34 |
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.
|
|
|
 |
|