Skip to content

Commit

Permalink
Merge pull request #367 from rsokl/no-diff-test
Browse files Browse the repository at this point in the history
Add mirror no-autodiff numpy functions
  • Loading branch information
rsokl committed Mar 8, 2021
2 parents a0772d1 + 0405b41 commit 6d86c41
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/mygrad/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from mygrad.math.sequential.funcs import max, min
from mygrad.math.trigonometric.funcs import *
from mygrad.nnet.layers.utils import sliding_window_view
from mygrad.no_grad_funcs import *
from mygrad.tensor_creation.funcs import *
from mygrad.tensor_manip.array_shape.funcs import *
from mygrad.tensor_manip.tensor_joining.funcs import *
Expand Down
68 changes: 68 additions & 0 deletions src/mygrad/no_grad_funcs/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import sys
from typing import TYPE_CHECKING, Optional, Tuple, Union

from numpy import dtype, ndarray

from mygrad.tensor_base import _REGISTERED_NO_DIFF_NUMPY_FUNCS
from mygrad.typing import ArrayLike

__all__ = [
"allclose",
"bincount",
"can_cast",
"copyto",
"may_share_memory",
"min_scalar_type",
"result_type",
"shares_memory",
"shape",
]

_module = sys.modules[__name__]

if TYPE_CHECKING: # pragma: no cover

def allclose(
a: ArrayLike,
b: ArrayLike,
rtol: float = 1e-05,
atol: float = 1e-08,
equal_nan: bool = False,
) -> bool:
pass

def bincount(
x: ArrayLike, weights: Optional[ArrayLike] = None, minlength: int = 0
) -> ndarray:
pass

def can_cast(from_, to, casting="safe") -> bool:
pass

def copyto(
dst: ArrayLike, src: ArrayLike, casting: str = "same_kind", where: bool = True
):
pass

def may_share_memory(
a: ArrayLike, b: ArrayLike, max_work: Optional[int] = None
) -> bool:
pass

def min_scalar_type(a: ArrayLike) -> dtype:
pass

def result_type(*arrays_and_dtypes: Union[ArrayLike, dtype]) -> dtype:
pass

def shares_memory(
a: ArrayLike, b: ArrayLike, max_work: Optional[int] = None
) -> bool:
pass

def shape(a: ArrayLike) -> Tuple[int, ...]:
pass


for _func in _REGISTERED_NO_DIFF_NUMPY_FUNCS:
setattr(_module, _func.__name__, _func)
3 changes: 3 additions & 0 deletions src/mygrad/tensor_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,7 @@ def astensor(
np.min_scalar_type,
np.result_type,
np.shares_memory,
np.shape,
}


Expand Down Expand Up @@ -442,6 +443,8 @@ class _ConstantOnly(ValueError):


def _as_constant_array(t: Union["Tensor", np.ndarray]) -> np.ndarray:
"""Passes through all non-tensor objects and constant tensors. Raises on
non-constant tensors."""
if isinstance(t, Tensor):
if t.constant is False:
raise _ConstantOnly()
Expand Down
78 changes: 78 additions & 0 deletions tests/test_numpy_overrides.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import numpy as np
import pytest
from numpy.testing import assert_array_equal

import mygrad as mg
from mygrad.tensor_base import _REGISTERED_NO_DIFF_NUMPY_FUNCS


def test_no_autodiff_all_matches_registered_numpy_funcs():
from mygrad.no_grad_funcs import __all__ as all_no_autodiffs

assert set(all_no_autodiffs) >= set(
k.__name__ for k in _REGISTERED_NO_DIFF_NUMPY_FUNCS
)


@pytest.mark.parametrize(
"numpy_func", sorted(_REGISTERED_NO_DIFF_NUMPY_FUNCS, key=lambda x: x.__name__)
)
def test_registered_noautodiff_mirrored_in_mygrad(numpy_func):
assert getattr(mg, numpy_func.__name__) is numpy_func


def test_allclose():
assert np.allclose(mg.tensor([1.0, 2.0]), np.array([1.0, 2.0])) is True
assert np.allclose(mg.tensor([1.0, 2.0]), np.array([1.0, 1.0])) is False


def test_bincount():
w = mg.tensor([0.3, 0.5, 0.2, 0.7, 1.0, -0.6]) # weights
x = mg.tensor([0, 1, 1, 2, 2, 2])
assert_array_equal(np.bincount(x, weights=w), [0.3, 0.7, 1.1])


def test_can_cast():
assert np.can_cast(mg.tensor(1000.0), np.float32) is True
assert np.can_cast(mg.tensor([1000.0]), np.float32) is False


def test_may_share_memory():
assert np.may_share_memory(mg.tensor([1, 2]), mg.tensor([5, 8, 9])) is False

x = mg.zeros([3, 4])
assert np.may_share_memory(x[:, 0], x[:, 1]) is True


def test_shares_memory():
x = mg.tensor([1, 2, 3, 4])
assert np.shares_memory(x, mg.tensor([5, 6, 7])) is False
assert np.shares_memory(x[::2], x) is True
assert np.shares_memory(x[::2], x[1::2]) is False


def test_result_type():
assert np.result_type(mg.tensor(3.0), mg.tensor(-2)) is np.dtype("float64")


def test_min_scalar_type():
assert np.min_scalar_type(mg.tensor(3.1)) is np.dtype("float16")
assert np.min_scalar_type(mg.tensor(1e50)) is np.dtype("float64")


def test_copyto_tensor_to_tensor():
x = mg.tensor([1.0, 2.0])
y = mg.zeros((2,))
np.copyto(y, x)
assert_array_equal(y, [1.0, 2.0])


def test_copyto_respects_read_only():
x = mg.tensor([1.0, 2.0])
y = +mg.zeros((2,))
with pytest.raises(ValueError):
np.copyto(y, x)


def test_shape():
assert np.shape(mg.tensor(1, ndmin=3)) == (1, 1, 1)

0 comments on commit 6d86c41

Please sign in to comment.