def test_pass_operations_over_double(shift, t_or_f1, t_or_f2, neg): q0, q1, q2 = _make_qubits(3) X, Y, Z = (pauli + shift for pauli in Pauli.XYZ) op0 = PauliInteractionGate(Z, t_or_f1, X, t_or_f2)(q0, q1) ps_before = PauliString({q0: Z, q2: Y}, neg) ps_after = PauliString({q0: Z, q2: Y}, neg) _assert_pass_over([op0], ps_before, ps_after) op0 = PauliInteractionGate(Y, t_or_f1, X, t_or_f2)(q0, q1) ps_before = PauliString({q0: Z, q2: Y}, neg) ps_after = PauliString({q0: Z, q2: Y, q1: X}, neg) _assert_pass_over([op0], ps_before, ps_after) op0 = PauliInteractionGate(Z, t_or_f1, X, t_or_f2)(q0, q1) ps_before = PauliString({q0: Z, q1: Y}, neg) ps_after = PauliString({q1: Y}, neg) _assert_pass_over([op0], ps_before, ps_after) op0 = PauliInteractionGate(Y, t_or_f1, X, t_or_f2)(q0, q1) ps_before = PauliString({q0: Z, q1: Y}, neg) ps_after = PauliString({q0: X, q1: Z}, neg ^ t_or_f1 ^ t_or_f2) _assert_pass_over([op0], ps_before, ps_after) op0 = PauliInteractionGate(X, t_or_f1, X, t_or_f2)(q0, q1) ps_before = PauliString({q0: Z, q1: Y}, neg) ps_after = PauliString({q0: Y, q1: Z}, not neg ^ t_or_f1 ^ t_or_f2) _assert_pass_over([op0], ps_before, ps_after)
def test_get(qubit_pauli_map): other = cirq.NamedQubit('other') pauli_string = PauliString(qubit_pauli_map) for key in qubit_pauli_map: assert qubit_pauli_map.get(key) == pauli_string.get(key) assert qubit_pauli_map.get(other) == pauli_string.get(other) == None assert qubit_pauli_map.get(other, 5) == pauli_string.get(other, 5) == 5
def test_zip_paulis(map1, map2, out): ps1 = PauliString(map1) ps2 = PauliString(map2) out_actual = tuple(ps1.zip_paulis(ps2)) assert len(out_actual) == len(out) if len(out) <= 1: assert out_actual == out assert set(out_actual) == set(out) # Ignore output order
def test_repr(): q0, q1, q2 = _make_qubits(3) pauli_string = PauliString({q2: Pauli.X, q1: Pauli.Y, q0: Pauli.Z}) assert (repr(pauli_string) == "PauliString({NamedQubit('q0'): Pauli.Z, " "NamedQubit('q1'): Pauli.Y, NamedQubit('q2'): Pauli.X}, False)") assert (repr( pauli_string.negate()) == "PauliString({NamedQubit('q0'): Pauli.Z, " "NamedQubit('q1'): Pauli.Y, NamedQubit('q2'): Pauli.X}, True)")
def test_map_qubits(): a, b = (cirq.NamedQubit(name) for name in 'ab') q0, q1 = _make_qubits(2) qubit_pauli_map1 = {a: Pauli.X, b: Pauli.Y} qubit_pauli_map2 = {q0: Pauli.X, q1: Pauli.Y} qubit_map = {a: q0, b: q1} ps1 = PauliString(qubit_pauli_map1) ps2 = PauliString(qubit_pauli_map2) assert ps1.map_qubits(qubit_map) == ps2
def test_manual_default_decompose(): q0, q1, q2 = _make_qubits(3) mat = cirq.Circuit.from_ops( PauliStringPhasor(PauliString({q0: Pauli.Z}))**0.25, cirq.Z(q0)**-0.25, ).to_unitary_matrix() cirq.testing.assert_allclose_up_to_global_phase(mat, np.eye(2), rtol=1e-7, atol=1e-7) mat = cirq.Circuit.from_ops( PauliStringPhasor(PauliString({q0: Pauli.Y}))**0.25, cirq.Y(q0)**-0.25, ).to_unitary_matrix() cirq.testing.assert_allclose_up_to_global_phase(mat, np.eye(2), rtol=1e-7, atol=1e-7) mat = cirq.Circuit.from_ops( PauliStringPhasor(PauliString({ q0: Pauli.Z, q1: Pauli.Z, q2: Pauli.Z }))).to_unitary_matrix() cirq.testing.assert_allclose_up_to_global_phase( mat, np.diag([1, -1, -1, 1, -1, 1, 1, -1]), rtol=1e-7, atol=1e-7) mat = cirq.Circuit.from_ops( PauliStringPhasor(PauliString({ q0: Pauli.Z, q1: Pauli.Y, q2: Pauli.X }))**0.5).to_unitary_matrix() cirq.testing.assert_allclose_up_to_global_phase( mat, np.array([ [1, 0, 0, -1, 0, 0, 0, 0], [0, 1, -1, 0, 0, 0, 0, 0], [0, 1, 1, 0, 0, 0, 0, 0], [1, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 1], [0, 0, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, -1, 1, 0], [0, 0, 0, 0, -1, 0, 0, 1], ]) / np.sqrt(2), rtol=1e-7, atol=1e-7)
def test_decompose_with_symbol(): q0, = _make_qubits(1) ps = PauliString({q0: Pauli.Y}) op = PauliStringPhasor(ps, half_turns=cirq.value.Symbol('a')) circuit = cirq.Circuit.from_ops(op) cirq.ExpandComposite().optimize_circuit(circuit) assert circuit.to_text_diagram() == "q0: ───X^0.5───Z^a───X^-0.5───" ps = PauliString({q0: Pauli.Y}, True) op = PauliStringPhasor(ps, half_turns=cirq.value.Symbol('a')) circuit = cirq.Circuit.from_ops(op) cirq.ExpandComposite().optimize_circuit(circuit) assert circuit.to_text_diagram( ) == "q0: ───X^0.5───X───Z^a───X───X^-0.5───"
def test_map_qubits(): q0, q1, q2, q3 = _make_qubits(4) qubit_map = {q1: q2, q0: q3} before = PauliStringPhasor(PauliString({ q0: Pauli.Z, q1: Pauli.Y }), half_turns=0.1) after = PauliStringPhasor(PauliString({ q3: Pauli.Z, q2: Pauli.Y }), half_turns=0.1) assert before.map_qubits(qubit_map) == after
def test_drop_negligible(): q0, = _make_qubits(1) sym = cirq.value.Symbol('a') circuit = cirq.Circuit.from_ops( PauliStringPhasor(PauliString({q0: Pauli.Z}))**0.25, PauliStringPhasor(PauliString({q0: Pauli.Z}))**1e-10, PauliStringPhasor(PauliString({q0: Pauli.Z}))**sym, ) expected = cirq.Circuit.from_ops( PauliStringPhasor(PauliString({q0: Pauli.Z}))**0.25, PauliStringPhasor(PauliString({q0: Pauli.Z}))**sym, ) cirq.DropNegligible().optimize_circuit(circuit) cirq.DropEmptyMoments().optimize_circuit(circuit) assert circuit == expected
def test_default_decompose(paulis, half_turns, neg): paulis = [pauli for pauli in paulis if pauli is not None] qubits = _make_qubits(len(paulis)) # Get matrix from decomposition pauli_string = PauliString({q: p for q, p in zip(qubits, paulis)}, neg) actual = cirq.Circuit.from_ops( PauliStringPhasor(pauli_string, half_turns=half_turns)).to_unitary_matrix() # Calculate expected matrix to_z_mats = { Pauli.X: (cirq.Y**-0.5).matrix(), Pauli.Y: (cirq.X**0.5).matrix(), Pauli.Z: np.eye(2) } expected_convert = np.eye(1) for pauli in paulis: expected_convert = np.kron(expected_convert, to_z_mats[pauli]) t = 1j**(half_turns * 2 * (-1 if neg else 1)) expected_z = np.diag([1, t, t, 1, t, 1, 1, t][:2**len(paulis)]) expected = expected_convert.T.conj().dot(expected_z).dot(expected_convert) cirq.testing.assert_allclose_up_to_global_phase(actual, expected, rtol=1e-7, atol=1e-7)
def pauli_string_to_z_ops( pauli_string: PauliString) -> Iterable[ops.Operation]: """Yields the single qubit operations to apply before a Pauli string of Zs (and apply the inverse of these operations after) to make it equivalent to the given pauli_string.""" for qubit, pauli in pauli_string.items(): yield CliffordGate.from_single_map({pauli: (Pauli.Z, False)})(qubit)
def test_str(): q0, q1, q2 = _make_qubits(3) ps = PauliStringPhasor( PauliString({ q2: Pauli.Z, q1: Pauli.Y, q0: Pauli.X }, False))**0.5 assert (str(ps) == '{+, q0:X, q1:Y, q2:Z}**0.5') ps = PauliStringPhasor( PauliString({ q2: Pauli.Z, q1: Pauli.Y, q0: Pauli.X }, True))**-0.5 assert (str(ps) == '{-, q0:X, q1:Y, q2:Z}**-0.5')
def test_getitem(qubit_pauli_map): other = cirq.NamedQubit('other') pauli_string = PauliString(qubit_pauli_map) for key in qubit_pauli_map: assert qubit_pauli_map[key] == pauli_string[key] with pytest.raises(KeyError): _ = qubit_pauli_map[other] with pytest.raises(KeyError): _ = pauli_string[other]
def test_repr(): q0, q1, q2 = _make_qubits(3) ps = PauliStringPhasor(PauliString({ q2: Pauli.Z, q1: Pauli.Y, q0: Pauli.X }))**0.5 assert ( repr(ps) == 'PauliStringPhasor({+, q0:X, q1:Y, q2:Z}, half_turns=0.5)') ps = PauliStringPhasor( PauliString({ q2: Pauli.Z, q1: Pauli.Y, q0: Pauli.X }, True))**-0.5 assert (repr(ps) == 'PauliStringPhasor({-, q0:X, q1:Y, q2:Z}, half_turns=-0.5)')
def test_negate(): q0, q1 = _make_qubits(2) qubit_pauli_map = {q0: Pauli.X, q1: Pauli.Y} ps1 = PauliString(qubit_pauli_map) ps2 = PauliString(qubit_pauli_map, True) assert ps1.negate() == -ps1 == ps2 assert ps1 == ps2.negate() == -ps2 assert ps1.negate().negate() == ps1
def test_try_cast_to(): class Dummy: pass op = PauliStringPhasor(PauliString({})) ext = cirq.Extensions() assert not op.try_cast_to(cirq.CompositeOperation, ext) is None assert not op.try_cast_to(cirq.BoundedEffect, ext) is None assert not op.try_cast_to(cirq.ParameterizableEffect, ext) is None assert not op.try_cast_to(cirq.ExtrapolatableEffect, ext) is None assert not op.try_cast_to(cirq.ReversibleEffect, ext) is None assert op.try_cast_to(Dummy, ext) is None op = PauliStringPhasor(PauliString({}), half_turns=cirq.value.Symbol('a')) ext = cirq.Extensions() assert not op.try_cast_to(cirq.CompositeOperation, ext) is None assert not op.try_cast_to(cirq.BoundedEffect, ext) is None assert not op.try_cast_to(cirq.ParameterizableEffect, ext) is None assert op.try_cast_to(cirq.ExtrapolatableEffect, ext) is None assert op.try_cast_to(cirq.ReversibleEffect, ext) is None assert op.try_cast_to(Dummy, ext) is None
def test_text_diagram(): q0, q1, q2 = _make_qubits(3) circuit = cirq.Circuit.from_ops( PauliStringPhasor(PauliString({q0: Pauli.Z})), PauliStringPhasor(PauliString({q0: Pauli.Y}))**0.25, PauliStringPhasor(PauliString({ q0: Pauli.Z, q1: Pauli.Z, q2: Pauli.Z })), PauliStringPhasor( PauliString({ q0: Pauli.Z, q1: Pauli.Y, q2: Pauli.X }, True))**0.5, PauliStringPhasor(PauliString({ q0: Pauli.Z, q1: Pauli.Y, q2: Pauli.X }), half_turns=cirq.value.Symbol('a')), PauliStringPhasor(PauliString({ q0: Pauli.Z, q1: Pauli.Y, q2: Pauli.X }, True), half_turns=cirq.value.Symbol('b'))) assert circuit.to_text_diagram() == """ q0: ───[Z]───[Y]^0.25───[Z]───[Z]────────[Z]─────[Z]────── │ │ │ │ q1: ────────────────────[Z]───[Y]────────[Y]─────[Y]────── │ │ │ │ q2: ────────────────────[Z]───[X]^-0.5───[X]^a───[X]^-b─── """.strip()
def test_default_text_diagram(): class DiagramGate(PauliStringGateOperation, cirq.TextDiagrammable): def map_qubits(self, qubit_map): pass def text_diagram_info( self, args: cirq.TextDiagramInfoArgs) -> cirq.TextDiagramInfo: return self._pauli_string_diagram_info(args) q0, q1, q2 = _make_qubits(3) ps = PauliString({q0: Pauli.X, q1: Pauli.Y, q2: Pauli.Z}) circuit = cirq.Circuit.from_ops( DiagramGate(ps), DiagramGate(ps.negate()), ) assert circuit.to_text_diagram() == """ q0: ───[X]───[X]─── │ │ q1: ───[Y]───[Y]─── │ │ q2: ───[Z]───[Z]─── """.strip()
def test_eq_ne_hash(): q0, q1, q2 = _make_qubits(3) eq = EqualsTester() eq.make_equality_group(lambda: PauliString({}), lambda: PauliString({}, False)) eq.add_equality_group(PauliString({}, True)) for q, pauli in itertools.product((q0, q1), Pauli.XYZ): eq.add_equality_group(PauliString({q: pauli}, False)) eq.add_equality_group(PauliString({q: pauli}, True)) for q, p0, p1 in itertools.product((q0, q1), Pauli.XYZ, Pauli.XYZ): eq.add_equality_group(PauliString({q: p0, q2: p1}, False))
def test_on_wrong_number_qubits(): q0, q1, q2 = _make_qubits(3) class DummyGate(PauliStringGateOperation): def map_qubits(self, qubit_map): ps = self.pauli_string.map_qubits(qubit_map) return DummyGate(ps) g = DummyGate(PauliString({q0: Pauli.X, q1: Pauli.Y})) _ = g.with_qubits(q1, q2) with pytest.raises(ValueError): _ = g.with_qubits() with pytest.raises(ValueError): _ = g.with_qubits(q2) with pytest.raises(ValueError): _ = g.with_qubits(q0, q1, q2)
def test_op_calls_validate(): q0, q1, q2 = _make_qubits(3) bad_qubit = cirq.NamedQubit('bad') class ValidError(Exception): pass class ValiGate(PauliStringGateOperation): def validate_args(self, qubits): super().validate_args(qubits) if bad_qubit in qubits: raise ValidError() def map_qubits(self, qubit_map): ps = self.pauli_string.map_qubits(qubit_map) return ValiGate(ps) g = ValiGate(PauliString({q0: Pauli.X, q1: Pauli.Y, q2: Pauli.Z})) _ = g.with_qubits(q1, q0, q2) with pytest.raises(ValidError): _ = g.with_qubits(q0, q1, bad_qubit)
def test_extrapolate_effect_with_symbol(): eq = cirq.testing.EqualsTester() eq.add_equality_group( PauliStringPhasor(PauliString({}), half_turns=cirq.value.Symbol('a')), PauliStringPhasor(PauliString({}))**cirq.value.Symbol('a')) eq.add_equality_group( PauliStringPhasor(PauliString({}))**cirq.value.Symbol('b')) with pytest.raises(ValueError): _ = PauliStringPhasor(PauliString({}), half_turns=0.5)**cirq.value.Symbol('b') with pytest.raises(ValueError): _ = PauliStringPhasor(PauliString({}), half_turns=cirq.value.Symbol('a'))**0.5 with pytest.raises(ValueError): _ = PauliStringPhasor( PauliString({}), half_turns=cirq.value.Symbol('a'))**cirq.value.Symbol('b')
def test_inverse(): op1 = PauliStringPhasor(PauliString({}), half_turns=0.25) op2 = PauliStringPhasor(PauliString({}), half_turns=-0.25) assert op1.inverse() == op2
def test_extrapolate_effect(): op1 = PauliStringPhasor(PauliString({}), half_turns=0.5) op2 = PauliStringPhasor(PauliString({}), half_turns=1.5) op3 = PauliStringPhasor(PauliString({}), half_turns=0.125) assert op1**3 == op2 assert op1**0.25 == op3
def test_eq_ne_hash(): q0, q1, q2 = _make_qubits(3) eq = cirq.testing.EqualsTester() ps1 = PauliString({q0: Pauli.X, q1: Pauli.Y, q2: Pauli.Z}) ps2 = PauliString({q0: Pauli.X, q1: Pauli.Y, q2: Pauli.X}) eq.make_equality_group( lambda: PauliStringPhasor(PauliString({}), half_turns=0.5), lambda: PauliStringPhasor(PauliString({}), half_turns=-1.5), lambda: PauliStringPhasor(PauliString({}), half_turns=2.5)) eq.make_equality_group( lambda: PauliStringPhasor(PauliString({}, True), half_turns=-0.5)) eq.add_equality_group(PauliStringPhasor(ps1), PauliStringPhasor(ps1, half_turns=1)) eq.add_equality_group(PauliStringPhasor(ps1.negate(), half_turns=1)) eq.add_equality_group(PauliStringPhasor(ps2), PauliStringPhasor(ps2, half_turns=1)) eq.add_equality_group(PauliStringPhasor(ps2.negate(), half_turns=1)) eq.add_equality_group(PauliStringPhasor(ps2, half_turns=0.5)) eq.add_equality_group(PauliStringPhasor(ps2.negate(), half_turns=-0.5)) eq.add_equality_group( PauliStringPhasor(ps1, half_turns=cirq.value.Symbol('a')))
def test_from_single(pauli): q0, = _make_qubits(1) assert PauliString.from_single(q0, pauli) == PauliString({q0: pauli})
def test_contains(qubit_pauli_map): other = cirq.NamedQubit('other') pauli_string = PauliString(qubit_pauli_map) for key in qubit_pauli_map: assert key in pauli_string assert other not in pauli_string
def test_keys(qubit_pauli_map): pauli_string = PauliString(qubit_pauli_map) assert (len(qubit_pauli_map.keys()) == len(pauli_string.keys()) == len( pauli_string.qubits())) assert (set(qubit_pauli_map.keys()) == set(pauli_string.keys()) == set( pauli_string.qubits()))
def test_with_parameters_resolved_by(): op = PauliStringPhasor(PauliString({}), half_turns=cirq.value.Symbol('a')) resolver = cirq.study.ParamResolver({'a': 0.1}) actual = op.with_parameters_resolved_by(resolver) expected = PauliStringPhasor(PauliString({}), half_turns=0.1) assert actual == expected
def test_is_parametrized(): op = PauliStringPhasor(PauliString({})) assert not op.is_parameterized() assert not (op**0.1).is_parameterized() assert (op**cirq.value.Symbol('a')).is_parameterized()