sum - for non numeric type

1 view
Skip to first unread message

PGK

unread,
Jul 30, 2009, 7:16:15 PM7/30/09
to gg95
Hi all,

I see that I can't use the sum intrinsic with my 2D vec3 array, as
it's not a numeric type. (I was initially hoping the following code
would compile; to sum over the first dimension; I also overloaded the
addition operator.) What is the best way to achieve such a sum, but
particularly using an array-based approach; so avoiding (i,j)
iteration variables?

Thanks,
Graham

type, public :: vec3
real(kind=k), dimension(3) :: es
end type vec3

type(vec3), dimension(n,n) :: A
type(vec3), dimension(n) :: B
B = sum(A,1)

Alvaro Fernandez

unread,
Aug 6, 2009, 2:24:11 PM8/6/09
to gg...@googlegroups.com
If you haven't gotten an answer yet from anyone, here's what you need to do: use modules to create a "class", and create your own  sum 'method' that will handle the situation:
 
1. Create a module called e.g. vec3_class.
2. Put the type definitions you have in this module.
3. Using interfaces, create your own "sum".
4. Define the internal sum procedure to do what you want. I followed your lead.
5. 'use' the module.
 
Here's an example, with no validation or anything. I don't have g95 installed on this box, so the syntax may be off in  a place or two. The one thing I am not sure about is whether you can overload on an instrinsic function like sum(). I think you can. Otherwise, you can call it mysum(), or I can show you how to overload the "+" operator and that will work fine no matter what.
 
module vec3_class
 
private                     ! default all contents are private
public :: vec3, sum    ! except the type "wrap" and the interface to the method
 
implicit none             ! Always. :)
 
type :: vec3
  private                                         ! Makes the contents of this type private; the name is public, cf above.
  real(kind=k), dimension(3) :: es
end type vec3
interface sum
    module procedure sum_             ! Name for this method. You can add more here as long as they
end interface                                   ! can be disambiguated - good old compile-time polymorphism.
 
contains
   
    function sum_(this,dim) result(fval)
        type(vec3),intent(in) :: this
        integer,intent(in) :: dim
        real(kind=k) :: fval
 
        fval = sum(this%es,dim=dim)  ! Pass in the contents of the object to the intrinsic.
    end function sum_
 
end module vec3_class
 
program test
    use vec3_class   ! Bring in the interface and type definition.
    implicit none

    type(vec3),  dimension(n,n) :: A
    type(vec3),  dimension(n) :: B
    B = sum(A,1)
 
end program test
 
 


From: PGK <graha...@gmail.com>
To: gg95 <gg...@googlegroups.com>
Sent: Thursday, July 30, 2009 6:16:15 PM
Subject: sum - for non numeric type

PGK

unread,
Aug 11, 2009, 6:05:58 AM8/11/09
to gg95
Thanks Alvaro,

I tried your code, but unfortunately it won't compile. I fixed the
typos, but it seems that perhaps the sum intrinsic can't be
overloaded. I had previously tried overloading the (+) operator, but I
also tried that again, using the vec3 class/module approach you
suggested, but no luck there either. I also tried adding the elemental
keyword to the "methods"; alas again.

I receive error messages such as
Error: Generic function 'sum' at (1) is not consistent with a
specific intrinsic interface
when overloading the "sum" intrinsic; and
Error: 'array' argument of 'sum' intrinsic at (1) must be a
numeric type
Error: Function 'sum' at (1) has no implicit type
when trying the (+) operator.

Here is the current code, with commenting configured for the "sum"
approach:

------------------------------------------------------------------------------------

module vec3_class

implicit none ! Always. :)

private ! default all contents are private
public :: vec3 ! except the type "wrap" and the interface to the
method
public :: sum
!public :: plus, operator(+)
integer, parameter :: k = 8

type :: vec3
private ! Makes the contents of this type private;
! the name is public, cf above.
real(kind=k), dimension(3) :: es
end type vec3

