Esempio n. 1
0
def gen_pauli_measurement_circuits(state_circuit, compiler_pass, operator):
    # compile main circuit once
    state_cu = CompilationUnit(state_circuit)
    compiler_pass.apply(state_cu)
    compiled_state = state_cu.circuit
    final_map = state_cu.final_map
    # make a measurement circuit for each pauli
    pauli_circuits = []
    coeffs = []
    energy = 0
    for p, c in operator.terms.items():
        if p == ():
            # constant term
            energy += c
        else:
            # make measurement circuits and compile them
            pauli_circ = Circuit(state_circuit.n_qubits -
                                 1)  # ignore syndrome qubit
            append_pauli_measurement(qps_from_openfermion(p), pauli_circ)
            pauli_cu = CompilationUnit(pauli_circ)
            compiler_pass.apply(pauli_cu)
            pauli_circ = pauli_cu.circuit
            init_map = pauli_cu.initial_map
            # map measurements onto the placed qubits from the state
            rename_map = {
                i: final_map[o]
                for o, i in init_map.items() if o in final_map
            }
            pauli_circ.rename_units(rename_map)
            state_and_measure = compiled_state.copy()
            state_and_measure.append(pauli_circ)
            pauli_circuits.append(state_and_measure)
            coeffs.append(c)
    return pauli_circuits, coeffs, energy
Esempio n. 2
0
def predicate_route_device(my_circuit, my_device):
    gp = GraphPlacement(my_device)
    gp.place(my_circuit)
    cu = CompilationUnit(my_circuit, [ConnectivityPredicate(my_device)])
    routing_passes = SequencePass(
        [RoutingPass(my_device),
         DecomposeSwapsToCXs(my_device, False)])
    routing_passes.apply(cu)
    return cu.circuit, cu.check_all_predicates()
Esempio n. 3
0
def decompose_circuit(tk_circuit, decomposition_lvl):
    """Function to decompose circuit, with decomposition_lvl 1 decomposing BRIDGEs and 2 decomposing as much as possible (SWAPs).

    While normal pytket Circuits may contain bridge gates, these are not compatible with IBM Qiskit architectures. Therefore,
    one might have to decompose the circuit before converting it to an IBM Qiskit compatible version.

    Parameters
    ----------
    tk_circuit : pytket Circuit
        A pytket circuit
    decomposition_lvl : integer
        use 1 to decompose BRIDGEs, 2 to decompose as far as possible including SWAPs

    Returns
    -------
    pytket Circuit
        A pytket circuit decomposed
    """
    cu = CompilationUnit(tk_circuit)
    # 1 to decompose BRIDGE gates, 2 to decompose as far as possible (includes acceptable SWAPs!)
    if decomposition_lvl == 1:
        seqpass = SequencePass([DecomposeMultiQubitsIBM()])
    elif decomposition_lvl == 2:
        seqpass = SequencePass(
            [DecomposeMultiQubitsIBM(),
             DecomposeSingleQubitsIBM()])
    # apply decomposition and return the resulting circuit
    seqpass.apply(cu)
    return cu.circuit
