def makeOracle(q0, q1, secretFunction): """ Gates implementing the secret function f(x).""" if secretFunction[0]: yield [CNOT(q0, q1), X(q1)] if secretFunction[1]: yield CNOT(q0, q1)
def test_simplify_circuit_exponents(): qreg = LineQubit.range(2) circuit = Circuit([H.on(qreg[0]), CNOT.on(*qreg), Z.on(qreg[1])]) # Invert circuit inverse_circuit = cirq.inverse(circuit) inverse_repr = inverse_circuit.__repr__() inverse_qasm = inverse_circuit._to_qasm_output().__str__() # Expected circuit after simplification expected_inv = Circuit([Z.on(qreg[1]), CNOT.on(*qreg), H.on(qreg[0])]) expected_repr = expected_inv.__repr__() expected_qasm = expected_inv._to_qasm_output().__str__() # Check inverse_circuit is logically equivalent to expected_inverse # but they have a different representation assert inverse_circuit == expected_inv assert inverse_repr != expected_repr assert inverse_qasm != expected_qasm # Simplify the circuit _simplify_circuit_exponents(inverse_circuit) # Check inverse_circuit has the expected simplified representation simplified_repr = inverse_circuit.__repr__() simplified_qasm = inverse_circuit._to_qasm_output().__str__() assert inverse_circuit == expected_inv assert simplified_repr == expected_repr assert simplified_qasm == expected_qasm
def __call__(self, qubits): q0, q1, q2 = qubits yield rx(sympy.Symbol("rad0")).on(q0) yield CNOT(q0, q1) yield H(q2) yield CNOT(q2, q1) yield TOFFOLI(q1, q0, q2)
def test_simple_pauli_deco_dict_CNOT(): """Tests that the _simple_pauli_deco_dict function returns a decomposition dicitonary which is consistent with a local depolarizing noise model. The channel acting on the state each qubit is assumed to be: D(rho) = = (1 - epsilon) rho + epsilon I/2 = (1 - p) rho + p/3 (X rho X + Y rho Y^dag + Z rho Z) """ # Deduce epsilon from BASE_NOISE epsilon = BASE_NOISE * 4.0 / 3.0 c_neg = -(1 / 4) * epsilon / (1 - epsilon) c_pos = 1 - 3 * c_neg qreg = LineQubit.range(2) # Get the decomposition of a CNOT gate deco = DECO_DICT[CNOT.on(*qreg)] # The first term of 'deco' corresponds to no error occurring first_coefficient, first_imp_seq = deco[0] assert np.isclose(c_pos * c_pos, first_coefficient) assert first_imp_seq == [CNOT.on(*qreg)] # The second term corresponds to a Pauli X error on one qubit second_coefficient, second_imp_seq = deco[1] assert np.isclose(c_pos * c_neg, second_coefficient) assert second_imp_seq == [CNOT.on(*qreg), X.on(qreg[0])] # The last term corresponds to two Pauli Z errors on both qubits last_coefficient, last_imp_seq = deco[-1] assert np.isclose(c_neg * c_neg, last_coefficient) assert last_imp_seq == [CNOT.on(*qreg), Z.on(qreg[0]), Z.on(qreg[1])]
def _max_ent_state_circuit(num_qubits: int) -> Circuit: r"""Generates a circuits which prepares the maximally entangled state |\omega\rangle = U |0\rangle = \sum_i |i\rangle \otimes |i\rangle . Args: num_qubits: The number of qubits on which the circuit is applied. Only 2 or 4 qubits are supported. Returns: The circuits which prepares the state |\omega\rangle. """ qreg = LineQubit.range(num_qubits) circ = Circuit() if num_qubits == 2: circ.append(H.on(qreg[0])) circ.append(CNOT.on(*qreg)) elif num_qubits == 4: # Prepare half of the qubits in a uniform superposition circ.append(H.on(qreg[0])) circ.append(H.on(qreg[1])) # Create a perfect correlation between the two halves of the qubits. circ.append(CNOT.on(qreg[0], qreg[2])) circ.append(CNOT.on(qreg[1], qreg[3])) else: raise NotImplementedError( "Only 2- or 4-qubit maximally entangling circuits are supported." ) return circ
def make_oracle(q0, q1, secret_function): """ Gates implementing the secret function f(x).""" # coverage: ignore if secret_function[0]: yield [CNOT(q0, q1), X(q1)] if secret_function[1]: yield CNOT(q0, q1)
def test_aqt_device_wrong_op_str(): circuit = Circuit() q0, q1 = LineQubit.range(2) circuit.append(CNOT(q0, q1)**1.0) for op in circuit.all_operations(): with pytest.raises(ValueError): _result = get_op_string(op)
def _max_ent_state_circuit(num_qubits: int) -> Circuit: r"""Generates a circuit which prepares the maximally entangled state |\omega\rangle = U |0\rangle = \sum_i |i\rangle \otimes |i\rangle . Args: num_qubits: The number of qubits on which the circuit is applied. It must be an even number because of the structure of a maximally entangled state. Returns: The circuits which prepares the state |\omega\rangle. Raises: Value error: if num_qubits is not an even positive integer. """ if not isinstance(num_qubits, int) or num_qubits % 2 or num_qubits == 0: raise ValueError( "The argument 'num_qubits' must be an even and positive integer.") alice_reg = LineQubit.range(num_qubits // 2) bob_reg = LineQubit.range(num_qubits // 2, num_qubits) return Circuit( # Prepare alice_register in a uniform superposition H.on_each(*alice_reg), # Correlate alice_register with bob_register [CNOT.on(alice_reg[i], bob_reg[i]) for i in range(num_qubits // 2)], )
def twoLevelControlledRy(circuit, l, angle, k, externalControl, reg, workReg): """ Implements two level Ry rotation from state |0> to |k>, if externalControl qubit is on for reference: http://www.physics.udel.edu/~msafrono/650/Lecture%206.pdf """ grayList = generateGrayList(l, k) # handle the case where l=0 or 1 if k == 0: return if l == 1 and k == 1: circuit.append(cirq.ry(angle).controlled().on(externalControl, reg[0])) return # swap states according to Gray Code until one step before the end for element in grayList: targetQub = element[0] number = element[1] number = number[0:targetQub] + number[targetQub + 1:] controlQub = numberControl(circuit, l - 1, number, reg[0:targetQub] + reg[targetQub + 1:], workReg) if element == grayList[-1]: # reached end circuit.append(TOFFOLI(controlQub, externalControl, workReg[l - 2]), strategy=new) circuit.append( cirq.ry(angle).controlled().on(workReg[l - 2], reg[targetQub])) circuit.append(TOFFOLI(controlQub, externalControl, workReg[l - 2]), strategy=new) else: # swap states circuit.append(CNOT(controlQub, reg[targetQub]), strategy=new) numberControlT(circuit, l - 1, number, reg[0:targetQub] + reg[targetQub + 1:], workReg) # undo for element in reverse(grayList[:-1]): targetQub = element[0] number = element[1] number = number[0:targetQub] + number[targetQub + 1:] controlQub = numberControl(circuit, l - 1, number, reg[0:targetQub] + reg[targetQub + 1:], workReg) circuit.append(CNOT(controlQub, reg[targetQub]), strategy=new) numberControlT(circuit, l - 1, number, reg[0:targetQub] + reg[targetQub + 1:], workReg) return
def U_h(circuit, l, n_i, m, n_phiReg, w_phiReg, n_aReg, w_aReg, n_bReg, w_bReg, wReg, eReg, pReg, hReg, w_hReg, P_phi, P_a, P_b): """Implement U_h from paper""" # for k in range(n_i + m): for k in range(1): countsList = generateParticleCounts( n_i, m, k) # reduce the available number of particles for counts in [countsList[0]]: n_phi, n_a, n_b = counts[0], counts[1], counts[2] # controlled R-y from |0> to |k> on all qubits with all possible angles depending on n_phi, n_a, n_b, and flavor for flavor in ['phi']: # for flavor in ['phi', 'a', 'b']: angle = U_hAngle(flavor, n_phi, n_a, n_b, P_phi, P_a, P_b) # add in x gates for checking phiControl = numberControl(circuit, l, n_phi, n_phiReg, w_phiReg) print("cirq phiControl: ", phiControl) aControl = numberControl(circuit, l, n_a, n_aReg, w_aReg) print("cirq aControl: ", aControl) # bControl = numberControl(circuit, l, n_b, n_bReg, w_bReg) print("cirq wReg[0]: ", wReg[0]) # circuit.append(TOFFOLI(phiControl, aControl, wReg[0]), strategy=new) # circuit.append(TOFFOLI(bControl, wReg[0], wReg[1]), strategy=new) flavorControl( circuit, flavor, pReg[k], wReg[2], wReg[4]) # wReg[4] is work qubit but is reset to 0 # circuit.append(TOFFOLI(wReg[1], wReg[2], wReg[3]), strategy=new) # circuit.append(TOFFOLI(eReg[0], wReg[3], wReg[4]), strategy=new) # # # print("m ", m) # # print("hReg[m]: ",hReg[m]) # # twoLevelControlledRy(circuit, l, angle, k+1, wReg[4], hReg[m], w_hReg) # # circuit.append(TOFFOLI(eReg[0], wReg[3], wReg[4]), strategy=new) # next steps undo work qubits # circuit.append(TOFFOLI(wReg[1], wReg[2], wReg[3]), strategy=new) # flavorControl(circuit, flavor, pReg[k], wReg[2], wReg[4]) # circuit.append(TOFFOLI(bControl, wReg[0], wReg[1]), strategy=new) # circuit.append(TOFFOLI(phiControl, aControl, wReg[0]), strategy=new) # numberControlT(circuit, l, n_b, n_bReg, w_bReg) # numberControlT(circuit, l, n_a, n_aReg, w_aReg) # numberControlT(circuit, l, n_phi, n_phiReg, w_phiReg) # subtract from the counts register depending on which flavor particle emitted for flavor, countReg, workReg in zip(['phi', 'a', 'b'], [n_phiReg, n_aReg, n_bReg], [w_phiReg, w_aReg, w_bReg]): flavorControl(circuit, flavor, pReg[k], wReg[0], wReg[1]) minus1(circuit, l, countReg, workReg, wReg[0], wReg[1], 0) flavorControl(circuit, flavor, pReg[k], wReg[0], wReg[1]) # apply x on eReg if hReg[m] = 0, apply another x so we essentially control on not 0 instead of 0 isZeroControl = numberControl(circuit, l, 0, hReg[m], w_hReg) circuit.append(CNOT(isZeroControl, eReg[0])) circuit.append(X(eReg[0]), strategy=new) numberControlT(circuit, l, 0, hReg[m], w_hReg)
def test_represent_operations_in_circuit_local(circuit_type: str): """Tests all operation representations are created.""" qreg = LineQubit.range(2) circ_mitiq = Circuit([CNOT(*qreg), H(qreg[0]), Y(qreg[1]), CNOT(*qreg)]) circ = convert_from_mitiq(circ_mitiq, circuit_type) reps = represent_operations_in_circuit_with_local_depolarizing_noise( ideal_circuit=circ, noise_level=0.1, ) for op in convert_to_mitiq(circ)[0].all_operations(): found = False for rep in reps: if _equal(rep.ideal, Circuit(op), require_qubit_equality=True): found = True assert found # The number of reps. should match the number of unique operations assert len(reps) == 3
def plus1(circuit, l, countReg, workReg, control, ancilla, level): """ Recursively add 1 to the LSB of a register and carries to all bits, if control == 1 l: number of qubits in count register countReg, workReg: count register and associated work register control: control qubit to determine if plus1 should be executed ancilla: extra work qubit level: current qubit we are operating on, recursively travels from qubit 0 to l-1 """ # apply X to LSB if level == 0: circuit.append(CNOT(control, countReg[0]), strategy=new) if level < l - 1: # first level uses CNOT instead of TOFFOLI gate if level == 0: # move all X gates to first step to avoid unnecesarry gates circuit.append([X(qubit) for qubit in countReg], strategy=new) circuit.append(TOFFOLI(countReg[0], control, workReg[0]), strategy=new) else: circuit.append(TOFFOLI(countReg[level], workReg[level - 1], ancilla), strategy=new) circuit.append(TOFFOLI(ancilla, control, workReg[level]), strategy=new) circuit.append(TOFFOLI(countReg[level], workReg[level - 1], ancilla), strategy=new) circuit.append(TOFFOLI(workReg[level], control, countReg[level + 1]), strategy=new) # recursively call next layer print("countReg ", countReg) plus1(circuit, l, countReg, workReg, control, ancilla, level + 1) # undo work qubits (exact opposite of first 7 lines - undoes calculation) if level == 0: circuit.append(TOFFOLI(countReg[0], control, workReg[0]), strategy=new) circuit.append([X(qubit) for qubit in countReg], strategy=new) else: circuit.append(TOFFOLI(countReg[level], workReg[level - 1], ancilla), strategy=new) circuit.append(TOFFOLI(ancilla, control, workReg[level]), strategy=new) circuit.append(TOFFOLI(countReg[level], workReg[level - 1], ancilla), strategy=new)
def oracle_method(first_param, second_param, secret_function): if secret_function[0]: yield CNOT(first_param, second_param), X(second_param) if secret_function[1]: yield CNOT(first_param, second_param)
return noisy_simulation( circuit, BASE_NOISE, obs, ) # Simple identity 1-qubit circuit for testing q = LineQubit(1) oneq_circ = Circuit(Z.on(q), Z.on(q)) # Simple identity 2-qubit circuit for testing qreg = LineQubit.range(2) twoq_circ = Circuit( Y.on(qreg[1]), CNOT.on(*qreg), Y.on(qreg[1]), ) @mark.parametrize("circuit", [oneq_circ, twoq_circ]) @mark.parametrize("decomposition_dict", [NOISELESS_DECO_DICT, DECO_DICT_SIMP, DECO_DICT]) def test_execute_with_pec_one_qubit(circuit: Circuit, decomposition_dict: DecompositionDict): """Tests that execute_with_pec mitigates the error of a noisy expectation value. """ unmitigated = executor(circuit) mitigated = execute_with_pec(circuit, executor,
DecompositionDict, _operation_to_choi, _circuit_to_choi, ) from mitiq.pec.sampling import sample_sequence, sample_circuit BASE_NOISE = 0.02 DECO_DICT = _simple_pauli_deco_dict(BASE_NOISE) DECO_DICT_SIMP = _simple_pauli_deco_dict(BASE_NOISE, simplify_paulis=True) NOISELESS_DECO_DICT = _simple_pauli_deco_dict(0) # Simple 2-qubit circuit qreg = LineQubit.range(2) twoq_circ = Circuit( X.on(qreg[0]), CNOT.on(*qreg), ) @pytest.mark.parametrize("gate", [X, Y, Z, CNOT]) def test_sample_sequence_types(gate: Gate): num_qubits = gate.num_qubits() qreg = LineQubit.range(num_qubits) for _ in range(1000): imp_seq, sign, norm = sample_sequence(gate.on(*qreg), DECO_DICT) assert all([isinstance(op, Operation) for op in imp_seq]) assert sign in {1, -1} assert norm > 1 @pytest.mark.parametrize("seed", (1, 2, 3, 5))
def exponentiate_general_case(pauli_string, param): """ Returns a Circuit object corresponding to the exponential of the `pauli_string` object, i.e. exp(-1.0j * param * pauli_string) Parameters: ---------- pauli_string : (PauliString object) represents the Pauli term to exponentiate param : (float) scalar, non-complex, value Returns: ------- circuit : (Circuit) represents a parameterized circuit corresponding to the exponential of the input `pauli_string` and parameter `param` """ def reverse_circuit_operations(c): reverse_circuit = Circuit() operations_in_c = [] reverse_operations_in_c = [] for operation in c.all_operations(): operations_in_c.append(operation) reverse_operations_in_c = inverse(operations_in_c) for operation in reverse_operations_in_c: reverse_circuit.append( [operation], strategy=InsertStrategy.EARLIEST) return reverse_circuit circuit = Circuit() change_to_z_basis = Circuit() change_to_original_basis = Circuit() cnot_seq = Circuit() prev_qubit = None highest_target_qubit = None for qubit, pauli in pauli_string.items(): if pauli == X: change_to_z_basis.append( [H(qubit)], strategy=InsertStrategy.EARLIEST) change_to_original_basis.append( [H(qubit)], strategy=InsertStrategy.EARLIEST) elif pauli == Y: RX = Rx(np.pi/2.0) change_to_z_basis.append( [RX(qubit)], strategy=InsertStrategy.EARLIEST) RX = inverse(RX) change_to_original_basis.append( [RX(qubit)], strategy=InsertStrategy.EARLIEST) if prev_qubit is not None: cnot_seq.append([CNOT(prev_qubit, qubit)], strategy=InsertStrategy.EARLIEST) prev_qubit = qubit highest_target_qubit = qubit circuit += change_to_z_basis circuit += cnot_seq RZ = Rz(2.0 * pauli_string.coefficient * param) circuit.append([RZ(highest_target_qubit)], strategy=InsertStrategy.EARLIEST) circuit += reverse_circuit_operations(cnot_seq) circuit += change_to_original_basis return circuit
def _simple_pauli_deco_dict(base_noise: float, simplify_paulis: bool = False ) -> DecompositionDict: """Returns a simple hard-coded decomposition dictionary to be used for testing and protoptyping. The decomposition is compatible with one-qubit or two-qubit circuits involving only Pauli and CNOT gates. The keys of the output dictionary are Pauli and CNOT operations. The decomposition assumes that Pauli and CNOT operations, followed by local depolarizing noise, are implementable. Args: base_noise: The depolarizing noise level. simplify_paulis: If True, products of Paulis are simplified to a single Pauli. If False, Pauli sequences are not simplified. Returns: decomposition_dict: The decomposition dictionary. """ # Initialize two qubits qreg = LineQubit.range(2) # Single-qubit Pauli operations i0 = I.on(qreg[0]) x0 = X.on(qreg[0]) y0 = Y.on(qreg[0]) z0 = Z.on(qreg[0]) i1 = I.on(qreg[1]) x1 = X.on(qreg[1]) y1 = Y.on(qreg[1]) z1 = Z.on(qreg[1]) single_paulis = [x0, y0, z0, x1, y1, z1] # Single-qubit decomposition coefficients epsilon = base_noise * 4 / 3 c_neg = -(1 / 4) * epsilon / (1 - epsilon) c_pos = 1 - 3 * c_neg assert np.isclose(c_pos + 3 * c_neg, 1.0) # Single-qubit decomposition dictionary decomposition_dict = {} if simplify_paulis: # Hard-coded simplified gates decomposition_dict = { x0: [(c_pos, [x0]), (c_neg, [i0]), (c_neg, [z0]), (c_neg, [y0])], y0: [(c_pos, [y0]), (c_neg, [z0]), (c_neg, [i0]), (c_neg, [x0])], z0: [(c_pos, [z0]), (c_neg, [y0]), (c_neg, [x0]), (c_neg, [i0])], x1: [(c_pos, [x1]), (c_neg, [i1]), (c_neg, [z1]), (c_neg, [y1])], y1: [(c_pos, [y1]), (c_neg, [z1]), (c_neg, [i1]), (c_neg, [x1])], z1: [(c_pos, [z1]), (c_neg, [y1]), (c_neg, [x1]), (c_neg, [i1])], } else: for local_paulis in [[x0, y0, z0], [x1, y1, z1]]: for key in local_paulis: key_deco_pos = [(c_pos, [key])] key_deco_neg = [(c_neg, [key, op]) for op in local_paulis] decomposition_dict[key] = ( key_deco_pos + key_deco_neg # type: ignore ) # Two-qubit Paulis xx = [x0, x1] xy = [x0, y1] xz = [x0, z1] yx = [y0, x1] yy = [y0, y1] yz = [y0, z1] zx = [z0, x1] zy = [z0, y1] zz = [z0, z1] double_paulis = [xx, xy, xz, yx, yy, yz, zx, zy, zz] # Two-qubit decomposition coefficients (assuming local noise) c_pos_pos = c_pos * c_pos c_pos_neg = c_neg * c_pos c_neg_neg = c_neg * c_neg assert np.isclose(c_pos_pos + 6 * c_pos_neg + 9 * c_neg_neg, 1.0) cnot = CNOT.on(qreg[0], qreg[1]) cnot_decomposition = [(c_pos_pos, [cnot])] for p in single_paulis: cnot_decomposition.append((c_pos_neg, [cnot] + [p])) for pp in double_paulis: cnot_decomposition.append((c_neg_neg, [cnot] + pp)) # type: ignore decomposition_dict[cnot] = cnot_decomposition # type: ignore return decomposition_dict # type: ignore
def makeOracle(q0, q1, secretFunction): if secretFunction[0]: yield [CNOT(q0, q1), X(q1)] if secretFunction[1]: yield CNOT(q0, q1)
def get_cnot_circuit(control_line, target_line): cnot_circuit = Circuit() cnot_circuit.append([CNOT(control_line, target_line)], strategy=InsertStrategy.EARLIEST) return cnot_circuit
obs = np.array( [[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] ) else: raise ValueError("The input must be a circuit with 1 or 2 qubits.") return noisy_simulation(circuit, BASE_NOISE, obs,) # Simple identity 1-qubit circuit for testing q = LineQubit(1) oneq_circ = Circuit(Z.on(q), Z.on(q)) # Simple identity 2-qubit circuit for testing qreg = LineQubit.range(2) twoq_circ = Circuit(Y.on(qreg[1]), CNOT.on(*qreg), Y.on(qreg[1]),) @mark.parametrize("circuit", [oneq_circ, twoq_circ]) @mark.parametrize( "decomposition_dict", [NOISELESS_DECO_DICT, DECO_DICT_SIMP, DECO_DICT] ) def test_execute_with_pec_one_qubit( circuit: Circuit, decomposition_dict: DecompositionDict ): """Tests that execute_with_pec mitigates the error of a noisy expectation value. """ unmitigated = executor(circuit) mitigated = execute_with_pec( circuit, executor, decomposition_dict=decomposition_dict
import unittest import ddt from cirq import rx, Z, CNOT from paulicirq.linear_combinations import * q0, q1, q2 = cirq.LineQubit.range(3) op_tuple_1 = (rx(sympy.Symbol("θ"))(q0), CNOT(q2, q1)) op_tuple_2 = (CNOT(q0, q2), Z(q1)) m1 = cirq.Moment(op_tuple_1) m2 = cirq.Moment(op_tuple_2) @ddt.ddt class LinearSymbolicDictTest(unittest.TestCase): """ A test class for `LinearSymbolicDict`, `LinearCombinationOfMoments`, and `LinearCombinationOfOperations` in `paulicirq.gates.linear_combinations`. """ @ddt.unpack @ddt.data([LinearCombinationOfOperations, op_tuple_1, op_tuple_2], [LinearCombinationOfMoments, m1, m2]) def test_numerical(self, _type, term1, term2): c1 = 0.123 c2 = 0.589 lc1 = _type({term1: c1, term2: c2})