Skip to content

Commit

Permalink
Foldability check includes a check for inverse (unitaryfund#939)
Browse files Browse the repository at this point in the history
* cirq inverse

* inverse ry test

* format

* Update mitiq/zne/scaling/folding.py

Co-authored-by: Andrea Mari <[email protected]>

* terminal measurements

Co-authored-by: Andrea Mari <[email protected]>
  • Loading branch information
purva-thakre and andreamari authored Oct 6, 2021
1 parent 0f57a04 commit 11c6c68
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 6 deletions.
12 changes: 8 additions & 4 deletions mitiq/zne/scaling/folding.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,14 @@ def _check_foldable(circuit: Circuit) -> None:
)

if not has_unitary(circuit):
raise UnfoldableCircuitError(
"Circuit contains non-unitary channels which are not terminal "
"measurements and cannot be folded."
)
circ_measurements = _pop_measurements(circuit)
if inverse(circuit, default=None) is None:
raise UnfoldableCircuitError(
"Circuit contains non-invertible channels which are not"
"terminal measurements and cannot be folded."
)
else:
_append_measurements(circuit, circ_measurements)


def _squash_moments(circuit: Circuit) -> Circuit:
Expand Down
83 changes: 81 additions & 2 deletions mitiq/zne/scaling/tests/test_folding.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
equal_up_to_global_phase,
InsertStrategy,
testing,
ry,
rz,
)
from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister
from qiskit.quantum_info.operators import Operator
Expand All @@ -51,6 +53,7 @@
_create_fold_mask,
_apply_fold_mask,
)
from sympy import Symbol


def test_squash_moments_two_qubits():
Expand Down Expand Up @@ -407,14 +410,90 @@ def test_fold_with_intermediate_measurements_raises_error(fold_method):
)
def test_fold_with_channels_raises_error(fold_method):
"""Tests local folding functions raise an error on circuits with
non-unitary channels (which are not measurements).
non-invertible channels (which are not measurements).
"""
qbit = LineQubit(0)
circ = Circuit(
ops.H.on(qbit), ops.depolarize(p=0.1).on(qbit), ops.measure(qbit)
)
with pytest.raises(
UnfoldableCircuitError, match="Circuit contains non-unitary channels"
UnfoldableCircuitError, match="Circuit contains non-invertible"
):
fold_method(circ, scale_factor=3.0)


@pytest.mark.parametrize(
"fold_method",
[
fold_gates_from_left,
fold_gates_from_right,
fold_gates_at_random,
fold_global,
],
)
def test_parametrized_circuit_folding(fold_method):
"""Checks if the circuit is folded as expected when the circuit operations
have a valid inverse.
"""
theta = Symbol("theta")
q = LineQubit(0)
ansatz_circ = Circuit(ry(theta).on(q))
folded_circ = fold_method(ansatz_circ, scale_factor=3.0)
expected_circ = Circuit(ry(theta).on(q), ry(-theta).on(q), ry(theta).on(q))
assert _equal(folded_circ, expected_circ)


@pytest.mark.parametrize(
"fold_method",
[
fold_gates_from_left,
fold_gates_from_right,
fold_gates_at_random,
fold_global,
],
)
def test_parametrized_circuit_folding_terminal_measurement(fold_method):
"""Checks if the circuit with a terminal measurement is folded as expected
when the circuit operations have a valid inverse.
"""
theta = Symbol("theta")
q = LineQubit(0)
ansatz_circ = Circuit(ry(theta).on(q), ops.measure(q))
folded_circ = fold_method(ansatz_circ, scale_factor=3.0)
expected_circ = Circuit(
ry(theta).on(q), ry(-theta).on(q), ry(theta).on(q), ops.measure(q)
)
assert _equal(folded_circ, expected_circ)


@pytest.mark.parametrize(
"fold_method",
[
fold_gates_from_left,
fold_gates_from_right,
fold_gates_at_random,
fold_global,
],
)
def test_errors_raised_parametrized_circuits(fold_method):
"""Checks if proper error is raised in a symbolic circuit when it cannot
be folded.
"""
theta = Symbol("theta")
q = LineQubit(0)
ansatz_circ = Circuit(ry(theta).on(q), ops.measure(q), rz(theta).on(q))
with pytest.raises(
UnfoldableCircuitError,
match="Circuit contains intermediate measurements",
):
fold_method(ansatz_circ, scale_factor=3.0)

qbit = LineQubit(0)
circ = Circuit(
ry(theta).on(q), ops.depolarize(p=0.1).on(qbit), ops.measure(qbit)
)
with pytest.raises(
UnfoldableCircuitError, match="Circuit contains non-invertible"
):
fold_method(circ, scale_factor=3.0)

Expand Down

0 comments on commit 11c6c68

Please sign in to comment.