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
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