ivy icon indicating copy to clipboard operation
ivy copied to clipboard

add transpose method to numpy frontend

Open martinoywa opened this issue 2 years ago • 13 comments

This PR addresses Issue #4586

martinoywa avatar Sep 18 '22 12:09 martinoywa

Please double-check the documentation for numpy.transpose at https://numpy.org/doc/stable/reference/generated/numpy.transpose.html

Since numpy doesn't normally accept an out keyword argument, I would omit it from the frontend function and pass out=None to the ivy function, to prevent inconsistent behaviour with different backends.

You also need to add hypothesis tests to https://github.com/martinoywa/ivy/blob/master/ivy_tests/test_ivy/test_frontends/test_numpy/test_matrix/test_methods.py

Hi, thanks for the hint on out. Still working on the tests.

martinoywa avatar Sep 20 '22 10:09 martinoywa

Do you need help with the hypothesis tests?

Hi, yes. I noticed some changes in the implementation with the addition of classes. I've pushed my implementation based on the changes. It passes locally. Please check.

martinoywa avatar Sep 27 '22 10:09 martinoywa

Hi @Nightcrab, I'm having some trouble coming up with hypothesis tests for the method. Would you mind lending a hand?

martinoywa avatar Oct 03 '22 12:10 martinoywa

@martinoywa You might want to use the arrays_and_axes helper function to generate the inputs for this test.

Nightcrab avatar Oct 04 '22 06:10 Nightcrab

That's actually what I was using to generate the test cases but they kept on crashing. This is what I have for the test.

@handle_cmd_line_args
@given(
    x_axes=helpers.arrays_and_axes(
        min_num_dims=1,
        max_num_dims=2,
        min_dim_size=1,
        max_dim_size=2,
        num=1
    ),
)
def test_numpy_transpose(
    x_axes,
    as_variable,
    native_array,
    fw,
):
    x, axes = x_axes
    helpers.test_frontend_method(
        input_dtypes_init=ivy.int32,
        as_variable_flags_init=as_variable,
        num_positional_args_init=0,
        native_array_flags_init=native_array,
        all_as_kwargs_np_init={
            "data": x[0],
            },
        input_dtypes_method=[],
        as_variable_flags_method=as_variable,
        num_positional_args_method=0,
        native_array_flags_method=native_array,
        all_as_kwargs_np_method={
            "axes":axes,
        },
        fw=fw,
        frontend="numpy",
        class_name="matrix",
        method_name="transpose",
    )

martinoywa avatar Oct 04 '22 17:10 martinoywa

The error I get is as below. Which I believe is related to the axes and how permute_dims expects it to be, but I'm still struggling to figure out how to fix it.

