传递布尔数组而不用 `f2py` 复制?
Pass boolean array without copying with `f2py`?
如果我打算用 f2py
向 Fortran 变量传递一个布尔值 NumPy 数组,应该如何键入它们? integer*1
和logical*1
我都试过了,但是这两个都表明数组被复制了。
例如,如果我编译文件,foo.f95
,包含:
subroutine foo(x, n)
logical*1 x(n)
!f2py intent(in) x
!f2py intent(hide), depend(x) :: n=shape(x,0)
...
end subroutine
与 f2py -c -m foo foo.f90 -DF2PY_REPORT_ON_ARRAY_COPY=1
和 运行 类似:
import numpy as np
import foo
x = np.random.randn(100) < 0
foo.foo(x)
它打印
copied an array: size=100, elsize=1
如果将 logical*1
更改为 integer*1
,我会得到相同的结果。 Fortran 文件中布尔数组的正确类型是什么,这样数组就不会被复制?
请注意,这不是内存连续性问题,因为数组是一维的——foo.foo(np.asfortranarray(x))
打印相同的复制消息。
从一些实验(*)来看,似乎 Python/f2py 将 np.int8
视为与 logical*1
兼容,而 np.bool
或 np.bool8
对某些人不兼容原因。将 print *, "(fort) x = ", x
插入 foo.f90 后,我们得到:
>>> foo.foo( np.array( [ True, False, False ], dtype=np.bool ) )
copied an array: size=3, elsize=1
(fort) x = T F F
>>> foo.foo( np.array( [ False, True, False ], dtype=np.bool8 ) )
copied an array: size=3, elsize=1
(fort) x = F T F
>>> foo.foo( np.array( [ False, False, True ], dtype=np.int8 ) ) # no copy
(fort) x = F F T
因为 True
和 False
只是简单地映射到 1 和 0,所以在 Python 端使用 int8
数组可能会很方便。
(*) 一些实验
这里,我把f2py intent注释改成了inout
,看看我们是否可以从Fortran端修改数组。
foo.f90:
subroutine foo(x, n)
use iso_c_binding
implicit none
integer n
logical*1 x( n )
! logical x( n )
! logical(c_bool) x( n )
!f2py intent(inout) x
!f2py intent(hide), depend(x) :: n=shape(x,0)
print *, "(fort) x = ", x
print *, "(fort) sizeof(x(1)) = ", sizeof(x(1))
print *, "(fort) resetting x(:) to true"
x(:) = .true.
end subroutine
test.py:
import numpy as np
import foo
for T in [ np.bool, np.bool8,
np.int, np.int8, np.int32, np.int64,
np.uint, np.uint8, np.uint32, np.uint64,
np.dtype('b'), np.dtype('int8'), np.dtype('int32') ]:
print( "-------------------------" )
print( "dtype =", T )
x = np.array( [ True, False, True ], dtype=T )
print( "input x =", x )
try:
foo.foo( x )
print( "output x =", x )
except:
print( "failed" )
logical*1
的结果:
-------------------------
dtype = <class 'bool'>
input x = [ True False True]
failed
-------------------------
dtype = <class 'numpy.bool_'>
input x = [ True False True]
failed
-------------------------
dtype = <class 'int'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.int8'>
input x = [1 0 1]
(fort) x = T F T
(fort) sizeof(x(1)) = 1
(fort) resetting x(:) to true
output x = [1 1 1]
-------------------------
dtype = <class 'numpy.int32'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.int64'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.uint64'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.uint8'>
input x = [1 0 1]
(fort) x = T F T
(fort) sizeof(x(1)) = 1
(fort) resetting x(:) to true
output x = [1 1 1]
-------------------------
dtype = <class 'numpy.uint32'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.uint64'>
input x = [1 0 1]
failed
-------------------------
dtype = int8
input x = [1 0 1]
(fort) x = T F T
(fort) sizeof(x(1)) = 1
(fort) resetting x(:) to true
output x = [1 1 1]
-------------------------
dtype = int8
input x = [1 0 1]
(fort) x = T F T
(fort) sizeof(x(1)) = 1
(fort) resetting x(:) to true
output x = [1 1 1]
-------------------------
dtype = int32
input x = [1 0 1]
failed
logical
的结果(默认种类):
-------------------------
dtype = <class 'bool'>
input x = [ True False True]
failed
-------------------------
dtype = <class 'numpy.bool_'>
input x = [ True False True]
failed
-------------------------
dtype = <class 'int'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.int8'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.int32'>
input x = [1 0 1]
(fort) x = T F T
(fort) sizeof(x(1)) = 4
(fort) resetting x(:) to true
output x = [1 1 1]
-------------------------
dtype = <class 'numpy.int64'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.uint64'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.uint8'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.uint32'>
input x = [1 0 1]
(fort) x = T F T
(fort) sizeof(x(1)) = 4
(fort) resetting x(:) to true
output x = [1 1 1]
-------------------------
dtype = <class 'numpy.uint64'>
input x = [1 0 1]
failed
-------------------------
dtype = int8
input x = [1 0 1]
failed
-------------------------
dtype = int8
input x = [1 0 1]
failed
-------------------------
dtype = int32
input x = [1 0 1]
(fort) x = T F T
(fort) sizeof(x(1)) = 4
(fort) resetting x(:) to true
output x = [1 1 1]
结果 logical(c_bool)
(通过 iso_c_binding):
-------------------------
dtype = <class 'bool'>
input x = [ True False True]
failed
-------------------------
dtype = <class 'numpy.bool_'>
input x = [ True False True]
failed
-------------------------
dtype = <class 'int'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.int8'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.int32'>
input x = [1 0 1]
(fort) x = T F F
(fort) sizeof(x(1)) = 1
(fort) resetting x(:) to true
output x = [65793 0 1]
-------------------------
dtype = <class 'numpy.int64'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.uint64'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.uint8'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.uint32'>
input x = [1 0 1]
(fort) x = T F F
(fort) sizeof(x(1)) = 1
(fort) resetting x(:) to true
output x = [65793 0 1]
-------------------------
dtype = <class 'numpy.uint64'>
input x = [1 0 1]
failed
-------------------------
dtype = int8
input x = [1 0 1]
failed
-------------------------
dtype = int8
input x = [1 0 1]
failed
-------------------------
dtype = int32
input x = [1 0 1]
(fort) x = T F F
(fort) sizeof(x(1)) = 1
(fort) resetting x(:) to true
output x = [65793 0 1]
出于某种原因,最后一个 logical(c_bool)
不适用于上述用法...(f2py 似乎将 logical(c_bool)
视为 4 个字节,而 gfortran 将其视为 1 个字节,所以不一致...)
如果我打算用 f2py
向 Fortran 变量传递一个布尔值 NumPy 数组,应该如何键入它们? integer*1
和logical*1
我都试过了,但是这两个都表明数组被复制了。
例如,如果我编译文件,foo.f95
,包含:
subroutine foo(x, n)
logical*1 x(n)
!f2py intent(in) x
!f2py intent(hide), depend(x) :: n=shape(x,0)
...
end subroutine
与 f2py -c -m foo foo.f90 -DF2PY_REPORT_ON_ARRAY_COPY=1
和 运行 类似:
import numpy as np
import foo
x = np.random.randn(100) < 0
foo.foo(x)
它打印
copied an array: size=100, elsize=1
如果将 logical*1
更改为 integer*1
,我会得到相同的结果。 Fortran 文件中布尔数组的正确类型是什么,这样数组就不会被复制?
请注意,这不是内存连续性问题,因为数组是一维的——foo.foo(np.asfortranarray(x))
打印相同的复制消息。
从一些实验(*)来看,似乎 Python/f2py 将 np.int8
视为与 logical*1
兼容,而 np.bool
或 np.bool8
对某些人不兼容原因。将 print *, "(fort) x = ", x
插入 foo.f90 后,我们得到:
>>> foo.foo( np.array( [ True, False, False ], dtype=np.bool ) )
copied an array: size=3, elsize=1
(fort) x = T F F
>>> foo.foo( np.array( [ False, True, False ], dtype=np.bool8 ) )
copied an array: size=3, elsize=1
(fort) x = F T F
>>> foo.foo( np.array( [ False, False, True ], dtype=np.int8 ) ) # no copy
(fort) x = F F T
因为 True
和 False
只是简单地映射到 1 和 0,所以在 Python 端使用 int8
数组可能会很方便。
(*) 一些实验
这里,我把f2py intent注释改成了inout
,看看我们是否可以从Fortran端修改数组。
foo.f90:
subroutine foo(x, n)
use iso_c_binding
implicit none
integer n
logical*1 x( n )
! logical x( n )
! logical(c_bool) x( n )
!f2py intent(inout) x
!f2py intent(hide), depend(x) :: n=shape(x,0)
print *, "(fort) x = ", x
print *, "(fort) sizeof(x(1)) = ", sizeof(x(1))
print *, "(fort) resetting x(:) to true"
x(:) = .true.
end subroutine
test.py:
import numpy as np
import foo
for T in [ np.bool, np.bool8,
np.int, np.int8, np.int32, np.int64,
np.uint, np.uint8, np.uint32, np.uint64,
np.dtype('b'), np.dtype('int8'), np.dtype('int32') ]:
print( "-------------------------" )
print( "dtype =", T )
x = np.array( [ True, False, True ], dtype=T )
print( "input x =", x )
try:
foo.foo( x )
print( "output x =", x )
except:
print( "failed" )
logical*1
的结果:
-------------------------
dtype = <class 'bool'>
input x = [ True False True]
failed
-------------------------
dtype = <class 'numpy.bool_'>
input x = [ True False True]
failed
-------------------------
dtype = <class 'int'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.int8'>
input x = [1 0 1]
(fort) x = T F T
(fort) sizeof(x(1)) = 1
(fort) resetting x(:) to true
output x = [1 1 1]
-------------------------
dtype = <class 'numpy.int32'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.int64'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.uint64'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.uint8'>
input x = [1 0 1]
(fort) x = T F T
(fort) sizeof(x(1)) = 1
(fort) resetting x(:) to true
output x = [1 1 1]
-------------------------
dtype = <class 'numpy.uint32'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.uint64'>
input x = [1 0 1]
failed
-------------------------
dtype = int8
input x = [1 0 1]
(fort) x = T F T
(fort) sizeof(x(1)) = 1
(fort) resetting x(:) to true
output x = [1 1 1]
-------------------------
dtype = int8
input x = [1 0 1]
(fort) x = T F T
(fort) sizeof(x(1)) = 1
(fort) resetting x(:) to true
output x = [1 1 1]
-------------------------
dtype = int32
input x = [1 0 1]
failed
logical
的结果(默认种类):
-------------------------
dtype = <class 'bool'>
input x = [ True False True]
failed
-------------------------
dtype = <class 'numpy.bool_'>
input x = [ True False True]
failed
-------------------------
dtype = <class 'int'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.int8'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.int32'>
input x = [1 0 1]
(fort) x = T F T
(fort) sizeof(x(1)) = 4
(fort) resetting x(:) to true
output x = [1 1 1]
-------------------------
dtype = <class 'numpy.int64'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.uint64'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.uint8'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.uint32'>
input x = [1 0 1]
(fort) x = T F T
(fort) sizeof(x(1)) = 4
(fort) resetting x(:) to true
output x = [1 1 1]
-------------------------
dtype = <class 'numpy.uint64'>
input x = [1 0 1]
failed
-------------------------
dtype = int8
input x = [1 0 1]
failed
-------------------------
dtype = int8
input x = [1 0 1]
failed
-------------------------
dtype = int32
input x = [1 0 1]
(fort) x = T F T
(fort) sizeof(x(1)) = 4
(fort) resetting x(:) to true
output x = [1 1 1]
结果 logical(c_bool)
(通过 iso_c_binding):
-------------------------
dtype = <class 'bool'>
input x = [ True False True]
failed
-------------------------
dtype = <class 'numpy.bool_'>
input x = [ True False True]
failed
-------------------------
dtype = <class 'int'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.int8'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.int32'>
input x = [1 0 1]
(fort) x = T F F
(fort) sizeof(x(1)) = 1
(fort) resetting x(:) to true
output x = [65793 0 1]
-------------------------
dtype = <class 'numpy.int64'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.uint64'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.uint8'>
input x = [1 0 1]
failed
-------------------------
dtype = <class 'numpy.uint32'>
input x = [1 0 1]
(fort) x = T F F
(fort) sizeof(x(1)) = 1
(fort) resetting x(:) to true
output x = [65793 0 1]
-------------------------
dtype = <class 'numpy.uint64'>
input x = [1 0 1]
failed
-------------------------
dtype = int8
input x = [1 0 1]
failed
-------------------------
dtype = int8
input x = [1 0 1]
failed
-------------------------
dtype = int32
input x = [1 0 1]
(fort) x = T F F
(fort) sizeof(x(1)) = 1
(fort) resetting x(:) to true
output x = [65793 0 1]
出于某种原因,最后一个 logical(c_bool)
不适用于上述用法...(f2py 似乎将 logical(c_bool)
视为 4 个字节,而 gfortran 将其视为 1 个字节,所以不一致...)