Skip to content

Commit

Permalink
add: frombuffer to ivy functional api
Browse files Browse the repository at this point in the history
  • Loading branch information
trantuantdt committed Apr 5, 2023
1 parent d42a654 commit e0be35b
Show file tree
Hide file tree
Showing 6 changed files with 270 additions and 0 deletions.
160 changes: 160 additions & 0 deletions ivy/container/creation.py
Original file line number Diff line number Diff line change
Expand Up @@ -1320,3 +1320,163 @@ def one_hot(
map_sequences=map_sequences,
out=out,
)

@staticmethod
def static_frombuffer(
buffer: ivy.Container,
dtype: Optional[Union[ivy.Dtype, ivy.NativeDtype]] = float,
count: Optional[int] = -1,
offset: Optional[int] = 0,
key_chains: Optional[Union[List[str], Dict[str, str]]] = None,
to_apply: bool = True,
prune_unapplied: bool = False,
map_sequences: bool = False,
) -> ivy.Container:
"""
ivy.Container static method variant of ivy.frombuffer. This method simply
wraps the function, and so the docstring for ivy.frombuffer also applies
to this method with minimal changes.
Parameters
----------
buffer
An object that exposes the buffer interface.
dtype
Data-type of the returned array; default: float.
count
Number of items to read. -1 means all data in the buffer.
offset
Start reading the buffer from this offset (in bytes); default: 0.
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``.
Returns
-------
out
1-dimensional array.
Examples
--------
With :class:`ivy.Container` inputs:
>>> x = ivy.Container(
... a = b'\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\x00@',
... b = b'\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\x00@'
... )
>>> y = ivy.Container.static_frombuffer(x)
>>> print(y)
{
a: ivy.array([1., 2.]),
b: ivy.array([2., 1., 2.])
}
>>> x = ivy.Container(
... a = b'\x01\x02\x03\x04',
... b = b'\x05\x04\x03\x03\x02'
... )
>>> y = ivy.Container.static_frombuffer(x, dtype=ivy.int8, count=3, offset=1)
>>> print(y)
{
a: ivy.array([2, 3, 4]),
b: ivy.array([4, 3, 3])
}
"""
return ContainerBase.cont_multi_map_in_function(
"frombuffer",
buffer,
dtype=dtype,
count=count,
offset=offset,
key_chains=key_chains,
to_apply=to_apply,
prune_unapplied=prune_unapplied,
map_sequences=map_sequences,
)

