Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Move methods from graphix and add Aer methods #7

Merged
merged 2 commits into from
May 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 13 additions & 42 deletions examples/aer_sim.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@
import random
from graphix import Circuit
from graphix_ibmq.runner import IBMQBackend
from qiskit import transpile
from qiskit.tools.visualization import plot_histogram
from qiskit_aer import AerSimulator
from qiskit_aer.noise import NoiseModel, depolarizing_error


def cp(circuit, theta, control, target):
"""Controlled phase gate, decomposed"""
circuit.rz(control, theta / 2)
Expand All @@ -34,28 +33,6 @@ def swap(circuit, a, b):
circuit.cnot(b, a)
circuit.cnot(a, b)

def format_result(pattern, result):
"""Format the result so that only the result corresponding to the output qubit is taken out.

Returns
-------
masked_results : dict
Dictionary of formatted results.
"""
masked_results = {}
N_node = pattern.Nnode + len(pattern.results)

# Iterate over original measurement results
for key, value in result.get_counts().items():
masked_key = ""
for idx in pattern.output_nodes:
masked_key += key[N_node - idx - 1]
if masked_key in masked_results:
masked_results[masked_key] += value
else:
masked_results[masked_key] = value

return masked_results

#%%
# Now let us define a circuit to apply QFT to three-qubit state.
Expand All @@ -68,16 +45,16 @@ def format_result(pattern, result):
# prepare random state for each input qubit
for i in range(3):
theta = random.uniform(0, np.pi)
phi = random.uniform(0, 2*np.pi)
phi = random.uniform(0, 2 * np.pi)
circuit.ry(i, theta)
circuit.rz(i, phi)
psi[i] = [np.cos(theta/2), np.sin(theta/2)*np.exp(1j*phi)]
psi[i] = [np.cos(theta / 2), np.sin(theta / 2) * np.exp(1j * phi)]

# 8 dimension input statevector
input_state = [0]*8
for i in range(8):
input_state = [0] * 8
for i in range(8):
i_str = f"{i:03b}"
input_state[i] = psi[0][int(i_str[0])]*psi[1][int(i_str[1])]*psi[2][int(i_str[2])]
input_state[i] = psi[0][int(i_str[0])] * psi[1][int(i_str[1])] * psi[2][int(i_str[2])]

# QFT
circuit.h(0)
Expand Down Expand Up @@ -112,11 +89,8 @@ def format_result(pattern, result):
#%%
# We can now simulate the circuit with Aer.

simulator = AerSimulator()
circ_sim = transpile(backend.circ, simulator)

# run and get counts
result = format_result(pattern, simulator.run(circ_sim, shots=1024).result())
result = backend.simulate()

#%%
# We can also simulate the circuit with noise model
Expand All @@ -125,36 +99,33 @@ def format_result(pattern, result):
noise_model = NoiseModel()
# add depolarizing error to all single qubit u1, u2, u3 gates
error = depolarizing_error(0.01, 1)
noise_model.add_all_qubit_quantum_error(error, ['u1', 'u2', 'u3'])
noise_model.add_all_qubit_quantum_error(error, ["u1", "u2", "u3"])

# print noise model info
print(noise_model)

#%%
# Now we can run the simulation with noise model

sim_noise = AerSimulator(noise_model=noise_model)
# transpile circuit for noisy basis gates
circ_noise = transpile(backend.circ, sim_noise)
# run and get counts
result_noise = format_result(pattern, sim_noise.run(circ_noise).result())
result_noise = backend.simulate(noise_model=noise_model)


#%%
# Now let us compare the results with theoretical output

# calculate the theoretical output state
state = [0]*8
omega = np.exp(1j*np.pi/4)
state = [0] * 8
omega = np.exp(1j * np.pi / 4)

for i in range(8):
for j in range(8):
state[i] += input_state[j]*omega**(i*j)/2**1.5
state[i] += input_state[j] * omega ** (i * j) / 2**1.5

# calculate the theoretical counts
count_theory = {}
for i in range(2**3):
count_theory[f"{i:03b}"] = 1024*np.abs(state[i])**2
count_theory[f"{i:03b}"] = 1024 * np.abs(state[i]) ** 2