Esempio n. 4
0
def place_on_device(
    circuit: cirq.Circuit,
    device: cirq.google.XmonDevice,
) -> Tuple[cirq.Circuit, Dict[cirq.Qid, cirq.Qid], Dict[cirq.Qid, cirq.Qid]]:
    """Place a circuit on an device.

    Converts a circuit to a new circuit that respects the adjacency of a given
    device and is equivalent to the given circuit up to qubit ordering.

    Args:
        circuit: The circuit to place on a grid.
        device: The device to place the circuit on.

    Returns:
        routed_circuit: The new circuit
        initial_map: Initial placement of qubits
        final_map: The final placement of qubits after action of the circuit
    """
    index_to_qubit = sorted(device.qubit_set())
    qubit_to_index = {q: i for i, q in enumerate(index_to_qubit)}
    tk_circuit = pytket.cirq.cirq_to_tk(circuit)
    tk_device = _device_to_tket_device(device, qubit_to_index)

    unit = CompilationUnit(tk_circuit, [ConnectivityPredicate(tk_device)])
    passes = SequencePass(
        [PlacementPass(GraphPlacement(tk_device)),
         RoutingPass(tk_device)])
    passes.apply(unit)
    valid = unit.check_all_predicates()
    if not valid:
        raise RuntimeError("Routing failed")

    initial_map = {
        cirq.LineQubit(_tk_to_i(n1)): index_to_qubit[_tk_to_i(n2)]
        for n1, n2 in unit.initial_map.items()
    }
    final_map = {
        cirq.LineQubit(_tk_to_i(n1)): index_to_qubit[_tk_to_i(n2)]
        for n1, n2 in unit.final_map.items()
    }
    routed_circuit = pytket.cirq.tk_to_cirq(unit.circuit)
    routed_circuit = routed_circuit.transform_qubits(
        lambda q: index_to_qubit[q.x])

    return routed_circuit, initial_map, final_map
Esempio n. 5
0
def place_on_device(
    circuit: cirq.Circuit,
    device: cg.XmonDevice,
) -> Tuple[cirq.Circuit, Dict[cirq.Qid, cirq.Qid], Dict[cirq.Qid, cirq.Qid]]:
    """Place a circuit on an device.

    Converts a circuit to a new circuit that respects the adjacency of a given
    device and is equivalent to the given circuit up to qubit ordering.

    Args:
        circuit: The circuit to place on a grid.
        device: The device to place the circuit on.

    Returns:
        routed_circuit: The new circuit
        initial_map: Initial placement of qubits
        final_map: The final placement of qubits after action of the circuit
    """
    tk_circuit = pytket.extensions.cirq.cirq_to_tk(circuit)
    tk_device = _device_to_tket_device(device)

    unit = CompilationUnit(tk_circuit, [ConnectivityPredicate(tk_device)])
    passes = SequencePass(
        [PlacementPass(GraphPlacement(tk_device)),
         RoutingPass(tk_device)])
    passes.apply(unit)
    valid = unit.check_all_predicates()
    if not valid:
        raise RuntimeError("Routing failed")

    initial_map = {
        tk_to_cirq_qubit(n1): tk_to_cirq_qubit(n2)
        for n1, n2 in unit.initial_map.items()
    }
    final_map = {
        tk_to_cirq_qubit(n1): tk_to_cirq_qubit(n2)
        for n1, n2 in unit.final_map.items()
    }
    routed_circuit = pytket.extensions.cirq.tk_to_cirq(unit.circuit)

    return routed_circuit, initial_map, final_map
Esempio n. 6
0
def compile_measurements(all_measures, backend, ansatz_final_map):
    compiled_measures = []
    for measure_circ in all_measures:
        cu = CompilationUnit(measure_circ)
        backend.default_compilation_pass.apply(cu)
        measure_circ = cu.circuit
        # Permute qubits to match their locations after the ansatz
        qb_map = {
            cu.final_map[m_qb]: original_qb
            for original_qb, m_qb in ansatz_final_map.items()
        }
        measure_circ.rename_units(qb_map)
        compiled_measures.append(measure_circ)
    return compiled_measures
Esempio n. 7
0
 def run(self, qobj: QasmQobj) -> TketJob:
     module = disassemble(qobj)
     circ_list = [qiskit_to_tk(qc) for qc in module[0]]
     if self._comp_pass:
         final_maps = []
         compiled_list = []
         for c in circ_list:
             cu = CompilationUnit(c)
             self._comp_pass.apply(cu)
             compiled_list.append(cu.circuit)
             final_maps.append(cu.final_map)
         circ_list = compiled_list
     else:
         final_maps = [None for c in circ_list]
     handles = self._backend.process_circuits(circ_list, n_shots=qobj.config.shots)
     return TketJob(self, handles, qobj, final_maps)
