Skip to content

Commit

Permalink
Add align_left/align_right transformers to replace AlignLeft/`A…
Browse files Browse the repository at this point in the history
…lignRight` (#4891)

* Add / to replace /

* Make context an optional parameter with default value None
  • Loading branch information
tanujkhattar authored Jan 28, 2022
1 parent fdf85f0 commit 4d445c4
Show file tree
Hide file tree
Showing 9 changed files with 193 additions and 13 deletions.
2 changes: 2 additions & 0 deletions cirq-core/cirq/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,8 @@
)

from cirq.transformers import (
align_left,
align_right,
compute_cphase_exponents_for_fsim_decomposition,
decompose_clifford_tableau_to_operations,
decompose_cphase_into_two_fsim,
Expand Down
2 changes: 2 additions & 0 deletions cirq-core/cirq/optimizers/align_left.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@

from cirq import circuits
from cirq.circuits.insert_strategy import InsertStrategy
from cirq._compat import deprecated_class


@deprecated_class(deadline='v1.0', fix='Use cirq.align_left(circuit, context) instead.')
class AlignLeft:
"""Aligns gates to the left of the circuit."""

Expand Down
7 changes: 4 additions & 3 deletions cirq-core/cirq/optimizers/align_left_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@


def assert_optimizes(before, after):
opt = cirq.AlignLeft()
opt(before)
assert before == after
with cirq.testing.assert_deprecated("Use cirq.align_left", deadline='v1.0'):
opt = cirq.AlignLeft()
opt(before)
assert before == after


def test_align_left():
Expand Down
2 changes: 2 additions & 0 deletions cirq-core/cirq/optimizers/align_right.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@

from cirq import circuits
from cirq.circuits.insert_strategy import InsertStrategy
from cirq._compat import deprecated_class


@deprecated_class(deadline='v1.0', fix='Use cirq.align_right(circuit, context) instead')
class AlignRight:
"""Aligns gates to the right of the circuit."""

Expand Down
7 changes: 4 additions & 3 deletions cirq-core/cirq/optimizers/align_right_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@


def assert_optimizes(before, after):
opt = cirq.AlignRight()
opt(before)
assert before == after
with cirq.testing.assert_deprecated("Use cirq.align_right", deadline='v1.0'):
opt = cirq.AlignRight()
opt(before)
assert before == after


def test_align_right():
Expand Down
2 changes: 2 additions & 0 deletions cirq-core/cirq/transformers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
two_qubit_gate_product_tabulation,
)

from cirq.transformers.align import align_left, align_right