# plot and compare the results
plot_histogram(
Expand Down
66 changes: 17 additions & 49 deletions examples/ibm_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,11 @@
import random
from graphix import Circuit
from graphix_ibmq.runner import IBMQBackend
from qiskit import IBMQ, transpile
from qiskit_ibm_provider import IBMProvider
from qiskit import IBMQ
from qiskit.tools.visualization import plot_histogram
from qiskit_aer import AerSimulator
from qiskit.providers.fake_provider import FakeLagos


def cp(circuit, theta, control, target):
"""Controlled phase gate, decomposed"""
circuit.rz(control, theta / 2)
Expand All @@ -35,28 +34,6 @@ def swap(circuit, a, b):
circuit.cnot(b, a)
circuit.cnot(a, b)

def format_result(pattern, result):
"""Format the result so that only the result corresponding to the output qubit is taken out.

Returns
-------
masked_results : dict
Dictionary of formatted results.
"""
masked_results = {}
N_node = pattern.Nnode + len(pattern.results)

# Iterate over original measurement results
for key, value in result.get_counts().items():
masked_key = ""
for idx in pattern.output_nodes:
masked_key += key[N_node - idx - 1]
if masked_key in masked_results:
masked_results[masked_key] += value
else:
masked_results[masked_key] = value

return masked_results

#%%
# Now let us define a circuit to apply QFT to three-qubit state.
Expand All @@ -69,16 +46,16 @@ def format_result(pattern, result):
# prepare random state for each input qubit
for i in range(3):
theta = random.uniform(0, np.pi)
phi = random.uniform(0, 2*np.pi)
phi = random.uniform(0, 2 * np.pi)
circuit.ry(i, theta)
circuit.rz(i, phi)
psi[i] = [np.cos(theta/2), np.sin(theta/2)*np.exp(1j*phi)]
psi[i] = [np.cos(theta / 2), np.sin(theta / 2) * np.exp(1j * phi)]

# 8 dimension input statevector
input_state = [0]*8
for i in range(8):
input_state = [0] * 8
for i in range(8):
i_str = f"{i:03b}"
input_state[i] = psi[0][int(i_str[0])]*psi[1][int(i_str[1])]*psi[2][int(i_str[2])]
input_state[i] = psi[0][int(i_str[0])] * psi[1][int(i_str[1])] * psi[2][int(i_str[2])]

# QFT
circuit.h(0)
Expand Down Expand Up @@ -113,60 +90,51 @@ def format_result(pattern, result):
#%%
# Get the API token and load the IBMQ acount.

IBMQ.save_account('MY_API_TOKEN', overwrite=True)
IBMQ.save_account("MY_API_TOKEN", overwrite=True)
IBMQ.load_account()

#%%
# Get provider and the backend.

instance_name = 'ibm-q/open/main'
instance_name = "ibm-q/open/main"
backend_name = "ibm_lagos"

provider = IBMProvider(instance=instance_name)
backend = provider.get_backend(backend_name)
print(f"Using backend {backend.name}")
backend.get_backend(instance=instance_name, resource=backend_name)

#%%
# We can now execute the circuit on the device backend.

circ_device = transpile(backend.circ, backend)
job = backend.run(circ_device, shots=1024, dynamic=True)
print(f"Your job's id: {job.job_id()}")
result = format_result(pattern, job.result())
result = backend.run()

#%%
# Retrieve the job if needed

# job = provider.backend.retrieve_job("Job ID")
# result = format_result(pattern, job.result())
# result = backend.retrieve_result("Job ID")

#%%
# We can simulate the circuit with noise model based on the device we used

# get the noise model of the device backend
backend_noisemodel = FakeLagos()
sim_noise = AerSimulator.from_backend(backend_noisemodel)

# transpile the circuit for the noisy basis gates
circ_noise = transpile(backend.circ, sim_noise)
# execute noisy simulation and get counts
result_noise = format_result(pattern, sim_noise.run(circ_noise).result())
result_noise = backend.simulate(noise_model=backend_noisemodel)

#%%
# Now let us compare the results with theoretical output

# calculate the theoretical output state
state = [0]*8
omega = np.exp(1j*np.pi/4)
state = [0] * 8
omega = np.exp(1j * np.pi / 4)

for i in range(8):
for j in range(8):
state[i] += input_state[j]*omega**(i*j)/2**1.5
state[i] += input_state[j] * omega ** (i * j) / 2**1.5

# calculate the theoretical counts
count_theory = {}
for i in range(2**3):
count_theory[f"{i:03b}"] = 1024*np.abs(state[i])**2
count_theory[f"{i:03b}"] = 1024 * np.abs(state[i]) ** 2

# plot and compare the results
plot_histogram(
Expand Down
Loading