def strat_act_on_from_apply_decompose(val: Any, args: 'cirq.SimulationState', qubits: Sequence['cirq.Qid']) -> bool: operations, qubits1, _ = _try_decompose_into_operations_and_qubits(val) assert len(qubits1) == len(qubits) qubit_map = {q: qubits[i] for i, q in enumerate(qubits1)} if operations is None: return NotImplemented for operation in operations: operation = operation.with_qubits( *[qubit_map[q] for q in operation.qubits]) protocols.act_on(operation, args) return True
def apply_unitary(self, op: 'cirq.Operation'): ch_form_args = clifford.StabilizerChFormSimulationState( prng=np.random.RandomState(), qubits=self.qubit_map.keys(), initial_state=self.ch_form) try: act_on(op, ch_form_args) except TypeError: raise ValueError( f'{str(op.gate)} cannot be run with Clifford simulator.' ) # type: ignore return
def _act_on_(self, args: 'cirq.OperationTarget') -> bool: if self.repeat_until: circuit = self._mapped_single_loop() while True: for op in circuit.all_operations(): protocols.act_on(op, args) if self.repeat_until.resolve(args.classical_data): break else: for op in self._decompose_(): protocols.act_on(op, args) return True
def _act_on_(self, sim_state: 'cirq.SimulationStateBase') -> bool: if self.repeat_until: circuit = self._mapped_single_loop() while True: for op in circuit.all_operations(): protocols.act_on(op, sim_state) if self.repeat_until.resolve(sim_state.classical_data): break else: for op in self._decompose_(): protocols.act_on(op, sim_state) return True
def _act_on_fallback_( self, action: Union['cirq.Operation', 'cirq.Gate'], qubits: Sequence['cirq.Qid'], allow_decompose: bool = True, ) -> bool: gate = action.gate if isinstance(action, ops.Operation) else action if isinstance(gate, ops.IdentityGate): return True if isinstance(gate, ops.SwapPowGate) and gate.exponent % 2 == 1 and gate.global_shift == 0: q0, q1 = qubits args0 = self.args[q0] args1 = self.args[q1] if args0 is args1: args0.swap(q0, q1, inplace=True) else: self.args[q0] = args1.rename(q1, q0, inplace=True) self.args[q1] = args0.rename(q0, q1, inplace=True) return True # Go through the op's qubits and join any disparate ActOnArgs states # into a new combined state. op_args_opt: Optional[TActOnArgs] = None for q in qubits: if op_args_opt is None: op_args_opt = self.args[q] elif q not in op_args_opt.qubits: op_args_opt = op_args_opt.kronecker_product(self.args[q]) op_args = op_args_opt or self.args[None] # (Backfill the args map with the new value) for q in op_args.qubits: self.args[q] = op_args # Act on the args with the operation act_on_qubits = qubits if isinstance(action, ops.Gate) else None protocols.act_on(action, op_args, act_on_qubits, allow_decompose=allow_decompose) # Decouple any measurements or resets if self.split_untangled_states and isinstance( gate, (ops.MeasurementGate, ops.ResetChannel) ): for q in qubits: q_args, op_args = op_args.factor((q,), validate=False) self.args[q] = q_args # (Backfill the args map with the new value) for q in op_args.qubits: self.args[q] = op_args return True
def _act_on_(self, args): from cirq.sim import clifford if self._is_parameterized_(): return NotImplemented if isinstance(args, clifford.ActOnCliffordTableauArgs): if args.prng.random() < self.probability: # Note: because we're doing this probabilistically, it's not # safe to fallback to other strategies if act_on fails. Those # strategies could double-count the probability. protocols.act_on(self.sub_gate, args) return True return NotImplemented
def apply_unitary(self, op: 'cirq.Operation'): tableau_args = clifford.ActOnCliffordTableauArgs( self.tableau, [self.qubit_map[i] for i in op.qubits], np.random.RandomState(), {}) ch_form_args = clifford.ActOnStabilizerCHFormArgs( self.ch_form, [self.qubit_map[i] for i in op.qubits]) try: act_on(op, tableau_args) act_on(op, ch_form_args) except TypeError: raise ValueError('%s cannot be run with Clifford simulator.' % str(op.gate)) # type: ignore return
def _generate_clifford_from_known_gate( cls, num_qubits: int, gate: raw_types.Gate ) -> Union['SingleQubitCliffordGate', 'CliffordGate']: qubits = devices.LineQubit.range(num_qubits) t = qis.CliffordTableau(num_qubits=num_qubits) args = sim.CliffordTableauSimulationState(tableau=t, qubits=qubits, prng=np.random.RandomState()) protocols.act_on(gate, args, qubits, allow_decompose=False) if num_qubits == 1: return SingleQubitCliffordGate.from_clifford_tableau(args.tableau) return CliffordGate.from_clifford_tableau(args.tableau)
def _core_iterator( self, circuit: circuits.AbstractCircuit, sim_state: OperationTarget[TActOnArgs], all_measurements_are_terminal: bool = False, ) -> Iterator[TStepResultBase]: """Standard iterator over StepResult from Moments of a Circuit. Args: circuit: The circuit to simulate. sim_state: The initial args for the simulation. The form of this state depends on the simulation implementation. See documentation of the implementing class for details. Yields: StepResults from simulating a Moment of the Circuit. """ if len(circuit) == 0: yield self._create_step_result(sim_state) return noisy_moments = self.noise.noisy_moments(circuit, sorted(circuit.all_qubits())) measured: Dict[Tuple['cirq.Qid', ...], bool] = collections.defaultdict(bool) for moment in noisy_moments: for op in ops.flatten_to_ops(moment): try: # TODO: support more general measurements. # Github issue: https://github.com/quantumlib/Cirq/issues/3566 # Preprocess measurements if all_measurements_are_terminal and measured[op.qubits]: continue if isinstance(op.gate, ops.MeasurementGate): measured[op.qubits] = True if all_measurements_are_terminal: continue if self._ignore_measurement_results: op = ops.phase_damp(1).on(*op.qubits) # Simulate the operation protocols.act_on(op, sim_state) except TypeError: raise TypeError( f"{self.__class__.__name__} doesn't support {op!r}") step_result = self._create_step_result(sim_state) yield step_result sim_state = step_result._sim_state
def _core_iterator( self, circuit: 'cirq.AbstractCircuit', sim_state: OperationTarget[TActOnArgs], all_measurements_are_terminal: bool = False, ) -> Iterator[TStepResultBase]: """Standard iterator over StepResult from Moments of a Circuit. Args: circuit: The circuit to simulate. sim_state: The initial args for the simulation. The form of this state depends on the simulation implementation. See documentation of the implementing class for details. all_measurements_are_terminal: Whether all measurements in the given circuit are terminal. Yields: StepResults from simulating a Moment of the Circuit. Raises: TypeError: The simulator encounters an op it does not support. """ if len(circuit) == 0: yield self._create_step_result(sim_state) return noisy_moments = self.noise.noisy_moments(circuit, sorted(circuit.all_qubits())) measured: Dict[Tuple['cirq.Qid', ...], bool] = collections.defaultdict(bool) for moment in noisy_moments: for op in ops.flatten_to_ops(moment): try: # Preprocess measurements if all_measurements_are_terminal and measured[op.qubits]: continue if isinstance(op.gate, ops.MeasurementGate): measured[op.qubits] = True if all_measurements_are_terminal: continue # Simulate the operation protocols.act_on(op, sim_state) except TypeError: raise TypeError( f"{self.__class__.__name__} doesn't support {op!r}") step_result = self._create_step_result(sim_state) yield step_result sim_state = step_result._sim_state
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 in the computational basis. Represented as a big endian int. 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) ) return state = CliffordState(qubit_map, initial_state=initial_state) ch_form_args = clifford.ActOnStabilizerCHFormArgs( state.ch_form, [], self._prng, {}, ) for moment in circuit: ch_form_args.log_of_measurement_results = {} for op in moment: try: ch_form_args.axes = tuple(state.qubit_map[i] for i in op.qubits) act_on(op, ch_form_args) except TypeError: raise NotImplementedError( f"CliffordSimulator doesn't support {op!r}" ) # type: ignore yield CliffordSimulatorStepResult( measurements=ch_form_args.log_of_measurement_results, state=state )
def state_vector_has_stabilizer(state_vector: np.ndarray, stabilizer: DensePauliString) -> bool: """Checks that the stabilizer does not modify the value of the state_vector, including the global phase. Does not mutate the input state_vector.""" args = act_on_state_vector_args.ActOnStateVectorArgs( target_tensor=state_vector.copy(), available_buffer=np.empty_like(state_vector), axes=range(protocols.num_qubits(stabilizer)), prng=np.random.RandomState(), log_of_measurement_results={}) protocols.act_on(stabilizer, args) return np.allclose(args.target_tensor, state_vector)
def _act_all_on_state_vector(actions: Iterable[Any], qubits: Sequence['cirq.Qid'], args: 'cirq.ActOnStateVectorArgs'): assert len(qubits) == len(args.axes) qubit_map = {q: args.axes[i] for i, q in enumerate(qubits)} old_axes = args.axes try: for action in actions: args.axes = tuple(qubit_map[q] for q in action.qubits) protocols.act_on(action, args) finally: args.axes = old_axes return True
def sample( self, qubits: Sequence['cirq.Qid'], repetitions: int = 1, seed: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None, ) -> np.ndarray: measurements: Dict[str, List[np.ndarray]] = {} prng = value.parse_random_state(seed) for i in range(repetitions): op = ops.measure(*qubits, key=str(i)) state = self.state.copy() ch_form_args = ActOnStabilizerCHFormArgs(state, prng, measurements, self.qubits) protocols.act_on(op, ch_form_args) return np.array(list(measurements.values()), dtype=bool)
def _act_on_(self, sim_state: 'cirq.SimulationStateBase', qubits: Sequence['cirq.Qid']): if len(qubits) != 1: return NotImplemented from cirq.sim import simulation_state if (isinstance(sim_state, simulation_state.SimulationState) and not sim_state.can_represent_mixed_states): result = sim_state._perform_measurement(qubits)[0] gate = common_gates.XPowGate( dimension=self.dimension)**(self.dimension - result) protocols.act_on(gate, sim_state, qubits) return True return NotImplemented
def _run(self, circuit: 'cirq.AbstractCircuit', repetitions: int) -> Dict[str, np.ndarray]: measurements: Dict[str, List[np.ndarray]] = { key: [] for key in protocols.measurement_key_names(circuit) } qubits = circuit.all_qubits() for _ in range(repetitions): state = CliffordTableauSimulationState( CliffordTableau(num_qubits=len(qubits)), qubits=list(qubits), prng=self._prng ) for op in circuit.all_operations(): protocols.act_on(op, state) for k, v in state.log_of_measurement_results.items(): measurements[k].append(np.array(v, dtype=np.uint8)) return {k: np.array(v) for k, v in measurements.items()}
def strat_act_on_from_apply_decompose( val: Any, args: ActOnArgs, ) -> bool: operations, qubits, _ = _try_decompose_into_operations_and_qubits(val) if operations is None: return NotImplemented assert len(qubits) == len(args.axes) qubit_map = {q: args.axes[i] for i, q in enumerate(qubits)} old_axes = args.axes try: for operation in operations: args.axes = tuple(qubit_map[q] for q in operation.qubits) protocols.act_on(operation, args) finally: args.axes = old_axes return True
def _base_iterator( self, circuit: circuits.Circuit, qubit_order: ops.QubitOrderOrList, initial_state: 'cirq.STATE_VECTOR_LIKE', perform_measurements: bool = True, ) -> Iterator['SparseSimulatorStep']: qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for( circuit.all_qubits()) num_qubits = len(qubits) qid_shape = protocols.qid_shape(qubits) qubit_map = {q: i for i, q in enumerate(qubits)} state = qis.to_valid_state_vector(initial_state, num_qubits, qid_shape=qid_shape, dtype=self._dtype) if len(circuit) == 0: yield SparseSimulatorStep(state, {}, qubit_map, self._dtype) sim_state = act_on_state_vector_args.ActOnStateVectorArgs( target_tensor=np.reshape(state, qid_shape), available_buffer=np.empty(qid_shape, dtype=self._dtype), axes=[], prng=self._prng, log_of_measurement_results={}, ) 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 perform_measurements or not isinstance( op.gate, ops.MeasurementGate): sim_state.axes = tuple(qubit_map[qubit] for qubit in op.qubits) protocols.act_on(op, sim_state) yield SparseSimulatorStep( state_vector=sim_state.target_tensor, measurements=dict(sim_state.log_of_measurement_results), qubit_map=qubit_map, dtype=self._dtype, ) sim_state.log_of_measurement_results.clear()
def apply_measurement( self, op: 'cirq.Operation', measurements: Dict[str, List[np.ndarray]], prng: np.random.RandomState, collapse_state_vector=True, ): if not isinstance(op.gate, cirq.MeasurementGate): raise TypeError( 'apply_measurement only supports cirq.MeasurementGate operations. Found %s instead.' % str(op.gate)) if collapse_state_vector: state = self else: state = self.copy() ch_form_args = clifford.ActOnStabilizerCHFormArgs( state.ch_form, prng, measurements, self.qubit_map.keys()) act_on(op, ch_form_args)
def _final_clifford_tableau( circuit: Circuit, qubit_map) -> Optional[clifford_tableau.CliffordTableau]: """Initializes a CliffordTableau with default args for the given qubits and evolves it by having each operation act on the tableau. Returns None if any of the operation can not act on a CliffordTableau, returns the tableau otherwise.""" tableau = clifford_tableau.CliffordTableau(len(qubit_map)) for op in circuit.all_operations(): try: args = act_on_clifford_tableau_args.ActOnCliffordTableauArgs( tableau=tableau, axes=[qubit_map[qid] for qid in op.qubits], # type: ignore prng=np.random.RandomState(), log_of_measurement_results={}, ) protocols.act_on(op, args, allow_decompose=True) except TypeError: return None return tableau
def _core_iterator( self, circuit: circuits.Circuit, sim_state: clifford.ActOnStabilizerCHFormArgs, ): """Iterator over CliffordSimulatorStepResult 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: CliffordStepResult from simulating a Moment of the Circuit. """ def create_state(): return CliffordState(sim_state.qubit_map, sim_state.state.copy()) if len(circuit) == 0: yield CliffordSimulatorStepResult( measurements=sim_state.log_of_measurement_results, state=create_state()) return for moment in circuit: sim_state.log_of_measurement_results = {} for op in moment: try: sim_state.axes = tuple(sim_state.qubit_map[i] for i in op.qubits) act_on(op, sim_state) except TypeError: raise NotImplementedError( f"CliffordSimulator doesn't support {op!r}" ) # type: ignore yield CliffordSimulatorStepResult( measurements=sim_state.log_of_measurement_results, state=create_state())
def _core_iterator( self, circuit: circuits.Circuit, sim_state: act_on_state_vector_args.ActOnStateVectorArgs, ): """Iterator over SparseSimulatorStep 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: SparseSimulatorStep from simulating a Moment of the Circuit. """ if len(circuit) == 0: yield SparseSimulatorStep( state_vector=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())) for op_tree in noisy_moments: for op in flatten_to_ops(op_tree): sim_state.axes = tuple(sim_state.qubit_map[qubit] for qubit in op.qubits) protocols.act_on(op, sim_state) yield SparseSimulatorStep( state_vector=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 _run(self, circuit: circuits.Circuit, repetitions: int) -> Dict[str, np.ndarray]: measurements: Dict[str, List[int]] = { key: [] for key in protocols.measurement_keys(circuit) } qubits = circuit.all_qubits() for _ in range(repetitions): state = ActOnCliffordTableauArgs( CliffordTableau(num_qubits=len(qubits)), qubits=list(qubits), prng=self._prng, log_of_measurement_results={}, ) for op in circuit.all_operations(): protocols.act_on(op, state) for k, v in state.log_of_measurement_results.items(): measurements[k].append(v) return {k: np.array(v) for k, v in measurements.items()}
def from_op_list( cls, operations: Sequence[raw_types.Operation], qubit_order: Sequence[raw_types.Qid] ) -> 'CliffordGate': """Construct a new Clifford gates from several known operations. Args: operations: A list of cirq operations to construct the Clifford gate. The combination order is the first element in the list applies the transformation on the stabilizer state first. qubit_order: Determines how qubits are ordered when decomposite the operations. Returns: A CliffordGate instance, which has the transformation on the stabilizer state equivalent to the composition of operations. Raises: ValueError: When one or more operations do not have stabilizer effect. """ for op in operations: if op.gate and op.gate._has_stabilizer_effect_(): continue raise ValueError( "Clifford Gate can only be constructed from the " "operations that has stabilizer effect." ) base_tableau = qis.CliffordTableau(len(qubit_order)) args = sim.clifford.ActOnCliffordTableauArgs( tableau=base_tableau, qubits=qubit_order, prng=np.random.RandomState(0), # unused log_of_measurement_results={}, # unused ) for op in operations: protocols.act_on(op, args, allow_decompose=True) return CliffordGate.from_clifford_tableau(args.tableau)
def state_vector_has_stabilizer(state_vector: np.ndarray, stabilizer: DensePauliString) -> bool: """Checks that the state_vector is stabilized by the given stabilizer. The stabilizer should not modify the value of the state_vector, up to the global phase. Args: state_vector: An input state vector. Is not mutated by this function. stabilizer: A potential stabilizer of the above state_vector as a DensePauliString. Returns: Whether the stabilizer stabilizes the supplied state. """ args = act_on_state_vector_args.ActOnStateVectorArgs( target_tensor=state_vector.copy(), available_buffer=np.empty_like(state_vector), axes=range(protocols.num_qubits(stabilizer)), prng=np.random.RandomState(), log_of_measurement_results={}) protocols.act_on(stabilizer, args) return np.allclose(args.target_tensor, state_vector)
def _run(self, circuit: circuits.Circuit, repetitions: int) -> Dict[str, np.ndarray]: measurements: Dict[str, List[int]] = { key: [] for key in protocols.measurement_keys(circuit) } axes_map = {q: i for i, q in enumerate(circuit.all_qubits())} for _ in range(repetitions): state = ActOnCliffordTableauArgs( CliffordTableau(num_qubits=len(axes_map)), axes=(), prng=self._prng, log_of_measurement_results={}, ) for op in circuit.all_operations(): state.axes = tuple(axes_map[q] for q in op.qubits) protocols.act_on(op, state) for k, v in state.log_of_measurement_results.items(): measurements[k].append(v) return {k: np.array(v) for k, v in measurements.items()}
def _act_on_(self, args): from cirq import ops, sim, protocols if isinstance( args, sim.ActOnStabilizerCHFormArgs) and self._exponent % 2 == 1: args.state.omega *= 1j**(2 * self.global_shift * self._exponent) protocols.act_on(ops.CNOT, args) args.axes = args.axes[::-1] protocols.act_on(ops.CNOT, args) args.axes = args.axes[::-1] protocols.act_on(ops.CNOT, args) return True return NotImplemented
def _act_on_(self, args: 'cirq.ActOnArgs', qubits: Sequence['cirq.Qid']): from cirq import ops, sim, protocols if isinstance(args, (sim.ActOnStabilizerCHFormArgs, sim.ActOnCliffordTableauArgs)): if not self._has_stabilizer_effect_(): return NotImplemented if isinstance(args, sim.ActOnStabilizerCHFormArgs): args.state.omega *= 1j ** (2 * self.global_shift * self._exponent) if self._exponent % 2 == 1: protocols.act_on(ops.CNOT, args, qubits) protocols.act_on(ops.CNOT, args, tuple(reversed(qubits))) protocols.act_on(ops.CNOT, args, qubits) # An even exponent does not change anything except the global phase above. return True return NotImplemented
def apply_operation(self, op: 'cirq.Operation'): """Applies the operation to the state.""" protocols.act_on(op, self)
def apply_operation(self, op: 'cirq.Operation'): protocols.act_on(op, self)