Skip to content
This repository was archived by the owner on Nov 7, 2024. It is now read-only.

Support of .imag and .real for backends #856

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion tensornetwork/backends/abstract_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -1010,4 +1010,25 @@ def power(self, a: Tensor, b: Union[Tensor, float]) -> Tensor:
"""
raise NotImplementedError(
f"Backend {self.name} has not implemented power.")


def real(self, tensor: Tensor) -> Tensor:
"""Return Re(tensor)
Args:
tensor: Input Tensor

Returns: Re(tensor), real part of tensor

"""
raise NotImplementedError(
f"Backend {self.name} has not implemented .real")

def imag(self, tensor: Tensor) -> Tensor:
"""Return Im(tensor)
Args:
tensor: Input tensor.

Returns: Im(tensor), imaginary part of tensor.

"""
raise NotImplementedError(
f"Backend {self.name} has not implemented .imag")
22 changes: 22 additions & 0 deletions tensornetwork/backends/jax/jax_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -871,3 +871,25 @@ def sign(self, tensor: Tensor) -> Tensor:
tensor: The input tensor.
"""
return jnp.sign(tensor)

def real(self, tensor: Tensor) -> Tensor:
"""

Args:
tensor: Input Tensor

Returns: Re(tensor),Real part of tensor

"""
return jnp.real(tensor)

def imag(self, tensor: Tensor) -> Tensor:
"""

Args:
tensor: Input Tensor

Returns: Im(tensor), Imaginary part of tensor

"""
return jnp.imag(tensor)
24 changes: 24 additions & 0 deletions tensornetwork/backends/jax/jax_backend_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1096,3 +1096,27 @@ def test_inv(dtype, atol):
tensor = backend.randn((10, 10, 10), dtype=dtype, seed=10)
with pytest.raises(ValueError, match="input to"):
backend.inv(tensor)


@pytest.mark.parametrize("dtype", np_dtypes)
@pytest.mark.parametrize("input_cur", [np.array([1, 2]),
np.array([5+6j, 4+10j]),
np.array([5j, 7j])])
def test_real(dtype,input_cur):
backend = jax_backend.JaxBackend()
cur = backend.convert_to_tensor(input_cur)
acual = backend.real(cur)
expcted = jax.numpy.real(cur)
np.testing.assert_allclose(acual, expcted)


@pytest.mark.parametrize("dtype", np_dtypes)
@pytest.mark.parametrize("input_cur", [np.array([1, 2]),
np.array([5+6j, 4+10j]),
np.array([5j, 7j])])
def test_imag(dtype, input_cur):
backend = jax_backend.JaxBackend()
cur = backend.convert_to_tensor(input_cur)
acual = backend.imag(cur)
expcted = jax.numpy.imag(cur)
np.testing.assert_allclose(acual, expcted)
33 changes: 17 additions & 16 deletions tensornetwork/backends/numpy/numpy_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -759,24 +759,25 @@ def deserialize_tensor(self, s: str) -> Tensor:
m.write(s.encode('latin-1'))
m.seek(0)
return np.load(m)
def power(self, a: Tensor, b: Union[Tensor, float]) -> Tensor:

def real(self, tensor: Tensor) -> Tensor:
"""
Returns the exponentiation of tensor a raised to b.
If b is a tensor, then the exponentiation is element-wise
between the two tensors, with a as the base and b as the power.
Note that a and b must be broadcastable to the same shape if
b is a tensor.
If b is a scalar, then the exponentiation is each value in a
raised to the power of b.

Retuns Re(tensor), returns real element in tensor given
Args:
tensor: Input Tensor

Returns:
returns real element in tensor given
"""
return np.real(tensor)

def imag(self, tensor: Tensor) -> Tensor:
"""
Returns Im(tensor), returns the Imaginary part of tensor
Args:
a: The tensor containing the bases.
b: The tensor containing the powers; or a single scalar as the power.
tensor: Input Tensor

Returns:
The tensor that is each element of a raised to the
power of b. Note that the shape of the returned tensor
is that produced by the broadcast of a and b.
returns the Imaginary part of tensor
"""
return np.power(a, b)
return np.imag(tensor)
28 changes: 17 additions & 11 deletions tensornetwork/backends/numpy/numpy_backend_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -950,16 +950,22 @@ def test_serialize(dtype):
assert isinstance(s, str)
assert (tensor == backend.deserialize_tensor(s)).all()


