Beispiel #1
0
def test_convert_to_sycamore_gates_swap_zz():
    qubits = cirq.LineQubit.range(3)

    gamma = np.random.randn()
    circuit1 = cirq.Circuit(cirq.SWAP(qubits[0], qubits[1]),
                            cirq.Z(qubits[2]),
                            cirq.ZZ(qubits[0], qubits[1])**gamma,
                            strategy=cirq.InsertStrategy.NEW)
    circuit2 = cirq.Circuit(cirq.ZZ(qubits[0], qubits[1])**gamma,
                            cirq.Z(qubits[2]),
                            cirq.SWAP(qubits[0], qubits[1]),
                            strategy=cirq.InsertStrategy.NEW)

    compiled_circuit1 = circuit1.copy()
    cgoc.ConvertToSycamoreGates()(compiled_circuit1)
    compiled_circuit2 = circuit2.copy()
    cgoc.ConvertToSycamoreGates()(compiled_circuit2)

    cirq.testing.assert_same_circuits(compiled_circuit1, compiled_circuit2)
    assert len(
        list(
            compiled_circuit1.findall_operations_with_gate_type(
                cirq.google.SycamoreGate))) == 3
    cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent(
        circuit1, compiled_circuit1, atol=1e-7)
Beispiel #2
0
def test_sycamore_gateset_compiles_swap_zz():
    qubits = cirq.LineQubit.range(3)

    gamma = np.random.randn()
    circuit1 = cirq.Circuit(
        cirq.SWAP(qubits[0], qubits[1]),
        cirq.Z(qubits[2]),
        cirq.ZZ(qubits[0], qubits[1])**gamma,
        strategy=cirq.InsertStrategy.NEW,
    )
    circuit2 = cirq.Circuit(
        cirq.ZZ(qubits[0], qubits[1])**gamma,
        cirq.Z(qubits[2]),
        cirq.SWAP(qubits[0], qubits[1]),
        strategy=cirq.InsertStrategy.NEW,
    )
    gateset = cirq_google.SycamoreTargetGateset()
    compiled_circuit1 = cirq.optimize_for_target_gateset(circuit1,
                                                         gateset=gateset)
    compiled_circuit2 = cirq.optimize_for_target_gateset(circuit2,
                                                         gateset=gateset)
    cirq.testing.assert_same_circuits(compiled_circuit1, compiled_circuit2)
    assert (len(
        list(
            compiled_circuit1.findall_operations_with_gate_type(
                cirq_google.SycamoreGate))) == 3)
    cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent(
        circuit1, compiled_circuit1, atol=1e-7)
def test_convert_to_sycamore_gates_swap_zz():
    qubits = cirq.LineQubit.range(3)

    gamma = np.random.randn()
    circuit1 = cirq.Circuit(
        cirq.SWAP(qubits[0], qubits[1]),
        cirq.Z(qubits[2]),
        cirq.ZZ(qubits[0], qubits[1]) ** gamma,
        strategy=cirq.InsertStrategy.NEW,
    )
    circuit2 = cirq.Circuit(
        cirq.ZZ(qubits[0], qubits[1]) ** gamma,
        cirq.Z(qubits[2]),
        cirq.SWAP(qubits[0], qubits[1]),
        strategy=cirq.InsertStrategy.NEW,
    )

    compiled_circuit1 = circuit1.copy()
    with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'):
        cgoc.ConvertToSycamoreGates()(compiled_circuit1)
    compiled_circuit2 = circuit2.copy()
    with cirq.testing.assert_deprecated("Use cirq.optimize_for_target_gateset", deadline='v1.0'):
        cgoc.ConvertToSycamoreGates()(compiled_circuit2)

    cirq.testing.assert_same_circuits(compiled_circuit1, compiled_circuit2)
    assert (
        len(list(compiled_circuit1.findall_operations_with_gate_type(cirq_google.SycamoreGate)))
        == 3
    )
    cirq.testing.assert_circuits_with_terminal_measurements_are_equivalent(
        circuit1, compiled_circuit1, atol=1e-7
    )
Beispiel #4
0
def test_merge_swap_rzz_and_2q_unitaries():
    q = cirq.LineQubit.range(3)
    c_orig = cirq.Circuit(
        cirq.SWAP(*q[:2]),
        cirq.ZZ(*q[:2]) ** 0.5,
        cirq.ZZ(*q[:2]) ** 0.25,
        cirq.SWAP(*q[:2]),
        cirq.SWAP(q[0], q[2]).with_tags("ignore"),
        cirq.ZZ(q[0], q[2]) ** 0.75,
        cirq.Moment(cirq.H.on_each(*q)),
        cirq.CNOT(q[0], q[2]),
        cirq.CircuitOperation(
            cirq.FrozenCircuit(
                cirq.CNOT(*q[0:2]),
                cirq.H(q[0]),
                cirq.CZ(*q[:2]),
            )
        ),
        cirq.CNOT(*q[1:3]),
        cirq.X(q[0]),
        cirq.ZZ(*q[:2]) ** 0.15,
        cirq.SWAP(*q[:2]),
        cirq.Moment(cirq.X(q[0]).with_tags("ignore"), cirq.Y(q[1])),
        cirq.CNOT(*q[:2]),
        strategy=cirq.InsertStrategy.NEW,
    )
    cirq.testing.assert_has_diagram(
        c_orig,
        '''
                                                                 [ 0: ───@───H───@─── ]
0: ───×───ZZ───────ZZ────────×───×['ignore']───ZZ────────H───@───[       │       │    ]───────X───ZZ────────×───X['ignore']───@───
      │   │        │         │   │             │             │   [ 1: ───X───────@─── ]           │         │                 │
      │   │        │         │   │             │             │   │                                │         │                 │
1: ───×───ZZ^0.5───ZZ^0.25───×───┼─────────────┼─────────H───┼───#2───────────────────────@───────ZZ^0.15───×───Y─────────────X───
                                 │             │             │                            │
2: ──────────────────────────────×─────────────ZZ^0.75───H───X────────────────────────────X───────────────────────────────────────
''',
    )

    c_new = sycamore_gateset.merge_swap_rzz_and_2q_unitaries(
        c_orig,
        context=cirq.TransformerContext(tags_to_ignore=("ignore",)),
        merged_swap_rzz_tag='swap_rzz',
        merged_2q_component_tag='2q_component',
    )
    cirq.testing.assert_has_diagram(
        c_new,
        '''
                                                                                                                                                                [           [ 0: ───@───H───@─── ]        ]
      [ 0: ───×───ZZ─────── ]                   [ 0: ───ZZ────────×─── ]                                 [ 0: ───ZZ────────H───@─── ]                           [ 0: ───────[       │       │    ]───X─── ]                           [ 0: ───ZZ────────×─── ]                                 [ 0: ───────@─── ]
0: ───[       │   │         ]───────────────────[       │         │    ]───────────────────×['ignore']───[       │             │    ]───────────────────────────[           [ 1: ───X───────@─── ]        ]───────────────────────────[       │         │    ]───────────────────X['ignore']───[           │    ]───────────────────
      [ 1: ───×───ZZ^0.5─── ]['swap_rzz']       [ 1: ───ZZ^0.25───×─── ]['swap_rzz']       │             [ 2: ───ZZ^0.75───H───X─── ]['2q_component']           [           │                             ]                           [ 1: ───ZZ^0.15───×─── ]['swap_rzz']                     [ 1: ───Y───X─── ]['2q_component']
      │                                         │                                          │             │                                                      [ 1: ───H───#2─────────────────────────── ]['2q_component']           │                                                        │
      │                                         │                                          │             │                                                      │                                                                     │                                                        │
1: ───#2────────────────────────────────────────#2─────────────────────────────────────────┼─────────────┼──────────────────────────────────────────────────────#2────────────────────────────────────────────────────────────@───────#2───────────────────────────────────────────────────────#2───────────────────────────────────
                                                                                           │             │                                                                                                                    │
2: ────────────────────────────────────────────────────────────────────────────────────────×─────────────#2───────────────────────────────────────────────────────────────────────────────────────────────────────────────────X─────────────────────────────────────────────────────────────────────────────────────────────────────
''',
    )
Beispiel #5
0
def test_zz_diagrams():
    a = cirq.NamedQubit('a')
    b = cirq.NamedQubit('b')
    circuit = cirq.Circuit(cirq.ZZ(a, b), cirq.ZZ(a, b)**3, cirq.ZZ(a, b)**0.5)
    cirq.testing.assert_has_diagram(
        circuit,
        """
a: ───ZZ───ZZ───ZZ───────
      │    │    │
b: ───ZZ───ZZ───ZZ^0.5───
""",
    )
Beispiel #6
0
def test_zz_swap():
    q1, q2 = cirq.LineQubit.range(2)
    circuit1 = cirq.Circuit(ZZSwap(zz_exponent=0.123).on(q1, q2))
    u1 = circuit1.unitary()
    circuit2 = cirq.Circuit(cirq.ZZ(q1, q2)**0.123, cirq.SWAP(q1, q2))
    u2 = circuit2.unitary()
    circuit3 = cirq.Circuit(cirq.SWAP(q1, q2), cirq.ZZ(q1, q2)**0.123)
    u3 = circuit3.unitary()

    np.testing.assert_allclose(u1, u2)
    np.testing.assert_allclose(u2, u3)
    np.testing.assert_allclose(u3, u1)
Beispiel #7
0
def test_get_logical_operations():
    a, b, c, d = qubits = cirq.LineQubit.range(4)
    mapping = dict(zip(qubits, qubits))
    operations = [
        cirq.ZZ(a, b),
        cca.SwapPermutationGate()(b, c),
        cirq.SWAP(a, b),
        cca.SwapPermutationGate()(c, d),
        cca.SwapPermutationGate()(b, c),
        cirq.ZZ(a, b)
    ]
    assert list(cca.get_logical_operations(operations, mapping)) == [
        cirq.ZZ(a, b), cirq.SWAP(a, c),
        cirq.ZZ(a, d)
    ]
    def test_time_evolution(self):
        # Given
        hamiltonian = PauliSum([
            PauliTerm('X', 0) * PauliTerm('X', 1),
            PauliTerm('Y', 0, 0.5) * PauliTerm('Y', 1),
            PauliTerm('Z', 0, 0.3) * PauliTerm('Z', 1)
        ])
        time = 0.4
        order = 2

        circuit = cirq.Circuit()
        q1 = cirq.LineQubit(0)
        q2 = cirq.LineQubit(1)
        for _ in range(0, order):
            circuit.append(
                cirq.XX(q1, q2)**(hamiltonian.terms[0].coefficient * 2 * time /
                                  order / pi))
            circuit.append(
                cirq.YY(q1, q2)**(hamiltonian.terms[1].coefficient * 2 * time /
                                  order / pi))
            circuit.append(
                cirq.ZZ(q1, q2)**(hamiltonian.terms[2].coefficient * 2 * time /
                                  order / pi))
        u = circuit._unitary_()

        #When
        unitary_evolution = time_evolution(hamiltonian,
                                           time,
                                           trotter_order=order)
        u1 = unitary_evolution.to_unitary()

        # Then
        self.assertEqual(compare_unitary(u1, u, tol=1e-10), True)
