Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[WIP] Layer Fidelity Extensions #1517

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ def __init__(
seed: Optional[Union[int, SeedSequence, BitGenerator, Generator]] = None,
two_qubit_gate: Optional[str] = None,
one_qubit_basis_gates: Optional[Sequence[str]] = None,
layer_barrier: Optional[bool] = True,
min_delay: Optional[Sequence[int]] = None
):
"""Initialize a layer fidelity experiment.

Expand All @@ -150,6 +152,10 @@ def __init__(
one_qubit_basis_gates: Optional, 1q-gates to use for implementing 1q-Clifford operations.
If not specified (but ``backend`` is supplied),
all 1q-gates supported in the backend are automatically set.
layer_barrier: Optional, enforce a barrier across the whole layer. Default is True
which is the defined protocol for layer. But can be set to false for testing.
min_delay: Option. Define a minimum delay in each layer in units of dt. This
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the motivation for using min_delay? Maybe more description here would help? It adds some extra delay after all the 2q gates for debugging of some duration effect? It seems like does not work well with layer_barrier=False?

delay operation will be applied in any 1Q edge of the layer.
Comment on lines +155 to +158
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
layer_barrier: Optional, enforce a barrier across the whole layer. Default is True
which is the defined protocol for layer. But can be set to false for testing.
min_delay: Option. Define a minimum delay in each layer in units of dt. This
delay operation will be applied in any 1Q edge of the layer.
layer_barrier: Optional, enforce a barrier across the whole layer. Default is True
which is the defined protocol for layer. But can be set to false for testing.
min_delay: Option. Define a minimum delay in each layer in units of dt. This
delay operation will be applied in any 1Q edge of the layer.


Raises:
QiskitError: If any invalid argument is supplied.
Expand Down Expand Up @@ -225,6 +231,10 @@ def __init__(
# Verify two_qubit_gate and one_qubit_basis_gates
self.__validate_basis_gates()

#optional items for the circuit generation
self.layer_barrier = layer_barrier
self.min_delay = min_delay
Comment on lines +234 to +236
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should probably be experiment options like lengths, seed, etc.


@classmethod
def _default_experiment_options(cls) -> Options:
"""Default experiment options.
Expand Down Expand Up @@ -371,9 +381,25 @@ def circuits_generator(self) -> Iterable[QuantumCircuit]:
composite_clbits.extend(
[(c,) for c in range(2 * num_2q_gates, 2 * num_2q_gates + num_1q_gates)]
)

if self.min_delay is None:
min_delay = None
else:
min_delay = self.min_delay[i_set]

for length in opts.lengths:
circ = QuantumCircuit(num_qubits, num_qubits)
#define the barrier instruction
barrier_inst = CircuitInstruction(Barrier(num_qubits), circ.qubits)
if not self.layer_barrier:
#we want separate barriers for each qubit so define them individually
barrier_inst_gate = []
for two_q_gate in two_qubit_layer:
barrier_inst_gate.append(CircuitInstruction(Barrier(2), [circ.qubits[two_q_gate[0]],circ.qubits[two_q_gate[1]]]))
for one_q in one_qubits:
barrier_inst_gate.append(CircuitInstruction(Barrier(1), [circ.qubits[one_q]]))
else:
barrier_inst_gate = [barrier_inst]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor -- barrier_inst vs barrier_inst_gate is a little confusing. Maybe barriest_inst could be something like full_barrier?

self.__circuit_body(
circ,
length,
Expand All @@ -384,7 +410,8 @@ def circuits_generator(self) -> Iterable[QuantumCircuit]:
_to_gate_2q,
gate2q,
gate2q_cliff,
barrier_inst,
barrier_inst_gate,
min_delay
)
# add the measurements
circ._append(barrier_inst)
Expand Down Expand Up @@ -434,7 +461,8 @@ def __circuit_body(
_to_gate_2q,
gate2q,
gate2q_cliff,
barrier_inst,
barrier_inst_lst,
min_delay=None
):
# initialize cliffords and a ciruit (0: identity clifford)
cliffs_2q = [0] * len(two_qubit_layer)
Expand All @@ -454,16 +482,21 @@ def __circuit_body(
sample = rng.integers(NUM_1Q_CLIFFORD)
cliffs_1q[k] = compose_1q(cliffs_1q[k], sample)
circ._append(_to_gate_1q(sample), (circ.qubits[q],), ())
circ._append(barrier_inst)
for barrier_inst in barrier_inst_lst:
circ._append(barrier_inst)
# add two qubit gates
for j, qpair in enumerate(two_qubit_layer):
circ._append(gate2q, tuple(circ.qubits[q] for q in qpair), ())
cliffs_2q[j] = compose_2q(cliffs_2q[j], gate2q_cliff)
# TODO: add dd if necessary
for k, q in enumerate(one_qubits):
# TODO: add dd if necessary
pass
circ._append(barrier_inst)
#if there is a min_delay, just need
#to add to one of the qubits
if min_delay is not None and k==0:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if you have physical_qubits=[0, 1, 2, 3] and two_qubit_layers=[[(0, 1), (2, 3)]]? Won't one_qubits be empty and min_delay silently ignored?

circ.delay(min_delay,q)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks weird now to loop over a list and then only do something for the first item instead of something like if min_delay and one_qubits: circ.delay(min_delay, one_qubits[0]) but I guess the loop is there for adding DD.

for barrier_inst in barrier_inst_lst:
circ._append(barrier_inst)
# add the last inverse
for j, qpair in enumerate(two_qubit_layer):
inv = inverse_2q(cliffs_2q[j])
Expand Down
Loading