- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Dear All,
for a new project, we are considering the exploitation of some of the advanced features of the Fortran 2003 standard, essentially run-time polymorphism via abstract data types.
The attached package contains a set of several Fortran 2003 sources files (together with the corresponding compilation bash script) that declare
two abstract data types for an operator [type(abs_operator)] (in its strict linear algebra sense, as e.g., a matrix) and its operands [type(abs_operands)] (e.g., a vector), respectively. An operator "is applied" to an operand, and returns a (pointer to) an operand. This "is applied" action is implemented thorough a deferred function of the operator. [The current implementation of a matrix and a vector is only a toy implementation, don't
pay too much attention into it].
Besides, we would like to create new operators by combining existing ones using overloaded +, *, etc. In order to overload +, a realization of an operator, type(sum_abs_operator), is declared, and its constructor, that takes two operators, and returns type(sum_abs_operator),
is used for that purpose. The same strategy is used for *. Such overloading is done for the operator abstract data type.
Using all these machinery as currently implemented, we are getting SIGSEV when executing the main program (drive_fops.f90) with ifort 13.0.1., 14.0.1, and 14.0.2 (the ones that we could test so far). In particular, in the implementation of the apply method corresponding to type(sum_abs_operator):
function sum_abs_operator_apply(op,arg) result(res)
implicit none
class(sum_abs_operator), intent(in) :: op
class(abs_operand) , intent(in) :: arg
class(abs_operand) , pointer :: res
res => op%op1%apply(arg) + op%op2%apply(arg)
end function sum_abs_operator_apply
a SIGSEV is triggered during the evaluation of " res=> ...". However, if implemented as:
function sum_abs_operator_apply(op,arg) result(res)
implicit none
class(sum_abs_operator), intent(in) :: op
class(abs_operand) , intent(in) :: arg
class(abs_operand) , pointer :: res
class(abs_operand) , pointer :: tmp1, tmp2
tmp1 => op%op1%apply(arg)
tmp2 => op%op2%apply(arg)
res => tmp1 + tmp2
end function sum_abs_operator_apply
then everything works fine (and they seem to be pretty similar to each other). The strange
thing about the SIGSEV is that during the evaluation of " res=> ...", it seems that the
compiler is not calling the vector realization of the deferred function that overloads
+ for the abstract operand, but that of the abstract operator (i.e., sum_abs_operator_construct).
May be there is no issue, and it is our missunderstanding, but we
have no clue about what could be causing this. We would highly appreciate any advice
that you could give us in that respect. Also, as we are beginning the usage of
these OO features of Fortran2003 we would also appreciate if you have any suggestion
on how to implement all this machinery in a better/cleaner/safer way (if any).
Thanks very much in advance.
Best regards,
Alberto.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
See what the following do:
res => (op%op1%apply(arg) + op%op2%apply(arg))
res => ((op%op1%apply(arg)) + (op%op2%apply(arg)))
RE: drive_fops
The deallocate's at the end are likely problematic as the pointee may not be allocatable (in the case of v it is not allocatable)
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Dear Jim,
thanks for your response. The expressions you provided do not compile (see error messages below). I do not actually understand the error message. Any clue of what's going on ?
Best regards,
Alberto.
ifort -c -module Objects -g -O0 -r8 -traceback -debug all -check all -ftrapuv -stand f03 -o Objects/foperator.o foperator.f90
foperator.f90(140): error #6678: When the target is an expression it must deliver a pointer result.
res => ( op%op1%apply(arg) + op%op2%apply(arg) )
-------------------------------^
ifort -c -module Objects -g -O0 -r8 -traceback -debug all -check all -ftrapuv -stand f03 -o Objects/foperator.o foperator.f90
foperator.f90(140): error #6678: When the target is an expression it must deliver a pointer result.
res => ( (op%op1%apply(arg)) + (op%op2%apply(arg)) )
---------------------------------^
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You're using pointer assignment (=>). Here you probably want just intrinsic assignment (=). I have not looked at your whole code.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It looked to me as if the pointer=> construct was intended to point to the temporary expression result. I haven't read the latest standards to see if this were permitted. I apologize for any inconvenience my reply may have caused.
The assignment operator (=) will work, but it may also require a copy operation (though the optimization process may result in generating the result in the lhs of = as opposed to in a temp then copy.
An alternate method might be to use the ASSOCIATE which may produce the same functionality as intended by the code using the pointer=>.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
No, you can't point to an expression. You can only point to things that have the TARGET attribute and there is no way to give an expression that attribute.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Sure? Here "+" is (should be) overloaded with a function that returns a pointer. As far as I understand you can point to a pointer, right? I mean, a pointer is intrinsically a target, right? Would the assignment operator work in this case? I would say no.
In the example posted by Alberto (we work together) everything works fine when doing
tmp1 + tmp2
both being pointers defined locally whereas doing
op%op1%apply(arg) + op%op2%apply(arg)
a SIGSEV occurs.
If we (Alberto and me) are right, in the second case the compiler is overloading + with the wrong function (sum_abs_operator_constructor), the one acting on op which is a type that bounds the procedure apply that returns a vector, instead of doing it with the one acting on vectors (addvec). Introducing local pointers tmp => op%op1%apply(arg) everything works fine.
Many thanks!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Putting together what Steve last said you can't point to an expression, which in the case I presented was a result of an expression, and which appears to be what you want for desired behavior. It would then lead to res => tmp1 + tmp2 producing a result of an expression of which you are assigning a pointer to. The fact that the compiler does not emit an error message would then be indicative of an error in the compiler.
In your attached .f90 files you return a pointer to a newly allocated object, which is correct. In the code presented in first post you do not, which is wrong. You could do something like:
function sum_abs_operator_apply(op,arg) result(res) implicit none class(sum_abs_operator), intent(in) :: op class(abs_operand) , intent(in) :: arg class(abs_operand) , pointer :: res class(abs_operand) , SAVE :: res_save res_save = op%op1%apply(arg) + op%op2%apply(arg) res => res_save end function sum_abs_operator_apply
However, this restricts your code to having only one sum_abs_operator_apply object pending at any one time. And code that would not be thread safe.
While you could ALLOCATE the return object and point res at it, then you have to assure that somehow the object is deleted at the appropriate time. This would mean you would need to add reference counting and garbage collection, etc...
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Or consider:
function sum_abs_operator_apply(op,arg) result(res) implicit none class(sum_abs_operator), intent(in) :: op class(abs_operand) , intent(in) :: arg class(abs_operand) , pointer :: res integer, parameter :: MAX_LIFETIME = 100 class(abs_operand) , SAVE :: res_save(MAX_LIFETIME) integer , SAVE :: i = 1 res_save(i) = op%op1%apply(arg) + op%op2%apply(arg) res => res_save i = i + 1 if(i .gt. MAX_LIFETIME) i = 1 end function sum_abs_operator_apply
This would provide a longer lifetime. You will have to decide what is safe for the lifetime.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jim, your code does not compile (see the errors below). Once again:
+ is overloaded with a function that returns a pointer
In fact, the following error (which I got in another context using the Intel compiler) explicitly says that you can point to an expression:
error #6678: When the target is an expression it must deliver a pointer result. error #6678: When the target is an expression it must deliver a pointer result.
We are quite convinced that the problem is the wrong overloading but we would be 100% sure. We really appreciate your help in clarifying the issue.
Many thanks,
foperator.f90(150): error #8304: In an intrinsic assignment statement, variable shall not be polymorphic. [RES_SAVE]
res_save = op%op1%apply(arg) + op%op2%apply(arg)
----^
foperator.f90(151): error #6796: The variable must have the TARGET attribute or be a subobject of an object with the TARGET attribute, or it must have the POINTER attribute. [RES_SAVE]
res => res_save
-----------^
foperator.f90(149): error #8223: An entity declared with the CLASS keyword shall be a dummy argument or have the ALLOCATABLE or POINTER attribute. [RES_SAVE]
class(abs_operand) , SAVE :: res_save
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Considering the error message:
function sum_abs_operator_apply(op,arg) result(res) implicit none class(sum_abs_operator), intent(in) :: op class(abs_operand) , intent(in) :: arg class(abs_operand) , pointer :: res integer, parameter :: MAX_LIFETIME = 100 class(abs_operand), pointer, SAVE :: res_save(MAX_LIFETIME) integer , SAVE :: i = 1 select type(arg) type is(vector) select type(res) type is(vector) if(.not.associated(res_save(i))) allocate(vector::res_save(i)) res = res_save(i) ! note = to copy pointer not =>, though => may work as well i = i + 1 if(i .gt. MAX_LIFETIME) i = 1 ! type is(...) end select class default write(*,*) 'This realization of operator (vector) cannot be applied' write(*,*) 'to this realization of operand' end select end function sum_abs_operator_apply
Would that work?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Note, it would be better to take the array of pointers out of the function and place them in the scope of the module (with the contains function sum_abs_...) and use multiple arrays of your various types. These arrays can then have a proper init to NULLIFY the initial entries, and if desired DEALLOCATE's to reclaim memory at appropriate times.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
We have compiled the code using the IBM compiler and the problem disappeared. It is quite clear that this an IFC issue: it is overloading the wrong function.
Best
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Javier, which code did you compile? Please attach the source you used.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The same code Alberto posted with the minor corrections he uploaded afterwards (the bug he corrected is unrelated to the issue). I attach it again in a single package to make it easier for you. Download it, compile.sh and it works. Go to foperator.f90 uncomment line 141, comment lines 146-148, and you will see the SIGSEV. You will also see a print from the (wrongly) overloaded function.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks - we'll take a look.
By the way, I see that the build script uses -ftrapuv. I recommend not using that - it doesn't add any value.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Javier Principe wrote:
We have compiled the code using the IBM compiler and the problem disappeared. It is quite clear that this an IFC issue: it is overloading the wrong function.
Best
Javier,
Have you tried Intel compiler version 15? FWIW, your program doesn't generate any segmentation violation error with Intel Fortran 15.0.0.108 on Windows. The output is as follows:
XXX XXX 9.00000000000000 9.00000000000000 2.00000000000000 2.00000000000000 2.00000000000000 2.00000000000000 Press any key to continue . . .
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Dear FortranFan,
just to be sure, did you follow the instructions pointed by Javier to reproduce the issue?, i.e.,
Go to foperator.f90 uncomment line 141, comment lines 146-148, and you will see the SIGSEV.
I tried Intel Fortran compiler for Linux, versions 14.0.3.174, 14.0.4.211, and 15.0.0.090, and the SIGSEV is still there.
Best regards,
Alberto.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I was able to reproduce the problem in 15.0.

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page