Beispiel #9
0
def cost_circuit(gamma):
    """
    returns circuit for evolution with cost Hamiltonian
    """
    for ii in range(N):
        for jj in range(ii + 1, N):
            yield cirq.ZZ(qubits[ii], qubits[jj])**(gamma * J[ii, jj])
Beispiel #10
0
def test_merge_swap_rzz_and_2q_unitaries_deep():
    q = cirq.LineQubit.range(3)
    swap_rzz = cirq.FrozenCircuit(cirq.SWAP(*q[:2]), cirq.ZZ(*q[:2]) ** 0.5)
    rzz_swap = cirq.FrozenCircuit(cirq.ZZ(*q[1:]) ** 0.25, cirq.SWAP(*q[1:]))
    x_cnot_x = cirq.FrozenCircuit(cirq.X(q[0]), cirq.CNOT(*q[:2]), cirq.X(q[0]))
    x_cz_x = cirq.FrozenCircuit(cirq.X(q[2]), cirq.CZ(*q[1:]), cirq.X(q[2]))
    c_orig = cirq.Circuit(
        cirq.CircuitOperation(swap_rzz).repeat(3).with_tags("ignore"),
        cirq.CircuitOperation(rzz_swap).repeat(5).with_tags("preserve_tag"),
        cirq.CircuitOperation(x_cnot_x).repeat(7).with_tags("ignore"),
        cirq.CircuitOperation(x_cz_x).repeat(9).with_tags("preserve_tag"),
        cirq.CircuitOperation(
            cirq.FrozenCircuit(
                [swap_rzz, rzz_swap, x_cnot_x, x_cz_x],
                cirq.Moment(cirq.Y(qq).with_tags("ignore") for qq in q),
            )
        ),
    )
    t_swap_rzz = "_merged_swap_rzz_tag"
    t_2q_cmp = "_merged_2q_unitaries_component"
    t_all = "_intermediate_result_tag_apply_to_all"

    def _wrap_cop(c: cirq.FrozenCircuit, *tags) -> cirq.FrozenCircuit:
        return cirq.FrozenCircuit(cirq.CircuitOperation(c).with_tags(*tags, t_all))

    c_expected = cirq.Circuit(
        cirq.CircuitOperation(swap_rzz).repeat(3).with_tags("ignore"),
        cirq.CircuitOperation(_wrap_cop(rzz_swap, t_swap_rzz)).repeat(5).with_tags("preserve_tag"),
        cirq.CircuitOperation(x_cnot_x).repeat(7).with_tags("ignore"),
        cirq.CircuitOperation(_wrap_cop(x_cz_x, t_2q_cmp)).repeat(9).with_tags("preserve_tag"),
        cirq.CircuitOperation(
            cirq.FrozenCircuit(
                [_wrap_cop(swap_rzz, t_swap_rzz), _wrap_cop(rzz_swap, t_swap_rzz)],
                [_wrap_cop(x_cnot_x, t_2q_cmp), _wrap_cop(x_cz_x, t_2q_cmp)],
                cirq.Moment(cirq.Y(qq).with_tags("ignore") for qq in q),
            )
        ),
    )
    context = cirq.TransformerContext(tags_to_ignore=["ignore"], deep=True)
    c_new = sycamore_gateset.merge_swap_rzz_and_2q_unitaries(
        c_orig,
        context=context,
        merged_swap_rzz_tag=t_swap_rzz,
        merged_2q_component_tag=t_2q_cmp,
        intermediate_result_tag=t_all,
    )
    cirq.testing.assert_same_circuits(cirq.drop_empty_moments(c_new, context=context), c_expected)
Beispiel #11
0
def test_ops_are_consistent_with_device_graph():
    device_graph = ccr.get_linear_device_graph(3)
    qubits = cirq.LineQubit.range(3)
    circuit = cirq.Circuit(cirq.ZZ(qubits[0], qubits[2]))
    assert not ccr.ops_are_consistent_with_device_graph(
        circuit.all_operations(), device_graph)
    assert not ccr.ops_are_consistent_with_device_graph(
        [cirq.X(cirq.GridQubit(0, 0))], device_graph)
Beispiel #12
0
 def _rot_zz_layer(self, gamma: float, with_noise: bool
                   ) -> Iterator[cirq.OP_TREE]:
     if with_noise:
         j_s = self._couplings.copy()
     else:
         j_s = self._noiseless_j.copy()
     for i, j_i in enumerate(j_s):
         yield cirq.ZZ(self._qubit_list[i],
                       self._qubit_list[(i + 1) % self._num_qubits]
                       ) ** (j_i * gamma / 2.0)
Beispiel #13
0
def two_qubit_unitary(bits, symbols):
    """Make a Cirq circuit that creates an arbitrary two qubit unitary."""
    circuit = cirq.Circuit()
    circuit += one_qubit_unitary(bits[0], symbols[0:3])
    circuit += one_qubit_unitary(bits[1], symbols[3:6])
    circuit += [cirq.ZZ(*bits)**symbols[6]]
    circuit += [cirq.YY(*bits)**symbols[7]]
    circuit += [cirq.XX(*bits)**symbols[8]]
    circuit += one_qubit_unitary(bits[0], symbols[9:12])
    circuit += one_qubit_unitary(bits[1], symbols[12:])
    return circuit
Beispiel #14
0
def random_qaoa_circuit(length, depth=1, βγs=None):
    """qaoa_circuit: qaoa circuit with qubits - useful for testing.
    """
    βγs = [[(randn(), randn()) for _ in range(length)]
           for _ in range(depth)] if βγs is None else βγs

    qubits = cirq.LineQubit.range(length)
    c =  cirq.Circuit().from_ops([[[cirq.X(qubit)**β for qubit in qubits]+\
                                   [cirq.ZZ(qubits[i], qubits[i+1])**γ for i in range(len(qubits)-1)]
                                   for β, γ in βγs[i]] for i in range(depth)])
    return c
def _all_operations(q0, q1, q2, q3, q4, include_measurements=True):
    return (
        cirq.Z(q0),
        cirq.Z(q0)**0.625,
        cirq.Y(q0),
        cirq.Y(q0)**0.375,
        cirq.X(q0),
        cirq.X(q0)**0.875,
        cirq.H(q1),
        cirq.CZ(q0, q1),
        cirq.CZ(q0, q1)**0.25,  # Requires 2-qubit decomposition
        cirq.CNOT(q0, q1),
        cirq.CNOT(q0, q1)**0.5,  # Requires 2-qubit decomposition
        cirq.SWAP(q0, q1),
        cirq.SWAP(q1, q0)**-1,
        cirq.SWAP(q0, q1)**0.75,  # Requires 2-qubit decomposition
        cirq.CCZ(q0, q1, q2),
        cirq.CCX(q0, q1, q2),
        cirq.CCZ(q0, q1, q2)**0.5,
        cirq.CCX(q0, q1, q2)**0.5,
        cirq.CSWAP(q0, q1, q2),
        cirq.XX(q0, q1),
        cirq.XX(q0, q1)**0.75,
        cirq.YY(q0, q1),
        cirq.YY(q0, q1)**0.75,
        cirq.ZZ(q0, q1),
        cirq.ZZ(q0, q1)**0.75,
        cirq.IdentityGate(1).on(q0),
        cirq.IdentityGate(3).on(q0, q1, q2),
        cirq.ISWAP(q2, q0),  # Requires 2-qubit decomposition
        cirq.PhasedXPowGate(phase_exponent=0.111, exponent=0.25).on(q1),
        cirq.PhasedXPowGate(phase_exponent=0.333, exponent=0.5).on(q1),
        cirq.PhasedXPowGate(phase_exponent=0.777, exponent=-0.5).on(q1),
        cirq.wait(q0, nanos=0),
        cirq.measure(q0, key='xX'),
        cirq.measure(q2, key='x_a'),
        cirq.measure(q3, key='X'),
        cirq.measure(q2, key='x_a'),
        cirq.measure(q1, q2, q3, key='multi', invert_mask=(False, True)),
    )
Beispiel #16
0
def two_qubit_unitary(bits, symbols):
    """Make a Cirq circuit that creates an arbitrary two qubit unitary.
    Bits: 2
    Symbols: 15
    """
    # Corollary 6 of https://arxiv.org/pdf/quant-ph/0507171.pdf
    circuit = cirq.Circuit()
    circuit += one_qubit_unitary(bits[0], symbols[0:3])
    circuit += one_qubit_unitary(bits[1], symbols[3:6])
    circuit += [cirq.ZZ(*bits)**symbols[6]]
    circuit += [cirq.YY(*bits)**symbols[7]]
    circuit += [cirq.XX(*bits)**symbols[8]]
    circuit += one_qubit_unitary(bits[0], symbols[9:12])
    circuit += one_qubit_unitary(bits[1], symbols[12:])
    return circuit
Beispiel #17
0
    def test_time_evolution_with_symbolic_parameter(self):
        # Given
        hamiltonian = PauliSum([
            PauliTerm("X", 0) * PauliTerm("X", 1),
            PauliTerm("Y", 0, 0.5) * PauliTerm("Y", 1),
            PauliTerm("Z", 0, 0.3) * PauliTerm("Z", 1),
        ])
        time_symbol = sympy.Symbol("t")
        time_value = 0.4
        symbols_map = [(time_symbol, time_value)]
        order = 2

        circuit = cirq.Circuit()
        q1 = cirq.LineQubit(0)
        q2 = cirq.LineQubit(1)
        for _ in range(0, order):
            circuit.append(
                cirq.XX(q1, q2)**(hamiltonian.terms[0].coefficient * 2 *
                                  time_value / order / pi))
            circuit.append(
                cirq.YY(q1, q2)**(hamiltonian.terms[1].coefficient * 2 *
                                  time_value / order / pi))
            circuit.append(
                cirq.ZZ(q1, q2)**(hamiltonian.terms[2].coefficient * 2 *
                                  time_value / order / pi))
        target_unitary = circuit._unitary_()

        # When
        unitary_evolution_symbolic = time_evolution(hamiltonian,
                                                    time_symbol,
                                                    trotter_order=order)
        unitary_evolution = unitary_evolution_symbolic.evaluate(symbols_map)
        final_unitary = unitary_evolution.to_unitary()
        # Then
        self.assertEqual(
            compare_unitary(final_unitary, target_unitary, tol=1e-10), True)
Beispiel #18
0
def _swap_and_zz(q_0: cirq.GridQubit, q_1: cirq.GridQubit,
                 zz_coeff: float) -> List[cirq.Gate]:
    gate_seq = [cirq.SWAP(q_0, q_1)]
    if zz_coeff != 0:
        gate_seq.append(cirq.ZZ(q_0, q_1)**zz_coeff)
    return gate_seq
