def test_sample_2qb(self): qpu = PyLinalg() prog = Program() qbits = prog.qalloc(2) prog.apply(X, qbits[0]) circ = prog.to_circ() obs = Observable(2, pauli_terms=[Term(1., "ZZ", [0, 1])]) job = circ.to_job("OBS", observable=obs) result = qpu.submit(job) self.assertAlmostEqual(result.value, -1) prog = Program() qbits = prog.qalloc(2) prog.apply(X, qbits[0]) prog.apply(X, qbits[1]) circ = prog.to_circ() obs = Observable(2, pauli_terms=[Term(1., "ZZ", [0, 1])]) job = circ.to_job("OBS", observable=obs) result = qpu.submit(job) self.assertAlmostEqual(result.value, 1)
def C(graph): energy = Observable(graph.V) for edge in itertools.combinations(range(graph.V), 2): energy.add_term(Term(-graph.E[edge] / 2, "ZZ", edge)) energy.constant_coeff += np.sum(graph.E) / 4 return energy
def generate_random_observable(nbqbit: int) -> Observable: """ Generate a random observable. Args: nbqbit (int): number of qubits Returns: Observable: an observable """ # Determine randomly the number of Pauli terms in the observable nb_terms = rd.randint(1, nbqbit) pauli_terms = [] for _ in range(nb_terms): # Determine randomly the number of qubits involve in the Pauli term nb_qbit_term = rd.randint(1, nbqbit) # Build randomly the tensor of the term tensor = ''.join( [rd.choice(['X', 'Y', 'Z']) for _ in range(nb_qbit_term)]) # Create and add the term to the list pauli_terms.append( Term(rd.random(), tensor, rd.sample(range(nbqbit), nb_qbit_term))) # build and return the observable return Observable(nbqbit, pauli_terms=pauli_terms, constant_coeff=rd.random())
def test4_cannot_measure_observable(self): """ Checks if measuring an Observable raises an error """ prog = Program() qbits = prog.qalloc(1) prog.apply(X, qbits) circ = prog.to_circ() qpu = BackendToQPU(Aer.get_backend('qasm_simulator')) self.assertRaises(QPUException, qpu.submit, circ.to_job("OBS", observable=Observable(1)))
def test_basic(self): with self.assertRaises(QPUException): prog = Program() qbits = prog.qalloc(1) prog.apply(X, qbits) circ = prog.to_circ() obs = Observable(1, pauli_terms=[Term(1., "Z", [0])]) job = circ.to_job("OBS", observable=obs, nbshots=10) qpu = PyLinalg() result = qpu.submit(job)
def test_sample_1qb_Y(self): prog = Program() qbits = prog.qalloc(1) prog.apply(H, qbits) prog.apply(PH(-np.pi / 2), qbits) circ = prog.to_circ() obs = Observable(1, pauli_terms=[Term(1., "Y", [0])]) job = circ.to_job("OBS", observable=obs) qpu = PyLinalg() result = qpu.submit(job) self.assertAlmostEqual(result.value, -1) obs = Observable(1, pauli_terms=[Term(18., "Y", [0])]) job = circ.to_job("OBS", observable=obs) result = qpu.submit(job) self.assertAlmostEqual(result.value, -18) prog = Program() qbits = prog.qalloc(1) prog.apply(H, qbits) prog.apply(PH(np.pi / 2), qbits) circ = prog.to_circ() obs = Observable(1, pauli_terms=[Term(1., "Y", [0])]) job = circ.to_job("OBS", observable=obs) result = qpu.submit(job) self.assertAlmostEqual(result.value, 1) obs = Observable(1, pauli_terms=[Term(18., "Y", [0])]) job = circ.to_job("OBS", observable=obs) result = qpu.submit(job) self.assertAlmostEqual(result.value, 18)
def test_submit_job(self): # Create a valid qpu qpu_valid = SimulatedAnnealing( temp_t=TestSimulatedAnnealing.temp_t_valid, n_steps=TestSimulatedAnnealing.n_steps_valid, seed=8017) # Create an Observable Job and check that such Jobs are not dealt with by the qpu observable = Observable(5) job = Job(observable=observable) with pytest.raises(exceptions_types.QPUException): assert result == qpu_valid.submit_job(job) # Create a circuit Job a and check that such Jobs are not dealt with by the qpu from qat.lang.AQASM import Program, H prog = Program() reg = prog.qalloc(1) prog.apply(H, reg) prog.reset(reg) with pytest.raises(exceptions_types.QPUException): assert result == qpu_valid.submit(prog.to_circ().to_job(nbshots=1)) # Create a Job from a Schedule with empty drive and check that such # Jobs are not dealt with by the qpu schedule = Schedule() job = Job(schedule=schedule) with pytest.raises(exceptions_types.QPUException): assert result == qpu_valid.submit_job(job) # Create a job from a Schedule with a drive with more than one observable # or an observable with coefficient not 1 to check that such Jobs don't work # with the qpu observable = get_observable(TestSimulatedAnnealing.J_valid, TestSimulatedAnnealing.h_valid, TestSimulatedAnnealing.offset_valid) drive_invalid_1 = [(1, observable), (1, observable)] schedule = Schedule(drive=drive_invalid_1) job = schedule.to_job() with pytest.raises(exceptions_types.QPUException): assert result == qpu_valid.submit_job(job) drive_invalid_2 = [(5, observable)] schedule = Schedule(drive=drive_invalid_2) job = schedule.to_job() with pytest.raises(exceptions_types.QPUException): assert result == qpu_valid.submit_job(job) # Solve the problem and check that the returned result is Result result = qpu_valid.submit_job(TestSimulatedAnnealing.job_valid) assert isinstance(result, Result)
def get_observable(J, h, offset): """ Returns an Observable from a J coupling and magnetic field h of an Ising problem. Returns: :class:`~qat.core.Observable`: an Ising Hamiltonian encoding the problem """ n_spins = J.shape[0] observable = Observable(n_spins, constant_coeff=-offset) for i in range(n_spins): if not np.isclose(h[i], 0): observable.terms.append(Term(-h[i], "Z", [i])) for j in range(i + 1, n_spins): if not np.isclose(J[i, j], 0): observable.terms.append(Term(-J[i, j], "ZZ", [i, j])) return observable
def bipartition(s, p): ###Define a variational circuit #As a Program prog = Program() #With n qubits nqbits = len(s) qbits = prog.qalloc(nqbits) #Define the variational states (einsatz) #|psi(theta)> = Rx1(theta1x)...Rxn(theta1n)|0,...,0> for i in range(0, nqbits): for j in range(1): #H(qbits[i]) thetaij = prog.new_var(float, "theta"+str(i)+str(j)) if j == 0 : RX(np.pi*thetaij)(qbits[i]) #RZ(thetaij)(qbits[i]) #H Rz H method #elif j ==1 : # RY(thetaij)(qbits[i]) #elif j == 2: # RZ(thetaij)(qbits[i]) # elif j == 3 : # RY(thetaij)(qbits[i]) # elif j == 4 : # RX(thetaij)(qbits[i]) #H(qbits[i]) #export program into a quntum circuit circuit = prog.to_circ() #print created variables" print("Variables:", circuit.get_variables()) ###Define an observable #Initialization obs = Observable(nqbits) #Observable = Hamiltonian we want to minimize # => Reformulate bi-partition problem in Hamiltonian minimalization problem : #Bi-partition problem : Find A1,A2 such that A1 u A2 = s and minimizes |sum_{n1 in A1}n1 - sum_{n2 in A2}n2| #Optimization Problem : Find e = {ei} in {-1,1}^n minimizing |sum_{1<=i<=n}ei.si| #Non-Linear Integer Programming Optimization Problem Find e = {ei} in {-1,1}^n minimizing (sum_{1<=i<=n}ei.si)^2 #Ising problem : Find e = {ei} in {-1,1}^n minimizing sum_{1<=i<=n}(si)^2 + sum_{1<=i<=n, 1<=i<j<=n} (si.sj).ei.ej)^2 (si^2 = 1) J = [[si*sj for si in s] for sj in s] b = [si**2 for si in s] obs += sum(b)*Observable(nqbits, constant_coeff = sum(b)) for i in range(nqbits): for j in range(i-1): obs += Observable(nqbits, pauli_terms = [Term(J[i][j], "ZZ", [i, j])]) #Term(coefficient, tensorprod, [qubits]) ###Create a quantum job #Made of a circuit and and an observable job = circuit.to_job(observable = obs) #nbshots=inf ###Define classical optimizer : scipy.optimia.minimize method_name = "COBYLA" #"Nelder-Mead", "Powell", "CG",... optimize = ScipyMinimizePlugin(method = method_name, tol = 1e-3, options = {"maxiter" : p}) ###Define qpu on which to run quantum job stack = optimize | get_default_qpu() optimizer_args = {"method": method_name, "tol":1e-3, "options":{"maxiter":p}} result = stack.submit(job, meta_data ={"ScipyMinimizePlugin": json.dumps(optimizer_args)}) ###Get characteristics of best parametrized circuit found final_energy = result.value parameters = json.loads(result.meta_data['parameters']) print("final energy:", final_energy) print('best parameters:', parameters) #print('trace:', result.meta_data['optimization_trace']) ###Deduce the most probable state => solution of the problem #Probability to measure qubit i in state |0> : cos(theta_i)^2 #Probability to measure qubit i in state |1> : sin(theta_i)^2 states = {} best_state = '' max_proba = 0 for i in range(2**nqbits): state = bin(i)[2:].zfill(nqbits) proba = 1 for i in range(nqbits): proba = proba/2*((1+(-1)**int(state[nqbits-i-1]))*np.cos(parameters[i]*np.pi/2)+(1+(-1)**(int(state[nqbits-i-1])+1))*np.sin(parameters[i]*np.pi/2)) if max_proba < proba: max_proba = proba best_state = state states[state] = proba print(states) A1 = [] A2 = [] for i in range(nqbits): if best_state[i] == '0': A1.append(s[i]) elif best_state[i] == '1': A2.append(s[i]) return A1, A2