# `ExTorch.Tensor`

An ``ExTorch.Tensor`` is a multi-dimensional matrix containing elements of a single data type.

# `cuda_device_count`

```elixir
@spec cuda_device_count() :: integer()
```

Get the number of available CUDA devices.

# `cuda_is_available`

```elixir
@spec cuda_is_available() :: boolean()
```

Check if CUDA is available.

# `cuda_max_memory_allocated`

```elixir
@spec cuda_max_memory_allocated(integer()) :: integer()
```

Get peak allocated CUDA memory in bytes for a device.
Returns -1 if CUDA is not available.

# `cuda_memory_allocated`

```elixir
@spec cuda_memory_allocated(integer()) :: integer()
```

Get currently allocated CUDA memory in bytes for a device.
Returns -1 if CUDA is not available.

# `cuda_memory_reserved`

```elixir
@spec cuda_memory_reserved(integer()) :: integer()
```

Get currently reserved CUDA memory in bytes for a device.
Returns -1 if CUDA is not available.

# `data_ptr`

```elixir
@spec data_ptr(t()) :: integer()
```

Get the raw data pointer of a tensor as an integer.

This is intended for zero-copy tensor exchange with other frameworks
(e.g., Nx/Torchx) that share the same process address space.

The returned pointer is only valid as long as the source tensor is alive.

# `device`

```elixir
@spec device(t()) :: ExTorch.Device.device()
```

Get the device of a tensor.

## Arguments
  - tensor (`ExTorch.Tensor`): Input tensor

# `dim`

```elixir
@spec dim(t()) :: integer()
```

Get the total dimensions of a tensor.

## Arguments
  - `tensor`: Input tensor

# `dtype`

```elixir
@spec dtype(t()) :: ExTorch.DType.dtype()
```

Get the dtype of a tensor.

## Arguments
  - tensor (`ExTorch.Tensor`): Input tensor

# `element_size`

```elixir
@spec element_size(t()) :: integer()
```

Get the element size in bytes for the tensor's dtype.

# `from_binary`

```elixir
@spec from_binary(binary(), tuple()) :: t()
```

See `ExTorch.Tensor.from_binary/3`

Available signature calls:

* `from_binary(data, shape)`

# `from_binary`

```elixir
@spec from_binary(binary(), tuple(), ExTorch.DType.dtype()) :: t()
@spec from_binary(binary(), tuple(), [{:dtype, ExTorch.DType.dtype()}]) :: t()
```

Create a tensor from raw binary data.

Copies the binary data into libtorch-managed memory. This is safe to use
with Erlang binaries since the data is copied immediately.

## Args
  - `data` - Raw binary data.
  - `shape` - Tensor dimensions as a tuple.
  - `dtype` - Data type of the elements.

# `from_blob`

```elixir
@spec from_blob(
  integer(),
  tuple(),
  tuple()
) :: t()
```

See `ExTorch.Tensor.from_blob/5`

Available signature calls:

* `from_blob(ptr, shape, blob_strides)`

# `from_blob`

```elixir
@spec from_blob(
  integer(),
  tuple(),
  tuple(),
  ExTorch.DType.dtype()
) :: t()
@spec from_blob(
  integer(),
  tuple(),
  tuple(),
  dtype: ExTorch.DType.dtype(),
  device: ExTorch.Device.device()
) :: t()
```

See `ExTorch.Tensor.from_blob/5`

Available signature calls:

* `from_blob(ptr, shape, blob_strides, kwargs)`
* `from_blob(ptr, shape, blob_strides, dtype)`

# `from_blob`

```elixir
@spec from_blob(
  integer(),
  tuple(),
  tuple(),
  ExTorch.DType.dtype(),
  ExTorch.Device.device()
) :: t()
@spec from_blob(
  integer(),
  tuple(),
  tuple(),
  ExTorch.DType.dtype(),
  [{:device, ExTorch.Device.device()}]
) :: t()
```

Create a tensor from a raw data pointer (zero-copy).

The created tensor shares the memory pointed to by `ptr`. The caller
**must** keep the source data alive for the lifetime of the returned tensor.

## Arguments
  - `ptr` - Raw memory address as an integer.
  - `shape` - Tensor dimensions as a tuple.
  - `strides` - Stride in each dimension as a tuple.
  - `dtype` - Data type of the elements.
  - `device` - Device where the memory lives (default: `:cpu`).

# `is_complex`

```elixir
@spec is_complex(t()) :: boolean()
```

Returns `true` if the datatype of `input` is a complex data type. i.e., one
of `:complex64` or `:complex128`

