Skip to content

Commit

Permalink
Updates to quantum volume and how to use qiskit (#1289)
Browse files Browse the repository at this point in the history
Gets the Quantum Volume and how to use qiskit demos working

---------

Co-authored-by: Astral Cai <[email protected]>
  • Loading branch information
albi3ro and astralcai authored Jan 10, 2025
1 parent 614b305 commit 88a3a17
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
}
],
"dateOfPublication": "2024-07-02T00:00:00+00:00",
"dateOfLastModification": "2024-10-07T00:00:00+00:00",
"dateOfLastModification": "2025-01-08T00:00:00+00:00",
"categories": [
"Quantum Computing",
"How-to"
Expand Down
10 changes: 7 additions & 3 deletions demonstrations/how_to_use_qiskit1_with_pennylane.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ def qiskit_GHZ_circuit(n):
#

pl_circuit = qml.QNode(pl_qfunc, device=qml.device("lightning.qubit", wires=n))
pl_circuit()
print(pl_circuit())

######################################################################
# .. rst-class:: sphx-glr-script-out
Expand All @@ -263,7 +263,7 @@ def qiskit_GHZ_circuit(n):
pl_qfunc = qml.from_qiskit(qc, measurements=measurements)

pl_circuit = qml.QNode(pl_qfunc, device=qml.device("default.qubit", wires=n))
pl_circuit(shots=5)
print(pl_circuit(shots=5))

######################################################################
# .. rst-class:: sphx-glr-script-out
Expand Down Expand Up @@ -304,6 +304,7 @@ def qiskit_GHZ_circuit(n):
#

from qiskit.circuit import ParameterVector, Parameter
from matplotlib import pyplot as plt

n = 3

Expand All @@ -316,6 +317,8 @@ def qiskit_GHZ_circuit(n):
qc.ry(angle2, [2])

qc.draw("mpl")
plt.show()


######################################################################
# .. rst-class:: image-no-text-wrap
Expand Down Expand Up @@ -349,7 +352,8 @@ def differentiable_circuit(phis, theta):
theta = np.array([0.19])

print(differentiable_circuit(phis, theta))
print(qml.draw_mpl(differentiable_circuit)(phis, theta))
qml.draw_mpl(differentiable_circuit, style="pennylane")(phis, theta)
plt.show()

######################################################################
# .. rst-class:: sphx-glr-script-out
Expand Down
2 changes: 1 addition & 1 deletion demonstrations/quantum_volume.metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
}
],
"dateOfPublication": "2020-12-15T00:00:00+00:00",
"dateOfLastModification": "2024-10-11T00:00:00+00:00",
"dateOfLastModification": "2025-01-08T00:00:00+00:00",
"categories": [
"Quantum Hardware",
"Quantum Computing"
Expand Down
55 changes: 25 additions & 30 deletions demonstrations/quantum_volume.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,19 +343,17 @@ def permute_qubits(num_qubits):

##############################################################################
#
# Next, we need to apply SU(4) gates to pairs of qubits. PennyLane doesn't have
# built-in functionality to generate these random matrices, however its cousin
# `Strawberry Fields <https://strawberryfields.ai/>`_ does! We will use the
# ``random_interferometer`` method, which can generate unitary matrices uniformly
# Next, we need to apply SU(4) gates to pairs of qubits.
# We can use scipy to generate unitary matrices uniformly
# at random. This function actually generates elements of U(4), but they are
# essentially equivalent up to a global phase.

from strawberryfields.utils import random_interferometer
from scipy.stats import unitary_group

def apply_random_su4_layer(num_qubits):
for qubit_idx in range(0, num_qubits, 2):
if qubit_idx < num_qubits - 1:
rand_haar_su4 = random_interferometer(N=4)
rand_haar_su4 = unitary_group.rvs(4)
qml.QubitUnitary(rand_haar_su4, wires=[qubit_idx, qubit_idx + 1])


Expand Down Expand Up @@ -386,9 +384,10 @@ def qv_circuit_layer(num_qubits):
m = 3 # number of qubits

with qml.tape.QuantumTape() as tape:
qml.layer(qv_circuit_layer, m, num_qubits=m)
for _ in range(m):
qv_circuit_layer(m)

expanded_tape = tape.expand(stop_at=lambda op: isinstance(op, qml.QubitUnitary))
(expanded_tape, ), _ = qml.transforms.decompose(tape, gate_set={qml.QubitUnitary, qml.SWAP})
print(qml.drawer.tape_text(expanded_tape, wire_order=dev_ideal.wires, show_all_wires=True, show_matrices=True))


Expand Down Expand Up @@ -487,12 +486,11 @@ def heavy_output_set(m, probs):
#

# Adds a measurement of the first m qubits to the previous circuit
with tape:
qml.probs(wires=range(m))
tape = tape.copy(measurements=[qml.probs(wires=range(m))])

# Run the circuit, compute heavy outputs, and print results
output_probs = qml.execute([tape], dev_ideal, None) # returns a list of result !
output_probs = output_probs[0].reshape(2 ** m, )
[output_probs] = qml.execute([tape], dev_ideal) # returns a list of result !
output_probs = output_probs.reshape(2 ** m, )
heavy_outputs, prob_heavy_output = heavy_output_set(m, output_probs)

print("State\tProbability")
Expand Down Expand Up @@ -583,25 +581,22 @@ def heavy_output_set(m, probs):
# Lima noise model. Again, we won't be running on Lima directly ---
# we'll set up a local device to simulate its behaviour.
#

dev_noisy = qml.device("qiskit.remote", wires=5, shots=1000, backend=FakeLimaV2())

##############################################################################
#
# As a final point, since we are allowed to do as much optimization as we like,
# let's put the compiler to work. The compiler will perform a number of
# optimizations to simplify our circuit. We'll also specify some high-quality
# qubit placement and routing techniques [#sabre]_ in order to fit the circuits
# on the hardware graph in the best way possible.

dev_noisy.set_transpile_args(
**{

transpile_args = {
"optimization_level": 3,
"coupling_map": FakeLimaV2().coupling_map,
"layout_method": "sabre",
"routing_method": "sabre",
}
)

dev_noisy = qml.device("qiskit.remote", wires=5, shots=1000, backend=FakeLimaV2(), **transpile_args)


##############################################################################
Expand All @@ -625,28 +620,28 @@ def heavy_output_set(m, probs):
for trial in range(num_trials):

# Simulate the circuit analytically
with qml.tape.QuantumTape() as tape:
qml.layer(qv_circuit_layer, m, num_qubits=m)
with qml.tape.QuantumTape() as tape_probs:
for _ in range(m):
qv_circuit_layer(m)
qml.probs(wires=range(m))

# when using qml.execute, shots must be on the tape
tape_counts = tape_probs.copy(measurements=[qml.counts()], shots=1000)

output_probs = qml.execute([tape], dev_ideal, None)
output_probs = qml.execute([tape_probs], dev_ideal)
output_probs = output_probs[0].reshape(2 ** m, )
heavy_outputs, prob_heavy_output = heavy_output_set(m, output_probs)

# Execute circuit on the noisy device
qml.execute([tape], dev_noisy, None)

# Get the output bit strings; flip ordering of qubits to match PennyLane
counts = dev_noisy._current_job.result().get_counts()
reordered_counts = {x[::-1]: counts[x] for x in counts.keys()}
[counts] = qml.execute([tape_counts], dev_noisy)

device_heavy_outputs = np.sum(
[
reordered_counts[x] if x[:m] in heavy_outputs else 0
for x in reordered_counts.keys()
counts[x] if x[:m] in heavy_outputs else 0
for x in counts.keys()
]
)
fraction_device_heavy_output = device_heavy_outputs / dev_noisy.shots
fraction_device_heavy_output = device_heavy_outputs / dev_noisy.shots.total_shots

probs_ideal[m - min_m, trial] = prob_heavy_output
probs_noisy[m - min_m, trial] = fraction_device_heavy_output
Expand Down

0 comments on commit 88a3a17

Please sign in to comment.