【问题标题】:Fortran polymorphic array assignment for `PACK`: issues`PACK` 的 Fortran 多态数组赋值:问题
【发布时间】:2020-10-12 09:51:05
【问题描述】:

我正在尝试在多态数组上编写计算效率高的 PACK 操作,我正在处理 gfortran 9.2.0 的问题:

  • PACK 操作必须对派生类型数量的多态数组起作用,并自行返回结果
  • 由于我不在这里解释的原因,这个数组应该被重新分配
  • 通常,返回索引的位置与原始数组的位置之间存在重叠:类似于array(1:5) = array([2,4,6,8,10])

我遇到了问题,因为我尝试使用 gfortran 的唯一分配版本是带有循环的 - 所有基于数组的版本都会产生编译器或运行时段错误。

本程序报告了一个例子:

module m
   implicit none
   
   type, public :: t
      integer :: i = 0
      contains
      
      procedure, private, pass(this) :: t_assign => t_to_t
      generic :: assignment(=) => t_assign
   end type t
   
   type, public, extends(t) :: tt
      integer :: j = 0
      contains
      procedure, private, pass(this) :: t_assign => t_to_tt
   end type tt
   
   contains
   
   elemental subroutine t_to_t(this,that)
      class(t), intent(inout) :: this
      class(t), intent(in   ) :: that
      this%i = that%i
   end subroutine t_to_t
   
   elemental subroutine t_to_tt(this,that)
      class(tt), intent(inout) :: this
      class(t ), intent(in   ) :: that

      this%i = that%i
      select type (thatPtr=>that)
         type is (t)
            this%j = 0
         type is (tt)
            this%j = thatPtr%j
         class default
            ! Cannot stop here
            this%i = -1
            this%j = -1
      end select        
   end subroutine t_to_tt
      
end module m

program test_poly_pack
   use m
   implicit none
   
   integer, parameter :: n = 100
   integer :: i,j
   class(t), allocatable :: poly(:),otherPoly(:)
         
   allocate(t :: poly(n))
   allocate(t :: otherPoly(10))
   
   ! Assign dummy values
   forall(i=1:n) poly(i)%i = i
   
   ! Array assignment with indices => ICE segfault:
   ! internal compiler error: Segmentation fault
   otherPoly(1:10) = poly([10,20,30,40,50,60,70,80,90,100])
   
   ! Scalar assignment with loop -> OK
   do i=1,10
     otherPoly(i) = poly(10*i)
   end do
   
   ! Array assignment with PACK => Compiles OK, Segfault on runtime. GDB returns: 
   ! Thread 1 received signal SIGSEGV, Segmentation fault.
   ! 0x000000000040163d in m::t_to_t (this=..., that=...) at test_poly_pack.f90:31
   ! 31                this%i = that%i


   otherPoly(1:10) = pack(poly,mod([(j,j=1,100)],10)==0)

   do i=1,10
     print *, ' polymorphic(',i,')%i = ',otherPoly(i)%i
   end do   
   
end program test_poly_pack   

我做错了什么,和/或这只是一个编译器错误还是我应该遵循任何最佳实践?

【问题讨论】:

  • 你真的应该显示你的错误信息。并更新你的编译器。您是否收到一条消息说内在赋值不能是多态的?请注意,allocate(otherPoly(1:10),source = pack(poly,mod([(j,j=1,100)],10)==0)) 有效。
  • 如果您在编译器中遇到段错误,则它是编译器中的错误。你必须向 GCC 报告,我们真的帮不了你。错误消息显示请提交完整的错误报告。您的确切问题是什么?
  • 谢谢,我添加了与错误相关的输出
  • 问题是最佳实践是什么:由于数组版本似乎存在问题,什么是不需要临时分配的计算高效实现?
  • 好吧,我看不出答案是什么,显然这取决于编译器中的错误,我看不出你会做错什么。您只是在寻找解决方法吗?重新分配可能是目前最好的。直到您报告的错误得到修复。或者使用没有这些错误的编译器。

标签: arrays fortran polymorphism


【解决方案1】:

崩溃是编译器错误。当编译器说internal compiler error ... Please submit a full bug report时,你真的可以信任它,你应该采取相应的行动(并提交错误报告)。运行时崩溃也是编译器错误(错误代码)。

如果你知道赋值时的实际类型,你可以使用类型保护

   select type (p => poly)
     type is (t)
       select type(op => otherpoly)
         type is (t)
           op(1:10) = pack(p,mod([(j,j=1,100)],10)==0)
       end select
   end select

如果你需要它是多态的 - 你可能需要重新分配

allocate(otherPoly(1:10),source = pack(poly,mod([(j,j=1,100)],10)==0))

直到您希望报告的错误得到修复。

【讨论】:

  • 谢谢,您的两种解决方法都适用于 gfortran。正如您所说,它们都不太符合面向对象编程的精神——这(当它起作用时)极大地简化了语法。发布这个问题时,我认为即使对于 Fortran 来说也是非常基本的 OO 东西,我一定做错了什么。
  • @FedericoPerini 我不知道如何更清楚地重复它。这是一个编译器错误。你没有做错任何事。您应该向 GCC 报告该错误。就是这样。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-04
  • 1970-01-01
  • 2011-06-21
  • 1970-01-01
  • 2023-01-27
  • 1970-01-01
相关资源
最近更新 更多