## Arguments
  - `tensor` (`ExTorch.Tensor`): Input tensor.

## Examples
    # Complex tensors yield true
    iex> a = ExTorch.rand({2, 2}, dtype: :complex64)
    iex> ExTorch.Tensor.is_complex(a)
    true

    # Non-complex tensors yield false
    iex> b = ExTorch.randint(3, {2, 2}, dtype: :int32)
    iex> ExTorch.Tensor.is_complex(b)
    false

# `is_conj`

```elixir
@spec is_conj(t()) :: boolean()
```

Returns `true` if `input` is a conjugated tensor. i.e., its conjugate bit is
set to `true`.

## Arguments
  - `tensor` (`ExTorch.Tensor`): Input tensor.

## Examples
    # Complex tensors have the conj bit set to false by default
    iex> a = ExTorch.rand({3, 4}, dtype: :complex64)
    iex> ExTorch.Tensor.is_conj(a)
    false

    # Conjugated tensor views have the conj bit set to true
    iex> b = ExTorch.conj(a)
    iex> ExTorch.Tensor.is_conj(b)
    true

    # Materialized conjugate tensors have the conj bit set to false
    iex> c = ExTorch.resolve_conj(b)
    iex> ExTorch.Tensor.is_conj(c)
    false

# `is_contiguous`

```elixir
@spec is_contiguous(t()) :: boolean()
```

Check if a tensor is contiguous in memory.

# `is_floating_point`

```elixir
@spec is_floating_point(t()) :: boolean()
```

Returns `true` if the datatype of `input` is a floating data type. i.e., one
of `:float16`, `:float32`, `:float64` or `:bfloat16`.

## Arguments
  - `tensor` (`ExTorch.Tensor`): Input tensor.

## Examples
    # Floating-type tensors yield true
    iex> a = ExTorch.rand({2, 2}, dtype: :float16)
    iex> ExTorch.Tensor.is_floating_point(a)
    true

    # Other type of tensors yield false
    iex> b = ExTorch.rand({2, 2}, dtype: :complex128)
    iex> ExTorch.Tensor.is_floating_point(b)
    false

# `is_nonzero`

```elixir
@spec is_nonzero(t()) :: boolean()
```

Returns `true` if the input is a single element tensor which is not equal to
zero after type conversions.

## Arguments
  - `tensor` (`ExTorch.Tensor`): Input tensor.

## Examples
    iex> ExTorch.Tensor.is_nonzero(ExTorch.tensor([0.0]))
    false
    iex> ExTorch.Tensor.is_nonzero(ExTorch.tensor([1.5]))
    true
    iex> ExTorch.Tensor.is_nonzero(ExTorch.tensor([false]))
    false
    iex> ExTorch.Tensor.is_nonzero(ExTorch.tensor([3]))
    true
    iex> ExTorch.Tensor.is_nonzero(ExTorch.tensor([1, 2, 3]))
    ** (ErlangError) Erlang error: "Boolean value of Tensor with more than one value is ambiguous"
        (extorch 0.1.0-pre0) ExTorch.Native.is_nonzero(#Tensor<
    [1, 2, 3]
    [size: {3}, dtype: :byte, device: :cpu, requires_grad: false]>)

# `item`

```elixir
@spec item(t()) :: ExTorch.Scalar.t()
```

Returns the value of this tensor as a standard Elixir value.

This only works for tensors with one element. For other cases, see `ExTorch.Tensor.to_list/1`.

## Arguments
  - `tensor` (`ExTorch.Tensor`): Input tensor.

## Examples
    iex> x = ExTorch.tensor([false])
    iex> ExTorch.Tensor.item(x)
    false

    iex> x = ExTorch.tensor([-3.5])
    iex> ExTorch.Tensor.item(x)
    -3.5

    iex> x = ExTorch.tensor([ExTorch.Complex.complex(-2, 1)])
    iex> ExTorch.Tensor.item(x)
    -2.0 + 1.0j

    iex> x = ExTorch.tensor([:nan])
    iex> ExTorch.Tensor.item(x)
    :nan

# `layout`

```elixir
@spec layout(t()) :: ExTorch.Layout.layout()
```

Get the `layout` of a tensor.

## Arguments
  - tensor (`ExTorch.Tensor`): Input tensor

# `memory_format`

```elixir
@spec memory_format(t()) :: ExTorch.MemoryFormat.memory_format()
```

Get the `memory_format` of a tensor.

## Arguments
  - tensor (`ExTorch.Tensor`): Input tensor

# `ndim`

```elixir
@spec ndim(t()) :: integer()
```

