diff --git a/cirq/google/xmon_gates.py b/cirq/google/xmon_gates.py index 851f9c6900d..836f3be55f3 100644 --- a/cirq/google/xmon_gates.py +++ b/cirq/google/xmon_gates.py @@ -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. @@ -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 @@ -183,7 +184,13 @@ 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, @@ -191,6 +198,7 @@ class ExpWGate(XmonGate, ops.TextDiagrammableGate, ops.PhaseableGate, ops.BoundedEffectGate, + ops.ParameterizableGate, PotentialImplementation): """A rotation around an axis in the XY plane of the Bloch sphere. @@ -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. @@ -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): @@ -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] diff --git a/cirq/google/xmon_gates_test.py b/cirq/google/xmon_gates_test.py index 1c5ab33e225..4bc11e96216 100644 --- a/cirq/google/xmon_gates_test.py +++ b/cirq/google/xmon_gates_test.py @@ -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 @@ -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 @@ -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)) @@ -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(), @@ -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) diff --git a/cirq/ops/gate_features.py b/cirq/ops/gate_features.py index 4ea65910014..eb733ae593e 100644 --- a/cirq/ops/gate_features.py +++ b/cirq/ops/gate_features.py @@ -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. """ diff --git a/cirq/ops/partial_reflection_gate.py b/cirq/ops/partial_reflection_gate.py index a3e7aba8b45..ebec963d0e0 100644 --- a/cirq/ops/partial_reflection_gate.py +++ b/cirq/ops/partial_reflection_gate.py @@ -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)) diff --git a/cirq/ops/partial_reflection_gate_test.py b/cirq/ops/partial_reflection_gate_test.py index ca4ff51089c..e0721f8a9f8 100644 --- a/cirq/ops/partial_reflection_gate_test.py +++ b/cirq/ops/partial_reflection_gate_test.py @@ -15,7 +15,6 @@ from typing import Union import numpy as np -import pytest import cirq from cirq.ops.partial_reflection_gate import PartialReflectionGate @@ -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) diff --git a/docs/simulation.md b/docs/simulation.md index c0540e0cadd..6a1227a41a6 100644 --- a/docs/simulation.md +++ b/docs/simulation.md @@ -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─── ```