Beispiel #19
0
     'X': np.sqrt(0.5),
     'Y': np.sqrt(0.5),
     'Z': np.sqrt(0.5)
 }),
 ({
     cirq.Y(q0): np.sqrt(0.5),
     cirq.H(q2): 1
 }, {
     'IX': np.sqrt(0.5),
     'YI': np.sqrt(0.5),
     'IZ': np.sqrt(0.5)
 }),
 ({
     cirq.XX(q0, q1): -2,
     cirq.YY(q0, q1): 3j,
     cirq.ZZ(q0, q1): 4
 }, {
     'XX': -2,
     'YY': 3j,
     'ZZ': 4
 }),
 ({
     cirq.XX(q0, q1): -2,
     cirq.YY(q0, q2): 3j,
     cirq.ZZ(q1, q2): 4
 }, {
     'XXI': -2,
     'YIY': 3j,
     'IZZ': 4
 }),
 ({
Beispiel #20
0
def test_cirq_to_circuit() -> None:
    q0 = cq.LineQubit(0)
    q1 = cq.LineQubit(1)
    q2 = cq.LineQubit(2)

    gate = cirq_to_circuit(cq.Circuit(cq.X(q0)))[0]
    assert isinstance(gate, qf.X)
    assert gate.qubits == (0, )

    gate = cirq_to_circuit(cq.Circuit(cq.X(q1)**0.4))[0]
    assert isinstance(gate, qf.XPow)
    assert gate.qubits == (1, )

    gate = cirq_to_circuit(cq.Circuit(cq.CZ(q1, q0)))[0]
    assert isinstance(gate, qf.CZ)
    assert gate.qubits == (1, 0)

    gate = cirq_to_circuit(cq.Circuit(cq.CZ(q1, q0)**0.3))[0]
    assert isinstance(gate, qf.CZPow)
    assert gate.qubits == (1, 0)
    assert gate.param("t") == 0.3

    gate = cirq_to_circuit(cq.Circuit(cq.CNOT(q0, q1)))[0]
    assert isinstance(gate, qf.CNot)
    assert gate.qubits == (0, 1)

    gate = cirq_to_circuit(cq.Circuit(cq.CNOT(q0, q1)**0.25))[0]
    assert isinstance(gate, qf.CNotPow)
    assert gate.qubits == (0, 1)
    assert gate.param("t") == 0.25

    gate = cirq_to_circuit(cq.Circuit(cq.SWAP(q0, q1)))[0]
    assert isinstance(gate, qf.Swap)

    gate = cirq_to_circuit(cq.Circuit(cq.ISWAP(q0, q1)))[0]
    assert isinstance(gate, qf.ISwap)

    gate = cirq_to_circuit(cq.Circuit(cq.CSWAP(q0, q1, q2)))[0]
    assert isinstance(gate, qf.CSwap)

    gate = cirq_to_circuit(cq.Circuit(cq.CCX(q0, q1, q2)))[0]
    assert isinstance(gate, qf.CCNot)

    gate = cirq_to_circuit(cq.Circuit(cq.CCZ(q0, q1, q2)))[0]
    assert isinstance(gate, qf.CCZ)

    gate = cirq_to_circuit(cq.Circuit(cq.I(q0)))[0]
    assert isinstance(gate, qf.I)

    gate = cirq_to_circuit(cq.Circuit(cq.XX(q0, q2)))[0]
    assert isinstance(gate, qf.XX)
    assert gate.param("t") == 1.0

    gate = cirq_to_circuit(cq.Circuit(cq.XX(q0, q2)**0.3))[0]
    assert isinstance(gate, qf.XX)
    assert gate.param("t") == 0.3

    gate = cirq_to_circuit(cq.Circuit(cq.YY(q0, q2)))[0]
    assert isinstance(gate, qf.YY)
    assert gate.param("t") == 1.0

    gate = cirq_to_circuit(cq.Circuit(cq.YY(q0, q2)**0.3))[0]
    assert isinstance(gate, qf.YY)
    assert gate.param("t") == 0.3

    gate = cirq_to_circuit(cq.Circuit(cq.ZZ(q0, q2)))[0]
    assert isinstance(gate, qf.ZZ)
    assert gate.param("t") == 1.0

    gate = cirq_to_circuit(cq.Circuit(cq.ZZ(q0, q2)**0.3))[0]
    assert isinstance(gate, qf.ZZ)
    assert gate.param("t") == 0.3

    # Check that cirq's parity gates are the same as QF's XX, YY, ZZ
    # up to parity
    U = (cq.XX(q0, q2)**0.8)._unitary_()
    gate0 = qf.Unitary(U, [0, 1])
    assert qf.gates_close(gate0, qf.XX(0.8, 0, 1))

    U = (cq.YY(q0, q2)**0.3)._unitary_()
    gate0 = qf.Unitary(U, [0, 1])
    assert qf.gates_close(gate0, qf.YY(0.3, 0, 1))

    U = (cq.ZZ(q0, q2)**0.2)._unitary_()
    gate0 = qf.Unitary(U, [0, 1])
    assert qf.gates_close(gate0, qf.ZZ(0.2, 0, 1))
Beispiel #21
0
 def _z_layer_direct(self, gamma: float) -> List[cirq.Gate]:
     gate_seq = self._local_field_gates(gamma)
     for (l_0, l_1), val in self._interaction_terms.items():
         gate_seq.append(
             cirq.ZZ(self._qubits[l_0], self._qubits[l_1])**(val * gamma))
     return gate_seq
Beispiel #22
0
def xxz_chain(qubits, boundary_condition="closed", data_dir=None):
    """1D XXZ model quantum data set.

    $$
    H = \sum_{i} \sigma_i^x \sigma_{i+1}^x + \sigma_i^y \sigma_{i+1}^y +
    \Delta\sigma_i^z \sigma_{i+1}^z
    $$

    Contains 76 circuit parameterizations corresponding to
    the ground states of the 1D XXZ chain for g in [0.3,1.8].
    This dataset contains 76 datapoints. Each datapoint is represented by a
    circuit (`cirq.Circuit`), a label (Python `float`) a Hamiltonian
    (`cirq.PauliSum`) and some additional metadata. Each Hamiltonian in a
    datapoint is a 1D XXZ chain with boundary condition `boundary_condition` on
    `qubits` whos order parameter dictates the value of label. The circuit in a
    datapoint prepares (an approximation to) the ground state of the Hamiltonian
    in the datapoint.

    Example usage:

    >>> qbs = cirq.GridQubit.rect(4, 1)
    >>> circuits, labels, pauli_sums, addinfo  =
    ...     tfq.datasets.xxz_chain(qbs, "closed")

    You can print the available order parameters

    >>> [info.g for info in addinfo]
    [0.30, 0.32, 0.34, ... ,1.76, 1.78, 1.8]

    and the circuit corresponding to the ground state for a certain order
    parameter

    >>> print(circuits[10])
                           ┌──────────────────┐   ┌──────────────────┐
    (0, 0): ───X───H───@─────────────ZZ─────────────────────YY────────── ...
                       │             │                      │
    (1, 0): ───X───────X────ZZ───────┼─────────────YY───────┼─────────── ...
                            │        │             │        │
    (2, 0): ───X───H───@────ZZ^-0.922┼─────────────YY^-0.915┼─────────── ...
                       │             │                      │
    (3, 0): ───X───────X─────────────ZZ^-0.922──────────────YY^-0.915─── ...
                           └──────────────────┘   └──────────────────┘

    The labels indicate the phase of the system
    >>> labels[10]
    0

    Additionally, you can obtain the `cirq.PauliSum` representation of the
    Hamiltonian

    >>> print(pauli_sums[10])
    0.400*Z((0, 0))*Z((1, 0))+0.400*Z((1, 0))*Z((2, 0))+ ...
    +1.000*Y((0, 0))*Y((3, 0))+1.000*X((0, 0))*X((3, 0))

    The fourth output, `addinfo`, contains additional information
    about each instance of the system (see `tfq.datasets.spin_system.SpinSystem`
    ).

    For instance, you can print the ground state obtained from
    exact diagonalization

    >>> addinfo[10].gs
    [-8.69032854e-18-6.58023246e-20j  4.54546402e-17+3.08736567e-17j
     -9.51026525e-18+2.42638062e-17j  4.52284042e-02+3.18111120e-01j
                                    ...
      4.52284042e-02+3.18111120e-01j -6.57974275e-18-3.84526414e-17j
     -1.60673943e-17+5.79767820e-17j  2.86193021e-17-5.06694574e-17j]

    with corresponding ground state energy

    >>> addinfo[10].gs_energy
    -6.744562646538039

    You can also inspect the parameters

    >>> addinfo[10].params
    {'theta_0': 1.0780547, 'theta_1': 0.99271035, 'theta_2': 1.0854135, ...

    and change them to experiment with different parameter values by using
    the unresolved variational circuit returned by xxzchain
    >>> new_params = {}
    ... for symbol_name, value in addinfo[10].params.items():
    ...    new_params[symbol_name] = 0.5 * value
    >>> new_params
    {'theta_0': 0.5390273332595825, 'theta_1': 0.49635517597198486, ...
    >>> new_circuit = cirq.resolve_parameters(addinfo[10].var_circuit,
    ... new_params)
    >>> print(new_circuit)
                           ┌──────────────────┐   ┌──────────────────┐
    (0, 0): ───X───H───@─────────────ZZ─────────────────────YY────────── ...
                       │             │                      │
    (1, 0): ───X───────X────ZZ───────┼─────────────YY───────┼─────────── ...
                            │        │             │        │
    (2, 0): ───X───H───@────ZZ^(7/13)┼─────────────YY^0.543 ┼─────────── ...
                       │             │                      │
    (3, 0): ───X───────X─────────────ZZ^(7/13)──────────────YY^0.543 ─── ...
                           └──────────────────┘   └──────────────────┘
    Args:
        qubits: Python `lst` of `cirq.GridQubit`s. Supported number of spins
            are [4, 8, 12, 16].
        boundary_condition: Python `str` indicating the boundary condition
            of the chain. Supported boundary conditions are ["closed"].
        data_dir: Optional Python `str` location where to store the data on
            disk. Defaults to `/tmp/.keras`.
    Returns:
        A Python `lst` cirq.Circuit of depth len(qubits) / 2 with resolved
            parameters.
        A Python `lst` of labels, 0, for the critical metallic phase
            (`Delta<=1`) and 1 for the insulating phase (`Delta>1`).
        A Python `lst` of `cirq.PauliSum`s.
        A Python `lst` of `namedtuple` instances containing the following
            fields:
        - `g`: Numpy `float` order parameter.
        - `gs`: Complex `np.ndarray` ground state wave function from
            exact diagonalization.
        - `gs_energy`: Numpy `float` ground state energy from exact
            diagonalization.
        - `res_energy`: Python `float` residual between the circuit energy
            and the exact energy from exact diagonalization.
        - `fidelity`: Python `float` overlap between the circuit state
            and the exact ground state from exact diagonalization.
        - `params`: Dict with Python `str` keys and Numpy`float` values.
            Contains $M \times P $ parameters. Here $M$ is the number of
            parameters per circuit layer and $P$ the circuit depth.
        - `var_circuit`: Variational `cirq.Circuit` quantum circuit with
            unresolved Sympy parameters.
    """

    supported_n = [4, 8, 12, 16]
    supported_bc = ["closed"]
    if any(isinstance(q, list) for q in qubits):
        raise TypeError("qubits must be a one-dimensional list")

    if not all(isinstance(q, cirq.GridQubit) for q in qubits):
        raise TypeError("qubits must be a list of cirq.GridQubit objects.")

    nspins = len(qubits)
    depth = nspins // 2
    if nspins not in supported_n:
        raise ValueError("Supported number of spins are {}, received {}".format(
            supported_n, nspins))

    if boundary_condition not in supported_bc:
        raise ValueError(
            "Supported boundary conditions are {}, received {}".format(
                supported_bc, boundary_condition))

    data_path = _download_spin_data('XXZ_chain', boundary_condition, nspins,
                                    data_dir)

    name_generator = unique_name()

    # 4 * N/2 parameters.
    symbol_names = [next(name_generator) for _ in range(2 * nspins)]
    symbols = [sympy.Symbol(name) for name in symbol_names]

    # Define the circuit.
    circuit = cirq.Circuit(cirq.X.on_each(qubits))
    even_qubits = qubits[::2]
    odd_qubits = qubits[1::2]
    circuit.append(cirq.H(qubits[i]) for i in range(0, nspins, 2))
    circuit.append(cirq.CNOT(q1, q2) for q1, q2 in zip(even_qubits, odd_qubits))

    for d in range(depth):
        for q1, q2 in zip(odd_qubits, even_qubits[1:]):
            circuit.append(cirq.ZZ(q1, q2)**(symbols[d]))
            circuit.append(cirq.YY(q1, q2)**(symbols[d + depth]))
            circuit.append(cirq.XX(q1, q2)**(symbols[d + depth]))
        if boundary_condition == "closed":
            circuit.append(cirq.ZZ(qubits[-1], qubits[0])**(symbols[d]))
            circuit.append(cirq.YY(qubits[-1], qubits[0])**(symbols[d + depth]))
            circuit.append(cirq.XX(qubits[-1], qubits[0])**(symbols[d + depth]))
        for q1, q2 in zip(even_qubits, odd_qubits):
            circuit.append(cirq.ZZ(q1, q2)**(symbols[d + 2 * depth]))
            circuit.append(cirq.YY(q1, q2)**(symbols[d + 3 * depth]))
            circuit.append(cirq.XX(q1, q2)**(symbols[d + 3 * depth]))
    # Initiate lists.
    resolved_circuits = []
    hamiltonians = []
    order_parameters = []
    additional_info = []
    labels = []
    # Load the data and append to the lists.
    for i, directory in enumerate(x for x in os.listdir(data_path)):
        # The folders are named according to the order value data they contain.
        g = float(directory)
        with open(os.path.join(data_path, directory, "stats.txt"), "r") as file:
            lines = file.readlines()
            res_e = float(lines[0].split("=")[1].strip("\n"))
            fidelity = float(lines[2].split("=")[1].strip("\n"))
        order_parameters.append(g)
        params = np.load(os.path.join(data_path, directory, "params.npy")) \
                 / np.pi
        # Parameters are stored as np.float32, but cirq expects np.float64
        # See https://github.com/quantumlib/Cirq/issues/3359
        params = params.astype(np.float)
        additional_info.append(
            SpinSystemInfo(g=g,
                           gs=np.load(
                               os.path.join(data_path, directory,
                                            "groundstate.npy"))[:, 0],
                           gs_energy=np.load(
                               os.path.join(data_path, directory,
                                            "energy.npy"))[0],
                           res_energy=res_e,
                           fidelity=fidelity,
                           params=dict(zip(symbol_names, params.flatten())),
                           var_circuit=circuit))
        # Resolve the circuit parameters.
        resolved_circuit = cirq.resolve_parameters(circuit,
                                                   additional_info[i].params)
        resolved_circuits.append(resolved_circuit)
        # Make the PauliSum.
        paulisum = sum(order_parameters[i] * cirq.Z(q1) * cirq.Z(q2) +
                       cirq.Y(q1) * cirq.Y(q2) + cirq.X(q1) * cirq.X(q2)
                       for q1, q2 in zip(qubits, qubits[1:]))

        if boundary_condition == "closed":
            paulisum += order_parameters[i] * cirq.Z(qubits[0]) * cirq.Z(
                qubits[-1]) + cirq.Y(qubits[0]) * cirq.Y(qubits[-1]) + cirq.X(
                    qubits[0]) * cirq.X(qubits[-1])
        hamiltonians.append(paulisum)

        # Set labels for the different phases.
        if order_parameters[i] <= 1.0:
            labels.append(0)
        else:
            labels.append(1)

    # Make sure that the data is ordered from g=0.2 to g=1.8.
    _, resolved_circuits, labels, hamiltonians, additional_info = zip(*sorted(
        zip(order_parameters, resolved_circuits, labels, hamiltonians,
            additional_info)))

    return resolved_circuits, labels, hamiltonians, additional_info
Beispiel #23
0
def tfi_rectangular(qubits, boundary_condition="torus", data_dir=None):
    """2D transverse field Ising-model quantum data set.

    $$
    H = - \sum_{\langle i,j \rangle} \sigma_i^z \sigma_{j}^z - g\sigma_i^x
    $$

    Contains 51 circuit parameterizations corresponding to
    the ground states of the 2D TFI chain for g in [2.5,3.5].
    This dataset contains 51 datapoints. Each datapoint is represented by a
    circuit (`cirq.Circuit`), a label (Python `float`) a Hamiltonian
    (`cirq.PauliSum`) and some additional metadata. Each Hamiltonian in a
    datapoint is a 2D TFI rectangular lattice with boundary condition
    `boundary_condition` on `qubits` whos order parameter dictates the value of
    label. The circuit in a datapoint prepares (an approximation to) the ground
    state of the Hamiltonian in the datapoint.

    Example usage:

    >>> qbs = cirq.GridQubit.rect(9, 1)
    >>> circuits, labels, pauli_sums, addinfo  =
    ...     tfq.datasets.tfi_rectangular(qbs, "torus")

    You can print the available order parameters

    >>> [info.g for info in addinfo]
    [2.5, 2.52, 2.54, ... ,3.46 , 3.48, 3.5]

    and the circuit corresponding to the ground state for a certain order
    parameter

    >>> print(circuits[10])
                       ┌──────────────────────┐   ┌───────────────────── ...
    (0, 0): ───H────ZZ─────────────────────────ZZ─────────────────────── ...
                    │                          │
    (1, 0): ───H────ZZ^0.948896────────────────┼──────────ZZ──────────── ...
                                               │          │
    (2, 0): ───H────ZZ─────────────────────────┼──────────┼───────────── ...
                    │                          │          │
    (3, 0): ───H────┼──────────ZZ──────────────┼──────────┼───────────── ...
       .            .                          .          .
       .            .                          .          .

    The labels indicate the phase of the system
    >>> labels[10]
    0

    Additionally, you can obtain the `cirq.PauliSum` representation of the
    Hamiltonian

    >>> print(pauli_sums[10])
    -2.700*X((0, 0))-2.700*X((1, 0))-2.700*X((2, 0))-2.700*X((3, 0))-
    2.700*X((4, 0))-2.700*X((5, 0))-2.700*X((6, 0))-2.700*X((7, 0))- ...
    -1.000*Z((3, 0))*Z((6, 0))-1.000*Z((4, 0))*Z((5, 0))

    The fourth output, `addinfo`, contains additional information
    about each instance of the system (see `tfq.datasets.spin_system.SpinSystem`
    ).

    For instance, you can print the ground state obtained from
    exact diagonalization

    >>> addinfo[10].gs
    [-0.11843355-0.30690906j -0.04374221-0.11335368j -0.04374221-0.11335368j
     -0.02221491-0.0575678j  -0.04374221-0.11335368j -0.02221491-0.0575678j
                ...
     -0.04374221-0.11335368j -0.02221491-0.0575678j  -0.04374221-0.11335368j
     -0.04374221-0.11335368j -0.11843355-0.30690906j]

    with corresponding ground state energy

    >>> addinfo[10].gs_energy
    -26.974953331962762

    You can also inspect the parameters

    >>> addinfo[10].params
    {'theta_0': 0.948896, 'theta_1': 0.90053445, ...
    'theta_8': 0.76966083, 'theta_9': 0.87608284}

    and change them to experiment with different parameter values by using
    the unresolved variational circuit returned by tfichain
    >>> new_params = {}
    ... for symbol_name, value in addinfo[10].params.items():
    ...    new_params[symbol_name] = 0.5 * value
    >>> new_params
    {'theta_0': 0.47444799542427063, 'theta_1': 0.4502672255039215, ...
    'theta_8': 0.38483041524887085, 'theta_9': 0.43804141879081726}
    >>> new_circuit = cirq.resolve_parameters(addinfo[10].var_circuit,
    ... new_params)
    >>> print(new_circuit)
                       ┌──────────────────────┐   ┌───────────────────── ...
    (0, 0): ───H────ZZ─────────────────────────ZZ─────────────────────── ...
                    │                          │
    (1, 0): ───H────ZZ^0.474───────────────────┼──────────ZZ──────────── ...
                                               │          │
    (2, 0): ───H────ZZ─────────────────────────┼──────────┼───────────── ...
                    │                          │          │
    (3, 0): ───H────┼──────────ZZ──────────────┼──────────┼───────────── ...
       .            .                          .          .
       .            .                          .          .

    Args:
        qubits: Python `lst` of `cirq.GridQubit`s. Supported number of spins
            are [9, 12, 16].
        boundary_condition: Python `str` indicating the boundary condition
            of the chain. Supported boundary conditions are ["torus"].
        data_dir: Optional Python `str` location where to store the data on
            disk. Defaults to `/tmp/.keras`.
    Returns:
        A Python `lst` cirq.Circuit of depth ceil(len(qubits) / 2) with resolved
            parameters.
        A Python `lst` of labels, 0, for the phase (`g<3.04`),
            1 for the critical point (`g==3.04`) and 2 for the phase (`g>3.04`).
        A Python `lst` of `cirq.PauliSum`s.
        A Python `lst` of `namedtuple` instances containing the following
            fields:
        - `g`: Numpy `float` order parameter.
        - `gs`: Complex `np.ndarray` ground state wave function from
            exact diagonalization.
        - `gs_energy`: Numpy `float` ground state energy from exact
            diagonalization.
        - `res_energy`: Python `float` residual between the circuit energy
            and the exact energy from exact diagonalization.
        - `fidelity`: Python `float` overlap between the circuit state
            and the exact ground state from exact diagonalization.
        - `params`: Dict with Python `str` keys and Numpy`float` values.
            Contains $M \times P $ parameters. Here $M$ is the number of
            parameters per circuit layer and $P$ the circuit depth.
        - `var_circuit`: Variational `cirq.Circuit` quantum circuit with
            unresolved Sympy parameters.
    """

    supported_n = [9, 12, 16]
    supported_bc = ["torus"]
    if any(isinstance(q, list) for q in qubits):
        raise TypeError("qubits must be a one-dimensional list")

    if not all(isinstance(q, cirq.GridQubit) for q in qubits):
        raise TypeError("qubits must be a list of cirq.GridQubit objects.")

    nspins = len(qubits)
    depth = int(np.ceil(nspins / 2))

    if nspins not in supported_n:
        raise ValueError("Supported number of spins are {}, received {}".format(
            supported_n, nspins))

    if boundary_condition not in supported_bc:
        raise ValueError(
            "Supported boundary conditions are {}, received {}".format(
                supported_bc, boundary_condition))

    data_path = _download_spin_data('TFI_rect', boundary_condition, nspins,
                                    data_dir)

    name_generator = unique_name()

    # 2 * depth parameters.
    symbol_names = [next(name_generator) for _ in range(2 * depth)]

    symbols = [sympy.Symbol(name) for name in symbol_names]

    # Define the circuit.
    circuit = cirq.Circuit(cirq.H.on_each(qubits))
    if boundary_condition == 'torus':
        if nspins == 9:
            #3x3
            edges = {
                'g1': [[0, 1], [2, 5], [3, 4], [6, 7]],
                'g2': [[0, 6], [1, 4], [7, 8]],
                'g3': [[0, 3], [1, 2], [4, 7], [5, 8]],
                'g4': [[0, 2], [1, 7], [3, 5], [6, 8]],
                'g5': [[2, 8], [3, 6], [4, 5]]
            }
        if nspins == 12:
            #4x3
            edges = {
                'g1': [[0, 3], [1, 2], [4, 7], [5, 8], [6, 9], [10, 11]],
                'g2': [[0, 1], [2, 5], [3, 4], [6, 7], [8, 11], [9, 10]],
                'g3': [[0, 9], [1, 10], [2, 11], [3, 6], [4, 5], [7, 8]],
                'g4': [[0, 2], [1, 4], [3, 5], [6, 8], [7, 10], [9, 11]]
            }
        if nspins == 16:
            #4x4
            edges = {
                'g1': [[0, 3], [1, 2], [4, 7], [5, 9], [6, 10], [8, 12],
                       [11, 15], [13, 14]],
                'g2': [[0, 4], [1, 5], [2, 6], [3, 15], [7, 11], [8, 9],
                       [10, 14], [12, 13]],
                'g3': [[0, 12], [1, 13], [2, 3], [4, 5], [6, 7], [8, 11],
                       [9, 10], [14, 15]],
                'g4': [[0, 1], [2, 14], [3, 7], [4, 8], [5, 6], [9, 13],
                       [10, 11], [12, 15]]
            }
    for d in range(depth):
        for graph in edges.values():
            circuit.append(
                cirq.ZZ(qubits[edge[0]], qubits[edge[1]])**(symbols[d])
                for edge in graph)
        circuit.append(cirq.X(q1)**(symbols[d + depth]) for q1 in qubits)

    # Initiate lists.
    resolved_circuits = []
    hamiltonians = []
    order_parameters = []
    additional_info = []
    labels = []

    # Load the data and append to the lists.
    for i, directory in enumerate(x for x in os.listdir(data_path)):
        # The folders are named according to the order value data they contain.
        g = float(directory)
        with open(os.path.join(data_path, directory, "stats.txt"), "r") as file:
            lines = file.readlines()
            res_e = float(lines[0].split("=")[1].strip("\n"))
            fidelity = float(lines[2].split("=")[1].strip("\n"))
        order_parameters.append(g)
        params = np.load(os.path.join(data_path, directory, "params.npy")) \
                 / np.pi
        additional_info.append(
            SpinSystemInfo(g=g,
                           gs=np.load(
                               os.path.join(data_path, directory,
                                            "groundstate.npy"))[:, 0],
                           gs_energy=np.load(
                               os.path.join(data_path, directory,
                                            "energy.npy"))[0],
                           res_energy=res_e,
                           fidelity=fidelity,
                           params=dict(zip(symbol_names, params.flatten())),
                           var_circuit=circuit))
        # Resolve the circuit parameters.
        param_resolver = cirq.resolve_parameters(circuit,
                                                 additional_info[i].params)
        resolved_circuits.append(param_resolver)
        paulisum = -order_parameters[i] * sum(cirq.X(q) for q in qubits)
        # Make the PauliSum.
        for graph in edges.values():
            paulisum -= sum(
                cirq.Z(qubits[edge[0]]) * cirq.Z(qubits[edge[1]])
                for edge in graph)

        hamiltonians.append(paulisum)

        # Set labels for the different phases.
        if order_parameters[i] < 3.04:
            labels.append(0)
        elif order_parameters[i] == 3.04:
            labels.append(1)
        else:
            labels.append(2)

    # Make sure that the data is ordered from g=2.5 to g=3.5.
    _, resolved_circuits, labels, hamiltonians, additional_info = zip(*sorted(
        zip(order_parameters, resolved_circuits, labels, hamiltonians,
            additional_info)))

    return resolved_circuits, labels, hamiltonians, additional_info
Beispiel #24
0
def matrix_to_sycamore_operations(
        target_qubits: List[cirq.GridQubit],
        matrix: np.ndarray) -> Tuple[cirq.OP_TREE, List[cirq.GridQubit]]:
    """A method to convert a unitary matrix to a list of Sycamore operations.

    This method will return a list of `cirq.Operation`s using the qubits and (optionally) ancilla
    qubits to implement the unitary matrix `matrix` on the target qubits `qubits`.
    The operations are also supported by `cirq.google.gate_sets.SYC_GATESET`.

    Args:
        target_qubits: list of qubits the returned operations will act on. The qubit order defined by the list
            is assumed to be used by the operations to implement `matrix`.
        matrix: a matrix that is guaranteed to be unitary and of size (2**len(qs), 2**len(qs)).
    Returns:
        A tuple of operations and ancilla qubits allocated.
            Operations: In case the matrix is supported, a list of operations `ops` is returned.
                `ops` acts on `qs` qubits and for which `cirq.unitary(ops)` is equal to `matrix` up
                to certain tolerance. In case the matrix is not supported, it might return NotImplemented to
                reduce the noise in the judge output.
            Ancilla qubits: In case ancilla qubits are allocated a list of ancilla qubits. Otherwise
                an empty list.
        .
    """
    def optimize_circuit(circ):
        ouut = []
        converter = cirq.google.ConvertToSycamoreGates()
        for _ in circ.all_operations():
            ouut.append(converter.convert(_))
        return cirq.google.optimized_for_sycamore(
            cirq.Circuit(ouut), optimizer_type="sycamore"), []

    if np.trace(matrix) == len(matrix):
        return [], []

    if len(matrix) == 2:
        try:
            comparison = matrix == cirq.unitary(cirq.Z)
            if (comparison.all()): return cirq.Z(target_qubits[0]), []

            comparison = matrix == cirq.unitary(cirq.X)
            if (comparison.all()): return cirq.X(target_qubits[0]), []

            comparison = matrix == cirq.unitary(cirq.Y)
            if (comparison.all()): return cirq.Y(target_qubits[0]), []

            comparison = matrix == cirq.unitary(cirq.H)
            if (comparison.all()): return cirq.H.on(target_qubits[0]), []

            comparison = matrix == cirq.unitary(cirq.S)
            if (comparison.all()): return cirq.S(target_qubits[0]), []

            comparison = matrix == cirq.unitary(cirq.T)
            if (comparison.all()): return cirq.T(target_qubits[0]), []

        except [TypeError, ValueError]:
            return NotImplemented, []

    if len(matrix) == 4:
        try:
            comparison = matrix == cirq.unitary(cirq.CNOT)
            if (comparison.all()):
                return optimize_circuit(
                    cirq.Circuit(cirq.CNOT(target_qubits[0],
                                           target_qubits[1])))

            comparison = matrix == cirq.unitary(cirq.XX)
            if (comparison.all()):
                return optimize_circuit(
                    cirq.Circuit(cirq.XX(target_qubits[0], target_qubits[1])))

            comparison = matrix == cirq.unitary(cirq.YY)
            if (comparison.all()):
                return optimize_circuit(
                    cirq.Circuit(cirq.YY(target_qubits[0], target_qubits[1])))

            comparison = matrix == cirq.unitary(cirq.ZZ)
            if (comparison.all()):
                return optimize_circuit(
                    cirq.Circuit(cirq.ZZ(target_qubits[0], target_qubits[1])))

            comparison = matrix == cirq.unitary(cirq.google.SYC)
            if (comparison.all()):
                return optimize_circuit(
                    cirq.Circuit(
                        cirq.google.SYC(target_qubits[0], target_qubits[1])))

        except TypeError:
            return NotImplemented, []

    if len(matrix) == 8:
        try:
            comparison = matrix == cirq.unitary(cirq.CCX)
            if (comparison.all()):
                return optimize_circuit(
                    cirq.Circuit(
                        cirq.CCX(target_qubits[0], target_qubits[1],
                                 target_qubits[2])))

            comparison = matrix == cirq.unitary(cirq.CSWAP)
            if (comparison.all()):
                return optimize_circuit(
                    cirq.Circuit(
                        cirq.CSWAP(target_qubits[0], target_qubits[1],
                                   target_qubits[2])))

            comparison = matrix == cirq.unitary(cirq.CCZ)
            if (comparison.all()):
                return optimize_circuit(
                    cirq.Circuit(
                        cirq.CCZ(target_qubits[0], target_qubits[1],
                                 target_qubits[2])))

            comparison = matrix == cirq.unitary(
                cirq.ControlledGate(cirq.ISWAP**0.5, 1))
            if (comparison.all()):
                return cirq.ControlledGate(cirq.ISWAP**0.5, 1)

        except TypeError:
            return NotImplemented, []

    if len(matrix) == 16:
        try:
            comparison = matrix == cirq.unitary(
                cirq.ControlledGate(cirq.ISWAP**0.5, 2))
            if (comparison.all()):
                return optimize_circuit(
                    cirq.Circuit(
                        cirq.ControlledGate(sub_gate=cirq.ISWAP**0.5).on(
                            target_qubits[2], target_qubits[0],
                            target_qubits[1])))

        except TypeError:
            return NotImplemented, []

    return NotImplemented, []
Beispiel #25
0
 def _decompose_(self, qubits):
     return [[cirq.X(qubit)**β for qubit in qubits] + [
         cirq.ZZ(qubits[i], qubits[i + 1])**γ
         for i in range(self.n_qubits - 1)
     ] for β, γ in split_2s(self.βγs)]
Beispiel #26
0
def _get_circuit_proto_pairs():
    q0 = cirq.GridQubit(0, 0)
    q1 = cirq.GridQubit(0, 1)

    pairs = [
        # HPOW and aliases.
        (cirq.Circuit(cirq.HPowGate(exponent=0.3)(q0)),
         _build_gate_proto("HP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           [0.3, 1.0, 0.0], ['0_0'])),
        (cirq.Circuit(cirq.HPowGate(exponent=sympy.Symbol('alpha'))(q0)),
         _build_gate_proto("HP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           ['alpha', 1.0, 0.0], ['0_0'])),
        (cirq.Circuit(cirq.HPowGate(exponent=3.1 * sympy.Symbol('alpha'))(q0)),
         _build_gate_proto("HP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           ['alpha', 3.1, 0.0], ['0_0'])),
        (cirq.Circuit(cirq.H(q0)),
         _build_gate_proto("HP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           [1.0, 1.0, 0.0], ['0_0'])),

        # XPOW and aliases.
        (cirq.Circuit(cirq.XPowGate(exponent=0.3)(q0)),
         _build_gate_proto("XP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           [0.3, 1.0, 0.0], ['0_0'])),
        (cirq.Circuit(cirq.XPowGate(exponent=sympy.Symbol('alpha'))(q0)),
         _build_gate_proto("XP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           ['alpha', 1.0, 0.0], ['0_0'])),
        (cirq.Circuit(cirq.XPowGate(exponent=3.1 * sympy.Symbol('alpha'))(q0)),
         _build_gate_proto("XP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           ['alpha', 3.1, 0.0], ['0_0'])),
        (cirq.Circuit(cirq.X(q0)),
         _build_gate_proto("XP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           [1.0, 1.0, 0.0], ['0_0'])),

        # YPOW and aliases
        (cirq.Circuit(cirq.YPowGate(exponent=0.3)(q0)),
         _build_gate_proto("YP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           [0.3, 1.0, 0.0], ['0_0'])),
        (cirq.Circuit(cirq.YPowGate(exponent=sympy.Symbol('alpha'))(q0)),
         _build_gate_proto("YP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           ['alpha', 1.0, 0.0], ['0_0'])),
        (cirq.Circuit(cirq.YPowGate(exponent=3.1 * sympy.Symbol('alpha'))(q0)),
         _build_gate_proto("YP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           ['alpha', 3.1, 0.0], ['0_0'])),
        (cirq.Circuit(cirq.Y(q0)),
         _build_gate_proto("YP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           [1.0, 1.0, 0.0], ['0_0'])),

        # ZPOW and aliases.
        (cirq.Circuit(cirq.ZPowGate(exponent=0.3)(q0)),
         _build_gate_proto("ZP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           [0.3, 1.0, 0.0], ['0_0'])),
        (cirq.Circuit(cirq.ZPowGate(exponent=sympy.Symbol('alpha'))(q0)),
         _build_gate_proto("ZP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           ['alpha', 1.0, 0.0], ['0_0'])),
        (cirq.Circuit(cirq.ZPowGate(exponent=3.1 * sympy.Symbol('alpha'))(q0)),
         _build_gate_proto("ZP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           ['alpha', 3.1, 0.0], ['0_0'])),
        (cirq.Circuit(cirq.Z(q0)),
         _build_gate_proto("ZP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           [1.0, 1.0, 0.0], ['0_0'])),

        # XXPow and aliases
        (cirq.Circuit(cirq.XXPowGate(exponent=0.3)(q0, q1)),
         _build_gate_proto("XXP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           [0.3, 1.0, 0.0], ['0_0', '0_1'])),
        (cirq.Circuit(cirq.XXPowGate(exponent=sympy.Symbol('alpha'))(q0, q1)),
         _build_gate_proto("XXP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           ['alpha', 1.0, 0.0], ['0_0', '0_1'])),
        (cirq.Circuit(
            cirq.XXPowGate(exponent=3.1 * sympy.Symbol('alpha'))(q0, q1)),
         _build_gate_proto("XXP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           ['alpha', 3.1, 0.0], ['0_0', '0_1'])),
        (cirq.Circuit(cirq.XX(q0, q1)),
         _build_gate_proto("XXP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           [1.0, 1.0, 0.0], ['0_0', '0_1'])),

        # YYPow and aliases
        (cirq.Circuit(cirq.YYPowGate(exponent=0.3)(q0, q1)),
         _build_gate_proto("YYP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           [0.3, 1.0, 0.0], ['0_0', '0_1'])),
        (cirq.Circuit(cirq.YYPowGate(exponent=sympy.Symbol('alpha'))(q0, q1)),
         _build_gate_proto("YYP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           ['alpha', 1.0, 0.0], ['0_0', '0_1'])),
        (cirq.Circuit(
            cirq.YYPowGate(exponent=3.1 * sympy.Symbol('alpha'))(q0, q1)),
         _build_gate_proto("YYP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           ['alpha', 3.1, 0.0], ['0_0', '0_1'])),
        (cirq.Circuit(cirq.YY(q0, q1)),
         _build_gate_proto("YYP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           [1.0, 1.0, 0.0], ['0_0', '0_1'])),

        # ZZPow and aliases
        (cirq.Circuit(cirq.ZZPowGate(exponent=0.3)(q0, q1)),
         _build_gate_proto("ZZP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           [0.3, 1.0, 0.0], ['0_0', '0_1'])),
        (cirq.Circuit(cirq.ZZPowGate(exponent=sympy.Symbol('alpha'))(q0, q1)),
         _build_gate_proto("ZZP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           ['alpha', 1.0, 0.0], ['0_0', '0_1'])),
        (cirq.Circuit(
            cirq.ZZPowGate(exponent=3.1 * sympy.Symbol('alpha'))(q0, q1)),
         _build_gate_proto("ZZP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           ['alpha', 3.1, 0.0], ['0_0', '0_1'])),
        (cirq.Circuit(cirq.ZZ(q0, q1)),
         _build_gate_proto("ZZP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           [1.0, 1.0, 0.0], ['0_0', '0_1'])),

        # CZPow and aliases
        (cirq.Circuit(cirq.CZPowGate(exponent=0.3)(q0, q1)),
         _build_gate_proto("CZP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           [0.3, 1.0, 0.0], ['0_0', '0_1'])),
        (cirq.Circuit(cirq.CZPowGate(exponent=sympy.Symbol('alpha'))(q0, q1)),
         _build_gate_proto("CZP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           ['alpha', 1.0, 0.0], ['0_0', '0_1'])),
        (cirq.Circuit(
            cirq.CZPowGate(exponent=3.1 * sympy.Symbol('alpha'))(q0, q1)),
         _build_gate_proto("CZP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           ['alpha', 3.1, 0.0], ['0_0', '0_1'])),
        (cirq.Circuit(cirq.CZ(q0, q1)),
         _build_gate_proto("CZP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           [1.0, 1.0, 0.0], ['0_0', '0_1'])),

        # CNOTPow and aliases
        (cirq.Circuit(cirq.CNotPowGate(exponent=0.3)(q0, q1)),
         _build_gate_proto("CNP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           [0.3, 1.0, 0.0], ['0_0', '0_1'])),
        (cirq.Circuit(
            cirq.CNotPowGate(exponent=sympy.Symbol('alpha'))(q0, q1)),
         _build_gate_proto("CNP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           ['alpha', 1.0, 0.0], ['0_0', '0_1'])),
        (cirq.Circuit(
            cirq.CNotPowGate(exponent=3.1 * sympy.Symbol('alpha'))(q0, q1)),
         _build_gate_proto("CNP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           ['alpha', 3.1, 0.0], ['0_0', '0_1'])),
        (cirq.Circuit(cirq.CNOT(q0, q1)),
         _build_gate_proto("CNP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           [1.0, 1.0, 0.0], ['0_0', '0_1'])),

        # SWAPPow and aliases
        (cirq.Circuit(cirq.SwapPowGate(exponent=0.3)(q0, q1)),
         _build_gate_proto("SP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           [0.3, 1.0, 0.0], ['0_0', '0_1'])),
        (cirq.Circuit(
            cirq.SwapPowGate(exponent=sympy.Symbol('alpha'))(q0, q1)),
         _build_gate_proto("SP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           ['alpha', 1.0, 0.0], ['0_0', '0_1'])),
        (cirq.Circuit(
            cirq.SwapPowGate(exponent=3.1 * sympy.Symbol('alpha'))(q0, q1)),
         _build_gate_proto("SP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           ['alpha', 3.1, 0.0], ['0_0', '0_1'])),
        (cirq.Circuit(cirq.SWAP(q0, q1)),
         _build_gate_proto("SP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           [1.0, 1.0, 0.0], ['0_0', '0_1'])),

        # ISWAPPow and aliases
        (cirq.Circuit(cirq.ISwapPowGate(exponent=0.3)(q0, q1)),
         _build_gate_proto("ISP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           [0.3, 1.0, 0.0], ['0_0', '0_1'])),
        (cirq.Circuit(
            cirq.ISwapPowGate(exponent=sympy.Symbol('alpha'))(q0, q1)),
         _build_gate_proto("ISP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           ['alpha', 1.0, 0.0], ['0_0', '0_1'])),
        (cirq.Circuit(
            cirq.ISwapPowGate(exponent=3.1 * sympy.Symbol('alpha'))(q0, q1)),
         _build_gate_proto("ISP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           ['alpha', 3.1, 0.0], ['0_0', '0_1'])),
        (cirq.Circuit(cirq.ISWAP(q0, q1)),
         _build_gate_proto("ISP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           [1.0, 1.0, 0.0], ['0_0', '0_1'])),

        # PhasedXPow and aliases
        (cirq.Circuit(
            cirq.PhasedXPowGate(phase_exponent=0.9,
                                exponent=0.3,
                                global_shift=0.2)(q0)),
         _build_gate_proto("PXP", [
             'phase_exponent', 'phase_exponent_scalar', 'exponent',
             'exponent_scalar', 'global_shift'
         ], [0.9, 1.0, 0.3, 1.0, 0.2], ['0_0'])),
        (cirq.Circuit(
            cirq.PhasedXPowGate(phase_exponent=sympy.Symbol('alpha'),
                                exponent=0.3)(q0)),
         _build_gate_proto("PXP", [
             'phase_exponent', 'phase_exponent_scalar', 'exponent',
             'exponent_scalar', 'global_shift'
         ], ['alpha', 1.0, 0.3, 1.0, 0.0], ['0_0'])),
        (cirq.Circuit(
            cirq.PhasedXPowGate(phase_exponent=3.1 * sympy.Symbol('alpha'),
                                exponent=0.3)(q0)),
         _build_gate_proto("PXP", [
             'phase_exponent', 'phase_exponent_scalar', 'exponent',
             'exponent_scalar', 'global_shift'
         ], ['alpha', 3.1, 0.3, 1.0, 0.0], ['0_0'])),
        (cirq.Circuit(
            cirq.PhasedXPowGate(phase_exponent=0.9,
                                exponent=sympy.Symbol('beta'))(q0)),
         _build_gate_proto("PXP", [
             'phase_exponent', 'phase_exponent_scalar', 'exponent',
             'exponent_scalar', 'global_shift'
         ], [0.9, 1.0, 'beta', 1.0, 0.0], ['0_0'])),
        (cirq.Circuit(
            cirq.PhasedXPowGate(phase_exponent=0.9,
                                exponent=5.1 * sympy.Symbol('beta'))(q0)),
         _build_gate_proto("PXP", [
             'phase_exponent', 'phase_exponent_scalar', 'exponent',
             'exponent_scalar', 'global_shift'
         ], [0.9, 1.0, 'beta', 5.1, 0.0], ['0_0'])),
        (cirq.Circuit(
            cirq.PhasedXPowGate(phase_exponent=3.1 * sympy.Symbol('alpha'),
                                exponent=5.1 * sympy.Symbol('beta'))(q0)),
         _build_gate_proto("PXP", [
             'phase_exponent', 'phase_exponent_scalar', 'exponent',
             'exponent_scalar', 'global_shift'
         ], ['alpha', 3.1, 'beta', 5.1, 0.0], ['0_0'])),

        # RX, RY, RZ with symbolization is tested in special cases as the
        # string comparison of the float converted sympy.pi does not happen
        # smoothly. See: test_serialize_deserialize_special_case_one_qubit
        (cirq.Circuit(cirq.rx(np.pi)(q0)),
         _build_gate_proto("XP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           [1.0, 1.0, -0.5], ['0_0'])),
        (cirq.Circuit(cirq.ry(np.pi)(q0)),
         _build_gate_proto("YP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           [1.0, 1.0, -0.5], ['0_0'])),
        (cirq.Circuit(cirq.rz(np.pi)(q0)),
         _build_gate_proto("ZP",
                           ['exponent', 'exponent_scalar', 'global_shift'],
                           [1.0, 1.0, -0.5], ['0_0'])),

        # Identity
        (cirq.Circuit(cirq.I(q0)),
         _build_gate_proto("I", ['unused'], [True], ['0_0'])),

        # FSimGate
        (cirq.Circuit(cirq.FSimGate(theta=0.1, phi=0.2)(q0, q1)),
         _build_gate_proto("FSIM",
                           ['theta', 'theta_scalar', 'phi', 'phi_scalar'],
                           [0.1, 1.0, 0.2, 1.0], ['0_0', '0_1'])),
        (cirq.Circuit(
            cirq.FSimGate(theta=2.1 * sympy.Symbol("alpha"),
                          phi=1.3 * sympy.Symbol("beta"))(q0, q1)),
         _build_gate_proto("FSIM",
                           ['theta', 'theta_scalar', 'phi', 'phi_scalar'],
                           ['alpha', 2.1, 'beta', 1.3], ['0_0', '0_1'])),
    ]

    return pairs
l = 3

out_qubit, label_disc, data1, data2, data3, label_gen = cirq.GridQubit.rect(
    1, 6)

gs = sympy.symbols("g:22")
gen = cirq.Circuit(
    cirq.rx(gs[0]).on(data1),
    cirq.rx(gs[1]).on(data2),
    cirq.rx(gs[2]).on(data3),
    cirq.rx(gs[3]).on(label_gen),
    cirq.rz(gs[4]).on(data1),
    cirq.rz(gs[5]).on(data2),
    cirq.rz(gs[6]).on(data3),
    cirq.rz(gs[7]).on(label_gen),
    cirq.ZZ(data1, data2)**gs[8],
    cirq.ZZ(data3, label_gen)**gs[9],
    cirq.ZZ(data2, data3)**gs[10],
    cirq.rx(gs[11]).on(data1),
    cirq.rx(gs[12]).on(data2),
    cirq.rx(gs[13]).on(data3),
    cirq.rx(gs[14]).on(label_gen),
    cirq.rz(gs[15]).on(data1),
    cirq.rz(gs[16]).on(data2),
    cirq.rz(gs[17]).on(data3),
    cirq.rz(gs[18]).on(label_gen),
    cirq.ZZ(data1, data2)**gs[19],
    cirq.ZZ(data3, label_gen)**gs[20],
    cirq.ZZ(data2, data3)**gs[21],
)
Beispiel #28
0
    def to_cirq(self, input_cirq_qubits=None):
        """Convert to a cirq gate.

        Args:
            input_cirq_qubits: list[cirq.LineQubit]
                (optional) a list of cirq Qubits that the gate can act on. If not provided
                the function will generate new cirq.LineQubit objects.
        Returns:
        A cirq Circuit object that corresponds to the specification of the quantum gate.
            In the special case the gate itself was natively generated from cirq, the function
            will faithfully reproduce the original GateOperation object, taking into account
            whether the gate acts on GridQubit objects or LineQubit objects.
            In the other cases the resulting cirq gate simply assumes that the qubits are
            LineQubit objects.
        """

        if self.name not in ALL_GATES:
            sys.exit("Gate {} currently not supported.".format(self.name))

        q_inds = []
        q_inds.append(self.qubits[0].index)
        if len(self.qubits) >= 2:
            q_inds.append(self.qubits[1].index)
        if len(self.qubits) >= 3:
            q_inds.append(self.qubits[2].index)

        cirq_qubits = []
        if input_cirq_qubits == None:
            for q in self.qubits:
                if q.info["label"] == "cirq":
                    qkey = q.info["QubitKey"]
                    if q.info["QubitType"] == "GridQubit":
                        cirq_qubits.append(cirq.GridQubit(qkey[0], qkey[1]))
                    if q.info["QubitType"] == "LineQubit":
                        cirq_qubits.append(cirq.LineQubit(qkey))
                else:
                    cirq_qubits.append(cirq.LineQubit(q.index))
        else:
            cirq_qubits = [
                input_cirq_qubits[x] for x in [q.index for q in self.qubits]
            ]

        if len(self.params) > 0:
            params = self.params

        # single-qubit gates
        if self.name == "I":  # Identity
            return cirq.I(cirq_qubits[0])
        if self.name == "X":  # Pauli X
            return cirq.X(cirq_qubits[0])
        if self.name == "Y":  # Pauli Y
            return cirq.Y(cirq_qubits[0])
        if self.name == "Z":  # Pauli Z
            return cirq.Z(cirq_qubits[0])
        if self.name == "H":  # Hadamard
            return cirq.H(cirq_qubits[0])
        if self.name == "S":  # S gate
            return cirq.S(cirq_qubits[0])
        if self.name == "T":  # T gate
            return cirq.T(cirq_qubits[0])
        if self.name == "Rx":  # Single-qubit X rotation
            return cirq.rx(params[0])(cirq_qubits[0])
        if self.name == "Ry":  # Single-qubit Y rotation
            return cirq.ry(params[0])(cirq_qubits[0])
        if self.name == "Rz":  # Single-qubit Z rotation
            return cirq.rz(params[0])(cirq_qubits[0])
        if self.name == "PHASE":  # Phase gate
            return cirq.Z(cirq_qubits[0])**(params[0] / pi)
        if self.name == "ZXZ":  # PhasedXPowGate gate
            g = cirq.PhasedXPowGate(phase_exponent=params[0] / pi,
                                    exponent=params[1] / pi)
            return g(cirq_qubits[0])
        if self.name == "RH":  # HPowGate
            g = cirq.H**(params[0] / pi)
            return g(cirq_qubits[0])
        if self.name == "Da":  # Damping alpha gate
            g = DampingAlpha(params[0])
            return g(cirq_qubits[0])
        if self.name == "Db":  # Damping beta gate
            g = DampingBeta(params[0])
            return g(cirq_qubits[0])

        # two-qubit gates
        if self.name == "CNOT":
            return cirq.CNOT(cirq_qubits[0], cirq_qubits[1])
        if self.name == "CZ":
            return cirq.CZ(cirq_qubits[0], cirq_qubits[1])
        if self.name == "CPHASE":
            return cirq.CZPowGate(exponent=params[0] / pi)(cirq_qubits[0],
                                                           cirq_qubits[1])
        if self.name == "SWAP":
            return cirq.SWAP(cirq_qubits[0], cirq_qubits[1])
        if self.name == "XX":
            return cirq.XX(cirq_qubits[0],
                           cirq_qubits[1])**(params[0] * 2 / pi)
        if self.name == "YY":
            return cirq.YY(cirq_qubits[0],
                           cirq_qubits[1])**(params[0] * 2 / pi)
        if self.name == "ZZ":
            return cirq.ZZ(cirq_qubits[0],
                           cirq_qubits[1])**(params[0] * 2 / pi)
Beispiel #29
0
    def test_cirq_qsim_all_supported_gates(self):
        q0 = cirq.GridQubit(1, 1)
        q1 = cirq.GridQubit(1, 0)
        q2 = cirq.GridQubit(0, 1)
        q3 = cirq.GridQubit(0, 0)

        circuit = cirq.Circuit(
            cirq.Moment([
                cirq.H(q0),
                cirq.H(q1),
                cirq.H(q2),
                cirq.H(q3),
            ]),
            cirq.Moment([
                cirq.T(q0),
                cirq.T(q1),
                cirq.T(q2),
                cirq.T(q3),
            ]),
            cirq.Moment([
                cirq.CZPowGate(exponent=0.7, global_shift=0.2)(q0, q1),
                cirq.CXPowGate(exponent=1.2, global_shift=0.4)(q2, q3),
            ]),
            cirq.Moment([
                cirq.XPowGate(exponent=0.3, global_shift=1.1)(q0),
                cirq.YPowGate(exponent=0.4, global_shift=1)(q1),
                cirq.ZPowGate(exponent=0.5, global_shift=0.9)(q2),
                cirq.HPowGate(exponent=0.6, global_shift=0.8)(q3),
            ]),
            cirq.Moment([
                cirq.CX(q0, q2),
                cirq.CZ(q1, q3),
            ]),
            cirq.Moment([
                cirq.X(q0),
                cirq.Y(q1),
                cirq.Z(q2),
                cirq.S(q3),
            ]),
            cirq.Moment([
                cirq.XXPowGate(exponent=0.4, global_shift=0.7)(q0, q1),
                cirq.YYPowGate(exponent=0.8, global_shift=0.5)(q2, q3),
            ]),
            cirq.Moment([cirq.I(q0),
                         cirq.I(q1),
                         cirq.IdentityGate(2)(q2, q3)]),
            cirq.Moment([
                cirq.rx(0.7)(q0),
                cirq.ry(0.2)(q1),
                cirq.rz(0.4)(q2),
                cirq.PhasedXPowGate(phase_exponent=0.8,
                                    exponent=0.6,
                                    global_shift=0.3)(q3),
            ]),
            cirq.Moment([
                cirq.ZZPowGate(exponent=0.3, global_shift=1.3)(q0, q2),
                cirq.ISwapPowGate(exponent=0.6, global_shift=1.2)(q1, q3),
            ]),
            cirq.Moment([
                cirq.XPowGate(exponent=0.1, global_shift=0.9)(q0),
                cirq.YPowGate(exponent=0.2, global_shift=1)(q1),
                cirq.ZPowGate(exponent=0.3, global_shift=1.1)(q2),
                cirq.HPowGate(exponent=0.4, global_shift=1.2)(q3),
            ]),
            cirq.Moment([
                cirq.SwapPowGate(exponent=0.2, global_shift=0.9)(q0, q1),
                cirq.PhasedISwapPowGate(phase_exponent=0.8, exponent=0.6)(q2,
                                                                          q3),
            ]),
            cirq.Moment([
                cirq.PhasedXZGate(x_exponent=0.2,
                                  z_exponent=0.3,
                                  axis_phase_exponent=1.4)(q0),
                cirq.T(q1),
                cirq.H(q2),
                cirq.S(q3),
            ]),
            cirq.Moment([
                cirq.SWAP(q0, q2),
                cirq.XX(q1, q3),
            ]),
            cirq.Moment([
                cirq.rx(0.8)(q0),
                cirq.ry(0.9)(q1),
                cirq.rz(1.2)(q2),
                cirq.T(q3),
            ]),
            cirq.Moment([
                cirq.YY(q0, q1),
                cirq.ISWAP(q2, q3),
            ]),
            cirq.Moment([
                cirq.T(q0),
                cirq.Z(q1),
                cirq.Y(q2),
                cirq.X(q3),
            ]),
            cirq.Moment([
                cirq.FSimGate(0.3, 1.7)(q0, q2),
                cirq.ZZ(q1, q3),
            ]),
            cirq.Moment([
                cirq.ry(1.3)(q0),
                cirq.rz(0.4)(q1),
                cirq.rx(0.7)(q2),
                cirq.S(q3),
            ]),
            cirq.Moment([
                cirq.MatrixGate(
                    np.array([[0, -0.5 - 0.5j, -0.5 - 0.5j, 0],
                              [0.5 - 0.5j, 0, 0, -0.5 + 0.5j],
                              [0.5 - 0.5j, 0, 0, 0.5 - 0.5j],
                              [0, -0.5 - 0.5j, 0.5 + 0.5j, 0]]))(q0, q1),
                cirq.MatrixGate(
                    np.array([[0.5 - 0.5j, 0, 0, -0.5 + 0.5j],
                              [0, 0.5 - 0.5j, -0.5 + 0.5j, 0],
                              [0, -0.5 + 0.5j, -0.5 + 0.5j, 0],
                              [0.5 - 0.5j, 0, 0, 0.5 - 0.5j]]))(q2, q3),
            ]),
            cirq.Moment([
                cirq.MatrixGate(np.array([[1, 0], [0, 1j]]))(q0),
                cirq.MatrixGate(np.array([[0, -1j], [1j, 0]]))(q1),
                cirq.MatrixGate(np.array([[0, 1], [1, 0]]))(q2),
                cirq.MatrixGate(np.array([[1, 0], [0, -1]]))(q3),
            ]),
            cirq.Moment([
                cirq.riswap(0.7)(q0, q1),
                cirq.givens(1.2)(q2, q3),
            ]),
            cirq.Moment([
                cirq.H(q0),
                cirq.H(q1),
                cirq.H(q2),
                cirq.H(q3),
            ]),
        )

        simulator = cirq.Simulator()
        cirq_result = simulator.simulate(circuit)

        qsim_simulator = qsimcirq.QSimSimulator()
        qsim_result = qsim_simulator.simulate(circuit)

        assert cirq.linalg.allclose_up_to_global_phase(
            qsim_result.state_vector(), cirq_result.state_vector())
Beispiel #30
0
def tfi_chain(qubits, boundary_condition="closed", data_dir=None):
    """1D Transverse field Ising-model quantum data set.

    $$
    H = - \sum_{i} \sigma_i^z \sigma_{i+1}^z - g\sigma_i^x
    $$

    Contains 81 circuit parameterizations corresponding to
    the ground states of the 1D TFI chain for g in [0.2,1.8].
    This dataset contains 81 datapoints. Each datapoint is represented by a
    circuit (`cirq.Circuit`), a label (Python `float`) a Hamiltonian
    (`cirq.PauliSum`) and some additional metadata. Each Hamiltonian in a
    datapoint is a 1D TFI chain with boundary condition `boundary_condition` on
    `qubits` whos order parameter dictates the value of label. The circuit in a
    datapoint prepares (an approximation to) the ground state of the Hamiltonian
    in the datapoint.

    Example usage:

    >>> qbs = cirq.GridQubit.rect(4, 1)
    >>> circuits, labels, pauli_sums, addinfo  =
    ...     tfq.datasets.tfi_chain(qbs, "closed")

    You can print the available order parameters

    >>> [info.g for info in addinfo]
    [0.20, 0.22, 0.24, ... ,1.76, 1.78, 1.8]

    and the circuit corresponding to the ground state for a certain order
    parameter

    >>> print(circuits[10])
                                                          ┌─────── ...
    (0, 0): ───H───ZZ──────────────────────────────────ZZ───────── ...
                   │                                   │
    (1, 0): ───H───ZZ^0.761───ZZ─────────X^0.641───────┼────────── ...
                              │                        │
    (2, 0): ───H──────────────ZZ^0.761───ZZ────────────┼────────── ...
                                         │             │
    (3, 0): ───H─────────────────────────ZZ^0.761──────ZZ^0.761─── ...
                                                      └─────────── ...

    The labels indicate the phase of the system
    >>> labels[10]
    0

    Additionally, you can obtain the `cirq.PauliSum` representation of the
    Hamiltonian

    >>> print(pauli_sums[10])
    -1.000*Z((0, 0))*Z((1, 0))-1.000*Z((1, 0))*Z((2, 0))-1.000*Z((2, 0))*
    Z((3, 0))-1.000*Z((0, 0))*Z((3, 0)) ...
    -0.400*X((2, 0))-0.400*X((3, 0))

    The fourth output, `addinfo`, contains additional information
    about each instance of the system (see `tfq.datasets.spin_system.SpinSystem`
    ).

    For instance, you can print the ground state obtained from
    exact diagonalization

    >>> addinfo[10].gs
    [[-0.38852974+0.57092165j]
     [-0.04107317+0.06035461j]
                ...
     [-0.04107317+0.06035461j]
     [-0.38852974+0.57092165j]]

    with corresponding ground state energy

    >>> addinfo[10].gs_energy
    -4.169142950406478

    You can also inspect the parameters

    >>> addinfo[10].params
    {"theta_0": 0.7614564630036476, "theta_1": 0.6774991338794768,
    "theta_2": 0.6407093304791429, "theta_3": 0.7335369771742435}

    and change them to experiment with different parameter values by using
    the unresolved variational circuit returned by tfichain
    >>> new_params = {}
    ... for symbol_name, value in addinfo[10].params.items():
    ...    new_params[symbol_name] = 0.5 * value
    >>> new_params
    {"theta_0": 0.3807282315018238, "theta_1": 0.3387495669397384,
    "theta_2": 0.32035466523957146, "theta_3": 0.36676848858712174}
    >>> new_circuit = cirq.resolve_parameters(addinfo[10].var_circuit,
    ... new_params)
    >>> print(new_circuit)
                                                           ┌─────── ...
    (0, 0): ───H───ZZ──────────────────────────────────ZZ───────── ...
                   │                                   │
    (1, 0): ───H───ZZ^0.761───ZZ─────────X^0.32────────┼────────── ...
                              │                        │
    (2, 0): ───H──────────────ZZ^0.761───ZZ────────────┼────────── ...
                                         │             │
    (3, 0): ───H─────────────────────────ZZ^0.761──────ZZ^0.761─── ...
                                                      └─────────── ...

    Args:
        qubits: Python `lst` of `cirq.GridQubit`s. Supported number of spins
            are [4, 8, 12, 16].
        boundary_condition: Python `str` indicating the boundary condition
            of the chain. Supported boundary conditions are ["closed"].
        data_dir: Optional Python `str` location where to store the data on
            disk. Defaults to `/tmp/.keras`.
    Returns:
        A Python `lst` cirq.Circuit of depth len(qubits) / 2 with resolved
            parameters.
        A Python `lst` of labels, 0, for the ferromagnetic phase (`g<1`), 1 for
            the critical point (`g==1`) and 2 for the paramagnetic phase
            (`g>1`).
        A Python `lst` of `cirq.PauliSum`s.
        A Python `lst` of `namedtuple` instances containing the following
            fields:
        - `g`: Numpy `float` order parameter.
        - `gs`: Complex `np.ndarray` ground state wave function from
            exact diagonalization.
        - `gs_energy`: Numpy `float` ground state energy from exact
            diagonalization.
        - `res_energy`: Python `float` residual between the circuit energy
            and the exact energy from exact diagonalization.
        - `fidelity`: Python `float` overlap between the circuit state
            and the exact ground state from exact diagonalization.
        - `params`: Dict with Python `str` keys and Numpy`float` values.
            Contains $M \times P $ parameters. Here $M$ is the number of
            parameters per circuit layer and $P$ the circuit depth.
        - `var_circuit`: Variational `cirq.Circuit` quantum circuit with
            unresolved Sympy parameters.
    """

    supported_n = [4, 8, 12, 16]
    supported_bc = ["closed"]
    if any(isinstance(q, list) for q in qubits):
        raise TypeError("qubits must be a one-dimensional list")

    if not all(isinstance(q, cirq.GridQubit) for q in qubits):
        raise TypeError("qubits must be a list of cirq.GridQubit objects.")

    nspins = len(qubits)
    depth = nspins // 2
    if nspins not in supported_n:
        raise ValueError("Supported number of spins are {}, received {}".format(
            supported_n, nspins))

    if boundary_condition not in supported_bc:
        raise ValueError(
            "Supported boundary conditions are {}, received {}".format(
                supported_bc, boundary_condition))

    data_path = _download_spin_data('TFI_chain', boundary_condition, nspins,
                                    data_dir)

    name_generator = unique_name()

    # 2 * N/2 parameters.
    symbol_names = [next(name_generator) for _ in range(nspins)]
    symbols = [sympy.Symbol(name) for name in symbol_names]

    # Define the circuit.
    circuit = cirq.Circuit(cirq.H.on_each(qubits))

    for d in range(depth):
        circuit.append(
            cirq.ZZ(q1, q2)**(symbols[d]) for q1, q2 in zip(qubits, qubits[1:]))
        if boundary_condition == "closed":
            circuit.append(cirq.ZZ(qubits[nspins - 1], qubits[0])**(symbols[d]))
        circuit.append(cirq.X(q1)**(symbols[d + depth]) for q1 in qubits)

    # Initiate lists.
    resolved_circuits = []
    hamiltonians = []
    order_parameters = []
    additional_info = []
    labels = []
    # Load the data and append to the lists.
    for i, directory in enumerate(x for x in os.listdir(data_path)):
        # The folders are named according to the order value data they contain.
        g = float(directory)
        with open(os.path.join(data_path, directory, "stats.txt"), "r") as file:
            lines = file.readlines()
            res_e = float(lines[0].split("=")[1].strip("\n"))
            fidelity = float(lines[2].split("=")[1].strip("\n"))
        order_parameters.append(g)
        params = np.load(os.path.join(data_path, directory, "params.npy")) \
                 / np.pi
        # Parameters are stored as np.float32, but cirq expects np.float64
        # See https://github.com/quantumlib/Cirq/issues/3359
        params = params.astype(np.float)
        additional_info.append(
            SpinSystemInfo(g=g,
                           gs=np.load(
                               os.path.join(data_path, directory,
                                            "groundstate.npy"))[:, 0],
                           gs_energy=np.load(
                               os.path.join(data_path, directory,
                                            "energy.npy"))[0],
                           res_energy=res_e,
                           fidelity=fidelity,
                           params=dict(zip(symbol_names, params.flatten())),
                           var_circuit=circuit))

        # Resolve the circuit parameters.
        resolved_circuit = cirq.resolve_parameters(circuit,
                                                   additional_info[i].params)
        resolved_circuits.append(resolved_circuit)

        # Make the PauliSum.
        paulisum = sum(
            -cirq.Z(q1) * cirq.Z(q2) for q1, q2 in zip(qubits, qubits[1:]))
        if boundary_condition == "closed":
            paulisum += -cirq.Z(qubits[0]) * cirq.Z(qubits[-1])
        paulisum += -order_parameters[i] * sum(cirq.X(q) for q in qubits)
        hamiltonians.append(paulisum)

        # Set labels for the different phases.
        if order_parameters[i] < 1.0:
            labels.append(0)
        elif order_parameters[i] == 1.0:
            labels.append(1)
        else:
            labels.append(2)
    # Make sure that the data is ordered from g=0.2 to g=1.8.
    _, resolved_circuits, labels, hamiltonians, additional_info = zip(*sorted(
        zip(order_parameters, resolved_circuits, labels, hamiltonians,
            additional_info)))

    return resolved_circuits, labels, hamiltonians, additional_info