Skip to content

Commit

Permalink
Add initial support for converting Quil programs into Cirq circuits (#…
Browse files Browse the repository at this point in the history
…3211)

This PR adds Quil import support in a way analogous to the existing QASM import functionality, by leveraging the Quil parser that already exists in pyQuil.

By using `circuit_from_quil` from the `cirq.contrib.quil_import` module, all Quil standard gates, measurements, and simple (non-parameterized) DEFGATEs can be converted to Cirq operations (see below).

Additionally adds Quil output for special cases of `TwoQubitDiagonalGate`, and fixes a bug in the way DEFGATE blocks were being generated by the Quil outputter.

```python
In [1]: from cirq.contrib.quil_import import circuit_from_quil

In [2]: circuit_from_quil("""
   ...: DECLARE ro BIT[3]
   ...: I 0
   ...: I 1
   ...: I 2
   ...: X 0
   ...: Y 1
   ...: Z 2
   ...: H 0
   ...: S 1
   ...: T 2
   ...: PHASE(pi/8) 0
   ...: PHASE(pi/8) 1
   ...: PHASE(pi/8) 2
   ...: RX(pi/2) 0
   ...: RY(pi/2) 1
   ...: RZ(pi/2) 2
   ...: CZ 0 1
   ...: CNOT 1 2
   ...: CPHASE(pi/2) 0 1
   ...: SWAP 1 2
   ...: ISWAP 0 1
   ...: XY(pi/2) 1 2
   ...: CCNOT 0 1 2
   ...: CSWAP 0 1 2
   ...: MEASURE 0 ro[0]
   ...: MEASURE 1 ro[1]
   ...: MEASURE 2 ro[2]
   ...: """)
Out[2]:
0: ───I───X───H───Z^(1/8)───Rx(0.5π)───@───────@───────────iSwap───────────────@───@───M('ro[0]')───
                                       │       │           │                   │   │
1: ───I───Y───S───Z^(1/8)───Ry(0.5π)───@───@───@^0.5───×───iSwap───iSwap───────@───×───M('ro[1]')───
                                           │           │           │           │   │
2: ───I───Z───T───Z^(1/8)───Rz(0.5π)───────X───────────×───────────iSwap^0.5───X───×───M('ro[2]')───

In [3]: circuit_from_quil("""
   ...: DEFGATE MYZ:
   ...:     1,0
   ...:     0,-1
   ...:
   ...: MYZ 0
   ...: """)
Out[3]:
      ┌     ┐
0: ───│ 1  0│───
      │ 0 -1│
      └     ┘
```

Related to #1742, #2386, #2983
  • Loading branch information
karalekas committed Aug 13, 2020
1 parent 193c35d commit 1aabcb7
Show file tree
Hide file tree
Showing 10 changed files with 588 additions and 20 deletions.
12 changes: 6 additions & 6 deletions cirq/circuits/quil_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ def __init__(self, matrix: np.ndarray) -> None:

def _quil_(self, qubits: Tuple['cirq.Qid', ...],
formatter: 'cirq.QuilFormatter') -> str:
return (f'DEFGATE USERGATE:\n\t'
return (f'DEFGATE USERGATE:\n '
f'{to_quil_complex_format(self.matrix[0, 0])}, '
f'{to_quil_complex_format(self.matrix[0, 1])}\n\t'
f'{to_quil_complex_format(self.matrix[0, 1])}\n '
f'{to_quil_complex_format(self.matrix[1, 0])}, '
f'{to_quil_complex_format(self.matrix[1, 1])}\n'
f'{formatter.format("USERGATE {0}", qubits[0])}\n')
Expand Down Expand Up @@ -73,19 +73,19 @@ def _value_equality_values_(self):
def _quil_(self, qubits: Tuple['cirq.Qid', ...],
formatter: 'cirq.QuilFormatter') -> str:
return (
f'DEFGATE USERGATE:\n\t'
f'DEFGATE USERGATE:\n '
f'{to_quil_complex_format(self.matrix[0, 0])}, '
f'{to_quil_complex_format(self.matrix[0, 1])}, '
f'{to_quil_complex_format(self.matrix[0, 2])}, '
f'{to_quil_complex_format(self.matrix[0, 3])}\n\t'
f'{to_quil_complex_format(self.matrix[0, 3])}\n '
f'{to_quil_complex_format(self.matrix[1, 0])}, '
f'{to_quil_complex_format(self.matrix[1, 1])}, '
f'{to_quil_complex_format(self.matrix[1, 2])}, '
f'{to_quil_complex_format(self.matrix[1, 3])}\n\t'
f'{to_quil_complex_format(self.matrix[1, 3])}\n '
f'{to_quil_complex_format(self.matrix[2, 0])}, '
f'{to_quil_complex_format(self.matrix[2, 1])}, '
f'{to_quil_complex_format(self.matrix[2, 2])}, '
f'{to_quil_complex_format(self.matrix[2, 3])}\n\t'
f'{to_quil_complex_format(self.matrix[2, 3])}\n '
f'{to_quil_complex_format(self.matrix[3, 0])}, '
f'{to_quil_complex_format(self.matrix[3, 1])}, '
f'{to_quil_complex_format(self.matrix[3, 2])}, '
Expand Down
81 changes: 71 additions & 10 deletions cirq/circuits/quil_output_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ def test_quil_one_qubit_gate_output():
assert str(output) == """# Created using Cirq.
DEFGATE USERGATE1:
\t1.0+0.0i, 0.0+0.0i
\t0.0+0.0i, 1.0+0.0i
1.0+0.0i, 0.0+0.0i
0.0+0.0i, 1.0+0.0i
USERGATE1 0
"""

Expand All @@ -136,12 +136,12 @@ def test_two_quil_one_qubit_gate_output():
assert str(output) == """# Created using Cirq.
DEFGATE USERGATE1:
\t1.0+0.0i, 0.0+0.0i
\t0.0+0.0i, 1.0+0.0i
1.0+0.0i, 0.0+0.0i
0.0+0.0i, 1.0+0.0i
USERGATE1 0
DEFGATE USERGATE2:
\t2.0+0.0i, 0.0+0.0i
\t0.0+0.0i, 3.0+0.0i
2.0+0.0i, 0.0+0.0i
0.0+0.0i, 3.0+0.0i
USERGATE2 0
"""

Expand All @@ -157,10 +157,10 @@ def test_quil_two_qubit_gate_output():
assert str(output) == """# Created using Cirq.
DEFGATE USERGATE1:
\t1.0+0.0i, 0.0+0.0i, 0.0+0.0i, 0.0+0.0i
\t0.0+0.0i, 1.0+0.0i, 0.0+0.0i, 0.0+0.0i
\t0.0+0.0i, 0.0+0.0i, 1.0+0.0i, 0.0+0.0i
\t0.0+0.0i, 0.0+0.0i, 0.0+0.0i, 1.0+0.0i
1.0+0.0i, 0.0+0.0i, 0.0+0.0i, 0.0+0.0i
0.0+0.0i, 1.0+0.0i, 0.0+0.0i, 0.0+0.0i
0.0+0.0i, 0.0+0.0i, 1.0+0.0i, 0.0+0.0i
0.0+0.0i, 0.0+0.0i, 0.0+0.0i, 1.0+0.0i
USERGATE1 0 1
"""

Expand Down Expand Up @@ -378,3 +378,64 @@ def test_equivalent_unitaries():
cirq_unitary = cirq.Circuit(cirq.SWAP(q0, q1), operations,
cirq.SWAP(q0, q1)).unitary()
assert np.allclose(pyquil_unitary, cirq_unitary)


QUIL_CPHASES_PROGRAM = """
CPHASE00(pi/2) 0 1
CPHASE01(pi/2) 0 1
CPHASE10(pi/2) 0 1
CPHASE(pi/2) 0 1
"""

QUIL_DIAGONAL_DEFGATE_PROGRAM = """
DEFGATE USERGATE1:
1.0, 0.0, 0.0, 0.0
0.0, 1.0, 0.0, 0.0
0.0, 0.0, 1.0, 0.0
0.0, 0.0, 0.0, 1.0
USERGATE1 0 1
"""


def test_two_qubit_diagonal_gate_quil_output():
pyquil = pytest.importorskip("pyquil")
pyquil_simulation_tools = pytest.importorskip("pyquil.simulation.tools")
q0, q1 = _make_qubits(2)
operations = [
cirq.TwoQubitDiagonalGate([np.pi / 2, 0, 0, 0])(q0, q1),
cirq.TwoQubitDiagonalGate([0, np.pi / 2, 0, 0])(q0, q1),
cirq.TwoQubitDiagonalGate([0, 0, np.pi / 2, 0])(q0, q1),
cirq.TwoQubitDiagonalGate([0, 0, 0, np.pi / 2])(q0, q1),
]
output = cirq.QuilOutput(operations, (q0, q1))
program = pyquil.Program(str(output))
assert f"\n{program.out()}" == QUIL_CPHASES_PROGRAM

pyquil_unitary = pyquil_simulation_tools.program_unitary(program,
n_qubits=2)
# Qubit ordering differs between pyQuil and Cirq.
cirq_unitary = cirq.Circuit(cirq.SWAP(q0, q1), operations,
cirq.SWAP(q0, q1)).unitary()
assert np.allclose(pyquil_unitary, cirq_unitary)
# Also test non-CPHASE case.
operations = [
cirq.TwoQubitDiagonalGate([0, 0, 0, 0])(q0, q1),
]
output = cirq.QuilOutput(operations, (q0, q1))
program = pyquil.Program(str(output))
assert f"\n{program.out()}" == QUIL_DIAGONAL_DEFGATE_PROGRAM


def test_parseable_defgate_output():
pyquil = pytest.importorskip("pyquil")
q0, q1 = _make_qubits(2)
operations = [
QuilOneQubitGate(np.array([[1, 0], [0, 1]])).on(q0),
QuilTwoQubitGate(
np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0],
[0, 0, 0, 1]])).on(q0, q1)
]
output = cirq.QuilOutput(operations, (q0, q1))
# Just checks that we can create a pyQuil Program without crashing.
pyquil.Program(str(output))
5 changes: 4 additions & 1 deletion cirq/contrib/contrib-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@ pylatex~=1.3.0
# quimb
quimb
opt_einsum
autoray
autoray

# quil import
pyquil~=2.21.0
15 changes: 15 additions & 0 deletions cirq/contrib/quil_import/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2020 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.

from cirq.contrib.quil_import.quil import circuit_from_quil

0 comments on commit 1aabcb7

Please sign in to comment.