| .. _complex_numbers-doc: | 
 |  | 
 | Complex Numbers | 
 | =============== | 
 |  | 
 | Complex numbers are numbers that can be expressed in the form :math:`a + bj`, where a and b are real numbers, | 
 | and *j* is called the imaginary unit, which satisfies the equation :math:`j^2 = -1`. Complex numbers frequently occur in mathematics and | 
 | engineering, especially in topics like signal processing. Traditionally many users and libraries (e.g., TorchAudio) have | 
 | handled complex numbers by representing the data in float tensors with shape :math:`(..., 2)` where the last | 
 | dimension contains the real and imaginary values. | 
 |  | 
 | Tensors of complex dtypes provide a more natural user experience while working with complex numbers. Operations on | 
 | complex tensors (e.g., :func:`torch.mv`, :func:`torch.matmul`) are likely to be faster and more memory efficient | 
 | than operations on float tensors mimicking them. Operations involving complex numbers in PyTorch are optimized | 
 | to use vectorized assembly instructions and specialized kernels (e.g. LAPACK, cuBlas). | 
 |  | 
 | .. note:: | 
 |      Spectral operations in the `torch.fft module <https://pytorch.org/docs/stable/fft.html#torch-fft>`_ support | 
 |      native complex tensors. | 
 |  | 
 | .. warning :: | 
 |      Complex tensors is a beta feature and subject to change. | 
 |  | 
 | Creating Complex Tensors | 
 | ------------------------ | 
 |  | 
 | We support two complex dtypes: `torch.cfloat` and `torch.cdouble` | 
 |  | 
 | :: | 
 |  | 
 |      >>> x = torch.randn(2,2, dtype=torch.cfloat) | 
 |      >>> x | 
 |      tensor([[-0.4621-0.0303j, -0.2438-0.5874j], | 
 |           [ 0.7706+0.1421j,  1.2110+0.1918j]]) | 
 |  | 
 | .. note:: | 
 |  | 
 |      The default dtype for complex tensors is determined by the default floating point dtype. | 
 |      If the default floating point dtype is `torch.float64` then complex numbers are inferred to | 
 |      have a dtype of `torch.complex128`, otherwise they are assumed to have a dtype of `torch.complex64`. | 
 |  | 
 | All factory functions apart from :func:`torch.linspace`, :func:`torch.logspace`, and :func:`torch.arange` are | 
 | supported for complex tensors. | 
 |  | 
 | Transition from the old representation | 
 | -------------------------------------- | 
 |  | 
 | Users who currently worked around the lack of complex tensors with real tensors of shape :math:`(..., 2)` | 
 | can easily to switch using the complex tensors in their code using :func:`torch.view_as_complex` | 
 | and :func:`torch.view_as_real`. Note that these functions don’t perform any copy and return a | 
 | view of the input tensor. | 
 |  | 
 | :: | 
 |  | 
 |      >>> x = torch.randn(3, 2) | 
 |      >>> x | 
 |      tensor([[ 0.6125, -0.1681], | 
 |           [-0.3773,  1.3487], | 
 |           [-0.0861, -0.7981]]) | 
 |      >>> y = torch.view_as_complex(x) | 
 |      >>> y | 
 |      tensor([ 0.6125-0.1681j, -0.3773+1.3487j, -0.0861-0.7981j]) | 
 |      >>> torch.view_as_real(y) | 
 |      tensor([[ 0.6125, -0.1681], | 
 |           [-0.3773,  1.3487], | 
 |           [-0.0861, -0.7981]]) | 
 |  | 
 | Accessing real and imag | 
 | ----------------------- | 
 |  | 
 | The real and imaginary values of a complex tensor can be accessed using the :attr:`real` and | 
 | :attr:`imag`. | 
 |  | 
 | .. note:: | 
 |      Accessing `real` and `imag` attributes doesn't allocate any memory, and in-place updates on the | 
 |      `real` and `imag` tensors will update the original complex tensor. Also, the | 
 |      returned `real` and `imag` tensors are not contiguous. | 
 |  | 
 | :: | 
 |  | 
 |      >>> y.real | 
 |      tensor([ 0.6125, -0.3773, -0.0861]) | 
 |      >>> y.imag | 
 |      tensor([-0.1681,  1.3487, -0.7981]) | 
 |  | 
 |      >>> y.real.mul_(2) | 
 |      tensor([ 1.2250, -0.7546, -0.1722]) | 
 |      >>> y | 
 |      tensor([ 1.2250-0.1681j, -0.7546+1.3487j, -0.1722-0.7981j]) | 
 |      >>> y.real.stride() | 
 |      (2,) | 
 |  | 
 | Angle and abs | 
 | ------------- | 
 |  | 
 | The angle and absolute values of a complex tensor can be computed using :func:`torch.angle` and | 
 | :func:`torch.abs`. | 
 |  | 
 | :: | 
 |  | 
 |      >>> x1=torch.tensor([3j, 4+4j]) | 
 |      >>> x1.abs() | 
 |      tensor([3.0000, 5.6569]) | 
 |      >>> x1.angle() | 
 |      tensor([1.5708, 0.7854]) | 
 |  | 
 | Linear Algebra | 
 | -------------- | 
 |  | 
 | Many linear algebra operations, like :func:`torch.matmul`, :func:`torch.svd`, :func:`torch.solve` etc., support complex numbers. | 
 | If you'd like to request an operation we don't currently support, please `search <https://github.com/pytorch/pytorch/issues?q=is%3Aissue+is%3Aopen+complex>`_ | 
 | if an issue has already been filed and if not, `file one <https://github.com/pytorch/pytorch/issues/new/choose>`_. | 
 |  | 
 |  | 
 | Serialization | 
 | ------------- | 
 |  | 
 | Complex tensors can be serialized, allowing data to be saved as complex values. | 
 |  | 
 | :: | 
 |  | 
 |      >>> torch.save(y, 'complex_tensor.pt') | 
 |      >>> torch.load('complex_tensor.pt') | 
 |      tensor([ 0.6125-0.1681j, -0.3773+1.3487j, -0.0861-0.7981j]) | 
 |  | 
 |  | 
 | Autograd | 
 | -------- | 
 |  | 
 | PyTorch supports autograd for complex tensors. The gradient computed is the Conjugate Wirtinger derivative, | 
 | the negative of which is precisely the direction of steepest descent used in Gradient Descent algorithm. Thus, | 
 | all the existing optimizers work out of the box with complex parameters. For more details, | 
 | check out the note :ref:`complex_autograd-doc`. | 
 |  | 
 | We do not fully support the following subsystems: | 
 |  | 
 | * Quantization | 
 |  | 
 | * JIT | 
 |  | 
 | * Sparse Tensors | 
 |  | 
 | * Distributed | 
 |  | 
 | If any of these would help your use case, please `search <https://github.com/pytorch/pytorch/issues?q=is%3Aissue+is%3Aopen+complex>`_ | 
 | if an issue has already been filed and if not, `file one <https://github.com/pytorch/pytorch/issues/new/choose>`_. |