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

Support for adding barriers and delays to Circuit #974

Closed
rmshaffer opened this issue May 9, 2024 · 5 comments · Fixed by #993 · May be fixed by #1002
Closed

Support for adding barriers and delays to Circuit #974

rmshaffer opened this issue May 9, 2024 · 5 comments · Fixed by #993 · May be fixed by #1002
Assignees
Labels
enhancement New feature or request good first issue Good for newcomers

Comments

@rmshaffer
Copy link
Contributor

rmshaffer commented May 9, 2024

Describe the feature you'd like

Users should be able to add barriers and delays to Circuit objects using the same syntax as gates.

Implementing barrier and delay instructions should involve minimal complexity. OpenQASM supports both the barrier and delay instructions at the program level, so we could simply add these instructions in global scope in the resulting OpenQASM program.

For example, the code may look like:

circ = Circuit().x(0).barrier([0, 1]).x(0).delay(0, 1e-6)
print(circ)

which would output something like:

T  : |0|1|2|     3     |
                     
q0 : -X-|-X-delay(1e-6)-
        |            
q1 : ---|---------------

T  : |0|1|2|     3     |

How would this feature be used? Please describe.

The barrier and delay instructions are useful when precise timing of quantum operations is needed within a program. One example is in #417, where the time of measurement needs to be determined precisely.

Describe alternatives you've considered

Today, the Braket service supports barrier and delay as OpenPulse instructions, which is a workaround for achieving this functionality. For example, the program below contains a barrier on qubits $0 and $1 inside a cal block:

program = Program(source="""OPENQASM 3.0;
bit[1] b;
x $0;
cal {
    waveform t = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    play(q0_drive, t);
    barrier $0, $1;
}
b[0] = measure $0;
""")
@rmshaffer rmshaffer added enhancement New feature or request good first issue Good for newcomers labels May 9, 2024
@rmshaffer
Copy link
Contributor Author

rmshaffer commented May 21, 2024

An implementation of Barrier would probably look something like this:

from braket.circuits import Gate, Instruction, circuit

class Barrier(Gate):
    def __init__(self, qubit_count):
        super().__init__(qubit_count=qubit_count, ascii_symbols=[f"||" for i in range(qubit_count)])

    def bind_values(self, **kwargs):
        raise NotImplementedError

    @property
    def _qasm_name(self):
        return f"barrier"

    def __hash__(self):
        return hash((self.name, self.qubit_count, self.qubit_count))

    @staticmethod
    @circuit.subroutine(register=True)
    def barrier(target):
        return Instruction(Barrier(len(target)), target=target)

Gate.register_gate(Barrier)

Example usage of Barrier would then look like:

from braket.circuits import Circuit

circ = Circuit().barrier([0,1,2])
print(circ.to_ir("OPENQASM").source)

which would output:

OPENQASM 3.0;
bit[3] b;
qubit[3] q;
barrier q[0], q[1], q[2];
b[0] = measure q[0];
b[1] = measure q[1];
b[2] = measure q[2];

An implementation of Delay would look similar, except that it would also take a parameter representing the duration of the delay.

@Manvi-Agrawal
Copy link

@rmshaffer I would like to work on this issue

@Manvi-Agrawal
Copy link

@rmshaffer could you please look at PR #980. Is it okay to have a delay gate that supports delay in ns or do we want to support more units like dt?

@rmshaffer
Copy link
Contributor Author

@rmshaffer could you please look at PR #980. Is it okay to have a delay gate that supports delay in ns or do we want to support more units like dt?

Reviewing now. To answer your question here, we should specify delay in seconds to be consistent with the existing pulse API for delay:

def delay(
self,
qubits_or_frames: Union[Frame, list[Frame], QubitSet],
duration: Union[float, FreeParameterExpression],
) -> PulseSequence:
"""Adds an instruction to advance the frame clock by the specified `duration` value.
Args:
qubits_or_frames (Union[Frame, list[Frame], QubitSet]): Qubits or frame(s) on which
the delay needs to be introduced.
duration (Union[float, FreeParameterExpression]): value (in seconds) defining
the duration of the delay.
Returns:
PulseSequence: self, with the instruction added.
"""

@rmshaffer
Copy link
Contributor Author

Closing this unitaryHACK issue, since the changes have been merged into a feature branch. Thank you @Manvi-Agrawal for your contribution! 🥳

PR #1002 has been opened to track the remaining changes to merge this feature to main.

@rmshaffer rmshaffer linked a pull request Jun 17, 2024 that will close this issue
8 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment