1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
# Owner(s): ["module: dynamo"]
"""
Basic tests to assert and illustrate the behavior around the decision to use 0D
arrays in place of array scalars.
Extensive tests of this sort of functionality is in numpy_tests/core/*scalar*
Also test the isscalar function (which is deliberately a bit more lax).
"""
from torch.testing._internal.common_utils import (
instantiate_parametrized_tests,
parametrize,
run_tests,
subtest,
TEST_WITH_TORCHDYNAMO,
TestCase,
xfailIfTorchDynamo,
)
if TEST_WITH_TORCHDYNAMO:
import numpy as np
from numpy.testing import assert_equal
else:
import torch._numpy as np
from torch._numpy.testing import assert_equal
parametrize_value = parametrize(
"value",
[
subtest(np.int64(42), name="int64"),
subtest(np.array(42), name="array"),
subtest(np.asarray(42), name="asarray"),
subtest(np.asarray(np.int64(42)), name="asarray_int"),
],
)
@instantiate_parametrized_tests
class TestArrayScalars(TestCase):
@parametrize_value
def test_array_scalar_basic(self, value):
assert value.ndim == 0
assert value.shape == ()
assert value.size == 1
assert value.dtype == np.dtype("int64")
@parametrize_value
def test_conversion_to_int(self, value):
py_scalar = int(value)
assert py_scalar == 42
assert isinstance(py_scalar, int)
assert not isinstance(value, int)
@parametrize_value
def test_decay_to_py_scalar(self, value):
# NumPy distinguishes array scalars and 0D arrays. For instance
# `scalar * list` is equivalent to `int(scalar) * list`, but
# `0D array * list` is equivalent to `0D array * np.asarray(list)`.
# Our scalars follow 0D array behavior (because they are 0D arrays)
lst = [1, 2, 3]
product = value * lst
assert isinstance(product, np.ndarray)
assert product.shape == (3,)
assert_equal(product, [42, 42 * 2, 42 * 3])
# repeat with right-mulitply
product = lst * value
assert isinstance(product, np.ndarray)
assert product.shape == (3,)
assert_equal(product, [42, 42 * 2, 42 * 3])
def test_scalar_comparisons(self):
scalar = np.int64(42)
arr = np.array(42)
assert arr == scalar
assert arr >= scalar
assert arr <= scalar
assert scalar == 42
assert arr == 42
# @xfailIfTorchDynamo
@instantiate_parametrized_tests
class TestIsScalar(TestCase):
#
# np.isscalar(...) checks that its argument is a numeric object with exactly one element.
#
# This differs from NumPy which also requires that shape == ().
#
scalars = [
subtest(42, "literal"),
subtest(int(42.0), "int"),
subtest(np.float32(42), "float32"),
subtest(np.array(42), "array_0D", decorators=[xfailIfTorchDynamo]),
subtest([42], "list", decorators=[xfailIfTorchDynamo]),
subtest([[42]], "list-list", decorators=[xfailIfTorchDynamo]),
subtest(np.array([42]), "array_1D", decorators=[xfailIfTorchDynamo]),
subtest(np.array([[42]]), "array_2D", decorators=[xfailIfTorchDynamo]),
]
import math
not_scalars = [
int,
np.float32,
subtest("s", decorators=[xfailIfTorchDynamo]),
subtest("string", decorators=[xfailIfTorchDynamo]),
(),
[],
math.sin,
np,
np.transpose,
[1, 2],
np.asarray([1, 2]),
np.float32([1, 2]),
]
@parametrize("value", scalars)
def test_is_scalar(self, value):
assert np.isscalar(value)
@parametrize("value", not_scalars)
def test_is_not_scalar(self, value):
assert not np.isscalar(value)
if __name__ == "__main__":
run_tests()
|