Skip to content

Commit

Permalink
added conj elementwise function to ivy experimental API (ivy-llc#9958)
Browse files Browse the repository at this point in the history
Co-authored-by: Felix Hirwa Nshuti <[email protected]>
  • Loading branch information
Giac3 and fnhirwa authored Feb 24, 2023
1 parent a32ef02 commit 5bbf8fb
Show file tree
Hide file tree
Showing 8 changed files with 277 additions and 3 deletions.
28 changes: 28 additions & 0 deletions ivy/array/experimental/elementwise.py
Original file line number Diff line number Diff line change
Expand Up @@ -1164,3 +1164,31 @@ def binarizer(
Binarized output data
"""
return ivy.binarizer(self._data, threshold=threshold, out=out)

def conj(self: ivy.Array, /, *, out: Optional[ivy.Array] = None) -> ivy.Array:
"""
ivy.Array instance method variant of ivy.conj. This method simply wraps
the function, and so the docstring for ivy.conj also applies to this
method with minimal changes.
Parameters
----------
self
input array.
out
optional output array, for writing the result to.
It must have a shape that the inputs broadcast to.
Returns
-------
ret
an array containing the complex conjugates of values in the input array,
with the same dtype as the input array.
Examples
--------
>>> x = ivy.array([4+3j, 6+2j, 1-6j])
>>> x.conj()
ivy.array([4-3j, 6-2j, 1+6j])
"""
return ivy.conj(self._data, out=out)
129 changes: 126 additions & 3 deletions ivy/container/experimental/elementwise.py
Original file line number Diff line number Diff line change
Expand Up @@ -3139,7 +3139,6 @@ def static_binarizer(
Maps the values of the input tensor to either 0 or 1,
element-wise, based on the outcome of a comparison
against a threshold value.
Parameters
----------
self
Expand Down Expand Up @@ -3190,7 +3189,6 @@ def binarizer(
Maps the values of the input tensor to either 0 or 1,
element-wise, based on the outcome of a comparison
against a threshold value.
Parameters
----------
threshold
Expand All @@ -3210,7 +3208,6 @@ def binarizer(
out
optional output container, for writing the result to. It must have a shape
that the inputs broadcast to.
Returns
-------
ret
Expand All @@ -3225,3 +3222,129 @@ def binarizer(
map_sequences=map_sequences,
out=out,
)

@staticmethod
def static_conj(
x: Union[ivy.Container, ivy.Array, ivy.NativeArray],
/,
*,
key_chains: Optional[Union[List[str], Dict[str, str]]] = None,
to_apply: bool = True,
prune_unapplied: bool = False,
map_sequences: bool = False,
out: Optional[ivy.Container] = None,
) -> ivy.Container:
"""
ivy.Container static method variant of ivy.conj.
This method simply wraps the function, and so the docstring for
ivy.conj also applies to this method with minimal changes.
Parameters
----------
x
input container.
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 container, for writing the result to. It must have a shape
that the inputs broadcast to.
Returns
-------
ret
a container containing output array(s) of the same
dtype as the input array(s) with the complex conjugates of
the complex values present in the input array. If x is a
container of scalar(s) then a container of scalar(s)
will be returned.
Examples
--------
>>> x = ivy.Container(a=ivy.array([-1+5j, 0-0j, 1.23j]),
... b=ivy.array([7.9, 0.31+3.3j, -4.2-5.9j]))
>>> z = ivy.Container.static_conj(x)
>>> print(z)
{
a: ivy.array([-1-5j, 0+0j, -1.23j]),
b: ivy.array([7.9, 0.31-3.3j, -4.2+5.9j])
}
"""
return ContainerBase.cont_multi_map_in_function(
"conj",
x,
key_chains=key_chains,
to_apply=to_apply,
prune_unapplied=prune_unapplied,
map_sequences=map_sequences,
out=out,
)

def conj(
self: ivy.Container,
*,
key_chains: Optional[Union[List[str], Dict[str, str]]] = None,
to_apply: bool = True,
prune_unapplied: bool = False,
map_sequences: bool = False,
out: Optional[ivy.Container] = None,
) -> ivy.Container:
"""
ivy.Container instance method variant of ivy.conj.
This method simply wraps the function, and so the docstring
for ivy.conj also applies to this method with minimal changes.
Parameters
----------
self
input container.
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 container, for writing the result to. It must have a shape
that the inputs broadcast to.
Returns
-------
ret
a container containing output array(s) of the same dtype
as the input array(s) with the complex conjugates of the
complex values present in the input array.
If x is a container of scalar(s) then a container of
scalar(s) will be returned.
Examples
--------
>>> x = ivy.Container(a=ivy.array([-1j, 0.335+2.345j, 1.23+7j]),\
b=ivy.array([0.0, 1.2+3.3j, 1+0j]))
>>> x.conj()
{
a: ivy.array([1j, 0.335-2345j, 1.23-7j]),
b: ivy.array([0.0, 1.2-3.3j, 1-0j])
}
"""
return self.static_conj(
self,
key_chains=key_chains,
to_apply=to_apply,
prune_unapplied=prune_unapplied,
map_sequences=map_sequences,
out=out,
)
9 changes: 9 additions & 0 deletions ivy/functional/backends/jax/experimental/elementwise.py
Original file line number Diff line number Diff line change
Expand Up @@ -524,3 +524,12 @@ def xlogy(x: JaxArray, y: JaxArray, /, *, out: Optional[JaxArray] = None) -> Jax

def real(x: JaxArray, /, *, out: Optional[JaxArray] = None) -> JaxArray:
return jnp.real(x)


def conj(
x: Union[JaxArray],
/,
*,
out: Optional[JaxArray] = None,
) -> JaxArray:
return jnp.conj(x)
9 changes: 9 additions & 0 deletions ivy/functional/backends/numpy/experimental/elementwise.py
Original file line number Diff line number Diff line change
Expand Up @@ -429,3 +429,12 @@ def xlogy(

def real(x: np.ndarray, /, *, out: Optional[np.ndarray] = None) -> np.ndarray:
return np.real(x)


def conj(
x: Union[np.ndarray],
/,
*,
out: Optional[np.ndarray] = None,
) -> np.ndarray:
return np.conj(x, out=out)
Original file line number Diff line number Diff line change
Expand Up @@ -613,3 +613,12 @@ def real(
out: Optional[Union[tf.Tensor, tf.Variable]] = None,
) -> Union[tf.Tensor, tf.Variable]:
return tf.math.real(x)


def conj(
x: Union[tf.Tensor, tf.Variable],
/,
*,
out: Optional[Union[tf.Tensor, tf.Variable]] = None,
) -> Union[tf.Tensor, tf.Variable]:
return tf.math.conj(x)
10 changes: 10 additions & 0 deletions ivy/functional/backends/torch/experimental/elementwise.py
Original file line number Diff line number Diff line change
Expand Up @@ -436,3 +436,13 @@ def xlogy(

def real(x: torch.Tensor, /, *, out: Optional[torch.Tensor] = None) -> torch.Tensor:
return torch.real(x)


def conj(
x: Union[torch.Tensor],
/,
*,
out: Optional[torch.Tensor] = None,
) -> torch.Tensor:
conj_x = torch.conj(x)
return torch.resolve_conj(input=conj_x)
56 changes: 56 additions & 0 deletions ivy/functional/ivy/experimental/elementwise.py
Original file line number Diff line number Diff line change
Expand Up @@ -1358,3 +1358,59 @@ def binarizer(
xc = ivy.copy_array(x, out=out)
bin = ivy.where(xc > threshold, 1, 0)
return bin


@to_native_arrays_and_back
@handle_out_argument
@handle_nestable
@handle_exceptions
@handle_array_like_without_promotion
def conj(
x: Union[ivy.Array, ivy.NativeArray],
/,
*,
out: Optional[ivy.Array] = None,
) -> ivy.Array:
"""Computes the complex conjugate of complex values in x
Parameters
----------
x
input array.
out
optional output array, for writing the result to.
It must have a shape that the inputs broadcast to.
Returns
-------
ret
an arrray of the same dtype as the input array with
the complex conjugates of the complex values present
in the input array. If x is a scalar then a scalar
will be returned.
The descriptions above assume an array input for simplicity, but
the method also accepts :class:`ivy.Container` instances
in place of: class:`ivy.Array` or :class:`ivy.NativeArray`
instances, as shown in the type hints and also the examples below.
Examples
--------
With :class:`ivy.Array` inputs:
>>> x = ivy.array([4.2-0j, 3j, 7+5j])
>>> z = ivy.conj(x)
>>> print(z)
ivy.array([4.2+0j, -3j, 7+5j])
With :class:`ivy.Container` input:
>>> x = ivy.Container(a=ivy.array([-6.7-7j, 0.314+0.355j, 1.23]),\
b=ivy.array([5j, 5.32-6.55j, 3.001]))
>>> z = ivy.conj(x)
>>> print(z)
{
a: ivy.array([-6.7+7j, 0.314-0.355j, 1.23]),
b: ivy.array([-5j, 5.32+6.55j, 3.001])
}
"""
return ivy.current_backend(x).conj(x, out=out)
Original file line number Diff line number Diff line change
Expand Up @@ -1125,3 +1125,33 @@ def test_binarizer(
x=x[0],
threshold=threshold,
)


# conj
@handle_test(
fn_tree="conj",
dtype_and_x=helpers.dtype_and_values(
available_dtypes=helpers.get_dtypes("real_and_complex")
),
test_with_out=st.just(False),
)
def test_conj(
*,
dtype_and_x,
test_flags,
backend_fw,
fn_name,
on_device,
ground_truth_backend,
):

input_dtype, x = dtype_and_x
helpers.test_function(
ground_truth_backend=ground_truth_backend,
input_dtypes=input_dtype,
test_flags=test_flags,
fw=backend_fw,
fn_name=fn_name,
on_device=on_device,
x=x[0],
)

0 comments on commit 5bbf8fb

Please sign in to comment.