gpt4 book ai didi

复数矩阵类型的 Fortran 运算符重载

转载 作者:行者123 更新时间:2023-12-02 18:44:20 25 4
gpt4 key购买 nike

如何为我的类重载运算符(+)和赋值(-)?

编译器向我显示以下消息

Error: Component to the right of a part reference with nonzero rank must not have the ALLOCATABLE 
attribute at (1).

对于分配(=),我不知道该怎么做。对于c++来说更容易。返回指针 this

function zmat_zmat_add(zmatrix1,zmatrix2) result(res_zmat_zmat)
type(zmatrix_type), dimension(:,:), intent(in) :: zmatrix1
type(zmatrix_type), dimension(:,:), intent(in) :: zmatrix2
type(zmatrix_type) :: res_zmat_zmat
integer :: rows
integer :: i,j ! liczniki pętli
rows=3

do i=1, rows
do j=1, rows
res_zmat_zmat%zmatrix_data(i,j)%realis= &
zmatrix1%zmatrix_data(i,j)%realis + zmatrix2%zmatrix_data(i,j)%realis
res_zmat_zmat%zmatrix_data(i,j)%imaginalis = &
zmatrix1%zmatrix_data(i,j)%imaginalis + &
zmatrix2%zmatrix_data(i,j)%imaginalis
enddo
enddo

end function zmat_zmat_add

剩余代码

module zmatrix_module
implicit none
type, public :: zcomplex_type

real :: realis
real :: imaginalis

end type zcomplex_type

type, extends(zcomplex_type), public :: zmatrix_type
type(zcomplex_type), dimension(:,:), allocatable, public :: zmatrix_data
end type zmatrix_type

public :: zmatrix_allocate
public :: zmatrix_free
public :: zmatrix_set
public :: zmatrix_print

interface operator(+)
procedure zzadd
procedure zmat_zmat_add
end interface

contains

function zzadd(z1,z2) result(res)
type(zcomplex_type), intent(in) :: z1
type(zcomplex_type), intent(in) :: z2
type(zcomplex_type) :: res
res%realis=z1%realis+z2%realis
res%imaginalis= z1%imaginalis +z2%imaginalis
end function zzadd


function zmat_zmat_add(zmatrix1,zmatrix2) result(res_zmat_zmat)
type(zmatrix_type), dimension(:,:), intent(in) :: zmatrix1
type(zmatrix_type), dimension(:,:), intent(in) :: zmatrix2
type(zmatrix_type) :: res_zmat_zmat
integer :: rows
integer :: i,j
rows=3

do i=1, rows
do j=1, rows
res_zmat_zmat%zmatrix_data(i,j)%realis= &
zmatrix1%zmatrix_data(i,j)%realis + zmatrix2%zmatrix_data(i,j)%realis
res_zmat_zmat%zmatrix_data(i,j)%imaginalis = &
zmatrix1%zmatrix_data(i,j)%imaginalis + &
zmatrix2%zmatrix_data(i,j)%imaginalis
enddo
enddo

end function zmat_zmat_add

subroutine zmatrix_allocate(zarray,rows)
type(zmatrix_type), intent(out) :: zarray
integer, intent(in) :: rows
allocate(zarray%zmatrix_data(1:rows, 1:rows))
end subroutine zmatrix_allocate

subroutine zmatrix_free(zarray)
type(zmatrix_type), intent(inout) :: zarray
deallocate(zarray%zmatrix_data)
end subroutine zmatrix_free



subroutine zmatrix_set(zarray, rows, re_values, im_values)
type(zmatrix_type), intent(inout) :: zarray
integer, intent(in) :: rows
real, intent(in) :: re_values, im_values
integer :: i,j
do i=1, rows
do j=1, rows
zarray%zmatrix_data(i,j)%realis = re_values
zarray%zmatrix_data(i,j)%imaginalis = im_values
enddo
enddo
end subroutine zmatrix_set

