def __init__(
        self,
        circuit: cirq.FrozenCircuit,
        repetitions: INT_TYPE = 1,
        qubit_map: dict[cirq.Qid, cirq.Qid] | None = None,
        measurement_key_map: dict[str, str] | None = None,
        param_resolver: study.ParamResolverOrSimilarType | None = None,
        repetition_ids: Sequence[str] | None = None,
        parent_path: tuple[str, ...] = (),
        extern_keys: frozenset[cirq.MeasurementKey] = frozenset(),
        use_repetition_ids: bool | None = None,
        repeat_until: cirq.Condition | None = None,
    ):
        """Initializes a CircuitOperation.

        Args:
            circuit: The FrozenCircuit wrapped by this operation.
            repetitions: How many times the circuit should be repeated. This can be
                integer, or a sympy expression. If sympy, the expression must
                resolve to an integer, or float within 0.001 of integer, at
                runtime.
            qubit_map: Remappings for qubits in the circuit.
            measurement_key_map: Remappings for measurement keys in the circuit.
                The keys and values should be unindexed (i.e. without repetition_ids).
                The values cannot contain the `MEASUREMENT_KEY_SEPARATOR`.
            param_resolver: Resolved values for parameters in the circuit.
            repetition_ids: List of identifiers for each repetition of the
                CircuitOperation. If populated, the length should be equal to the
                repetitions. If not populated and abs(`repetitions`) > 1, it is
                initialized to strings for numbers in `range(repetitions)`.
            parent_path: A tuple of identifiers for any parent CircuitOperations
                containing this one.
            extern_keys: The set of measurement keys defined at extern scope. The
                values here are used by decomposition and simulation routines to
                cache which external measurement keys exist as possible binding
                targets for unbound `ClassicallyControlledOperation` keys. This
                field is not intended to be set or changed manually, and should be
                empty in circuits that aren't in the middle of decomposition.
            use_repetition_ids: When True, any measurement key in the subcircuit
                will have its path prepended with the repetition id for each
                repetition. When False, this will not happen and the measurement
                key will be repeated. When None, default to False unless the caller
                passes `repetition_ids` explicitly.
            repeat_until: A condition that will be tested after each iteration of
                the subcircuit. The subcircuit will repeat until condition returns
                True, but will always run at least once, and the measurement key
                need not be defined prior to the subcircuit (but must be defined in
                a measurement within the subcircuit). This field is incompatible
                with repetitions or repetition_ids.

        Raises:
            TypeError: if repetitions is not an integer or sympy expression, or if
                the provided circuit is not a FrozenCircuit.
            ValueError: if any of the following conditions is met.
                - Negative repetitions on non-invertible circuit
                - Number of repetition IDs does not match repetitions
                - Repetition IDs used with parameterized repetitions
                - Conflicting qubit dimensions in qubit_map
                - Measurement key map has invalid key names
                - repeat_until used with other repetition controls
                - Key(s) in repeat_until are not modified by circuit
        """
        # This fields is exclusively for use in decomposition. It should not be
        # referenced outside this class.
        self._extern_keys = extern_keys

        # All other fields are pseudo-private: read access is allowed via the
        # @property methods, but mutation is prohibited.
        self._param_resolver = study.ParamResolver(param_resolver)
        self._parent_path = parent_path

        self._circuit = circuit
        if not isinstance(self._circuit, circuits.FrozenCircuit):
            raise TypeError(f'Expected circuit of type FrozenCircuit, got: {type(self._circuit)!r}')

        # Ensure that the circuit is invertible if the repetitions are negative.
        self._repetitions = repetitions
        self._repetition_ids = None if repetition_ids is None else list(repetition_ids)
        if use_repetition_ids is None:
            use_repetition_ids = repetition_ids is not None
        self._use_repetition_ids = use_repetition_ids
        if isinstance(self._repetitions, float):
            if math.isclose(self._repetitions, round(self._repetitions)):
                self._repetitions = round(self._repetitions)
        if isinstance(self._repetitions, INT_CLASSES):
            if self._repetitions < 0:
                try:
                    protocols.inverse(self._circuit.unfreeze())
                except TypeError:
                    raise ValueError('repetitions are negative but the circuit is not invertible')

            # Initialize repetition_ids to default, if unspecified. Else, validate their length.
            loop_size = abs(self._repetitions)
            if not self._repetition_ids:
                self._repetition_ids = self._default_repetition_ids()
            elif len(self._repetition_ids) != loop_size:
                raise ValueError(
                    f'Expected repetition_ids to be a list of length {loop_size}, '
                    f'got: {self._repetition_ids}'
                )
        elif isinstance(self._repetitions, sympy.Expr):
            if self._repetition_ids is not None:
                raise ValueError('Cannot use repetition ids with parameterized repetitions')
        else:
            raise TypeError(
                f'Only integer or sympy repetitions are allowed.\n'
                f'User provided: {self._repetitions}'
            )

        # Disallow qid mapping dimension conflicts.
        self._qubit_map = dict(qubit_map or {})
        for q, q_new in self._qubit_map.items():
            if q_new.dimension != q.dimension:
                raise ValueError(f'Qid dimension conflict.\nFrom qid: {q}\nTo qid: {q_new}')

        self._measurement_key_map = dict(measurement_key_map or {})
        # Disallow mapping to keys containing the `MEASUREMENT_KEY_SEPARATOR`
        for mapped_key in self._measurement_key_map.values():
            if value.MEASUREMENT_KEY_SEPARATOR in mapped_key:
                raise ValueError(
                    f'Mapping to invalid key: {mapped_key}. "{value.MEASUREMENT_KEY_SEPARATOR}" '
                    'is not allowed for measurement keys in a CircuitOperation'
                )

        self._repeat_until = repeat_until
        mapped_repeat_until = self._mapped_repeat_until
        if mapped_repeat_until:
            if self._use_repetition_ids or self._repetitions != 1:
                raise ValueError('Cannot use repetitions with repeat_until')
            if protocols.measurement_key_objs(self._mapped_single_loop()).isdisjoint(
                mapped_repeat_until.keys
            ):
                raise ValueError('Infinite loop: condition is not modified in subcircuit.')