@pytest.mark.parametrize('dtype', np_dtypes)
def test_power(dtype):
shape = (4, 3, 2)
@pytest.mark.parametrize("input_cur", [(np.array([1, 2, 3, 4])), (np.array([1j, 2j, 3j, 4j])),
(np.array([10+2j, 20+2j, 30+5j, 40+20j]))])
def test_real(dtype, input_cur):
backend = numpy_backend.NumPyBackend()
base_tensor = np.abs(backend.randn(shape, dtype=dtype, seed=10))
power_tensor = backend.randn(shape, dtype=dtype, seed=10)
actual = backend.power(base_tensor, power_tensor)
expected = np.power(base_tensor, power_tensor)
np.testing.assert_allclose(expected, actual)
power = np.random.rand(1)[0]
actual = backend.power(base_tensor, power)
expected = np.power(base_tensor, power)
np.testing.assert_allclose(expected, actual)
cur = backend.convert_to_tensor(input_cur)
np.testing.assert_allclose(cur.real, np.real(input_cur))


@pytest.mark.parametrize('dtype', np_dtypes)
@pytest.mark.parametrize("input_cur", [(np.array([1, 2, 3, 4])), (np.array([1j, 2j, 3j, 4j])),
(np.array([10+2j, 20+2j, 30+5j, 40+20j]))])
def test_imag(dtype, input_cur):
backend = numpy_backend.NumPyBackend()
cur = backend.convert_to_tensor(input_cur)
acual = cur.imag
expected = np.imag(input_cur)
np.testing.assert_allclose(acual, expected)
32 changes: 32 additions & 0 deletions tensornetwork/backends/pytorch/pytorch_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -472,3 +472,35 @@ def sign(self, tensor: Tensor) -> Tensor:
tensor: The input tensor.
"""
return torchlib.sign(tensor)

def real(self, tensor: Tensor) -> Tensor:
"""Return real part of tensor
Args:
tensor: Input Tensor

Returns: Re(tensor),Real part of tensor

"""
if torchlib.is_complex(tensor):
return torchlib.real(tensor)
else:
temp = torchlib.zeros_like(tensor, dtype=torchlib.cfloat)
tensor = torchlib.as_tensor(tensor, dtype=torchlib.cfloat)
torchlib.add(tensor, temp, out=tensor)
return torchlib.real(tensor)

def imag(self,tensor: Tensor) -> Tensor:
"""Return imag part of tensor
Args:
tensor: Input tensor

Returns: Im(tensor),returns Imaginary part of tensor

