def vqe(theta, hamiltonian): """ This is the function you need to test your parameterized quantum circuit. Args: theta (list): parameters hamiltonian (QubitOperator): Hamiltonian of the system Returns: energy of the wavefunction for parameters theta """ # Initialize the energy energy = 0 eng = MainEngine() qubits = eng.allocate_qureg(2) # Here you can add your circuit X | qubits[0] ansatz_op = QubitOperator('X0 Y1') # Apply the unitary e^{-i * ansatz_op * t} TimeEvolution(theta[0], ansatz_op) | qubits # Rx(theta[0]) | qubits[0] # Ry(theta[0]) | qubits[0] # Rz(theta[0]) | qubits[0] # Rx(theta[1]) | qubits[1] # Ry(theta[1]) | qubits[1] # Rz(theta[1]) | qubits[1] eng.flush() energy = eng.backend.get_expectation_value(hamiltonian, qubits) All(Measure) | qubits return energy
def test_simulator_time_evolution(sim): N = 8 # number of qubits time_to_evolve = 1.1 # time to evolve for eng = MainEngine(sim, []) qureg = eng.allocate_qureg(N) # initialize in random wavefunction by applying some gates: for qb in qureg: Rx(random.random()) | qb Ry(random.random()) | qb eng.flush() # Use cheat to get initial start wavefunction: qubit_to_bit_map, init_wavefunction = copy.deepcopy(eng.backend.cheat()) Qop = QubitOperator op = 0.3 * Qop("X0 Y1 Z2 Y3 X4") op += 1.1 * Qop(()) op += -1.4 * Qop("Y0 Z1 X3 Y5") op += -1.1 * Qop("Y1 X2 X3 Y4") ctrl_qubit = eng.allocate_qubit() H | ctrl_qubit with Control(eng, ctrl_qubit): TimeEvolution(time_to_evolve, op) | qureg eng.flush() qbit_to_bit_map, final_wavefunction = copy.deepcopy(eng.backend.cheat()) All(Measure) | qureg + ctrl_qubit # Check manually: def build_matrix(list_single_matrices): res = list_single_matrices[0] for i in range(1, len(list_single_matrices)): res = scipy.sparse.kron(res, list_single_matrices[i]) return res id_sp = scipy.sparse.identity(2, format="csr", dtype=complex) x_sp = scipy.sparse.csr_matrix([[0., 1.], [1., 0.]], dtype=complex) y_sp = scipy.sparse.csr_matrix([[0., -1.j], [1.j, 0.]], dtype=complex) z_sp = scipy.sparse.csr_matrix([[1., 0.], [0., -1.]], dtype=complex) gates = [x_sp, y_sp, z_sp] res_matrix = 0 for t, c in op.terms.items(): matrix = [id_sp] * N for idx, gate in t: matrix[qbit_to_bit_map[qureg[idx].id]] = gates[ord(gate) - ord('X')] matrix.reverse() res_matrix += build_matrix(matrix) * c res_matrix *= -1j * time_to_evolve init_wavefunction = numpy.array(init_wavefunction, copy=False) final_wavefunction = numpy.array(final_wavefunction, copy=False) res = scipy.sparse.linalg.expm_multiply(res_matrix, init_wavefunction) half = int(len(final_wavefunction) / 2) hadamard_f = 1. / math.sqrt(2.) # check evolution and control assert numpy.allclose(hadamard_f * res, final_wavefunction[half:]) assert numpy.allclose(final_wavefunction[:half], hadamard_f * init_wavefunction)
def _decompose_cnot_rotation(cmd): """ Decompose CNOT gates. """ qureg = Qureg(cmd.control_qubits + cmd.qubits[0]) H = QubitOperator("Z0 X1") T = TimeEvolution(-cmath.pi / 4, H) T | qureg Rz(cmath.pi) | qureg[0] Rx(cmath.pi) | qureg[1]
def _decompose_time_evolution_commuting_terms(cmd): qureg = cmd.qubits eng = cmd.engine hamiltonian = cmd.gate.hamiltonian time = cmd.gate.time with Control(eng, cmd.control_qubits): for term in hamiltonian.terms: ind_operator = QubitOperator(term, hamiltonian.terms[term]) TimeEvolution(time, ind_operator) | qureg
def test_recognize_individual_terms(): saving_backend = DummyEngine(save_commands=True) eng = MainEngine(backend=saving_backend, engine_list=[]) wavefunction = eng.allocate_qureg(5) op1 = QubitOperator("X1 Y2", 0.5) op2 = QubitOperator("Y2 X4", -0.5) op3 = QubitOperator("X2", 1.0) TimeEvolution(1., op1 + op2) | wavefunction TimeEvolution(1., op2) | wavefunction TimeEvolution(1., op3) | wavefunction cmd1 = saving_backend.received_commands[5] cmd2 = saving_backend.received_commands[6] cmd3 = saving_backend.received_commands[7] assert not te.rule_individual_terms.gate_recognizer(cmd1) assert te.rule_individual_terms.gate_recognizer(cmd2) assert te.rule_individual_terms.gate_recognizer(cmd3)
def _prep_state(self, params, eng): ''' \params must be of length 2*n_steps, where first half is betas and second half is gammas. Prepares state by first applying |psi> = self.init_state |0...0> then doing Prod U(beta, B)U(gamma, C) |psi>. ''' betas = params[:self.n_steps] gammas = params[self.n_steps:] qureg = self.init_state(eng) for i in range(self.n_steps): TimeEvolution(gammas[i], self.cost ) | qureg TimeEvolution(betas[i] , self.mixer) | qureg return qureg
def test_projectq_filters(self): """Verify ProjectQ filters work as intended""" eng = MainEngine() op = QubitOperator("X0 X1 X2", -0.5) wavefunction = eng.allocate_qureg(4) command = TimeEvolution(time=1., hamiltonian=op) | wavefunction self.assertFalse(_identify_non_commuting(command)) op = QubitOperator("X0 X1 X2", -0.5) + QubitOperator("Z1", 1.0) command = TimeEvolution(time=1., hamiltonian=op) | wavefunction self.assertTrue(_identify_non_commuting(command)) op = QubitOperator("X0 X1 X2", -0.5) command = TimeEvolution(time=1., hamiltonian=op) | wavefunction self.assertFalse(_two_gate_filter(None, command)) command = X | wavefunction self.assertTrue(_two_gate_filter(None, command))
def E2(t0, i): hamiltonian2quant = QubitOperator('', float(g[i][1])) + QubitOperator( 'Z0', float(g[i][2])) + QubitOperator('Z1', float( g[i][3])) + QubitOperator('Z0 Z1', float(g[i][4])) + QubitOperator( 'X0 X1', float(g[i][5])) + QubitOperator( 'Y0 Y1', float(g[i][6])) wavefunction = eng.allocate_qureg(2) X | wavefunction[0] TimeEvolution(time=t0, hamiltonian=hamiltonian2quant) | wavefunction eng.flush() energy = eng.backend.get_expectation_value(hamiltonian2quant, wavefunction) Measure | wavefunction eng.flush() return energy
def test_decompose_commuting_terms(): saving_backend = DummyEngine(save_commands=True) def my_filter(self, cmd): if len(cmd.qubits[0]) <= 2 or isinstance(cmd.gate, ClassicalInstructionGate): return True return False rules = DecompositionRuleSet([te.rule_commuting_terms]) replacer = AutoReplacer(rules) filter_eng = InstructionFilter(my_filter) eng = MainEngine(backend=saving_backend, engine_list=[replacer, filter_eng]) qureg = eng.allocate_qureg(5) with Control(eng, qureg[3]): op1 = QubitOperator("X1 Y2", 0.7) op2 = QubitOperator("Y2 X4", -0.8) op3 = QubitOperator((), 0.6) TimeEvolution(1.5, op1 + op2 + op3) | qureg cmd1 = saving_backend.received_commands[5] cmd2 = saving_backend.received_commands[6] cmd3 = saving_backend.received_commands[7] found = [False, False, False] scaled_op1 = QubitOperator("X0 Y1", 0.7) scaled_op2 = QubitOperator("Y0 X1", -0.8) for cmd in [cmd1, cmd2, cmd3]: if (cmd.gate == Ph(-1.5 * 0.6) and cmd.qubits[0][0].id == qureg[1].id and cmd.control_qubits[0].id == qureg[3].id # 1st qubit of [1,2,4] ): found[0] = True elif (isinstance(cmd.gate, TimeEvolution) and cmd.gate.hamiltonian.isclose(scaled_op1) and cmd.gate.time == pytest.approx(1.5) and cmd.qubits[0][0].id == qureg[1].id and cmd.qubits[0][1].id == qureg[2].id and cmd.control_qubits[0].id == qureg[3].id): found[1] = True elif (isinstance(cmd.gate, TimeEvolution) and cmd.gate.hamiltonian.isclose(scaled_op2) and cmd.gate.time == pytest.approx(1.5) and cmd.qubits[0][0].id == qureg[2].id and cmd.qubits[0][1].id == qureg[4].id and cmd.control_qubits[0].id == qureg[3].id): found[2] = True assert all(found)
def test_recognize_commuting_terms(): saving_backend = DummyEngine(save_commands=True) eng = MainEngine(backend=saving_backend, engine_list=[]) wavefunction = eng.allocate_qureg(5) op1 = QubitOperator("X1 Y2", 0.5) op2 = QubitOperator("Y2 X4", -0.5) op3 = QubitOperator((), 0.5) op4 = QubitOperator("X1 Y2", 0.5) + QubitOperator("X2", 1e-10) op5 = QubitOperator("X1 Y2", 0.5) + QubitOperator("X2", 1e-8) op6 = QubitOperator("X2", 1.0) TimeEvolution(1., op1 + op2 + op3 + op4) | wavefunction TimeEvolution(1., op1 + op5) | wavefunction TimeEvolution(1., op1 + op6) | wavefunction TimeEvolution(1., op1) | wavefunction cmd1 = saving_backend.received_commands[5] cmd2 = saving_backend.received_commands[6] cmd3 = saving_backend.received_commands[7] cmd4 = saving_backend.received_commands[8] assert te.rule_commuting_terms.gate_recognizer(cmd1) assert not te.rule_commuting_terms.gate_recognizer(cmd2) assert not te.rule_commuting_terms.gate_recognizer(cmd3) assert not te.rule_commuting_terms.gate_recognizer(cmd4)
def test_decompose_individual_terms_invalid(): eng = MainEngine(backend=DummyEngine(), engine_list=[]) qb0 = WeakQubitRef(eng, idx=0) qb1 = WeakQubitRef(eng, idx=1) op1 = QubitOperator("X0 Y1", 0.5) op2 = op1 + QubitOperator("Y2 X4", -0.5) op3 = QubitOperator((), 0.5) op4 = QubitOperator("X0 Y0", 0.5) with pytest.raises(ValueError): te._decompose_time_evolution_individual_terms( Command(eng, TimeEvolution(1, op1), ([qb0], [qb1]))) with pytest.raises(ValueError): te._decompose_time_evolution_individual_terms( Command(eng, TimeEvolution(1, op2), ([qb0], ))) with pytest.raises(ValueError): te._decompose_time_evolution_individual_terms( Command(eng, TimeEvolution(1, op3), ([qb0], ))) with pytest.raises(ValueError): te._decompose_time_evolution_individual_terms( Command(eng, TimeEvolution(1, op4), ([qb0, qb1], )))
def test_restriction(): engine_list = restrictedgateset.get_engine_list( one_qubit_gates=(Rz, H), two_qubit_gates=(CNOT, AddConstant, Swap), other_gates=(Toffoli, AddConstantModN, MultiplyByConstantModN(2, 8)), ) backend = DummyEngine(save_commands=True) eng = projectq.MainEngine(backend, engine_list, verbose=True) qubit1 = eng.allocate_qubit() qubit2 = eng.allocate_qubit() qubit3 = eng.allocate_qubit() eng.flush() CNOT | (qubit1, qubit2) H | qubit1 with Control(eng, qubit2): Rz(0.2) | qubit1 Measure | qubit1 AddConstant(1) | (qubit1 + qubit2) AddConstantModN(1, 9) | (qubit1 + qubit2 + qubit3) Toffoli | (qubit1 + qubit2, qubit3) Swap | (qubit1, qubit2) MultiplyByConstantModN(2, 8) | qubit1 + qubit2 + qubit3 TimeEvolution(0.5, QubitOperator("X0 Y1 Z2")) | qubit1 + qubit2 + qubit3 QFT | qubit1 + qubit2 + qubit3 Rx(0.1) | (qubit1) MultiplyByConstantModN(2, 9) | qubit1 + qubit2 + qubit3 eng.flush() assert backend.received_commands[4].gate == X assert len(backend.received_commands[4].control_qubits) == 1 assert backend.received_commands[5].gate == H assert backend.received_commands[6].gate == Rz(0.1) assert backend.received_commands[10].gate == Measure assert backend.received_commands[11].gate == AddConstant(1) assert backend.received_commands[12].gate == AddConstantModN(1, 9) assert backend.received_commands[13].gate == X assert len(backend.received_commands[13].control_qubits) == 2 assert backend.received_commands[14].gate == Swap assert backend.received_commands[15].gate == MultiplyByConstantModN(2, 8) for cmd in backend.received_commands[16:]: assert cmd.gate != QFT assert not isinstance(cmd.gate, Rx) assert not isinstance(cmd.gate, MultiplyByConstantModN) assert not isinstance(cmd.gate, TimeEvolution)
def E(thetas, i): #the conjugate gradient minimizer uses np arrays and not scalars if (not isinstance(thetas, float)): theta = thetas[0] else: theta = thetas hamiltonian2quant = QubitOperator('', float(g[i][1])) + QubitOperator( 'Z0', float(g[i][2])) + QubitOperator('Z1', float( g[i][3])) + QubitOperator('Z0 Z1', float(g[i][4])) + QubitOperator( 'X0 X1', float(g[i][5])) + QubitOperator( 'Y0 Y1', float(g[i][6])) wavefunction = eng.allocate_qureg(2) X | wavefunction[0] op1 = QubitOperator('X0 Y1') TimeEvolution(time=theta, hamiltonian=op1) | wavefunction eng.flush() energy = eng.backend.get_expectation_value(hamiltonian2quant, wavefunction) Measure | wavefunction eng.flush() return energy
def E(theta, i): #build second quantized hamiltonian (devided for clearer arrangement) hamiltonian2quant = QubitOperator('', float(g[i][1])) + QubitOperator( 'Z0', float(g[i][2])) hamiltonian2quant += QubitOperator('Z1', float(g[i][3])) + QubitOperator( 'Z0 Z1', float(g[i][4])) hamiltonian2quant += QubitOperator('X0 X1', float( g[i][5])) + QubitOperator('Y0 Y1', float(g[i][6])) #allocate two qubits in |00> state wavefunction = eng.allocate_qureg(2) #set to "HF basis" |01> X | wavefunction[0] #build operator op1 op1 = QubitOperator('X0 Y1') #create time evolution operator e^{-i*op1*t} TimeEvolution(time=theta, hamiltonian=op1) | wavefunction eng.flush() #calculate energy=expectation value energy = eng.backend.get_expectation_value(hamiltonian2quant, wavefunction) Measure | wavefunction return energy
def zoo_profile(): """Generate and display the zoo of quantum gates.""" # create a main compiler engine with a drawing backend drawing_engine = CircuitDrawer() locations = {0: 1, 1: 2, 2: 0, 3: 3} drawing_engine.set_qubit_locations(locations) main_eng = MainEngine(drawing_engine) qureg = main_eng.allocate_qureg(4) # define a zoo of gates te_gate = TimeEvolution(0.5, 0.1 * QubitOperator('X0 Y2')) def add(x, y): return x, y + 1 zoo = [ (X, 3), (Y, 2), (Z, 0), (Rx(0.5), 2), (Ry(0.5), 1), (Rz(0.5), 1), (Ph(0.5), 0), (S, 3), (T, 2), (H, 1), (Toffoli, (0, 1, 2)), (Barrier, None), (Swap, (0, 3)), (SqrtSwap, (0, 1)), (get_inverse(SqrtSwap), (2, 3)), (SqrtX, 2), (C(get_inverse(SqrtX)), (0, 2)), (C(Ry(0.5)), (2, 3)), (CNOT, (2, 1)), (Entangle, None), (te_gate, None), (QFT, None), (Tensor(H), None), (BasicMathGate(add), (2, 3)), (All(Measure), None), ] # apply them for gate, pos in zoo: if pos is None: gate | qureg elif isinstance(pos, tuple): gate | tuple(qureg[i] for i in pos) else: gate | qureg[pos] main_eng.flush() # generate latex code to draw the circuit s = drawing_engine.get_latex() prefix = 'zoo' with open('{}.tex'.format(prefix), 'w') as f: f.write(s) # compile latex source code and open pdf file os.system('pdflatex {}.tex'.format(prefix)) openfile('{}.pdf'.format(prefix))
from projectq.ops import All, QubitOperator, H, Measure, X, Z, TimeEvolution from projectq import MainEngine import numpy as np eng = MainEngine() state = eng.allocate_qureg(2) All(H) | state # TimeEvolution(np.pi/2,QubitOperator("X0")+QubitOperator("Z1"))|state # it can be prove that the two approach above is equal TimeEvolution(np.pi / 2, QubitOperator("X0")) | state TimeEvolution(np.pi / 2, QubitOperator("Z1")) | state eng.flush() print(eng.backend.cheat()) All(Measure) | state # print([int(x) for x in state])
print("initialize engine..") # define energy hamiltonian H_t = H_Ising(N, J, alpha, beta) H_0 = H_ansatz(N, B) # start annealing print("start annealing..") state = engine.allocate_qureg(N) All(H) | state # |+] j = 0 for i in range(N): TimeEvolution(-B * dt / 2, QubitOperator("X" + str(i))) | state # j= 1:M-1 for j in range(1, M): for i in range(N): TimeEvolution(-beta * (j * dt**2 / T), QubitOperator("Z" + str(i))) | state TimeEvolution( -(alpha * (j * dt**2 / T) + B * dt * (1 - j * dt / T)), QubitOperator("X" + str(i))) | state for i in range(N - 1): TimeEvolution(-J * (j * dt**2 / T), QubitOperator("Z{0} Z{1}".format(i, i + 1))) | state TimeEvolution(-J * (j * dt**2 / T), QubitOperator("X{0} X{1}".format(i, i + 1))) | state # j=M
def test_decompose_individual_terms(): saving_eng = DummyEngine(save_commands=True) def my_filter(self, cmd): if (isinstance(cmd.gate, TimeEvolution)): return False return True rules = DecompositionRuleSet([te.rule_individual_terms]) replacer = AutoReplacer(rules) filter_eng = InstructionFilter(my_filter) eng = MainEngine(backend=Simulator(), engine_list=[replacer, filter_eng, saving_eng]) qureg = eng.allocate_qureg(5) # initialize in random wavefunction by applying some gates: Rx(0.1) | qureg[0] Ry(0.2) | qureg[1] Rx(0.45) | qureg[2] Rx(0.6) | qureg[3] Ry(0.77) | qureg[4] eng.flush() # Use cheat to get initial start wavefunction: qubit_to_bit_map, init_wavefunction = copy.deepcopy(eng.backend.cheat()) # Apply one qubit gates: op1 = QubitOperator((), 0.6) op2 = QubitOperator("X2", 0.21) op3 = QubitOperator("Y1", 0.33) op4 = QubitOperator("Z3", 0.42) op5 = QubitOperator("X0 Y1 Z2 Z4", -0.5) TimeEvolution(1.1, op1) | qureg eng.flush() qbit_to_bit_map1, final_wavefunction1 = copy.deepcopy(eng.backend.cheat()) TimeEvolution(1.2, op2) | qureg eng.flush() qbit_to_bit_map2, final_wavefunction2 = copy.deepcopy(eng.backend.cheat()) TimeEvolution(1.3, op3) | qureg eng.flush() qbit_to_bit_map3, final_wavefunction3 = copy.deepcopy(eng.backend.cheat()) TimeEvolution(1.4, op4) | qureg eng.flush() qbit_to_bit_map4, final_wavefunction4 = copy.deepcopy(eng.backend.cheat()) TimeEvolution(1.5, op5) | qureg eng.flush() qbit_to_bit_map5, final_wavefunction5 = copy.deepcopy(eng.backend.cheat()) All(Measure) | qureg # Check manually: def build_matrix(list_single_matrices): res = list_single_matrices[0] for i in range(1, len(list_single_matrices)): res = sps.kron(res, list_single_matrices[i]) return res.tocsc() id_sp = sps.identity(2, format="csc", dtype=complex) x_sp = sps.csc_matrix([[0., 1.], [1., 0.]], dtype=complex) y_sp = sps.csc_matrix([[0., -1.j], [1.j, 0.]], dtype=complex) z_sp = sps.csc_matrix([[1., 0.], [0., -1.]], dtype=complex) matrix1 = (sps.identity(2**5, format="csc", dtype=complex) * 0.6 * 1.1 * -1.0j) step1 = scipy.sparse.linalg.expm(matrix1).dot(init_wavefunction) assert numpy.allclose(step1, final_wavefunction1) matrix2_list = [] for i in range(5): if i == qbit_to_bit_map2[qureg[2].id]: matrix2_list.append(x_sp) else: matrix2_list.append(id_sp) matrix2_list.reverse() matrix2 = build_matrix(matrix2_list) * 0.21 * 1.2 * -1.0j step2 = scipy.sparse.linalg.expm(matrix2).dot(step1) assert numpy.allclose(step2, final_wavefunction2) matrix3_list = [] for i in range(5): if i == qbit_to_bit_map3[qureg[1].id]: matrix3_list.append(y_sp) else: matrix3_list.append(id_sp) matrix3_list.reverse() matrix3 = build_matrix(matrix3_list) * 0.33 * 1.3 * -1.0j step3 = scipy.sparse.linalg.expm(matrix3).dot(final_wavefunction2) assert numpy.allclose(step3, final_wavefunction3) matrix4_list = [] for i in range(5): if i == qbit_to_bit_map4[qureg[3].id]: matrix4_list.append(z_sp) else: matrix4_list.append(id_sp) matrix4_list.reverse() matrix4 = build_matrix(matrix4_list) * 0.42 * 1.4 * -1.0j step4 = scipy.sparse.linalg.expm(matrix4).dot(final_wavefunction3) assert numpy.allclose(step4, final_wavefunction4) matrix5_list = [] for i in range(5): if i == qbit_to_bit_map5[qureg[0].id]: matrix5_list.append(x_sp) elif i == qbit_to_bit_map5[qureg[1].id]: matrix5_list.append(y_sp) elif i == qbit_to_bit_map5[qureg[2].id]: matrix5_list.append(z_sp) elif i == qbit_to_bit_map5[qureg[4].id]: matrix5_list.append(z_sp) else: matrix5_list.append(id_sp) matrix5_list.reverse() matrix5 = build_matrix(matrix5_list) * -0.5 * 1.5 * -1.0j step5 = scipy.sparse.linalg.expm(matrix5).dot(final_wavefunction4) print(step5) print(final_wavefunction5) assert numpy.allclose(step5, final_wavefunction5)
def apply_time_evolution(hamiltonian: QubitOperator, time, wavefunction): projectq_qubit_operator = projectq.ops.QubitOperator() for term, coefficient in hamiltonian.terms.items(): projectq_qubit_operator.terms[term] = coefficient # print(time) TimeEvolution(time, projectq_qubit_operator) | wavefunction