Alias to `dim/1`

# `ndimension`

```elixir
@spec ndimension(t()) :: integer()
```

Alias to `dim/1`

# `numel`

```elixir
@spec numel(t()) :: integer()
```

Returns the total number of elements in the input tensor.

## Arguments
  - `tensor` (`ExTorch.Tensor`): Input tensor.

## Examples
    iex> x = ExTorch.empty({3, 4, 5})
    iex> ExTorch.Tensor.numel(x)
    60

# `repr`

```elixir
@spec repr(t()) :: binary()
```

See `ExTorch.Tensor.repr/2`

Available signature calls:

* `repr(tensor)`

# `repr`

```elixir
@spec repr(t(),
  edgeitems: integer(),
  linewidth: integer(),
  precision: integer(),
  sci_mode: boolean() | nil,
  threshold: float()
) :: binary()
@spec repr(t(), ExTorch.Utils.PrintOptions.t()) :: binary()
```

Get a human readable representation of a tensor.

## Arguments
  - tensor (`ExTorch.Tensor`): Input tensor

## Keyword args
- `precision`: Number of digits of precision for floating point output. Default: 4

- `threshold`: Total number of array elements which trigger summarization
rather than full `repr`. Default: 1000.

- `edgeitems`: Number of array items in summary at beginning and end of
each dimension. Default: 3.

- `linewidth`: The number of characters per line for the purpose of
  inserting line breaks (default = 80). Thresholded matrices will
  ignore this parameter.

- `sci_mode`: Enable (`true`) or disable (`false`) scientific notation. If
  `nil` (default) is specified, the value is defined by
  the formatter. This value is automatically chosen by the framework.

# `requires_grad`

```elixir
@spec requires_grad(t()) :: boolean()
```

Get the `requires_grad` status of a tensor.

## Arguments
  - tensor (`ExTorch.Tensor`): Input tensor

# `size`

```elixir
@spec size(t()) :: tuple()
```

Get the size of a tensor.

## Arguments
  - `tensor`: Input tensor

# `strides`

```elixir
@spec strides(t()) :: [integer()]
```

Get the strides of a tensor.

Returns a list of integers representing the step size in each dimension.

# `to`

```elixir
@spec to(t()) :: t()
```

See `ExTorch.Tensor.to/6`

Available signature calls:

* `to(input)`

# `to`

```elixir
@spec to(
  t(),
  ExTorch.DType.dtype() | nil
) :: t()
@spec to(t(),
  dtype: ExTorch.DType.dtype() | nil,
  device: ExTorch.Device.device() | nil,
  non_blocking: boolean(),
  copy: boolean(),
  memory_format: ExTorch.MemoryFormat.memory_format()
) :: t()
```

See `ExTorch.Tensor.to/6`

Available signature calls:

* `to(input, kwargs)`
* `to(input, dtype)`

# `to`

```elixir
@spec to(
  t(),
  ExTorch.DType.dtype() | nil,
  ExTorch.Device.device() | nil
) :: t()
@spec to(
  t(),
  ExTorch.DType.dtype() | nil,
  device: ExTorch.Device.device() | nil,
  non_blocking: boolean(),
  copy: boolean(),
  memory_format: ExTorch.MemoryFormat.memory_format()
) :: t()
```

See `ExTorch.Tensor.to/6`

Available signature calls:

* `to(input, dtype, kwargs)`
* `to(input, dtype, device)`

# `to`

```elixir
@spec to(
  t(),
  ExTorch.DType.dtype() | nil,
  ExTorch.Device.device() | nil,
  non_blocking: boolean(),
  copy: boolean(),
  memory_format: ExTorch.MemoryFormat.memory_format()
) :: t()
@spec to(
  t(),
  ExTorch.DType.dtype() | nil,
  ExTorch.Device.device() | nil,
  boolean()
) :: t()
```

See `ExTorch.Tensor.to/6`

Available signature calls:

* `to(input, dtype, device, non_blocking)`
* `to(input, dtype, device, kwargs)`

# `to`

```elixir
@spec to(
  t(),
  ExTorch.DType.dtype() | nil,
  ExTorch.Device.device() | nil,
  boolean(),
  boolean()
) :: t()
@spec to(
  t(),
  ExTorch.DType.dtype() | nil,
  ExTorch.Device.device() | nil,
  boolean(),
  copy: boolean(),
  memory_format: ExTorch.MemoryFormat.memory_format()
) :: t()
```

See `ExTorch.Tensor.to/6`

Available signature calls:

