def test_openqasm_test_qasm_single_qubit_gates_controls(): backend = OpenQASMEngine() eng = MainEngine(backend=backend, engine_list=[], verbose=True) qubit = eng.allocate_qubit() ctrls = eng.allocate_qureg(2) with Control(eng, ctrls): X | qubit NOT | qubit eng.flush() qasm = [l for l in backend.circuit.qasm().split('\n')[2:] if l] assert qasm == [ 'qreg q0[1];', 'qreg q1[1];', 'qreg q2[1];', 'creg c0[1];', 'creg c1[1];', 'creg c2[1];', 'ccx q1[0],q2[0],q0[0];', 'ccx q1[0],q2[0],q0[0];', ] with pytest.raises(RuntimeError): with Control(eng, ctrls): Y | qubit eng.flush()
def _decompose_time_evolution_individual_terms(cmd): """ Implements a TimeEvolution gate with a hamiltonian having only one term. To implement exp(-i * t * hamiltonian), where the hamiltonian is only one term, e.g., hamiltonian = X0 x Y1 X Z2, we first perform local transformations to in order that all Pauli operators in the hamiltonian are Z. We then implement exp(-i * t * (Z1 x Z2 x Z3) and transform the basis back to the original. For more details see, e.g., James D. Whitfield, Jacob Biamonte & Aspuru-Guzik Simulation of electronic structure Hamiltonians using quantum computers, Molecular Physics, 109:5, 735-750 (2011). or Nielsen and Chuang, Quantum Computation and Information. """ assert len(cmd.qubits) == 1 qureg = cmd.qubits[0] eng = cmd.engine time = cmd.gate.time hamiltonian = cmd.gate.hamiltonian assert len(hamiltonian.terms) == 1 term = list(hamiltonian.terms)[0] coefficient = hamiltonian.terms[term] check_indices = set() # Check that hamiltonian is not identity term, # Previous or operator should have apply a global phase instead: assert not term == () # hamiltonian has only a single local operator if len(term) == 1: with Control(eng, cmd.control_qubits): if term[0][1] == 'X': Rx(time * coefficient * 2.) | qureg[term[0][0]] elif term[0][1] == 'Y': Ry(time * coefficient * 2.) | qureg[term[0][0]] else: Rz(time * coefficient * 2.) | qureg[term[0][0]] # hamiltonian has more than one local operator else: with Control(eng, cmd.control_qubits): with Compute(eng): # Apply local basis rotations for index, action in term: check_indices.add(index) if action == 'X': H | qureg[index] elif action == 'Y': Rx(math.pi / 2.) | qureg[index] # Check that qureg had exactly as many qubits as indices: assert check_indices == set((range(len(qureg)))) # Compute parity for i in range(len(qureg) - 1): CNOT | (qureg[i], qureg[i + 1]) Rz(time * coefficient * 2.) | qureg[-1] # Uncompute parity and basis change Uncompute(eng)
def ExecuteTeleport(eng, state_creation_function, verbose=False): b1, b2 = GetBellPair(eng) psi = eng.allocate_qubit() if verbose: print("Alice : state creation") state_creation_function(eng, psi) CNOT | (psi, b1) if verbose: print("Alice : entangled qubit") H | psi Measure | psi Measure | b1 messageToBob = [int(psi), int(b1)] if verbose: print("Alice : message {} : Bob.".format(messageToBob)) with Control(eng, b1): X | b2 with Control(eng, psi): Z | b2 if verbose: print("Bob is trying to uncompute the state.") with Dagger(eng): state_creation_function(eng, b2) del b2 eng.flush() if verbose: print("Bob successfully arrived at |0>")
def complex_algorithm(eng, qreg): All(H) | qreg with Control(eng, qreg[0]): All(X) | qreg[1:] All(Ry(math.pi / 4)) | qreg[1:] with Control(eng, qreg[-1]): All(X) | qreg[1:-1]
def _decompose_QPE(cmd): # pylint: disable=invalid-name """Decompose the Quantum Phase Estimation gate.""" eng = cmd.engine # Ancillas is the first qubit/qureg. System-qubit is the second qubit/qureg qpe_ancillas = cmd.qubits[0] system_qubits = cmd.qubits[1] # Hadamard on the ancillas Tensor(H) | qpe_ancillas # The Unitary Operator unitary = cmd.gate.unitary # Control U on the system_qubits if callable(unitary): # If U is a function for i, ancilla in enumerate(qpe_ancillas): with Control(eng, ancilla): unitary(system_qubits, time=2**i) else: for i, ancilla in enumerate(qpe_ancillas): ipower = int(2**i) with Loop(eng, ipower): with Control(eng, ancilla): unitary | system_qubits # Inverse QFT on the ancillas get_inverse(QFT) | qpe_ancillas
def lcu_controlled_unitary(eng, list_of_U, coefts, ctrl, sys, sys_dim): size = len(list_of_U) if not size: print('Error in lcu - I got an empty list of unitaries!') ctrl_dim = math.ceil(math.log(size, 2)) for i in range(0, size): temp = np.binary_repr(i) temp = temp.zfill(ctrl_dim) # pad with zeros for fixed length bin with Compute(eng): for j in range(0, ctrl_dim): if (int(temp[j]) == 0): X | ctrl[j] # if unitaries passed are qubitoperator, directly apply them, no unpacking required if isinstance(list_of_U[0], QubitOperator): with Control(eng, ctrl): list_of_U[i] | sys Uncompute(eng) else: with Control(eng, ctrl): if (isinstance(coefts[i], complex)): # can be i, or -1 Ph(0.5 * math.pi) | sys[j] # apply global phase i if (np.sign(-1j * coefts[i]) < 0): Ph(math.pi) | sys[j] # global phase is actually -i elif (np.sign(coefts[i]) < 0): Ph(math.pi) | sys[j] # apply global phase -1 for j in range(0, sys_dim): if (list_of_U[i][j] == I): continue list_of_U[i][j] | sys[j] Uncompute(eng)
def mul_by_constant_modN(eng, c, N, quint_in): """ Multiplies a quantum integer by a classical number a modulo N, i.e., |x> -> |a*x mod N> (only works if a and N are relative primes, otherwise the modular inverse does not exist). """ assert (c < N and c >= 0) assert (gcd(c, N) == 1) n = len(quint_in) quint_out = eng.allocate_qureg(n + 1) for i in range(n): with Control(eng, quint_in[i]): AddConstantModN((c << i) % N, N) | quint_out for i in range(n): Swap | (quint_out[i], quint_in[i]) cinv = inv_mod_N(c, N) for i in range(n): with Control(eng, quint_in[i]): SubConstantModN((cinv << i) % N, N) | quint_out del quint_out
def mul_by_constant_modN(eng, constant, N, quint_in): # pylint: disable=invalid-name """ Multiply a quantum integer by a classical number a modulo N. i.e., |x> -> |a*x mod N> (only works if a and N are relative primes, otherwise the modular inverse does not exist). """ if constant < 0 or constant > N: raise ValueError('Pre-condition failed: 0 <= constant < N') if gcd(constant, N) != 1: raise ValueError('Pre-condition failed: gcd(constant, N) == 1') n_qubits = len(quint_in) quint_out = eng.allocate_qureg(n_qubits + 1) for i in range(n_qubits): with Control(eng, quint_in[i]): AddConstantModN((constant << i) % N, N) | quint_out for i in range(n_qubits): Swap | (quint_out[i], quint_in[i]) cinv = inv_mod_N(constant, N) for i in range(n_qubits): with Control(eng, quint_in[i]): SubConstantModN((cinv << i) % N, N) | quint_out del quint_out
def _decompose_QPE(cmd): """ Decompose the Quantum Phase Estimation gate. """ eng = cmd.engine # Ancillas is the first qubit/qureg. System-qubit is the second qubit/qureg qpe_ancillas = cmd.qubits[0] system_qubits = cmd.qubits[1] # Hadamard on the ancillas Tensor(H) | qpe_ancillas # The Unitary Operator U = cmd.gate.unitary # Control U on the system_qubits if (callable(U)): # If U is a function for i in range(len(qpe_ancillas)): with Control(eng, qpe_ancillas[i]): U(system_qubits, time=2**i) else: for i in range(len(qpe_ancillas)): ipower = int(2**i) with Loop(eng, ipower): with Control(eng, qpe_ancillas[i]): U | system_qubits # Inverse QFT on the ancillas get_inverse(QFT) | qpe_ancillas
def _decompose_parity_measurement(cmd): ancilla = cmd.engine.allocate_qubit() for pos, action in cmd.gate._bases: qureg = Qureg([cmd.qubits[0][pos]]) if action == "X": H | cmd.qubits[0][pos] with Control(cmd.engine, qureg): X | ancilla H | cmd.qubits[0][pos] elif action == "Y": H | cmd.qubits[0][pos] S | cmd.qubits[0][pos] with Control(cmd.engine, qureg): X | ancilla get_inverse(S) | cmd.qubits[0][pos] H | cmd.qubits[0][pos] elif action == "Z": with Control(cmd.engine, qureg): X | ancilla # if there is a minus sign if (cmd.gate._is_inverted): X | ancilla # at last measure the parity: Measure | ancilla
def run_teleport(eng, state_creation_function, verbose=False): """ Runs quantum teleportation on the provided main compiler engine. Creates a state from |0> using the state_creation_function, teleports this state to Bob who then tries to uncompute his qubit using the inverse of the state_creation_function. If successful, deleting the qubit won't raise an error in the underlying Simulator back-end (else it will). Args: eng (MainEngine): Main compiler engine to run the circuit on. state_creation_function (function): Function which accepts the main engine and a qubit in state |0>, which it then transforms to the state that Alice would like to send to Bob. verbose (bool): If True, info messages will be printed. """ # make a Bell-pair b1, b2 = create_bell_pair(eng) # Alice creates a nice state to send psi = eng.allocate_qubit() if verbose: print("Alice is creating her state from scratch, i.e., |0>.") state_creation_function(eng, psi) # entangle it with Alice's b1 CNOT | (psi, b1) if verbose: print("Alice entangled her qubit with her share of the Bell-pair.") # measure two values (once in Hadamard basis) and send the bits to Bob H | psi Measure | psi Measure | b1 msg_to_bob = [int(psi), int(b1)] if verbose: print("Alice is sending the message {} to Bob.".format(msg_to_bob)) # Bob may have to apply up to two operation depending on the message sent # by Alice: with Control(eng, b1): X | b2 with Control(eng, psi): Z | b2 # try to uncompute the psi state if verbose: print("Bob is trying to uncompute the state.") with Dagger(eng): state_creation_function(eng, b2) # check whether the uncompute was successful. The simulator only allows to # delete qubits which are in a computational basis state. del b2 eng.flush() if verbose: print("Bob successfully arrived at |0>")
def s1(eng, qubits, R): A = qubits[5:8] output_reg = qubits[8:12] test_carrier_1 = qubits[12] test_carrier_2 = qubits[13] C(X, 1) | (R[1], A[0]) C(X, 1) | (R[2], A[1]) C(X, 1) | (R[3], A[2]) X | output_reg[0] X | test_carrier_1 X | test_carrier_2 MultiplyModN(2) | (A, R, output_reg) modular_decrement_gate() | (R, output_reg) with Compute(eng): All(X) | output_reg with Control(eng, output_reg): X | test_carrier_1 Uncompute(eng) modular_increment_gate() | (R, output_reg) modular_increment_gate() | (R, output_reg) with Compute(eng): All(X) | output_reg with Control(eng, output_reg): X | test_carrier_2 Uncompute(eng) C(Z, 1) | (test_carrier_2, test_carrier_1) with Compute(eng): All(X) | output_reg with Control(eng, output_reg): X | test_carrier_2 Uncompute(eng) modular_decrement_gate() | (R, output_reg) modular_decrement_gate() | (R, output_reg) with Compute(eng): All(X) | output_reg with Control(eng, output_reg): X | test_carrier_1 Uncompute(eng) modular_increment_gate() | (R, output_reg) InverseMultiplyModN(2) | (A, R, output_reg) C(X, 1) | (R[3], A[2]) C(X, 1) | (R[2], A[1]) C(X, 1) | (R[1], A[0]) X | output_reg[0] X | test_carrier_1 X | test_carrier_2
def subtract_quantum(eng, quint_a, quint_b): """ Subtract two quantum integers. i.e., |a>|b> -> |a>|b-a> (only works if quint_a and quint_b are the same size) Args: eng (MainEngine): ProjectQ MainEngine quint_a (list): Quantum register (or list of qubits) quint_b (list): Quantum register (or list of qubits) Notes: Quantum subtraction using bitwise complementation of quantum adder: b-a = (a + b')'. Same as the quantum addition circuit except that the steps involving the carry qubit are left out and complement b at the start and at the end of the circuit is added. Ancilla: 0, size: 9n-8, toffoli: 2n-2, depth: 5n-5. .. rubric:: References Quantum addition using ripple carry from: https://arxiv.org/pdf/0910.2530.pdf """ # pylint: disable = pointless-statement, expression-not-assigned if len(quint_a) != len(quint_b): raise ValueError('quint_a and quint_b must have the same size!') n_qubits = len(quint_a) + 1 All(X) | quint_b for i in range(1, n_qubits - 1): CNOT | (quint_a[i], quint_b[i]) for j in range(n_qubits - 3, 0, -1): CNOT | (quint_a[j], quint_a[j + 1]) for k in range(0, n_qubits - 2): with Control(eng, [quint_a[k], quint_b[k]]): X | (quint_a[k + 1]) for i in range(n_qubits - 2, 0, -1): # noqa: E741 CNOT | (quint_a[i], quint_b[i]) with Control(eng, [quint_a[i - 1], quint_b[i - 1]]): X | quint_a[i] for j in range(1, n_qubits - 2): CNOT | (quint_a[j], quint_a[j + 1]) for n_qubits in range(0, n_qubits - 1): CNOT | (quint_a[n_qubits], quint_b[n_qubits]) All(X) | quint_b
def quantum_conditional_add(eng, quint_a, quint_b, conditional): """ Add up two quantum integers if conditional is high. i.e., |a>|b>|c> -> |a>|b+a>|c> (without a carry out qubit) if conditional is low, no operation is performed, i.e., |a>|b>|c> -> |a>|b>|c> Args: eng (MainEngine): ProjectQ MainEngine quint_a (list): Quantum register (or list of qubits) quint_b (list): Quantum register (or list of qubits) conditional (list): Conditional qubit Notes: Ancilla: 0, Size: 7n-7, Toffoli: 3n-3, Depth: 5n-3. .. rubric:: References Quantum Conditional Add from https://arxiv.org/pdf/1609.01241.pdf """ # pylint: disable = pointless-statement, expression-not-assigned if len(quint_a) != len(quint_b): raise ValueError('quint_a and quint_b must have the same size!') if len(conditional) != 1: raise ValueError('Conditional qubit must be a single qubit!') n_qubits = len(quint_a) + 1 for i in range(1, n_qubits - 1): CNOT | (quint_a[i], quint_b[i]) for i in range(n_qubits - 2, 1, -1): CNOT | (quint_a[i - 1], quint_a[i]) for k in range(0, n_qubits - 2): with Control(eng, [quint_a[k], quint_b[k]]): X | (quint_a[k + 1]) with Control(eng, [quint_a[n_qubits - 2], conditional[0]]): X | quint_b[n_qubits - 2] for i in range(n_qubits - 2, 0, -1): # noqa: E741 with Control(eng, [quint_a[i - 1], quint_b[i - 1]]): X | quint_a[i] with Control(eng, [quint_a[i - 1], conditional[0]]): X | (quint_b[i - 1]) for j in range(1, n_qubits - 2): CNOT | (quint_a[j], quint_a[j + 1]) for k in range(1, n_qubits - 1): CNOT | (quint_a[k], quint_b[k])
def _decompose_entangle(cmd): """ Decompose the entangle gate. """ qr = cmd.qubits[0] eng = cmd.engine with Control(eng, cmd.control_qubits): H | qr[0] with Control(eng, qr[0]): All(X) | qr[1:]
def _decompose_QFT(cmd): qb = cmd.qubits[0] eng = cmd.engine with Control(eng, cmd.control_qubits): for i in range(len(qb)): H | qb[-1 - i] for j in range(len(qb) - 1 - i): with Control(eng, qb[-1 - (j + i + 1)]): R(math.pi / (1 << (1 + j))) | qb[-1 - i]
def active_fun(self, train_or_test): """ :param train_or_test: bool, True or False :return: loss """ if train_or_test == 'train': x_epoch = self.train_x y_epoch = self.train_y return_test_label = False elif train_or_test == 'test': x_epoch = self.test_x y_epoch = self.test_y return_test_label = True else: print('error!!!') y_sim = [] for encoded_data in x_epoch: self.eng.backend.set_wavefunction(self.init_wavefun, self.qureg) for w in range(2): # represent the data with same weight for i in range(len(encoded_data[0])): if encoded_data[w][i]: X | self.qureg[self.n_qubits1data * w + i] with Control(self.eng, self.qureg[self.n_qubits1data * w + i]): Ry(2 * encoded_data[-1] * self.alpha[w] / 2**i) | self.qureg[-2] # add bios Ry(2 * self.alpha[-1]) | self.qureg[-2] with Control(self.eng, self.qureg[-2]): Y | self.qureg[-1] Rz(-np.pi / 2) | self.qureg[2] Ry(-2 * self.alpha[-1]) | self.qureg[-2] for w in range(2): # represent the data with same weight for i in range(len(encoded_data[0])): with Control(self.eng, self.qureg[self.n_qubits1data * w + i]): Ry(-2 * encoded_data[-1] * self.alpha[w] / 2**i) | self.qureg[-2] self.eng.flush() # self.eng.backend.collapse_wavefunction([self.qureg[-2]], [0]) result = self.eng.backend.get_probability('0', [self.qureg[-1]]) Measure | self.qureg y_sim.append(np.arccos(np.sqrt(result)) / (np.pi / 2)) # y_sim.append(result) loss = self.cal_loss(y_epoch, y_sim) if return_test_label: return loss, y_sim else: return loss
def test_simulator_functional_entangle(sim): eng = HiQMainEngine(sim, [GreedyScheduler()]) qubits = eng.allocate_qureg(5) # entangle all qubits: H | qubits[0] for qb in qubits[1:]: CNOT | (qubits[0], qb) eng.flush() id2pos, vec = sim.cheat() # check the state vector: assert .5 == pytest.approx(abs(vec[0])**2) # amplitudes 00000 and 11111 assert .5 == pytest.approx(abs( vec[31])**2) # are never moved even if qubit reordering made for i in range(1, 31): assert 0. == pytest.approx(abs(vec[i])) # unentangle all except the first 2 for qb in qubits[2:]: CNOT | (qubits[0], qb) # entangle using Toffolis for qb in qubits[2:]: Toffoli | (qubits[0], qubits[1], qb) eng.flush() # check the state vector: id2pos, vec = sim.cheat() assert .5 == pytest.approx(abs(vec[0])**2) assert .5 == pytest.approx(abs(vec[31])**2) for i in range(1, 31): assert 0. == pytest.approx(abs(vec[i])) # uncompute using multi-controlled NOTs with Control(eng, qubits[0:-1]): X | qubits[-1] with Control(eng, qubits[0:-2]): X | qubits[-2] with Control(eng, qubits[0:-3]): X | qubits[-3] CNOT | (qubits[0], qubits[1]) H | qubits[0] eng.flush() id2pos, vec = sim.cheat() # check the state vector: assert 1. == pytest.approx(abs(vec[0])**2) for i in range(1, 32): assert 0. == pytest.approx(abs(vec[i])) All(Measure) | qubits
def Add(eng, X_reg, D_reg, L_reg): print("Running Add") # Initialize auxiliary register A A_reg = eng.allocate_qureg(q) # Get registers of database D_reg_X = [qubit for qubit in D_reg if (D_reg.index(qubit) % (m + n) < m)] D_reg_Y = [qubit for qubit in D_reg if (D_reg.index(qubit) % (m + n) >= m)] for i in range(q): # Get registers of database D_reg_X_i = [qubit for qubit in D_reg_X if (D_reg_X.index(qubit) >= m * i \ and D_reg_X.index(qubit) < m * (i + 1))] D_reg_Y_i = [qubit for qubit in D_reg_Y if (D_reg_Y.index(qubit) >= n * i \ and D_reg_Y.index(qubit) < n * (i + 1))] # Look for where the database entries are larger than the query A_reg[i] = Larger(eng, D_reg_X_i, X_reg, A_reg[i]) # Correct for empty entries All(X) | D_reg_Y_i C(X, n) | (D_reg_Y_i, A_reg[i]) All(X) | D_reg_Y_i # Flip all higher bits, such that Hamming weight of A becomes 1 for j in range(i + 1, q): C(X, 1) | (A_reg[i], A_reg[j]) # Permute the database into the correct order D_reg = Permute_inv(eng, D_reg, A_reg) for i in range(q): with Control(eng, A_reg[i]): # Get registers of database D_reg_X_i = [qubit for qubit in D_reg_X if (D_reg_X.index(qubit) >= m * i \ and D_reg_X.index(qubit) < m * (i + 1))] # Add to the database and update register L for j in range(m): C(X, 1) | (X_reg[j], D_reg_X_i[j]) X | L_reg[i] # Clean Up All(X) | X_reg with Control(eng, X_reg): for i in range(q): C(X, 1) | (L_reg[i], A_reg[i]) All(X) | X_reg del A_reg print("Finished Add") return D_reg, L_reg
def test_decomposition(): for basis_state_index in range(0, 16): basis_state = [0] * 16 basis_state[basis_state_index] = 1. correct_dummy_eng = DummyEngine(save_commands=True) correct_eng = MainEngine(backend=Simulator(), engine_list=[correct_dummy_eng]) rule_set = DecompositionRuleSet(modules=[cnu2toffoliandcu]) test_dummy_eng = DummyEngine(save_commands=True) test_eng = MainEngine(backend=Simulator(), engine_list=[ AutoReplacer(rule_set), InstructionFilter(_decomp_gates), test_dummy_eng ]) test_sim = test_eng.backend correct_sim = correct_eng.backend correct_qb = correct_eng.allocate_qubit() correct_ctrl_qureg = correct_eng.allocate_qureg(3) correct_eng.flush() test_qb = test_eng.allocate_qubit() test_ctrl_qureg = test_eng.allocate_qureg(3) test_eng.flush() correct_sim.set_wavefunction(basis_state, correct_qb + correct_ctrl_qureg) test_sim.set_wavefunction(basis_state, test_qb + test_ctrl_qureg) with Control(test_eng, test_ctrl_qureg[:2]): Rx(0.4) | test_qb with Control(test_eng, test_ctrl_qureg): Ry(0.6) | test_qb with Control(correct_eng, correct_ctrl_qureg[:2]): Rx(0.4) | correct_qb with Control(correct_eng, correct_ctrl_qureg): Ry(0.6) | correct_qb test_eng.flush() correct_eng.flush() assert len(correct_dummy_eng.received_commands) == 8 assert len(test_dummy_eng.received_commands) == 20 for fstate in range(16): binary_state = format(fstate, '04b') test = test_sim.get_amplitude(binary_state, test_qb + test_ctrl_qureg) correct = correct_sim.get_amplitude( binary_state, correct_qb + correct_ctrl_qureg) assert correct == pytest.approx(test, rel=1e-12, abs=1e-12) Measure | test_qb + test_ctrl_qureg Measure | correct_qb + correct_ctrl_qureg test_eng.flush(deallocate_qubits=True) correct_eng.flush(deallocate_qubits=True)
def test_decomposition(gate_matrix): # Create single qubit gate with gate_matrix test_gate = MatrixGate() test_gate.matrix = np.matrix(gate_matrix) for basis_state in ([1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]): correct_dummy_eng = DummyEngine(save_commands=True) correct_eng = MainEngine(backend=Simulator(), engine_list=[correct_dummy_eng]) rule_set = DecompositionRuleSet(modules=[carb1q]) test_dummy_eng = DummyEngine(save_commands=True) test_eng = MainEngine( backend=Simulator(), engine_list=[ AutoReplacer(rule_set), InstructionFilter(_decomp_gates), test_dummy_eng, ], ) test_sim = test_eng.backend correct_sim = correct_eng.backend correct_qb = correct_eng.allocate_qubit() correct_ctrl_qb = correct_eng.allocate_qubit() correct_eng.flush() test_qb = test_eng.allocate_qubit() test_ctrl_qb = test_eng.allocate_qubit() test_eng.flush() correct_sim.set_wavefunction(basis_state, correct_qb + correct_ctrl_qb) test_sim.set_wavefunction(basis_state, test_qb + test_ctrl_qb) with Control(test_eng, test_ctrl_qb): test_gate | test_qb with Control(correct_eng, correct_ctrl_qb): test_gate | correct_qb test_eng.flush() correct_eng.flush() assert correct_dummy_eng.received_commands[3].gate == test_gate assert test_dummy_eng.received_commands[3].gate != test_gate for fstate in ['00', '01', '10', '11']: test = test_sim.get_amplitude(fstate, test_qb + test_ctrl_qb) correct = correct_sim.get_amplitude(fstate, correct_qb + correct_ctrl_qb) assert correct == pytest.approx(test, rel=1e-12, abs=1e-12) All(Measure) | test_qb + test_ctrl_qb All(Measure) | correct_qb + correct_ctrl_qb test_eng.flush(deallocate_qubits=True) correct_eng.flush(deallocate_qubits=True)
def grover_iteration(qubits, R): control_qubit = qubits[0] All(X) | R[0:5] All(H) | R[0:5] #### C(X, 2) | (R[0:2], control_qubit) with Control(eng, control_qubit): s1(eng, qubits, R) C(X, 2) | (R[0:2], control_qubit) #### X | R[1] C(X, 3) | (R[0:3], control_qubit) X | R[1] with Control(eng, control_qubit): s2(eng, qubits, R) X | R[1] C(X, 3) | (R[0:3], control_qubit) X | R[1] ### All(X) | R[1:3] C(X, 4) | (R[0:4], control_qubit) All(X) | R[1:3] with Control(eng, control_qubit): s3(eng, qubits, R) All(X) | R[1:3] C(X, 4) | (R[0:4], control_qubit) All(X) | R[1:3] ### All(X) | R[1:4] C(X, 4) | (R[0:4], control_qubit) All(X) | R[1:4] with Control(eng, control_qubit): s4(eng, qubits, R) All(X) | R[1:4] C(X, 4) | (R[0:4], control_qubit) All(X) | R[1:4] ### Z | R[0] All(H) | R[0:5] C(Z, 4) | (R[0:4], R[4]) All(H) | R[0:5] return (qubits, R)
def complex_oracle(eng, system_q, control): # This oracle selects the subspace |000000>+|111111> as the good one with Compute(eng): with Control(eng, system_q[0]): All(X) | system_q[1:] H | system_q[0] All(X) | system_q with Control(eng, system_q): X | control Uncompute(eng)
def _replace_inverse_add_quantum(cmd): eng = cmd.engine quint_a = cmd.qubits[0] quint_b = cmd.qubits[1] if len(cmd.qubits) == 3: quint_c = cmd.qubits[2] with Control(eng, cmd.control_qubits): inverse_add_quantum_carry(eng, quint_a, [quint_b, quint_c]) else: with Control(eng, cmd.control_qubits): subtract_quantum(eng, quint_a, quint_b)
def test_qubitop2singlequbit(): num_qubits = 4 random_initial_state = [ 0.2 + 0.1 * x * cmath.exp(0.1j + 0.2j * x) for x in range(2**(num_qubits + 1)) ] rule_set = DecompositionRuleSet(modules=[qubitop2onequbit]) test_eng = MainEngine( backend=Simulator(), engine_list=[AutoReplacer(rule_set), InstructionFilter(_decomp_gates)], ) test_qureg = test_eng.allocate_qureg(num_qubits) test_ctrl_qb = test_eng.allocate_qubit() test_eng.flush() test_eng.backend.set_wavefunction(random_initial_state, test_qureg + test_ctrl_qb) correct_eng = MainEngine() correct_qureg = correct_eng.allocate_qureg(num_qubits) correct_ctrl_qb = correct_eng.allocate_qubit() correct_eng.flush() correct_eng.backend.set_wavefunction(random_initial_state, correct_qureg + correct_ctrl_qb) qubit_op_0 = QubitOperator("X0 Y1 Z3", -1.0j) qubit_op_1 = QubitOperator("Z0 Y1 X3", cmath.exp(0.6j)) qubit_op_0 | test_qureg with Control(test_eng, test_ctrl_qb): qubit_op_1 | test_qureg test_eng.flush() correct_eng.backend.apply_qubit_operator(qubit_op_0, correct_qureg) with Control(correct_eng, correct_ctrl_qb): Ph(0.6) | correct_qureg[0] Z | correct_qureg[0] Y | correct_qureg[1] X | correct_qureg[3] correct_eng.flush() for fstate in range(2**(num_qubits + 1)): binary_state = format(fstate, '0' + str(num_qubits + 1) + 'b') test = test_eng.backend.get_amplitude(binary_state, test_qureg + test_ctrl_qb) correct = correct_eng.backend.get_amplitude( binary_state, correct_qureg + correct_ctrl_qb) assert correct == pytest.approx(test, rel=1e-10, abs=1e-10) All(Measure) | correct_qureg + correct_ctrl_qb All(Measure) | test_qureg + test_ctrl_qb correct_eng.flush() test_eng.flush()
def apply_gates(eng, qureg): MatrixGate(mat1) | qureg[0] MatrixGate(mat2) | qureg[1:] MatrixGate(mat3) | qureg with Control(eng, qureg[1]): MatrixGate(mat2) | (qureg[0], qureg[2]) MatrixGate(mat4) | qureg[0] with Control(eng, qureg[1], ctrl_state='0'): MatrixGate(mat1) | qureg[0] with Control(eng, qureg[2], ctrl_state='0'): MatrixGate(mat1) | qureg[0]
def test_recognize(): saving_backend = DummyEngine(save_commands=True) eng = MainEngine(backend=saving_backend, engine_list=[]) ctrl_qureg = eng.allocate_qureg(2) qureg = eng.allocate_qureg(2) with Control(eng, ctrl_qureg): QubitOperator("X0 Y1") | qureg with Control(eng, ctrl_qureg[0]): QubitOperator("X0 Y1") | qureg eng.flush() cmd0 = saving_backend.received_commands[4] cmd1 = saving_backend.received_commands[5] assert not qubitop2onequbit._recognize_qubitop(cmd0) assert qubitop2onequbit._recognize_qubitop(cmd1)
def quantum_multiplication(eng, quint_a, quint_b, product): """ Multiplies two quantum integers. i.e, |a>|b>|0> -> |a>|b>|a*b> (only works if quint_a and quint_b are of the same size, n qubits and product has size 2n+1). Args: eng (MainEngine): ProjectQ MainEngine quint_a (list): Quantum register (or list of qubits) quint_b (list): Quantum register (or list of qubits) product (list): Quantum register (or list of qubits) storing the result Notes: Ancilla: 2n + 1, size: 7n^2 - 9n + 4, toffoli: 5n^2 - 4n, depth: 3n^2 - 2. .. rubric:: References Quantum multiplication from: https://arxiv.org/abs/1706.05113. """ n_a = len(quint_a) if len(quint_a) != len(quint_b): raise ValueError('quint_a and quint_b must have the same size!') if len(product) != ((2 * n_a) + 1): raise ValueError('product size must be 2*n + 1') for i in range(0, n_a): with Control(eng, [quint_a[i], quint_b[0]]): X | product[i] with Control(eng, quint_b[1]): AddQuantum | ( quint_a[0:(n_a - 1)], # noqa: E203 product[1:n_a], [product[n_a + 1], product[n_a + 2]], ) for j in range(2, n_a): with Control(eng, quint_b[j]): AddQuantum | ( quint_a[0:(n_a - 1)], # noqa: E203 product[(0 + j):(n_a - 1 + j)], # noqa: E203 [product[n_a + j], product[n_a + j + 1]], )
def test_factoring(sim): eng = get_main_engine(sim) ctrl_qubit = eng.allocate_qubit() N = 15 a = 2 x = eng.allocate_qureg(4) X | x[0] H | ctrl_qubit with Control(eng, ctrl_qubit): MultiplyByConstantModN(pow(a, 2**7, N), N) | x H | ctrl_qubit eng.flush() cheat_tpl = sim.cheat() idx = cheat_tpl[0][ctrl_qubit[0].id] vec = cheat_tpl[1] for i in range(len(vec)): if abs(vec[i]) > 1.e-8: assert ((i >> idx) & 1) == 0 Measure | ctrl_qubit assert int(ctrl_qubit) == 0 del vec, cheat_tpl H | ctrl_qubit with Control(eng, ctrl_qubit): MultiplyByConstantModN(pow(a, 2, N), N) | x H | ctrl_qubit eng.flush() cheat_tpl = sim.cheat() idx = cheat_tpl[0][ctrl_qubit[0].id] vec = cheat_tpl[1] probability = 0. for i in range(len(vec)): if abs(vec[i]) > 1.e-8: if ((i >> idx) & 1) == 0: probability += abs(vec[i])**2 assert probability == pytest.approx(.5) Measure | ctrl_qubit Measure | x
def test_recognize_incorrect_gates(): saving_backend = DummyEngine(save_commands=True) eng = MainEngine(backend=saving_backend) qubit = eng.allocate_qubit() ctrl_qubit = eng.allocate_qubit() ctrl_qureg = eng.allocate_qureg(2) eng.flush() with Control(eng, ctrl_qubit): Rx(0.3) | qubit X | qubit with Control(eng, ctrl_qureg): X | qubit eng.flush(deallocate_qubits=True) for cmd in saving_backend.received_commands: assert not cnu2toffoliandcu._recognize_CnU(cmd)