Skip to content

Commit

Permalink
Merge branch 'unifyai:master' into dist
Browse files Browse the repository at this point in the history
  • Loading branch information
BigBalloon8 authored Aug 5, 2023
2 parents ea11bc1 + 2967685 commit 52cb03e
Show file tree
Hide file tree
Showing 35 changed files with 2,772 additions and 1,912 deletions.
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ docker/* @ricksanchezstoic
.idea/* @Aarsh2001 @zaeemansari70

# README
README.rst @guillesanbri
README.md @guillesanbri
1,655 changes: 1,655 additions & 0 deletions README.md

Large diffs are not rendered by default.

1,681 changes: 0 additions & 1,681 deletions README.rst

This file was deleted.

3 changes: 2 additions & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.. title:: Home

.. include:: ../README.rst
.. include:: ../README.md
:parser: myst_parser.sphinx_

.. toctree::
:hidden:
Expand Down
54 changes: 54 additions & 0 deletions ivy/data_classes/array/linear_algebra.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,60 @@ def inner(
*,
out: Optional[ivy.Array] = None,
) -> ivy.Array:
"""
Return the inner product of two vectors ``self`` and ``x2``.
Parameters
----------
self
first one-dimensional input array of size N.
Should have a numeric data type.
a(N,) array_like
First input vector. Input is flattened if not already 1-dimensional.
x2
second one-dimensional input array of size M.
Should have a numeric data type.
b(M,) array_like
Second input vector. Input is flattened if not already 1-dimensional.
out
optional output array, for writing the result to.
It must have a shape that the inputs broadcast to.
Returns
-------
ret
a two-dimensional array containing the inner product and whose
shape is (N, M).
The returned array must have a data type determined by Type Promotion Rules.
Examples
--------
Matrices of identical shapes
>>> x = ivy.array([[1., 2.], [3., 4.]])
>>> y = ivy.array([[5., 6.], [7., 8.]])
>>> d = x.inner(y)
>>> print(d)
ivy.array([[17., 23.], [39., 53.]])
Matrices of different shapes
>>> x = ivy.array([[1., 2.], [3., 4.],[5., 6.]])
>>> y = ivy.array([[5., 6.], [7., 8.]])
>>> d = x.inner(y)
>>> print(d)
ivy.array([[17., 23.], [39., 53.], [61., 83.]])
3D matrices
>>> x = ivy.array([[[1., 2.], [3., 4.]],
[[5., 6.], [7., 8.]]])
>>> y = ivy.array([[[9., 10.], [11., 12.]],
[[13., 14.], [15., 16.]]])
>>> d = x.inner(y)
>>> print(d)
ivy.array([[[[ 29., 35.], [ 41., 47.]],
[[ 67., 81.], [ 95., 109.]]],
[[[105., 127.], [149., 171.]],
[[143., 173.], [203., 233.]]]])
"""
return ivy.inner(self._data, x2, out=out)

def inv(
Expand Down
100 changes: 100 additions & 0 deletions ivy/data_classes/container/linear_algebra.py
Original file line number Diff line number Diff line change
Expand Up @@ -1005,6 +1005,57 @@ def _static_inner(
map_sequences: Union[bool, ivy.Container] = False,
out: Optional[ivy.Container] = None,
) -> ivy.Container:
"""
ivy.Container static method variant of ivy.inner. This method simply wraps the
function, and so the docstring for ivy.inner also applies to this method with
minimal changes.
Return the inner product of two vectors ``x1`` and ``x2``.
Parameters
----------
x1
first one-dimensional input array of size N.
Should have a numeric data type.
a(N,) array_like
First input vector. Input is flattened if not already 1-dimensional.
x2
second one-dimensional input array of size M.
Should have a numeric data type.
b(M,) array_like
Second input vector. Input is flattened if not already 1-dimensional.
key_chains
The key-chains to apply or not apply the method to. Default is ``None``.
to_apply
If True, the method will be applied to key_chains,
otherwise key_chains will be skipped. Default is ``True``.
prune_unapplied
Whether to prune key_chains for which the function was not applied.
Default is ``False``.
map_sequences
Whether to also map method to sequences (lists, tuples).
Default is ``False``.
out
optional output array, for writing the result to.
It must have a shape that the inputs broadcast to.
Returns
-------
ret
a two-dimensional array containing the inner product and whose
shape is (N, M).
The returned array must have a data type determined by Type Promotion Rules.
Examples
--------
>>> x1 = ivy.Container(a=ivy.array([[1, 2], [3, 4]]))
>>> x2 = ivy.Container(a=ivy.array([5, 6]))
>>> y = ivy.Container.static_inner(x1, x2)
>>> print(y)
{
a: ivy.array([17, 39])
}
"""
return ContainerBase.cont_multi_map_in_function(
"inner",
x1,
Expand All @@ -1027,6 +1078,55 @@ def inner(
map_sequences: Union[bool, ivy.Container] = False,
out: Optional[ivy.Container] = None,
) -> ivy.Container:
"""
ivy.Container instance method variant of ivy.inner. This method simply wraps the
function, and so the docstring for ivy.inner also applies to this method with
minimal changes.
Return the inner product of two vectors ``self`` and ``x2``.
Parameters
----------
self
input container of size N. Should have a numeric data type.
a(N,) array_like
First input vector. Input is flattened if not already 1-dimensional.
x2
one-dimensional input array of size M. Should have a numeric data type.
b(M,) array_like
Second input vector. Input is flattened if not already 1-dimensional.
key_chains
The key-chains to apply or not apply the method to. Default is ``None``.
to_apply
If True, the method will be applied to key_chains,
otherwise key_chains will be skipped. Default is ``True``.
prune_unapplied
Whether to prune key_chains for which the function was not applied.
Default is ``False``.
map_sequences
Whether to also map method to sequences (lists, tuples).
Default is ``False``.
out
optional output array, for writing the result to.
It must have a shape that the inputs broadcast to.
Returns
-------
ret
a new container representing the inner product and whose
shape is (N, M).
The returned array must have a data type determined by Type Promotion Rules.
Examples
--------
>>> x1 = ivy.Container(a=ivy.array([[1, 2], [3, 4]]))
>>> x2 = ivy.Container(a=ivy.array([5, 6]))
>>> y = ivy.Container.inner(x1, x2)
>>> print(y)
{
a: ivy.array([17, 39])
}
"""
return self._static_inner(
self,
x2,
Expand Down
5 changes: 2 additions & 3 deletions ivy/functional/backends/jax/experimental/statistical.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,8 @@ def quantile(
keepdims: bool = False,
out: Optional[JaxArray] = None,
) -> JaxArray:
if isinstance(axis, list):
axis = tuple(axis)

axis = tuple(axis) if isinstance(axis, list) else axis
interpolation = "nearest" if interpolation == "nearest_jax" else interpolation
return jnp.quantile(
a, q, axis=axis, method=interpolation, keepdims=keepdims, out=out
)
Expand Down
8 changes: 7 additions & 1 deletion ivy/functional/backends/jax/linear_algebra.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,13 @@ def eigvalsh(


@with_unsupported_dtypes({"0.4.14 and below": ("complex",)}, backend_version)
def inner(x1: JaxArray, x2: JaxArray, /, *, out: Optional[JaxArray] = None) -> JaxArray:
def inner(
x1: JaxArray,
x2: JaxArray,
/,
*,
out: Optional[JaxArray] = None
) -> JaxArray:
x1, x2 = ivy.promote_types_of_inputs(x1, x2)
return jnp.inner(x1, x2)

Expand Down
138 changes: 132 additions & 6 deletions ivy/functional/backends/numpy/experimental/statistical.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from ivy.func_wrapper import with_unsupported_dtypes
from . import backend_version
from ..statistical import _infer_dtype
from copy import deepcopy


@with_unsupported_dtypes(
Expand Down Expand Up @@ -166,6 +167,128 @@ def nanmean(
nanmean.support_native_out = True


def _validate_quantile(q):
if q.ndim == 1 and q.size < 10:
for i in range(q.size):
if not (0.0 <= q[i] <= 1.0):
return False
else:
if not (np.all(0 <= q) and np.all(q <= 1)):
return False
return True


def _to_positive_axis(axis, ndim):
if not isinstance(axis, (list, tuple)):
axis = [axis]

if len(axis) == 0:
raise ValueError("Axis can't be empty!")

if len(set(axis)) != len(axis):
raise ValueError("Duplicated axis!")

for i in range(len(axis)):
if not (isinstance(axis[i], int) and (ndim > axis[i] >= -ndim)):
raise ValueError("Axis must be int in range [-rank(x), rank(x))")
if axis[i] < 0:
axis[i] += ndim
return axis


def _handle_axis(a, q, fn, keepdims=False, axis=None):
nd = a.ndim
axis_arg = deepcopy(axis)
if axis is not None:
axis = _to_positive_axis(axis, nd)

if len(axis) == 1:
axis_arg = axis[0]
else:
keep = set(range(nd)) - set(axis)
nkeep = len(keep)

for i, s in enumerate(sorted(keep)):
a = np.moveaxis(a, s, i)
a = a.reshape(a.shape[:nkeep] + (-1,))
axis_arg = -1

ret = fn(a, q, axis=axis_arg)

if keepdims:
if axis is None:
index_ret = (None,) * nd
else:
index_ret = tuple(None if i in axis else slice(None) for i in range(nd))
ret = ret[(Ellipsis,) + index_ret]

return ret


def _quantile(a, q, axis=None):
ret_dtype = a.dtype
if q.ndim > 2:
raise ValueError("q argument must be a scalar or 1-dimensional!")
if axis is None:
axis = 0
a = a.flatten()

n = a.shape[axis]
if axis != 0:
a = np.moveaxis(a, axis, 0)

indices = []
for q_num in q:
index = q_num * (n - 1)
indices.append(index)

a.sort(0)
outputs = []

for index in indices:
indices_below = np.floor(index).astype(np.int32)
indices_upper = np.ceil(index).astype(np.int32)

weights = index - indices_below.astype("float64")

indices_below = np.clip(indices_below, 0, n - 1)
indices_upper = np.clip(indices_upper, 0, n - 1)
tensor_upper = np.take(a, indices_upper, axis=0) # , mode="clip")
tensor_below = np.take(a, indices_below, axis=0) # , mode="clip")

pred = weights <= 0.5
out = np.where(pred, tensor_below, tensor_upper)
outputs.append(out)
return np.array(outputs, dtype=ret_dtype)


def _compute_quantile_wrapper(
x, q, axis=None, keepdims=False, interpolation="linear", out=None
):
if not _validate_quantile(q):
raise ValueError("Quantiles must be in the range [0, 1]")
if interpolation in [
"linear",
"lower",
"higher",
"midpoint",
"nearest",
"nearest_jax",
]:
if interpolation == "nearest_jax":
return _handle_axis(x, q, _quantile, keepdims=keepdims, axis=axis)
else:
axis = tuple(axis) if isinstance(axis, list) else axis

return np.quantile(
x, q, axis=axis, method=interpolation, keepdims=keepdims, out=out
).astype(x.dtype)
else:
raise ValueError(
"Interpolation must be 'linear', 'lower', 'higher', 'midpoint' or 'nearest'"
)


def quantile(
a: np.ndarray,
q: Union[float, np.ndarray],
Expand All @@ -178,12 +301,15 @@ def quantile(
) -> np.ndarray:
# quantile method in numpy backend, always return an array with dtype=float64.
# in other backends, the output is the same dtype as the input.

(tuple(axis) if isinstance(axis, list) else axis)

return np.quantile(
a, q, axis=axis, method=interpolation, keepdims=keepdims, out=out
).astype(a.dtype)
# added the nearest_jax mode to enable jax-like calculations for method="nearest"
return _compute_quantile_wrapper(
a,
q,
axis=axis,
keepdims=keepdims,
interpolation=interpolation,
out=out,
)


def corrcoef(
Expand Down
6 changes: 5 additions & 1 deletion ivy/functional/backends/numpy/linear_algebra.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,11 @@ def eigvalsh(

@_scalar_output_to_0d_array
def inner(
x1: np.ndarray, x2: np.ndarray, /, *, out: Optional[np.ndarray] = None
x1: np.ndarray,
x2: np.ndarray,
/,
*,
out: Optional[np.ndarray] = None
) -> np.ndarray:
x1, x2 = ivy.promote_types_of_inputs(x1, x2)
return np.inner(x1, x2)
Expand Down
Loading

0 comments on commit 52cb03e

Please sign in to comment.