subroutine zmatrix_print(array,rows)
type(zmatrix_type), intent(in) :: array
integer, intent(in) :: rows
integer i,j

do i=1, rows
write(*,*) (array%zmatrix_data(i,j), j=1, rows)
enddo
write(*,*)
end subroutine zmatrix_print

end module zmatrix_module

Program main
use zmatrix_module
implicit none

type(zmatrix_type) :: mat1
type(zmatrix_type) :: mat2
type(zmatrix_type) :: mat3
type(zcomplex_type) :: z1
type(zcomplex_type) :: z2
type(zcomplex_type) :: z3
integer :: rows
rows=2
print *, " AAAAAAA"
call zmatrix_allocate(mat1,rows)

call zmatrix_set(mat1,rows,10.0,8.0)

call zmatrix_print(mat1,rows)

print *, "BBBBBBBB"
call zmatrix_allocate(mat2,rows)

call zmatrix_set(mat2,rows,1.0,2.0)

call zmatrix_print(mat2,rows)

print *, "CCCCCC"
call zmatrix_allocate(mat3,rows)

mat3=zmat_zmat_add(mat1,mat2)
mat3=mat1+mat2
call zmatrix_print(mat3,rows)

call zmatrix_free(mat1)
call zmatrix_free(mat2)
call zmatrix_free(mat3)
End Program main

最佳答案

注释指出了眼前的问题 - 您不需要 zmat_zmat_add 例程中的 dimension 属性 - 您正在将单个矩阵添加到另一个矩阵,而不是一个矩阵矩阵数组到另一个矩阵数组。因此,每个虚拟参数都有一个适当类型的标量。

但是,实际问题表明还有第二个问题,即如何为 zmat_zmat_add 分配结果数组。好吧,您使结果可分配并分配它!我在下面的第一个代码中展示了解决您所展示的问题的最直接方法。然而,您编写的代码读起来有点像将 C++ 编写为 Fortran。这不是解决这个问题的最佳方法,因此我提供了第二种解决方案,这是一种更适合 Fortran 的处理方式。这是第一个代码的下面。无论如何,这里是对您的代码的快速而肮脏的修复:

ijb@ijb-Latitude-5410:~/work/stack$ cat zm1.f90
module zmatrix_module
implicit none
type, public :: zcomplex_type

real :: realis
real :: imaginalis

end type zcomplex_type

type, extends(zcomplex_type), public :: zmatrix_type
type(zcomplex_type), dimension(:,:), allocatable, public :: zmatrix_data
end type zmatrix_type

public :: zmatrix_allocate
public :: zmatrix_free
public :: zmatrix_set
public :: zmatrix_print

interface operator(+)
procedure zzadd
procedure zmat_zmat_add
end interface

contains

function zzadd(z1,z2) result(res)
type(zcomplex_type), intent(in) :: z1
type(zcomplex_type), intent(in) :: z2
type(zcomplex_type) :: res
res%realis=z1%realis+z2%realis
res%imaginalis= z1%imaginalis +z2%imaginalis
end function zzadd


function zmat_zmat_add(zmatrix1,zmatrix2) result(res_zmat_zmat)
type(zmatrix_type), intent(in) :: zmatrix1
type(zmatrix_type), intent(in) :: zmatrix2
type(zmatrix_type) :: res_zmat_zmat
integer :: cols, rows
integer :: i,j

rows = Size( zmatrix1%zmatrix_data, Dim = 1 )
cols = Size( zmatrix1%zmatrix_data, Dim = 2 )

Allocate( res_zmat_zmat%zmatrix_data( 1:rows, 1:cols ) )

do i=1, rows
do j=1, cols
res_zmat_zmat%zmatrix_data(i,j)%realis= &
zmatrix1%zmatrix_data(i,j)%realis + zmatrix2%zmatrix_data(i,j)%realis
res_zmat_zmat%zmatrix_data(i,j)%imaginalis = &
zmatrix1%zmatrix_data(i,j)%imaginalis + &
zmatrix2%zmatrix_data(i,j)%imaginalis
enddo
enddo

