def noisy_moment(self, moment: ops.Moment, system_qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE': moments: List[ops.Moment] = [] if any([protocols.is_measurement(op.gate) for op in moment.operations ]): # Add readout error before measurement gate p00 = self._noise_properties.p00 p11 = self._noise_properties.p11 measurement_qubits = [ list(op.qubits)[0] for op in moment.operations if protocols.is_measurement(op.gate) ] if p00 is not None or p11 is not None: _apply_readout_noise(p00, p11, moments, measurement_qubits) moments.append(moment) else: moments.append(moment) if self._noise_properties.pauli_error is not None: # Add depolarization error# duration = max( [get_duration_ns(op.gate) for op in moment.operations]) pauli_error = self._noise_properties.pauli_error_from_depolarization( duration) _apply_depol_noise(pauli_error, moments, system_qubits) if self._noise_properties.t1_ns is not None: # Add amplitude damping noise duration = max( [get_duration_ns(op.gate) for op in moment.operations]) _apply_amplitude_damp_noise(duration, self._noise_properties.t1_ns, moments, system_qubits) return moments
def noisy_moments( self, moments: Iterable['cirq.Moment'], system_qubits: Sequence['cirq.Qid']) -> Sequence['cirq.OP_TREE']: # Split multi-qubit measurements into single-qubit measurements. # These will be recombined after noise is applied. split_measure_moments = [] multi_measurements = {} for moment in moments: split_measure_ops = [] for op in moment: if not protocols.is_measurement(op): split_measure_ops.append(op) continue m_key = protocols.measurement_key_obj(op) multi_measurements[m_key] = op for q in op.qubits: split_measure_ops.append(ops.measure(q, key=m_key)) split_measure_moments.append(circuits.Moment(split_measure_ops)) # Append PHYSICAL_GATE_TAG to non-virtual ops in the input circuit, # using `self.virtual_predicate` to determine virtuality. new_moments = [] for moment in split_measure_moments: virtual_ops = {op for op in moment if self.virtual_predicate(op)} physical_ops = [ op.with_tags(PHYSICAL_GATE_TAG) for op in moment if op not in virtual_ops ] # Both physical and virtual operations remain in the circuit, but # only ops with PHYSICAL_GATE_TAG will receive noise. if virtual_ops: # Only subclasses will trigger this case. new_moments.append( circuits.Moment(virtual_ops)) # coverage: ignore if physical_ops: new_moments.append(circuits.Moment(physical_ops)) split_measure_circuit = circuits.Circuit(new_moments) # Add noise from each noise model. The PHYSICAL_GATE_TAGs added # previously allow noise models to distinguish physical gates from # those added by other noise models. noisy_circuit = split_measure_circuit.copy() for model in self.noise_models: noisy_circuit = noisy_circuit.with_noise(model) # Recombine measurements. final_moments = [] for moment in noisy_circuit: combined_measure_ops = [] restore_keys = set() for op in moment: if not protocols.is_measurement(op): combined_measure_ops.append(op) continue restore_keys.add(protocols.measurement_key_obj(op)) for key in restore_keys: combined_measure_ops.append(multi_measurements[key]) final_moments.append(circuits.Moment(combined_measure_ops)) return final_moments
def find_terminal_measurements( circuit: 'cirq.AbstractCircuit', ) -> List[Tuple[int, 'cirq.Operation']]: """Finds all terminal measurements in the given circuit. A measurement is terminal if there are no other operations acting on the measured qubits after the measurement operation occurs in the circuit. Args: circuit: The circuit to find terminal measurements in. Returns: List of terminal measurements, each specified as (moment_index, measurement_operation). """ open_qubits: Set['cirq.Qid'] = set(circuit.all_qubits()) seen_control_keys: Set['cirq.MeasurementKey'] = set() terminal_measurements: List[Tuple[int, 'cirq.Operation']] = [] for i in range(len(circuit) - 1, -1, -1): moment = circuit[i] for q in open_qubits: op = moment.operation_at(q) if ( op is not None and open_qubits.issuperset(op.qubits) and protocols.is_measurement(op) and not (seen_control_keys & protocols.measurement_key_objs(op)) ): terminal_measurements.append((i, op)) open_qubits -= moment.qubits seen_control_keys |= protocols.control_keys(moment) if not open_qubits: break return terminal_measurements
def _core_iterator( self, circuit: circuits.Circuit, sim_state: 'MPSState', ): """Iterator over MPSSimulatorStepResult from Moments of a Circuit Args: circuit: The circuit to simulate. sim_state: The initial state args for the simulation in the computational basis. Yields: MPSStepResult from simulating a Moment of the Circuit. """ if len(circuit) == 0: yield MPSSimulatorStepResult( measurements=sim_state.log_of_measurement_results, state=sim_state ) return noisy_moments = self.noise.noisy_moments(circuit, sorted(circuit.all_qubits())) for op_tree in noisy_moments: for op in flatten_to_ops(op_tree): if protocols.is_measurement(op) or protocols.has_mixture(op): sim_state.axes = tuple(sim_state.qubit_map[qubit] for qubit in op.qubits) protocols.act_on(op, sim_state) else: raise NotImplementedError(f"Unrecognized operation: {op!r}") yield MPSSimulatorStepResult( measurements=sim_state.log_of_measurement_results, state=sim_state ) sim_state.log_of_measurement_results.clear()
def repeat( self, repetitions: INT_TYPE, ) -> 'CircuitOperation': """Returns a copy of this operation repeated 'repetitions' times. Args: repetitions: Number of times this operation should repeat. This is multiplied with any pre-existing repetitions. Returns: A copy of this operation repeated 'repetitions' times. Raises: TypeError: `repetitions` is not an integer value. NotImplementedError: The operation contains measurements and cannot have repetitions. """ if not isinstance(repetitions, (int, np.integer)): raise TypeError('Only integer repetitions are allowed.') if repetitions == 1: # As CircuitOperation is immutable, this can safely return the original. return self repetitions = int(repetitions) if protocols.is_measurement(self.circuit): raise NotImplementedError( 'Loops over measurements are not supported.') return self.replace(repetitions=self.repetitions * repetitions)
def _run(self, circuit: circuits.Circuit, param_resolver: study.ParamResolver, repetitions: int) -> Dict[str, np.ndarray]: """See definition in `cirq.SimulatesSamples`.""" if self._ignore_measurement_results: raise ValueError( "run() is not supported when ignore_measurement_results = True" ) param_resolver = param_resolver or study.ParamResolver({}) resolved_circuit = protocols.resolve_parameters( circuit, param_resolver) check_all_resolved(resolved_circuit) qubits = tuple(sorted(resolved_circuit.all_qubits())) act_on_args = self._create_act_on_args(0, qubits) prefix, general_suffix = split_into_matching_protocol_then_general( resolved_circuit, lambda op: not protocols.is_measurement(op)) step_result = None for step_result in self._core_iterator( circuit=prefix, sim_state=act_on_args, ): pass assert step_result is not None if general_suffix.are_all_measurements_terminal() and not any( general_suffix.findall_operations( lambda op: isinstance(op, circuits.CircuitOperation))): return self._run_sweep_sample(general_suffix, repetitions, act_on_args) return self._run_sweep_repeat(general_suffix, repetitions, act_on_args)
def _run(self, circuit: circuits.Circuit, param_resolver: study.ParamResolver, repetitions: int) -> Dict[str, np.ndarray]: """See definition in `cirq.SimulatesSamples`.""" param_resolver = param_resolver or study.ParamResolver({}) resolved_circuit = protocols.resolve_parameters( circuit, param_resolver) check_all_resolved(resolved_circuit) qubit_order = sorted(resolved_circuit.all_qubits()) prefix, general_suffix = split_into_matching_protocol_then_general( resolved_circuit, lambda op: not protocols.is_measurement(op)) step_result = None for step_result in self._base_iterator( circuit=prefix, qubit_order=qubit_order, initial_state=0, ): pass assert step_result is not None intermediate_state = step_result._density_matrix if general_suffix.are_all_measurements_terminal() and not any( general_suffix.findall_operations( lambda op: isinstance(op, circuits.CircuitOperation))): return self._run_sweep_sample(general_suffix, repetitions, qubit_order, intermediate_state) return self._run_sweep_repeat(general_suffix, repetitions, qubit_order, intermediate_state)
def _with_measurement_key_mapping_(self, key_map: Dict[str, str]): return Moment( protocols.with_measurement_key_mapping(op, key_map) if protocols.is_measurement(op) else op for op in self.operations )
def defer(op: 'cirq.Operation', _) -> 'cirq.OP_TREE': if op in terminal_measurements: return op gate = op.gate if isinstance(gate, ops.MeasurementGate): key = value.MeasurementKey.parse_serialized(gate.key) targets = [_MeasurementQid(key, q) for q in op.qubits] measurement_qubits[key] = targets cxs = [ops.CX(q, target) for q, target in zip(op.qubits, targets)] xs = [ops.X(targets[i]) for i, b in enumerate(gate.full_invert_mask()) if b] return cxs + xs elif protocols.is_measurement(op): return [defer(op, None) for op in protocols.decompose_once(op)] elif op.classical_controls: controls = [] for c in op.classical_controls: if isinstance(c, value.KeyCondition): if c.key not in measurement_qubits: raise ValueError(f'Deferred measurement for key={c.key} not found.') qubits = measurement_qubits[c.key] if len(qubits) != 1: # TODO: Multi-qubit conditions require # https://github.com/quantumlib/Cirq/issues/4512 # Remember to update docstring above once this works. raise ValueError('Only single qubit conditions are allowed.') controls.extend(qubits) else: raise ValueError('Only KeyConditions are allowed.') return op.without_classical_controls().controlled_by( *controls, control_values=[tuple(range(1, q.dimension)) for q in controls] ) return op
def _verify_unique_measurement_keys(operations: Iterable['cirq.Operation']): seen: Set[str] = set() for op in operations: if protocols.is_measurement(op): key = protocols.measurement_key(op) if key in seen: raise ValueError('Measurement key {} repeated'.format(key)) seen.add(key)
def _verify_unique_measurement_keys(operations: Iterable['cirq.Operation']): """Raises an error if a measurement key is repeated in the given set of Operations.""" seen_keys: Set[str] = set() for op in operations: if protocols.is_measurement(op): key = protocols.measurement_key(op) if key in seen_keys: raise ValueError('Measurement key {} repeated'.format(key)) seen_keys.add(key)
def optimize_circuit(self, circuit: _circuit.Circuit) -> None: deletions: List[Tuple[int, ops.Operation]] = [] for moment_index, moment in enumerate(circuit): for op in moment.operations: if protocols.is_measurement(op): continue if protocols.trace_distance_bound(op) <= self.tolerance: deletions.append((moment_index, op)) circuit.batch_remove(deletions)
def _base_iterator( self, circuit: circuits.Circuit, qubit_order: ops.QubitOrderOrList, initial_state: int) -> Iterator['MPSSimulatorStepResult']: """Iterator over MPSSimulatorStepResult from Moments of a Circuit Args: circuit: The circuit to simulate. qubit_order: Determines the canonical ordering of the qubits. This is often used in specifying the initial state, i.e. the ordering of the computational basis states. initial_state: The initial state for the simulation in the computational basis. Represented as a big endian int. Yields: MPSStepResult from simulating a Moment of the Circuit. """ qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for( circuit.all_qubits()) qubit_map = {q: i for i, q in enumerate(qubits)} if len(circuit) == 0: yield MPSSimulatorStepResult( measurements={}, state=MPSState( qubit_map, self.prng, self.simulation_options, self.grouping, initial_state=initial_state, ), ) return state = MPSState( qubit_map, self.prng, self.simulation_options, self.grouping, initial_state=initial_state, ) noisy_moments = self.noise.noisy_moments(circuit, sorted(circuit.all_qubits())) for op_tree in noisy_moments: for op in flatten_to_ops(op_tree): if protocols.is_measurement(op) or protocols.has_mixture(op): state.axes = tuple(qubit_map[qubit] for qubit in op.qubits) protocols.act_on(op, state) else: raise NotImplementedError( f"Unrecognized operation: {op!r}") yield MPSSimulatorStepResult( measurements=state.log_of_measurement_results, state=state) state.log_of_measurement_results.clear()
def mapped_circuit(self, deep: bool = False) -> 'cirq.Circuit': """Applies all maps to the contained circuit and returns the result. Args: deep: If true, this will also call mapped_circuit on any CircuitOperations this object contains. Returns: The contained circuit with all other member variables (repetitions, qubit mapping, parameterization, etc.) applied to it. This behaves like `cirq.decompose(self)`, but preserving moment structure. """ circuit = self.circuit.unfreeze() circuit = circuit.transform_qubits(lambda q: self.qubit_map.get(q, q)) if self.repetitions < 0: circuit = circuit**-1 has_measurements = protocols.is_measurement(circuit) if has_measurements: circuit = protocols.with_measurement_key_mapping( circuit, self.measurement_key_map) circuit = protocols.resolve_parameters(circuit, self.param_resolver, recursive=False) if deep: def map_deep(op: 'cirq.Operation') -> 'cirq.OP_TREE': return op.mapped_circuit( deep=True) if isinstance(op, CircuitOperation) else op if self.repetition_ids is None: return circuit.map_operations(map_deep) if not has_measurements: return circuit.map_operations(map_deep) * abs(self.repetitions) # Path must be constructed from the top down. rekeyed_circuit = circuits.Circuit( protocols.with_key_path(circuit, self.parent_path + (rep, )) for rep in self.repetition_ids) return rekeyed_circuit.map_operations(map_deep) if self.repetition_ids is None: return circuit if not has_measurements: return circuit * abs(self.repetitions) def rekey_op(op: 'cirq.Operation', rep: str): """Update measurement keys in `op` to include repetition ID `rep`.""" rekeyed_op = protocols.with_key_path(op, self.parent_path + (rep, )) if rekeyed_op is NotImplemented: return op return rekeyed_op return circuits.Circuit( circuit.map_operations(lambda op: rekey_op(op, rep)) for rep in self.repetition_ids)
def __post_init__(self): 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. if self.repetitions < 0: try: protocols.inverse(self.circuit.unfreeze()) except TypeError: raise ValueError( f'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: object.__setattr__(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}') # Disallow mapping to keys containing the `MEASUREMENT_KEY_SEPARATOR` for mapped_key in self.measurement_key_map.values(): if MEASUREMENT_KEY_SEPARATOR in mapped_key: raise ValueError( f'Mapping to invalid key: {mapped_key}. "{MEASUREMENT_KEY_SEPARATOR}" ' 'is not allowed for measurement keys in a CircuitOperation' ) # Validate the keys for all direct child measurements. They are not allowed to contain # `MEASUREMENT_KEY_SEPARATOR` for _, op in self.circuit.findall_operations(lambda op: not isinstance( op, CircuitOperation) and protocols.is_measurement(op)): for key in protocols.measurement_keys(op): key = self.measurement_key_map.get(key, key) if MEASUREMENT_KEY_SEPARATOR in key: raise ValueError( f'Measurement {op} found to have invalid key: {key}. ' f'"{MEASUREMENT_KEY_SEPARATOR}" is not allowed for measurement keys ' 'in a CircuitOperation. Consider remapping the key using ' '`measurement_key_map` in the CircuitOperation constructor.' ) # Disallow qid mapping dimension conflicts. 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}') # Ensure that param_resolver is converted to an actual ParamResolver. object.__setattr__(self, 'param_resolver', study.ParamResolver(self.param_resolver))
def _homogeneous_moment_is_measurements(moment: 'cirq.Moment') -> bool: """Whether the moment is nothing but measurement gates. If a moment is a mixture of measurement and non-measurement gates this will throw a ValueError. """ cases = {protocols.is_measurement(gate) for gate in moment} if len(cases) == 2: raise ValueError("Moment must be homogeneous: all measurements or all operations.") return True in cases
def is_supported_operation(op: 'cirq.Operation') -> bool: """Checks whether given operation can be simulated by this simulator.""" if protocols.is_measurement(op): return True if isinstance(op, GlobalPhaseOperation): return True if not protocols.has_unitary(op): return False u = cirq.unitary(op) if u.shape == (2, 2): return not SingleQubitCliffordGate.from_unitary(u) is None else: return op.gate in [cirq.CNOT, cirq.CZ]
def _decompose_(self) -> 'cirq.OP_TREE': result = self.circuit.unfreeze() result = result.transform_qubits(lambda q: self.qubit_map.get(q, q)) if self.repetitions < 0: result = result**-1 result = protocols.with_measurement_key_mapping( result, self.measurement_key_map) result = protocols.resolve_parameters(result, self.param_resolver, recursive=False) # repetition_ids don't need to be taken into account if the circuit has no measurements # or if repetition_ids are unset. if self.repetition_ids is None or not protocols.is_measurement(result): return list(result.all_operations()) * abs(self.repetitions) # If it's a measurement circuit with repetitions/repetition_ids, prefix the repetition_ids # to measurements. Details at https://tinyurl.com/measurement-repeated-circuitop. ops = [] # type: List[cirq.Operation] for parent_id in self.repetition_ids: for op in result.all_operations(): if isinstance(op, CircuitOperation): # For a CircuitOperation, prefix the current repetition_id to the children # repetition_ids. ops.append( op.with_repetition_ids( # If `op.repetition_ids` is None, this will return `[parent_id]`. cartesian_product_of_string_lists( [parent_id], op.repetition_ids))) elif protocols.is_measurement(op): # For a non-CircuitOperation measurement, prefix the current repetition_id # to the children measurement keys. Implemented by creating a mapping and # using the with_measurement_key_mapping protocol. ops.append( protocols.with_measurement_key_mapping( op, key_map={ key: f'{MEASUREMENT_KEY_SEPARATOR.join([parent_id, key])}' for key in protocols.measurement_keys(op) }, )) else: ops.append(op) return ops
def _strat_act_on_state_vector_from_channel( action: Any, args: 'cirq.StateVectorSimulationState', qubits: Sequence['cirq.Qid']) -> bool: index = args._state.apply_channel(action, args.get_axes(qubits), args.prng) if index is None: return NotImplemented if protocols.is_measurement(action): key = protocols.measurement_key_name(action) args._classical_data.record_channel_measurement(key, index) return True
def _core_iterator( self, circuit: circuits.Circuit, sim_state: act_on_density_matrix_args.ActOnDensityMatrixArgs, all_measurements_are_terminal: bool = False, ): """Iterator over DensityMatrixStepResult from Moments of a Circuit Args: circuit: The circuit to simulate. sim_state: The initial state args for the simulation in the computational basis. all_measurements_are_terminal: Indicator that all measurements are terminal, allowing optimization. Yields: DensityMatrixStepResult from simulating a Moment of the Circuit. """ if len(circuit) == 0: yield DensityMatrixStepResult( density_matrix=sim_state.target_tensor, measurements=dict(sim_state.log_of_measurement_results), qubit_map=sim_state.qubit_map, dtype=self._dtype, ) return noisy_moments = self.noise.noisy_moments(circuit, sorted(circuit.all_qubits())) measured = collections.defaultdict( bool) # type: Dict[Tuple[cirq.Qid, ...], bool] for moment in noisy_moments: for op in flatten_to_ops(moment): # TODO: support more general measurements. # Github issue: https://github.com/quantumlib/Cirq/issues/3566 if all_measurements_are_terminal and measured[op.qubits]: continue if protocols.is_measurement(op): measured[op.qubits] = True if all_measurements_are_terminal: continue if self._ignore_measurement_results: op = ops.phase_damp(1).on(*op.qubits) sim_state.axes = tuple(sim_state.qubit_map[qubit] for qubit in op.qubits) protocols.act_on(op, sim_state) yield DensityMatrixStepResult( density_matrix=sim_state.target_tensor, measurements=dict(sim_state.log_of_measurement_results), qubit_map=sim_state.qubit_map, dtype=self._dtype, ) sim_state.log_of_measurement_results.clear()
def _needs_trajectories(circuit: circuits.Circuit) -> bool: """Checks if the circuit requires trajectory simulation.""" for op in circuit.all_operations(): test_op = (op if not protocols.is_parameterized(op) else protocols.resolve_parameters( op, {param: 1 for param in protocols.parameter_names(op)})) if not (protocols.has_unitary(test_op) or protocols.is_measurement(test_op)): return True return False
def noisy_moment(self, moment: 'cirq.Moment', system_qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE': if not moment.operations: return [moment] if self.require_physical_tag: physical_ops = [PHYSICAL_GATE_TAG in op.tags for op in moment] if any(physical_ops): if not all(physical_ops): raise ValueError( "Moments are expected to be all physical or all virtual ops, " f"but found {moment.operations}") else: # Only moments with physical operations should have noise. return [moment] noise_ops: List['cirq.Operation'] = [] # Some devices (including Google hardware) require that all gates have # the same duration, but this does not. Instead, each moment is assumed # to be as long as the longest gate it contains. moment_ns: float = 0 for op in moment: op_duration: Optional[float] = None for key, duration in self.gate_durations_ns.items(): if not issubclass(type(op.gate), key): continue # gate type doesn't match # TODO: remove assumption of same time across qubits op_duration = duration break if op_duration is None and isinstance(op.gate, ops.WaitGate): # special case for wait gates if not predefined nanos = op.gate.duration.total_nanos() if isinstance(nanos, sympy.Expr): raise ValueError('Symbolic wait times are not supported') op_duration = nanos if op_duration is not None: moment_ns = max(moment_ns, op_duration) if moment_ns == 0: return [moment] for qubit in system_qubits: qubit_op = moment.operation_at(qubit) if self.skip_measurements and protocols.is_measurement(qubit_op): continue rates = self.rate_matrix_GHz[qubit] * moment_ns kraus_ops = _kraus_ops_from_rates(tuple(rates.reshape(-1)), rates.shape) noise_ops.append(ops.KrausChannel(kraus_ops).on(qubit)) if not noise_ops: return [moment] output = [moment, moment_module.Moment(noise_ops)] return output[::-1] if self._prepend else output
def intercept_decompose_func(self, op: ops.Operation) -> ops.OP_TREE: # Drop measurements. if protocols.is_measurement(op): return [] # Immediately completely decompose two qubit unitary operations. if len(op.qubits) == 2: m = protocols.unitary(op, None) if m is not None: return optimizers.two_qubit_matrix_to_operations( op.qubits[0], op.qubits[1], mat=m, allow_partial_czs=False) # Fallback to default. return NotImplemented
def validate_all_measurements(moment: 'cirq.Moment') -> bool: """Ensures that the moment is homogenous and returns whether all ops are measurement gates. Args: moment: the moment to be checked Returns: bool: True if all operations are measurements, False if none of them are Raises: ValueError: If a moment is a mixture of measurement and non-measurement gates. """ cases = {protocols.is_measurement(gate) for gate in moment} if len(cases) == 2: raise ValueError("Moment must be homogeneous: all measurements or all operations.") return True in cases
def _strat_act_on_state_vector_from_channel( action: Any, args: 'cirq.ActOnStateVectorArgs', qubits: Sequence['cirq.Qid']) -> bool: kraus_operators = protocols.kraus(action, default=None) if kraus_operators is None: return NotImplemented def prepare_into_buffer(k: int): linalg.targeted_left_multiply( left_matrix=kraus_tensors[k], right_target=args.target_tensor, target_axes=args.get_axes(qubits), out=args.available_buffer, ) shape = protocols.qid_shape(action) kraus_tensors = [ e.reshape(shape * 2).astype(args.target_tensor.dtype) for e in kraus_operators ] p = args.prng.random() weight = None fallback_weight = 0 fallback_weight_index = 0 for index in range(len(kraus_tensors)): prepare_into_buffer(index) weight = np.linalg.norm(args.available_buffer)**2 if weight > fallback_weight: fallback_weight_index = index fallback_weight = weight p -= weight if p < 0: break assert weight is not None, "No Kraus operators" if p >= 0 or weight == 0: # Floating point error resulted in a malformed sample. # Fall back to the most likely case. prepare_into_buffer(fallback_weight_index) weight = fallback_weight index = fallback_weight_index args.available_buffer /= np.sqrt(weight) args.swap_target_tensor_for(args.available_buffer) if protocols.is_measurement(action): key = protocols.measurement_key_name(action) args._classical_data.record_channel_measurement(key, index) return True
def _run(self, circuit: circuits.Circuit, param_resolver: study.ParamResolver, repetitions: int) -> Dict[str, np.ndarray]: """See definition in `cirq.SimulatesSamples`.""" param_resolver = param_resolver or study.ParamResolver({}) resolved_circuit = protocols.resolve_parameters( circuit, param_resolver) check_all_resolved(resolved_circuit) _, general_suffix = split_into_matching_protocol_then_general( resolved_circuit, lambda op: not protocols.is_measurement(op)) if general_suffix.are_all_measurements_terminal() and not any( general_suffix.findall_operations( lambda op: isinstance(op, circuits.CircuitOperation))): return self._run_sweep_sample(resolved_circuit, repetitions) return self._run_sweep_repeat(resolved_circuit, repetitions)
def _base_iterator( self, circuit: circuits.Circuit, qubit_order: ops.QubitOrderOrList, initial_state: int ) -> Iterator['cirq.CliffordSimulatorStepResult']: """Iterator over CliffordSimulatorStepResult from Moments of a Circuit Args: circuit: The circuit to simulate. qubit_order: Determines the canonical ordering of the qubits. This is often used in specifying the initial state, i.e. the ordering of the computational basis states. initial_state: The initial state for the simulation. Yields: CliffordStepResult from simulating a Moment of the Circuit. """ qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for( circuit.all_qubits()) qubit_map = {q: i for i, q in enumerate(qubits)} if len(circuit) == 0: yield CliffordSimulatorStepResult(measurements={}, state=CliffordState( qubit_map, initial_state=initial_state)) else: state = CliffordState(qubit_map, initial_state=initial_state) for moment in circuit: measurements = collections.defaultdict( list) # type: Dict[str, List[np.ndarray]] for op in moment: print(type(op)) if protocols.has_unitary(op): state.apply_unitary(op) elif protocols.is_measurement(op): key = protocols.measurement_key(op) measurements[key].extend( state.perform_measurement(op.qubits)) yield CliffordSimulatorStepResult(measurements=measurements, state=state)
def _strat_act_on_state_vector_from_mixture( action: Any, args: 'cirq.ActOnStateVectorArgs', qubits: Sequence['cirq.Qid']) -> bool: mixture = protocols.mixture(action, default=None) if mixture is None: return NotImplemented probabilities, unitaries = zip(*mixture) index = args.prng.choice(range(len(unitaries)), p=probabilities) shape = protocols.qid_shape(action) * 2 unitary = unitaries[index].astype(args.target_tensor.dtype).reshape(shape) linalg.targeted_left_multiply(unitary, args.target_tensor, args.get_axes(qubits), out=args.available_buffer) args.swap_target_tensor_for(args.available_buffer) if protocols.is_measurement(action): key = protocols.measurement_key_name(action) args._classical_data.record_channel_measurement(key, index) return True
def _decompose_(self) -> 'cirq.OP_TREE': result = self.circuit.unfreeze() result = result.transform_qubits(lambda q: self.qubit_map.get(q, q)) if self.repetitions < 0: result = result**-1 result = protocols.with_measurement_key_mapping( result, self.measurement_key_map) result = protocols.resolve_parameters(result, self.param_resolver, recursive=False) # repetition_ids don't need to be taken into account if the circuit has no measurements # or if repetition_ids are unset. if self.repetition_ids is None or not protocols.is_measurement(result): return list(result.all_operations()) * abs(self.repetitions) # If it's a measurement circuit with repetitions/repetition_ids, prefix the repetition_ids # to measurements. Details at https://tinyurl.com/measurement-repeated-circuitop. ops = [] # type: List[cirq.Operation] for repetition_id in self.repetition_ids: path = self.parent_path + (repetition_id, ) ops += protocols.with_key_path(result, path).all_operations() return ops
def mapped_circuit(self, deep: bool = False) -> 'cirq.Circuit': """Applies all maps to the contained circuit and returns the result. Args: deep: If true, this will also call mapped_circuit on any CircuitOperations this object contains. Returns: The contained circuit with all other member variables (repetitions, qubit mapping, parameterization, etc.) applied to it. This behaves like `cirq.decompose(self)`, but preserving moment structure. """ circuit = self.circuit.unfreeze() if self.qubit_map: circuit = circuit.transform_qubits( lambda q: self.qubit_map.get(q, q)) if self.repetitions < 0: circuit = circuit**-1 if self.measurement_key_map: circuit = protocols.with_measurement_key_mapping( circuit, self.measurement_key_map) if self.param_resolver: circuit = protocols.resolve_parameters(circuit, self.param_resolver, recursive=False) if self.repetition_ids: if not protocols.is_measurement(circuit): circuit = circuit * abs(self.repetitions) else: circuit = circuits.Circuit( protocols.with_rescoped_keys(circuit, (rep, )) for rep in self.repetition_ids) circuit = protocols.with_rescoped_keys(circuit, self.parent_path, bindable_keys=self.extern_keys) if deep: circuit = circuit.map_operations(lambda op: op.mapped_circuit( deep=True) if isinstance(op, CircuitOperation) else op) return circuit