* `to(input, dtype, device, non_blocking, kwargs)`
* `to(input, dtype, device, non_blocking, copy)`

# `to`

```elixir
@spec to(
  t(),
  ExTorch.DType.dtype() | nil,
  ExTorch.Device.device() | nil,
  boolean(),
  boolean(),
  [{:memory_format, ExTorch.MemoryFormat.memory_format()}]
) :: t()
@spec to(
  t(),
  ExTorch.DType.dtype() | nil,
  ExTorch.Device.device() | nil,
  boolean(),
  boolean(),
  ExTorch.MemoryFormat.memory_format()
) :: t()
```

Performs `ExTorch.Tensor` dtype and/or device conversion.

## Arguments
- `input` (`ExTorch.Tensor`) - the input tensor to convert.

## Optional arguments
- `dtype` (`ExTorch.DType` or `nil`) - the dtype to convert the `input`
tensor into. If `nil`, then it will be preserved from `input`. Default: `nil`.
 - `device` (`ExTorch.Device` or `nil`) - the device to move the `input`
tensor into. If `nil`, then it will be preserved from `input`. Default: `nil`.
- `non_blocking` (`boolean`) - when `true`, it tries to convert asynchronously
with respect to the host if possible, e.g., converting a CPU Tensor with
pinned memory to a CUDA Tensor. Default: `false`.
- `copy` (`boolean`) - If `true`, a new `ExTorch.Tensor` is created even when
`input` already matches the desired conversion. Default: `false`.
- `memory_format` (`ExTorch.MemoryFormat`) - the desired memory format of
the returned tensor. Default: `:preserve_format`.

## Notes
* If the `input` already has the correct `ExTorch.dtype` and `ExTorch.device`,
then `input` is returned. Otherwise, the returned tensor is a copy of `input` with
the desired `dtype` and `device`.
* Unlike PyTorch, `to` does not accept another tensor as parameter, please use
an explicit call to `to(input, dtype: other.dtype, device: other.device)` instead.

## Examples
    iex> a = ExTorch.randn({3, 3})
    #Tensor<
    [[ 0.5770, -0.8079, -0.4308],
     [-0.2186,  0.4031, -1.4976],
     [ 1.2380, -0.4259,  2.0745]]
    [
      size: {3, 3},
      dtype: :float,
      device: :cpu,
      requires_grad: false
    ]>

    # Change tensor dtype, preserving device
    iex> ExTorch.Tensor.to(a, dtype: :complex64)
    #Tensor<
    [[ 0.5770+0.j, -0.8079+0.j, -0.4308+0.j],
     [-0.2186+0.j,  0.4031+0.j, -1.4976+0.j],
     [ 1.2380+0.j, -0.4259+0.j,  2.0745+0.j]]
    [
      size: {3, 3},
      dtype: :complex_float,
      device: :cpu,
      requires_grad: false
    ]>

    # Change tensor device
    iex> ExTorch.Tensor.to(a, device: :cuda)
    #Tensor<
    [[ 0.5770, -0.8079, -0.4308],
     [-0.2186,  0.4031, -1.4976],
     [ 1.2380, -0.4259,  2.0745]]
    [
      size: {3, 3},
      dtype: :float,
      device: {:cuda, 0},
      requires_grad: false
    ]>

# `to_list`

```elixir
@spec to_list(t()) :: list()
```

Convert a tensor into a list.

## Arguments
  - tensor (`ExTorch.Tensor`): Input tensor

# `t`

```elixir
@type t() :: %ExTorch.Tensor{
  device: ExTorch.Device.device(),
  dtype: ExTorch.DType.dtype(),
  reference: reference(),
  resource: any(),
  size: tuple()
}
```

An ``ExTorch.Tensor`` is a multi-dimensional matrix containing elements of a single data type.

# `fetch`

```elixir
@spec fetch(t(), ExTorch.Index.t()) :: {:ok, t()}
```

Index a tensor using an accessor object. It acts as a alias for `ExTorch.index/2`.

# `scalar_to_tensor`

```elixir
@spec scalar_to_tensor(
  t() | ExTorch.Scalar.scalar_or_list(),
  ExTorch.Device.device()
) :: t()
```

Take a `ExTorch.Tensor` or `ExTorch.Scalar` definition and convert it into
a `ExTorch.Tensor`.

## Arguments
- `input` - the input to convert into an `ExTorch.Tensor`.
- `device` - an optional device to map the tensor into. This will only take effect
when `input` is one of any `ExTorch.Scalar` definitions. Default: `:cpu`

---

*Consult [api-reference.md](api-reference.md) for complete listing*
