def test_str(): c1 = cirq.NamedQubit('c1') c2 = cirq.NamedQubit('c2') q2 = cirq.NamedQubit('q2') assert (str(cirq.ControlledOperation([c1], cirq.CZ(c2, q2))) == "CCZ(c1, c2, q2)") class SingleQubitOp(cirq.Operation): def qubits(self) -> Tuple[cirq.Qid, ...]: pass def with_qubits(self, *new_qubits: cirq.Qid): pass def __str__(self): return "Op(q2)" assert (str(cirq.ControlledOperation( [c1, c2], SingleQubitOp())) == "C(c1, c2, Op(q2))")
def test_controlled_operation_init(): cb = cirq.NamedQubit('ctr') q = cirq.NamedQubit('q') g = cirq.SingleQubitGate() v = cirq.GateOperation(g, (q,)) c = cirq.ControlledOperation([cb], v) assert c.sub_operation == v assert c.controls == (cb,) assert c.qubits == (cb, q) assert c == c.with_qubits(cb, q) assert c.control_values == ((1,),) assert cirq.qid_shape(c) == (2, 2) c = cirq.ControlledOperation([cb], v, control_values=[0]) assert c.sub_operation == v assert c.controls == (cb,) assert c.qubits == (cb, q) assert c == c.with_qubits(cb, q) assert c.control_values == ((0,),) assert cirq.qid_shape(c) == (2, 2) c = cirq.ControlledOperation([cb.with_dimension(3)], v) assert c.sub_operation == v assert c.controls == (cb.with_dimension(3),) assert c.qubits == (cb.with_dimension(3), q) assert c == c.with_qubits(cb.with_dimension(3), q) assert c.control_values == ((1,),) assert cirq.qid_shape(c) == (3, 2) with pytest.raises(ValueError, match=r'len\(control_values\) != len\(controls\)'): _ = cirq.ControlledOperation([cb], v, control_values=[1, 1]) with pytest.raises(ValueError, match='Control values .*outside of range'): _ = cirq.ControlledOperation([cb], v, control_values=[2]) with pytest.raises(ValueError, match='Control values .*outside of range'): _ = cirq.ControlledOperation([cb], v, control_values=[(1, -1)])
def test_uninformed_circuit_diagram_info(): qbits = cirq.LineQubit.range(3) mock_gate = MockGate() c_op = cirq.ControlledOperation(qbits[:1], mock_gate(*qbits[1:])) args = protocols.CircuitDiagramInfoArgs.UNINFORMED_DEFAULT assert cirq.circuit_diagram_info(c_op, args) == cirq.CircuitDiagramInfo( wire_symbols=('@', 'M1', 'M2'), exponent=1, connected=True, exponent_qubit_index=1) assert mock_gate.captured_diagram_args == args
def test_op_tree_control(): gs = [cirq.SingleQubitGate() for _ in range(10)] op_tree = [ cirq.GateOperation(gs[i], [cirq.NamedQubit(str(i))]) for i in range(10) ] controls = cirq.LineQubit.range(2) controlled_op_tree = cirq.protocols.control(op_tree, controls) expected = [ cirq.ControlledOperation( controls, cirq.GateOperation(gs[i], [cirq.NamedQubit(str(i))])) for i in range(10) ] assert cirq.freeze_op_tree(controlled_op_tree) == tuple(expected)
def test_circuit_diagram(): qubits = cirq.LineQubit.range(3) c = cirq.Circuit() c.append(cirq.ControlledOperation(qubits[0], MultiH(2)(*qubits[1:]))) cirq.testing.assert_has_diagram( c, """ 0: ───@────── │ 1: ───H(1)─── │ 2: ───H(2)─── """)
def test_str(): c1 = cirq.NamedQubit('c1') c2 = cirq.NamedQubit('c2') q2 = cirq.NamedQubit('q2') assert str(cirq.ControlledOperation([c1], cirq.CZ(c2, q2))) == "CCZ(c1, c2, q2)" class SingleQubitOp(cirq.Operation): @property def qubits(self) -> Tuple[cirq.Qid, ...]: return () def with_qubits(self, *new_qubits: cirq.Qid): pass def __str__(self): return "Op(q2)" def _has_mixture_(self): return True assert str(cirq.ControlledOperation([c1, c2], SingleQubitOp())) == "CC(c1, c2, Op(q2))" assert ( str(cirq.ControlledOperation([c1, c2.with_dimension(3)], SingleQubitOp())) == "CC(c1, c2 (d=3), Op(q2))" ) assert ( str( cirq.ControlledOperation( [c1, c2.with_dimension(3)], SingleQubitOp(), control_values=[1, (2, 0)] ) ) == "C1C02(c1, c2 (d=3), Op(q2))" )
def cnot_to_controlled_parallel_x(self, circuit, index, operation): p_op = cirq.ParallelGateOperation(cirq.ops.X, [operation.qubits[1]]) current_controlled_op = \ cirq.ControlledOperation([operation.qubits[0]], p_op) # print("A--------> ", len(circuit)) circuit.clear_operations_touching(operation.qubits, [index]) # print("B--------> ", len(circuit), repr(circuit)) # Is this an issue about how operations are inserted? circuit.insert(index + 1, current_controlled_op, strategy=cirq.InsertStrategy.INLINE) # print("C--------> ", len(circuit), repr(circuit)) return current_controlled_op
def test_controlled_operation_eq(): c1 = cirq.NamedQubit('c1') q1 = cirq.NamedQubit('q1') c2 = cirq.NamedQubit('c2') eq = cirq.testing.EqualsTester() eq.make_equality_group(lambda: cirq.ControlledOperation([c1], cirq.X(q1))) eq.make_equality_group(lambda: cirq.ControlledOperation([c2], cirq.X(q1))) eq.make_equality_group(lambda: cirq.ControlledOperation([c1], cirq.Z(q1))) eq.add_equality_group(cirq.ControlledOperation([c2], cirq.Z(q1))) eq.add_equality_group(cirq.ControlledOperation([c1, c2], cirq.Z(q1)), cirq.ControlledOperation([c2, c1], cirq.Z(q1)))
def test_controlled_operation_eq(): c1 = cirq.NamedQubit('c1') q1 = cirq.NamedQubit('q1') c2 = cirq.NamedQubit('c2') eq = cirq.testing.EqualsTester() eq.make_equality_group(lambda: cirq.ControlledOperation([c1], cirq.X(q1))) eq.make_equality_group(lambda: cirq.ControlledOperation([c2], cirq.X(q1))) eq.make_equality_group(lambda: cirq.ControlledOperation([c1], cirq.Z(q1))) eq.add_equality_group(cirq.ControlledOperation([c2], cirq.Z(q1))) eq.add_equality_group(cirq.ControlledOperation([c1, c2], cirq.Z(q1)), cirq.ControlledOperation([c2, c1], cirq.Z(q1))) eq.add_equality_group( cirq.ControlledOperation([c1, c2.with_dimension(3)], cirq.Z(q1), control_values=[1, (0, 2)]), cirq.ControlledOperation([c2.with_dimension(3), c1], cirq.Z(q1), control_values=[(2, 0), 1]))
def merge_controlled_parallel_x(self, op1, op2): if (len(op1.controls) != len(op2.controls)) \ and (len(op1.controls) != 1) \ and op1.controls[0] != op2.controls[0]: return merged_qubits = op1.sub_operation.qubits + \ op2.sub_operation.qubits try: p_op = cirq.ParallelGateOperation(cirq.ops.X, merged_qubits) except ValueError as e: print(e, merged_qubits) merged_op = cirq.ControlledOperation([op1.controls[0]], sub_operation=p_op) return merged_op
def make_grover_circuit(n: int, input_qubit, f): """Find the value recognized by the oracle in sqrt(N) attempts.""" # For 2 input qubits, that means using Grover operator only once. c = cirq.Circuit() # circuit begin c.append(cirq.H.on(input_qubit[0])) # number=1 c.append(cirq.H.on(input_qubit[1])) # number=4 c.append(cirq.H.on(input_qubit[1])) # number=21 c.append(cirq.H.on(input_qubit[2])) # number=5 c.append(cirq.CZ.on(input_qubit[3], input_qubits[1])) # number=6 repeat = floor(sqrt(2**n) * pi / 4) for i in range(repeat): c.append(make_oracle(input_qubit, n, f)) c.append(cirq.H.on(input_qubit[0])) # number=3 c.append(cirq.H.on(input_qubit[1])) # number=2 c.append(cirq.H.on(input_qubit[2])) # number=7 c.append(cirq.H.on(input_qubit[3])) # number=8 c.append(cirq.X.on(input_qubit[0])) # number=9 c.append(cirq.X.on(input_qubit[1])) # number=10 c.append(cirq.X.on(input_qubit[2])) # number=11 c.append(cirq.X.on(input_qubit[3])) # number=12 c.append( cirq.ControlledOperation(input_qubit[1:], cirq.Z.on(input_qubit[0]))) c.append(cirq.X.on(input_qubit[0])) # number=13 c.append(cirq.X.on(input_qubit[1])) # number=14 c.append(cirq.X.on(input_qubit[2])) # number=15 c.append(cirq.X.on(input_qubit[3])) # number=16 c.append(cirq.H.on(input_qubit[0])) # number=17 c.append(cirq.H.on(input_qubit[1])) # number=18 c.append(cirq.H.on(input_qubit[2])) # number=19 c.append(cirq.H.on(input_qubit[3])) # number=20 # circuit end c.append(cirq.measure(*input_qubit, key='result')) return c
def make_oracle(input_qubits, n: int, f): """Implement function {f(x) = 1 if x==x', f(x) = 0 if x!= x'}.""" # Make oracle. # for (1, 1) it's just a Toffoli gate # otherwise negate the zero-bits. #yield(cirq.X(q) for (q, bit) in zip(input_qubits, x_bits) if not bit) #yield(cirq.TOFFOLI(input_qubits[0], input_qubits[1], output_qubit)) #yield(cirq.X(q) for (q, bit) in zip(input_qubits, x_bits) if not bit) for i in range(2**n): rep = np.binary_repr(i, n) if f(rep) == "1": for j in range(n): if rep[j] == "0": yield (cirq.X(input_qubits[j])) yield (cirq.ControlledOperation(input_qubits[1:], cirq.Z.on(input_qubits[0]))) for j in range(n): if rep[j] == "0": yield (cirq.X(input_qubits[j]))
assert cirq.protocols.control(controllee, [p], NotImplemented) is NotImplemented assert cirq.protocols.control(controllee, [p], None) is None assert cirq.protocols.control(controllee, [p, q], None) is None def test_controlled_by_error(): with pytest.raises(TypeError, match="returned NotImplemented"): _ = cirq.protocols.control(ReturnsNotImplemented(), [p]) with pytest.raises(TypeError, match="no controlled_by method"): _ = cirq.protocols.control(NoMethod(), [p]) @pytest.mark.parametrize( 'controllee,control_qubits,out', ((dummy_op, [q], cirq.ControlledOperation([q], dummy_op)), )) def test_pow_with_result(controllee, control_qubits, out): assert (cirq.protocols.control(controllee, control_qubits) == cirq.protocols.control(controllee, control_qubits, default=None) == out) def test_op_tree_control(): gs = [cirq.SingleQubitGate() for _ in range(10)] op_tree = [ cirq.GateOperation(gs[i], [cirq.NamedQubit(str(i))]) for i in range(10) ] controls = cirq.LineQubit.range(2) controlled_op_tree = cirq.protocols.control(op_tree, controls) expected = [ cirq.ControlledOperation(
def correct(self, qubits: List[cirq.Qid], ancillas: List[cirq.Qid]) -> cirq.Circuit: """Corrects the code word. Creates a correction circuit by computing the syndrome on the ancillas, and then using this syndrome to correct the qubits. Args: qubits: a vector of self.n qubits that contains (potentially corrupted) code words ancillas: a vector of self.n - self.k qubits that are set to zero and will contain the syndrome once the circuit is applied. Returns: The circuit that both computes the syndrome and uses this syndrome to correct errors. """ circuit = cirq.Circuit() gate_dict = {'X': cirq.X, 'Y': cirq.Y, 'Z': cirq.Z} # We set the ancillas so that measuring them directly would be the same # as measuring the qubits with Pauli strings. In other words, we store # the syndrome inside the ancillas. for r in range(self.n - self.k): for n in range(self.n): if self.M[r][n] == 'Z': circuit.append( cirq.ControlledOperation([qubits[n]], cirq.X(ancillas[r]))) elif self.M[r][n] == 'X': circuit.append(cirq.H(qubits[n])) circuit.append( cirq.ControlledOperation([qubits[n]], cirq.X(ancillas[r]))) circuit.append(cirq.H(qubits[n])) elif self.M[r][n] == 'Y': circuit.append(cirq.S(qubits[n])**-1) circuit.append(cirq.H(qubits[n])) circuit.append( cirq.ControlledOperation([qubits[n]], cirq.X(ancillas[r]))) circuit.append(cirq.H(qubits[n])) circuit.append(cirq.S(qubits[n])) # At this stage, the ancillas are equal to the syndrome. Now, we apply # the errors back to correct the code. for syndrome, correction in self.syndromes_to_corrections.items(): op = gate_dict[correction[0]] n = correction[1] # We do a Boolean operation on the ancillas (i.e. syndrome). for r in range(self.n - self.k): if syndrome[r] == 1: circuit.append(cirq.X(ancillas[r])) circuit.append(cirq.ControlledOperation(ancillas, op(qubits[n]))) for r in range(self.n - self.k): if syndrome[r] == 1: circuit.append(cirq.X(ancillas[r])) return circuit
def encode(self, additional_qubits: List[cirq.Qid], unencoded_qubits: List[cirq.Qid]) -> cirq.Circuit: """Creates a circuit that encodes the qubits using the code words. Args: additional_qubits: The list of self.n - self.k qubits needed to encode the qubit. unencoded_qubits: The list of self.k qubits that contain the original message. Returns: A circuit where the self.n qubits are the encoded qubits. """ assert len(additional_qubits) == self.n - self.k assert len(unencoded_qubits) == self.k qubits = additional_qubits + unencoded_qubits circuit = cirq.Circuit() # Equation 4.8: # This follows the improvements of: # https://cs269q.stanford.edu/projects2019/stabilizer_code_report_Y.pdf for r, x in enumerate(self.logical_Xs): for j in range(self.r, self.n - self.k): # By constructions, the first r rows can never contain a Z, as # r is defined by the Gaussian elimination as the rank. if x[j] == 'X' or x[j] == 'Y': circuit.append( cirq.ControlledOperation([unencoded_qubits[r]], cirq.X(additional_qubits[j]))) gate_dict = {'X': cirq.X, 'Y': cirq.Y, 'Z': cirq.Z} for r in range(self.r): circuit.append(cirq.H(qubits[r])) # Let's consider the first stabilizer: # The reason for adding S gate is Y gate we used is the complex format (i.e. to # make it Hermitian). It has following four cases: (ignore the phase factor) # (I+X@P_2...P_k)|0...0> = |0...0> + |1>|\psi> # (I+Y@P_2...P_k)|0...0> = |0...0> + i|1>|\psi> # The other forms are not possible in the standard form, by construction. # The first case means we need [1,1] vector and controlled gates and in the # second case we need [1, i] vector and controlled gates. Corresponding, it is # the first column of H and the first column of SH respectively. # For the other stabilizers, the process can be repeated, as by definition they # commute. if self.M[r][r] == 'Y' or self.M[r][r] == 'Z': circuit.append(cirq.S(qubits[r])) for n in range(self.n): if n == r: continue if self.M[r][n] == 'I': continue op = gate_dict[self.M[r][n]] circuit.append( cirq.ControlledOperation([qubits[r]], op(qubits[n]))) # At this stage, the state vector should be equal to equations 3.17 and 3.18. return circuit
prefix = gates[:i + 1] expected_a = cirq.LinearCombinationOfGates(collections.Counter(prefix)) expected_b = -expected_a assert_linear_combinations_are_equal(a, expected_a) assert_linear_combinations_are_equal(b, expected_b) @pytest.mark.parametrize('op', ( cirq.X(q0), cirq.Y(q1), cirq.XX(q0, q1), cirq.CZ(q0, q1), cirq.FREDKIN(q0, q1, q2), cirq.ControlledOperation((q0, q1), cirq.H(q2)), cirq.ParallelGateOperation(cirq.X, (q0, q1, q2)), cirq.PauliString({ q0: cirq.X, q1: cirq.Y, q2: cirq.Z }), )) def test_empty_linear_combination_of_operations_accepts_all_operations(op): combination = cirq.LinearCombinationOfOperations({}) combination[op] = -0.5j assert len(combination) == 1 @pytest.mark.parametrize('terms', ( {
def construct_controlled_circuit(self, choice=True): """ :param choice: The value on which to condition: True = |1>, False = |0> :return: """ moments = [] for i in range(int(math.log2(len(self.A)))): number_of_blocks = 2**i step = len(self.A) // number_of_blocks n = math.ceil(len(self.A) / (2 * number_of_blocks)) for j in range(2**i): l = int(self.bin_C[j * step:(2 * j + 1) * n][::-1], 2) # First comes the incrementer from figure 5 moments += ShorIncrementer( self.A[(2 * j + 1) * n:(2 * j + 1) * n + n], self.A[j * step:(2 * j + 1) * n], ctrl=self.garbage).construct_circuit().moments # Then the set of CNOTs from figure 5 moments += [ cirq.CNOT(self.garbage, k) for k in self.A[(2 * j + 1) * n:(2 * j + 1) * n + n] ] # Afterwards the Carry operation from figure 5 to see if wen need to increment Xh moments += ShorCarryGate(a=self.A[j * step:(2 * j + 1) * n], c=l, g=self.A[(2 * j + 1) * n:(2 * j + 1) * n + n - 1], ancilla=self.garbage, control=self.control) \ .construct_controlled_circuit(choice).moments # Then the incrementer controlled by the result of the Carry operation moments += ShorIncrementer( self.A[(2 * j + 1) * n:(2 * j + 1) * n + n], self.A[j * step:(2 * j + 1) * n], self.garbage).construct_circuit().moments # Reset the carry_result qubit to its original value moments += ShorCarryGate( a=self.A[j * step:(2 * j + 1) * n], c=l, g=self.A[(2 * j + 1) * n:(2 * j + 1) * n + n - 1], ancilla=self.garbage, control=self.control).construct_controlled_circuit( choice).moments # lastly the CNOTs moments += [ cirq.CNOT(self.garbage, k) for k in self.A[(2 * j + 1) * n:(2 * j + 1) * n + n] ] circuit = cirq.Circuit() # Last layer is the 1-bit addition for i in range(len(self.bin_C)): if self.bin_C[i] == '1': if choice: # moments += [cirq.CNOT(self.control, self.A[i])] moments += [ cirq.ControlledOperation(self.control, cirq.X(self.A[i])) ] else: moments += [ cirq.ControlledOperation(self.control, cirq.X(self.A[i]), control_values=[0] * len(self.control)) ] circuit.append(moments) return circuit
def test_bounded_effect(): qubits = cirq.LineQubit.range(2) cy = cirq.ControlledOperation(qubits[0], cirq.Y(qubits[1])) assert cirq.trace_distance_bound(cy**0.001) < 0.01
def test_controlled_operation_is_consistent(gate: cirq.GateOperation): cb = cirq.NamedQubit('ctr') cgate = cirq.ControlledOperation(cb, gate) cirq.testing.assert_implements_consistent_protocols(cgate)
cirq.CCNOT, 'CCX': cirq.CCX, 'CCXPowGate': cirq.CCXPowGate(exponent=0.123, global_shift=0.456), 'CCZ': cirq.CCZ, 'CCZPowGate': cirq.CCZPowGate(exponent=0.123, global_shift=0.456), 'CNOT': cirq.CNOT, 'CNotPowGate': cirq.CNotPowGate(exponent=0.123, global_shift=0.456), 'ControlledOperation': cirq.ControlledOperation(sub_operation=cirq.Y(cirq.NamedQubit('target')), controls=cirq.LineQubit.range(2), control_values=[0, 1]), 'ControlledGate': cirq.ControlledGate(sub_gate=cirq.Y, num_controls=2, control_values=[0, 1], control_qid_shape=(3, 2)), 'CX': cirq.CX, 'CSWAP': cirq.CSWAP, 'CSwapGate': cirq.CSwapGate(), 'CZ': cirq.CZ, 'CZPowGate':
def test_controlled_mixture(): a, b = cirq.LineQubit.range(2) c_yes = cirq.ControlledOperation(controls=[b], sub_operation=cirq.phase_flip(0.25).on(a)) assert cirq.has_mixture(c_yes) assert cirq.approx_eq(cirq.mixture(c_yes), [(0.75, np.eye(4)), (0.25, cirq.unitary(cirq.CZ))])
def controlled_by( self, *control_qubits: 'cirq.Qid', control_values: Optional[Sequence[Union[int, Collection[int]]]] = None, ) -> 'cirq.Operation': return cirq.ControlledOperation(control_qubits, self, control_values)
def construct_controlled_circuit(self, choice): # The choice parameter will serve to choose between adding c or N-c n = len(self.a) b = bin(self.c)[2:].zfill(n)[::-1] circuit = cirq.Circuit() # Particular cases (Not defined in the paper) # Please double check them if len(self.a) == 1: if b[0] == '1': if choice: circuit.append( cirq.TOFFOLI(self.control, self.a[0], self.ancilla)) else: circuit.append( cirq.ControlledOperation([self.control, self.a[0]], cirq.X(self.ancilla), control_values=[0, 1])) return circuit elif len(self.a) == 2: if b[1] == '1': if choice: circuit.append( cirq.TOFFOLI(self.control, self.a[1], self.ancilla)) circuit.append(cirq.CNOT(self.control, self.a[1])) else: circuit.append( cirq.ControlledOperation([self.control, self.a[1]], cirq.X(self.ancilla), control_values=[0, 1])) circuit.append( cirq.ControlledOperation([self.control], cirq.X(self.a[1]), control_values=[0])) if b[0] == '1': if choice: circuit.append( cirq.ControlledOperation( [self.control, self.a[0], self.a[1]], cirq.X(self.ancilla), control_values=[1, 1, 1])) else: circuit.append( cirq.ControlledOperation( [self.control, self.a[0], self.a[1]], cirq.X(self.ancilla), control_values=[0, 1, 1])) if b[1] == '1': if choice: circuit.append(cirq.CNOT(self.control, self.a[1])) else: circuit.append( cirq.ControlledOperation([self.control], cirq.X(self.a[1]), control_values=[0])) return circuit # If the (choice == True) the operation will carried if the control qubit is equal to 1 # Otherwise it will be done if the control qubit is equal to 0 if choice: moment1 = [cirq.TOFFOLI(self.control, self.g[-1], self.ancilla)] else: moment1 = [ cirq.ControlledOperation([self.control, self.g[-1]], cirq.X(self.ancilla), control_values=[0, 1]) ] if b[0] == '1': moments = [cirq.TOFFOLI(self.a[0], self.a[1], self.g[0])] else: moments = [] moment3 = [] if b[1] == '1': moments += [cirq.X(self.a[1]), cirq.CNOT(self.a[1], self.g[0])] for i in range(2, n): moments += [cirq.TOFFOLI(self.g[i - 2], self.a[i], self.g[i - 1])] moment3 += [cirq.TOFFOLI(self.g[i - 2], self.a[i], self.g[i - 1])] if b[i] == '1': moments += [ cirq.X(self.a[i]), cirq.CNOT(self.a[i], self.g[i - 1]) ] circuit.append(moment1) circuit.append(moments[::-1]) circuit.append(moment3) circuit.append(moment1) circuit.append(moment3[::-1]) circuit.append(moments) return circuit