"""
if torchlib.is_complex(tensor):
return torchlib.imag(tensor)
else:
temp = torchlib.zeros_like(tensor, dtype=torchlib.cfloat)
tensor = torchlib.as_tensor(tensor, dtype=torchlib.cfloat)
torchlib.add(tensor, temp, out=tensor)
return torchlib.imag(tensor)
26 changes: 26 additions & 0 deletions tensornetwork/backends/pytorch/pytorch_backend_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -664,3 +664,29 @@ def test_matmul_rank2():
actual = backend.matmul(a, b)
expected = np.matmul(t1, t2)
np.testing.assert_allclose(expected, actual)


@pytest.mark.parametrize("dtype", torch_randn_dtypes)
@pytest.mark.parametrize("input_cur", [(np.array([1+6j, 2+7j])), (np.array([1j, 2j])),
(np.array([5+3j, 4+7j]))])
def test_real(dtype, input_cur):
backend = pytorch_backend.PyTorchBackend()
cur = backend.convert_to_tensor(input_cur)
acual = backend.real(cur)
expected = torch.real(cur)
np.testing.assert_allclose(acual, expected)
cur = backend.convert_to_tensor(np.array([1, 2]))
np.testing.assert_allclose(backend.real(cur), np.array([1, 2]))


@pytest.mark.parametrize("dtype", torch_randn_dtypes)
@pytest.mark.parametrize("input_cur", [(np.array([1+6j, 2+7j])), (np.array([1j, 2j])),
(np.array([5+3j, 4+7j]))])
def test_imag(dtype, input_cur):
backend = pytorch_backend.PyTorchBackend()
cur = backend.convert_to_tensor(input_cur)
acual = backend.imag(cur)
expected = torch.imag(cur)
np.testing.assert_allclose(acual, expected)
cur = backend.convert_to_tensor(np.array([1, 2]))
np.testing.assert_allclose(backend.imag(cur), np.array([0, 0]))
9 changes: 9 additions & 0 deletions tensornetwork/backends/symmetric/symmetric_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -680,3 +680,12 @@ def sign(self, tensor: Tensor) -> Tensor:

def pivot(self, tensor: Tensor, pivot_axis: int = -1) -> Tensor:
raise NotImplementedError("Symmetric backend doesn't support pivot.")

def real(self, tensor: Tensor) -> Tensor:
temp = tensor.data[abs(tensor.data.imag) > 0]
return temp.real


def imag(self, tensor:Tensor) -> Tensor:
temp = tensor.data[abs(tensor.data.imag) < 0]
return temp.imag
22 changes: 22 additions & 0 deletions tensornetwork/backends/symmetric/symmetric_backend_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1644,3 +1644,25 @@ def test_gmres_raises():
backend.gmres(lambda x: x, b, x0=mps, tol=-0.001)
with pytest.raises(ValueError, match="atol = "):
backend.gmres(lambda x: x, b, x0=mps, atol=-0.001)


@pytest.mark.parametrize("dtype", np_dtypes)
@pytest.mark.parametrize("R", [2, 3, 4, 5])
@pytest.mark.parametrize("num_charges", [1, 2])
def test_real(dtype, R, num_charges):
backend = symmetric_backend.SymmetricBackend()
a = get_tensor(R, num_charges, dtype)
a = backend.real(a)
temp = np.isreal(a)
assert(temp.all())


@pytest.mark.parametrize("dtype", np_dtypes)
@pytest.mark.parametrize("R", [2, 3, 4, 5])
@pytest.mark.parametrize("num_charges", [1, 2])
def test_imag(dtype, R, num_charges):
backend = symmetric_backend.SymmetricBackend()
a = get_tensor(R, num_charges, dtype)
a = backend.imag(a)
temp = np.iscomplex(a)
assert(temp.all())
22 changes: 22 additions & 0 deletions tensornetwork/backends/tensorflow/tensorflow_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,3 +383,25 @@ def sign(self, tensor: Tensor) -> Tensor:
tensor: The input tensor.
"""
return tf.math.sign(tensor)

def real(self, tensor: Tensor) -> Tensor:
"""

Args:
tensor: Input Tensor

Returns: Real part of tensor, Re(tensor)

"""
return tf.math.real(tensor)

def imag(self, tensor: Tensor) -> Tensor:
"""

Args:
tensor: Input Tensor

Returns: Imaginary part of tensor, Im(tensor)

"""
return tf.math.imag(tensor)
19 changes: 19 additions & 0 deletions tensornetwork/backends/tensorflow/tensorflow_backend_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -599,3 +599,22 @@ def test_pivot(dtype, pivot_axis):
expected = tf.reshape(tensor, pivot_shape)
actual = backend.pivot(tensor, pivot_axis=pivot_axis)
np.testing.assert_allclose(expected, actual)


@pytest.mark.parametrize("dtype", tf_dtypes)
@pytest.mark.parametrize("input_cur", [(np.array([1, 2, 3, 4])), (np.array([1j, 2j, 3j, 4j])),
(np.array([10+2j, 20+2j, 30+5j, 40+20j]))])
def test_real(dtype, input_cur):
backend = tensorflow_backend.TensorFlowBackend()
cur = backend.convert_to_tensor(input_cur)
expected = tf.math.real(input_cur)
np.testing.assert_allclose(backend.real(cur), expected)

@pytest.mark.parametrize("dtype", tf_dtypes)
@pytest.mark.parametrize("input_cur", [(np.array([1, 2, 3, 4])), (np.array([1j, 2j, 3j, 4j])),
(np.array([10+2j, 20+2j, 30+5j, 40+20j]))])
def test_imag(dtype, input_cur):
backend = tensorflow_backend.TensorFlowBackend()
cur = backend.convert_to_tensor(input_cur)
expected = tf.math.imag(input_cur)
np.testing.assert_allclose(backend.imag(cur), expected)