def compute_displays_sweep( self, program: Union[circuits.Circuit, schedules.Schedule], params: Optional[study.Sweepable] = None, qubit_order: ops.QubitOrderOrList = ops.QubitOrder.DEFAULT, initial_state: Union[int, np.ndarray] = 0, ) -> List[study.ComputeDisplaysResult]: """Computes displays in the supplied Circuit or Schedule. In contrast to `compute_displays`, this allows for sweeping over different parameter values. Args: program: The circuit or schedule to simulate. params: Parameters to run with the program. qubit_order: Determines the canonical ordering of the qubits used to define the order of amplitudes in the wave function. initial_state: If an int, the state is set to the computational basis state corresponding to this state. Otherwise if it is a np.ndarray it is the full initial state, either a pure state or the full density matrix. If it is the pure state it must be the correct size, be normalized (an L2 norm of 1), and be safely castable to an appropriate dtype for the simulator. If it is a mixed state it must be correctly sized and positive semidefinite with trace one. Returns: List of ComputeDisplaysResults for this run, one for each possible parameter resolver. """ circuit = (program.to_circuit() if isinstance(program, schedules.Schedule) else program) qubit_order = ops.QubitOrder.as_qubit_order(qubit_order) qubits = qubit_order.order_for(circuit.all_qubits()) compute_displays_results: List[study.ComputeDisplaysResult] = [] for param_resolver in study.to_resolvers(params): display_values: Dict[Hashable, Any] = {} # Compute the displays in the first Moment moment = circuit[0] matrix = density_matrix_utils.to_valid_density_matrix( initial_state, num_qubits=len(qubits), dtype=self._dtype) qubit_map = {q: i for i, q in enumerate(qubits)} _enter_moment_display_values_into_dictionary( display_values, moment, matrix, qubits, qubit_map) # Compute the displays in the rest of the Moments all_step_results = self.simulate_moment_steps( circuit, param_resolver, qubits, initial_state) for step_result, moment in zip(all_step_results, circuit[1:]): _enter_moment_display_values_into_dictionary( display_values, moment, step_result.density_matrix(), qubits, step_result._qubit_map) compute_displays_results.append( study.ComputeDisplaysResult(params=param_resolver, display_values=display_values)) return compute_displays_results
def compute_samples_displays_sweep( self, program: Union[circuits.Circuit, schedules.Schedule], params: Optional[study.Sweepable] = None ) -> List[study.ComputeDisplaysResult]: """Computes SamplesDisplays in the supplied Circuit or Schedule. In contrast to `compute_displays`, this allows for sweeping over different parameter values. Args: program: The circuit or schedule to simulate. params: Parameters to run with the program. Returns: List of ComputeDisplaysResults for this run, one for each possible parameter resolver. """ circuit = (program if isinstance(program, circuits.Circuit) else program.to_circuit()) param_resolvers = study.to_resolvers(params or study.ParamResolver({})) compute_displays_results = [] # type: List[study.ComputeDisplaysResult] for param_resolver in param_resolvers: display_values = {} # type: Dict[Hashable, Any] preceding_circuit = circuits.Circuit() for i, moment in enumerate(circuit): displays = (op for op in moment if isinstance(op, ops.SamplesDisplay)) for display in displays: measurement_key = str(display.key) measurement_circuit = circuits.Circuit.from_ops( display.measurement_basis_change(), ops.measure(*display.qubits, key=measurement_key) ) measurements = self._run( preceding_circuit + measurement_circuit, param_resolver, display.num_samples) display_values[display.key] = ( display.value_derived_from_samples( measurements[measurement_key])) preceding_circuit.append(circuit[i]) compute_displays_results.append(study.ComputeDisplaysResult( params=param_resolver, display_values=display_values)) return compute_displays_results