end function zmat_zmat_add

subroutine zmatrix_allocate(zarray,rows)
type(zmatrix_type), intent(out) :: zarray
integer, intent(in) :: rows
allocate(zarray%zmatrix_data(1:rows, 1:rows))
end subroutine zmatrix_allocate

subroutine zmatrix_free(zarray)
type(zmatrix_type), intent(inout) :: zarray
deallocate(zarray%zmatrix_data)
end subroutine zmatrix_free



subroutine zmatrix_set(zarray, rows, re_values, im_values)
type(zmatrix_type), intent(inout) :: zarray
integer, intent(in) :: rows
real, intent(in) :: re_values, im_values
integer :: i,j
do i=1, rows
do j=1, rows
zarray%zmatrix_data(i,j)%realis = re_values
zarray%zmatrix_data(i,j)%imaginalis = im_values
enddo
enddo
end subroutine zmatrix_set

subroutine zmatrix_print(array,rows)
type(zmatrix_type), intent(in) :: array
integer, intent(in) :: rows
integer i,j

do i=1, rows
write(*,*) (array%zmatrix_data(i,j), j=1, rows)
enddo
write(*,*)
end subroutine zmatrix_print

end module zmatrix_module

Program main
use zmatrix_module
implicit none

type(zmatrix_type) :: mat1
type(zmatrix_type) :: mat2
type(zmatrix_type) :: mat3
integer :: rows
rows=2
print *, " AAAAAAA"
call zmatrix_allocate(mat1,rows)

call zmatrix_set(mat1,rows,10.0,8.0)

call zmatrix_print(mat1,rows)

print *, "BBBBBBBB"
call zmatrix_allocate(mat2,rows)

call zmatrix_set(mat2,rows,1.0,2.0)

call zmatrix_print(mat2,rows)

print *, "CCCCCC"
call zmatrix_allocate(mat3,rows)

mat3=zmat_zmat_add(mat1,mat2)
mat3=mat1+mat2
call zmatrix_print(mat3,rows)

call zmatrix_free(mat1)
call zmatrix_free(mat2)
call zmatrix_free(mat3)
End Program main

