def _set_qubit_x_true(clifford, circuit, qubit): """Set destabilizer.X[qubit, qubit] to be True. This is done by permuting columns l > qubit or if necessary applying a Hadamard """ x = clifford.destabilizer.X[qubit] z = clifford.destabilizer.Z[qubit] if x[qubit]: return # Try to find non-zero element for i in range(qubit + 1, clifford.num_qubits): if x[i]: _append_swap(clifford, i, qubit) circuit.swap(i, qubit) return # no non-zero element found: need to apply Hadamard somewhere for i in range(qubit, clifford.num_qubits): if z[i]: _append_h(clifford, i) circuit.h(i) if i != qubit: _append_swap(clifford, i, qubit) circuit.swap(i, qubit) return
def _calc_decoupling(cliff_ox, cliff_oz, qubit_list, min_qubit, num_qubits): """Calculate a decoupling operator D: D^{-1} * Ox * D = x1 D^{-1} * Oz * D = z1 and reduce the clifford such that it will act trivially on min_qubit """ circ = QuantumCircuit(num_qubits) # decouple_cliff is initialized to an identity clifford decouple_cliff = cliff_ox.copy() num_qubits = decouple_cliff.num_qubits decouple_cliff.table.phase = np.zeros(2 * num_qubits) if (decouple_cliff.table.array != np.eye(2 * num_qubits)).any(): raise QiskitError("Symplectic Gaussian elimination fails.") qubit0 = min_qubit # The qubit for the symplectic Gaussian elimination # Reduce the pair of Paulis to a representative in the equivalence class # ['XZ', 'XX', 'XI', 'IZ', 'II'] by adding single-qubit gates for qubit in qubit_list: typeq = _from_pair_cliffs_to_type(cliff_ox, cliff_oz, qubit) if typeq in [ [[True, True], [False, False]], # 'YI' [[True, True], [True, True]], # 'YY' [[True, True], [True, False]] ]: # 'YZ': circ.s(qubit) _append_s(decouple_cliff, qubit) elif typeq in [ [[True, False], [False, False]], # 'ZI' [[True, False], [True, False]], # 'ZZ' [[True, False], [False, True]], # 'ZX' [[False, False], [False, True]] ]: # 'IX' circ.h(qubit) _append_h(decouple_cliff, qubit) elif typeq in [ [[False, False], [True, True]], # 'IY' [[True, False], [True, True]] ]: # 'ZY' circ.s(qubit) circ.h(qubit) _append_s(decouple_cliff, qubit) _append_h(decouple_cliff, qubit) elif typeq == [[True, True], [False, True]]: # 'YX' circ.h(qubit) circ.s(qubit) _append_h(decouple_cliff, qubit) _append_s(decouple_cliff, qubit) elif typeq == [[False, True], [True, True]]: # 'XY' circ.s(qubit) circ.h(qubit) circ.s(qubit) _append_s(decouple_cliff, qubit) _append_h(decouple_cliff, qubit) _append_s(decouple_cliff, qubit) # Reducing each pair of Paulis (except of qubit0) to 'II' # by adding two-qubit gates and single-qubit gates A_qubits = [] B_qubits = [] C_qubits = [] D_qubits = [] for qubit in qubit_list: typeq = _from_pair_cliffs_to_type(cliff_ox, cliff_oz, qubit) if typeq in A_class: A_qubits.append(qubit) elif typeq in B_class: B_qubits.append(qubit) elif typeq in C_class: C_qubits.append(qubit) elif typeq in D_class: D_qubits.append(qubit) if len(A_qubits) % 2 != 1: raise QiskitError("Symplectic Gaussian elimination fails.") if qubit0 not in A_qubits: # SWAP qubit0 and qubitA qubitA = A_qubits[0] circ.swap(qubit0, qubitA) _append_swap(decouple_cliff, qubit0, qubitA) if qubit0 in B_qubits: B_qubits.remove(qubit0) B_qubits.append(qubitA) A_qubits.remove(qubitA) A_qubits.append(qubit0) elif qubit0 in C_qubits: C_qubits.remove(qubit0) C_qubits.append(qubitA) A_qubits.remove(qubitA) A_qubits.append(qubit0) elif qubit0 in D_qubits: D_qubits.remove(qubit0) D_qubits.append(qubitA) A_qubits.remove(qubitA) A_qubits.append(qubit0) else: A_qubits.remove(qubitA) A_qubits.append(qubit0) # Reduce pairs in Class C to 'II' for qubit in C_qubits: circ.cx(qubit0, qubit) _append_cx(decouple_cliff, qubit0, qubit) # Reduce pairs in Class D to 'II' for qubit in D_qubits: circ.cx(qubit, qubit0) _append_cx(decouple_cliff, qubit, qubit0) # Reduce pairs in Class B to 'II' if len(B_qubits) > 1: for qubit in B_qubits[1:]: qubitB = B_qubits[0] circ.cx(qubitB, qubit) _append_cx(decouple_cliff, qubitB, qubit) if len(B_qubits) > 0: qubitB = B_qubits[0] circ.cx(qubit0, qubitB) circ.h(qubitB) circ.cx(qubitB, qubit0) _append_cx(decouple_cliff, qubit0, qubitB) _append_h(decouple_cliff, qubitB) _append_cx(decouple_cliff, qubitB, qubit0) # Reduce pairs in Class A (except of qubit0) to 'II' Alen = int((len(A_qubits) - 1) / 2) if Alen > 0: A_qubits.remove(qubit0) for qubit in range(Alen): circ.cx(A_qubits[2 * qubit + 1], A_qubits[2 * qubit]) circ.cx(A_qubits[2 * qubit], qubit0) circ.cx(qubit0, A_qubits[2 * qubit + 1]) _append_cx(decouple_cliff, A_qubits[2 * qubit + 1], A_qubits[2 * qubit]) _append_cx(decouple_cliff, A_qubits[2 * qubit], qubit0) _append_cx(decouple_cliff, qubit0, A_qubits[2 * qubit + 1]) return circ, decouple_cliff