def with_operations(self, *contents: 'cirq.OP_TREE') -> 'cirq.Moment': """Returns a new moment with the given contents added. Args: contents: New operations to add to this moment. Returns: The new moment. """ from cirq.ops import op_tree operations = list(self._operations) qubits = set(self._qubits) for op in op_tree.flatten_to_ops(contents): if any(q in qubits for q in op.qubits): raise ValueError('Overlapping operations: {}'.format(op)) operations.append(op) qubits.update(op.qubits) # Use private variables to facilitate a quick copy. m = Moment() m._operations = tuple(operations) m._qubits = frozenset(qubits) m._qubit_to_op = self._qubit_to_op.copy() for op in operations: for q in op.qubits: m._qubit_to_op[q] = op return m
def __init__(self, *contents: 'cirq.OP_TREE') -> None: """Constructs a moment with the given operations. Args: operations: The operations applied within the moment. Will be flattened and frozen into a tuple before storing. Raises: ValueError: A qubit appears more than once. """ from cirq.ops import op_tree self._operations = tuple(op_tree.flatten_to_ops(contents)) # An internal dictionary to support efficient operation access by qubit. self._qubit_to_op: Dict['cirq.Qid', 'cirq.Operation'] = {} for op in self.operations: for q in op.qubits: # Check that operations don't overlap. if q in self._qubit_to_op: raise ValueError('Overlapping operations: {}'.format( self.operations)) self._qubit_to_op[q] = op self._qubits = frozenset(self._qubit_to_op.keys())
def _decompose_into_cliffords(op: 'cirq.Operation') -> List['cirq.Operation']: # An operation that can be ignored? if isinstance(op, global_phase_op.GlobalPhaseOperation): return [] # Already a known Clifford? if isinstance(op.gate, (clifford_gate.SingleQubitCliffordGate, pauli_interaction_gate.PauliInteractionGate)): return [op] # Specifies a decomposition into Cliffords? v = getattr(op, '_decompose_into_clifford_', None) if v is not None: result = v() if result is not None and result is not NotImplemented: return list(op_tree.flatten_to_ops(result)) # Specifies a decomposition that happens to contain only Cliffords? decomposed = protocols.decompose_once(op, None) if decomposed is not None: return [ out for sub_op in decomposed for out in _decompose_into_cliffords(sub_op) ] raise TypeError(f'Operation is not a known Clifford and did not decompose ' f'into known Cliffords: {op!r}')
def __init__(self, *contents: 'cirq.OP_TREE') -> None: """Constructs a moment with the given operations. Args: contents: The operations applied within the moment. Will be flattened and frozen into a tuple before storing. Raises: ValueError: A qubit appears more than once. """ self._operations = tuple(op_tree.flatten_to_ops(contents)) # An internal dictionary to support efficient operation access by qubit. self._qubit_to_op: Dict['cirq.Qid', 'cirq.Operation'] = {} for op in self.operations: for q in op.qubits: # Check that operations don't overlap. if q in self._qubit_to_op: raise ValueError( f'Overlapping operations: {self.operations}') self._qubit_to_op[q] = op self._qubits = frozenset(self._qubit_to_op.keys()) self._measurement_key_objs: Optional[ AbstractSet['cirq.MeasurementKey']] = None self._control_keys: Optional[FrozenSet['cirq.MeasurementKey']] = None
def validate(self, circuit_or_optree: Union['cirq.AbstractCircuit', op_tree.OP_TREE]) -> bool: """Validates gates forming `circuit_or_optree` should be contained in Gateset. Args: circuit_or_optree: The `cirq.Circuit` or `cirq.OP_TREE` to validate. """ # To avoid circular import. from cirq.circuits import circuit optree = circuit_or_optree if isinstance(circuit_or_optree, circuit.AbstractCircuit): optree = circuit_or_optree.all_operations() return all(self._validate_operation(op) for op in op_tree.flatten_to_ops(optree))
def __sub__(self, other: 'cirq.OP_TREE') -> 'cirq.Moment': must_remove = set(op_tree.flatten_to_ops(other)) new_ops = [] for op in self.operations: if op in must_remove: must_remove.remove(op) else: new_ops.append(op) if must_remove: raise ValueError(f"Subtracted missing operations from a moment.\n" f"Missing operations: {must_remove!r}\n" f"Moment: {self!r}") return Moment(new_ops)
def __init__(self, *contents: 'cirq.OP_TREE') -> None: """Constructs a moment with the given operations. Args: operations: The operations applied within the moment. Will be flattened and frozen into a tuple before storing. Raises: ValueError: A qubit appears more than once. """ from cirq.ops import op_tree self._operations = tuple(op_tree.flatten_to_ops(contents)) # Check that operations don't overlap. affected_qubits = [q for op in self.operations for q in op.qubits] self._qubits = frozenset(affected_qubits) if len(affected_qubits) != len(self._qubits): raise ValueError( 'Overlapping operations: {}'.format(self.operations))
def with_operations(self, *contents: 'cirq.OP_TREE') -> 'cirq.Moment': """Returns a new moment with the given contents added. Args: *contents: New operations to add to this moment. Returns: The new moment. Raises: ValueError: If the contents given overlaps a current operation in the moment. """ flattened_contents = tuple(op_tree.flatten_to_ops(contents)) m = Moment() # Use private variables to facilitate a quick copy. m._qubit_to_op = self._qubit_to_op.copy() qubits = set(self._qubits) for op in flattened_contents: if any(q in qubits for q in op.qubits): raise ValueError(f'Overlapping operations: {op}') qubits.update(op.qubits) for q in op.qubits: m._qubit_to_op[q] = op m._qubits = frozenset(qubits) m._operations = self._operations + flattened_contents m._sorted_operations = None m._measurement_key_objs = self._measurement_key_objs_().union( set( itertools.chain(*(protocols.measurement_key_objs(op) for op in flattened_contents)))) m._control_keys = self._control_keys_().union( set( itertools.chain(*(protocols.control_keys(op) for op in flattened_contents)))) return m
def conjugated_by(self, clifford: 'cirq.OP_TREE') -> 'PauliString': r"""Returns the Pauli string conjugated by a clifford operation. The product-of-Paulis $P$ conjugated by the Clifford operation $C$ is $$ C^\dagger P C $$ For example, conjugating a +Y operation by an S operation results in a +X operation (as opposed to a -X operation). In a circuit diagram where `P` is a pauli string observable immediately after a Clifford operation `C`, the pauli string `P.conjugated_by(C)` is the equivalent pauli string observable just before `C`. --------------------------C---P--- = ---C---P------------------------ = ---C---P---------C^-1---C------- = ---C---P---C^-1---------C------- = --(C^-1 · P · C)--------C------- = ---P.conjugated_by(C)---C------- Analogously, a Pauli product P can be moved from before a Clifford C in a circuit diagram to after the Clifford C by conjugating P by the inverse of C: ---P---C--------------------------- = -----C---P.conjugated_by(C^-1)--- Args: clifford: The Clifford operation to conjugate by. This can be an individual operation, or a tree of operations. Note that the composite Clifford operation defined by a sequence of operations is equivalent to a circuit containing those operations in the given order. Somewhat counter-intuitively, this means that the operations in the sequence are conjugated onto the Pauli string in reverse order. For example, `P.conjugated_by([C1, C2])` is equivalent to `P.conjugated_by(C2).conjugated_by(C1)`. Examples: >>> a, b = cirq.LineQubit.range(2) >>> print(cirq.X(a).conjugated_by(cirq.CZ(a, b))) X(0)*Z(1) >>> print(cirq.X(a).conjugated_by(cirq.S(a))) -Y(0) >>> print(cirq.X(a).conjugated_by([cirq.H(a), cirq.CNOT(a, b)])) Z(0)*X(1) Returns: The Pauli string conjugated by the given Clifford operation. """ pauli_map = dict(self._qubit_pauli_map) should_negate = False for op in list(op_tree.flatten_to_ops(clifford))[::-1]: if pauli_map.keys().isdisjoint(set(op.qubits)): continue for clifford_op in _decompose_into_cliffords(op)[::-1]: if pauli_map.keys().isdisjoint(set(clifford_op.qubits)): continue should_negate ^= PauliString._pass_operation_over( pauli_map, clifford_op, False) coef = -self._coefficient if should_negate else self.coefficient return PauliString(qubit_pauli_map=pauli_map, coefficient=coef)