def _set_row_x_zero(clifford, circuit, qubit): """Set destabilizer.X[qubit, i] to False for all i > qubit. This is done by applying CNOTS assumes k<=N and A[k][k]=1 """ x = clifford.destabilizer.X[qubit] z = clifford.destabilizer.Z[qubit] # Check X first for i in range(qubit + 1, clifford.num_qubits): if x[i]: _append_cx(clifford, qubit, i) circuit.cx(qubit, i) # Check whether Zs need to be set to zero: if np.any(z[qubit:]): if not z[qubit]: # to treat Zs: make sure row.Z[k] to True _append_s(clifford, qubit) circuit.s(qubit) # reverse CNOTS for i in range(qubit + 1, clifford.num_qubits): if z[i]: _append_cx(clifford, i, qubit) circuit.cx(i, qubit) # set row.Z[qubit] to False _append_s(clifford, qubit) circuit.s(qubit)
def _set_row_z_zero(clifford, circuit, qubit): """Set stabilizer.Z[qubit, i] to False for all i > qubit. Implemented by applying (reverse) CNOTS assumes qubit < num_qubits and _set_row_x_zero has been called first """ x = clifford.stabilizer.X[qubit] z = clifford.stabilizer.Z[qubit] # check whether Zs need to be set to zero: if np.any(z[qubit + 1:]): for i in range(qubit + 1, clifford.num_qubits): if z[i]: _append_cx(clifford, i, qubit) circuit.cx(i, qubit) # check whether Xs need to be set to zero: if np.any(x[qubit:]): _append_h(clifford, qubit) circuit.h(qubit) for i in range(qubit + 1, clifford.num_qubits): if x[i]: _append_cx(clifford, qubit, i) circuit.cx(qubit, i) if z[qubit]: _append_s(clifford, qubit) circuit.s(qubit) _append_h(clifford, qubit) circuit.h(qubit)
def _reduce_cost(clifford, inv_circuit, cost): """Two-qubit cost reduction step""" num_qubits = clifford.num_qubits for qubit0 in range(num_qubits): for qubit1 in range(qubit0 + 1, num_qubits): for n0, n1 in product(range(3), repeat=2): # Apply a 2-qubit block reduced = clifford.copy() for qubit, n in [(qubit0, n0), (qubit1, n1)]: if n == 1: _append_v(reduced, qubit) elif n == 2: _append_w(reduced, qubit) _append_cx(reduced, qubit0, qubit1) # Compute new cost new_cost = _cx_cost(reduced) if new_cost == cost - 1: # Add decomposition to inverse circuit for qubit, n in [(qubit0, n0), (qubit1, n1)]: if n == 1: inv_circuit.sdg(qubit) inv_circuit.h(qubit) elif n == 2: inv_circuit.h(qubit) inv_circuit.s(qubit) inv_circuit.cx(qubit0, qubit1) return reduced, inv_circuit, new_cost # If we didn't reduce cost raise QiskitError("Failed to reduce Clifford CX cost.")
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