Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compute expectation value #4484

Merged
merged 48 commits into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
8c9868d
added expectation_value function
ludmilaasb Aug 14, 2023
16ba2df
Merge remote-tracking branch 'origin/master' into compute_expectation…
ludmilaasb Aug 14, 2023
1f5f7b0
added tests
ludmilaasb Aug 15, 2023
c27d6f0
Use local PRNG in `spsa_grad` (#4165)
frederikwilde Aug 15, 2023
0070333
Reverse factor 1/2 in transmon_interaction (#4478)
Qottmann Aug 15, 2023
89b6f5f
passing tests
ludmilaasb Aug 15, 2023
b15147c
Merge branch 'PennyLaneAI:master' into compute_expectation_value
ludmilaasb Aug 15, 2023
7777b4e
up
ludmilaasb Aug 15, 2023
69534d6
Merge branch 'compute_expectation_value' of github.com:ludmilaasb/pen…
ludmilaasb Aug 15, 2023
20746d4
small fix
ludmilaasb Aug 16, 2023
775ca0e
Apply suggestions from code review
ludmilaasb Aug 17, 2023
2e4a79d
Update pennylane/math/quantum.py
ludmilaasb Aug 17, 2023
ecdb5d4
Apply suggestions from code review
ludmilaasb Aug 17, 2023
cdcecc0
added more random states to test
ludmilaasb Aug 22, 2023
924a9aa
fix import
ludmilaasb Aug 23, 2023
4383aa4
changed test decorator
ludmilaasb Aug 23, 2023
4ce9666
up
ludmilaasb Aug 23, 2023
8e378f1
Merge branch 'master' into compute_expectation_value
ludmilaasb Sep 19, 2023
a68290e
Merge branch 'PennyLaneAI:master' into compute_expectation_value
ludmilaasb Jan 29, 2024
6ee3a32
changed examples and added more tests
ludmilaasb Jan 29, 2024
4d66ef9
Apply suggestions from code review
ludmilaasb Feb 5, 2024
2b4df2a
Merge branch 'PennyLaneAI:master' into compute_expectation_value
ludmilaasb Feb 5, 2024
f3a309c
updated changelog
ludmilaasb Feb 5, 2024
99d3f5a
added more tests
ludmilaasb Feb 6, 2024
eded14d
list to array fix
ludmilaasb Feb 7, 2024
8ada9dc
Merge branch 'master' into compute_expectation_value
ludmilaasb Feb 7, 2024
4613f1e
Merge branch 'PennyLaneAI:master' into compute_expectation_value
ludmilaasb Feb 8, 2024
65f53ca
Merge branch 'PennyLaneAI:master' into compute_expectation_value
ludmilaasb Feb 9, 2024
68ce1e7
added more tests
ludmilaasb Feb 9, 2024
72d89b3
tf einsum fix
ludmilaasb Feb 9, 2024
f99f67b
up
ludmilaasb Feb 9, 2024
03da70d
fixed allclose issue and torch tensor problem with type
ludmilaasb Feb 13, 2024
5d9c75e
small fix
ludmilaasb Feb 13, 2024
a452fa2
Merge branch 'master' into compute_expectation_value
ludmilaasb Feb 13, 2024
0689ebe
added more tests
ludmilaasb Feb 13, 2024
89c8d2e
fix hermitian test
ludmilaasb Feb 13, 2024
16e31b7
Merge branch 'master' into compute_expectation_value
astralcai May 9, 2024
ef8e2c9
Fix imports
astralcai May 9, 2024
643b382
Update changelog-dev.md
astralcai May 23, 2024
83c8b32
Merge branch 'master' into compute_expectation_value
astralcai May 23, 2024
68c7a25
Merge branch 'master' of https://github.com/PennyLaneAI/pennylane int…
astralcai Jun 14, 2024
22d8184
minor updates
astralcai Jun 14, 2024
21845fd
Merge branch 'master' into compute_expectation_value
astralcai Jun 14, 2024
c26e2eb
update test
astralcai Jun 14, 2024
0384e00
update docstring
astralcai Jun 17, 2024
0277aa6
Merge branch 'master' of https://github.com/PennyLaneAI/pennylane int…
astralcai Jun 17, 2024
d82ca50
apply suggestions from code review
astralcai Jun 17, 2024
3d2210c
Merge branch 'master' into compute_expectation_value
astralcai Jun 17, 2024
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
1 change: 1 addition & 0 deletions pennylane/math/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
dm_from_state_vector,
fidelity,
fidelity_statevector,
expectation_value,
ludmilaasb marked this conversation as resolved.
Show resolved Hide resolved
marginal_prob,
mutual_info,
purity,
Expand Down
57 changes: 57 additions & 0 deletions pennylane/math/quantum.py
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,63 @@
return vn_entropy_1 + vn_entropy_2 - vn_entropy_12


def expectation_value(operator_matrix, state_vector, check_state=False, c_dtype="complex128"):
r"""Compute the expectation value of an operator with respect to a pure state.

The expectation value of an operator :math:`A` for a pure state given by a state vector :math:`\ket{\psi}`
ludmilaasb marked this conversation as resolved.
Show resolved Hide resolved
is defined as

.. math::
\langle A \rangle_\psi = \bra{\psi} A \ket{\psi}

Args:
operator_matrix (tensor_like): operator matrix with shape ``(2**N, 2**N)`` or ``(batch_dim, 2**N, 2**N)``.
astralcai marked this conversation as resolved.
Show resolved Hide resolved
state_vector (tensor_like): state vector with shape ``(2**N)`` or ``(batch_dim, 2**N)``.
check_state (bool): If True, the function will check the validity of the state vector
via its shape and the norm
astralcai marked this conversation as resolved.
Show resolved Hide resolved
c_dtype (str): Complex floating point precision type.

Returns:
float: Expectation value of the operator for the state vector.
ludmilaasb marked this conversation as resolved.
Show resolved Hide resolved

**Example**

An operator matrix and a state vector can be used as arguments to obtain the expectation value, e.g.:

>>> state_vector = np.array([0, 1])
>>> operator_matrix = np.array([[0,1],[1,0]])
>>> qml.math.expectation_value(operator_matrix, state_vector)
0.0
ludmilaasb marked this conversation as resolved.
Show resolved Hide resolved
ludmilaasb marked this conversation as resolved.
Show resolved Hide resolved

.. seealso:: :func:`pennylane.math.fidelity`
dwierichs marked this conversation as resolved.
Show resolved Hide resolved

"""
# Cast as a c_dtype array
state_vector = cast(state_vector, dtype=c_dtype)

# Cannot be cast_like if jit
if not is_abstract(state_vector):
operator_matrix = cast_like(operator_matrix, state_vector)
ludmilaasb marked this conversation as resolved.
Show resolved Hide resolved

if check_state:
_check_state_vector(state_vector)

if qml.math.shape(operator_matrix)[-1] != qml.math.shape(state_vector)[-1]:
raise qml.QuantumFunctionError("The two states must have the same number of wires.")
astralcai marked this conversation as resolved.
Show resolved Hide resolved

batched0 = len(qml.math.shape(state_vector)) > 1

Check notice on line 767 in pennylane/math/quantum.py

View check run for this annotation

codefactor.io / CodeFactor

pennylane/math/quantum.py#L767

Unused variable 'batched0' (unused-variable)
batched1 = len(qml.math.shape(operator_matrix)) > 2

Check notice on line 768 in pennylane/math/quantum.py

View check run for this annotation

codefactor.io / CodeFactor

pennylane/math/quantum.py#L768

Unused variable 'batched1' (unused-variable)
ludmilaasb marked this conversation as resolved.
Show resolved Hide resolved
# The overlap <psi|A|psi>
overlap = qml.math.einsum(
f"...j,...ji,...i->...",

Check notice on line 771 in pennylane/math/quantum.py

View check run for this annotation

codefactor.io / CodeFactor

pennylane/math/quantum.py#L771

Using an f-string that does not have any interpolated variables (f-string-without-interpolation)
qml.math.conj(state_vector),
operator_matrix,
state_vector,
optimize="greedy",
)
return overlap
ludmilaasb marked this conversation as resolved.
Show resolved Hide resolved


def fidelity(state0, state1, check_state=False, c_dtype="complex128"):
r"""Compute the fidelity for two states (given as density matrices) acting on quantum
systems with the same size.
Expand Down
136 changes: 136 additions & 0 deletions tests/math/test_expectation_value_math.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
# Copyright 2023 Xanadu Quantum Technologies Inc.

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

# http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Unit tests for differentiable matrix-vector expectation values.
"""

import numpy as onp
import pytest

import torch
import jax.numpy as jnp
import tensorflow as tf

import pennylane as qml
from pennylane import numpy as np

pytestmark = pytest.mark.all_interfaces


class TestExpectationValueMath:
"""Tests for Expectation value of a operator for a state vector."""

ops_vs_vecstates = [
([[1, 0], [0, 0]], [1, 0], 1),
([[0, 1], [1, 0]], [0, 1], 0),
([[0.5, 0.5], [0.5, 0.5]], [1, 1] / np.sqrt(2), 1),
]

array_funcs = [
lambda x: x,
onp.array,
np.array,
jnp.array,
torch.tensor,
tf.Variable,
tf.constant,
]

check_state = [True, False]

@pytest.mark.parametrize("operator_and_states", ops_vs_vecstates)
@pytest.mark.parametrize("check_state", check_state)
@pytest.mark.parametrize("func", array_funcs)
def test_mat_expectation_value(self, operator_and_states, check_state, func):
"""Test the expectation value of a operator for a vector state."""
ops, state_vectors, expected = operator_and_states
ops = func(ops)
state_vectors = func(state_vectors)
overlap = qml.math.expectation_value(ops, state_vectors, check_state)
assert qml.math.allclose(expected, overlap)

state_wrong_amp = [([[1, 0], [0, 1]], [0.5, 0]), ([[1, 0], [0, 1]], [0, 0.5])]

@pytest.mark.parametrize("ops,state_vectors", state_wrong_amp)
def test_state_vector_wrong_amplitudes(self, ops, state_vectors):
"""Test that a message is raised when a state does not have right norm"""
with pytest.raises(ValueError, match="Sum of amplitudes-squared does not equal one."):
qml.math.expectation_value(ops, state_vectors, check_state=True)

state_wrong_shape = [([[1, 0], [0, 1]], [0, 1, 0]), ([[1, 0], [0, 1]], [0, 0, 0, 0, 1])]

@pytest.mark.parametrize("ops,state_vectors", state_wrong_shape)
def test_state_vector_wrong_shape(self, ops, state_vectors):
"""Test that a message is raised when the state does not have the right shape."""
with pytest.raises(ValueError, match="State vector must be of shape"):
qml.math.expectation_value(ops, state_vectors, check_state=True)

def test_same_number_wires_dm(self):
"""Test that the two states must act on the same number of wires"""
ops = np.diag([0, 1, 0, 0])
state_vectors = [1, 0]
with pytest.raises(
qml.QuantumFunctionError, match="The two states must have the same number of wires"
):
qml.math.expectation_value(ops, state_vectors, check_state=True)

@pytest.mark.parametrize("check_state", check_state)
@pytest.mark.parametrize("func", array_funcs)
def test_broadcast_op_sv(self, check_state, func):
"""Test simultaneous broadcasting of operators and state vectors works."""
ops = func(
[
[
[
1,
0,
],
[0, 0],
],
[[0.5, 0.5], [0.5, 0.5]],
[[1, 0], [0, 1]],
]
)
state_vectors = qml.math.stack([func([0, 1]), func([1, 0]), func([1, 1]) / np.sqrt(2)])
expected = [0, 0.5, 1]

overlap = qml.math.expectation_value(ops, state_vectors, check_state)
assert qml.math.allclose(overlap, expected)

@pytest.mark.parametrize("check_state", check_state)
@pytest.mark.parametrize("func", array_funcs)
def test_broadcast_op_unbatched(self, check_state, func):
"""Test broadcasting works for expectation values when the operators input is unbatched"""
ops = func([[1, 0], [0, 0]])
state_vectors = func([[0, 1], [1, 0], [1, 1] / np.sqrt(2)])
ludmilaasb marked this conversation as resolved.
Show resolved Hide resolved
expected = [0, 1, 0.5]

overlap = qml.math.expectation_value(ops, state_vectors, check_state)
assert qml.math.allclose(overlap, expected)

@pytest.mark.parametrize("check_state", check_state)
@pytest.mark.parametrize("func", array_funcs)
def test_broadcast_sv_unbatched(self, check_state, func):
"""Test broadcasting works for expectation values when the state vector input is unbatched"""
ops = func(
[
[[1, 0], [0, 0]],
[[0.5, 0.5], [0.5, 0.5]],
[[0, 0], [0, 1]],
]
)
state_vectors = func([1, 0])
expected = [1, 0.5, 0]

overlap = qml.math.expectation_value(ops, state_vectors, check_state)
assert qml.math.allclose(overlap, expected)
Loading