interface sum ! Name for this method. You can add more
module procedure sum_ ! here as long as they can be disambiguated
end interface ! good old compile-time polymorphism.

!interface operator(+)
! module procedure plus
!end interface

contains

function sum_(this,dim) result(fval)
type(vec3),intent(in) :: this
integer,intent(in) :: dim
real(kind=k) :: fval

! Pass in the contents of the object to the intrinsic.
fval = sum(this%es,dim=dim)
end function sum_

function plus(a,b) result(r)
type(vec3), intent(in) :: a, b
type(vec3) :: r
r%es = a%es + b%es
end function plus

end module vec3_class

program test

use vec3_class ! Bring in the interface and type definition.
implicit none

integer, parameter :: n = 4
type(vec3), dimension(n,n) :: A
type(vec3), dimension(n) :: B
! type(vec3) :: X, Y, Z
! Z = plus(X,Y)
! Z = X + Y

jfh

unread,
Aug 13, 2009, 8:24:24 PM8/13/09
to gg95
The following not only compiled with g95 on my platform (Sparc
Solaris) but printed what I think were correct answers. A different
compiler printed wrong answers: I am still trying to find out whether
it's its fault or mine.

module vec3_class

implicit none ! Always. :)

private ! default all contents are private except those listed
public :: vec3
public :: sum
public :: k, plus, operator(+), assignment(=)
integer, parameter :: k = selected_real_kind(14) !! was 8: not
portable

type :: vec3
!! private ! if private, main program can't print vec3
real(kind=k), dimension(3) :: es
end type vec3

interface operator(+)
module procedure plus
end interface

interface assignment(=)
module procedure v3toa3
module procedure a3tov3
end interface

interface sum
module procedure sum_
end interface

contains

elemental function sum_(this,dim) result(fval) ! elemental lets
"this"
type(vec3),intent(in) :: this ! be an array
integer,intent(in) :: dim
real(kind=k) :: fval

! Pass in the contents of the object to the intrinsic.
fval = sum(this%es,dim)
end function sum_

pure subroutine v3toa3(toarray3,fromvec3)
real(k),intent(out) :: toarray3(3)
type(vec3),intent(in) :: fromvec3

toarray3 = fromvec3%es
end subroutine v3toa3

pure subroutine a3tov3(tovec3,fromarray3)
real(k),intent(in) :: fromarray3(3)
type(vec3),intent(out) :: tovec3

tovec3%es = fromarray3
end subroutine a3tov3

elemental function plus(a,b) result(r)
type(vec3), intent(in) :: a, b
type(vec3) :: r
r%es = a%es + b%es
end function plus

end module vec3_class

program test

use vec3_class ! Bring in the interface and type definition.
implicit none

integer, parameter :: n = 4
type(vec3), dimension(n,n) :: A
type(vec3), dimension(n) :: B
real(k) :: C(n,n), ninth = 1.0_k/9.0_k
integer i,j,l
forall(i=1:n,j=1:n) A(i,j) = (/ninth,ninth,-ninth/) ! uses a3tov3
print *,'A: '
print *, A
print *,'A+A: '
print *, A+A
! original B = sum(A,1) ! changed to the following:
C = sum(A,1)
print *,'C: '
print *, C
print *,'sum(C): '
print *, sum(C)
end program test

-- John Harper

PGK

unread,
Aug 15, 2009, 11:01:40 AM8/15/09
to gg95
Thanks. I'm still not getting what I'm after though. I'd like to
reduce a 2D array of type vec3, to a 1D array, also of vec3; if
possible using the sum intrinsic, but not using a do loop. Here is an
example using integers (a numeric type):

integer, dimension(2,2) :: a = reshape ((/1,1,2,2/), (/2,2/))
print *, sum(a,1)

which gives output:

2 4

I'd like to do the same with my vec3 type, instead of integers.
Reply all
Reply to author
Forward
0 new messages