ijb@ijb-Latitude-5410:~/work/stack$ gfortran --version
GNU Fortran (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

ijb@ijb-Latitude-5410:~/work/stack$ gfortran -std=f2018 -Wall -Wextra -fcheck=all -O -Wuse-without-only zm1.f90 -o zm1
zm1.f90:99:4:

99 | use zmatrix_module
| 1
Warning: USE statement at (1) has no ONLY qualifier [-Wuse-without-only]
ijb@ijb-Latitude-5410:~/work/stack$ ./zm1
AAAAAAA
10.0000000 8.00000000 10.0000000 8.00000000
10.0000000 8.00000000 10.0000000 8.00000000

BBBBBBBB
1.00000000 2.00000000 1.00000000 2.00000000
1.00000000 2.00000000 1.00000000 2.00000000

CCCCCC
11.0000000 10.0000000 11.0000000 10.0000000
11.0000000 10.0000000 11.0000000 10.0000000

ijb@ijb-Latitude-5410:~/work/stack$

正如我所说,这不是解决这个问题的一种非常“Fortran”的方法。这就是我要做的。注意

  • 内在复杂数据类型
  • 简化代码的数组语法
  • 当可分配数组是计算结果时进行分配,再次简化代码
  • 使用内在函数来查找数组的属性,而不是携带包含重复信息的额外变量
  • 类型绑定(bind)过程
  • (不仅是 Fortran,还使用 ​​private 进行封装并最大程度地减少 namespace 污染)
  • 很可能是其他人

无论如何,这里是

Module zmatrix_module

Implicit None

Type, Public :: zmatrix_type
Private
Complex, Dimension(:,:), Allocatable, Private :: zmatrix_data
Contains
Procedure, Public :: allocate => zmatrix_allocate
Procedure, Public :: free => zmatrix_free
Procedure, Public :: set => zmatrix_set
Procedure, Public :: print => zmatrix_print
Generic , Public :: Operator( + ) => add
Procedure, Private :: add => zmat_zmat_add
End Type zmatrix_type

Private

Contains

Function zmat_zmat_add(zmatrix1,zmatrix2) Result(res_zmat_zmat)

Class(zmatrix_type), Intent(in) :: zmatrix1
Type (zmatrix_type), Intent(in) :: zmatrix2

Type (zmatrix_type) :: res_zmat_zmat

! Uses allocation on assignment
! Also use array syntax to simplify code
res_zmat_zmat%zmatrix_data = zmatrix1%zmatrix_data + zmatrix2%zmatrix_data

End Function zmat_zmat_add

Subroutine zmatrix_allocate(zarray,rows)
! Note Intent(out) ensures the array is deallocate on entry to the routine
Class(zmatrix_type), Intent(out) :: zarray
Integer, Intent(in) :: rows
Allocate(zarray%zmatrix_data(1:rows, 1:rows))
End Subroutine zmatrix_allocate

Subroutine zmatrix_free(zarray)
Class(zmatrix_type), Intent(inout) :: zarray
Deallocate(zarray%zmatrix_data)
End Subroutine zmatrix_free

Subroutine zmatrix_set(zarray, values )
Class(zmatrix_type), Intent(inout) :: zarray
Complex, Intent(in) :: values
zarray%zmatrix_data = values
End Subroutine zmatrix_set

Subroutine zmatrix_print(array)
Class(zmatrix_type), Intent(in) :: array

Integer :: i

! Don't need to carry around extra data, just ask the array its size
Do i=1, Size( array%zmatrix_data, Dim = 1 )
Write(*,*) array%zmatrix_data(i,:)
Enddo
Write(*,*)
End Subroutine zmatrix_print

End Module zmatrix_module

Program main

Use zmatrix_module, Only : zmatrix_type

Implicit None

Type( zmatrix_type ) :: mat1
Type( zmatrix_type ) :: mat2
Type( zmatrix_type ) :: mat3

Integer :: rows

rows=2

Print *, " AAAAAAA"
Call mat1%allocate( rows )

Call mat1%set( ( 10.0, 8.0 ) )

Call mat1%print()

Print *, "BBBBBBBB"
Call mat2%allocate( rows )

Call mat2%set( ( 1.0, 2.0 ) )

Call mat2%print()

Print *, "CCCCCC"
! Note mat3 gets auto-allocated as a result of the operation
mat3 = mat1 + mat2
Call mat3%print()

Call mat3%free()
Call mat2%free()
Call mat1%free()

End Program main

ijb@ijb-Latitude-5410:~/work/stack$ gfortran --version
GNU Fortran (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

ijb@ijb-Latitude-5410:~/work/stack$ gfortran -std=f2018 -Wall -Wextra -fcheck=all -O -Wuse-without-only zm2.f90 -o zm2
ijb@ijb-Latitude-5410:~/work/stack$ ./zm2
AAAAAAA
(10.0000000,8.00000000) (10.0000000,8.00000000)
(10.0000000,8.00000000) (10.0000000,8.00000000)

BBBBBBBB
(1.00000000,2.00000000) (1.00000000,2.00000000)
(1.00000000,2.00000000) (1.00000000,2.00000000)

CCCCCC
(11.0000000,10.0000000) (11.0000000,10.0000000)
(11.0000000,10.0000000) (11.0000000,10.0000000)

ijb@ijb-Latitude-5410:~/work/stack$

还有另一种方法可以很好地适应这种情况,即参数化派生类型。但我在这里没有经验,所以我不会讨论我不知道的事情。

关于复数矩阵类型的 Fortran 运算符重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67654935/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com