Получаете два значения от fortran для Python?

Можно ли получить от Фортрана два значения? например, я хочу получить максимальный балл и эту координату из матрицы

# 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?


person Minxo    schedule 21.11.2020    source источник
comment
Другим легче помочь с вашей конкретной проблемой, если вы опишете / дадите точное сообщение об ошибке, вместо того, чтобы сказать это не работает, см. как спросить. Как указано в ответе на ваш предыдущий вопрос, вы должны добавить import findthemax, чтобы импортировать созданный модуль f2py. После импорта модуля f2py вам может быть очень полезно внимательно просмотреть вывод, например, print(findthemax.__doc__) и print(findthemax.findthemax.__doc__), таким образом можно решить многие недоразумения, связанные с f2py.   -  person jbdv    schedule 23.11.2020


Ответы (3)


Вы можете использовать подпрограмму 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
person jack    schedule 22.11.2020

Ваша реализация максимального значения и его индекса медленная, потому что она использует стандарт для циклов 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]
person jack    schedule 21.11.2020
comment
Хотя это может быть правильно, это не отвечает на вопрос - person Ian Bush; 21.11.2020
comment
Я предположил, что OP просто не знал об этом и, следовательно, не мог даже попросить об этом. @Minxo тебе подходит ответ? - person jack; 21.11.2020
comment
Это ускорило бы мои вычисления, но все же я слышал, что использование фортрана намного быстрее, и я действительно хочу использовать fortran для своих вычислений. Спасибо, в любом случае - person Minxo; 22.11.2020
comment
Стоит знать, как это сделать ... так что, надеюсь, вы сможете исправить мою ошибку в ответе, поскольку у меня нет python, установленного прямо на моем новом NUC. - person Holmz; 22.11.2020
comment
@Minxo Я создал еще один ответ, который вызывает подпрограмму fortran из python. Вы можете попробовать оба метода, и я думаю, это зависит от сценария, какой из них быстрее. В большинстве случаев я бы использовал внутренние процедуры numpy ... - person jack; 22.11.2020

Со стороны фортрана у вас есть

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
person Holmz    schedule 22.11.2020
comment
Итак, как получить два значения в Python? - person Vladimir F; 22.11.2020