Skip to content

Make xmon gates parameterizable #427

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

Merged
merged 4 commits into from
May 30, 2018
Merged
Show file tree
Hide file tree
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
30 changes: 27 additions & 3 deletions cirq/google/xmon_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ class Exp11Gate(XmonGate,
ops.TextDiagrammableGate,
ops.InterchangeableQubitsGate,
ops.PhaseableGate,
ops.ParameterizableGate,
PotentialImplementation):
"""A two-qubit interaction that phases the amplitude of the 11 state.

Expand Down Expand Up @@ -160,7 +161,7 @@ def text_diagram_wire_symbols(self,
qubit_count=None,
use_unicode_characters=True,
precision=3):
return 'Z', 'Z'
return '@', 'Z'

def text_diagram_exponent(self):
return self.half_turns
Expand All @@ -183,14 +184,21 @@ def __ne__(self, other):
return not self == other

def __hash__(self):
return hash((ops.Rot11Gate, self.half_turns))
return hash((Exp11Gate, self.half_turns))

def is_parameterized(self) -> bool:
return isinstance(self.half_turns, Symbol)

def with_parameters_resolved_by(self, param_resolver) -> 'Exp11Gate':
return Exp11Gate(half_turns=param_resolver.value_of(self.half_turns))


class ExpWGate(XmonGate,
ops.SingleQubitGate,
ops.TextDiagrammableGate,
ops.PhaseableGate,
ops.BoundedEffectGate,
ops.ParameterizableGate,
PotentialImplementation):
"""A rotation around an axis in the XY plane of the Bloch sphere.

Expand Down Expand Up @@ -325,10 +333,20 @@ def __hash__(self):
return hash((ops.RotYGate, self.half_turns))
return hash((ExpWGate, self.half_turns, self.axis_half_turns))

def is_parameterized(self) -> bool:
return (isinstance(self.half_turns, Symbol) or
isinstance(self.axis_half_turns, Symbol))

def with_parameters_resolved_by(self, param_resolver) -> 'ExpWGate':
return ExpWGate(
half_turns=param_resolver.value_of(self.half_turns),
axis_half_turns=param_resolver.value_of(self.axis_half_turns))


class ExpZGate(XmonGate,
ops.SingleQubitGate,
ops.TextDiagrammableGate,
ops.ParameterizableGate,
PotentialImplementation):
"""A rotation around the Z axis of the Bloch sphere.

Expand Down Expand Up @@ -384,7 +402,7 @@ def has_matrix(self):
def matrix(self):
if not self.has_matrix():
raise ValueError("Don't have a known matrix.")
return ops.RotZGate(half_turns=self.half_turns).matrix()
return np.diag([(-1j)**self.half_turns, 1j**self.half_turns])

def trace_distance_bound(self):
if isinstance(self.half_turns, Symbol):
Expand Down Expand Up @@ -427,6 +445,12 @@ def __ne__(self, other):
def __hash__(self):
return hash((ExpZGate, self.half_turns))

def is_parameterized(self) -> bool:
return isinstance(self.half_turns, Symbol)

def with_parameters_resolved_by(self, param_resolver) -> 'ExpZGate':
return ExpZGate(half_turns=param_resolver.value_of(self.half_turns))


def _canonicalize_half_turns(
half_turns: Union[Symbol, float]
Expand Down
52 changes: 48 additions & 4 deletions cirq/google/xmon_gates_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import pytest
import numpy as np
from google.protobuf import message, text_format

from cirq.api.google.v1 import operations_pb2
Expand All @@ -20,6 +21,7 @@
XmonGate, XmonQubit, XmonMeasurementGate, ExpZGate, Exp11Gate, ExpWGate,
)
from cirq.ops import KnownMatrixGate, ReversibleGate
from cirq.study import ParamResolver
from cirq.value import Symbol
from cirq.testing import EqualsTester

Expand Down Expand Up @@ -127,6 +129,27 @@ def test_z_to_proto():
""")


def test_z_matrix():
assert np.allclose(ExpZGate(half_turns=1).matrix(),
np.array([[-1j, 0], [0, 1j]]))
assert np.allclose(ExpZGate(half_turns=0.5).matrix(),
np.array([[1 - 1j, 0], [0, 1 + 1j]]) / np.sqrt(2))
assert np.allclose(ExpZGate(half_turns=0).matrix(),
np.array([[1, 0], [0, 1]]))
assert np.allclose(ExpZGate(half_turns=-0.5).matrix(),
np.array([[1 + 1j, 0], [0, 1 - 1j]]) / np.sqrt(2))