def test_swaps_basisorder() -> None:
    # Check that implicit swaps can be corrected irrespective of BasisOrder
    b = AerStateBackend()
    c = Circuit(4)
    c.X(0)
    c.CX(0, 1)
    c.CX(1, 0)
    c.CX(1, 3)
    c.CX(3, 1)
    c.X(2)
    cu = CompilationUnit(c)
    CliffordSimp(True).apply(cu)
    c1 = cu.circuit
    assert c1.n_gates_of_type(OpType.CX) == 2

    b.compile_circuit(c)
    b.compile_circuit(c1)

    handles = b.process_circuits([c, c1])
    s_ilo = b.get_state(c1, basis=BasisOrder.ilo)
    correct_ilo = b.get_state(c, basis=BasisOrder.ilo)

    assert np.allclose(s_ilo, correct_ilo)
    s_dlo = b.get_state(c1, basis=BasisOrder.dlo)
    correct_dlo = b.get_state(c, basis=BasisOrder.dlo)
    assert np.allclose(s_dlo, correct_dlo)

    qbs = c.qubits
    for result in b.get_results(handles):
        assert (result.get_state([qbs[1], qbs[2], qbs[3],
                                  qbs[0]]).real.tolist().index(1.0) == 6)
        assert (result.get_state([qbs[2], qbs[1], qbs[0],
                                  qbs[3]]).real.tolist().index(1.0) == 9)
        assert (result.get_state([qbs[2], qbs[3], qbs[0],
                                  qbs[1]]).real.tolist().index(1.0) == 12)

    bu = AerUnitaryBackend()
    u_ilo = bu.get_unitary(c1, basis=BasisOrder.ilo)
    correct_ilo = bu.get_unitary(c, basis=BasisOrder.ilo)
    assert np.allclose(u_ilo, correct_ilo)
    u_dlo = bu.get_unitary(c1, basis=BasisOrder.dlo)
    correct_dlo = bu.get_unitary(c, basis=BasisOrder.dlo)
    assert np.allclose(u_dlo, correct_dlo)
Esempio n. 9
0
def run_tket_pass(circ: Circuit, total_pass, backend: str):
    try:
        cu = CompilationUnit(circ)
        start_time = time.process_time()
        total_pass.apply(cu)
        time_elapsed = time.process_time() - start_time
        print(time_elapsed)
        circ2 = cu.circuit
        if backend in (_BACKEND_GOOGLE, _BACKEND_RIGETTI):
            two_qb_gate = OpType.CZ
        else:
            two_qb_gate = OpType.CX
        return [
            circ2.n_gates,
            circ2.depth(),
            circ2.n_gates_of_type(two_qb_gate),
            circ2.depth_by_type(two_qb_gate), time_elapsed
        ]
    except Exception as e:
        print(e)
        print("t|ket> error")
        return [nan, nan, nan, nan, nan]
Esempio n. 10
0
def test_compilation_correctness() -> None:
    c = Circuit(5)
    c.H(0).H(1).H(2)
    c.CX(0, 1).CX(1, 2)
    c.Rx(0.25, 1).Ry(0.75, 1).Rz(0.5, 2)
    c.CCX(2, 1, 0)
    c.CY(1, 0).CY(2, 1)
    c.H(0).H(1).H(2)
    c.Rz(0.125, 0)
    c.X(1)
    c.Rz(0.125, 2).X(2).Rz(0.25, 2)
    c.SX(3).Rz(0.125, 3).SX(3)
    c.CX(0, 3).CX(0, 4)
    u_backend = AerUnitaryBackend()
    u = u_backend.get_unitary(c)
    ibm_backend = IBMQBackend("ibmq_santiago",
                              hub="ibm-q",
                              group="open",
                              project="main")
    for ol in range(3):
        p = ibm_backend.default_compilation_pass(optimisation_level=ol)
        cu = CompilationUnit(c)
        p.apply(cu)
        c1 = cu.circuit
        compiled_u = u_backend.get_unitary(c1)

        # Adjust for placement
        imap = cu.initial_map
        fmap = cu.final_map
        c_idx = {c.qubits[i]: i for i in range(5)}
        c1_idx = {c1.qubits[i]: i for i in range(5)}
        ini = {c_idx[qb]: c1_idx[node] for qb, node in imap.items()}
        inv_fin = {c1_idx[node]: c_idx[qb] for qb, node in fmap.items()}
        m_ini = lift_perm(ini)
        m_inv_fin = lift_perm(inv_fin)

        assert compare_unitaries(u, m_inv_fin @ compiled_u @ m_ini)
