def _flatten_to_known_matrix_ops( iter_ops: Iterable[ops.Operation], ext: Extensions) -> Generator[ops.Operation, None, None]: for op in iter_ops: # Check if the operation has a known matrix known_matrix_gate = ext.try_cast(op.gate, ops.KnownMatrixGate) if known_matrix_gate is not None: yield op continue # If not, check if it has a decomposition composite_gate = ext.try_cast(op.gate, ops.CompositeGate) if composite_gate is not None: # Recurse decomposition to get known matrix gates. op_tree = composite_gate.default_decompose(op.qubits) op_list = ops.flatten_op_tree(op_tree) for op in _flatten_to_known_matrix_ops(op_list, ext): yield op continue # Pass measurement gates through meas_gate = ext.try_cast(op.gate, ops.MeasurementGate) if meas_gate is not None: yield op continue # Otherwise, fail raise TypeError( 'Operation without a known matrix or decomposition: {!r}'.format( op))
def __init__(self, tolerance: float = 1e-8, allow_partial_czs: bool = True, extensions: Extensions = None) -> None: self.tolerance = tolerance self.allow_partial_czs = allow_partial_czs self.extensions = extensions or Extensions()
def _wrap_operation(op: ops.Operation, ext: extension.Extensions) -> ops.Operation: new_qubits = [_QCircuitQubit(e) for e in op.qubits] diagrammable = ext.try_cast(QCircuitDiagrammable, op) if diagrammable is None: diagrammable = fallback_qcircuit_extensions.cast( QCircuitDiagrammable, op) return _QCircuitOperation(op, diagrammable).with_qubits(*new_qubits)
def __init__(self, composite_gate_extension: Extensions = None) -> None: """Construct the optimization pass. Args: composite_gate_extension: An extension that that can be used to supply or override a CompositeGate decomposition. """ self.extension = composite_gate_extension or Extensions()
def _wrap_operation(op: ops.Operation, ext: extension.Extensions) -> ops.Operation: new_qubits = [_QCircuitQubit(e) for e in op.qubits] new_gate = ext.try_cast(op.gate, QCircuitDiagrammableGate) if new_gate is None: new_gate = fallback_qcircuit_extensions.cast(op.gate, QCircuitDiagrammableGate) return ops.Operation(_QCircuitGate(new_gate), new_qubits)
def __init__(self, tolerance: float = 1e-8, allow_partial_czs: bool = True, extensions: Extensions = None, post_clean_up: Callable[[Sequence[ops.Operation]], ops.OP_TREE ] = lambda op_list: op_list ) -> None: super().__init__(post_clean_up=post_clean_up) self.tolerance = tolerance self.allow_partial_czs = allow_partial_czs self.extensions = extensions or Extensions()
def test_to_text_diagram_extended_gate(): q = cirq.NamedQubit('(0, 0)') q2 = cirq.NamedQubit('(0, 1)') q3 = cirq.NamedQubit('(0, 2)') class FGate(cirq.Gate): def __repr__(self): return 'python-object-FGate:arbitrary-digits' f = FGate() c = Circuit([ Moment([f.on(q)]), ]) # Fallback to repr without extension. diagram = Circuit([ Moment([f.on(q)]), ]).to_text_diagram(use_unicode_characters=False) assert diagram.strip() == """ (0, 0): ---python-object-FGate:arbitrary-digits--- """.strip() # When used on multiple qubits, show the qubit order as a digit suffix. diagram = Circuit([ Moment([f.on(q, q3, q2)]), ]).to_text_diagram(use_unicode_characters=False) assert diagram.strip() == """ (0, 0): ---python-object-FGate:arbitrary-digits:0--- | (0, 1): ---python-object-FGate:arbitrary-digits:2--- | (0, 2): ---python-object-FGate:arbitrary-digits:1--- """.strip() # Succeeds with extension. class FGateAsText(cirq.TextDiagrammableGate): def __init__(self, f_gate): self.f_gate = f_gate def text_diagram_wire_symbols(self, qubit_count=None, use_unicode_characters=True, precision=3): return 'F' diagram = c.to_text_diagram(Extensions( {cirq.TextDiagrammableGate: { FGate: FGateAsText }}), use_unicode_characters=False) assert diagram.strip() == """ (0, 0): ---F--- """.strip()
def test_composite_extension_overrides(): q0, q1 = QubitId(), QubitId() cnot = CNOT(q0, q1) circuit = Circuit() circuit.append(cnot) opt = ExpandComposite(composite_gate_extension=Extensions( {CompositeGate: { CNotGate: lambda e: OtherCNot() }})) opt.optimize_circuit(circuit) expected = Circuit() expected.append([Z(q0), Y(q1)**-0.5, CZ(q0, q1), Y(q1)**0.5, Z(q0)]) assert_equal_mod_empty(expected, circuit)
def test_operation_to_unitary_matrix(): ex = Extensions() a = cirq.NamedQubit('a') b = cirq.NamedQubit('b') m = _operation_to_unitary_matrix(cirq.X(a), {a: 0}, ex) cirq.testing.assert_allclose_up_to_global_phase(m, np.array([[0, 1], [1, 0]]), atol=1e-8) m = _operation_to_unitary_matrix(cirq.X(a), {a: 0, b: 1}, ex) cirq.testing.assert_allclose_up_to_global_phase( m, np.kron(cirq.X.matrix(), np.eye(2))) cirq.testing.assert_allclose_up_to_global_phase(m, np.array([ [0, 0, 1, 0], [0, 0, 0, 1], [1, 0, 0, 0], [0, 1, 0, 0], ]), atol=1e-8) m = _operation_to_unitary_matrix(cirq.X(a), {a: 1, b: 0}, ex) cirq.testing.assert_allclose_up_to_global_phase(m, np.array([ [0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], ]), atol=1e-8) m = _operation_to_unitary_matrix(cirq.CNOT(b, a), {a: 0, b: 1}, ex) cirq.testing.assert_allclose_up_to_global_phase(m, np.array([ [1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0], ]), atol=1e-8) m = _operation_to_unitary_matrix(cirq.CNOT(b, a), {a: 1, b: 0}, ex) cirq.testing.assert_allclose_up_to_global_phase(m, np.array([ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], ]), atol=1e-8)
def _get_operation_text_diagram_exponent( op: ops.Operation, ext: Extensions, precision: Optional[int]) -> Optional[str]: text_diagram_gate = ext.try_cast(op.gate, ops.TextDiagrammableGate) if text_diagram_gate is None: return None exponent = text_diagram_gate.text_diagram_exponent() if exponent == 1: return None if isinstance(exponent, float) and precision is not None: return '{{:.{}}}'.format(precision).format(exponent) s = str(exponent) if '+' in s or ' ' in s or '-' in s[1:]: return '({})'.format(exponent) return s
def inverse(root: op_tree.OP_TREE, extensions: Extensions = None) -> op_tree.OP_TREE: """Generates OP_TREE inverses. Args: root: An operation tree containing only invertible operations. extensions: For caller-provided implementations of gate inverses. Returns: An OP_TREE that performs the inverse operation of the given OP_TREE. """ ext = extensions or Extensions() return op_tree.transform_op_tree( root=root, op_transformation=lambda e: _reverse_operation(e, ext), iter_transformation=lambda e: reversed(list(e)))
def _reverse_operation(operation: raw_types.Operation, ext: Extensions) -> raw_types.Operation: """Returns the inverse of an operation, if possible. Args: operation: The operation to reverse. ext: Used when casting the operation into a reversible effect. Returns: An operation on the same qubits but with the inverse gate. Raises: TypeError: The operation isn't reversible. """ reversible_op = ext.cast(gate_features.ReversibleEffect, operation) return cast(raw_types.Operation, reversible_op.inverse())
def _operations_to_unitary_matrix(iter_ops: Iterable[ops.Operation], qubit_map: Dict[QubitId, int], ignore_terminal_measurements: bool, ext: Extensions) -> np.ndarray: # Precondition is that circuit has only terminal measurements. total = np.eye(1 << len(qubit_map)) for op in iter_ops: meas_gate = ext.try_cast(op.gate, ops.MeasurementGate) if meas_gate is not None: if not ignore_terminal_measurements: raise TypeError( 'Terminal measurement operation but not ignoring these ' 'measurements: {!r}'.format(op)) continue # coverage: ignore mat = _operation_to_unitary_matrix(op, qubit_map, ext) total = np.matmul(mat, total) return total
def _reverse_operation(operation: raw_types.Operation, extensions: Extensions) -> raw_types.Operation: """Returns the inverse of an operation, if possible. Args: operation: The operation to reverse. Returns: An operation on the same qubits but with the inverse gate. Raises: ValueError: The operation's gate isn't reversible. """ gate = extensions.try_cast(operation.gate, gate_features.ReversibleGate) if gate is None: raise ValueError('Not reversible: {}'.format(operation)) return raw_types.Operation(gate.inverse(), operation.qubits)
def test_extension(): class DummyGate(ops.Gate): pass optimizer = MergeRotations(extensions=Extensions({ ops.KnownMatrixGate: { DummyGate: lambda _: ops.SingleQubitMatrixGate(np.array([[0, 1], [1, 0]])) } })) q = ops.QubitId() c = circuits.Circuit([ circuits.Moment([DummyGate().on(q)]), ]) assert_optimizes(before=c, after=circuits.Circuit([circuits.Moment([ops.X(q)])]), optimizer=optimizer)
def to_text_diagram_drawer( self, ext: Extensions = None, use_unicode_characters: bool = True, qubit_name_suffix: str = '', precision: Optional[int] = 3, qubit_order: ops.QubitOrderOrList = ops.QubitOrder.DEFAULT, ) -> TextDiagramDrawer: """Returns a TextDiagramDrawer with the circuit drawn into it. Args: ext: For extending gates to implement TextDiagrammableGate. use_unicode_characters: Determines if unicode characters are allowed (as opposed to ascii-only diagrams). qubit_name_suffix: Appended to qubit names in the diagram. precision: Number of digits to use when representing numbers. qubit_order: Determines how qubits are ordered in the diagram. Returns: The TextDiagramDrawer instance. """ if ext is None: ext = Extensions() qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for( self.qubits()) qubit_map = {qubits[i]: i for i in range(len(qubits))} diagram = TextDiagramDrawer() for q, i in qubit_map.items(): diagram.write(0, i, str(q) + qubit_name_suffix) for moment in [Moment()] * 2 + self.moments + [Moment()]: _draw_moment_in_diagram(moment, ext, use_unicode_characters, qubit_map, diagram, precision) w = diagram.width() for i in qubit_map.values(): diagram.horizontal_line(i, 0, w) return diagram
def to_unitary_matrix( self, qubit_order: ops.QubitOrderOrList = ops.QubitOrder.DEFAULT, qubits_that_should_be_present: Iterable[QubitId] = (), ignore_terminal_measurements: bool = True, ext: Extensions = None) -> np.ndarray: """Converts the circuit into a unitary matrix, if possible. Args: qubit_order: Determines how qubits are ordered when passing matrices into np.kron. ext: The extensions to use when attempting to cast gates into KnownMatrixGate instances. qubits_that_should_be_present: Qubits that may or may not appear in operations within the circuit, but that should be included regardless when generating the matrix. ignore_terminal_measurements: When set, measurements at the end of the circuit are ignored instead of causing the conversion to fail. Returns: A (possibly gigantic) 2d numpy array corresponding to a matrix equivalent to the circuit's effect on a quantum state. Raises: TypeError: The circuit contains gates that don't have a known unitary matrix, such as measurement gates, gates parameterized by a Symbol, etc. """ if ext is None: ext = Extensions() qs = ops.QubitOrder.as_qubit_order(qubit_order).order_for( self.qubits().union(qubits_that_should_be_present)) qubit_map = {i: q for q, i in enumerate(qs)} # type: Dict[QubitId, int] matrix_ops = _flatten_to_known_matrix_ops(self.iter_ops(), ext) if not self.are_all_measurements_terminal(): raise TypeError('Circuit contains a non-terminal measurement') return _operations_to_unitary_matrix(matrix_ops, qubit_map, ignore_terminal_measurements, ext)
def test_recursive_composite_extension_overrides(): q0, q1 = QubitId(), QubitId() swap = SWAP(q0, q1) circuit = Circuit() circuit.append(swap) opt = ExpandComposite(composite_gate_extension=Extensions( {CompositeGate: { CNotGate: lambda e: OtherCNot() }})) opt.optimize_circuit(circuit) expected = Circuit() expected.append([Z(q0), Y(q1)**-0.5, CZ(q0, q1), Y(q1)**0.5, Z(q0)]) expected.append( [Z(q1), Y(q0)**-0.5, CZ(q1, q0), Y(q0)**0.5, Z(q1)], strategy=InsertStrategy.INLINE) expected.append( [Z(q0), Y(q1)**-0.5, CZ(q0, q1), Y(q1)**0.5, Z(q0)], strategy=InsertStrategy.INLINE) assert_equal_mod_empty(expected, circuit)
def _operation_to_unitary_matrix(op: ops.Operation, qubit_map: Dict[QubitId, int], ext: Extensions) -> np.ndarray: known_matrix_gate = ext.try_cast(op.gate, ops.KnownMatrixGate) if known_matrix_gate is None: raise TypeError('Operation without a known matrix: {!r}'.format(op)) sub_mat = known_matrix_gate.matrix() qubit_count = len(qubit_map) bit_locs = [qubit_count - qubit_map[q] - 1 for q in op.qubits][::-1] over_mask = ~sum(1 << b for b in bit_locs) result = np.zeros(shape=(1 << qubit_count, 1 << qubit_count), dtype=np.complex128) for i in range(1 << qubit_count): sub_i = sum(_moved_bit(i, b, k) for k, b in enumerate(bit_locs)) over_i = i & over_mask for sub_j in range(sub_mat.shape[1]): j = sum(_moved_bit(sub_j, k, b) for k, b in enumerate(bit_locs)) result[i, over_i | j] = sub_mat[sub_i, sub_j] return result
def _get_operation_text_diagram_symbols( op: ops.Operation, ext: Extensions, use_unicode_characters: bool, precision: Optional[int]) -> Iterable[str]: text_diagram_gate = ext.try_cast(op.gate, ops.TextDiagrammableGate) if text_diagram_gate is not None: wire_symbols = text_diagram_gate.text_diagram_wire_symbols( qubit_count=len(op.qubits), use_unicode_characters=use_unicode_characters, precision=precision) if len(op.qubits) == len(wire_symbols): return wire_symbols elif len(wire_symbols) == 1: return len(op.qubits) * wire_symbols else: raise ValueError( 'Multi-qubit operation with TextDiagrammableGate {} that ' 'requires {} qubits but found {} qubits'.format( repr(op.gate), len(wire_symbols), len(op.qubits))) name = repr(op.gate) if len(op.qubits) == 1: return [name] return ['{}:{}'.format(name, i) for i in range(len(op.qubits))]
def __init__(self, tolerance: float = 1e-8, extensions=None) -> None: self.tolerance = tolerance self.extensions = extensions or Extensions()
# # 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 import ops from cirq.extension import Extensions from cirq.google import xmon_gates xmon_gate_ext = Extensions() xmon_gate_ext.add_cast( # type: ignore desired_type=xmon_gates.XmonGate, actual_type=ops.XPowGate, conversion=lambda e: xmon_gates.ExpWGate(exponent=e.exponent, phase_exponent=0)) xmon_gate_ext.add_cast( # type: ignore desired_type=xmon_gates.XmonGate, actual_type=ops.YPowGate, conversion=lambda e: xmon_gates.ExpWGate(exponent=e.exponent, phase_exponent=0.5))
# 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 import ops from cirq.extension import Extensions from cirq.google import xmon_gates xmon_gate_ext = Extensions() xmon_gate_ext.add_cast( desired_type=xmon_gates.XmonGate, actual_type=ops.RotXGate, conversion=lambda e: xmon_gates.ExpWGate(half_turns=e.half_turns, axis_half_turns=0)) xmon_gate_ext.add_cast( desired_type=xmon_gates.XmonGate, actual_type=ops.RotYGate, conversion=lambda e: xmon_gates.ExpWGate(half_turns=e.half_turns, axis_half_turns=0.5)) xmon_gate_ext.add_cast( desired_type=xmon_gates.XmonGate,
# # 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 import ops from cirq.extension import Extensions from cirq.google import xmon_gates xmon_gate_ext = Extensions() xmon_gate_ext.add_cast( # type: ignore desired_type=xmon_gates.XmonGate, actual_type=ops.RotXGate, conversion=lambda e: xmon_gates.ExpWGate(half_turns=e.half_turns, axis_half_turns=0)) xmon_gate_ext.add_cast( # type: ignore desired_type=xmon_gates.XmonGate, actual_type=ops.RotYGate, conversion=lambda e: xmon_gates.ExpWGate(half_turns=e.half_turns, axis_half_turns=0.5))
np.real(matrix[0, 0]), np.imag(matrix[0, 0]), np.real(matrix[1, 0]), np.imag(matrix[1, 0]), np.real(matrix[0, 1]), np.imag( matrix[0, 1]), np.real(matrix[1, 1]), np.imag(matrix[1, 1])) # Clean up. matrix_repr = matrix_repr.replace('+-', '-') matrix_repr = matrix_repr.replace('+0.0i', '') matrix_repr = matrix_repr.replace('.0,', ',') matrix_repr = matrix_repr.replace('.0}', '}') matrix_repr = matrix_repr.replace('.0+', '+') matrix_repr = matrix_repr.replace('.0-', '-') return QuirkGate({'id': '?', 'matrix': matrix_repr}) quirk_gate_ext = Extensions() quirk_gate_ext.add_cast(QuirkGate, ops.RotXGate, x_to_known) quirk_gate_ext.add_cast(QuirkGate, ops.RotYGate, y_to_known) quirk_gate_ext.add_cast(QuirkGate, ops.RotZGate, z_to_known) quirk_gate_ext.add_cast(QuirkGate, ExpZGate, z_to_known) quirk_gate_ext.add_cast(QuirkGate, ExpWGate, w_to_known) quirk_gate_ext.add_cast(QuirkGate, ops.Rot11Gate, cz_to_known) quirk_gate_ext.add_cast(QuirkGate, Exp11Gate, cz_to_known) quirk_gate_ext.add_cast(QuirkGate, ops.CNotGate, lambda e: QuirkGate('•', 'X', can_merge=False)) quirk_gate_ext.add_cast(QuirkGate, ops.SwapGate, lambda e: QuirkGate('Swap', 'Swap')) quirk_gate_ext.add_cast(QuirkGate, ops.HGate, lambda e: QuirkGate('H')) quirk_gate_ext.add_cast(QuirkGate, ops.MeasurementGate, lambda e: QuirkGate('Measure'))
# Clean up. matrix_repr = matrix_repr.replace('+-', '-') matrix_repr = matrix_repr.replace('+0.0i', '') matrix_repr = matrix_repr.replace('.0,', ',') matrix_repr = matrix_repr.replace('.0}', '}') matrix_repr = matrix_repr.replace('.0+', '+') matrix_repr = matrix_repr.replace('.0-', '-') return QuirkOp({ 'id': '?', 'matrix': matrix_repr }) quirk_gate_ext = Extensions() quirk_gate_ext.add_recursive_cast( QuirkOp, ops.GateOperation, lambda ext, op: ext.try_cast(QuirkOp, op.gate)) quirk_gate_ext.add_cast(QuirkOp, ops.RotXGate, x_to_known) quirk_gate_ext.add_cast(QuirkOp, ops.RotYGate, y_to_known) quirk_gate_ext.add_cast(QuirkOp, ops.RotZGate, z_to_known) quirk_gate_ext.add_cast(QuirkOp, ExpZGate, z_to_known) quirk_gate_ext.add_cast(QuirkOp, ExpWGate, w_to_known) quirk_gate_ext.add_cast(QuirkOp, ops.Rot11Gate, cz_to_known) quirk_gate_ext.add_cast(QuirkOp, Exp11Gate, cz_to_known) quirk_gate_ext.add_cast(QuirkOp, ops.CNotGate, lambda e: QuirkOp('•', 'X', can_merge=False))