from cirq.transformers.transformer_api import (
LogLevel,
TRANSFORMER,
Expand Down
73 changes: 73 additions & 0 deletions cirq-core/cirq/transformers/align.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Copyright 2022 The Cirq Developers
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Transformer passes which align operations to the left or right of the circuit."""

from typing import Optional, TYPE_CHECKING
from cirq import circuits, ops
from cirq.transformers import transformer_api

if TYPE_CHECKING:
import cirq


@transformer_api.transformer
def align_left(
circuit: 'cirq.AbstractCircuit', *, context: Optional['cirq.TransformerContext'] = None
) -> 'cirq.Circuit':
"""Align gates to the left of the circuit.
Note that tagged operations with tag in `context.ignore_tags` will continue to stay in their
original position and will not be aligned.
Args:
circuit: Input circuit to transform.
context: `cirq.TransformerContext` storing common configurable options for transformers.
Returns:
Copy of the transformed input circuit.
"""
if context is None:
context = transformer_api.TransformerContext()

ret = circuits.Circuit()
for i, moment in enumerate(circuit):
for op in moment:
if isinstance(op, ops.TaggedOperation) and set(op.tags).intersection(
context.ignore_tags
):
ret.append([ops.Moment()] * (i + 1 - len(ret)))
ret[i] = ret[i].with_operation(op)
else:
ret.append(op)
return ret


@transformer_api.transformer
def align_right(
circuit: 'cirq.AbstractCircuit', *, context: Optional['cirq.TransformerContext'] = None
) -> 'cirq.Circuit':
"""Align gates to the right of the circuit.
Note that tagged operations with tag in `context.ignore_tags` will continue to stay in their
original position and will not be aligned.
Args:
circuit: Input circuit to transform.
context: `cirq.TransformerContext` storing common configurable options for transformers.
Returns:
Copy of the transformed input circuit.
"""
return align_left(circuit[::-1], context=context)[::-1]
99 changes: 99 additions & 0 deletions cirq-core/cirq/transformers/align_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Copyright 2022 The Cirq Developers
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import cirq


def test_align_basic_no_context():
q1 = cirq.NamedQubit('q1')
q2 = cirq.NamedQubit('q2')
c = cirq.Circuit(
[
cirq.Moment([cirq.X(q1)]),
cirq.Moment([cirq.Y(q1), cirq.X(q2)]),
cirq.Moment([cirq.X(q1)]),
]
)
cirq.testing.assert_same_circuits(
cirq.align_left(c),
cirq.Circuit(
cirq.Moment([cirq.X(q1), cirq.X(q2)]),
cirq.Moment([cirq.Y(q1)]),
cirq.Moment([cirq.X(q1)]),
),
)
cirq.testing.assert_same_circuits(
cirq.align_right(c),
cirq.Circuit(
cirq.Moment([cirq.X(q1)]),
cirq.Moment([cirq.Y(q1)]),
cirq.Moment([cirq.X(q1), cirq.X(q2)]),
),
)


def test_align_left_no_compile_context():
q1 = cirq.NamedQubit('q1')
q2 = cirq.NamedQubit('q2')
cirq.testing.assert_same_circuits(
cirq.align_left(
cirq.Circuit(
[
cirq.Moment([cirq.X(q1)]),
cirq.Moment([cirq.Y(q1), cirq.X(q2)]),
cirq.Moment([cirq.X(q1), cirq.Y(q2).with_tags("nocompile")]),
cirq.Moment([cirq.Y(q1)]),
cirq.measure(*[q1, q2], key='a'),
]
),
context=cirq.TransformerContext(ignore_tags=["nocompile"]),
),
cirq.Circuit(
[
cirq.Moment([cirq.X(q1), cirq.X(q2)]),
cirq.Moment([cirq.Y(q1)]),
cirq.Moment([cirq.X(q1), cirq.Y(q2).with_tags("nocompile")]),
cirq.Moment([cirq.Y(q1)]),
cirq.measure(*[q1, q2], key='a'),
]
),
)


def test_align_right_no_compile_context():
q1 = cirq.NamedQubit('q1')
q2 = cirq.NamedQubit('q2')
cirq.testing.assert_same_circuits(
cirq.align_right(
cirq.Circuit(
[
cirq.Moment([cirq.X(q1)]),
cirq.Moment([cirq.Y(q1), cirq.X(q2).with_tags("nocompile")]),
cirq.Moment([cirq.X(q1), cirq.Y(q2)]),
cirq.Moment([cirq.Y(q1)]),
cirq.measure(*[q1, q2], key='a'),
]
),
context=cirq.TransformerContext(ignore_tags=["nocompile"]),
),
cirq.Circuit(
[
cirq.Moment([cirq.X(q1)]),
cirq.Moment([cirq.Y(q1), cirq.X(q2).with_tags("nocompile")]),
cirq.Moment([cirq.X(q1)]),
cirq.Moment([cirq.Y(q1), cirq.Y(q2)]),
cirq.measure(*[q1, q2], key='a'),
]
),
)
12 changes: 5 additions & 7 deletions docs/tutorials/google/spin_echoes.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@
"\n",
" # Alignment.\n",
" if with_alignment:\n",
" cirq.AlignRight().optimize_circuit(circuit)\n",
" circuit = cirq.align_right(circuit)\n",
" cirq.SynchronizeTerminalMeasurements().optimize_circuit(circuit)\n",
"\n",
" return circuit\n",
Expand Down Expand Up @@ -760,7 +760,7 @@
"id": "q66K76iTG23G"
},
"source": [
"To align gates into moments and push them as far left as possible, use `cirq.AlignLeft`."
"To align gates into moments and push them as far left as possible, use `cirq.align_left`."
]
},
{
Expand Down Expand Up @@ -809,8 +809,7 @@
}
],
"source": [
"left_aligned_circuit = circuit.copy()\n",
"cirq.AlignLeft().optimize_circuit(left_aligned_circuit)\n",
"left_aligned_circuit = cirq.align_left(circuit)\n",
"left_aligned_circuit"
]
},
Expand Down Expand Up @@ -859,7 +858,7 @@
"id": "v7VhDhlOHQuQ"
},
"source": [
"You can also align gates and push them to the right with `cirq.AlignRight`."
"You can also align gates and push them to the right with `cirq.align_right`."
]
},
{
Expand Down Expand Up @@ -908,8 +907,7 @@
}
],
"source": [
"right_aligned_circuit = circuit.copy()\n",
"cirq.AlignRight().optimize_circuit(right_aligned_circuit)\n",
"right_aligned_circuit = cirq.align_right(circuit)\n",
"right_aligned_circuit"
]
},
Expand Down

0 comments on commit 4d445c4

Please sign in to comment.