def remove_ket1(box): if not isinstance(box, Ket): return box x_gates = Circuit.id(0) for bit in box.bitstring: x_gates = x_gates @ (X if bit else Circuit.id(1)) return Ket(*(len(box.bitstring) * (0, ))) >> x_gates
def tensor_from_counts(counts, post_selection=None, scalar=1, normalize=True): """ Parameters ---------- counts : dict From bitstrings to counts. post_selection : dict, optional From qubit indices to bits. scalar : complex, optional Scale the output using the Born rule. normalize : bool, optional Whether to normalize the counts. Returns ------- tensor : discopy.tensor.Tensor Of dimension :code:`n_qubits * (2, )` for :code:`n_qubits` the number of post-selected qubits. """ if normalize: counts = probs_from_counts(counts) n_qubits = len(list(counts.keys()).pop()) if post_selection: post_selected = dict() for bitstring, count in counts.items(): if all(bitstring[qubit] == bit for qubit, bit in post_selection.items()): post_selected.update({ tuple(bit for qubit, bit in enumerate(bitstring) if qubit not in post_selection): count }) n_qubits -= len(post_selection.keys()) counts = post_selected array = np.zeros(n_qubits * (2, )) for bitstring, count in counts.items(): array += count * Ket(*bitstring).array array = abs(scalar)**2 * array return Tensor(Dim(1), Dim(*(n_qubits * (2, ))), array)
def to_tk(self): def remove_ket1(box): if not isinstance(box, Ket): return box x_gates = Circuit.id(0) for bit in box.bitstring: x_gates = x_gates @ (X if bit else Circuit.id(1)) return Ket(*(len(box.bitstring) * (0, ))) >> x_gates def swap(tk_circ, i, j): old = Qubit('q', i) tmp = Qubit('tmp', 0) new = Qubit('q', j) tk_circ.rename_units({old: tmp}) tk_circ.rename_units({new: old}) tk_circ.rename_units({tmp: new}) def prepare_qubit(tk_circ, left, box, right): if len(right) > 0: renaming = dict() for i in range(len(left), tk_circ.n_qubits): old = Qubit('q', i) new = Qubit('q', i + len(box.cod)) renaming.update({old: new}) tk_circ.rename_units(renaming) tk_circ.add_blank_wires(len(box.cod)) def add_gate(tk_circ, box, off): qubits = [off + j for j in range(len(box.dom))] if isinstance(box, (Rx, Rz)): tk_circ.__getattribute__(box.name[:2])(2 * box.phase, *qubits) elif isinstance(box, CRz): tk_circ.__getattribute__(box.name[:3])(2 * box.phase, *qubits) else: tk_circ.__getattribute__(box.name)(*qubits) def measure_qubit(tk_circ, left, box, right): if len(right) > 0: renaming = dict() for i, _ in enumerate(box.dom): old = Qubit('q', len(left) + i) tmp = Qubit('tmp', i) renaming.update({old: tmp}) for i, _ in enumerate(right): old = Qubit('q', len(left @ box.dom) + i) new = Qubit('q', len(left) + i) renaming.update({old: new}) tk_circ.rename_units(renaming) renaming = dict() for j, _ in enumerate(box.dom): tmp = Qubit('tmp', j) new = Qubit('q', len(left @ right) + j) renaming.update({tmp: new}) tk_circ.rename_units(renaming) return { len(left @ right) + j: box.bitstring[j] for j, _ in enumerate(box.dom) } circuit = CircuitFunctor(ob=Quiver(len), ar=Quiver(remove_ket1))(self) if circuit.dom != PRO(0): circuit = Ket(*(len(circuit.dom) * (0, ))) >> circuit tk_circ = TketCircuit() for left, box, right in circuit.layers: if isinstance(box, Ket): prepare_qubit(tk_circ, left, box, right) elif isinstance(box, Bra): tk_circ.post_selection.update( measure_qubit(tk_circ, left, box, right)) elif box == SWAP: swap(tk_circ, len(left), len(left) + 1) elif box.dom == box.cod == PRO(0): tk_circ.scalar *= box.array[0] else: add_gate(tk_circ, box, len(left)) return tk_circ