Esempio n. 11
0
def compile_ansatz(ansatz, backend):
    # Solve for device constraints
    cu = CompilationUnit(ansatz)
    backend.default_compilation_pass.apply(cu)
    return cu.circuit, cu.final_map
Esempio n. 12
0
                          (15, 16), (16, 17), (17, 18), (18, 19), (19, 20),
                          (20, 21), (21, 22), (12, 23), (16, 24), (20, 25),
                          (23, 26), (24, 30), (25, 34), (26, 27), (27, 28),
                          (28, 29), (29, 30), (30, 31), (31, 32), (32, 33),
                          (33, 34), (34, 35), (35, 36), (28, 37), (32, 38),
                          (36, 39), (37, 42), (38, 46), (39, 50), (40, 41),
                          (41, 42), (42, 43), (43, 44), (44, 45), (45, 46),
                          (46, 47), (47, 48), (48, 49), (49, 50), (40, 51),
                          (44, 52), (48, 53), (51, 54), (52, 58), (53, 62),
                          (54, 55), (55, 56), (56, 57), (57, 58), (58, 59),
                          (59, 60), (60, 61), (61, 62), (62, 63), (63, 64),
                          (56, 65), (60, 66), (64, 67), (65, 70), (66, 74),
                          (67, 78), (68, 69), (69, 70), (70, 71), (71, 72),
                          (72, 73), (73, 74), (74, 75), (75, 76), (76, 77),
                          (77, 78), (68, 79), (72, 80), (76, 81)]

tk_circuit = pytket.cirq.cirq_to_tk(circuit)
tk_device = _device_connection_list_to_tket_device(device_connection_list)

unit = CompilationUnit(tk_circuit, [ConnectivityPredicate(tk_device)])

passes = SequencePass([
    PlacementPass(GraphPlacement(tk_device)),
    RoutingPass(tk_device, bridge_lookahead=0, bridge_interactions=0)
])  # NO BRIDGE
passes.apply(unit)
valid = unit.check_all_predicates()

assert valid

routed_circuit = pytket.cirq.tk_to_cirq(unit.circuit)
Esempio n. 13
0
pass1 = DecomposeMultiQubitsIBM()

# This pass converts all multi-qubit gates into CX and single-qubit gates. So let's create a circuit containing some non-CX multi-qubit gates:

from pytket.circuit import Circuit

circ = Circuit(3)
circ.CRz(0.5, 0, 1)
circ.T(2)
circ.CSWAP(2, 0, 1)

# In order to apply a pass to a circuit, we must first create a `CompilationUnit` from it. We can think of this as a 'bridge' between the circuit and the pass. The `CompilationUnit` is constructed from the circuit; the pass is applied to the `CompilationUnit`; and the transformed circuit is extracted from the `CompilationUnit`:

from pytket.predicates import CompilationUnit

cu = CompilationUnit(circ)
pass1.apply(cu)
circ1 = cu.circuit

# Let's have a look at the result of the transformation:

print(circ1.get_commands())

# ## Predicates

# Every `CompilationUnit` has associated with it a set of 'predicates', which describe target properties that can be checked against the circuit. There are many types of predicates available in `pytket`. For example, the `GateSetPredicate` checks whether all gates in a circuit belong to a particular set:

from pytket.predicates import GateSetPredicate
from pytket.circuit import OpType

pred1 = GateSetPredicate(