Initializes a CircuitOperation.

        Args:
            circuit: The FrozenCircuit wrapped by this operation.
            repetitions: How many times the circuit should be repeated. This can be
                integer, or a sympy expression. If sympy, the expression must
                resolve to an integer, or float within 0.001 of integer, at
                runtime.
            qubit_map: Remappings for qubits in the circuit.
            measurement_key_map: Remappings for measurement keys in the circuit.
                The keys and values should be unindexed (i.e. without repetition_ids).
                The values cannot contain the `MEASUREMENT_KEY_SEPARATOR`.
            param_resolver: Resolved values for parameters in the circuit.
            repetition_ids: List of identifiers for each repetition of the
                CircuitOperation. If populated, the length should be equal to the
                repetitions. If not populated and abs(`repetitions`) > 1, it is
                initialized to strings for numbers in `range(repetitions)`.
            parent_path: A tuple of identifiers for any parent CircuitOperations
                containing this one.
            extern_keys: The set of measurement keys defined at extern scope. The
                values here are used by decomposition and simulation routines to
                cache which external measurement keys exist as possible binding
                targets for unbound `ClassicallyControlledOperation` keys. This
                field is not intended to be set or changed manually, and should be
                empty in circuits that aren't in the middle of decomposition.
            use_repetition_ids: When True, any measurement key in the subcircuit
                will have its path prepended with the repetition id for each
                repetition. When False, this will not happen and the measurement
                key will be repeated. When None, default to False unless the caller
                passes `repetition_ids` explicitly.
            repeat_until: A condition that will be tested after each iteration of
                the subcircuit. The subcircuit will repeat until condition returns
                True, but will always run at least once, and the measurement key
                need not be defined prior to the subcircuit (but must be defined in
                a measurement within the subcircuit). This field is incompatible
                with repetitions or repetition_ids.

        Raises:
            TypeError: if repetitions is not an integer or sympy expression, or if
                the provided circuit is not a FrozenCircuit.
            ValueError: if any of the following conditions is met.
                - Negative repetitions on non-invertible circuit
                - Number of repetition IDs does not match repetitions
                - Repetition IDs used with parameterized repetitions
                - Conflicting qubit dimensions in qubit_map
                - Measurement key map has invalid key names
                - repeat_until used with other repetition controls
                - Key(s) in repeat_until are not modified by circuit
        
cirq-core/cirq/circuits/circuit_operation.py