【问题标题】:Getting two values from fortran for Python?从 Python 的 fortran 获取两个值?
【发布时间】:2021-03-04 15:18:22
【问题描述】:

是否可以从 fortran 中获取两个值? 例如,我想从一个矩阵中得到最高分和这个坐标

# python code 
import numpy as np

matrix = np.array([[1, 10, 3, 4, 9],
                  [2, 1, 0, 9, 13], 
                  [3, 5, 10, 18, 3]])

max_score= 0
column_coord = 0
row_coord = 0

for i in range(len(matrix[:,0])):
    for j in range(len(matrix[0,:])):
        if matrix[i, j] >= max_score:
            # getting max_score, column, row coordinate
            max_score= matrix[i, j]
            column_coord = i
            row_coord = j
print(max_score, column_coord, row_coord)

这段代码可以正常工作,但是如果矩阵变大,会花费很多时间 找到我想要的值。
所以,我决定使用 f2py 来进行更快的计算,这就是 fortran 代码。 cc 是列长,rr 是行长。

subroutine findthemax(cc, rr, matrix, max_score, col_coord, row_coord)
integer, intent(in) :: cc, rr 
integer, intent(in) :: matrix(0:cc, 0:rr)
integer, intent(out) :: max_score, col_coord, row_coord

max_score = 0
col_coord = 0
row_coord = 0

do i = 1, cc
    do j = 1, rr
        if (matrix(i, j).GE.max_score) then
            max_score = matrix(i, j)
            col_coord = i
            row_coord = j
        end if        
    end do
end do
return
end subroutine

我想得到max_score、col_coord、row_coord,所以我导入了findthemax模块
(名为 findthemax.f90)是我用 f2py 改造的。

import numpy as np

matrix = np.array([[1, 10, 3, 4, 9],
                  [2, 1, 0, 9, 13], 
                  [3, 5, 10, 18, 3]])

cc = len(matrix[:,0])
rr = len(matrix[0,:])

max_score, column_coord, row_coord = findthemax.findthemax(cc, rr, matrix)

我不知道为什么这不起作用,那是因为我实际上并不知道
如何使用 fortran 和 f2py 返回两个以上的值。有人可以告诉我如何
从 fortran 中获取多个值?

【问题讨论】:

  • 如果您描述/给出确切的错误信息,而不是说这不起作用,其他人更容易帮助您解决特定问题,请参阅how to ask。正如您先前问题的answer 所示,您必须添加import findthemax 才能导入创建的f2py 模块。导入 f2py 模块后,您可能会发现仔细查看例如的输出非常有用。 print(findthemax.__doc__)print(findthemax.findthemax.__doc__),很多f2py的误解可以这样解决。

标签: python fortran f2py


【解决方案1】:

在 fortran 方面你有

subroutine findthemax(cc, rr, matrix, max_score, col_coord, row_coord)
integer, intent(in) :: cc, rr 
integer, intent(in) :: matrix(0:cc, 0:rr)
integer, intent(out) :: max_score, col_coord, row_coord

max_score = 0
col_coord = 0
row_coord = 0

do i = 1, cc    !Does this need a 0, cc ??
    do j = 1, rr   !Does this need a 0, rr ??
        if (matrix(i, j).GE.max_score) then
            max_score = matrix(i, j)
            col_coord = i
            row_coord = j
        end if        
    end do
end do
return
end subroutine

你可能想要这样的东西:

subroutine findthemax(cc, rr, matrix, max_score, col_coord, row_coord)
integer, intent(in) :: cc, rr 
integer, intent(in) :: matrix(cc+1, rr+1)  ! not zero ??
integer, intent(out) :: max_score, col_coord, row_coord

max_score = 0
col_coord = 0
row_coord = 0

Outter_Loop: do j = 1, UBOUND(MATRIX, DIM=2)
  Inner_Loop: do i = 1, UBOUND(MATRIX, DIM=1)
        if (matrix(i, j) >= max_score) then
            max_score = matrix(i, j)
            col_coord = i
            row_coord = j
        end if        
    end do Inner_Loop
end do Outter_Loop
return

end subroutine

在 fortran 中使用内部函数会更优雅:

subroutine findthemax(cc, rr, matrix, threeple)
IMPLICIT NONE
integer, intent(in)  :: cc, rr 
integer, intent(in)  :: matrix(cc+1,rr+1)  ! not 0:rr, or its it 1:rr+1 ???
integer, intent(OUT)  :: Threeple(3)
integer, DIMENSION(2) :: At_Min

! YOU MAY NEED TRANSPOSE - but just intentionally reverse rows and columns if python is row major??

Threeple(1) = MAXVAL(matrix)

At_Min = MAXLOC(Matrix)
Threeple(2) = At_Min(2) ! Or is it (1)??
Threeple(3) = At_Min(1) ! Or is it (2)??

return
end subroutine findthemax

【讨论】:

  • 那么,如何获取两个值给 Python 呢?
【解决方案2】:

您可以通过以下方式使用具有多个返回值的fortran子例程。

Fortran 代码findthemax.f90

subroutine findthemax(matrix, max_score, row, col)
  integer, intent(in)  :: matrix(:,:)
  integer, intent(out) :: max_score, row, col

  integer :: ind(2)

  ind       = maxloc(matrix)
  row       = ind(1)
  col       = ind(2)
  max_score = matrix(row,col)
end subroutine

通过 f2py 编译

$ f2py -c findthemax.f90 -m findthemax

将其导入您的 python 代码

import findthemax
import numpy as np

matrix = np.array([[1, 10,  3,  4,  9],
                   [2,  1,  0,  9, 13],
                   [3,  5, 10, 18,  3]])

(max_score, row, col) = findthemax.findthemax(matrix)

print(max_score)        # 18
print(row)              #  3
print(col)              #  4

【讨论】:

    【解决方案3】:

    您对最大值及其索引的实现是,因为它使用python 的循环标准。 Numpy 拥有大量快速/优化的内置函数,大多数甚至在底层使用 fortran 代码。

    对于您的问题,您应该查看numpy.argmax

    示例代码

    import numpy as np
    
    matrix = np.array([[1, 10, 3, 4, 9],
                      [2, 1, 0, 9, 13], 
                      [3, 5, 10, 18, 3]])
    
    # get flat index of maximum
    flat = np.argmax(matrix)
    
    # flat index to row/col indices
    (row, col) = np.unravel_index(flat, matrix.shape)
    
    # max value
    mymax = matrix[row,col]
    

    【讨论】:

    • 虽然这可能是正确的,但它并不能回答问题
    • 我猜 OP 只是不知道它,因此,甚至不能要求它。 @Minxo 这个答案适合你吗?
    • 这会加快我的计算速度,但我仍然听说使用 fortran 快得多,我真的想使用 fortran 进行计算。还是谢谢
    • 值得知道如何去做......所以希望你能纠正我的答案,因为我没有在我的新 NUC 上设置 python。
    • @Minxo 我创建了另一个答案,它从 python 调用一个 fortran 例程。您可以尝试这两种方法,我想这取决于哪种方法更快。在大多数情况下,我会使用 numpy 的内部例程...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-12
    • 2020-11-22
    • 2020-09-09
    • 2023-03-20
    • 1970-01-01
    相关资源
    最近更新 更多