NumPy 源码解析(十一)
.\numpy\numpy\f2py\tests\test_isoc.py
from . import util
import numpy as np
import pytest
from numpy.testing import assert_allclose
class TestISOC(util.F2PyTest):
sources = [
util.getpath("tests", "src", "isocintrin", "isoCtests.f90"),
]
@pytest.mark.slow
def test_c_double(self):
out = self.module.coddity.c_add(1, 2)
exp_out = 3
assert out == exp_out
def test_bindc_function(self):
out = self.module.coddity.wat(1, 20)
exp_out = 8
assert out == exp_out
def test_bindc_kinds(self):
out = self.module.coddity.c_add_int64(1, 20)
exp_out = 21
assert out == exp_out
def test_bindc_add_arr(self):
a = np.array([1,2,3])
b = np.array([1,2,3])
out = self.module.coddity.add_arr(a, b)
exp_out = a * 2
assert_allclose(out, exp_out)
def test_process_f2cmap_dict():
from numpy.f2py.auxfuncs import process_f2cmap_dict
f2cmap_all = {"integer": {"8": "rubbish_type"}}
new_map = {"INTEGER": {"4": "int"}}
c2py_map = {"int": "int", "rubbish_type": "long"}
exp_map, exp_maptyp = ({"integer": {"8": "rubbish_type", "4": "int"}}, ["int"])
res_map, res_maptyp = process_f2cmap_dict(f2cmap_all, new_map, c2py_map)
assert res_map == exp_map
assert res_maptyp == exp_maptyp
.\numpy\numpy\f2py\tests\test_kind.py
import sys
import os
import pytest
import platform
from numpy.f2py.crackfortran import (
_selected_int_kind_func as selected_int_kind,
_selected_real_kind_func as selected_real_kind,
)
from . import util
class TestKind(util.F2PyTest):
sources = [util.getpath("tests", "src", "kind", "foo.f90")]
@pytest.mark.skipif(sys.maxsize < 2 ** 31 + 1, reason="Fails for 32 bit machines")
def test_int(self):
"""Test `int` kind_func for integers up to 10**40."""
selectedintkind = self.module.selectedintkind
for i in range(40):
assert selectedintkind(i) == selected_int_kind(
i
), f"selectedintkind({i}): expected {selected_int_kind(i)!r} but got {selectedintkind(i)!r}"
def test_real(self):
"""
Test (processor-dependent) `real` kind_func for real numbers
of up to 31 digits precision (extended/quadruple).
"""
selectedrealkind = self.module.selectedrealkind
for i in range(32):
assert selectedrealkind(i) == selected_real_kind(
i
), f"selectedrealkind({i}): expected {selected_real_kind(i)!r} but got {selectedrealkind(i)!r}"
@pytest.mark.xfail(platform.machine().lower().startswith("ppc"), reason="Some PowerPC may not support full IEEE 754 precision")
def test_quad_precision(self):
"""
Test kind_func for quadruple precision [`real(16)`] of 32+ digits .
"""
selectedrealkind = self.module.selectedrealkind
for i in range(32, 40):
assert selectedrealkind(i) == selected_real_kind(
i
), f"selectedrealkind({i}): expected {selected_real_kind(i)!r} but got {selectedrealkind(i)!r}"
.\numpy\numpy\f2py\tests\test_mixed.py
import os
import textwrap
import pytest
from numpy.testing import IS_PYPY
from . import util
class TestMixed(util.F2PyTest):
sources = [
util.getpath("tests", "src", "mixed", "foo.f"),
util.getpath("tests", "src", "mixed", "foo_fixed.f90"),
util.getpath("tests", "src", "mixed", "foo_free.f90"),
]
@pytest.mark.slow
def test_all(self):
assert self.module.bar11() == 11
assert self.module.foo_fixed.bar12() == 12
assert self.module.foo_free.bar13() == 13
@pytest.mark.xfail(IS_PYPY, reason="PyPy cannot modify tp_doc after PyType_Ready")
def test_docstring(self):
expected = textwrap.dedent("""\
a = bar11()
Wrapper for ``bar11``.
Returns
-------
a : int
""")
assert self.module.bar11.__doc__ == expected
.\numpy\numpy\f2py\tests\test_modules.py
import pytest
import textwrap
from . import util
from numpy.testing import IS_PYPY
@pytest.mark.slow
class TestModuleDocString(util.F2PyTest):
sources = [util.getpath("tests", "src", "modules", "module_data_docstring.f90")]
@pytest.mark.xfail(IS_PYPY, reason="PyPy cannot modify tp_doc after PyType_Ready")
def test_module_docstring(self):
assert self.module.mod.__doc__ == textwrap.dedent(
"""\
i : 'i'-scalar
x : 'i'-array(4)
a : 'f'-array(2,3)
b : 'f'-array(-1,-1), not allocated\x00
foo()\n
Wrapper for ``foo``.\n\n"""
)
@pytest.mark.slow
class TestModuleAndSubroutine(util.F2PyTest):
module_name = "example"
sources = [
util.getpath("tests", "src", "modules", "gh25337", "data.f90"),
util.getpath("tests", "src", "modules", "gh25337", "use_data.f90"),
]
def test_gh25337(self):
self.module.data.set_shift(3)
assert "data" in dir(self.module)
@pytest.mark.slow
class TestUsedModule(util.F2PyTest):
module_name = "fmath"
sources = [
util.getpath("tests", "src", "modules", "use_modules.f90"),
]
def test_gh25867(self):
compiled_mods = [x for x in dir(self.module) if "__" not in x]
assert "useops" in compiled_mods
assert self.module.useops.sum_and_double(3, 7) == 20
assert "mathops" in compiled_mods
assert self.module.mathops.add(3, 7) == 10
.\numpy\numpy\f2py\tests\test_parameter.py
import os
import pytest
import numpy as np
from . import util
class TestParameters(util.F2PyTest):
sources = [
util.getpath("tests", "src", "parameter", "constant_real.f90"),
util.getpath("tests", "src", "parameter", "constant_integer.f90"),
util.getpath("tests", "src", "parameter", "constant_both.f90"),
util.getpath("tests", "src", "parameter", "constant_compound.f90"),
util.getpath("tests", "src", "parameter", "constant_non_compound.f90"),
util.getpath("tests", "src", "parameter", "constant_array.f90"),
]
@pytest.mark.slow
def test_constant_real_single(self):
x = np.arange(6, dtype=np.float32)[::2]
pytest.raises(ValueError, self.module.foo_single, x)
x = np.arange(3, dtype=np.float32)
self.module.foo_single(x)
assert np.allclose(x, [0 + 1 + 2 * 3, 1, 2])
@pytest.mark.slow
def test_constant_real_double(self):
x = np.arange(6, dtype=np.float64)[::2]
pytest.raises(ValueError, self.module.foo_double, x)
x = np.arange(3, dtype=np.float64)
self.module.foo_double(x)
assert np.allclose(x, [0 + 1 + 2 * 3, 1, 2])
@pytest.mark.slow
def test_constant_compound_int(self):
x = np.arange(6, dtype=np.int32)[::2]
pytest.raises(ValueError, self.module.foo_compound_int, x)
x = np.arange(3, dtype=np.int32)
self.module.foo_compound_int(x)
assert np.allclose(x, [0 + 1 + 2 * 6, 1, 2])
@pytest.mark.slow
def test_constant_non_compound_int(self):
x = np.arange(4, dtype=np.int32)
self.module.foo_non_compound_int(x)
assert np.allclose(x, [0 + 1 + 2 + 3 * 4, 1, 2, 3])
@pytest.mark.slow
def test_constant_integer_int(self):
x = np.arange(6, dtype=np.int32)[::2]
pytest.raises(ValueError, self.module.foo_int, x)
x = np.arange(3, dtype=np.int32)
self.module.foo_int(x)
assert np.allclose(x, [0 + 1 + 2 * 3, 1, 2])
@pytest.mark.slow
def test_constant_integer_long(self):
x = np.arange(6, dtype=np.int64)[::2]
pytest.raises(ValueError, self.module.foo_long, x)
x = np.arange(3, dtype=np.int64)
self.module.foo_long(x)
assert np.allclose(x, [0 + 1 + 2 * 3, 1, 2])
def test_constant_both(self):
x = np.arange(6, dtype=np.float64)[::2]
pytest.raises(ValueError, self.module.foo, x)
x = np.arange(3, dtype=np.float64)
self.module.foo(x)
assert np.allclose(x, [0 + 1 * 3 * 3 + 2 * 3 * 3, 1 * 3, 2 * 3])
@pytest.mark.slow
def test_constant_no(self):
x = np.arange(6, dtype=np.float64)[::2]
pytest.raises(ValueError, self.module.foo_no, x)
x = np.arange(3, dtype=np.float64)
self.module.foo_no(x)
assert np.allclose(x, [0 + 1 * 3 * 3 + 2 * 3 * 3, 1 * 3, 2 * 3])
@pytest.mark.slow
def test_constant_sum(self):
x = np.arange(6, dtype=np.float64)[::2]
pytest.raises(ValueError, self.module.foo_sum, x)
x = np.arange(3, dtype=np.float64)
self.module.foo_sum(x)
assert np.allclose(x, [0 + 1 * 3 * 3 + 2 * 3 * 3, 1 * 3, 2 * 3])
def test_constant_array(self):
x = np.arange(3, dtype=np.float64)
y = np.arange(5, dtype=np.float64)
z = self.module.foo_array(x, y)
assert np.allclose(x, [0.0, 1./10, 2./10])
assert np.allclose(y, [0.0, 1.*10, 2.*10, 3.*10, 4.*10])
assert np.allclose(z, 19.0)
def test_constant_array_any_index(self):
x = np.arange(6, dtype=np.float64)
y = self.module.foo_array_any_index(x)
assert np.allclose(y, x.reshape((2, 3), order='F'))
def test_constant_array_delims(self):
x = self.module.foo_array_delims()
assert x == 9
.\numpy\numpy\f2py\tests\test_pyf_src.py
from numpy.f2py._src_pyf import process_str
from numpy.testing import assert_equal
pyf_src = """
python module foo
<_rd=real,double precision>
interface
subroutine <s,d>foosub(tol)
<_rd>, intent(in,out) :: tol
end subroutine <s,d>foosub
end interface
end python module foo
"""
expected_pyf = """
python module foo
interface
subroutine sfoosub(tol)
real, intent(in,out) :: tol
end subroutine sfoosub
subroutine dfoosub(tol)
double precision, intent(in,out) :: tol
end subroutine dfoosub
end interface
end python module foo
"""
def normalize_whitespace(s):
"""
去除字符串首尾的空白字符,并将内部连续的空白字符转换为单个空格。
"""
return ' '.join(s.split())
def test_from_template():
"""
gh-10712的回归测试函数。
"""
pyf = process_str(pyf_src)
normalized_pyf = normalize_whitespace(pyf)
normalized_expected_pyf = normalize_whitespace(expected_pyf)
assert_equal(normalized_pyf, normalized_expected_pyf)
.\numpy\numpy\f2py\tests\test_quoted_character.py
"""See https://github.com/numpy/numpy/pull/10676.
"""
import sys
import pytest
from . import util
class TestQuotedCharacter(util.F2PyTest):
sources = [util.getpath("tests", "src", "quoted_character", "foo.f")]
@pytest.mark.skipif(sys.platform == "win32",
reason="Fails with MinGW64 Gfortran (Issue #9673)")
@pytest.mark.slow
def test_quoted_character(self):
assert self.module.foo() == (b"'", b'"', b";", b"!", b"(", b")")
.\numpy\numpy\f2py\tests\test_regression.py
import os
import pytest
import platform
import numpy as np
import numpy.testing as npt
from . import util
class TestIntentInOut(util.F2PyTest):
sources = [util.getpath("tests", "src", "regression", "inout.f90")]
@pytest.mark.slow
def test_inout(self):
x = np.arange(6, dtype=np.float32)[::2]
pytest.raises(ValueError, self.module.foo, x)
x = np.arange(3, dtype=np.float32)
self.module.foo(x)
assert np.allclose(x, [3, 1, 2])
class TestNegativeBounds(util.F2PyTest):
sources = [util.getpath("tests", "src", "negative_bounds", "issue_20853.f90")]
@pytest.mark.slow
def test_negbound(self):
xvec = np.arange(12)
xlow = -6
xhigh = 4
def ubound(xl, xh):
return xh - xl + 1
rval = self.module.foo(is_=xlow, ie_=xhigh,
arr=xvec[:ubound(xlow, xhigh)])
expval = np.arange(11, dtype=np.float32)
assert np.allclose(rval, expval)
class TestNumpyVersionAttribute(util.F2PyTest):
sources = [util.getpath("tests", "src", "regression", "inout.f90")]
@pytest.mark.slow
def test_numpy_version_attribute(self):
assert hasattr(self.module, "__f2py_numpy_version__")
assert isinstance(self.module.__f2py_numpy_version__, str)
assert np.__version__ == self.module.__f2py_numpy_version__
def test_include_path():
incdir = np.f2py.get_include()
fnames_in_dir = os.listdir(incdir)
for fname in ("fortranobject.c", "fortranobject.h"):
assert fname in fnames_in_dir
class TestIncludeFiles(util.F2PyTest):
sources = [util.getpath("tests", "src", "regression", "incfile.f90")]
options = [f"-I{util.getpath('tests', 'src', 'regression')}",
f"--include-paths {util.getpath('tests', 'src', 'regression')}"]
@pytest.mark.slow
def test_gh25344(self):
exp = 7.0
res = self.module.add(3.0, 4.0)
assert exp == res
class TestF77Comments(util.F2PyTest):
sources = [util.getpath("tests", "src", "regression", "f77comments.f")]
@pytest.mark.slow
def test_gh26148(self):
x1 = np.array(3, dtype=np.int32)
x2 = np.array(5, dtype=np.int32)
res = self.module.testsub(x1, x2)
assert(res[0] == 8)
assert(res[1] == 15)
def test_gh26466(self):
expected = np.arange(1, 11, dtype=np.float32) * 2
res = self.module.testsub2()
npt.assert_allclose(expected, res)
class TestF90Contiuation(util.F2PyTest):
sources = [util.getpath("tests", "src", "regression", "f90continuation.f90")]
@pytest.mark.slow
def test_gh26148b(self):
x1 = np.array(3, dtype=np.int32)
x2 = np.array(5, dtype=np.int32)
res=self.module.testsub(x1, x2)
assert(res[0] == 8)
assert(res[1] == 15)
@pytest.mark.slow
def test_gh26623():
try:
aa = util.build_module(
[util.getpath("tests", "src", "regression", "f90continuation.f90")],
["-lfoo.bar"],
module_name="Blah",
)
except RuntimeError as rerr:
assert "lparen got assign" not in str(rerr)
@pytest.mark.slow
@pytest.mark.skipif(platform.system() not in ['Linux', 'Darwin'], reason='Unsupported on this platform for now')
def test_gh25784():
try:
aa = util.build_module(
[util.getpath("tests", "src", "regression", "f77fixedform.f95")],
options=[
"--f77flags='-ffixed-form -O2'",
"--f90flags=\"-ffixed-form -Og\"",
],
module_name="Blah",
)
except ImportError as rerr:
assert "unknown_subroutine_" in str(rerr)
.\numpy\numpy\f2py\tests\test_return_character.py
import pytest
from numpy import array
from . import util
import platform
IS_S390X = platform.machine() == "s390x"
@pytest.mark.slow
class TestReturnCharacter(util.F2PyTest):
def check_function(self, t, tname):
if tname in ["t0", "t1", "s0", "s1"]:
assert t("23") == b"2"
r = t("ab")
assert r == b"a"
r = t(array("ab"))
assert r == b"a"
r = t(array(77, "u1"))
assert r == b"M"
elif tname in ["ts", "ss"]:
assert t(23) == b"23"
assert t("123456789abcdef") == b"123456789a"
elif tname in ["t5", "s5"]:
assert t(23) == b"23"
assert t("ab") == b"ab"
assert t("123456789abcdef") == b"12345"
else:
raise NotImplementedError
class TestFReturnCharacter(TestReturnCharacter):
sources = [
util.getpath("tests", "src", "return_character", "foo77.f"),
util.getpath("tests", "src", "return_character", "foo90.f90"),
]
@pytest.mark.xfail(IS_S390X, reason="callback returns ' '")
@pytest.mark.parametrize("name", "t0,t1,t5,s0,s1,s5,ss".split(","))
def test_all_f77(self, name):
self.check_function(getattr(self.module, name), name)
@pytest.mark.xfail(IS_S390X, reason="callback returns ' '")
@pytest.mark.parametrize("name", "t0,t1,t5,ts,s0,s1,s5,ss".split(","))
def test_all_f90(self, name):
self.check_function(getattr(self.module.f90_return_char, name), name)
.\numpy\numpy\f2py\tests\test_return_complex.py
import pytest
from numpy import array
from . import util
@pytest.mark.slow
class TestReturnComplex(util.F2PyTest):
def check_function(self, t, tname):
if tname in ["t0", "t8", "s0", "s8"]:
err = 1e-5
else:
err = 0.0
assert abs(t(234j) - 234.0j) <= err
assert abs(t(234.6) - 234.6) <= err
assert abs(t(234) - 234.0) <= err
assert abs(t(234.6 + 3j) - (234.6 + 3j)) <= err
assert abs(t(-234) + 234.0) <= err
assert abs(t([234]) - 234.0) <= err
assert abs(t((234, )) - 234.0) <= err
assert abs(t(array(234)) - 234.0) <= err
assert abs(t(array(23 + 4j, "F")) - (23 + 4j)) <= err
assert abs(t(array([234])) - 234.0) <= err
assert abs(t(array([[234]])) - 234.0) <= err
assert abs(t(array([234]).astype("b")) + 22.0) <= err
assert abs(t(array([234], "h")) - 234.0) <= err
assert abs(t(array([234], "i")) - 234.0) <= err
assert abs(t(array([234], "l")) - 234.0) <= err
assert abs(t(array([234], "q")) - 234.0) <= err
assert abs(t(array([234], "f")) - 234.0) <= err
assert abs(t(array([234], "d")) - 234.0) <= err
assert abs(t(array([234 + 3j], "F")) - (234 + 3j)) <= err
assert abs(t(array([234], "D")) - 234.0) <= err
pytest.raises(TypeError, t, "abc")
pytest.raises(IndexError, t, [])
pytest.raises(IndexError, t, ())
pytest.raises(TypeError, t, t)
pytest.raises(TypeError, t, {})
try:
r = t(10**400)
assert repr(r) in ["(inf+0j)", "(Infinity+0j)"]
except OverflowError:
pass
class TestFReturnComplex(TestReturnComplex):
sources = [
util.getpath("tests", "src", "return_complex", "foo77.f"),
util.getpath("tests", "src", "return_complex", "foo90.f90"),
]
@pytest.mark.parametrize("name", "t0,t8,t16,td,s0,s8,s16,sd".split(","))
def test_all_f77(self, name):
self.check_function(getattr(self.module, name), name)
@pytest.mark.parametrize("name", "t0,t8,t16,td,s0,s8,s16,sd".split(","))
def test_all_f90(self, name):
self.check_function(getattr(self.module.f90_return_complex, name),
name)
.\numpy\numpy\f2py\tests\test_return_integer.py
import pytest
from numpy import array
from . import util
@pytest.mark.slow
class TestReturnInteger(util.F2PyTest):
def check_function(self, t, tname):
assert t(123) == 123
assert t(123.6) == 123
assert t("123") == 123
assert t(-123) == -123
assert t([123]) == 123
assert t((123, )) == 123
assert t(array(123)) == 123
assert t(array(123, "b")) == 123
assert t(array(123, "h")) == 123
assert t(array(123, "i")) == 123
assert t(array(123, "l")) == 123
assert t(array(123, "B")) == 123
assert t(array(123, "f")) == 123
assert t(array(123, "d")) == 123
pytest.raises(ValueError, t, "abc")
pytest.raises(IndexError, t, [])
pytest.raises(IndexError, t, ())
pytest.raises(Exception, t, t)
pytest.raises(Exception, t, {})
if tname in ["t8", "s8"]:
pytest.raises(OverflowError, t, 100000000000000000000000)
pytest.raises(OverflowError, t, 10000000011111111111111.23)
class TestFReturnInteger(TestReturnInteger):
sources = [
util.getpath("tests", "src", "return_integer", "foo77.f"),
util.getpath("tests", "src", "return_integer", "foo90.f90"),
]
@pytest.mark.parametrize("name",
"t0,t1,t2,t4,t8,s0,s1,s2,s4,s8".split(","))
def test_all_f77(self, name):
self.check_function(getattr(self.module, name), name)
@pytest.mark.parametrize("name",
"t0,t1,t2,t4,t8,s0,s1,s2,s4,s8".split(","))
def test_all_f90(self, name):
self.check_function(getattr(self.module.f90_return_integer, name),
name)
.\numpy\numpy\f2py\tests\test_return_logical.py
import pytest
from numpy import array
from . import util
class TestReturnLogical(util.F2PyTest):
def check_function(self, t):
assert t(True) == 1
assert t(False) == 0
assert t(0) == 0
assert t(None) == 0
assert t(0.0) == 0
assert t(0j) == 0
assert t(1j) == 1
assert t(234) == 1
assert t(234.6) == 1
assert t(234.6 + 3j) == 1
assert t("234") == 1
assert t("aaa") == 1
assert t("") == 0
assert t([]) == 0
assert t(()) == 0
assert t({}) == 0
assert t(t) == 1
assert t(-234) == 1
assert t(10**100) == 1
assert t([234]) == 1
assert t((234,)) == 1
assert t(array(234)) == 1
assert t(array([234])) == 1
assert t(array([[234]])) == 1
assert t(array([127], "b")) == 1
assert t(array([234], "h")) == 1
assert t(array([234], "i")) == 1
assert t(array([234], "l")) == 1
assert t(array([234], "f")) == 1
assert t(array([234], "d")) == 1
assert t(array([234 + 3j], "F")) == 1
assert t(array([234], "D")) == 1
assert t(array(0)) == 0
assert t(array([0])) == 0
assert t(array([[0]])) == 0
assert t(array([0j])) == 0
assert t(array([1])) == 1
pytest.raises(ValueError, t, array([0, 0]))
class TestFReturnLogical(TestReturnLogical):
sources = [
util.getpath("tests", "src", "return_logical", "foo77.f"),
util.getpath("tests", "src", "return_logical", "foo90.f90"),
]
@pytest.mark.slow
@pytest.mark.parametrize("name", "t0,t1,t2,t4,s0,s1,s2,s4".split(","))
def test_all_f77(self, name):
self.check_function(getattr(self.module, name))
@pytest.mark.slow
@pytest.mark.parametrize("name",
"t0,t1,t2,t4,t8,s0,s1,s2,s4,s8".split(","))
def test_all_f90(self, name):
self.check_function(getattr(self.module.f90_return_logical, name))
.\numpy\numpy\f2py\tests\test_return_real.py
import platform
import pytest
import numpy as np
from numpy import array
from . import util
@pytest.mark.slow
class TestReturnReal(util.F2PyTest):
def check_function(self, t, tname):
if tname in ["t0", "t4", "s0", "s4"]:
err = 1e-5
else:
err = 0.0
assert abs(t(234) - 234.0) <= err
assert abs(t(234.6) - 234.6) <= err
assert abs(t("234") - 234) <= err
assert abs(t("234.6") - 234.6) <= err
assert abs(t(-234) + 234) <= err
assert abs(t([234]) - 234) <= err
assert abs(t((234, )) - 234.0) <= err
assert abs(t(array(234)) - 234.0) <= err
assert abs(t(array(234).astype("b")) + 22) <= err
assert abs(t(array(234, "h")) - 234.0) <= err
assert abs(t(array(234, "i")) - 234.0) <= err
assert abs(t(array(234, "l")) - 234.0) <= err
assert abs(t(array(234, "B")) - 234.0) <= err
assert abs(t(array(234, "f")) - 234.0) <= err
assert abs(t(array(234, "d")) - 234.0) <= err
if tname in ["t0", "t4", "s0", "s4"]:
assert t(1e200) == t(1e300)
pytest.raises(ValueError, t, "abc")
pytest.raises(IndexError, t, [])
pytest.raises(IndexError, t, ())
pytest.raises(Exception, t, t)
pytest.raises(Exception, t, {})
try:
r = t(10**400)
assert repr(r) in ["inf", "Infinity"]
except OverflowError:
pass
@pytest.mark.skipif(
platform.system() == "Darwin",
reason="Prone to error when run with numpy/f2py/tests on mac os, "
"but not when run in isolation",
)
@pytest.mark.skipif(
np.dtype(np.intp).itemsize < 8,
reason="32-bit builds are buggy"
)
class TestCReturnReal(TestReturnReal):
suffix = ".pyf"
module_name = "c_ext_return_real"
code = """
python module c_ext_return_real
usercode \'\'\'
float t4(float value) { return value; }
void s4(float *t4, float value) { *t4 = value; }
double t8(double value) { return value; }
void s8(double *t8, double value) { *t8 = value; }
\'\'\'
interface
function t4(value)
real*4 intent(c) :: t4,value
end
function t8(value)
real*8 intent(c) :: t8,value
end
subroutine s4(t4,value)
intent(c) s4
real*4 intent(out) :: t4
real*4 intent(c) :: value
end
subroutine s8(t8,value)
intent(c) s8
real*8 intent(out) :: t8
real*8 intent(c) :: value
end
end interface
end python module c_ext_return_real
"""
@pytest.mark.parametrize("name", "t4,t8,s4,s8".split(","))
def test_all(self, name):
self.check_function(getattr(self.module, name), name)
class TestFReturnReal(TestReturnReal):
sources = [
util.getpath("tests", "src", "return_real", "foo77.f"),
util.getpath("tests", "src", "return_real", "foo90.f90"),
]
@pytest.mark.parametrize("name", "t0,t4,t8,td,s0,s4,s8,sd".split(","))
def test_all(self, name):
def test_all_f77(self, name):
self.check_function(getattr(self.module, name), name)
@pytest.mark.parametrize("name", "t0,t4,t8,td,s0,s4,s8,sd".split(","))
def test_all_f90(self, name):
self.check_function(getattr(self.module.f90_return_real, name), name)
.\numpy\numpy\f2py\tests\test_semicolon_split.py
import platform
import pytest
import numpy as np
from . import util
@pytest.mark.skipif(
platform.system() == "Darwin",
reason="Prone to error when run with numpy/f2py/tests on mac os, "
"but not when run in isolation",
)
@pytest.mark.skipif(
np.dtype(np.intp).itemsize < 8,
reason="32-bit builds are buggy"
)
class TestMultiline(util.F2PyTest):
suffix = ".pyf"
module_name = "multiline"
code = f"""
python module {module_name}
usercode '''
void foo(int* x) {{
char dummy = ';';
*x = 42;
}}
'''
interface
subroutine foo(x)
intent(c) foo
integer intent(out) :: x
end subroutine foo
end interface
end python module {module_name}
"""
def test_multiline(self):
assert self.module.foo() == 42
@pytest.mark.skipif(
platform.system() == "Darwin",
reason="Prone to error when run with numpy/f2py/tests on mac os, "
"but not when run in isolation",
)
@pytest.mark.skipif(
np.dtype(np.intp).itemsize < 8,
reason="32-bit builds are buggy"
)
@pytest.mark.slow
class TestCallstatement(util.F2PyTest):
suffix = ".pyf"
module_name = "callstatement"
code = f"""
python module {module_name}
usercode '''
void foo(int* x) {{
}}
'''
interface
subroutine foo(x)
intent(c) foo
integer intent(out) :: x
callprotoargument int*
callstatement {{ &
; &
x = 42; &
}}
end subroutine foo
end interface
end python module {module_name}
"""
def test_callstatement(self):
assert self.module.foo() == 42
.\numpy\numpy\f2py\tests\test_size.py
import os
import pytest
import numpy as np
from . import util
class TestSizeSumExample(util.F2PyTest):
sources = [util.getpath("tests", "src", "size", "foo.f90")]
@pytest.mark.slow
def test_all(self):
r = self.module.foo([[]])
assert r == [0]
r = self.module.foo([[1, 2]])
assert r == [3]
r = self.module.foo([[1, 2], [3, 4]])
assert np.allclose(r, [3, 7])
r = self.module.foo([[1, 2], [3, 4], [5, 6]])
assert np.allclose(r, [3, 7, 11])
@pytest.mark.slow
def test_transpose(self):
r = self.module.trans([[]])
assert np.allclose(r.T, np.array([[]]))
r = self.module.trans([[1, 2]])
assert np.allclose(r, [[1.], [2.]])
r = self.module.trans([[1, 2, 3], [4, 5, 6]])
assert np.allclose(r, [[1, 4], [2, 5], [3, 6]])
@pytest.mark.slow
def test_flatten(self):
r = self.module.flatten([[]])
assert np.allclose(r, [])
r = self.module.flatten([[1, 2]])
assert np.allclose(r, [1, 2])
r = self.module.flatten([[1, 2, 3], [4, 5, 6]])
assert np.allclose(r, [1, 2, 3, 4, 5, 6])
.\numpy\numpy\f2py\tests\test_string.py
import os
import pytest
import textwrap
import numpy as np
from . import util
class TestString(util.F2PyTest):
sources = [util.getpath("tests", "src", "string", "char.f90")]
@pytest.mark.slow
def test_char(self):
strings = np.array(["ab", "cd", "ef"], dtype="c").T
inp, out = self.module.char_test.change_strings(
strings, strings.shape[1])
assert inp == pytest.approx(strings)
expected = strings.copy()
expected[1, :] = "AAA"
assert out == pytest.approx(expected)
class TestDocStringArguments(util.F2PyTest):
sources = [util.getpath("tests", "src", "string", "string.f")]
def test_example(self):
a = np.array(b"123\0\0")
b = np.array(b"123\0\0")
c = np.array(b"123")
d = np.array(b"123")
self.module.foo(a, b, c, d)
assert a.tobytes() == b"123\0\0"
assert b.tobytes() == b"B23\0\0"
assert c.tobytes() == b"123"
assert d.tobytes() == b"D23"
class TestFixedString(util.F2PyTest):
sources = [util.getpath("tests", "src", "string", "fixed_string.f90")]
@staticmethod
def _sint(s, start=0, end=None):
"""Return the content of a string buffer as integer value.
For example:
_sint('1234') -> 4321
_sint('123A') -> 17321
"""
if isinstance(s, np.ndarray):
s = s.tobytes()
elif isinstance(s, str):
s = s.encode()
assert isinstance(s, bytes)
if end is None:
end = len(s)
i = 0
for j in range(start, min(end, len(s))):
i += s[j] * 10**j
return i
def _get_input(self, intent="in"):
if intent in ["in"]:
yield ""
yield "1"
yield "1234"
yield "12345"
yield b""
yield b"\0"
yield b"1"
yield b"\01"
yield b"1\0"
yield b"1234"
yield b"12345"
yield np.ndarray((), np.bytes_, buffer=b"")
yield np.array(b"")
yield np.array(b"\0")
yield np.array(b"1")
yield np.array(b"1\0")
yield np.array(b"\01")
yield np.array(b"1234")
yield np.array(b"123\0")
yield np.array(b"12345")
def test_intent_in(self):
for s in self._get_input():
r = self.module.test_in_bytes4(s)
expected = self._sint(s, end=4)
assert r == expected, s
def test_intent_inout(self):
for s in self._get_input(intent="inout"):
rest = self._sint(s, start=4)
r = self.module.test_inout_bytes4(s)
expected = self._sint(s, end=4)
assert r == expected
assert rest == self._sint(s, start=4)
.\numpy\numpy\f2py\tests\test_symbolic.py
import pytest
from numpy.f2py.symbolic import (
Expr,
Op,
ArithOp,
Language,
as_symbol,
as_number,
as_string,
as_array,
as_complex,
as_terms,
as_factors,
eliminate_quotes,
insert_quotes,
fromstring,
as_expr,
as_apply,
as_numer_denom,
as_ternary,
as_ref,
as_deref,
normalize,
as_eq,
as_ne,
as_lt,
as_gt,
as_le,
as_ge,
)
from . import util
class TestSymbolic(util.F2PyTest):
def test_eliminate_quotes(self):
def worker(s):
r, d = eliminate_quotes(s)
s1 = insert_quotes(r, d)
assert s1 == s
for kind in ["", "mykind_"]:
worker(kind + '"1234" // "ABCD"')
worker(kind + '"1234" // ' + kind + '"ABCD"')
worker(kind + "\"1234\" // 'ABCD'")
worker(kind + '"1234" // ' + kind + "'ABCD'")
worker(kind + '"1\\"2\'AB\'34"')
worker("a = " + kind + "'1\\'2\"AB\"34'")
def test_sanity(self):
x = as_symbol("x")
y = as_symbol("y")
z = as_symbol("z")
assert x.op == Op.SYMBOL
assert repr(x) == "Expr(Op.SYMBOL, 'x')"
assert x == x
assert x != y
assert hash(x) is not None
n = as_number(123)
m = as_number(456)
assert n.op == Op.INTEGER
assert repr(n) == "Expr(Op.INTEGER, (123, 4))"
assert n == n
assert n != m
assert hash(n) is not None
fn = as_number(12.3)
fm = as_number(45.6)
assert fn.op == Op.REAL
assert repr(fn) == "Expr(Op.REAL, (12.3, 4))"
assert fn == fn
assert fn != fm
assert hash(fn) is not None
c = as_complex(1, 2)
c2 = as_complex(3, 4)
assert c.op == Op.COMPLEX
assert repr(c) == ("Expr(Op.COMPLEX, (Expr(Op.INTEGER, (1, 4)), "
"Expr(Op.INTEGER, (2, 4))))")
assert c == c
assert c != c2
assert hash(c) is not None
s = as_string("'123'")
s2 = as_string('"ABC"')
assert s.op == Op.STRING
assert repr(s) == "Expr(Op.STRING, (\"'123'\", 1))"
assert s == s
assert s != s2
a = as_array((n, m))
b = as_array((n, ))
assert a.op == Op.ARRAY
assert repr(a) == ("Expr(Op.ARRAY, (Expr(Op.INTEGER, (123, 4)), "
"Expr(Op.INTEGER, (456, 4))))")
assert a == a
assert a != b
t = as_terms(x)
u = as_terms(y)
assert t.op == Op.TERMS
assert repr(t) == "Expr(Op.TERMS, {Expr(Op.SYMBOL, 'x'): 1})"
assert t == t
assert t != u
assert hash(t) is not None
v = as_factors(x)
w = as_factors(y)
assert v.op == Op.FACTORS
assert repr(v) == "Expr(Op.FACTORS, {Expr(Op.SYMBOL, 'x'): 1})"
assert v == v
assert w != v
assert hash(v) is not None
t = as_ternary(x, y, z)
u = as_ternary(x, z, y)
assert t.op == Op.TERNARY
assert t == t
assert t != u
assert hash(t) is not None
e = as_eq(x, y)
f = as_lt(x, y)
assert e.op == Op.RELATIONAL
assert e == e
assert e != f
assert hash(e) is not None
def test_tostring_fortran(self):
x = as_symbol("x")
y = as_symbol("y")
z = as_symbol("z")
n = as_number(123)
m = as_number(456)
a = as_array((n, m))
c = as_complex(n, m)
assert str(x) == "x"
assert str(n) == "123"
assert str(a) == "[123, 456]"
assert str(c) == "(123, 456)"
assert str(Expr(Op.TERMS, {x: 1})) == "x"
assert str(Expr(Op.TERMS, {x: 2})) == "2 * x"
assert str(Expr(Op.TERMS, {x: -1})) == "-x"
assert str(Expr(Op.TERMS, {x: -2})) == "-2 * x"
assert str(Expr(Op.TERMS, {x: 1, y: 1})) == "x + y"
assert str(Expr(Op.TERMS, {x: -1, y: -1})) == "-x - y"
assert str(Expr(Op.TERMS, {x: 2, y: 3})) == "2 * x + 3 * y"
assert str(Expr(Op.TERMS, {x: -2, y: 3})) == "-2 * x + 3 * y"
assert str(Expr(Op.TERMS, {x: 2, y: -3})) == "2 * x - 3 * y"
assert str(Expr(Op.FACTORS, {x: 1})) == "x"
assert str(Expr(Op.FACTORS, {x: 2})) == "x ** 2"
assert str(Expr(Op.FACTORS, {x: -1})) == "x ** -1"
assert str(Expr(Op.FACTORS, {x: -2})) == "x ** -2"
assert str(Expr(Op.FACTORS, {x: 1, y: 1})) == "x * y"
assert str(Expr(Op.FACTORS, {x: 2, y: 3})) == "x ** 2 * y ** 3"
v = Expr(Op.FACTORS, {x: 2, Expr(Op.TERMS, {x: 1, y: 1}): 3})
assert str(v) == "x ** 2 * (x + y) ** 3", str(v)
v = Expr(Op.FACTORS, {x: 2, Expr(Op.FACTORS, {x: 1, y: 1}): 3})
assert str(v) == "x ** 2 * (x * y) ** 3", str(v)
assert str(Expr(Op.APPLY, ("f", (), {}))) == "f()"
assert str(Expr(Op.APPLY, ("f", (x, ), {}))) == "f(x)"
assert str(Expr(Op.APPLY, ("f", (x, y), {}))) == "f(x, y)"
assert str(Expr(Op.INDEXING, ("f", x))) == "f[x]"
assert str(as_ternary(x, y, z)) == "merge(y, z, x)"
assert str(as_eq(x, y)) == "x .eq. y"
assert str(as_ne(x, y)) == "x .ne. y"
assert str(as_lt(x, y)) == "x .lt. y"
assert str(as_le(x, y)) == "x .le. y"
assert str(as_gt(x, y)) == "x .gt. y"
assert str(as_ge(x, y)) == "x .ge. y"
def test_tostring_c(self):
language = Language.C
x = as_symbol("x")
y = as_symbol("y")
z = as_symbol("z")
n = as_number(123)
assert Expr(Op.FACTORS, {x: 2}).tostring(language=language) == "x * x"
assert (Expr(Op.FACTORS, {
x + y: 2
}).tostring(language=language) == "(x + y) * (x + y)")
assert Expr(Op.FACTORS, {
x: 12
}).tostring(language=language) == "pow(x, 12)"
assert as_apply(ArithOp.DIV, x,
y).tostring(language=language) == "x / y"
assert (as_apply(ArithOp.DIV, x,
x + y).tostring(language=language) == "x / (x + y)")
assert (as_apply(ArithOp.DIV, x - y, x +
y).tostring(language=language) == "(x - y) / (x + y)")
assert (x + (x - y) / (x + y) +
n).tostring(language=language) == "123 + x + (x - y) / (x + y)"
assert as_ternary(x, y, z).tostring(language=language) == "(x?y:z)"
assert as_eq(x, y).tostring(language=language) == "x == y"
assert as_ne(x, y).tostring(language=language) == "x != y"
assert as_lt(x, y).tostring(language=language) == "x < y"
assert as_le(x, y).tostring(language=language) == "x <= y"
assert as_gt(x, y).tostring(language=language) == "x > y"
assert as_ge(x, y).tostring(language=language) == "x >= y"
def test_operations(self):
x = as_symbol("x")
y = as_symbol("y")
z = as_symbol("z")
assert x + x == Expr(Op.TERMS, {x: 2})
assert x - x == Expr(Op.INTEGER, (0, 4))
assert x + y == Expr(Op.TERMS, {x: 1, y: 1})
assert x - y == Expr(Op.TERMS, {x: 1, y: -1})
assert x * x == Expr(Op.FACTORS, {x: 2})
assert x * y == Expr(Op.FACTORS, {x: 1, y: 1})
assert +x == x
assert -x == Expr(Op.TERMS, {x: -1}), repr(-x)
assert 2 * x == Expr(Op.TERMS, {x: 2})
assert 2 + x == Expr(Op.TERMS, {x: 1, as_number(1): 2})
assert 2 * x + 3 * y == Expr(Op.TERMS, {x: 2, y: 3})
assert (x + y) * 2 == Expr(Op.TERMS, {x: 2, y: 2})
assert x**2 == Expr(Op.FACTORS, {x: 2})
assert (x + y)**2 == Expr(
Op.TERMS,
{
Expr(Op.FACTORS, {x: 2}): 1,
Expr(Op.FACTORS, {y: 2}): 1,
Expr(Op.FACTORS, {
x: 1,
y: 1
}): 2,
},
)
assert (x + y) * x == x**2 + x * y
assert (x + y)**2 == x**2 + 2 * x * y + y**2
assert (x + y)**2 + (x - y)**2 == 2 * x**2 + 2 * y**2
assert (x + y) * z == x * z + y * z
assert z * (x + y) == x * z + y * z
assert (x / 2) == as_apply(ArithOp.DIV, x, as_number(2))
assert (2 * x / 2) == x
assert (3 * x / 2) == as_apply(ArithOp.DIV, 3 * x, as_number(2))
assert (4 * x / 2) == 2 * x
assert (5 * x / 2) == as_apply(ArithOp.DIV, 5 * x, as_number(2))
assert (6 * x / 2) == 3 * x
assert ((3 * 5) * x / 6) == as_apply(ArithOp.DIV, 5 * x, as_number(2))
assert (30 * x**2 * y**4 / (24 * x**3 * y**3)) == as_apply(
ArithOp.DIV, 5 * y, 4 * x)
assert ((15 * x / 6) / 5) == as_apply(ArithOp.DIV, x,
as_number(2)), (15 * x / 6) / 5
assert (x / (5 / x)) == as_apply(ArithOp.DIV, x**2, as_number(5))
assert (x / 2.0) == Expr(Op.TERMS, {x: 0.5})
s = as_string('"ABC"')
t = as_string('"123"')
assert s // t == Expr(Op.STRING, ('"ABC123"', 1))
assert s // x == Expr(Op.CONCAT, (s, x))
assert x // s == Expr(Op.CONCAT, (x, s))
c = as_complex(1.0, 2.0)
assert -c == as_complex(-1.0, -2.0)
assert c + c == as_expr((1 + 2j) * 2)
def test_substitute(self):
x = as_symbol("x")
y = as_symbol("y")
z = as_symbol("z")
a = as_array((x, y))
assert x.substitute({x: y}) == y
assert (x + y).substitute({x: z}) == y + z
assert (x * y).substitute({x: z}) == y * z
assert (x**4).substitute({x: z}) == z**4
assert (x / y).substitute({x: z}) == z / y
assert x.substitute({x: y + z}) == y + z
assert a.substitute({x: y + z}) == as_array((y + z, y))
assert as_ternary(x, y, z).substitute({x: y + z}) == as_ternary(y + z, y, z)
assert as_eq(x, y).substitute({x: y + z}) == as_eq(y + z, y)
def test_traverse(self):
x = as_symbol("x")
y = as_symbol("y")
z = as_symbol("z")
f = as_symbol("f")
def replace_visit(s, r=z):
if s == x:
return r
assert x.traverse(replace_visit) == z
assert y.traverse(replace_visit) == y
assert z.traverse(replace_visit) == z
assert (f(y)).traverse(replace_visit) == f(y)
assert (f(x)).traverse(replace_visit) == f(z)
assert (f[y]).traverse(replace_visit) == f[y]
assert (f[z]).traverse(replace_visit) == f[z]
assert (x + y + z).traverse(replace_visit) == (2 * z + y)
assert (x + f(y, x - z)).traverse(replace_visit) == (z + f(y, as_number(0)))
function_symbols = set()
symbols = set()
def collect_symbols(s):
if s.op is Op.APPLY:
oper = s.data[0]
function_symbols.add(oper)
if oper in symbols:
symbols.remove(oper)
elif s.op is Op.SYMBOL and s not in function_symbols:
symbols.add(s)
(x + f(y, x - z)).traverse(collect_symbols)
assert function_symbols == {f}
assert symbols == {x, y, z}
def collect_symbols2(expr, symbols):
if expr.op is Op.SYMBOL:
symbols.add(expr)
symbols = set()
(x + f(y, x - z)).traverse(collect_symbols2, symbols)
assert symbols == {x, y, z, f}
def collect_symbols3(expr, symbols):
if expr.op is Op.APPLY:
return expr
if expr.op is Op.SYMBOL:
symbols.add(expr)
symbols = set()
(x + f(y, x - z)).traverse(collect_symbols3, symbols)
assert symbols == {x}
def test_linear_solve(self):
x = as_symbol("x")
y = as_symbol("y")
z = as_symbol("z")
assert x.linear_solve(x) == (as_number(1), as_number(0))
assert (x + 1).linear_solve(x) == (as_number(1), as_number(1))
assert (2 * x).linear_solve(x) == (as_number(2), as_number(0))
assert (2 * x + 3).linear_solve(x) == (as_number(2), as_number(3))
assert as_number(3).linear_solve(x) == (as_number(0), as_number(3))
assert y.linear_solve(x) == (as_number(0), y)
assert (y * z).linear_solve(x) == (as_number(0), y * z)
assert (x + y).linear_solve(x) == (as_number(1), y)
assert (z * x + y).linear_solve(x) == (z, y)
assert ((z + y) * x + y).linear_solve(x) == (z + y, y)
assert (z * y * x + y).linear_solve(x) == (z * y, y)
pytest.raises(RuntimeError, lambda: (x * x).linear_solve(x))
def test_as_numer_denom(self):
x = as_symbol("x")
y = as_symbol("y")
n = as_number(123)
assert as_numer_denom(x) == (x, as_number(1))
assert as_numer_denom(x / n) == (x, n)
assert as_numer_denom(n / x) == (n, x)
assert as_numer_denom(x / y) == (x, y)
assert as_numer_denom(x * y) == (x * y, as_number(1))
assert as_numer_denom(n + x / y) == (x + n * y, y)
assert as_numer_denom(n + x / (y - x / n)) == (y * n**2, y * n - x)
def test_polynomial_atoms(self):
x = as_symbol("x")
y = as_symbol("y")
n = as_number(123)
assert x.polynomial_atoms() == {x}
assert n.polynomial_atoms() == set()
assert (y[x]).polynomial_atoms() == {y[x]}
assert (y(x)).polynomial_atoms() == {y(x)}
assert (y(x) + x).polynomial_atoms() == {y(x), x}
assert (y(x) * x[y]).polynomial_atoms() == {y(x), x[y]}
assert (y(x)**x).polynomial_atoms() == {y(x)}
.\numpy\numpy\f2py\tests\test_value_attrspec.py
import os
import pytest
from . import util
class TestValueAttr(util.F2PyTest):
sources = [util.getpath("tests", "src", "value_attrspec", "gh21665.f90")]
@pytest.mark.slow
def test_gh21665(self):
inp = 2
out = self.module.fortfuncs.square(inp)
exp_out = 4
assert out == exp_out
.\numpy\numpy\f2py\tests\util.py
"""
Utility functions for
- building and importing modules on test time, using a temporary location
- detecting if compilers are present
- determining paths to tests
"""
import glob
import os
import sys
import subprocess
import tempfile
import shutil
import atexit
import textwrap
import re
import pytest
import contextlib
import numpy
import concurrent.futures
from pathlib import Path
from numpy._utils import asunicode
from numpy.testing import temppath, IS_WASM
from importlib import import_module
from numpy.f2py._backends._meson import MesonBackend
_module_dir = None
_module_num = 5403
if sys.platform == "cygwin":
NUMPY_INSTALL_ROOT = Path(__file__).parent.parent.parent
_module_list = list(NUMPY_INSTALL_ROOT.glob("**/*.dll"))
def _cleanup():
global _module_dir
if _module_dir is not None:
try:
sys.path.remove(_module_dir)
except ValueError:
pass
try:
shutil.rmtree(_module_dir)
except OSError:
pass
_module_dir = None
def get_module_dir():
global _module_dir
if _module_dir is None:
_module_dir = tempfile.mkdtemp()
atexit.register(_cleanup)
if _module_dir not in sys.path:
sys.path.insert(0, _module_dir)
return _module_dir
def get_temp_module_name():
global _module_num
get_module_dir()
name = "_test_ext_module_%d" % _module_num
_module_num += 1
if name in sys.modules:
raise RuntimeError("Temporary module name already in use.")
return name
def _memoize(func):
memo = {}
def wrapper(*a, **kw):
key = repr((a, kw))
if key not in memo:
try:
memo[key] = func(*a, **kw)
except Exception as e:
memo[key] = e
raise
ret = memo[key]
if isinstance(ret, Exception):
raise ret
return ret
wrapper.__name__ = func.__name__
return wrapper
@_memoize
def build_module(source_files, options=[], skip=[], only=[], module_name=None):
"""
Compile and import a f2py module, built from the given files.
"""
code = f"import sys; sys.path = {sys.path!r}; import numpy.f2py; numpy.f2py.main()"
d = get_module_dir()
dst_sources = []
f2py_sources = []
for fn in source_files:
if not os.path.isfile(fn):
raise RuntimeError("%s is not a file" % fn)
dst = os.path.join(d, os.path.basename(fn))
shutil.copyfile(fn, dst)
dst_sources.append(dst)
base, ext = os.path.splitext(dst)
if ext in (".f90", ".f95", ".f", ".c", ".pyf"):
f2py_sources.append(dst)
assert f2py_sources
if module_name is None:
module_name = get_temp_module_name()
f2py_opts = ["-c", "-m", module_name] + options + f2py_sources
f2py_opts += ["--backend", "meson"]
if skip:
f2py_opts += ["skip:"] + skip
if only:
f2py_opts += ["only:"] + only
cwd = os.getcwd()
try:
os.chdir(d)
cmd = [sys.executable, "-c", code] + f2py_opts
p = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
out, err = p.communicate()
if p.returncode != 0:
raise RuntimeError("Running f2py failed: %s\n%s" %
(cmd[4:], asunicode(out)))
finally:
os.chdir(cwd)
for fn in dst_sources:
os.unlink(fn)
if sys.platform == "cygwin":
_module_list.extend(
glob.glob(os.path.join(d, "{:s}*".format(module_name)))
)
subprocess.check_call(
["/usr/bin/rebase", "--database", "--oblivious", "--verbose"]
+ _module_list
)
return import_module(module_name)
@_memoize
def build_code(source_code,
options=[],
skip=[],
only=[],
suffix=None,
module_name=None):
"""
Compile and import Fortran code using f2py.
编译并导入 Fortran 代码,使用 f2py 工具。
"""
if suffix is None:
suffix = ".f"
with temppath(suffix=suffix) as path:
with open(path, "w") as f:
f.write(source_code)
return build_module([path],
options=options,
skip=skip,
only=only,
module_name=module_name)
def check_language(lang, code_snippet=None):
tmpdir = tempfile.mkdtemp()
try:
meson_file = os.path.join(tmpdir, "meson.build")
with open(meson_file, "w") as f:
f.write("project('check_compilers')\n")
f.write(f"add_languages('{lang}')\n")
if code_snippet:
f.write(f"{lang}_compiler = meson.get_compiler('{lang}')\n")
f.write(f"{lang}_code = '''{code_snippet}'''\n")
f.write(
f"_have_{lang}_feature ="
f"{lang}_compiler.compiles({lang}_code,"
f" name: '{lang} feature check')\n"
)
runmeson = subprocess.run(
["meson", "setup", "btmp"],
check=False,
cwd=tmpdir,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
if runmeson.returncode == 0:
return True
else:
return False
finally:
shutil.rmtree(tmpdir)
return False
fortran77_code = '''
C Example Fortran 77 code
PROGRAM HELLO
PRINT *, 'Hello, Fortran 77!'
END
'''
fortran90_code = '''
! Example Fortran 90 code
program hello90
type :: greeting
character(len=20) :: text
end type greeting
type(greeting) :: greet
greet%text = 'hello, fortran 90!'
print *, greet%text
end program hello90
'''
class CompilerChecker:
def __init__(self):
self.compilers_checked = False
self.has_c = False
self.has_f77 = False
self.has_f90 = False
def check_compilers(self):
if (not self.compilers_checked) and (not sys.platform == "cygwin"):
with concurrent.futures.ThreadPoolExecutor() as executor:
futures = [
executor.submit(check_language, "c"),
executor.submit(check_language, "fortran", fortran77_code),
executor.submit(check_language, "fortran", fortran90_code)
]
self.has_c = futures[0].result()
self.has_f77 = futures[1].result()
self.has_f90 = futures[2].result()
self.compilers_checked = True
if not IS_WASM:
checker = CompilerChecker()
checker.check_compilers()
def has_c_compiler():
return checker.has_c
def has_f77_compiler():
return checker.has_f77
def has_f90_compiler():
return checker.has_f90
class SimplifiedMesonBackend(MesonBackend):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def compile(self):
self.write_meson_build(self.build_dir)
self.run_meson(self.build_dir)
def build_meson(source_files, module_name=None, **kwargs):
"""
通过 Meson 构建并导入一个模块。
"""
build_dir = get_module_dir()
if module_name is None:
module_name = get_temp_module_name()
backend = SimplifiedMesonBackend(
modulename=module_name,
sources=source_files,
extra_objects=kwargs.get("extra_objects", []),
build_dir=build_dir,
include_dirs=kwargs.get("include_dirs", []),
library_dirs=kwargs.get("library_dirs", []),
libraries=kwargs.get("libraries", []),
define_macros=kwargs.get("define_macros", []),
undef_macros=kwargs.get("undef_macros", []),
f2py_flags=kwargs.get("f2py_flags", []),
sysinfo_flags=kwargs.get("sysinfo_flags", []),
fc_flags=kwargs.get("fc_flags", []),
flib_flags=kwargs.get("flib_flags", []),
setup_flags=kwargs.get("setup_flags", []),
remove_build_dir=kwargs.get("remove_build_dir", False),
extra_dat=kwargs.get("extra_dat", {}),
)
try:
backend.compile()
except:
pytest.skip("Failed to compile module")
sys.path.insert(0, f"{build_dir}/{backend.meson_build_dir}")
return import_module(module_name)
class F2PyTest:
code = None
sources = None
options = []
skip = []
only = []
suffix = ".f"
module = None
_has_c_compiler = None
_has_f77_compiler = None
_has_f90_compiler = None
@property
def module_name(self):
cls = type(self)
return f'_{cls.__module__.rsplit(".",1)[-1]}_{cls.__name__}_ext_module'
@classmethod
def setup_class(cls):
if sys.platform == "win32":
pytest.skip("Fails with MinGW64 Gfortran (Issue #9673)")
F2PyTest._has_c_compiler = has_c_compiler()
F2PyTest._has_f77_compiler = has_f77_compiler()
F2PyTest._has_f90_compiler = has_f90_compiler()
def setup_method(self):
if self.module is not None:
return
codes = self.sources if self.sources else []
if self.code:
codes.append(self.suffix)
needs_f77 = any(str(fn).endswith(".f") for fn in codes)
needs_f90 = any(str(fn).endswith(".f90") for fn in codes)
needs_pyf = any(str(fn).endswith(".pyf") for fn in codes)
if needs_f77 and not self._has_f77_compiler:
pytest.skip("No Fortran 77 compiler available")
if needs_f90 and not self._has_f90_compiler:
pytest.skip("No Fortran 90 compiler available")
if needs_pyf and not (self._has_f90_compiler or self._has_f77_compiler):
pytest.skip("No Fortran compiler available")
if self.code is not None:
self.module = build_code(
self.code,
options=self.options,
skip=self.skip,
only=self.only,
suffix=self.suffix,
module_name=self.module_name,
)
if self.sources is not None:
self.module = build_module(
self.sources,
options=self.options,
skip=self.skip,
only=self.only,
module_name=self.module_name,
)
def getpath(*a):
d = Path(numpy.f2py.__file__).parent.resolve()
return d.joinpath(*a)
@contextlib.contextmanager
def switchdir(path):
curpath = Path.cwd()
os.chdir(path)
try:
yield
finally:
os.chdir(curpath)
.\numpy\numpy\f2py\tests\__init__.py
from numpy.testing import IS_WASM, IS_EDITABLE
if IS_WASM:
pytest.skip(
"WASM/Pyodide does not use or support Fortran",
allow_module_level=True
)
if IS_EDITABLE:
pytest.skip(
"Editable install doesn't support tests with a compile step",
allow_module_level=True
)
.\numpy\numpy\f2py\use_rules.py
"""
Build 'use others module data' mechanism for f2py2e.
Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
Copyright 2011 -- present NumPy Developers.
Permission to use, modify, and distribute this software is given under the
terms of the NumPy License.
NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
"""
__version__ = "$Revision: 1.3 $"[10:-1]
f2py_version = 'See `f2py -v`'
from .auxfuncs import (
applyrules, dictappend, gentitle, hasnote, outmess
)
usemodule_rules = {
'body': """
#begintitle#
static char doc_#apiname#[] = \"\\\nVariable wrapper signature:\\n\\
\t #name# = get_#name#()\\n\\
Arguments:\\n\\
#docstr#\";
extern F_MODFUNC(#usemodulename#,#USEMODULENAME#,#realname#,#REALNAME#);
static PyObject *#apiname#(PyObject *capi_self, PyObject *capi_args) {
/*#decl#*/
\tif (!PyArg_ParseTuple(capi_args, \"\")) goto capi_fail;
printf(\"c: %d\\n\",F_MODFUNC(#usemodulename#,#USEMODULENAME#,#realname#,#REALNAME#));
\treturn Py_BuildValue(\"\");
capi_fail:
\treturn NULL;
}
""",
'method': '\t{\"get_#name#\",#apiname#,METH_VARARGS|METH_KEYWORDS,doc_#apiname#},',
'need': ['F_MODFUNC']
}
def buildusevars(m, r):
ret = {}
outmess(
'\t\tBuilding use variable hooks for module "%s" (feature only for F90/F95)...\n' % (m['name']))
varsmap = {}
revmap = {}
if 'map' in r:
for k in r['map'].keys():
if r['map'][k] in revmap:
outmess('\t\t\tVariable "%s<=%s" is already mapped by "%s". Skipping.\n' % (
r['map'][k], k, revmap[r['map'][k]]))
else:
revmap[r['map'][k]] = k
if 'only' in r and r['only']:
for v in r['map'].keys():
if r['map'][v] in m['vars']:
if revmap[r['map'][v]] == v:
varsmap[v] = r['map'][v]
else:
outmess('\t\t\tIgnoring map "%s=>%s". See above.\n' %
(v, r['map'][v]))
else:
outmess(
'\t\t\tNo definition for variable "%s=>%s". Skipping.\n' % (v, r['map'][v]))
else:
for v in m['vars'].keys():
if v in revmap:
varsmap[v] = revmap[v]
else:
varsmap[v] = v
for v in varsmap.keys():
ret = dictappend(ret, buildusevar(v, varsmap[v], m['vars'], m['name']))
return ret
def buildusevar(name, realname, vars, usemodulename):
outmess('\t\t\tConstructing wrapper function for variable "%s=>%s"...\n' % (
name, realname))
ret = {}
vrd = {'name': name,
'realname': realname,
'REALNAME': realname.upper(),
'usemodulename': usemodulename,
'USEMODULENAME': usemodulename.upper(),
'texname': name.replace('_', '\\_'),
'begintitle': gentitle('%s=>%s' % (name, realname)),
'endtitle': gentitle('end of %s=>%s' % (name, realname)),
'apiname': '#modulename#_use_%s_from_%s' % (realname, usemodulename)
}
nummap = {0: 'Ro', 1: 'Ri', 2: 'Rii', 3: 'Riii', 4: 'Riv',
5: 'Rv', 6: 'Rvi', 7: 'Rvii', 8: 'Rviii', 9: 'Rix'}
vrd['texnamename'] = name
for i in nummap.keys():
vrd['texnamename'] = vrd['texnamename'].replace(repr(i), nummap[i])
if hasnote(vars[realname]):
vrd['note'] = vars[realname]['note']
rd = dictappend({}, vrd)
print(name, realname, vars[realname])
ret = applyrules(usemodule_rules, rd)
return ret
.\numpy\numpy\f2py\_backends\_backend.py
from __future__ import annotations
from abc import ABC, abstractmethod
class Backend(ABC):
def __init__(
self,
modulename,
sources,
extra_objects,
build_dir,
include_dirs,
library_dirs,
libraries,
define_macros,
undef_macros,
f2py_flags,
sysinfo_flags,
fc_flags,
flib_flags,
setup_flags,
remove_build_dir,
extra_dat
):
self.modulename = modulename
self.sources = sources
self.extra_objects = extra_objects
self.build_dir = build_dir
self.include_dirs = include_dirs
self.library_dirs = library_dirs
self.libraries = libraries
self.define_macros = define_macros
self.undef_macros = undef_macros
self.f2py_flags = f2py_flags
self.sysinfo_flags = sysinfo_flags
self.fc_flags = fc_flags
self.flib_flags = flib_flags
self.setup_flags = setup_flags
self.remove_build_dir = remove_build_dir
self.extra_dat = extra_dat
@abstractmethod
def compile(self) -> None:
"""Compile the wrapper."""
pass
.\numpy\numpy\f2py\_backends\_distutils.py
from ._backend import Backend
from numpy.distutils.core import setup, Extension
from numpy.distutils.system_info import get_info
from numpy.distutils.misc_util import dict_append
from numpy.exceptions import VisibleDeprecationWarning
import os
import sys
import shutil
import warnings
class DistutilsBackend(Backend):
def __init__(sef, *args, **kwargs):
warnings.warn(
"\ndistutils has been deprecated since NumPy 1.26.x\n"
"Use the Meson backend instead, or generate wrappers"
" without -c and use a custom build script",
VisibleDeprecationWarning,
stacklevel=2,
)
super().__init__(*args, **kwargs)
def compile(self):
num_info = {}
if num_info:
self.include_dirs.extend(num_info.get("include_dirs", []))
ext_args = {
"name": self.modulename,
"sources": self.sources,
"include_dirs": self.include_dirs,
"library_dirs": self.library_dirs,
"libraries": self.libraries,
"define_macros": self.define_macros,
"undef_macros": self.undef_macros,
"extra_objects": self.extra_objects,
"f2py_options": self.f2py_flags,
}
if self.sysinfo_flags:
for n in self.sysinfo_flags:
i = get_info(n)
if not i:
print(
f"No {repr(n)} resources found"
"in system (try `f2py --help-link`)"
)
dict_append(ext_args, **i)
ext = Extension(**ext_args)
sys.argv = [sys.argv[0]] + self.setup_flags
sys.argv.extend(
[
"build",
"--build-temp",
self.build_dir,
"--build-base",
self.build_dir,
"--build-platlib",
".",
"--disable-optimization",
]
)
if self.fc_flags:
sys.argv.extend(["config_fc"] + self.fc_flags)
if self.flib_flags:
sys.argv.extend(["build_ext"] + self.flib_flags)
setup(ext_modules=[ext])
if self.remove_build_dir and os.path.exists(self.build_dir):
print(f"Removing build directory {self.build_dir}")
shutil.rmtree(self.build_dir)
.\numpy\numpy\f2py\_backends\_meson.py
from __future__ import annotations
import os
import errno
import shutil
import subprocess
import sys
import re
from pathlib import Path
from ._backend import Backend
from string import Template
from itertools import chain
class MesonTemplate:
"""Template meson build file generation class."""
def __init__(
self,
modulename: str,
sources: list[Path],
deps: list[str],
libraries: list[str],
library_dirs: list[Path],
include_dirs: list[Path],
object_files: list[Path],
linker_args: list[str],
fortran_args: list[str],
build_type: str,
python_exe: str,
):
self.modulename = modulename
self.build_template_path = (
Path(__file__).parent.absolute() / "meson.build.template"
)
self.sources = sources
self.deps = deps
self.libraries = libraries
self.library_dirs = library_dirs
if include_dirs is not None:
self.include_dirs = include_dirs
else:
self.include_dirs = []
self.substitutions = {}
self.objects = object_files
self.fortran_args = [
f"'{x}'" if not (x.startswith("'") and x.endswith("'")) else x
for x in fortran_args
]
self.pipeline = [
self.initialize_template,
self.sources_substitution,
self.deps_substitution,
self.include_substitution,
self.libraries_substitution,
self.fortran_args_substitution,
]
self.build_type = build_type
self.python_exe = python_exe
self.indent = " " * 21
def meson_build_template(self) -> str:
if not self.build_template_path.is_file():
raise FileNotFoundError(
errno.ENOENT,
"Meson build template"
f" {self.build_template_path.absolute()}"
" does not exist.",
)
return self.build_template_path.read_text()
def initialize_template(self) -> None:
self.substitutions["modulename"] = self.modulename
self.substitutions["buildtype"] = self.build_type
self.substitutions["python"] = self.python_exe
def sources_substitution(self) -> None:
self.substitutions["source_list"] = ",\n".join(
[f"{self.indent}'''{source}'''," for source in self.sources]
)
def deps_substitution(self) -> None:
self.substitutions["dep_list"] = f",\n{self.indent}".join(
[f"{self.indent}dependency('{dep}')," for dep in self.deps]
)
def libraries_substitution(self) -> None:
self.substitutions["lib_dir_declarations"] = "\n".join(
[
f"lib_dir_{i} = declare_dependency(link_args : ['''-L{lib_dir}'''])"
for i, lib_dir in enumerate(self.library_dirs)
]
)
self.substitutions["lib_declarations"] = "\n".join(
[
f"{lib.replace('.','_')} = declare_dependency(link_args : ['-l{lib}'])"
for lib in self.libraries
]
)
self.substitutions["lib_list"] = f"\n{self.indent}".join(
[f"{self.indent}{lib.replace('.','_')}," for lib in self.libraries]
)
self.substitutions["lib_dir_list"] = f"\n{self.indent}".join(
[f"{self.indent}lib_dir_{i}," for i in range(len(self.library_dirs))]
)
def include_substitution(self) -> None:
self.substitutions["inc_list"] = f",\n{self.indent}".join(
[f"{self.indent}'''{inc}'''," for inc in self.include_dirs]
)
def fortran_args_substitution(self) -> None:
if self.fortran_args:
self.substitutions["fortran_args"] = (
f"{self.indent}fortran_args: [{', '.join([arg for arg in self.fortran_args])}],"
)
else:
self.substitutions["fortran_args"] = ""
def generate_meson_build(self):
for node in self.pipeline:
node()
template = Template(self.meson_build_template())
meson_build = template.substitute(self.substitutions)
meson_build = re.sub(r",,", ",", meson_build)
return meson_build
class MesonBackend(Backend):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.dependencies = self.extra_dat.get("dependencies", [])
self.meson_build_dir = "bbdir"
self.build_type = (
"debug" if any("debug" in flag for flag in self.fc_flags) else "release"
)
self.fc_flags = _get_flags(self.fc_flags)
def _move_exec_to_root(self, build_dir: Path):
walk_dir = Path(build_dir) / self.meson_build_dir
path_objects = chain(
walk_dir.glob(f"{self.modulename}*.so"),
walk_dir.glob(f"{self.modulename}*.pyd"),
)
for path_object in path_objects:
dest_path = Path.cwd() / path_object.name
if dest_path.exists():
dest_path.unlink()
shutil.copy2(path_object, dest_path)
os.remove(path_object)
def write_meson_build(self, build_dir: Path) -> None:
"""Writes the meson build file at specified location"""
meson_template = MesonTemplate(
self.modulename,
self.sources,
self.dependencies,
self.libraries,
self.library_dirs,
self.include_dirs,
self.extra_objects,
self.flib_flags,
self.fc_flags,
self.build_type,
sys.executable,
)
Path(build_dir).mkdir(parents=True, exist_ok=True)
meson_build_file = Path(build_dir) / "meson.build"
meson_build_file.write_text(src)
return meson_build_file
def _run_subprocess_command(self, command, cwd):
subprocess.run(command, cwd=cwd, check=True)
def run_meson(self, build_dir: Path):
setup_command = ["meson", "setup", self.meson_build_dir]
self._run_subprocess_command(setup_command, build_dir)
compile_command = ["meson", "compile", "-C", self.meson_build_dir]
self._run_subprocess_command(compile_command, build_dir)
def compile(self) -> None:
self.sources = _prepare_sources(self.modulename, self.sources, self.build_dir)
self.write_meson_build(self.build_dir)
self.run_meson(self.build_dir)
self._move_exec_to_root(self.build_dir)
def _prepare_sources(mname, sources, bdir):
extended_sources = sources.copy()
Path(bdir).mkdir(parents=True, exist_ok=True)
for source in sources:
if Path(source).exists() and Path(source).is_file():
shutil.copy(source, bdir)
generated_sources = [
Path(f"{mname}module.c"),
Path(f"{mname}-f2pywrappers2.f90"),
Path(f"{mname}-f2pywrappers.f"),
]
bdir = Path(bdir)
for generated_source in generated_sources:
if generated_source.exists():
shutil.copy(generated_source, bdir / generated_source.name)
extended_sources.append(generated_source.name)
generated_source.unlink()
extended_sources = [
Path(source).name
for source in extended_sources
if not Path(source).suffix == ".pyf"
]
return extended_sources
def _get_flags(fc_flags):
flag_values = []
flag_pattern = re.compile(r"--f(77|90)flags=(.*)")
for flag in fc_flags:
match_result = flag_pattern.match(flag)
if match_result:
values = match_result.group(2).strip().split()
values = [val.strip("'\"") for val in values]
flag_values.extend(values)
unique_flags = list(dict.fromkeys(flag_values))
return unique_flags
.\numpy\numpy\f2py\_backends\__init__.py
def f2py_build_generator(name):
if name == "meson":
from ._meson import MesonBackend
return MesonBackend
elif name == "distutils":
from ._distutils import DistutilsBackend
return DistutilsBackend
else:
raise ValueError(f"Unknown backend: {name}")
.\numpy\numpy\f2py\_isocbind.py
"""
ISO_C_BINDING maps for f2py2e.
Only required declarations/macros/functions will be used.
Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
Copyright 2011 -- present NumPy Developers.
Permission to use, modify, and distribute this software is given under the
terms of the NumPy License.
NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
"""
iso_c_binding_map = {
'integer': {
'c_int': 'int',
'c_short': 'short',
'c_long': 'long',
'c_long_long': 'long_long',
'c_signed_char': 'signed_char',
'c_size_t': 'unsigned',
'c_int8_t': 'signed_char',
'c_int16_t': 'short',
'c_int32_t': 'int',
'c_int64_t': 'long_long',
'c_int_least8_t': 'signed_char',
'c_int_least16_t': 'short',
'c_int_least32_t': 'int',
'c_int_least64_t': 'long_long',
'c_int_fast8_t': 'signed_char',
'c_int_fast16_t': 'short',
'c_int_fast32_t': 'int',
'c_int_fast64_t': 'long_long',
'c_intmax_t': 'long_long',
'c_intptr_t': 'long',
'c_ptrdiff_t': 'long',
},
'real': {
'c_float': 'float',
'c_double': 'double',
'c_long_double': 'long_double'
},
'complex': {
'c_float_complex': 'complex_float',
'c_double_complex': 'complex_double',
'c_long_double_complex': 'complex_long_double'
},
'logical': {
'c_bool': 'unsigned_char'
},
'character': {
'c_char': 'char'
}
}
isoc_c2pycode_map = {}
iso_c2py_map = {}
isoc_kindmap = {}
for fortran_type, c_type_dict in iso_c_binding_map.items():
for c_type in c_type_dict.keys():
isoc_kindmap[c_type] = fortran_type
.\numpy\numpy\f2py\_src_pyf.py
import re
"""
process_file(filename)
takes templated file .xxx.src and produces .xxx file where .xxx
is .pyf .f90 or .f using the following template rules:
'<..>' denotes a template.
All function and subroutine blocks in a source file with names that
contain '<..>' will be replicated according to the rules in '<..>'.
The number of comma-separated words in '<..>' will determine the number of
replicates.
'<..>' may have two different forms, named and short. For example,
named:
<p=d,s,z,c> where anywhere inside a block '<p>' will be replaced with
'd', 's', 'z', and 'c' for each replicate of the block.
<_c> is already defined: <_c=s,d,c,z>
<_t> is already defined: <_t=real,double precision,complex,double complex>
short:
<s,d,c,z>, a short form of the named, useful when no <p> appears inside
a block.
In general, '<..>' contains a comma separated list of arbitrary
expressions. If these expression must contain a comma|leftarrow|rightarrow,
then prepend the comma|leftarrow|rightarrow with a backslash.
If an expression matches '\\<index>' then it will be replaced
by <index>-th expression.
Note that all '<..>' forms in a block must have the same number of
comma-separated entries.
Predefined named template rules:
<prefix=s,d,c,z>
<ftype=real,double precision,complex,double complex>
<ftypereal=real,double precision,\\0,\\1>
<ctype=float,double,complex_float,complex_double>
<ctypereal=float,double,\\0,\\1>
"""
routine_start_re = re.compile(r'(\n|\A)(( (\$|\*))|)\s*(subroutine|function)\b', re.I)
routine_end_re = re.compile(r'\n\s*end\s*(subroutine|function)\b.*(\n|\Z)', re.I)
function_start_re = re.compile(r'\n (\$|\*)\s*function\b', re.I)
def parse_structure(astr):
""" Return a list of tuples for each function or subroutine each
tuple is the start and end of a subroutine or function to be
expanded.
"""
spanlist = []
ind = 0
while True:
m = routine_start_re.search(astr, ind)
if m is None:
break
start = m.start()
if function_start_re.match(astr, start, m.end()):
while True:
i = astr.rfind('\n', ind, start)
if i == -1:
break
start = i
if astr[i:i+7] != '\n $':
break
start += 1
m = routine_end_re.search(astr, m.end())
ind = end = m and m.end()-1 or len(astr)
spanlist.append((start, end))
return spanlist
template_re = re.compile(r"<\s*(\w[\w\d]*)\s*>")
named_re = re.compile(r"<\s*(\w[\w\d]*)\s*=\s*(.*?)\s*>")
list_re = re.compile(r"<\s*((.*?))\s*>")
def find_repl_patterns(astr):
reps = named_re.findall(astr)
names = {}
for rep in reps:
name = rep[0].strip() or unique_key(names)
repl = rep[1].replace(r'\,', '@comma@')
thelist = conv(repl)
names[name] = thelist
return names
def find_and_remove_repl_patterns(astr):
names = find_repl_patterns(astr)
astr = re.subn(named_re, '', astr)[0]
return astr, names
item_re = re.compile(r"\A\\(?P<index>\d+)\Z")
def conv(astr):
b = astr.split(',')
l = [x.strip() for x in b]
for i in range(len(l)):
m = item_re.match(l[i])
if m:
j = int(m.group('index'))
l[i] = l[j]
return ','.join(l)
def unique_key(adict):
""" Obtain a unique key given a dictionary."""
allkeys = list(adict.keys())
done = False
n = 1
while not done:
newkey = '__l%s' % (n)
if newkey in allkeys:
n += 1
else:
done = True
return newkey
template_name_re = re.compile(r'\A\s*(\w[\w\d]*)\s*\Z')
def expand_sub(substr, names):
substr = substr.replace(r'\>', '@rightarrow@')
substr = substr.replace(r'\<', '@leftarrow@')
lnames = find_repl_patterns(substr)
substr = named_re.sub(r"<\1>", substr)
def listrepl(mobj):
thelist = conv(mobj.group(1).replace(r'\,', '@comma@'))
if template_name_re.match(thelist):
return "<%s>" % (thelist)
name = None
for key in lnames.keys():
if lnames[key] == thelist:
name = key
if name is None:
name = unique_key(lnames)
lnames[name] = thelist
return "<%s>" % name
substr = list_re.sub(listrepl, substr)
numsubs = None
base_rule = None
rules = {}
for r in template_re.findall(substr):
if r not in rules:
thelist = lnames.get(r, names.get(r, None))
if thelist is None:
raise ValueError('No replicates found for <%s>' % (r))
if r not in names and not thelist.startswith('_'):
names[r] = thelist
rule = [i.replace('@comma@', ',') for i in thelist.split(',')]
num = len(rule)
if numsubs is None:
numsubs = num
rules[r] = rule
base_rule = r
elif num == numsubs:
rules[r] = rule
else:
print("Mismatch in number of replacements (base <{}={}>) "
"for <{}={}>. Ignoring.".format(base_rule, ','.join(rules[base_rule]), r, thelist))
if not rules:
return substr
def namerepl(mobj):
name = mobj.group(1)
return rules.get(name, (k+1)*[name])[k]
newstr = ''
for k in range(numsubs):
newstr += template_re.sub(namerepl, substr) + '\n\n'
newstr = newstr.replace('@rightarrow@', '>')
newstr = newstr.replace('@leftarrow@', '<')
return newstr
def process_str(allstr):
newstr = allstr
writestr = ''
struct = parse_structure(newstr)
oldend = 0
names = {}
names.update(_special_names)
for sub in struct:
cleanedstr, defs = find_and_remove_repl_patterns(newstr[oldend:sub[0]])
writestr += cleanedstr
names.update(defs)
writestr += expand_sub(newstr[sub[0]:sub[1]], names)
oldend = sub[1]
writestr += newstr[oldend:]
return writestr
include_src_re = re.compile(r"(\n|\A)\s*include\s*['\"](?P<name>[\w\d./\\]+\.src)['\"]", re.I)
def resolve_includes(source):
d = os.path.dirname(source)
with open(source) as fid:
lines = []
for line in fid:
m = include_src_re.match(line)
if m:
fn = m.group('name')
if not os.path.isabs(fn):
fn = os.path.join(d, fn)
if os.path.isfile(fn):
lines.extend(resolve_includes(fn))
else:
lines.append(line)
else:
lines.append(line)
return lines
def process_file(source):
lines = resolve_includes(source)
return process_str(''.join(lines))
_special_names = find_repl_patterns('''
<_c=s,d,c,z>
<_t=real,double precision,complex,double complex>
<prefix=s,d,c,z>
<ftype=real,double precision,complex,double complex>
<ctype=float,double,complex_float,complex_double>
<ftypereal=real,double precision,\\0,\\1>
<ctypereal=float,double,\\0,\\1>
''')
.\numpy\numpy\f2py\__init__.py
"""Fortran to Python Interface Generator.
Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
Copyright 2011 -- present NumPy Developers.
Permission to use, modify, and distribute this software is given under the terms
of the NumPy License.
NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
"""
__all__ = ['run_main', 'get_include']
import sys
import subprocess
import os
import warnings
from numpy.exceptions import VisibleDeprecationWarning
from . import f2py2e
from . import diagnose
run_main = f2py2e.run_main
main = f2py2e.main
def get_include():
"""
Return the directory that contains the ``fortranobject.c`` and ``.h`` files.
.. note::
This function is not needed when building an extension with
`numpy.distutils` directly from ``.f`` and/or ``.pyf`` files
in one go.
Python extension modules built with f2py-generated code need to use
``fortranobject.c`` as a source file, and include the ``fortranobject.h``
header. This function can be used to obtain the directory containing
both of these files.
Returns
-------
include_path : str
Absolute path to the directory containing ``fortranobject.c`` and
``fortranobject.h``.
Notes
-----
.. versionadded:: 1.21.1
Unless the build system you are using has specific support for f2py,
building a Python extension using a ``.pyf`` signature file is a two-step
process. For a module ``mymod``:
* Step 1: run ``python -m numpy.f2py mymod.pyf --quiet``. This
generates ``mymodmodule.c`` and (if needed)
``mymod-f2pywrappers.f`` files next to ``mymod.pyf``.
* Step 2: build your Python extension module. This requires the
following source files:
* ``mymodmodule.c``
* ``mymod-f2pywrappers.f`` (if it was generated in Step 1)
* ``fortranobject.c``
See Also
--------
numpy.get_include : function that returns the numpy include directory
"""
return os.path.join(os.path.dirname(__file__), 'src')
def __getattr__(attr):
"""
Handle dynamic attribute access for the module.
Parameters
----------
attr : str
The name of the attribute being accessed dynamically.
Returns
-------
object
The value of the dynamically accessed attribute.
Raises
------
AttributeError
If the requested attribute does not exist.
Notes
-----
This function specifically handles access to the 'test' attribute,
importing PytestTester if needed.
"""
if attr == "test":
from numpy._pytesttester import PytestTester
test = PytestTester(__name__)
return test
else:
raise AttributeError("module {!r} has no attribute "
"{!r}".format(__name__, attr))
def __dir__():
"""
Return the list of attributes available in the module.
Returns
-------
list
List of attribute names in the module.
"""
return list(globals().keys() | {"test"})
.\numpy\numpy\f2py\__init__.pyi
import os
import subprocess
from collections.abc import Iterable
from typing import Literal as L, Any, overload, TypedDict
from numpy._pytesttester import PytestTester
class _F2PyDictBase(TypedDict):
csrc: list[str]
h: list[str]
class _F2PyDict(_F2PyDictBase, total=False):
fsrc: list[str]
ltx: list[str]
__all__: list[str]
test: PytestTester
def run_main(comline_list: Iterable[str]) -> dict[str, _F2PyDict]: ...
@overload
def compile(
source: str | bytes,
modulename: str = ...,
extra_args: str | list[str] = ...,
verbose: bool = ...,
source_fn: None | str | bytes | os.PathLike[Any] = ...,
extension: L[".f", ".f90"] = ...,
full_output: L[False] = ...,
) -> int: ...
@overload
def compile(
source: str | bytes,
modulename: str = ...,
extra_args: str | list[str] = ...,
verbose: bool = ...,
source_fn: None | str | bytes | os.PathLike[Any] = ...,
extension: L[".f", ".f90"] = ...,
full_output: L[True] = ...,
) -> subprocess.CompletedProcess[bytes]: ...
def get_include() -> str: ...
.\numpy\numpy\f2py\__main__.py
from numpy.f2py.f2py2e import main
main()
.\numpy\numpy\f2py\__version__.py
from numpy.version import version
.\numpy\numpy\fft\helper.py
def __getattr__(attr_name):
import warnings
ret = getattr(_helper, attr_name, None)
if ret is None:
raise AttributeError(
f"module 'numpy.fft.helper' has no attribute {attr_name}")
warnings.warn(
"The numpy.fft.helper has been made private and renamed to "
"numpy.fft._helper. All four functions exported by it (i.e. fftshift, "
"ifftshift, fftfreq, rfftfreq) are available from numpy.fft. "
f"Please use numpy.fft.{attr_name} instead.",
DeprecationWarning,
stacklevel=3
)
return ret
.\numpy\numpy\fft\tests\test_helper.py
import numpy as np
from numpy.testing import assert_array_almost_equal
from numpy import fft, pi
class TestFFTShift:
def test_definition(self):
x = [0, 1, 2, 3, 4, -4, -3, -2, -1]
y = [-4, -3, -2, -1, 0, 1, 2, 3, 4]
assert_array_almost_equal(fft.fftshift(x), y)
assert_array_almost_equal(fft.ifftshift(y), x)
x = [0, 1, 2, 3, 4, -5, -4, -3, -2, -1]
y = [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4]
assert_array_almost_equal(fft.fftshift(x), y)
assert_array_almost_equal(fft.ifftshift(y), x)
def test_inverse(self):
for n in [1, 4, 9, 100, 211]:
x = np.random.random((n,))
assert_array_almost_equal(fft.ifftshift(fft.fftshift(x)), x)
def test_axes_keyword(self):
freqs = [[0, 1, 2], [3, 4, -4], [-3, -2, -1]]
shifted = [[-1, -3, -2], [2, 0, 1], [-4, 3, 4]]
assert_array_almost_equal(fft.fftshift(freqs, axes=(0, 1)), shifted)
assert_array_almost_equal(fft.fftshift(freqs, axes=0),
fft.fftshift(freqs, axes=(0,)))
assert_array_almost_equal(fft.ifftshift(shifted, axes=(0, 1)), freqs)
assert_array_almost_equal(fft.ifftshift(shifted, axes=0),
fft.ifftshift(shifted, axes=(0,)))
assert_array_almost_equal(fft.fftshift(freqs), shifted)
assert_array_almost_equal(fft.ifftshift(shifted), freqs)
def test_uneven_dims(self):
""" Test 2D input, which has uneven dimension sizes """
freqs = [
[0, 1],
[2, 3],
[4, 5]
]
shift_dim0 = [
[4, 5],
[0, 1],
[2, 3]
]
assert_array_almost_equal(fft.fftshift(freqs, axes=0), shift_dim0)
assert_array_almost_equal(fft.ifftshift(shift_dim0, axes=0), freqs)
assert_array_almost_equal(fft.fftshift(freqs, axes=(0,)), shift_dim0)
assert_array_almost_equal(fft.ifftshift(shift_dim0, axes=[0]), freqs)
shift_dim1 = [
[1, 0],
[3, 2],
[5, 4]
]
assert_array_almost_equal(fft.fftshift(freqs, axes=1), shift_dim1)
assert_array_almost_equal(fft.ifftshift(shift_dim1, axes=1), freqs)
shift_dim_both = [
[5, 4],
[1, 0],
[3, 2]
]
assert_array_almost_equal(fft.fftshift(freqs, axes=(0, 1)), shift_dim_both)
assert_array_almost_equal(fft.ifftshift(shift_dim_both, axes=(0, 1)), freqs)
assert_array_almost_equal(fft.fftshift(freqs, axes=[0, 1]), shift_dim_both)
assert_array_almost_equal(fft.ifftshift(shift_dim_both, axes=[0, 1]), freqs)
assert_array_almost_equal(fft.fftshift(freqs, axes=None), shift_dim_both)
assert_array_almost_equal(fft.ifftshift(shift_dim_both, axes=None), freqs)
assert_array_almost_equal(fft.fftshift(freqs), shift_dim_both)
assert_array_almost_equal(fft.ifftshift(shift_dim_both), freqs)
def test_equal_to_original(self):
""" Test that the new (>=v1.15) implementation (see #10073) is equal to the original (<=v1.14) """
from numpy._core import asarray, concatenate, arange, take
def original_fftshift(x, axes=None):
""" How fftshift was implemented in v1.14"""
tmp = asarray(x)
ndim = tmp.ndim
if axes is None:
axes = list(range(ndim))
elif isinstance(axes, int):
axes = (axes,)
y = tmp
for k in axes:
n = tmp.shape[k]
p2 = (n + 1) // 2
mylist = concatenate((arange(p2, n), arange(p2)))
y = take(y, mylist, k)
return y
def original_ifftshift(x, axes=None):
""" How ifftshift was implemented in v1.14 """
tmp = asarray(x)
ndim = tmp.ndim
if axes is None:
axes = list(range(ndim))
elif isinstance(axes, int):
axes = (axes,)
y = tmp
for k in axes:
n = tmp.shape[k]
p2 = n - (n + 1) // 2
mylist = concatenate((arange(p2, n), arange(p2)))
y = take(y, mylist, k)
return y
for i in range(16):
for j in range(16):
for axes_keyword in [0, 1, None, (0,), (0, 1)]:
inp = np.random.rand(i, j)
assert_array_almost_equal(fft.fftshift(inp, axes_keyword),
original_fftshift(inp, axes_keyword))
assert_array_almost_equal(fft.ifftshift(inp, axes_keyword),
original_ifftshift(inp, axes_keyword))
class TestFFTFreq:
def test_definition(self):
x = [0, 1, 2, 3, 4, -4, -3, -2, -1]
assert_array_almost_equal(9*fft.fftfreq(9), x)
assert_array_almost_equal(9*pi*fft.fftfreq(9, pi), x)
x = [0, 1, 2, 3, 4, -5, -4, -3, -2, -1]
assert_array_almost_equal(10*fft.fftfreq(10), x)
assert_array_almost_equal(10*pi*fft.fftfreq(10, pi), x)
class TestRFFTFreq:
def test_definition(self):
x = [0, 1, 2, 3, 4]
assert_array_almost_equal(9*fft.rfftfreq(9), x)
assert_array_almost_equal(9*pi*fft.rfftfreq(9, pi), x)
x = [0, 1, 2, 3, 4, 5]
assert_array_almost_equal(10*fft.rfftfreq(10), x)
assert_array_almost_equal(10*pi*fft.rfftfreq(10, pi), x)
class TestIRFFTN:
def test_not_last_axis_success(self):
ar, ai = np.random.random((2, 16, 8, 32))
a = ar + 1j*ai
axes = (-2,)
fft.irfftn(a, axes=axes)
.\numpy\numpy\fft\tests\test_pocketfft.py
import numpy as np
import pytest
from numpy.random import random
from numpy.testing import (
assert_array_equal, assert_raises, assert_allclose, IS_WASM
)
import threading
import queue
def fft1(x):
L = len(x)
phase = -2j * np.pi * (np.arange(L) / L)
phase = np.arange(L).reshape(-1, 1) * phase
return np.sum(x*np.exp(phase), axis=1)
class TestFFTShift:
def test_fft_n(self):
assert_raises(ValueError, np.fft.fft, [1, 2, 3], 0)
class TestFFT1D:
def test_identity(self):
maxlen = 512
x = random(maxlen) + 1j*random(maxlen)
xr = random(maxlen)
for i in range(1, maxlen):
assert_allclose(np.fft.ifft(np.fft.fft(x[0:i])), x[0:i],
atol=1e-12)
assert_allclose(np.fft.irfft(np.fft.rfft(xr[0:i]), i),
xr[0:i], atol=1e-12)
@pytest.mark.parametrize("dtype", [np.single, np.double, np.longdouble])
def test_identity_long_short(self, dtype):
maxlen = 16
atol = 4 * np.spacing(np.array(1., dtype=dtype))
x = random(maxlen).astype(dtype) + 1j*random(maxlen).astype(dtype)
xx = np.concatenate([x, np.zeros_like(x)])
xr = random(maxlen).astype(dtype)
xxr = np.concatenate([xr, np.zeros_like(xr)])
for i in range(1, maxlen*2):
check_c = np.fft.ifft(np.fft.fft(x, n=i), n=i)
assert check_c.real.dtype == dtype
assert_allclose(check_c, xx[0:i], atol=atol, rtol=0)
check_r = np.fft.irfft(np.fft.rfft(xr, n=i), n=i)
assert check_r.dtype == dtype
assert_allclose(check_r, xxr[0:i], atol=atol, rtol=0)
@pytest.mark.parametrize("dtype", [np.single, np.double, np.longdouble])
def test_identity_long_short_reversed(self, dtype):
maxlen = 16
atol = 5 * np.spacing(np.array(1., dtype=dtype))
x = random(maxlen).astype(dtype) + 1j*random(maxlen).astype(dtype)
xx = np.concatenate([x, np.zeros_like(x)])
for i in range(1, maxlen*2):
check_via_c = np.fft.fft(np.fft.ifft(x, n=i), n=i)
assert check_via_c.dtype == x.dtype
assert_allclose(check_via_c, xx[0:i], atol=atol, rtol=0)
y = x.copy()
n = i // 2 + 1
y.imag[0] = 0
if i % 2 == 0:
y.imag[n-1:] = 0
yy = np.concatenate([y, np.zeros_like(y)])
check_via_r = np.fft.rfft(np.fft.irfft(x, n=i), n=i)
assert check_via_r.dtype == x.dtype
assert_allclose(check_via_r, yy[0:n], atol=atol, rtol=0)
def test_fft(self):
x = random(30) + 1j*random(30)
assert_allclose(fft1(x), np.fft.fft(x), atol=1e-6)
assert_allclose(fft1(x), np.fft.fft(x, norm="backward"), atol=1e-6)
assert_allclose(fft1(x) / np.sqrt(30),
np.fft.fft(x, norm="ortho"), atol=1e-6)
assert_allclose(fft1(x) / 30.,
np.fft.fft(x, norm="forward"), atol=1e-6)
@pytest.mark.parametrize("axis", (0, 1))
@pytest.mark.parametrize("dtype", (complex, float))
@pytest.mark.parametrize("transpose", (True, False))
def test_fft_out_argument(self, dtype, transpose, axis):
def zeros_like(x):
if transpose:
return np.zeros_like(x.T).T
else:
return np.zeros_like(x)
if dtype is complex:
y = random((10, 20)) + 1j*random((10, 20))
fft, ifft = np.fft.fft, np.fft.ifft
else:
y = random((10, 20))
fft, ifft = np.fft.rfft, np.fft.irfft
expected = fft(y, axis=axis)
out = zeros_like(expected)
result = fft(y, out=out, axis=axis)
assert result is out
assert_array_equal(result, expected)
expected2 = ifft(expected, axis=axis)
out2 = out if dtype is complex else zeros_like(expected2)
result2 = ifft(out, out=out2, axis=axis)
assert result2 is out2
assert_array_equal(result2, expected2)
def test_fft_inplace_out(self, axis):
y = random((20, 20)) + 1j * random((20, 20))
y1 = y.copy()
expected1 = np.fft.fft(y1, axis=axis)
result1 = np.fft.fft(y1, axis=axis, out=y1)
assert result1 is y1
assert_array_equal(result1, expected1)
y2 = y.copy()
out2 = y2[:10] if axis == 0 else y2[:, :10]
expected2 = np.fft.fft(y2, n=10, axis=axis)
result2 = np.fft.fft(y2, n=10, axis=axis, out=out2)
assert result2 is out2
assert_array_equal(result2, expected2)
if axis == 0:
assert_array_equal(y2[10:], y[10:])
else:
assert_array_equal(y2[:, 10:], y[:, 10:])
y3 = y.copy()
y3_sel = y3[5:] if axis == 0 else y3[:, 5:]
out3 = y3[5:15] if axis == 0 else y3[:, 5:15]
expected3 = np.fft.fft(y3_sel, n=10, axis=axis)
result3 = np.fft.fft(y3_sel, n=10, axis=axis, out=out3)
assert result3 is out3
assert_array_equal(result3, expected3)
if axis == 0:
assert_array_equal(y3[:5], y[:5])
assert_array_equal(y3[15:], y[15:])
else:
assert_array_equal(y3[:, :5], y[:, :5])
assert_array_equal(y3[:, 15:], y[:, 15:])
y4 = y.copy()
y4_sel = y4[:10] if axis == 0 else y4[:, :10]
out4 = y4[:15] if axis == 0 else y4[:, :15]
expected4 = np.fft.fft(y4_sel, n=15, axis=axis)
result4 = np.fft.fft(y4_sel, n=15, axis=axis, out=out4)
assert result4 is out4
assert_array_equal(result4, expected4)
if axis == 0:
assert_array_equal(y4[15:], y[15:])
else:
assert_array_equal(y4[:, 15:], y[:, 15:])
y5 = y.copy()
out5 = y5.T
result5 = np.fft.fft(y5, axis=axis, out=out5)
assert result5 is out5
assert_array_equal(result5, expected1)
y6 = y.copy()
out6 = y6[::-1] if axis == 0 else y6[:, ::-1]
result6 = np.fft.fft(y6, axis=axis, out=out6)
assert result6 is out6
assert_array_equal(result6, expected1)
def test_ifft(self, norm):
x = random(30) + 1j*random(30)
assert_allclose(
x, np.fft.ifft(np.fft.fft(x, norm=norm), norm=norm),
atol=1e-6)
with pytest.raises(ValueError,
match='Invalid number of FFT data points'):
np.fft.ifft([], norm=norm)
def test_fft2(self):
x = random((30, 20)) + 1j*random((30, 20))
assert_allclose(np.fft.fft(np.fft.fft(x, axis=1), axis=0),
np.fft.fft2(x), atol=1e-6)
assert_allclose(np.fft.fft2(x),
np.fft.fft2(x, norm="backward"), atol=1e-6)
assert_allclose(np.fft.fft2(x) / np.sqrt(30 * 20),
np.fft.fft2(x, norm="ortho"), atol=1e-6)
assert_allclose(np.fft.fft2(x) / (30. * 20.),
np.fft.fft2(x, norm="forward"), atol=1e-6)
def test_ifft2(self):
x = random((30, 20)) + 1j*random((30, 20))
assert_allclose(np.fft.ifft(np.fft.ifft(x, axis=1), axis=0),
np.fft.ifft2(x), atol=1e-6)
assert_allclose(np.fft.ifft2(x),
np.fft.ifft2(x, norm="backward"), atol=1e-6)
assert_allclose(np.fft.ifft2(x) * np.sqrt(30 * 20),
np.fft.ifft2(x, norm="ortho"), atol=1e-6)
assert_allclose(np.fft.ifft2(x) * (30. * 20.),
np.fft.ifft2(x, norm="forward"), atol=1e-6)
def test_fftn(self):
x = random((30, 20, 10)) + 1j*random((30, 20, 10))
assert_allclose(
np.fft.fft(np.fft.fft(np.fft.fft(x, axis=2), axis=1), axis=0),
np.fft.fftn(x), atol=1e-6)
assert_allclose(np.fft.fftn(x),
np.fft.fftn(x, norm="backward"), atol=1e-6)
assert_allclose(np.fft.fftn(x) / np.sqrt(30 * 20 * 10),
np.fft.fftn(x, norm="ortho"), atol=1e-6)
assert_allclose(np.fft.fftn(x) / (30. * 20. * 10.),
np.fft.fftn(x, norm="forward"), atol=1e-6)
def test_ifftn(self):
x = random((30, 20, 10)) + 1j*random((30, 20, 10))
assert_allclose(
np.fft.ifft(np.fft.ifft(np.fft.ifft(x, axis=2), axis=1), axis=0),
np.fft.ifftn(x), atol=1e-6)
assert_allclose(np.fft.ifftn(x),
np.fft.ifftn(x, norm="backward"), atol=1e-6)
assert_allclose(np.fft.ifftn(x) * np.sqrt(30 * 20 * 10),
np.fft.ifftn(x, norm="ortho"), atol=1e-6)
assert_allclose(np.fft.ifftn(x) * (30. * 20. * 10.),
np.fft.ifftn(x, norm="forward"), atol=1e-6)
def test_rfft(self):
x = random(30)
for n in [x.size, 2*x.size]:
for norm in [None, 'backward', 'ortho', 'forward']:
assert_allclose(
np.fft.fft(x, n=n, norm=norm)[:(n//2 + 1)],
np.fft.rfft(x, n=n, norm=norm), atol=1e-6)
assert_allclose(
np.fft.rfft(x, n=n),
np.fft.rfft(x, n=n, norm="backward"), atol=1e-6)
assert_allclose(
np.fft.rfft(x, n=n) / np.sqrt(n),
np.fft.rfft(x, n=n, norm="ortho"), atol=1e-6)
assert_allclose(
np.fft.rfft(x, n=n) / n,
np.fft.rfft(x, n=n, norm="forward"), atol=1e-6)
def test_rfft_even(self):
x = np.arange(8)
n = 4
y = np.fft.rfft(x, n)
assert_allclose(y, np.fft.fft(x[:n])[:n//2 + 1], rtol=1e-14)
def test_rfft_odd(self):
x = np.array([1, 0, 2, 3, -3])
y = np.fft.rfft(x)
assert_allclose(y, np.fft.fft(x)[:3], rtol=1e-14)
def test_irfft(self):
x = random(30)
assert_allclose(x, np.fft.irfft(np.fft.rfft(x)), atol=1e-6)
assert_allclose(x, np.fft.irfft(np.fft.rfft(x, norm="backward"),
norm="backward"), atol=1e-6)
assert_allclose(x, np.fft.irfft(np.fft.rfft(x, norm="ortho"),
norm="ortho"), atol=1e-6)
assert_allclose(x, np.fft.irfft(np.fft.rfft(x, norm="forward"),
norm="forward"), atol=1e-6)
def test_rfft2(self):
x = random((30, 20))
assert_allclose(np.fft.fft2(x)[:, :11], np.fft.rfft2(x), atol=1e-6)
assert_allclose(np.fft.rfft2(x),
np.fft.rfft2(x, norm="backward"), atol=1e-6)
assert_allclose(np.fft.rfft2(x) / np.sqrt(30 * 20),
np.fft.rfft2(x, norm="ortho"), atol=1e-6)
assert_allclose(np.fft.rfft2(x) / (30. * 20.),
np.fft.rfft2(x, norm="forward"), atol=1e-6)
def test_irfft2(self):
x = random((30, 20))
assert_allclose(x, np.fft.irfft2(np.fft.rfft2(x)), atol=1e-6)
assert_allclose(x, np.fft.irfft2(np.fft.rfft2(x, norm="backward"),
norm="backward"), atol=1e-6)
assert_allclose(x, np.fft.irfft2(np.fft.rfft2(x, norm="ortho"),
norm="ortho"), atol=1e-6)
assert_allclose(x, np.fft.irfft2(np.fft.rfft2(x, norm="forward"),
norm="forward"), atol=1e-6)
def test_rfftn(self):
x = random((30, 20, 10))
assert_allclose(np.fft.fftn(x)[:, :, :6], np.fft.rfftn(x), atol=1e-6)
assert_allclose(np.fft.rfftn(x),
np.fft.rfftn(x, norm="backward"), atol=1e-6)
assert_allclose(np.fft.rfftn(x) / np.sqrt(30 * 20 * 10),
np.fft.rfftn(x, norm="ortho"), atol=1e-6)
assert_allclose(np.fft.rfftn(x) / (30. * 20. * 10.),
np.fft.rfftn(x, norm="forward"), atol=1e-6)
def test_irfftn(self):
x = random((30, 20, 10))
assert_allclose(x, np.fft.irfftn(np.fft.rfftn(x)), atol=1e-6)
assert_allclose(x, np.fft.irfftn(np.fft.rfftn(x, norm="backward"),
norm="backward"), atol=1e-6)
assert_allclose(x, np.fft.irfftn(np.fft.rfftn(x, norm="ortho"),
norm="ortho"), atol=1e-6)
assert_allclose(x, np.fft.irfftn(np.fft.rfftn(x, norm="forward"),
norm="forward"), atol=1e-6)
def test_hfft(self):
x = random(14) + 1j * random(14)
x_herm = np.concatenate((random(1), x, random(1)))
x = np.concatenate((x_herm, x[::-1].conj()))
assert_allclose(np.fft.fft(x), np.fft.hfft(x_herm), atol=1e-6)
assert_allclose(np.fft.hfft(x_herm),
np.fft.hfft(x_herm, norm="backward"), atol=1e-6)
assert_allclose(np.fft.hfft(x_herm) / np.sqrt(30),
np.fft.hfft(x_herm, norm="ortho"), atol=1e-6)
assert_allclose(np.fft.hfft(x_herm) / 30.,
np.fft.hfft(x_herm, norm="forward"), atol=1e-6)
def test_ihfft(self):
x = random(14) + 1j * random(14)
x_herm = np.concatenate((random(1), x, random(1)))
x = np.concatenate((x_herm, x[::-1].conj()))
assert_allclose(x_herm, np.fft.ihfft(np.fft.hfft(x_herm)), atol=1e-6)
assert_allclose(x_herm, np.fft.ihfft(np.fft.hfft(x_herm,
norm="backward"), norm="backward"), atol=1e-6)
assert_allclose(x_herm, np.fft.ihfft(np.fft.hfft(x_herm,
norm="ortho"), norm="ortho"), atol=1e-6)
assert_allclose(x_herm, np.fft.ihfft(np.fft.hfft(x_herm,
norm="forward"), norm="forward"), atol=1e-6)
@pytest.mark.parametrize("op", [np.fft.fftn, np.fft.ifftn,
np.fft.rfftn, np.fft.irfftn])
def test_axes(self, op):
x = random((30, 20, 10))
axes = [(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)]
for a in axes:
op_tr = op(np.transpose(x, a))
tr_op = np.transpose(op(x, axes=a), a)
assert_allclose(op_tr, tr_op, atol=1e-
def test_s_negative_1(self, op):
x = np.arange(100).reshape(10, 10)
assert op(x, s=(-1, 5), axes=(0, 1)).shape == (10, 5)
@pytest.mark.parametrize("op", [np.fft.fftn, np.fft.ifftn,
np.fft.rfftn, np.fft.irfftn])
def test_s_axes_none(self, op):
x = np.arange(100).reshape(10, 10)
with pytest.warns(match='`axes` should not be `None` if `s`'):
op(x, s=(-1, 5))
@pytest.mark.parametrize("op", [np.fft.fft2, np.fft.ifft2])
def test_s_axes_none_2D(self, op):
x = np.arange(100).reshape(10, 10)
with pytest.warns(match='`axes` should not be `None` if `s`'):
op(x, s=(-1, 5), axes=None)
@pytest.mark.parametrize("op", [np.fft.fftn, np.fft.ifftn,
np.fft.rfftn, np.fft.irfftn,
np.fft.fft2, np.fft.ifft2])
def test_s_contains_none(self, op):
x = random((30, 20, 10))
with pytest.warns(match='array containing `None` values to `s`'):
op(x, s=(10, None, 10), axes=(0, 1, 2))
def test_all_1d_norm_preserving(self):
x = random(30)
x_norm = np.linalg.norm(x)
func_pairs = [(np.fft.fft, np.fft.ifft),
(np.fft.rfft, np.fft.irfft),
(np.fft.ihfft, np.fft.hfft),
]
for forw, back in func_pairs:
for n in [x.size, 2*x.size]:
for norm in [None, 'backward', 'ortho', 'forward']:
tmp = forw(x, n=n, norm=norm)
tmp = back(tmp, n=n, norm=norm)
assert_allclose(x_norm,
np.linalg.norm(tmp), atol=1e-6)
@pytest.mark.parametrize("axes", [(0, 1), (0, 2), None])
@pytest.mark.parametrize("dtype", (complex, float))
@pytest.mark.parametrize("transpose", (True, False))
def zeros_like(x):
if transpose:
return np.zeros_like(x.T).T
else:
return np.zeros_like(x)
if dtype is complex:
x = random((10, 5, 6)) + 1j*random((10, 5, 6))
fft, ifft = np.fft.fftn, np.fft.ifftn
else:
x = random((10, 5, 6))
fft, ifft = np.fft.rfftn, np.fft.irfftn
expected = fft(x, axes=axes)
out = zeros_like(expected)
result = fft(x, out=out, axes=axes)
assert result is out
assert_array_equal(result, expected)
expected2 = ifft(expected, axes=axes)
out2 = out if dtype is complex else zeros_like(expected2)
result2 = ifft(out, out=out2, axes=axes)
assert result2 is out2
assert_array_equal(result2, expected2)
@pytest.mark.parametrize("fft", [np.fft.fftn, np.fft.ifftn, np.fft.rfftn])
def test_fftn_out_and_s_interaction(self, fft):
if fft is np.fft.rfftn:
x = random((10, 5, 6))
else:
x = random((10, 5, 6)) + 1j*random((10, 5, 6))
with pytest.raises(ValueError, match="has wrong shape"):
fft(x, out=np.zeros_like(x), s=(3, 3, 3), axes=(0, 1, 2))
s = (10, 5, 5)
expected = fft(x, s=s, axes=(0, 1, 2))
out = np.zeros_like(expected)
result = fft(x, s=s, axes=(0, 1, 2), out=out)
assert result is out
assert_array_equal(result, expected)
@pytest.mark.parametrize("s", [(9, 5, 5), (3, 3, 3)])
def test_irfftn_out_and_s_interaction(self, s):
x = random((9, 5, 6, 2)) + 1j*random((9, 5, 6, 2))
expected = np.fft.irfftn(x, s=s, axes=(0, 1, 2))
out = np.zeros_like(expected)
result = np.fft.irfftn(x, s=s, axes=(0, 1, 2), out=out)
assert result is out
assert_array_equal(result, expected)
@pytest.mark.parametrize(
"dtype",
[np.float32, np.float64, np.complex64, np.complex128])
@pytest.mark.parametrize("order", ["F", 'non-contiguous'])
@pytest.mark.parametrize(
"fft",
[np.fft.fft, np.fft.fft2, np.fft.fftn,
np.fft.ifft, np.fft.ifft2, np.fft.ifftn])
def test_fft_with_order(dtype, order, fft):
rng = np.random.RandomState(42)
X = rng.rand(8, 7, 13).astype(dtype, copy=False)
_tol = 8.0 * np.sqrt(np.log2(X.size)) * np.finfo(X.dtype).eps
if order == 'F':
Y = np.asfortranarray(X)
else:
Y = X[::-1]
X = np.ascontiguousarray(X[::-1])
if fft.__name__.endswith('fft'):
for axis in range(3):
X_res = fft(X, axis=axis)
Y_res = fft(Y, axis=axis)
assert_allclose(X_res, Y_res, atol=_tol, rtol=_tol)
elif fft.__name__.endswith(('fft2', 'fftn')):
axes = [(0, 1), (1, 2), (0, 2)]
if fft.__name__.endswith('fftn'):
axes.extend([(0,), (1,), (2,), None])
for ax in axes:
X_res = fft(X, axes=ax)
Y_res = fft(Y, axes=ax)
assert_allclose(X_res, Y_res, atol=_tol, rtol=_tol)
else:
raise ValueError()
@pytest.mark.skipif(IS_WASM, reason="Cannot start thread")
class TestFFTThreadSafe:
threads = 16
input_shape = (800, 200)
def _test_mtsame(self, func, *args):
def worker(args, q):
q.put(func(*args))
q = queue.Queue()
expected = func(*args)
t = [threading.Thread(target=worker, args=(args, q))
for i in range(self.threads)]
[x.start() for x in t]
[x.join() for x in t]
for i in range(self.threads):
assert_array_equal(q.get(timeout=5), expected,
'Function returned wrong value in multithreaded context')
def test_fft(self):
a = np.ones(self.input_shape) * 1+0j
self._test_mtsame(np.fft.fft, a)
def test_ifft(self):
a = np.ones(self.input_shape) * 1+0j
self._test_mtsame(np.fft.ifft, a)
def test_rfft(self):
a = np.ones(self.input_shape)
self._test_mtsame(np.fft.rfft, a)
def test_irfft(self):
a = np.ones(self.input_shape) * 1+0j
self._test_mtsame(np.fft.irfft, a)
def test_irfft_with_n_1_regression():
x = np.arange(10)
np.fft.irfft(x, n=1)
np.fft.hfft(x, n=1)
np.fft.irfft(np.array([0], complex), n=10)
def test_irfft_with_n_large_regression():
x = np.arange(5) * (1 + 1j)
result = np.fft.hfft(x, n=10)
expected = np.array([20., 9.91628173, -11.8819096, 7.1048486,
-6.62459848, 4., -3.37540152, -0.16057669,
1.8819096, -20.86055364])
assert_allclose(result, expected)
@pytest.mark.parametrize("fft", [
np.fft.fft, np.fft.ifft, np.fft.rfft, np.fft.irfft
])
@pytest.mark.parametrize("data", [
np.array([False, True, False]),
np.arange(10, dtype=np.uint8),
np.arange(5, dtype=np.int16),
])
def test_fft_with_integer_or_bool_input(data, fft):
result = fft(data)
float_data = data.astype(np.result_type(data, 1.))
expected = fft(float_data)
assert_array_equal(result, expected)
.\numpy\numpy\fft\tests\__init__.py
from datetime import datetime
def parse_timestamp(ts):
dt = datetime.strptime(ts, '%Y-%m-%d %H:%M:%S')
return dt
.\numpy\numpy\fft\_helper.py
"""
Discrete Fourier Transforms - _helper.py
"""
from numpy._core import integer, empty, arange, asarray, roll
from numpy._core.overrides import array_function_dispatch, set_module
__all__ = ['fftshift', 'ifftshift', 'fftfreq', 'rfftfreq']
integer_types = (int, integer)
def _fftshift_dispatcher(x, axes=None):
return (x,)
@array_function_dispatch(_fftshift_dispatcher, module='numpy.fft')
def fftshift(x, axes=None):
"""
Shift the zero-frequency component to the center of the spectrum.
This function swaps half-spaces for all axes listed (defaults to all).
Note that ``y[0]`` is the Nyquist component only if ``len(x)`` is even.
Parameters
----------
x : array_like
Input array.
axes : int or shape tuple, optional
Axes over which to shift. Default is None, which shifts all axes.
Returns
-------
y : ndarray
The shifted array.
See Also
--------
ifftshift : The inverse of `fftshift`.
Examples
--------
>>> freqs = np.fft.fftfreq(10, 0.1)
>>> freqs
array([ 0., 1., 2., ..., -3., -2., -1.])
>>> np.fft.fftshift(freqs)
array([-5., -4., -3., -2., -1., 0., 1., 2., 3., 4.])
Shift the zero-frequency component only along the second axis:
>>> freqs = np.fft.fftfreq(9, d=1./9).reshape(3, 3)
>>> freqs
array([[ 0., 1., 2.],
[ 3., 4., -4.],
[-3., -2., -1.]])
>>> np.fft.fftshift(freqs, axes=(1,))
array([[ 2., 0., 1.],
[-4., 3., 4.],
[-1., -3., -2.]])
"""
x = asarray(x)
if axes is None:
axes = tuple(range(x.ndim))
shift = [dim // 2 for dim in x.shape]
elif isinstance(axes, integer_types):
shift = x.shape[axes] // 2
else:
shift = [x.shape[ax] // 2 for ax in axes]
return roll(x, shift, axes)
@array_function_dispatch(_fftshift_dispatcher, module='numpy.fft')
def ifftshift(x, axes=None):
"""
The inverse of `fftshift`. Although identical for even-length `x`, the
functions differ by one sample for odd-length `x`.
Parameters
----------
x : array_like
Input array.
axes : int or shape tuple, optional
Axes over which to calculate. Defaults to None, which shifts all axes.
Returns
-------
y : ndarray
The shifted array.
See Also
--------
fftshift : Shift zero-frequency component to the center of the spectrum.
Examples
--------
>>> freqs = np.fft.fftfreq(9, d=1./9).reshape(3, 3)
>>> freqs
array([[ 0., 1., 2.],
[ 3., 4., -4.],
[-3., -2., -1.]])
>>> np.fft.ifftshift(np.fft.fftshift(freqs))
array([[ 0., 1., 2.],
[ 3., 4., -4.],
[-3., -2., -1.]])
"""
x = asarray(x)
if axes is None:
axes = tuple(range(x.ndim))
shift = [-(dim // 2) for dim in x.shape]
elif isinstance(axes, integer_types):
shift = -(x.shape[axes] // 2)
else:
shift = [-(x.shape[ax] // 2) for ax in axes]
return roll(x, shift, axes)
@set_module('numpy.fft')
def fftfreq(n, d=1.0, device=None):
"""
Return the Discrete Fourier Transform sample frequencies.
The returned float array `f` contains the frequency bin centers in cycles
per unit of the sample spacing (with zero at the start). For instance, if
the sample spacing is in seconds, then the frequency unit is cycles/second.
Given a window length `n` and a sample spacing `d`::
f = [0, 1, ..., n/2-1, -n/2, ..., -1] / (d*n) if n is even
f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n) if n is odd
Parameters
----------
n : int
窗口长度。
d : scalar, optional
采样间隔(采样率的倒数)。默认为 1。
device : str, optional
创建数组时指定的设备。默认为 ``None``。
仅供 Array-API 兼容性使用,如果传入,必须是 ``"cpu"``。
.. versionadded:: 2.0.0
Returns
-------
f : ndarray
长度为 `n` 的数组,包含采样频率。
Examples
--------
>>> signal = np.array([-2, 8, 6, 4, 1, 0, 3, 5], dtype=float)
>>> fourier = np.fft.fft(signal)
>>> n = signal.size
>>> timestep = 0.1
>>> freq = np.fft.fftfreq(n, d=timestep)
>>> freq
array([ 0. , 1.25, 2.5 , ..., -3.75, -2.5 , -1.25])
"""
if not isinstance(n, integer_types):
raise ValueError("n should be an integer")
val = 1.0 / (n * d)
results = empty(n, int, device=device)
N = (n-1)//2 + 1
p1 = arange(0, N, dtype=int, device=device)
results[:N] = p1
p2 = arange(-(n//2), 0, dtype=int, device=device)
results[N:] = p2
return results * val
@set_module('numpy.fft')
def rfftfreq(n, d=1.0, device=None):
"""
Return the Discrete Fourier Transform sample frequencies
(for usage with rfft, irfft).
The returned float array `f` contains the frequency bin centers in cycles
per unit of the sample spacing (with zero at the start). For instance, if
the sample spacing is in seconds, then the frequency unit is cycles/second.
Given a window length `n` and a sample spacing `d`::
f = [0, 1, ..., n/2-1, n/2] / (d*n) if n is even
f = [0, 1, ..., (n-1)/2-1, (n-1)/2] / (d*n) if n is odd
Unlike `fftfreq` (but like `scipy.fftpack.rfftfreq`)
the Nyquist frequency component is considered to be positive.
Parameters
----------
n : int
窗口长度。
d : scalar, optional
采样间隔(采样率的倒数)。默认为 1。
device : str, optional
创建数组时指定的设备。默认为 ``None``。
仅供 Array-API 兼容性使用,如果传入,必须是 ``"cpu"``。
.. versionadded:: 2.0.0
Returns
-------
f : ndarray
长度为 ``n//2 + 1`` 的数组,包含采样频率。
Examples
--------
# 创建一个 numpy 数组,表示输入的信号,其中包含浮点数
signal = np.array([-2, 8, 6, 4, 1, 0, 3, 5, -3, 4], dtype=float)
# 对信号进行快速傅立叶变换(FFT),返回变换后的复数数组
fourier = np.fft.rfft(signal)
# 获取信号的长度(即样本数)
n = signal.size
# 设置采样率为 100
sample_rate = 100
# 使用 FFT 计算频率数组,以实数形式返回频率值
freq = np.fft.fftfreq(n, d=1./sample_rate)
# 输出频率数组
freq
array([ 0., 10., 20., ..., -30., -20., -10.])
# 使用 rfft 方法计算频率数组,以实数形式返回频率值,仅包括非负部分
freq = np.fft.rfftfreq(n, d=1./sample_rate)
# 输出频率数组
freq
array([ 0., 10., 20., 30., 40., 50.])
"""
如果 n 不是整数类型(integer_types),则抛出数值错误
n 应该是一个整数
val = 1.0/(n*d)
N = n//2 + 1
results = arange(0, N, dtype=int, device=device)
return results * val