def spiders(n_legs_in, n_legs_out, dim): if len(dim) == 0: return Id() from discopy.quantum.gates import Bra, CX, H, Ket if n_legs_in == 0: d1 = Ket(0) >> H else: d1 = Id(qubit) for _ in range(n_legs_in - 1): d1 = d1 @ Id(qubit) >> CX >> Id(qubit) @ Bra(0) if n_legs_out == 0: d2 = H >> Bra(0) else: d2 = Id(qubit) for _ in range(n_legs_out - 1): d2 = Id(qubit) @ Ket(0) >> CX >> d2 @ Id(qubit) d = d1 >> d2 i, j, k = n_legs_in, n_legs_out, len(dim) permutation = Circuit.permutation p1 = permutation([i * (x % k) + (x // k) for x in range(i * k)]) p2 = permutation([k * (x % j) + (x // j) for x in range(j * k)]) ds = p1 >> Circuit.tensor(*[d] * len(dim)) >> p2 return ds
def measure(self, mixed=False): """ Measures a circuit on the computational basis using :code:`numpy`. Parameters ---------- mixed : bool, optional Whether to apply :class:`tensor.Functor` or :class:`CQMapFunctor`. Returns ------- array : numpy.ndarray """ from discopy.quantum.gates import Bra, Ket if mixed or self.is_mixed: return self.init_and_discard().eval(mixed=True).array.real state = (Ket(*(len(self.dom) * [0])) >> self).eval() effects = [ Bra(*index2bitstring(j, len(self.cod))).eval() for j in range(2**len(self.cod)) ] array = np.zeros(len(self.cod) * (2, ) or (1, )) for effect in effects: array += effect.array * np.absolute((state >> effect).array)**2 return array
def init_and_discard(self): """ Returns a circuit with empty domain and only bits as codomain. """ from discopy.quantum.gates import Bits, Ket circuit = self if circuit.dom: init = Id(0).tensor(*( Bits(0) if x.name == "bit" else Ket(0) for x in circuit.dom)) circuit = init >> circuit if circuit.cod != bit ** len(circuit.cod): discards = Id(0).tensor(*( Discard() if x.name == "qubit" else Id(bit) for x in circuit.cod)) circuit = circuit >> discards return circuit
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 = Id(0).tensor(*(n_qubits * [Ket(0)] + n_bits * [Bits(0)])) bras = {} 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]) swaps = swaps @ 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 Discard( ) if x.name == 'qubit' else Id(bit) for i, x in enumerate(circuit.cod))) if tk_circuit.scalar != 1: circuit = circuit @ MixedScalar(tk_circuit.scalar) return circuit >> tk_circuit.post_processing
def remove_ket1(box): if not isinstance(box, Ket): return box x_gates = Id(0).tensor(*(X if x else Id(1) for x in box.bitstring)) return Ket(*(len(box.bitstring) * (0, ))) >> x_gates