TRANSFER arbitrary data ? (long)



Sorry for the long post, I don't know how to make it more concise.
Let me see if I can explain what I'm trying to do... Consider a
subroutine to minimize a function of n variables,

subroutine minimize(Func, x)
real, dimension(:), intent(inout):: x
interface
real function Func(z)
real, dimension(:), intent(in):: z
end function Func
end interface
!
! Start calling Func(x) and use some clever
! algorithm to modify x until Func(x)
! reaches a minimum
end subroutine minimize

So I write the body of the minimizer, place it in a module, and
people can USE the module and minimize their own objective functions,

X= initial_guess
call minimize(my_function, X)

where my_function is supplied by the user and conforms to the
interface declaration in subroutine minimize.

The trouble is, user functions invariably depends on other things
(mathematical parameters) besides the argument X. The number and
type of the parameters is unknown at the time "minimize" is being
written. The old-time solution is to stuff the parameters in a
common block known to "my_function" and and make sure the common is
initialized before calling "minimize". This is not a good solution.
Nowadays we would replace the common by a module USEd by my_function,
but that is essentially the same solution, safer but still not a
good solution.

I want to modify "minimize" to take an additional argument representing
a block of arbitrary data and pass said block to the user function
without ever looking at it. The user function and the caller of
"minimize" know how to make sense of the block, but "minimize" itself
doesn't have to. Unfortunately Fortran 95 has no concept of a block
of arbitrary data. The CLASS(*) of Fortran 2003 seems to fit the
bill, but I don't have an F03 compiler.

I came up with a hack using the TRANSFER intrinsic but I'd like
some advice before putting in real code (if ever). The idea
is to wrap the parameters in a user-defined type and TRANSFER
that to an integer array and back.


subroutine minimize(Func, x, context)
real, dimension(:), intent(inout):: x
integer, dimension(:):: context
interface
real function Func(z, ctx)
real, dimension(:), intent(in):: z
integer, dimension(:):: ctx
end function Func
end interface
!
! Start calling Func(x, context) and use some
! clever algorithm to modify x until Func(x)
! reaches a minimum
end subroutine minimize

So "minimize" only need to know about one new assumed-shape
integer array. The user function and the caller of
"minimize" conspire as follows to exchange information:

type fred
! arbitrarily complex data structures go here
end type fred

type(fred) my_params

...

call minimize( &
my_function, x, &
TRANSFER(my_params, (/1/)) &
)

....

real function my_function(x, context)
real, dimension(:), intent(in):: x
integer, dimension(:):: context

type(fred) his_params

his_params= TRANSFER(context, his_params)

! computations have full access to his_params

return
end function my_function

all this in modules so the explicit interfaces are visible.
By using an array as the MOLD of the initial TRANSFER, I
ensure that the context(:) array passed to "minimize" is big enough.

Now, is this going to work ? My reading of the standard is that
TRANSFER is the only legal way to do any kind of type punning in
Fortran ("Returns a result with a physical representation identical
to that of SOURCE but with but interpreted with the type and type
parameters of MOLD", 13.14.110), but the standard is remarkably
laconic as to what one is allowed to do after the types are punned.
Meanwhile, there is the standard and there is the real world. In
the real world,

1) Is "A= TRANSFER( TRANSFER(A, (/1/)), A)" garanteed to be
a no-op ?
2) Is there a better type than default integer to use for
the intermediate array ?
3) Do I need to worry about trap representations ?
4) Can I TRANSFER and unpack a user-defined type with allocatable
components ?
5) Will the unpacked variable break aliasing rules and run afoul
of optimizers ?
6) For large allocatable components, will the TRANSFERS make
expensive copies ?

A more general question is: is this in the spirit of what TRANSFER
is supposed to do and will implementers support the idiom ? Or am
I crazy and should I give up now ?

Thanks for reading through this.

--
pa at panix dot com
.



Relevant Pages