Ejemplo n.º 1
0
 def make_units_adjacent(tk_gate):
     offset = tk_gate.qubits[0].index[0]
     swaps = Id(qubit**n_qubits @ bit**n_bits)
     for i, tk_qubit in enumerate(tk_gate.qubits[1:]):
         source, target = tk_qubit.index[0], offset + i + 1
         if source < target:
             left, right = swaps.cod[:source], swaps.cod[target:]
             swap = Id.swap(swaps.cod[source:source + 1],
                            swaps.cod[source + 1:target])
             if source <= offset:
                 offset -= 1
         elif source > target:
             left, right = swaps.cod[:target], swaps.cod[source + 1:]
             swap = Id.swap(swaps.cod[target:target + 1],
                            swaps.cod[target + 1:source + 1])
         else:  # pragma: no cover
             continue  # units are adjacent already
         swaps = swaps >> Id(left) @ swap @ Id(right)
     return offset, swaps
Ejemplo n.º 2
0
def from_tk(tk_circuit):
    """
    Translates from tket to discopy.
    """
    if not isinstance(tk_circuit, tk.Circuit):
        raise TypeError(messages.type_err(tk.Circuit, tk_circuit))
    if not isinstance(tk_circuit, Circuit):
        tk_circuit = Circuit.upgrade(tk_circuit)
    n_bits = tk_circuit.n_bits - len(tk_circuit.post_selection)
    n_qubits = tk_circuit.n_qubits

    def box_from_tk(tk_gate):
        name = tk_gate.op.type.name
        if name == 'Rx':
            return Rx(tk_gate.op.params[0] / 2)
        if name == 'Rz':
            return Rz(tk_gate.op.params[0] / 2)
        if name == 'CRz':
            return CRz(tk_gate.op.params[0] / 2)
        for gate in GATES:
            if name == gate.name:
                return gate
        raise NotImplementedError

    def make_units_adjacent(tk_gate):
        offset = tk_gate.qubits[0].index[0]
        swaps = Id(qubit**n_qubits @ bit**n_bits)
        for i, tk_qubit in enumerate(tk_gate.qubits[1:]):
            source, target = tk_qubit.index[0], offset + i + 1
            if source < target:
                left, right = swaps.cod[:source], swaps.cod[target:]
                swap = Id.swap(swaps.cod[source:source + 1],
                               swaps.cod[source + 1:target])
                if source <= offset:
                    offset -= 1
            elif source > target:
                left, right = swaps.cod[:target], swaps.cod[source + 1:]
                swap = Id.swap(swaps.cod[target:target + 1],
                               swaps.cod[target + 1:source + 1])
            else:  # pragma: no cover
                continue  # units are adjacent already
            swaps = swaps >> Id(left) @ swap @ Id(right)
        return offset, swaps

    circuit, bras = Id(qubit**n_qubits @ bit**n_bits), {}
    for tk_gate in tk_circuit.get_commands():
        if tk_gate.op.type.name == "Measure":
            offset = tk_gate.qubits[0].index[0]
            bit_index = tk_gate.bits[0].index[0]
            if bit_index in tk_circuit.post_selection:
                bras[offset] = tk_circuit.post_selection[bit_index]
                continue  # post selection happens at the end
            box = Measure(destructive=False, override_bits=True)
            swaps = Id(circuit.cod[:offset + 1]) @ Id.swap(
               circuit.cod[offset + 1:n_qubits + bit_index],
               circuit.cod[n_qubits:][bit_index: bit_index + 1])\
               @ Id(circuit.cod[n_qubits + bit_index + 1:])
        else:
            box = box_from_tk(tk_gate)
            offset, swaps = make_units_adjacent(tk_gate)
        left, right = swaps.cod[:offset], swaps.cod[offset + len(box.dom):]
        circuit = circuit >> swaps >> Id(left) @ box @ Id(right) >> swaps[::-1]
    circuit = circuit >> Id(0).tensor(
        *(Bra(bras[i]) if i in bras else Id(circuit.cod[i:i + 1])
          for i, _ in enumerate(circuit.cod)))
    if tk_circuit.scalar != 1:
        circuit = circuit @ scalar_box(tk_circuit.scalar)
    return circuit