def _generate_gate_set_for_arc_prob(target, params, cond_probs): # Here we deviate slightly from the original paper, by using Gray coding as described in: # [arXiv:1306.3991](https://arxiv.org/abs/1306.3991){:.external} # # The goal is to reduce the total number of gates, but the math is unchanged. graycode = GrayCode(len(params)) previous_binary = '1' * (2**len(params)) for notted_binary in graycode.generate_gray(): # We get the NOT of the code because we want to start with 111...1 so that we don't need # to have X gates on all qubits from the begining. This does not change the output and is # simply an optimization. binary = ''.join('1' if bit == '0' else '0' for bit in notted_binary) # TODO(tonybruguier): Further reduce the number of gates in case the prob is 0.0. This # would mean skipping a Gray code, so the accounting of the X gates must be done # carefully. for bit, previous_bit, param in zip(binary, previous_binary, params): if bit != previous_bit: yield pauli_gates.X(param) yield common_gates.ry(_prob_to_angle(cond_probs[int( binary, 2)])).on(target).controlled_by(*params) previous_binary = binary for previous_bit, param in zip(previous_binary, params): if previous_bit == '0': yield pauli_gates.X(param)
def _decompose_outside_control( self, control: 'cirq.Qid', near_target: 'cirq.Qid', far_target: 'cirq.Qid' ) -> 'cirq.OP_TREE': """A decomposition assuming one of the targets is in the middle. control: ───T──────@────────@───@────────────@──────────────── │ │ │ │ near: ─X─T──────X─@─T^-1─X─@─X────@─X^0.5─X─@─X^0.5──────── │ │ │ │ │ far: ─@─Y^-0.5─T─X─T──────X─T^-1─X─T^-1────X─S─────X^-0.5─ """ a, b, c = control, near_target, far_target t = common_gates.T sweep_abc = [common_gates.CNOT(a, b), common_gates.CNOT(b, c)] yield common_gates.CNOT(c, b) yield pauli_gates.Y(c) ** -0.5 yield t(a), t(b), t(c) yield sweep_abc yield t(b) ** -1, t(c) yield sweep_abc yield t(c) ** -1 yield sweep_abc yield t(c) ** -1 yield pauli_gates.X(b) ** 0.5 yield sweep_abc yield common_gates.S(c) yield pauli_gates.X(b) ** 0.5 yield pauli_gates.X(c) ** -0.5
def _decompose_(self, qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE': if len(self.dense_pauli_string) <= 0: return any_qubit = qubits[0] to_z_ops = op_tree.freeze_op_tree(self._to_z_basis_ops(qubits)) xor_decomp = tuple(xor_nonlocal_decompose(qubits, any_qubit)) yield to_z_ops yield xor_decomp if self.exponent_neg: yield pauli_gates.Z(any_qubit)**self.exponent_neg if self.exponent_pos: yield pauli_gates.X(any_qubit) yield pauli_gates.Z(any_qubit)**self.exponent_pos yield pauli_gates.X(any_qubit) yield protocols.inverse(xor_decomp) yield protocols.inverse(to_z_ops)
def _decompose_(self) -> op_tree.OP_TREE: if len(self.pauli_string) <= 0: return qubits = self.qubits any_qubit = qubits[0] to_z_ops = op_tree.freeze_op_tree(self.pauli_string.to_z_basis_ops()) xor_decomp = tuple(xor_nonlocal_decompose(qubits, any_qubit)) yield to_z_ops yield xor_decomp if self.exponent_neg: yield pauli_gates.Z(any_qubit)**self.exponent_neg if self.exponent_pos: yield pauli_gates.X(any_qubit) yield pauli_gates.Z(any_qubit)**self.exponent_pos yield pauli_gates.X(any_qubit) yield protocols.inverse(xor_decomp) yield protocols.inverse(to_z_ops)
def _decompose_inside_control(self, target1: raw_types.QubitId, control: raw_types.QubitId, target2: raw_types.QubitId ) -> op_tree.OP_TREE: """A decomposition assuming the control separates the targets. target1: ─@─X───────T──────@────────@─────────X───@─────X^-0.5─ │ │ │ │ │ │ control: ─X─@─X─────@─T^-1─X─@─T────X─@─X^0.5─@─@─X─@────────── │ │ │ │ │ │ target2: ─────@─H─T─X─T──────X─T^-1───X─T^-1────X───X─H─S^-1─── """ a, b, c = target1, control, target2 yield common_gates.CNOT(a, b) yield common_gates.CNOT(b, a) yield common_gates.CNOT(c, b) yield common_gates.H(c) yield common_gates.T(c) yield common_gates.CNOT(b, c) yield common_gates.T(a) yield common_gates.T(b)**-1 yield common_gates.T(c) yield common_gates.CNOT(a, b) yield common_gates.CNOT(b, c) yield common_gates.T(b) yield common_gates.T(c)**-1 yield common_gates.CNOT(a, b) yield common_gates.CNOT(b, c) yield pauli_gates.X(b)**0.5 yield common_gates.T(c)**-1 yield common_gates.CNOT(b, a) yield common_gates.CNOT(b, c) yield common_gates.CNOT(a, b) yield common_gates.CNOT(b, c) yield common_gates.H(c) yield common_gates.S(c)**-1 yield pauli_gates.X(a)**-0.5
def _decompose_inside_control( self, target1: 'cirq.Qid', control: 'cirq.Qid', target2: 'cirq.Qid' ) -> 'cirq.OP_TREE': """A decomposition assuming the control separates the targets. target1: ─@─X───────T──────@────────@─────────X───@─────X^-0.5─ │ │ │ │ │ │ control: ─X─@─X─────@─T^-1─X─@─T────X─@─X^0.5─@─@─X─@────────── │ │ │ │ │ │ target2: ─────@─H─T─X─T──────X─T^-1───X─T^-1────X───X─H─S^-1─── """ a, b, c = target1, control, target2 yield common_gates.CNOT(a, b) yield common_gates.CNOT(b, a) yield common_gates.CNOT(c, b) yield common_gates.H(c) yield common_gates.T(c) yield common_gates.CNOT(b, c) yield common_gates.T(a) yield common_gates.T(b) ** -1 yield common_gates.T(c) yield common_gates.CNOT(a, b) yield common_gates.CNOT(b, c) yield common_gates.T(b) yield common_gates.T(c) ** -1 yield common_gates.CNOT(a, b) yield common_gates.CNOT(b, c) yield pauli_gates.X(b) ** 0.5 yield common_gates.T(c) ** -1 yield common_gates.CNOT(b, a) yield common_gates.CNOT(b, c) yield common_gates.CNOT(a, b) yield common_gates.CNOT(b, c) yield common_gates.H(c) yield common_gates.S(c) ** -1 yield pauli_gates.X(a) ** -0.5
def __pow__(self, exponent: int) -> 'LinearCombinationOfOperations': if not isinstance(exponent, int): return NotImplemented if exponent < 0: return NotImplemented if len(self.qubits) != 1: return NotImplemented qubit = self.qubits[0] i = identity.I(qubit) x = pauli_gates.X(qubit) y = pauli_gates.Y(qubit) z = pauli_gates.Z(qubit) pauli_basis = {i, x, y, z} if not set(self.keys()).issubset(pauli_basis): return NotImplemented ai, ax, ay, az = self[i], self[x], self[y], self[z] bi, bx, by, bz = operator_spaces.pow_pauli_combination(ai, ax, ay, az, exponent) return LinearCombinationOfOperations({i: bi, x: bx, y: by, z: bz})