Can I mimic multiple passed-object dummy arguments in Fortran? - fortran

I would like to write a procedure which takes two passed-object dummy arguments, such as
module m
type, abstract :: Parent
contains
procedure(f_Parent), deferred :: f
end type
abstract interface
subroutine f_Parent(foo,bar)
import Parent
implicit none
class(Parent), intent(in) :: foo
class(Parent), intent(in) :: bar
end subroutine
end interface
type, extends(Parent) :: Child
contains
procedure, public :: f => f_Child
end type
contains
subroutine f_Child(foo,bar)
implicit none
class(Child), intent(in) :: foo
class(Child), intent(in) :: bar
end subroutine
end module
but this is not allowed by the Fortran standard, as bar is not a passed-object dummy argument, and so must be class(Parent) and not class(Child).
My current solution is
subroutine f_Child(foo,bar)
implicit none
class(Child), intent(in) :: foo
class(Parent), intent(in) :: bar
select type(bar); type is(Child)
end select
end subroutine
which works, but the select type construct is too slow, and dominates the runtime of my code (this subroutine is called many times).
I have tried having a single passed-object argument which holds both foo and bar, e.g. as an array or pointer, but this is also forbidden by the standard.
Is there any way of mimicking the behaviour of having multiple passed-object dummy arguments which does not incur the cost of a select type construct? Or maybe a faster way of getting an argument of class(Child) from class(Parent)?

You can do it by using single dispatch twice:
Module m
Implicit None
Type, Public, Abstract :: Parent
Contains
Procedure( i_Parent_Parent ), Public , Deferred :: f
Procedure( i_Child_Parent ), Pass( bar ), Private, Deferred :: f_c_p
Procedure( i_set ), Public , Deferred :: set
End Type Parent
Type, Public, Extends( Parent ) :: Child
Integer , Private :: data
Contains
Procedure , Public :: f => f_Child_Parent
Procedure, Pass( bar ), Private :: f_c_p => f_Child_Child
Procedure , Public :: set => f_Child_set
End Type Child
Private
Abstract Interface
Subroutine i_Parent_Parent( foo, bar )
Import :: Parent
Implicit None
Class( Parent ), Intent( In ) :: foo
Class( Parent ), Intent( In ) :: bar
End Subroutine i_Parent_Parent
Subroutine i_Child_Parent( foo, bar )
Import :: Parent, Child
Implicit None
Class( Child ), Intent( In ) :: foo
Class( Parent ), Intent( In ) :: bar
End Subroutine i_Child_Parent
Subroutine i_set( foo, data )
Import :: Parent
Class( Parent ), Intent( InOut ) :: foo
Integer , Intent( In ) :: data
End Subroutine i_set
End Interface
Contains
Subroutine f_Child_Parent( foo, bar )
Implicit None
Class( Child ), Intent( In ) :: foo
Class( Parent ), Intent( In ) :: bar
Call bar%f_c_p( foo )
End Subroutine f_Child_Parent
Subroutine f_Child_Child( foo, bar )
Implicit None
Class( Child ), Intent( In ) :: foo
Class( Child ), Intent( In ) :: bar
Write( *, * ) 'In child child foo%data = ', foo%data, ' bar%data = ', bar%data
End Subroutine f_Child_Child
Subroutine f_Child_set( foo, data )
Implicit None
Class( Child ), Intent( InOut ) :: foo
Integer , Intent( In ) :: data
foo%data = data
End Subroutine f_Child_set
End Module m
Program driver
Use m, Only : Parent, Child
Class( Parent ), Allocatable :: foo, bar
Allocate( Child :: foo )
Allocate( Child :: bar )
Call foo%set( 3 )
Call bar%set( 4 )
Call foo%f( bar )
End Program driver
ian#eris:~/work/stack$ gfortran-8 -std=f2008 -fcheck=all -Wall -Wextra dd.f90
ian#eris:~/work/stack$ ./a.out
In child child foo%data = 3 bar%data = 4
ian#eris:~/work/stack$
Whether this is quicker than select type will be implementation dependent, but I think it is cleaner.

Related

Implicit interface procedure pointer member for derived type

