Skip to content

Commit

Permalink
executor_observable compatability with typehint and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
bdg221 committed Sep 27, 2024
1 parent 1d447cf commit 163b045
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 14 deletions.
23 changes: 23 additions & 0 deletions mitiq/executor/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,29 @@ def evaluate(
"Expected observable to be hermitian. Continue with caution."
)

# Check executor and observable compatability with type hinting
if self._executor_return_type in FloatLike and observable is not None:
raise ValueError(
"When using a float like result, measurements should be "
"included in the circuit and an observable should not be used."
)
elif (
self._executor_return_type in DensityMatrixLike
and observable is None
):
raise ValueError(
"When using a density matrix like result, an observable is "
"required."
)
elif (
self._executor_return_type in MeasurementResultLike
and observable is None
):
raise ValueError(
"When using a measurement, or bitstring, like result, an "
"observable is required."
)

# Get all required circuits to run.
if (
observable is not None
Expand Down
70 changes: 56 additions & 14 deletions mitiq/executor/tests/test_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,21 +58,29 @@ def executor_pyquil_batched(programs) -> List[float]:


# Serial / batched executors which return measurements.
def executor_measurements(circuit) -> MeasurementResult:
def executor_measurements(circuit):
return sample_bitstrings(circuit, noise_level=(0,))


def executor_measurements_typed(circuit) -> MeasurementResult:
return sample_bitstrings(circuit, noise_level=(0,))


def executor_measurements_batched(circuits) -> List[MeasurementResult]:
return [executor_measurements(circuit) for circuit in circuits]
return [executor_measurements_typed(circuit) for circuit in circuits]


# Serial / batched executors which return density matrices.
def executor_density_matrix(circuit) -> np.ndarray:
def executor_density_matrix(circuit):
return compute_density_matrix(circuit, noise_level=(0,))


def executor_density_matrix_typed(circuit) -> np.ndarray:
return compute_density_matrix(circuit, noise_level=(0,))


def executor_density_matrix_batched(circuits) -> List[np.ndarray]:
return [executor_density_matrix(circuit) for circuit in circuits]
return [executor_density_matrix_typed(circuit) for circuit in circuits]


def test_executor_simple():
Expand All @@ -86,7 +94,7 @@ def test_executor_is_batched_executor():
assert Executor.is_batched_executor(executor_batched)
assert not Executor.is_batched_executor(executor_serial_typed)
assert not Executor.is_batched_executor(executor_serial)
assert not Executor.is_batched_executor(executor_measurements)
assert not Executor.is_batched_executor(executor_measurements_typed)
assert Executor.is_batched_executor(executor_measurements_batched)


Expand All @@ -96,7 +104,7 @@ def test_executor_non_hermitian_observable():
q = cirq.LineQubit(0)
circuits = [cirq.Circuit(cirq.I.on(q)), cirq.Circuit(cirq.X.on(q))]

executor = Executor(executor_measurements)
executor = Executor(executor_measurements_typed)

with pytest.warns(UserWarning, match="hermitian"):
executor.evaluate(circuits, obs)
Expand Down Expand Up @@ -216,7 +224,7 @@ def test_executor_evaluate_float(execute):


@pytest.mark.parametrize(
"execute", [executor_measurements, executor_measurements_batched]
"execute", [executor_measurements_typed, executor_measurements_batched]
)
def test_executor_evaluate_measurements(execute):
obs = Observable(PauliString("Z"))
Expand All @@ -229,24 +237,24 @@ def test_executor_evaluate_measurements(execute):
results = executor.evaluate(circuits, obs)
assert np.allclose(results, [1, -1])

if execute is executor_measurements:
if execute is executor_measurements_typed:
assert executor.calls_to_executor == 2
else:
assert executor.calls_to_executor == 1

assert executor.executed_circuits[0] == circuits[0] + cirq.measure(q)
assert executor.executed_circuits[1] == circuits[1] + cirq.measure(q)
assert executor.quantum_results[0] == executor_measurements(
assert executor.quantum_results[0] == executor_measurements_typed(
circuits[0] + cirq.measure(q)
)
assert executor.quantum_results[1] == executor_measurements(
assert executor.quantum_results[1] == executor_measurements_typed(
circuits[1] + cirq.measure(q)
)
assert len(executor.quantum_results) == len(circuits)


@pytest.mark.parametrize(
"execute", [executor_density_matrix, executor_density_matrix_batched]
"execute", [executor_density_matrix_typed, executor_density_matrix_batched]
)
def test_executor_evaluate_density_matrix(execute):
obs = Observable(PauliString("Z"))
Expand All @@ -259,16 +267,50 @@ def test_executor_evaluate_density_matrix(execute):
results = executor.evaluate(circuits, obs)
assert np.allclose(results, [1, -1])

if execute is executor_density_matrix:
if execute is executor_density_matrix_typed:
assert executor.calls_to_executor == 2
else:
assert executor.calls_to_executor == 1

assert executor.executed_circuits == circuits
assert np.allclose(
executor.quantum_results[0], executor_density_matrix(circuits[0])
executor.quantum_results[0], executor_density_matrix_typed(circuits[0])
)
assert np.allclose(
executor.quantum_results[1], executor_density_matrix(circuits[1])
executor.quantum_results[1], executor_density_matrix_typed(circuits[1])
)
assert len(executor.quantum_results) == len(circuits)


def test_executor_float_with_observable_typed():
obs = Observable(PauliString("Z"))
q = cirq.LineQubit(0)
circuit = cirq.Circuit(cirq.X.on(q))
executor = Executor(executor_serial_typed)
with pytest.raises(
ValueError,
match="When using a float like result",
):
executor.evaluate(circuit, obs)


def test_executor_measurements_without_observable_typed():
q = cirq.LineQubit(0)
circuit = cirq.Circuit(cirq.X.on(q))
executor = Executor(executor_measurements_typed)
with pytest.raises(
ValueError,
match="When using a measurement, or bitstring, like result",
):
executor.evaluate(circuit)


def test_executor_density_matrix_without_observable_typed():
q = cirq.LineQubit(0)
circuit = cirq.Circuit(cirq.X.on(q))
executor = Executor(executor_density_matrix_typed)
with pytest.raises(
ValueError,
match="When using a density matrix like result",
):
executor.evaluate(circuit)

0 comments on commit 163b045

Please sign in to comment.