Date sent: Tue, 27 Mar 2001 11:29:47 -0500
Send reply to: Fortran 90 List <[log in to unmask]>
From: Aleksandar Donev <[log in to unmask]>
Organization: Physics & Astronomy Department
Subject: Re: Pointers: Is this safe and legal?
To: [log in to unmask]
I understand your problem and have experienced the same problem myself.
The main difficulty I see with your solution is a reliance on somewhat obscure
side-effects on GLOBAL variables (e.g. the Graph pointer). Did you consider a
'conventional' reverse communication interface something like that shown below.
If so, what do you see as the main drawbacks?
MODULE OptimizeModule
USE CGmodule ! See below
USE GraphMultiplyModule ! See below
CONTAINS
SUBROUTINE Optimize(...,graph,...,CGstate)
TYPE(GraphType), INTENT(INOUT) :: graph
TYPE(CGstateType), INTENT(INOUT) :: CGstate
... Local Variables ...
....
CALL CGforOptimize(...,graph,...CGstate,...)
....
END SUBROUTINE Optimize
SUBROUTINE CGforOptimize(...,graph,...CGstate,...)
TYPE(GraphType), INTENT(INOUT) :: graph
TYPE(CGstateType), INTENT(INOUT) :: CGstate
! ... Conventional reverse communication interface to CG ...
DO
CALL CG(...,CGstate)
SELECT CASE(CGstate%public%UserAction)
CASE(CG_UserAction_Multiply)
CALL GraphMultiply(...graph...)
...
CASE(CG_UserAction_Precondition)
...
CASE(CG_UserAction_EndSuccess)
EXIT
CASE(CG_UserAction_EndFailure)
... Process failure condition ...
END SELECT
END DO
END SUBROUTINE CGforOptimize
END MODULE OptimizeModule
MODULE CGmodule
INTEGER, PUBLIC, PARAMETER :: CG_UserAction_Multiply = 1, &
CG_UserAction_Precondition = 2, &
CG_UserAction_EndSuccess = 3, &
CG_UserAction_EndFailure = 4
INTEGER, PRIVATE, PARAMETER :: CG_Return_Initialize = 1, &
CG_Return_AfterPreCondition = 2, &
etc...
TYPE, PUBLIC :: CGstate_public
PUBLIC
INTEGER :: UserAction ! Value tells caller what action is needed
...
END TYPE CGstate_public
TYPE, PUBLIC :: CGstate_private
PRIVATE
... stuff that is needed to continue next iteration ...
... but which is not meant to be visible to the user ...
INTEGER :: Return = CG_Return_Initialize
END TYPE CGstate_private
TYPE CGstate
PUBLIC
public :: CGstate_public
private :: CGstate_private
END TYPE CGstate
CONTAINS
SUBROUTINE CG(...,state)
...
TYPE(CGstateType), INTENT(INOUT) :: state
...
SELECT CASE (state%private%Return)
CASE(CG_ReturnTo_Initialize)
... First Call ... Do initialization ...
state%private%Return = CG_Return_AfterPrecondition
state%public%UserAction = CG_UserAction_Precondition
CASE(CG_Return_AfterPrecondition)
...
CASE(CG_Return_xyz)
...
END SELECT
...
END SUBROUTINE CG
END MODULE CGmodule
MODULE GraphMultiplyModule
TYPE, PUBLIC :: GraphType
INTEGER, DIMENSION(:), POINTER :: graph
END TYPE GraphType
CONTAINS
SUBROUTINE GraphMultiply(graph)
TYPE(GraphType), INTENT(INOUT) :: graph
...
END SUBROUTINE GraphMultiply
END MODULE GraphMultiplyModule
module TrickyReverseCommunication
integer, dimension(:), pointer [, save] :: graph ! How about SAVE here?
>
> contains
>
> subroutine Initialize(Graph_)
> integer, dimension(:), intent(in), target :: Graph_
> Graph=>Graph_ ! Point to a graph data-structure
> end subroutine Initialize
>
> subroutine Optimize(...)
> CALL CG(Multiply=GraphMultiply,...) ! We pass GraphMultiply to CG
> ...
> end subroutine Optimize
>
> subroutine GraphMultiply()
> ...=Graph... ! We use Graph here
> end subroutine GraphMultiply
>
> ....
> end module TrickyReverseCommunication
>
> Hello,
>
> > IMHO, this approach is legal, but poor design. It is not thread safe
> > since there is only one copy of graph. I think a much better way is to
> > define a derived type:
> >
> > type Opt_data
> > integer, dimension(:), pointer :: graph
> > ...
> > end type Opt_data
> >
> > The user declares an object of this type, which is passed to
> > Optimize. And you need a similar design for CG.
>
> Both comments (from you and Kurt) are very correct. I am very (painfully)
> aware of the design flaw, but let me explain why I see no way out of it. If
> you do, I would appreciate any ideas. I already mentioned the problem
> earlier when I asked about ways to share an argument between two procedures.
> Also, I mentioned that what bothered me was the inexistence of an equivalent
> of C++'s classes in F90.
>
> Namely, CG is really in a separate module and has nothing to do with
> Optimize. It is a plain Conjugate Gradient solver that should not know or
> care about what it is solving. So, changing it's design to include an
> argument Opt_data is in my opionion not a good choice. At the same time
> though, one wants to give enough freedom to the user to allow for a
> flexible, yet safe and elegant reverse communication interface for the
> preconditioner and matrix multiplication in CG. The example I showed is such
> an entangled "reverse communication" interface which uses modules to share
> data between procedures and a global pointer to share Graph between Optimize
> and GraphMultiply. *IF* we had a class-type derived data-type in which
> Opt_data would not just contain the data Graph, but also have an associated
> routine GraphMultiply that COULD be (i.e. the standard should allow this)
> passed on as an actual argument to Optimize, all would be great and the
> whole design thread safe and all. But for now modules are the only safe way
> I know of for sharing data-between procedures.
>
> Is the problem clear from this explanation? This is why I asked for a
> summary of proposed F2K changes, so I can write the code using modules for
> now, but in such a way that changing them to classes would be relatively
> easy.
>
> As to Kurt's advice, he was correct, I forgot to put TARGET on the actual
> argument, but I will do that for safety.
>
> Thanks,
> Aleksandar
>
> _____________________________________________
> Aleksandar Donev
> http://www.pa.msu.edu/~donev/
> [log in to unmask]
> (517) 432-6770
> Department of Physics and Astronomy
> Michigan State University
> East Lansing, MI 48824-1116
> _____________________________________________
Regards,
David.
----------------------------------------------------------
David Vowles
Research Officer
Department of Electrical and Electronic Engineering
The University of Adelaide
Australia 5005
Voice: +61 8 8303 5416
Fax: +61 8 8303 4360
Email: [log in to unmask]
Home Page: http://www.eleceng.adelaide.edu.au/Personal/dvowles/home.html
|