def test_z_parameterize():
parameterized_gate = ExpZGate(half_turns=Symbol('a'))
assert parameterized_gate.is_parameterized()
with pytest.raises(ValueError):
_ = parameterized_gate.matrix()
resolver = ParamResolver({'a': 0.1})
resolved_gate = parameterized_gate.with_parameters_resolved_by(resolver)
assert resolved_gate == ExpZGate(half_turns=0.1)


def test_cz_eq():
eq = EqualsTester()
eq.make_equality_pair(lambda: Exp11Gate(half_turns=0))
Expand Down Expand Up @@ -179,6 +202,22 @@ def test_cz_to_proto():
""")


def test_cz_potential_implementation():
ex = Extensions()
assert not ex.can_cast(Exp11Gate(half_turns=Symbol('a')), KnownMatrixGate)
assert ex.can_cast(Exp11Gate(), KnownMatrixGate)


def test_cz_parameterize():
parameterized_gate = Exp11Gate(half_turns=Symbol('a'))
assert parameterized_gate.is_parameterized()
with pytest.raises(ValueError):
_ = parameterized_gate.matrix()
resolver = ParamResolver({'a': 0.1})
resolved_gate = parameterized_gate.with_parameters_resolved_by(resolver)
assert resolved_gate == Exp11Gate(half_turns=0.1)


def test_w_eq():
eq = EqualsTester()
eq.add_equality_group(ExpWGate(),
Expand Down Expand Up @@ -270,7 +309,12 @@ def test_w_potential_implementation():
assert ex.can_cast(ExpWGate(), ReversibleGate)


def test_cz_potential_implementation():
ex = Extensions()
assert not ex.can_cast(Exp11Gate(half_turns=Symbol('a')), KnownMatrixGate)
assert ex.can_cast(Exp11Gate(), KnownMatrixGate)
def test_w_parameterize():
parameterized_gate = ExpWGate(half_turns=Symbol('a'),
axis_half_turns=Symbol('b'))
assert parameterized_gate.is_parameterized()
with pytest.raises(ValueError):
_ = parameterized_gate.matrix()
resolver = ParamResolver({'a': 0.1, 'b': 0.2})
resolved_gate = parameterized_gate.with_parameters_resolved_by(resolver)
assert resolved_gate == ExpWGate(half_turns=0.1, axis_half_turns=0.2)
3 changes: 0 additions & 3 deletions cirq/ops/gate_features.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,4 @@ def with_parameters_resolved_by(self,

Returns a gate of the same type, but with all Symbols replaced with
floats according to the given ParamResolver.

Raises:
ValueError: The gate has no parameters to resolve.
"""
2 changes: 0 additions & 2 deletions cirq/ops/partial_reflection_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,5 @@ def is_parameterized(self) -> bool:

def with_parameters_resolved_by(self,
param_resolver) -> 'PartialReflectionGate':
if not self.is_parameterized():
raise ValueError("Gate does not have any parameters to resolve.")
return self._with_half_turns(
half_turns=param_resolver.value_of(self.half_turns))
3 changes: 0 additions & 3 deletions cirq/ops/partial_reflection_gate_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
from typing import Union

import numpy as np
import pytest

import cirq
from cirq.ops.partial_reflection_gate import PartialReflectionGate
Expand Down Expand Up @@ -84,5 +83,3 @@ def test_partial_reflection_gate_with_parameters_resolved_by():
resolver = ParamResolver({'a': 0.1})
resolved_gate = gate.with_parameters_resolved_by(resolver)
assert resolved_gate.half_turns == 0.1
with pytest.raises(ValueError):
_ = resolved_gate.with_parameters_resolved_by(resolver)
2 changes: 1 addition & 1 deletion docs/simulation.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ circuit.append(basic_circuit())

print(circuit)
# prints
# (0, 0): ───X^0.5───Z───X^0.5───M───
# (0, 0): ───X^0.5───@───X^0.5───M───
# │
# (1, 0): ───X^0.5───Z───X^0.5───M───
```
Expand Down