我试图在R studio中调用用Fortran编写的模块,但是后者意外崩溃。

我尝试了其他Fortran示例(pi的阶乘和MC估计),这些示例运行良好。

我看到的无法使用的代码与这些示例之间的唯一区别是,我为纯函数使用了子例程包装器(调用其他纯函数),而这些示例仅依赖于子例程,而事实上我的函数具有 vector 输入。

这是我遵循的过程(或键入的代码):

  • R CMD SHLIB mypath/myfile.f90 #this compiles without problem; code supplied below.
  • dyn.load('ptoh') #This is just the given name of the wrapper subroutine
  • .Fortran('ptoh', dimen=as.integer(dimen), p=as.matrix(p), m=as.integer(m), h=integer(1) )

  • 我在R中任意设置的位置:dimen<-3; p<-c(4,6,7); m=3;
    您是否知道为什么会崩溃?构建包装器的方法正确吗?与bind(C, name="ptoh_")相关联的问题吗?

    我已经非常感谢您的帮助。

    吉尔斯

    我正在使用最新版本的R在运行HighSierra的Mac上工作。
    “myfile.90”中的代码如下:
    module hilbert
      implicit none
    
    contains
      pure function rotate_right(x, d, dimen)
        integer, intent(in) :: x, d, dimen
        integer :: rotate_right, tmp, mask
    
        mask = 2 ** dimen - 1
        rotate_right = shiftr(x, d)
        tmp = shiftl(x, dimen - d)
        rotate_right = iand(ior(rotate_right, tmp), mask)
      end
    
      pure function rotate_left(x, d, dimen)
        integer, intent(in) :: x, d, dimen
        integer :: rotate_left, tmp, mask
    
        mask = 2 ** dimen - 1
        rotate_left = shiftl(x, d)
        tmp = shiftr(x, dimen - d)
        rotate_left = iand(ior(rotate_left, tmp), mask)
      end
    
      pure function gc(i)
        integer, intent(in) :: i
        integer :: gc
    
        gc = ieor(i, shiftr(i, 1))
      end
    
      pure function entry_point(i)
        integer, intent(in) :: i
        integer :: entry_point
    
        if(i == 0) then
           entry_point = 0
        else
           entry_point = gc(2 * ((i - 1) / 2))
        end if
      end
    
      pure function exit_point(i, dimen)
        integer, intent(in) :: i, dimen
        integer :: exit_point, mask
    
        mask = 2 ** dimen - 1
        exit_point = ieor(entry_point(mask - i), 2 ** (dimen - 1))
      end
    
      pure function inverse_gc(g, dimen)
        integer, intent(in) :: g, dimen
        integer :: inverse_gc, j
    
        inverse_gc = g
        j = 1
        do while(j < dimen)
           inverse_gc = ieor(inverse_gc, shiftr(g, j))
           j = j + 1
        end do
      end
    
      pure function intercube_g(i) result(g)
        integer, intent(in) :: i
        integer :: g
    
        g = trailz(ieor(gc(i), gc(i + 1)))
      end
    
      pure function intracube_d(i, dimen) result(d)
        integer, intent(in) :: i, dimen
        integer :: d
    
        if(i == 0) then
           d = 0
        else if(modulo(i, 2) == 0) then
           d = modulo(intercube_g(i - 1), dimen)
        else
           d = modulo(intercube_g(i), dimen)
        end if
      end
    
      pure function transform(e, d, b, dimen) result(t)
        integer, intent(in) :: e, d, b, dimen
        integer :: t
    
        t = rotate_right(ieor(b, e), d + 1, dimen)
      end
    
      pure function inverse_transform(e, d, b, dimen) result(t)
        integer, intent(in) :: e, d, b, dimen
        integer :: t
    
        t = transform(rotate_right(e, d + 1, dimen), dimen - d - 2, b, dimen)
      end
    
      pure function ptoh(dimen, p, m) result(h)
        integer, intent(in) :: dimen, p(dimen), m
        integer :: h, e, d, i, j, l, w
    
        h = 0
        e = 0
        d = 2
        do i = m - 1, 0, -1
           l = 0
           do j = 1, dimen
              l = l + 2 ** (j - 1) * ibits(p(j), i, 1)
           end do
           l = transform(e, d, l, dimen)
           w = inverse_gc(l, dimen)
           e = ieor(e, rotate_left(entry_point(w), d + 1, dimen))
           d = modulo(d + intracube_d(w, dimen) + 1, dimen)
           h = ior(shiftl(h, dimen), w)
        end do
      end
    
      subroutine ptoh_R_wrapper(dimen, p, m, h) bind(C, name="ptoh_")
        integer :: dimen, p(dimen), m, h, ptoh
        external ptoh
    
        h = ptoh(dimen, p, m)
      end
    end
    

    最佳答案

    您在模块中使用名称subroutine公开了包装器"ptoh_",但是在R Studio中使用'ptoh'对其进行了调用。实际上,'ptoh'是包装(但也公开)的function的名称。

    因此,一旦函数不希望使用此参数,则错误可能来自传递参数h=integer(1)

    如果这是原因,要解决此问题,可以在R Studio中将调用更改为:

    .Fortran('ptoh_', dimen=as.integer(dimen), p=as.matrix(p), m=as.integer(m), h=integer(1))
    

    编辑:

    可能导致该错误的另一件事是您正在覆盖包装子例程中的名称ptoh
    subroutine ptoh_R_wrapper(dimen, p, m, h) bind(C, name="ptoh_")
      integer :: dimen, p(dimen), m, h, ptoh
      external ptoh
    
      h = ptoh(dimen, p, m)
    end
    

    函数ptoh在所有模块内部都已经可以使用,包括包装子程序内部(也应删除external ptoh语句)。

    将声明更改为此:
    subroutine ptoh_R_wrapper(dimen, p, m, h) bind(C, name="ptoh_")
      integer :: dimen, p(dimen), m, h
    
      h = ptoh(dimen, p, m)
    end
    

    并检查错误是否仍然存在。

    最后一点,当您要使子例程与C互操作时,请考虑在互操作参数中使用内部模块iso_c_binding中的kind参数(如果适用,还可以使用value属性)。

    我对R的了解不足以确保它是必需的,但这并没有伤害。最终代码如下所示:
    subroutine ptoh_R_wrapper(dimen, p, m, h) bind(C, name="ptoh_")
      use, intrinsic :: iso_c_binding, only: c_int
      integer(c_int) :: dimen, p(dimen), m, h
    
      h = ptoh(dimen, p, m)
    end
    

    关于r - 调用Fortran模块时R Studio崩溃,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51100869/

    10-11 18:02