Repository: ivy-llc/ivy
Pull request: fix matrix_norm superset behaviour
fixes #5402

Problem statement:
superset behaviour in matrix_norm (linear_algebra.py)
after adding superset behavoir to matrix_norm , the type hint in `axis: Optional[Union[int, Sequence[int]]] = None` gives the possibility to use an integer while the backend implemetations convert the axis to a tuple, in the case of an integer axis that would throw the error "int object is not iterable". Besides, in the original backend implementations, when the axis is an integer the vector norms are calculated instead while the ivy implementation separates the vector and matrix norms implementations, following the python array API standard . So I think there is no need for the int type hint. Also there is a mismatch between default values for the _axis_ argument in [Container, array, functional api] implementations (which is **None**) and the default values in backend implementations (which is **(-2, -1)**). This doesn't throw an error but I don't know if it's the convenient way.

Hints from issue discussion:
output after calling the function with an integer axis :  
```
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/workspaces/ivy/ivy/func_wrapper.py", line 144, in new_fn
    ret = fn(*args, **kwargs)
  File "/workspaces/ivy/ivy/func_wrapper.py", line 82, in new_fn
    return fn(*new_args, **new_kwargs)
  File "/workspaces/ivy/ivy/func_wrapper.py", line 338, in new_fn
    return fn(*args, **kwargs)
  File "/workspaces/ivy/ivy/func_wrapper.py", line 393, in new_fn
    return fn(*args, **kwargs)
  File "/workspaces/ivy/ivy/exceptions.py", line 65, in new_fn
    raise ivy.exceptions.IvyBackendException(fn.__name__, str(e))
ivy.exceptions.IvyBackendException: numpy: matrix_norm: 'int' object is not iterable
```  
axis argument in functional (also array and container) implementaion  
https://github.com/unifyai/ivy/blob/8db7a9f04a0dcf7cfd26384c646278f12a67a5c8/ivy/functional/ivy/linear_algebra.py#L936  
axis argument in backend implementations  
https://github.com/unifyai/ivy/blob/8db7a9f04a0dcf7cfd26384c646278f12a67a5c8/ivy/functional/backends/numpy/linear_algebra.py#L168  
also only numpy and jax backend implementations require a conversion of the sequence to a tuple. Tensorflow and pytorch handle that in the original implementattions.

Commit message: Merge branch 'master' into fix_matrix_norm_superset_behaviour

Patch to review:
diff --git a/ivy/array/linear_algebra.py b/ivy/array/linear_algebra.py
index 063a06b568ef5..f5f9aae7ac7b3 100644
--- a/ivy/array/linear_algebra.py
+++ b/ivy/array/linear_algebra.py
@@ -185,7 +185,7 @@ def matrix_norm(
         /,
         *,
         ord: Optional[Union[int, float, Literal[inf, -inf, "fro", "nuc"]]] = "fro",
-        axis: Optional[Union[int, Sequence[int]]] = None,
+        axis: Optional[Sequence[int]] = (-2, -1),
         keepdims: bool = False,
         out: Optional[ivy.Array] = None,
     ) -> ivy.Array:
diff --git a/ivy/container/linear_algebra.py b/ivy/container/linear_algebra.py
index 8e43b76c4df78..7449dae03f893 100644
--- a/ivy/container/linear_algebra.py
+++ b/ivy/container/linear_algebra.py
@@ -808,7 +808,7 @@ def static_matrix_norm(
         /,
         *,
         ord: Optional[Union[int, float, Literal[inf, -inf, "fro", "nuc"]]] = "fro",
-        axis: Optional[Union[int, Sequence[int]]] = None,
+        axis: Optional[Sequence[int]] = (-2, -1),
         keepdims: bool = False,
         key_chains: Optional[Union[List[str], Dict[str, str]]] = None,
         to_apply: bool = True,
@@ -870,7 +870,7 @@ def matrix_norm(
         /,
         *,
         ord: Optional[Union[int, float, Literal[inf, -inf, "fro", "nuc"]]] = "fro",
-        axis: Optional[Union[int, Sequence[int]]] = None,
+        axis: Optional[Sequence[int]] = (-2, -1),
         keepdims: bool = False,
         key_chains: Optional[Union[List[str], Dict[str, str]]] = None,
         to_apply: bool = True,
diff --git a/ivy/func_wrapper.py b/ivy/func_wrapper.py
index e1feecd8bbf79..69c70ad267c93 100644
--- a/ivy/func_wrapper.py
+++ b/ivy/func_wrapper.py
@@ -426,6 +426,7 @@ def _wrap_function(key: str, to_wrap: Callable, original: Callable) -> Callable:
             if (
                 isinstance(linalg_v, FunctionType)
                 and linalg_k != "namedtuple"
+                and linalg_k != "check_type"
                 and linalg_k != "with_unsupported_dtypes"
                 and not linalg_k.startswith("_")
             ):
diff --git a/ivy/functional/backends/jax/linear_algebra.py b/ivy/functional/backends/jax/linear_algebra.py
index e130c2b9b1afb..30829984d8187 100644
--- a/ivy/functional/backends/jax/linear_algebra.py
+++ b/ivy/functional/backends/jax/linear_algebra.py
@@ -1,6 +1,7 @@
 # global
 from collections import namedtuple
 from typing import Union, Optional, Tuple, Literal, Sequence, NamedTuple
+from typeguard import check_type
 
 import jax.numpy as jnp
 
@@ -166,11 +167,12 @@ def matrix_norm(
     /,
     *,
     ord: Optional[Union[int, float, Literal[inf, -inf, "fro", "nuc"]]] = "fro",
-    axis: Optional[Union[int, Sequence[int]]] = (-2, -1),
+    axis: Optional[Sequence[int]] = (-2, -1),
     keepdims: bool = False,
     out: Optional[JaxArray] = None,
 ) -> JaxArray:
-    if not isinstance(axis, tuple) and axis:
+    check_type("axis", axis, Sequence[int])
+    if not isinstance(axis, tuple):
         axis = tuple(axis)
     return jnp.linalg.norm(x, ord=ord, axis=axis, keepdims=keepdims)
 
diff --git a/ivy/functional/backends/numpy/linear_algebra.py b/ivy/functional/backends/numpy/linear_algebra.py
index 678d85b5117b8..bd61e009826c9 100644
--- a/ivy/functional/backends/numpy/linear_algebra.py
+++ b/ivy/functional/backends/numpy/linear_algebra.py
@@ -3,6 +3,7 @@
 from collections import namedtuple
 
 from typing import Union, Optional, Tuple, Literal, List, NamedTuple, Sequence
+from typeguard import check_type
 
 
 import numpy as np
@@ -159,11 +160,12 @@ def matrix_norm(
     /,
     *,
     ord: Optional[Union[int, float, Literal[inf, -inf, "fro", "nuc"]]] = "fro",
-    axis: Optional[Union[int, Sequence[int]]] = (-2, -1),
+    axis: Optional[Sequence[int]] = (-2, -1),
     keepdims: bool = False,
     out: Optional[np.ndarray] = None,
 ) -> np.ndarray:
-    if not isinstance(axis, tuple) and axis:
+    check_type("axis", axis, Sequence[int])
+    if not isinstance(axis, tuple):
         axis = tuple(axis)
     return np.linalg.norm(x, ord=ord, axis=axis, keepdims=keepdims)
 
diff --git a/ivy/functional/backends/tensorflow/linear_algebra.py b/ivy/functional/backends/tensorflow/linear_algebra.py
index 4a9e7f1a714cf..cd66260988af6 100644
--- a/ivy/functional/backends/tensorflow/linear_algebra.py
+++ b/ivy/functional/backends/tensorflow/linear_algebra.py
@@ -2,6 +2,7 @@
 
 from typing import Union, Optional, Tuple, Literal, List, NamedTuple, Sequence
 from collections import namedtuple
+from typeguard import check_type
 
 
 import tensorflow as tf
@@ -269,10 +270,11 @@ def matrix_norm(
     /,
     *,
     ord: Optional[Union[int, float, Literal[inf, -inf, "fro", "nuc"]]] = "fro",
-    axis: Optional[Union[int, Sequence[int]]] = (-2, -1),
+    axis: Optional[Sequence[int]] = (-2, -1),
     keepdims: bool = False,
     out: Optional[Union[tf.Tensor, tf.Variable]] = None,
 ) -> Union[tf.Tensor, tf.Variable]:
+    check_type("axis", axis, Sequence[int])
     if ord == -float("inf"):
         reduce_min = tf.reduce_min(
             tf.reduce_sum(tf.abs(x), axis=axis[1], keepdims=True), axis=axis
diff --git a/ivy/functional/backends/torch/linear_algebra.py b/ivy/functional/backends/torch/linear_algebra.py
index 179d0a8373811..7ca2d8d076934 100644
--- a/ivy/functional/backends/torch/linear_algebra.py
+++ b/ivy/functional/backends/torch/linear_algebra.py
@@ -4,6 +4,7 @@
 from typing import Union, Optional, Tuple, Literal, List, NamedTuple, Sequence
 
 from collections import namedtuple
+from typeguard import check_type
 
 
 # local
@@ -197,10 +198,11 @@ def matrix_norm(
     /,
     *,
     ord: Optional[Union[int, float, Literal[inf, -inf, "fro", "nuc"]]] = "fro",
-    axis: Optional[Union[int, Sequence[int]]] = (-2, -1),
+    axis: Optional[Sequence[int]] = (-2, -1),
     keepdims: bool = False,
     out: Optional[torch.Tensor] = None,
 ) -> torch.Tensor:
+    check_type("axis", axis, Sequence[int])
     if isinstance(ord, float):
         ord = int(ord)
     return torch.linalg.matrix_norm(x, ord=ord, dim=axis, keepdim=keepdims, out=out)
diff --git a/ivy/functional/ivy/linear_algebra.py b/ivy/functional/ivy/linear_algebra.py
index 338181e9257b4..f4b272cd5bc25 100644
--- a/ivy/functional/ivy/linear_algebra.py
+++ b/ivy/functional/ivy/linear_algebra.py
@@ -933,7 +933,7 @@ def matrix_norm(
     /,
     *,
     ord: Optional[Union[int, float, Literal[inf, -inf, "fro", "nuc"]]] = "fro",
-    axis: Optional[Union[int, Sequence[int]]] = None,
+    axis: Optional[Sequence[int]] = (-2, -1),
     keepdims: bool = False,
     out: Optional[ivy.Array] = None,
 ) -> ivy.Array:


Code review comments:
diff_hunk: @@ -808,7 +808,7 @@ def static_matrix_norm(
         /,
         *,
         ord: Optional[Union[int, float, Literal[inf, -inf, "fro", "nuc"]]] = "fro",
-        axis: Optional[Union[int, Sequence[int]]] = None,
+        axis: Optional[Sequence[int]] = (-2, -1),
path: ivy/container/linear_algebra.py
text: @user1:
here

diff_hunk: @@ -269,10 +270,11 @@ def matrix_norm(
     /,
     *,
     ord: Optional[Union[int, float, Literal[inf, -inf, "fro", "nuc"]]] = "fro",
-    axis: Optional[Union[int, Sequence[int]]] = (-2, -1),
+    axis: Optional[Sequence[int]] = (-2, -1),
path: ivy/functional/backends/tensorflow/linear_algebra.py
text: @user1:
here

diff_hunk: @@ -197,10 +198,11 @@ def matrix_norm(
     /,
     *,
     ord: Optional[Union[int, float, Literal[inf, -inf, "fro", "nuc"]]] = "fro",
-    axis: Optional[Union[int, Sequence[int]]] = (-2, -1),
+    axis: Optional[Sequence[int]] = (-2, -1),
path: ivy/functional/backends/torch/linear_algebra.py
text: @user1:
here

diff_hunk: @@ -933,7 +933,7 @@ def matrix_norm(
     /,
     *,
     ord: Optional[Union[int, float, Literal[inf, -inf, "fro", "nuc"]]] = "fro",
-    axis: Optional[Union[int, Sequence[int]]] = None,
+    axis: Optional[Sequence[int]] = (-2, -1),
path: ivy/functional/ivy/linear_algebra.py
text: @user1:
here

diff_hunk: @@ -166,11 +167,12 @@ def matrix_norm(
     /,
     *,
     ord: Optional[Union[int, float, Literal[inf, -inf, "fro", "nuc"]]] = "fro",
-    axis: Optional[Union[int, Sequence[int]]] = (-2, -1),
+    axis: Optional[Sequence[int]] = (-2, -1),
path: ivy/functional/backends/jax/linear_algebra.py
text: @user1:
here

diff_hunk: @@ -159,11 +160,12 @@ def matrix_norm(
     /,
     *,
     ord: Optional[Union[int, float, Literal[inf, -inf, "fro", "nuc"]]] = "fro",
-    axis: Optional[Union[int, Sequence[int]]] = (-2, -1),
+    axis: Optional[Sequence[int]] = (-2, -1),
path: ivy/functional/backends/numpy/linear_algebra.py
text: @user1:
here

diff_hunk: @@ -870,7 +870,7 @@ def matrix_norm(
         /,
         *,
         ord: Optional[Union[int, float, Literal[inf, -inf, "fro", "nuc"]]] = "fro",
-        axis: Optional[Union[int, Sequence[int]]] = None,
+        axis: Optional[Sequence[int]] = (-2, -1),
path: ivy/container/linear_algebra.py
text: @user1:
here

diff_hunk: @@ -185,7 +185,7 @@ def matrix_norm(
         /,
         *,
         ord: Optional[Union[int, float, Literal[inf, -inf, "fro", "nuc"]]] = "fro",
-        axis: Optional[Union[int, Sequence[int]]] = None,
+        axis: Optional[Sequence[int]] = (-2, -1),
path: ivy/array/linear_algebra.py
text: @user1:
axis: Optional[Tuple[int,int]] = (-2, -1) 
else would remain the same.