Skip to content

Commit

Permalink
Remove unnecessary circuit metadata (#1315)
Browse files Browse the repository at this point in the history
### Summary

As the number of qubits in the parallel experiment increases, the memory
footprint of job payload communicated through wire becomes more serious
issue. Some built-in experiment generates circuits with unnecessary
metadata, which is
- duplicated information existing in experiment metadata
- duplicated information existing in every circuit metadata
- un-used information in analysis

This PR removes such unnecessary fields from the circuit metadata to
reduce payload size. For example, if an experiment is paired with a
curve analysis, it only requires `xval` and other minimum keys necessary
for model matching.

### Details and comments

Tutorial is also updated.

---------

Co-authored-by: Will Shanks <[email protected]>
Co-authored-by: Helena Zhang <[email protected]>
  • Loading branch information
3 people authored Jan 10, 2024
1 parent ab40c5a commit 79e0a69
Show file tree
Hide file tree
Showing 24 changed files with 127 additions and 253 deletions.
22 changes: 12 additions & 10 deletions docs/manuals/characterization/t1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,10 @@ that is close to a logical value '0'.
mu = 1e-6

# qubit properties
t1 = [45 * mu, 45 * mu]
t2 = [value/2 for value in t1]
t1 = 45 * mu

# we will guess that our guess is 10% off the exact value of t1 for qubit 0.
t1_estimated_shift = t1[0]/10
t1_estimated_shift = t1/10

# We use log space for the delays because of the noise properties
delays = np.logspace(1, 11, num=23, base=np.exp(1))
Expand All @@ -111,25 +110,28 @@ that is close to a logical value '0'.
# Adding circuits with delay=0 and long delays so the centers in the IQ plane won't be misplaced.
# Without this, the fitting can provide wrong results.
delays = np.insert(delays, 0, 0)
delays = np.append(delays, [t1[0]*3])
delays = np.append(delays, [t1*3])

num_qubits = 2
num_shots = 2048

backend = MockIQBackend(
MockIQT1Helper(t1=t1, iq_cluster_centers=[((-5.0, -4.0), (-5.0, 4.0)), ((3.0, 1.0), (5.0, -3.0))]
, iq_cluster_width=[1.0, 2.0])
MockIQT1Helper(
t1=t1,
iq_cluster_centers=[((-5.0, -4.0), (-5.0, 4.0)), ((3.0, 1.0), (5.0, -3.0))],
iq_cluster_width=[1.0, 2.0],
)
)

# Creating a T1 experiment
expT1_kerneled = T1((0,), delays)
expT1_kerneled.analysis = T1KerneledAnalysis()
expT1_kerneled.analysis.set_options(p0={"amp": 1, "tau": t1[0] + t1_estimated_shift, "base": 0})
expT1_kerneled.analysis.set_options(p0={"amp": 1, "tau": t1 + t1_estimated_shift, "base": 0})

# Running the experiment
expdataT1_kerneled = expT1_kerneled.run(backend=backend, meas_return="avg",
meas_level=MeasLevel.KERNELED,
shots=num_shots).block_for_results()
expdataT1_kerneled = expT1_kerneled.run(
backend=backend, meas_return="avg", meas_level=MeasLevel.KERNELED, shots=num_shots
).block_for_results()

# Displaying results
display(expdataT1_kerneled.figure(0))
Expand Down
13 changes: 13 additions & 0 deletions docs/tutorials/custom_experiment.rst
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,19 @@ signature to restore the output to what it should be without the random Pauli fr
at the end. We make a new :class:`.AnalysisResultData` object since we're rewriting the
counts from the original experiment.

.. note::

As you may find here, circuit metadata is mainly used to generate a structured data
in the analysis class for convenience of result handling.
A metadata supplied to a particular circuit should appear in the corresponding
experiment result data dictionary stored in the experiment data.
If you attach large amount of metadata which is not expected to be used in the analysis,
the metadata just unnecessarily increases the job payload memory footprint,
and it prevents your experiment class from scaling in qubit size through
the composite experiment tooling.
If you still want to store some experiment setting, which is common to all circuits
or irrelevant to the analysis, use the experiment metadata instead.

.. jupyter-input::

from qiskit_experiments.framework import BaseAnalysis, AnalysisResultData
Expand Down
2 changes: 0 additions & 2 deletions qiskit_experiments/library/characterization/drag.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,6 @@ def circuits(self) -> List[QuantumCircuit]:
assigned_circuit = circuit.assign_parameters({beta: beta_val}, inplace=False)

assigned_circuit.metadata = {
"experiment_type": self._type,
"qubits": self.physical_qubits,
"xval": beta_val,
"nrep": rep,
}
Expand Down
6 changes: 0 additions & 6 deletions qiskit_experiments/library/characterization/fine_amplitude.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,7 @@ def _spam_cal_circuits(self, meas_circuit: QuantumCircuit) -> List[QuantumCircui
circ.compose(meas_circuit, inplace=True)

circ.metadata = {
"experiment_type": self._type,
"qubits": self.physical_qubits,
"xval": add_x,
"unit": "gate number",
"series": "spam-cal",
}

Expand Down Expand Up @@ -229,10 +226,7 @@ def circuits(self) -> List[QuantumCircuit]:
circuit.compose(meas_circ, qubits, range(meas_circ.num_clbits), inplace=True)

circuit.metadata = {
"experiment_type": self._type,
"qubits": self.physical_qubits,
"xval": repetition,
"unit": "gate number",
"series": 1,
}

Expand Down
7 changes: 1 addition & 6 deletions qiskit_experiments/library/characterization/fine_drag.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,12 +218,7 @@ def circuits(self) -> List[QuantumCircuit]:
params=[],
)

circuit.metadata = {
"experiment_type": self._type,
"qubits": self.physical_qubits,
"xval": repetition,
"unit": "gate number",
}
circuit.metadata = {"xval": repetition}

circuits.append(circuit)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,7 @@ def circuits(self) -> List[QuantumCircuit]:
circuit.sx(0)
circuit.measure_all()

circuit.metadata = {
"experiment_type": self._type,
"qubits": self.physical_qubits,
"xval": repetition,
"unit": "Number of delays",
}
circuit.metadata = {"xval": repetition}

circuits.append(circuit)

Expand Down
7 changes: 1 addition & 6 deletions qiskit_experiments/library/characterization/half_angle.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,12 +160,7 @@ def circuits(self) -> List[QuantumCircuit]:
circuit.sx(0)
circuit.measure_all()

circuit.metadata = {
"experiment_type": self._type,
"qubits": self.physical_qubits,
"xval": repetition,
"unit": "repetition number",
}
circuit.metadata = {"xval": repetition}

circuits.append(circuit)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ def circuits(self):
freq_shift = np.round(freq_shift, decimals=3)

assigned_circ = circuit.assign_parameters({freq_param: freq_shift}, inplace=False)
self._add_metadata(assigned_circ, freq, sched)
self._add_metadata(assigned_circ, freq)

circs.append(assigned_circ)

Expand Down
8 changes: 1 addition & 7 deletions qiskit_experiments/library/characterization/rabi.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,13 +163,7 @@ def circuits(self) -> List[QuantumCircuit]:
# which isn't serializable in the metadata.
amp = float(np.round(amp, decimals=6))
assigned_circ = circuit.assign_parameters({param: amp}, inplace=False)
assigned_circ.metadata = {
"experiment_type": self._type,
"qubits": self.physical_qubits,
"xval": amp,
"unit": "arb. unit",
"amplitude": amp,
}
assigned_circ.metadata = {"xval": amp}

circs.append(assigned_circ)

Expand Down
33 changes: 13 additions & 20 deletions qiskit_experiments/library/characterization/ramsey_xy.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,42 +155,35 @@ def circuits(self) -> List[QuantumCircuit]:
rotation_angle = rotation_angle * timing.dt

# Create the X and Y circuits.
metadata = {
"experiment_type": self._type,
"qubits": self.physical_qubits,
"osc_freq": self.experiment_options.osc_freq,
"unit": "s",
}

ram_x = self._pre_circuit()
ram_x.sx(0)
ram_x.delay(p_delay, 0, timing.delay_unit)
ram_x.rz(rotation_angle, 0)
ram_x.sx(0)
ram_x.measure_active()
ram_x.metadata = metadata.copy()

ram_y = self._pre_circuit()
ram_y.sx(0)
ram_y.delay(p_delay, 0, timing.delay_unit)
ram_y.rz(rotation_angle - np.pi / 2, 0)
ram_y.sx(0)
ram_y.measure_active()
ram_y.metadata = metadata.copy()

circs = []
for delay in self.experiment_options.delays:
assigned_x = ram_x.assign_parameters(
{p_delay: timing.round_delay(time=delay)}, inplace=False
)
assigned_x.metadata["series"] = "X"
assigned_x.metadata["xval"] = timing.delay_time(time=delay)

assigned_y = ram_y.assign_parameters(
{p_delay: timing.round_delay(time=delay)}, inplace=False
)
assigned_y.metadata["series"] = "Y"
assigned_y.metadata["xval"] = timing.delay_time(time=delay)
delay_dt = timing.round_delay(time=delay)
delay_sec = timing.delay_time(time=delay)

assigned_x = ram_x.assign_parameters({p_delay: delay_dt}, inplace=False)
assigned_x.metadata = {
"series": "X",
"xval": delay_sec,
}
assigned_y = ram_y.assign_parameters({p_delay: delay_dt}, inplace=False)
assigned_y.metadata = {
"series": "Y",
"xval": delay_sec,
}

circs.extend([assigned_x, assigned_y])

Expand Down
9 changes: 2 additions & 7 deletions qiskit_experiments/library/characterization/readout_angle.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,16 +85,11 @@ def circuits(self) -> List[QuantumCircuit]:
"""
circ0 = QuantumCircuit(1, 1)
circ0.measure(0, 0)
circ0.metadata = {"xval": 0}

circ1 = QuantumCircuit(1, 1)
circ1.x(0)
circ1.measure(0, 0)

for i, circ in enumerate([circ0, circ1]):
circ.metadata = {
"experiment_type": self._type,
"qubit": self.physical_qubits[0],
"xval": i,
}
circ1.metadata = {"xval": 1}

return [circ0, circ1]
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ def circuits(self):

circuit = self._template_circuit()
circuit.add_calibration("measure", self.physical_qubits, sched_)
self._add_metadata(circuit, freq, sched)
self._add_metadata(circuit, freq)

circs.append(circuit)

Expand Down
11 changes: 2 additions & 9 deletions qiskit_experiments/library/characterization/spectroscopy.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

import numpy as np
from qiskit import QuantumCircuit
from qiskit import pulse
from qiskit.exceptions import QiskitError
from qiskit.providers import Backend
from qiskit.qobj.utils import MeasLevel
Expand Down Expand Up @@ -109,19 +108,13 @@ def _backend_center_frequency(self) -> float:
which depends on the nature of the spectroscopy experiment.
"""

def _add_metadata(self, circuit: QuantumCircuit, freq: float, sched: pulse.ScheduleBlock):
def _add_metadata(self, circuit: QuantumCircuit, freq: float):
"""Helper method to add the metadata to avoid code duplication with subclasses."""

if not self._absolute:
freq += self._backend_center_frequency

circuit.metadata = {
"experiment_type": self._type,
"qubits": self.physical_qubits,
"xval": np.round(freq, decimals=3),
"unit": "Hz",
"schedule": str(sched),
}
circuit.metadata = {"xval": np.round(freq, decimals=3)}

def _metadata(self):
metadata = super()._metadata()
Expand Down
7 changes: 1 addition & 6 deletions qiskit_experiments/library/characterization/t1.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,7 @@ def circuits(self) -> List[QuantumCircuit]:
circ.barrier(0)
circ.measure(0, 0)

circ.metadata = {
"experiment_type": self._type,
"qubit": self.physical_qubits[0],
"unit": "s",
}
circ.metadata["xval"] = timing.delay_time(time=delay)
circ.metadata = {"xval": timing.delay_time(time=delay)}

circuits.append(circ)

Expand Down
10 changes: 2 additions & 8 deletions qiskit_experiments/library/characterization/t2hahn.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,18 +131,12 @@ def circuits(self) -> List[QuantumCircuit]:
"""
timing = BackendTiming(self.backend)

template = QuantumCircuit(1, 1)
template.metadata = {
"experiment_type": self._type,
"qubit": self.physical_qubits[0],
"unit": "s",
}

delay_param = Parameter("delay")

num_echoes = self.experiment_options.num_echoes

# First X rotation in 90 degrees
template = QuantumCircuit(1, 1)
template.rx(np.pi / 2, 0) # Brings the qubit to the X Axis
if num_echoes == 0:
# if number of echoes is 0 then just apply the delay gate
Expand Down Expand Up @@ -174,7 +168,7 @@ def circuits(self) -> List[QuantumCircuit]:
assigned = template.assign_parameters(
{delay_param: timing.round_delay(time=single_delay)}, inplace=False
)
assigned.metadata["xval"] = total_delay
assigned.metadata = {"xval": total_delay}
circuits.append(assigned)

return circuits
Expand Down
9 changes: 2 additions & 7 deletions qiskit_experiments/library/characterization/t2ramsey.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,7 @@ def circuits(self) -> List[QuantumCircuit]:
circ.barrier(0)
circ.measure(0, 0)

circ.metadata = {
"experiment_type": self._type,
"qubit": self.physical_qubits[0],
"xval": timing.delay_time(time=delay),
"osc_freq": self.experiment_options.osc_freq,
"unit": "s",
}
circ.metadata = {"xval": timing.delay_time(time=delay)}

circuits.append(circ)

Expand All @@ -144,4 +138,5 @@ def _metadata(self):
for run_opt in ["meas_level", "meas_return"]:
if hasattr(self.run_options, run_opt):
metadata[run_opt] = getattr(self.run_options, run_opt)
metadata["osc_freq"] = self.experiment_options.osc_freq
return metadata
8 changes: 2 additions & 6 deletions qiskit_experiments/library/characterization/zz_ramsey.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,10 +221,6 @@ def _template_circuits(
Returns:
Circuits for series 0 and 1
"""
metadata = {
"unit": "s",
}

delay = Parameter("delay")

timing = BackendTiming(self.backend)
Expand All @@ -244,7 +240,7 @@ def _template_circuits(

# Template circuit for series 0
# Control qubit starting in |0> state, flipping to |1> in middle
circ0 = QuantumCircuit(2, 1, metadata=metadata.copy())
circ0 = QuantumCircuit(2, 1)
circ0.metadata["series"] = "0"

circ0.sx(0)
Expand All @@ -271,7 +267,7 @@ def _template_circuits(

# Template circuit for series 1
# Control qubit starting in |1> state, flipping to |0> in middle
circ1 = QuantumCircuit(2, 1, metadata=metadata.copy())
circ1 = QuantumCircuit(2, 1)
circ1.metadata["series"] = "1"

circ1.x(1)
Expand Down
2 changes: 0 additions & 2 deletions qiskit_experiments/library/quantum_volume/qv_experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,8 @@ def circuits(self) -> List[QuantumCircuit]:
qv_circ = QuantumVolumeCircuit(depth, depth, seed=rng)
qv_circ.measure_active()
qv_circ.metadata = {
"experiment_type": self._type,
"depth": depth,
"trial": trial,
"qubits": self.physical_qubits,
"ideal_probabilities": self._get_ideal_data(qv_circ),
}
circuits.append(qv_circ)
Expand Down
Loading

0 comments on commit 79e0a69

Please sign in to comment.