Add a barrier operation for controlling transformations and optimizations of circuits
Is your feature request related to a use case or problem? Please explain
A barrier is an identity operation, equivalent to barrier_op = cirq.identity_each(*all_qubits), that serves as a directive for circuit compilation. Its main use is to separate pieces of a circuit, ensuring that any transformers, compiling processing and optimizers are restricted to only operate between barriers and not across them.
We've encountered a problem where applying transformations like cirq.merge_single_qubit_gates_to_phxz and cirq.stratified_circuit to an entire circuit can cause unwanted shifting of larger blocks (e.g., triangular blocks) within the circuit, even when the intention is to only affect specific initial moments. A barrier would prevent such unintended transformations from crossing a specified point in the circuit, allowing for more precise control over optimizations.
It is an extremely generally applicable tool for shaping experimental circuits into desired structure. This comes up in Trotter and many other contexts.
Describe the solution you would prefer
We would prefer a mechanism, similar to a "barrier" operation, that can be inserted into a cirq.Circuit. This barrier operation would act as a compile-time directive, preventing circuit transformations and optimizations from operating across it. Essentially, it would delineate sections of the circuit, ensuring that any re-writes or optimizations are confined to the gates within a given section, without affecting gates on the other side of the barrier.
There have been a discussions over time on this issue here.
How urgent is this for you? Is it blocking important work?
P1 – I need this no later than the next release
Describe alternatives/workarounds you've considered
One workaround we've considered is manually splitting the circuit into segments, applying transformations to the desired prefix, and then re-combining the circuits. For example:
qc = original_circuit[:k] # prefix circuit
qc = cirq.merge_single_qubit_gates_to_phxz(qc)
qc = cirq.stratified_circuit(
qc, categories=[lambda op: cirq.num_qubits(op) == k for k in (1, 2)]
)
final_circuit = qc + original_circuit[k:]
This only works based on many assumptions and will require assertion tests, etc. and is not generalizable.
@zlatko-minev Thank you for reporting this. Could I ask you to rewrite the title to describe more clearly what exactly the issue or feature request is? For maintainers and contributors, it's easier to figure out what an issue is about when the title is descriptive (but concise).
This Barrier implementation should address the issue. We can move it to Cirq.
Thanks, @vtomole , does this implementation allow you to have the barrier stop merging and moving of single qubit gates across it when using things like merge single qubit layers or align left, etc.?
Yep! Since it's an identity gate, we have our internal transformers recognize it to decide which parts to merge, align e.t.c and which parts to leave alone.
@zlatko-minev Do you want to come to cirq-cync today to discuss this proposal?
@dstrain115 I would love to come to the cync to discuss this as well but i'm blocked at those times these days. I'll look at the notes 😸 . We've had barrier discussions in the past: https://github.com/quantumlib/Cirq/issues/2642
@vtomole Thank you for referencing that past discussion – that was very helpful!
In reading #2642 and following the other links there, it looks like the approach of using tags for barriers was never followed through, although tags were added. Is that correct? (Searching the codebase for "barrier" didn't turn up any hits either.)
It also looks like your implementation in https://github.com/Infleqtion/client-superstaq/blob/fc43e01600a8fd9e98079dd7c6406d21a2b67fae/cirq-superstaq/cirq_superstaq/ops/qubit_gates.py#L408 does not rely on tags. Is that correct?
Just for better understanding, could you explain a little bit about the reason for not using tags in this? (Not questioning the validity of the choice at all, just trying to understand the pros & cons.)
Unrelated to the previous comment: for anyone reading this and interested in knowing more about barriers, there's a nice explanation in this answer to a question in the Quantum Computing Stack Exchange – the answer was edited by our very own @viathor .
Discussed in Cirq Cynq 2025-08-06:
- Some questions arose about behavior in the context of Moments
- Concerned that this affects transformers, simulators, and probably also cirq-google serialization.
- Need to work out the possible interations with these other elements in Cirq.
@ACE07-Sev per discussion in Cirq Cynq, assigning to you because of your interest in taking this on.
@zlatko-minev I'll follow up with info about the RFC template with the both of you.
Something I think could be an avenue for this feature is to check if a circuit has barriers, and if so, break the circuit into smaller circuits based on the barriers, and apply transformations on each chunk, and later compose them together.
This simplifies the logic, makes it easier to implement, but would depend on how efficient circuit composition is in cirq. Additionally, also whether this is what is intended or not logically speaking.
Yes, that could work well with barriers that act on all qubits.For barriers that do not act on all qubits, you would need a second stageOn Aug 7, 2025, at 6:26 AM, A.C.E07 @.***> wrote:ACE07-Sev left a comment (quantumlib/Cirq#7534) Something I think could be an avenue for this feature is to check if a circuit has barriers, and if so, break the circuit into smaller circuits based on the barriers, and apply transformations on each chunk, and later compose them together. This simplifies the logic, makes it easier to implement, but would depend on how efficient circuit composition is in cirq. Additionally, also whether this is what is intended or not.
—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you were mentioned.Message ID: @.***>
It also looks like your implementation in https://github.com/Infleqtion/client-superstaq/blob/fc43e01600a8fd9e98079dd7c6406d21a2b67fae/cirq-superstaq/cirq_superstaq/ops/qubit_gates.py#L408 does not rely on tags. Is that correct?
Correct.
Could you explain a little bit about the reason for not using tags in this?
AFAIK, tags completely ignore optimizations. I want to optimize the circuit, I just don't want to do it across the barriers. For example, the below code is an illustation of how I would want to combine 4 rx gates in sets of 2 instead of 1 big rx gate. A barrier with 2 rx gates to the left of it and 2 rx gates to the right will do what I want, but tags will not.
import cirq
import numpy as np
import cirq_superstaq as css
service = css.Service()
q = cirq.LineQubit(0)
c = cirq.Circuit(
cirq.rx(np.pi / 2).on(q),
cirq.rx(np.pi / 2).on(q),
cirq.rx(np.pi / 2).on(q).with_tags("ignore"),
cirq.rx(np.pi / 2).on(q),
)
context = cirq.TransformerContext(tags_to_ignore=["ignore"], deep=False)
optimized = cirq.merge_single_qubit_gates_to_phased_x_and_z(c, context=context)
print(optimized)
# prints
# 0: ───PhX(0)───Rx(0.5π)[ignore]───PhX(0)^0.5───
c1 = cirq.Circuit(
cirq.rx(np.pi / 2).on(q),
cirq.rx(np.pi / 2).on(q),
css.Barrier(num_qubits=1).on(q),
cirq.rx(np.pi / 2).on(q),
cirq.rx(np.pi / 2).on(q),
)
compiler_output = service.qscout_compile(c1)
output_circuit = compiler_output.circuit
print(output_circuit)
# prints
# 0: ───PhX(1.0)───│───PhX(1.0)───
Greetings all,
Hope all are well. Just rotating to this as per my schedule, may I ask if the RFC is done @mhucka sir?
@zlatko-minev What would be the desired behavior if a 2-qubit circuit has a barrier on the first qubit but not the second, and you ran the merge_k_qubit_unitaries(k=2) transformer? I can think of three possibilities.
- It stops entirely when it encounters the barrier.
- It changes to a
merge_1_qubit_unitariesand continues on the second qubit only. - It stays a 2-qubit transformer, but only on the second qubit. So any gates that include q2 would continue to be merged (meaning gates on [q1, q2] or on [q2]), but single-qubit gates on q1 alone would not be merged.
Do you think it would be consistent across transformers, or could different transformers have different preferred ways of handling it? align_left may be another interesting edge case to explore, and also raises the question, would the barrier itself get shifted left? And if so, would the operations on q1 after the barrier remain at the same absolute moment, or get shifted to remain at the same distance relative to the barrier?
TODO @mhucka - please link the RFC here
Link to RFC: https://tinyurl.com/rfc-cirq-barrier-operation
TODO - let us converge on the RFC and present it to a broader group at cirq cynq
Status update:
- Some questions have been posed on the RFC document. The author has replied to some, and that is great to see. There are still a couple not answered.
- The Cirq approach for resolving remaining questions on RFCs and reaching closure has not been written down in great detail (beyond stating that a review committee will come to a consensus). Until we get a different scheme in place, I propose that we use this GitHub issue to track questions and their status.
- The next is therefore for someone (probably me) to collect a list of remaining questions and add them here, then seek replies from the RFC author.
We don't have cinq today, correct?