In a derived type, I am trying to use a generic procedure function pointer member-type in order to point to different same derived type-bound procedures, which happen to have different interfaces.
module SharedMod
use SettingsMod
implicit none
type, public :: shared_t
type(settings_t) :: settings
...
contains
...
procedure, pass :: run
procedure, nopass :: readSettings, getSettingsFromProg
end type shared_t
contains
subroutine run(this, sett_file)
class(shared_t) :: this
character(len = 132), intent(in), optional :: sett_file
if (present(sett_file)) then
this%settings%GetSettings => this%readSettings
else
this%settings%GetSettings => this%getSettingsFromFinelg
endif
#if defined __PROG__
call this%settings%GetSettings(this%settings)
#else
call this%settings%GetSettings(this%settings, sett_file)
#endif
...
end subroutine run
...
subroutine readSettings(setts, file)
class(settings_t) :: setts
character(len = *), intent(in) :: file
integer :: itmp
real(RDP) :: rtmp
print *, '#Shared::readSetting() : reading settings from file..'
end subroutine readSettings
subroutine getSettingsFromProg(setts)
implicit none
class(settings_t) :: setts
print *, '#Shared::getSettingsFromProg() : reading settings from PROG..'
end subroutine getSettingsFromProg
end module
module SettingsMod
implicit none
type, public :: settings_t
...
procedure(), public, pointer, nopass :: GetSettings => null()
end module
When compiling using ifort I get:
error #8191: The procedure target must be a procedure or a procedure pointer. [READSETTINGS]
this%settings%GetSettings => this%readSettings
error #8191: The procedure target must be a procedure or a procedure pointer. [GETSETTINGSFROMFINELG]
this%settings%GetSettings => this%getSettingsFromFinelg
I also tried the version where GetSettings() is a type-boud procedure, i.e.
module SettingsMod
...
type, public :: settings_t
...
contains
procedure(), public, pass :: GetSettings => getSettingsFromProg, readSettings
...
end type settings_t
abstract interface
subroutine getSettingsFromProg(this)
import settings_t
class(settings_t) :: this
end subroutine getSettingsFromFinelg
end interface
abstract interface
subroutine readSettings(this, file)
import settings_t
class(settings_t) :: this
character(len = *), intent(in) :: file
end subroutine readSettings
end interface
...
end module
having :
error #6784: The number of actual arguments cannot be greater than the number of dummy arguments. [GETSETTINGS]
call this%settings%GetSettings(sett_file)
At this point, I have two questions:
Why do I get these errors??
How would you suggest to implement such a concept, if I was clear enough to explain it?
Thanks a lot.
EDIT after first #Vladimir 's comment.
After having post the answer in which I show how I finally found a working solution, still, I have more questions now:
Why did it work adding () just to the type-bound procedures pointed to?
Why did it work without pointer assignment?
Why did the equivalent type-bound procedure version not worked, even providing abstract interfaces to the two external procedures?
Still look forward to discussion.
It worked for the function-pointer procedure member-type version, after having added () after the procedure keyword in the shared_t type-bound procedures:
module SharedMod
use SettingsMod
implicit none
type, public :: shared_t
type(settings_t) :: settings
...
contains
...
procedure, pass :: run
procedure(), nopass :: readSettings, getSettingsFromProg
end type shared_t
contains
subroutine run(this, sett_file)
class(shared_t) :: this
character(len = 132), intent(in), optional :: sett_file
#if defined __PROG__
call this%settings%GetSettings(this%settings)
#else
call this%settings%GetSettings(this%settings, sett_file)
#endif
...
end subroutine run
...
subroutine readSettings(setts, file)
class(settings_t) :: setts
character(len = *), intent(in) :: file
integer :: itmp
real(RDP) :: rtmp
print *, '#Shared::readSetting() : reading settings from file..'
end subroutine readSettings
subroutine getSettingsFromProg(setts)
implicit none
class(settings_t) :: setts
print *, '#Shared::getSettingsFromProg() : reading settings from PROG..'
end subroutine getSettingsFromProg
end module
module SettingsMod
implicit none
type, public :: settings_t
...
procedure(), public, pointer, nopass :: GetSettings => null()
end module
Still, I have more questions now:
Why did it work adding () just to the type-bound procedures pointed to?
Why did it work without pointer assignment?
Why did the equivalent type-bound procedure version not worked, even providing abstract interfaces to the two external procedures?
Looking forward to discussion.

How to apply [##deriving show] to a type from module parameter of my functor?

I have a functor that takes a Set type like:
module type MySet = functor (S : Set.S) -> sig
val my_method : S.t -> S.elt -> S.elt list option
end
module MySet_Make : MySet = functor (S : Set.S) -> struct
let my_method set el = Some [el] (* whatever *)
end
module IntSet = Set.Make(Int)
module MyIntSet = MySet_Make(IntSet)
S.elt is the type of elements of the set
I want to apply [##deriving show] (from https://github.com/ocaml-ppx/ppx_deriving#plugin-show) to S.elt within my functor somehow, so that in one of my methods I can rely on having a show : S.elt -> string function available.
I feel like it must be possible but I can't work out the right syntax.
Alternatively - if there's a way to specify in the signature that the Set type S was made having elements of a "showable" type.
e.g. I can define:
module type Showable = sig
type t [##deriving show]
end
...but I can't work out how to specify that as a type constraint to elements of (S : Set.S)
You can construct new signatures that specify the exact function show you need:
module MySet_Make(S : sig
include Set.S
val show : elt -> string
end) = struct
let my_method _set el =
print_endline (S.show el);
Some [el]
end
Then you can build the actual module instance by constructing the module with the needed function:
module IntSet = struct
include Set.Make(Int)
(* For other types, this function could be created by just using [##deriving show] *)
let show = string_of_int
end
module MyIntSet = MySet_Make(IntSet)
Ok, after a couple of hours more fumbling around in the dark I found a recipe that does everything I wanted...
First we define a "showable" type, representing a module type that has had [##deriving show] (from https://github.com/ocaml-ppx/ppx_deriving#plugin-show) applied to it:
module type Showable = sig
type t
val pp : Format.formatter -> t -> unit
val show : t -> string
end
(I don't know if there's some way to get this directly from ppx_deriving.show without defining it manually?)
Then we re-define and extend the Set and Set.OrderedType (i.e. element) types to require that the elements are "showable":
module type OrderedShowable = sig
include Set.OrderedType
include Showable with type t := t
end
module ShowableSet = struct
include Set
module type S = sig
include Set.S
end
module Make (Ord : OrderedShowable) = struct
include Set.Make(Ord)
end
end
I think with the original code in my question I had got confused and used some kind of higher-order functor syntax (?) ...I don't know how it seemed to work at all, but at some point I realised my MySet_Make was returning a functor rather than a module. So we'll fix that now and just use a normal functor.
The other thing we can fix is to make MySet a further extension of ShowableSet ... so MySet_Make will take the element type as a parameter instead of another Set type. This makes the eventual code all simpler too:
module type MySet = sig
include ShowableSet.S
val my_method : t -> elt -> elt list option
val show_el : elt -> string
end
module AdjacencySet_Make (El : OrderedShowable) : AdjacencySet
with type elt = El.t
= struct
include ShowableSet.Make(El)
let my_method set el = Some [el] (* whatever *)
let show_el el = El.show el (* we can use the "showable" elements! *)
end
Then we just need an OrderedShowable version of Int as the element type. Int is already ordered so we just have to extend it by deriving "show" and then we can make a concrete MySet:
module Int' = struct
include Int
type t = int [##deriving show]
end
module MyIntSet = MySet_Make(Int')
And we can use it like:
# let myset = MyIntSet.of_list [3; 2; 8];;
# print_endline (MyIntSet.show_el 3);;
"3"

Cannot pass a valid communicator from fortran to c/c++

After passing MPI communicator from Fortran to C/C++ and upon checking the size communicator resulted in the following error message:
An error occurred in MPI_Comm_size on communicator...MPI_COMM_WORLD
...MPI_ERR_COMM: invalid communicator
Although the communicator on C/C++ side is not MPI_COMM_NULL, looks like it is not valid either. Below are the code that produced the error message.
C++
extern "C"
{
MPI_Comm* f_MPI_Comm_f2c(MPI_Fint f_handle)
{
MPI_Comm* comm;
comm = (MPI_Comm*)malloc(sizeof(MPI_Comm));
*comm = MPI_Comm_f2c(f_handle);
assert(*comm != MPI_COMM_NULL);
int size;
MPI_Comm_size(*comm, &size);
std::cout << "size: " << size << std::endl;
return comm;
}
}
Fortran module
module mymodule
use mpi
use, intrinsic :: ISO_C_Binding, only: c_ptr, c_null_ptr
implicit none
private
interface
function f_MPI_Comm_f2c(comm) result(optr) bind(C, name="f_MPI_Comm_f2c")
import c_ptr
implicit none
integer, intent(in) :: comm
type(c_ptr) :: optr
end function f_MPI_Comm_f2c
end interface
type(c_ptr), save :: ccomm = c_null_ptr
public :: CreateCcomm
CONTAINS
subroutine CreateCcomm(com)
!type(c_ptr) :: ccomm
integer, intent(in) :: com
ccomm = f_MPI_Comm_f2c(com)
end subroutine CreateCcomm
end module mymodule
Fortran driver
program main
use mpi
use mymodule, only : CreateCcomm
IMPLICIT NONE
integer error
call MPI_Init(error)
call CreateCcomm(MPI_COMM_WORLD)
call MPI_Finalize (error)
end

How to map modules to a module type in OCaml?

I want to define a module type that depends on other modules. I thought I could do it with a functor, but I believe functors are only mappings from modules to modules and it's not possible to use them to define mappings from a module to a module type.
Here's an example of what I'd like to do:
module type Field =
sig
type t
val add : t -> t -> t
val mul : t -> t -> t
end
module type Func (F1 : Field) (F2 : Field) =
sig
val eval : F1.t -> F2.t
end
module FuncField (F1 : Field) (F2 : Field) (F : Func F1 F2) =
struct
let eval a = F.eval a
let add a b = F2.add (F.eval a) (F.eval b)
let mul a b = F2.mul (F.eval a) (F.eval b)
end
I have a Field module type, like the real and rational numbers for example, and I want to define the type of functions Func from one field to another, which is F1.t -> F2.t for any two given modules F1, F2. With those module types in place, I can then define FuncField, which takes F1, F2, F and basically augments F.eval with add and mul.
When I run the code, I get a generic Error: Syntax error in the line where I define Func. Is there a way to define something like this in OCaml?
I'm not sure if this requires dependent types, but I'm mildly familiar with Coq, which has dependent types, and it didn't complain when I defined an equivalent construct:
Module Type Field.
Parameter T : Type.
Parameter add : T -> T -> T.
Parameter mul : T -> T -> T.
End Field.
Module Type Func (F1 : Field) (F2 : Field).
Parameter eval : F1.T -> F2.T.
End Func.
Module FuncField (F1 : Field) (F2 : Field) (F : Func F1 F2).
Definition eval a := F.eval a.
Definition add a b := F2.add (F.eval a) (F.eval b).
Definition mul a b := F2.mul (F.eval a) (F.eval b).
End FuncField.
Functors are functions from modules to modules. There is no such thing as a functor from module type to module type .... but you can cheat. :)
Unlike Coq, OCaml's modules are not fully dependent types, but they are "dependent enough" in this case.
The idea is that modules can contain module types. Since we can't return a module type directly, we will simply return a module that contain one!
Your example become like that:
module type Field = sig
type t
val add : t -> t -> t
val mul : t -> t -> t
end
module Func (F1 : Field) (F2 : Field) = struct
module type T = sig
val eval : F1.t -> F2.t
end
end
module FuncField (F1 : Field) (F2 : Field) (F : Func(F1)(F2).T) = struct
let eval a = F.eval a
let add a b = F2.add (F.eval a) (F.eval b)
let mul a b = F2.mul (F.eval a) (F.eval b)
end
Note the Func(F1)(F2).T syntax, which says "apply the functor, and out of the result, take the module type T". This combination of functor application + field access is only available in types (either normal ones or module types).
I don't remember where I found that trick first, but you can see it in action "in production" in tyxml (definition, usage).
Going outside the box a little since it doesn't seem like you really need a functor to accomplish what you describe. Simple module constraints might suffice:
module type Field =
sig
type t
val add : t -> t -> t
val mul : t -> t -> t
end
module type Func =
sig
type t1
type t2
val eval : t1 -> t2
end
module FuncField (F1 : Field) (F2 : Field) (F : Func with type t1 = F1.t and type t2 = F2.t) =
struct
let eval a = F.eval a
let add a b = F2.add (F.eval a) (F.eval b)
let mul a b = F2.mul (F.eval a) (F.eval b)
end

gfortran operator overloading derived type and real()

I want to overload an operator (*) to perform vector-scalar multiplication in the following class:
module vectorField_mod
use constants_mod
implicit none
private
public :: vectorField
public :: allocateVectorField
public :: delete
type vectorField
real(dpn),dimension(:,:,:),allocatable :: x,y,z
end type
interface operator (*)
module procedure scalarMultiply
end interface
contains
function scalarMultiply(f,g) result(q)
implicit none
type(vectorField),intent(in) :: f
real(dpn),intent(in) :: g
type(vectorField) :: q
q%x = f%x * g
q%y = f%y * g
q%z = f%z * g
q%sx = f%sx; q%sy = f%sy; q%sz = f%sz
end function
...
end module
But I'm getting the following error:
Error: Operands of binary numeric operator '*' at (1) are REAL(8)/TYPE(vectorfield)
I'm trying to implement this like:
type(vectorField) :: a
real(8) :: dt = 0.001
call allocateVectorField(a,..)
a = a*dt
Is this not a binary operation? Is there still a way to do this? Any help is greatly appreciated!
Summary:
1) The answer by #francescalus was necessary, but not sufficient to yield a successful compilation.
2) In addition, it turns out that the order of multiplication is important. That is a = adt works, but a = dta does not work (this was the problem I was having)
Here's an illustrative sample:
module constants_mod
integer,parameter :: dpn = selected_real_kind(14)
end module
module vectorField_mod
use constants_mod
implicit none
private
public :: vectorField
public :: allocateX,allocateY,allocateZ
public :: delete
public :: operator(*)
type vectorField
integer,dimension(3) :: sx,sy,sz
real(dpn),dimension(:,:,:),allocatable :: x,y,z
end type
interface delete
module procedure deallocateVectorField
end interface
interface operator (*)
module procedure scalarMultiply
end interface
contains
function scalarMultiply(f,g) result(q)
implicit none
type(vectorField),intent(in) :: f
real(dpn),intent(in) :: g
type(vectorField) :: q
q%x = f%x * g; q%y = f%y * g; q%z = f%z * g
q%sx = f%sx; q%sy = f%sy; q%sz = f%sz
end function
subroutine allocateX(field,Nx,Ny,Nz)
implicit none
type(vectorField),intent(inout) :: field
integer,intent(in) :: Nx,Ny,Nz
if (allocated(field%x)) deallocate(field%x)
allocate(field%x(Nx,Ny,Nz))
field%sx = shape(field%x)
end subroutine
subroutine allocateY(field,Nx,Ny,Nz)
implicit none
type(vectorField),intent(inout) :: field
integer,intent(in) :: Nx,Ny,Nz
if (allocated(field%y)) deallocate(field%y)
allocate(field%y(Nx,Ny,Nz))
field%sy = shape(field%y)
end subroutine
subroutine allocateZ(field,Nx,Ny,Nz)
implicit none
type(vectorField),intent(inout) :: field
integer,intent(in) :: Nx,Ny,Nz
if (allocated(field%z)) deallocate(field%z)
allocate(field%z(Nx,Ny,Nz))
field%sz = shape(field%z)
end subroutine
subroutine deallocateVectorField(field)
implicit none
type(vectorField),intent(inout) :: field
deallocate(field%x,field%y,field%z)
field%sx = 0; field%sy = 0; field%sz = 0
end subroutine
end module
program test
use constants_mod
use vectorField_mod
implicit none
type(vectorField) :: a,b
integer :: N = 1
real(dpn) :: dt = 0.1
call allocateX(a,N,N,N)
call allocateY(a,N,N,N)
call allocateZ(a,N,N,N)
call allocateX(b,N,N,N)
call allocateY(b,N,N,N)
call allocateZ(b,N,N,N)
a%x = dble(1.0); a%y = dble(1.0); a%z = dble(1.0)
b%x = dble(1.0); b%y = dble(1.0); b%z = dble(1.0)
a = b
a = a*dt ! compiles fine
a = dt*a ! does not compile
call delete(a)
call delete(b)
end program
The default accessibility of the module is private. This default applies also to the defined operator.
To make the operator identifier public (so that it can be used outside the module) use a public statement like:
public :: operator(*)