No-communications scheme
Ideal execution
Let’s showcase here more advanced examples of the no-communication model that showcase a more complex use of CUNQA than the one displayed in the Embarrassingly Parallel section.
For optimization algorithms, the mappers submodule and the
upgrade_parameters method of the the QJob were
developed. The usage of these two features can be seen in the following examples.
The following example shows how to obtain different statistics from QJob results:
Finally, we present an example of the local iterative QPE, so that the results obtained can be compared with the ones in Classical-communications scheme and Quantum-communications scheme.
import os, sys
# In order to import cunqa, we append to the search path the cunqa installation path
sys.path.append(os.getenv("HOME")) # HOME as install path is specific to CESGA
from cunqa.circuit import CunqaCircuit
from cunqa.qpu import qraise, get_QPUs, run, qdrop
import numpy as np
# 1. Circuit design
parametric_circuit = CunqaCircuit(3, 1)
parametric_circuit.h(0)
parametric_circuit.rx("x1", 1)
parametric_circuit.rx("x2", 2)
parametric_circuit.crz("theta", 0, 1)
parametric_circuit.crz("theta", 0, 2)
parametric_circuit.p("phase", 0)
parametric_circuit.h(0)
parametric_circuit.measure(0,0)
N_QPUS = 8 # Determines the number of bits of the phase that will be computed
PHASE_TO_COMPUTE = 1/2**5
SHOTS = 1024
BIT_PRECISION = N_QPUS
SEED = 18 # Set seed for reproducibility
# Parameters initial values
theta = 2 * np.pi * PHASE_TO_COMPUTE
x1 = np.pi
x2 = np.pi
try:
# 1. Deploy vQPUs
family = qraise(N_QPUS, "00:10:00", simulator = "Aer", co_located = True)
except Exception as error:
raise error
try:
qpus = get_QPUs(co_located = True, family = family)
measure = []
for k in range(BIT_PRECISION):
# 2. Circuit design
power = 2**(BIT_PRECISION - 1 - k)
phase = 0
for i in range(k):
if measure[i]:
phase = phase + (1 / (2**(k-i)))
phase = -np.pi * phase
params = {
"theta": power * theta,
"phase": phase,
"x1": x1,
"x2": x2
}
# 3. Execution
result = run(parametric_circuit, qpus[k%10], params, shots = 2000, seed = SEED).result
counts = result.counts
zeros = sum([counts for result, counts in counts.items() if result.endswith('0')])
ones = sum([counts for result, counts in counts.items() if result.endswith('1')])
measure.append(0 if zeros > ones else 1)
# 4. Post processing results
estimation = 0
for j,l in enumerate(measure):
estimation = estimation + (l/(2**(BIT_PRECISION - j)))
print(f"Estimated angle: {estimation}")
print(f"Real angle: {PHASE_TO_COMPUTE}")
# 5. Release resources
qdrop(family)
except Exception as error:
qdrop(family)
raise error
Noisy execution
Running on noisy vQPUs requires two changes with respect to an ideal execution: the vQPUs must be deployed with a backend configuration describing the noise model to emulate, and the circuit must be transpiled to the vQPU’s backend before being run.
To deploy the noisy vQPUs, as it was explained in
Overview, the qraise Bash command or its
Python function counterpart qraise have to be employed with the --backend flag,
in the first case, and with the backend argument, in the second; both being the path to a
backend configuration JSON file. This backend file points, through its
noise_model.noise_properties_path field, to a noise properties JSON file. The format of both files
is shown in Backend JSON and
Noise properties JSON.
qraise -n 4 -t 01:00:00 --co-located --backend="complete/path/to/backend.json"
family = qraise(4, "01:00:00", co_located=True, backend="complete/path/to/backend.json")
Once the noisy vQPUs are deployed, the circuit has to be transpiled to the
vQPU’s backend with the transpiler function before
running it. This step is required so that the circuit is expressed in terms of the basis gates and the
connectivity supported by the noisy backend. The following example shows the complete workflow:
import os, sys
# In order to import cunqa, we append to the search path the cunqa installation path
sys.path.append(os.getenv("HOME")) # HOME as install path is specific to CESGA
from cunqa.qpu import get_QPUs, run, qraise, qdrop
from cunqa.qjob import gather
from cunqa.circuit import CunqaCircuit
from cunqa.qiskit_deps.transpiler import transpiler
try:
# 1. Deploy noisy vQPUs
file_dir = os.path.dirname(os.path.abspath(__file__))
backend_path = file_dir + "/noisy_backend.json"
family = qraise(1, "00:10:00", simulator="Aer", co_located=True, backend=backend_path)
except Exception as error:
raise error
try:
[qpu] = get_QPUs(co_located=True)
# 2. Design circuit as any other execution
qc = CunqaCircuit(num_qubits = 2)
qc.h(0)
qc.cx(0,1)
qc.measure_all()
# 3. Transpilation. Required for execution on noisy QPUs
qc_transpiled = transpiler(qc, qpu.backend, opt_level = 2, initial_layout = None, seed = None)
# 4. Execution
qjob = run(qc_transpiled, qpu, shots = 1000)
print(f"Counts: {qjob.result.counts}" ) # Format: {'00':546, '11':454}
# 5. Relinquish resources
qdrop(family)
except Exception as error:
# 5. Relinquish resources even if an error is raised
qdrop(family)
raise error