def frombuffer(
self: ivy.Container,
dtype: Optional[Union[ivy.Dtype, ivy.NativeDtype]] = float,
count: Optional[int] = -1,
offset: Optional[int] = 0,
key_chains: Optional[Union[List[str], Dict[str, str]]] = None,
to_apply: bool = True,
prune_unapplied: bool = False,
map_sequences: bool = False,
) -> ivy.Container:
"""
ivy.Container instance method variant of ivy.frombuffer. This method
simply wraps the function, and so the docstring for ivy.frombuffer
also applies to this method with minimal changes.
Parameters
----------
self
An object that exposes the buffer interface.
dtype
Data-type of the returned array; default: float.
count
Number of items to read. -1 means all data in the buffer.
offset
Start reading the buffer from this offset (in bytes); default: 0.
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``.
Returns
-------
out
1-dimensional array.
Examples
--------
With :class:`ivy.Container` inputs:
>>> x = ivy.Container(
... a = b'\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\x00@',
... b = b'\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\x00@'
... )
>>> y = ivy.frombuffer(x)
>>> print(y)
{
a: ivy.array([1., 2.]),
b: ivy.array([2., 1., 2.])
}
>>> x = ivy.Container(
... a = b'\x01\x02\x03\x04',
... b = b'\x05\x04\x03\x03\x02'
... )
>>> y = ivy.frombuffer(x, dtype=ivy.int8, count=3, offset=1)
>>> print(y)
{
a: ivy.array([2, 3, 4]),
b: ivy.array([4, 3, 3])
}
"""
return self.static_frombuffer(
self,
dtype=dtype,
count=count,
offset=offset,
key_chains=key_chains,
to_apply=to_apply,
prune_unapplied=prune_unapplied,
map_sequences=map_sequences,
)
9 changes: 9 additions & 0 deletions ivy/functional/backends/jax/creation.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,3 +340,12 @@ def one_hot(
res = jnp.moveaxis(res, -1, axis)

return _to_device(res, device)


def frombuffer(
buffer: bytes,
dtype: Optional[jnp.dtype] = float,
count: Optional[int] = -1,
offset: Optional[int] = 0,
) -> JaxArray:
return jnp.frombuffer(buffer, dtype=dtype, count=count, offset=offset)
12 changes: 12 additions & 0 deletions ivy/functional/backends/numpy/creation.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,3 +273,15 @@ def one_hot(
res = np.moveaxis(res, -1, axis)

return res


def frombuffer(
buffer: bytes,
dtype: Optional[np.dtype] = float,
count: Optional[int] = -1,
offset: Optional[int] = 0,
) -> np.ndarray:
if isinstance(dtype, list):
dtype = np.dtype(dtype[0])

return np.frombuffer(buffer, dtype=dtype, count=count, offset=offset)
19 changes: 19 additions & 0 deletions ivy/functional/backends/tensorflow/creation.py
Original file line number Diff line number Diff line change
Expand Up @@ -421,3 +421,22 @@ def one_hot(
return tf.one_hot(
indices, depth, on_value=on_value, off_value=off_value, axis=axis, dtype=dtype
)


@with_unsupported_dtypes({"1.11.0 and below": ("uint32", "uint64")}, backend_version)
def frombuffer(
buffer: bytes,
dtype: Optional[tf.DType] = float,
count: Optional[int] = -1,
offset: Optional[int] = 0,
) -> Union[tf.Tensor, tf.Variable]:
ret = tf.io.decode_raw(buffer, dtype)
dtype = tf.dtypes.as_dtype(dtype)
if offset > 0:
offset = int(offset / dtype.size)
if count > -1:
ret = ret[offset:offset + count]
else:
ret = ret[offset:]

return ret
11 changes: 11 additions & 0 deletions ivy/functional/backends/torch/creation.py
Original file line number Diff line number Diff line change
Expand Up @@ -611,3 +611,14 @@ def one_hot(
res = torch.moveaxis(res, -1, axis)

return res.to(device, dtype)


def frombuffer(
buffer: bytes,
dtype: Optional[torch.dtype] = float,
count: Optional[int] = -1,
offset: Optional[int] = 0,
) -> torch.Tensor:
dtype = ivy.as_native_dtype(dtype)

return torch.frombuffer(buffer, dtype=dtype, count=count, offset=offset)
59 changes: 59 additions & 0 deletions ivy/functional/ivy/creation.py
Original file line number Diff line number Diff line change
Expand Up @@ -1920,3 +1920,62 @@ def logspace(
device=device,
out=out,
)


@outputs_to_ivy_arrays
@handle_nestable
def frombuffer(
buffer: bytes,
dtype: Optional[Union[ivy.Dtype, ivy.NativeDtype]] = float,
count: Optional[int] = -1,
offset: Optional[int] = 0,
) -> ivy.Array:
"""
Interpret a buffer as a 1-dimensional array.
.. note::
Note that either of the following must be true:
1. count is a positive non-zero number, and the total number of bytes in the buffer is equal or greater than offset plus count times the size (in bytes) of dtype.
2. count is negative, and the length (number of bytes) of the buffer subtracted by the offset is a multiple of the size (in bytes) of dtype.
Parameters
----------
buffer
An object that exposes the buffer interface.
dtype
Data-type of the returned array; default: float.
count
Number of items to read. -1 means all data in the buffer.
offset
Start reading the buffer from this offset (in bytes); default: 0.
Returns
-------
out
1-dimensional array.
Examples
--------
With :class:`bytes` inputs:
>>> x = b'\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\x00@'
>>> y = ivy.frombuffer(x)
>>> print(y)
(ivy.array([1., 2.]))
>>> x = b'\x01\x02\x03\x04'
>>> y = ivy.frombuffer(x, dtype='int8', count=-2, offset=1)
>>> print(y)
(ivy.array([2, 3, 4]))
>>> x = b'\x00\x00\x80?\x00\x00\x00@\x00\x00@@\x00\x00\x80@\x00\x00\xa0@\x00\x00\xc0@'
>>> y = ivy.frombuffer(x, dtype='float32', count=4, offset=4)
>>> print(y)
(ivy.array([2., 3., 4., 5.]))
"""
return current_backend().frombuffer(
buffer,
dtype=dtype,
count=count,
offset=offset,
)

0 comments on commit e0be35b

Please sign in to comment.