torch.conj()
The torch.conj() method performs lazy conjugate, flipping the sign of the imaginary part for complex tensors.

It returns only a view of the input with a flipped conjugate bit and does not produce a new tensor. It is memory-efficient, but it may not be compatible with all operations.
If the input is a real number, .conj() returns it as it is input, as there is no imaginary part in a real number.
Syntax
torch.conj(input)
Parameters
Argument | Description |
input (Tensor) |
It represents an input tensor, which can be real or complex. |
Complex tensor conjugation
Let’s define a complex tensor and find its conjugate.
import torch z = torch.tensor([2 + 2j, 3 - 9j], dtype=torch.complex64) conj_z = torch.conj(z) print(conj_z) # Output: tensor([2.-2.j, 3.+9.j])
The above output shows that it flipped the sign of the imaginary part, which is .j.
So, +2.j becomes -2.j and -9.j becomes +9.j.
Real tensor conjugation

Since a real tensor does not contain an imaginary part, the .conj() method returns the input as it is.
import torch x = torch.tensor([1.0, 2.0, 3.0]) conj_x = torch.conj(x) print(conj_x) # Output: tensor([1., 2., 3.])
torch.conj_physical()
The torch.conj_physical() method calculates the conjugate element-wise of the input tensor and returns a new tensor with the result physically stored in memory, rather than as a view.
The main difference between .conj_physical() and .conj() is that the .conj_physical() method returns a new tensor with the conjugate values explicitly computed and stored, whereas the .conj() method returns a view of the input tensor.
Syntax
torch.conj_physical(input, out=None)
Parameters
Argument | Description |
input (Tensor) | It can be a complex or real tensor. |
out (Tensor, optional) | It is a tensor that is allocated to store the result. If you do not have any, it will allocate a new tensor. |
Physical Conjugation

Here is the code example of executing physical conjugation:
import torch z = torch.tensor([8 - 6j, 2 - 1j], dtype=torch.complex64) conj_physical_z = torch.conj_physical(z) print(conj_physical_z) # Output: tensor([8.+6.j, 2.+1.j]) print(conj_physical_z.is_conj()) # Output: False
From the above code, you can see that the output is a new tensor with negated imaginary parts, not a view with a conjugate bit.
Using an out Parameter
You can create a pre-allocated tensor using methods like torch.empty() and then store the result of the. conj_physical() method.
import torch z = torch.tensor([1 + 2j], dtype=torch.complex64) out = torch.empty(1, dtype=torch.complex64) torch.conj_physical(z, out=out) print(out) # Output: tensor([1.-2.j])
torch.resolve_conj()
The torch.resolve_conj() method returns a new tensor with materialized conjugation if the input’s conjugate bit is set to True, else it returns the input.

It materializes the conjugate values if the input is a conjugate view.
Syntax
torch.resolve_conj(input)
Parameters
Argument | Description |
input (Tensor) | It represents an input tensor, which is either real or complex. |
Resolving conjugate view
Let’s define a complex tensor and find its conjugate view using torch.conj() method.
Then, we convert the lazy conjugate view into a real (physical) tensor where the conjugate is actually calculated using torch.resolve_conj() method.
import torch z = torch.tensor([7 - 5j], dtype=torch.complex64) conj_view = torch.conj(z) print(conj_view.is_conj()) # Output: True resolved = torch.resolve_conj(conj_view) print(resolved) # Output: tensor([7.+5.j]) print(resolved.is_conj()) # Output: False
In this program, when we first calculated the conjugated view, it was marked as True because the tensor had a conjugated view. It has not materialized yet.
After using the .resolve_conj() method, we materialize a view into a physical tensor and now resolved.is_conj() returns False because it’s no longer a view.
Non-Conjugate input
If you pass the tensor, which is not a conjugate view, meaning you have not performed torch.conj() operation yet, it will return the same output as the input, and if you check it with the .is_conj() method, it will return False.
import torch z = torch.tensor([1 + 2j], dtype=torch.complex64) resolved_view = torch.resolve_conj(z) print(resolved_view) # Output: tensor([1.+2.j]) print(resolved_view.is_conj()) # Output: False
Conclusion
Now, you all must have one burning question? Which method to use and in which scenario?
Use a torch.conj() method when you want memory efficiency, as it does not physically store anything.
Use a torch.conj_physical() when a physical copy of a tensor is required for other operations.
Use a torch.resolve_conj() method finalizes calculations and ensures no conjugate metadata remains.