test_methods.py:119: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../helpers/function_testing.py:1222: in test_frontend_method
    ret, ret_np_flat = get_ret_and_flattened_np_array(
../../../helpers/function_testing.py:1722: in get_ret_and_flattened_np_array
    ret = fn(*args, **kwargs)
../../../../../ivy/functional/frontends/numpy/matrix/methods.py:122: in transpose
    return ivy.permute_dims(self.A, axes=axes, out=None)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (ivy.array([[0]]),), kwargs = {'axes': [None], 'out': None}

    @functools.wraps(fn)
    def new_fn(*args, **kwargs):
        """
        Catch all exceptions and raise them in IvyException
    
        Parameters
        ----------
        args
            The arguments to be passed to the function.
    
        kwargs
            The keyword arguments to be passed to the function.
    
        Returns
        -------
            The return of the function, or raise IvyException if error is thrown.
        """
        try:
            return fn(*args, **kwargs)
        except (IndexError, ValueError) as e:
            raise ivy.exceptions.IvyError(fn.__name__, str(e))
        except Exception as e:
>           raise ivy.exceptions.IvyBackendException(fn.__name__, str(e))
E           ivy.exceptions.IvyBackendException: numpy: permute_dims: 'NoneType' object cannot be interpreted as an integer

martinoywa avatar Oct 04 '22 17:10 martinoywa

Looks to me like a problem with the frontend function. numpy.matrix.transpose accepts axes=None while ivy.permute_dims doesn't, so you need to implement the default behaviour, which according to numpy docs is this

None or no argument: reverses the order of the axes.

I imagine you can do this by passing the integers n to 0 to ivy.permute_dims where n is the number of dimensions of the input array.

Nightcrab avatar Oct 05 '22 00:10 Nightcrab

Hi, was wondering what you meant by n to 0 to ivy.permute_dims?

martinoywa avatar Oct 17 '22 11:10 martinoywa

If you call ivy.permute_dims(x,[5,4,3,2,1,0]) where x has 6 dimensions for example, what you get is a reversal of the axes (a.k.a a transposition in 6 dimensions).

Nightcrab avatar Oct 17 '22 12:10 Nightcrab

I get it now, thanks.

martinoywa avatar Oct 17 '22 17:10 martinoywa

Hi, I coded up what you mentioned earlier but I'm getting this new error which seems to be coming from the helper function that implements arrays_and_axes where it generates an axes that's a mismatch with the arrays. Any ideas on how to solve this?

test_methods.py:118: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../helpers/function_testing.py:1222: in test_frontend_method
    ret, ret_np_flat = get_ret_and_flattened_np_array(
../../../helpers/function_testing.py:1722: in get_ret_and_flattened_np_array
    ret = fn(*args, **kwargs)
../../../../../ivy/functional/frontends/numpy/matrix/methods.py:125: in transpose
    return ivy.permute_dims(self.A, axes=axes, out=None)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (ivy.array([[0]]),), kwargs = {'axes': [0], 'out': None}

    @functools.wraps(fn)
    def new_fn(*args, **kwargs):
        """
        Catch all exceptions and raise them in IvyException
    
        Parameters
        ----------
        args
            The arguments to be passed to the function.
    
        kwargs
            The keyword arguments to be passed to the function.
    
        Returns
        -------
            The return of the function, or raise IvyException if error is thrown.
        """
        try:
            return fn(*args, **kwargs)
        except (IndexError, ValueError) as e:
>           raise ivy.exceptions.IvyError(fn.__name__, str(e))
E           ivy.exceptions.IvyError: numpy: permute_dims: axes don't match array

martinoywa avatar Oct 27 '22 16:10 martinoywa

The transpose function looks as such;

def transpose(self, axes=None):
        if None in axes:
            return ivy.permute_dims(self.A, axes=tuple(range(self.A.ndim)[::-1]))
        return ivy.permute_dims(self.A, axes=axes, out=None)

martinoywa avatar Oct 27 '22 16:10 martinoywa

It seems like arrays_and_axes will not really do what we're looking for which is generating a permutation of size ndims.

I don't know of a helper that does this, so what I would suggest is using dtype_and_values to get the array then write a permutation generator in the test.

You could perhaps use helpers.floats to generate a float between 0 and 1 then use it to seed random.shuffle(y) where y=[x for x in range(array.ndim)].

Nightcrab avatar Oct 28 '22 00:10 Nightcrab

This PR has been labelled as stale because it has been inactive for more than 7 days. If you would like to continue working on this PR, then please add another comment or this PR will be closed in 7 days.

ivy-seed avatar Nov 08 '22 06:11 ivy-seed

WIP

martinoywa avatar Nov 14 '22 08:11 martinoywa

It seems like arrays_and_axes will not really do what we're looking for which is generating a permutation of size ndims.

I don't know of a helper that does this, so what I would suggest is using dtype_and_values to get the array then write a permutation generator in the test.

You could perhaps use helpers.floats to generate a float between 0 and 1 then use it to seed random.shuffle(y) where y=[x for x in range(array.ndim)].

I'm quite unfamiliar with hypothesis testing. How will this generated array help in testing the function?

martinoywa avatar Nov 20 '22 10:11 martinoywa

In general there are helpers to randomly generate test cases, but here it would be best to write your own. With the randomly shuffled array, you can provide test inputs that match what the function is expecting (permutations).

Nightcrab avatar Nov 22 '22 04:11 Nightcrab

So something similar to regular unit tests?

martinoywa avatar Nov 23 '22 18:11 martinoywa

Regular unit tests aren't randomly generated, and you're still using the hypothesis framework. You'd just be writing your own test strategy.

Nightcrab avatar Nov 23 '22 23:11 Nightcrab

This PR has been labelled as stale because it has been inactive for more than 7 days. If you would like to continue working on this PR, then please add another comment or this PR will be closed in 7 days.

ivy-seed avatar Dec 01 '22 06:12 ivy-seed

This PR has been closed because it has been marked as stale for more than 7 days with no activity.

ivy-seed avatar Dec 08 '22 06:12 ivy-seed