def _apply_unitary_to_tensor_( self, target_tensor: np.ndarray, available_buffer: np.ndarray, axes: Sequence[int], ) -> np.ndarray: control = axes[0] rest = axes[1:] active = linalg.slice_for_qubits_equal_to([control], 1) sub_axes = [r - int(r > control) for r in rest] target_view = target_tensor[active] buffer_view = available_buffer[active] result = protocols.apply_unitary_to_tensor(self.sub_gate, target_view, buffer_view, sub_axes, default=NotImplemented) if result is NotImplemented: return NotImplemented if result is target_view: return target_tensor if result is buffer_view: inactive = linalg.slice_for_qubits_equal_to([control], 0) available_buffer[inactive] = target_tensor[inactive] return available_buffer # HACK: assume they didn't somehow escape the slice view and edit the # rest of target_tensor. target_tensor[active] = result return target_tensor
def assert_apply_unitary_to_tensor_is_consistent_with_unitary( val: Any, exponents: Sequence[Any] = (1,), qubit_count: Optional[int] = None) -> None: n = qubit_count if qubit_count is not None else _infer_qubit_count(val) for exponent in exponents: val_exp = val if exponent == 1 else val**exponent eye = np.eye(2 << n, dtype=np.complex128).reshape((2,) * (2 * n + 2)) actual = protocols.apply_unitary_to_tensor( val=val_exp, target_tensor=eye, available_buffer=np.ones_like(eye) * float('nan'), axes=list(range(n)), default=None) expected = protocols.unitary(val_exp, default=None) # If you don't have a unitary, you shouldn't be able to apply a unitary. if expected is None: assert actual is None else: expected = np.kron(expected, np.eye(2)) # If you applied a unitary, it should match the one you say you have. if actual is not None: np.testing.assert_allclose( actual.reshape(2 << n, 2 << n), expected)
def _base_iterator( self, circuit: circuits.Circuit, qubit_order: ops.QubitOrderOrList, initial_state: Union[int, np.ndarray], perform_measurements: bool = True, ) -> Iterator[simulator.StepResult]: qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for( circuit.all_qubits()) num_qubits = len(qubits) qubit_map = {q: i for i, q in enumerate(qubits)} state = wave_function.to_valid_state_vector(initial_state, num_qubits, self._dtype) def on_stuck(bad_op: ops.Operation): return TypeError( "Can't simulate unknown operations that don't specify a " "_unitary_ method, a _decompose_ method, or " "(_has_unitary_ + _apply_unitary_to_tensor_) methods" ": {!r}".format(bad_op)) def keep(potential_op: ops.Operation) -> bool: return (protocols.has_unitary(potential_op) or ops.MeasurementGate.is_measurement(potential_op)) state = np.reshape(state, (2, ) * num_qubits) buffer = np.empty((2, ) * num_qubits, dtype=self._dtype) for moment in circuit: measurements = collections.defaultdict( list) # type: Dict[str, List[bool]] unitary_ops_and_measurements = protocols.decompose( moment.operations, keep=keep, on_stuck_raise=on_stuck) for op in unitary_ops_and_measurements: indices = [qubit_map[qubit] for qubit in op.qubits] if ops.MeasurementGate.is_measurement(op): gate = cast(ops.MeasurementGate, cast(ops.GateOperation, op).gate) if perform_measurements: invert_mask = gate.invert_mask or num_qubits * ( False, ) # Measure updates inline. bits, _ = wave_function.measure_state_vector( state, indices, state) corrected = [ bit ^ mask for bit, mask in zip(bits, invert_mask) ] measurements[cast(str, gate.key)].extend(corrected) else: result = protocols.apply_unitary_to_tensor( op, state, buffer, indices) if result is buffer: buffer = state state = result yield SimulatorStep(state, measurements, qubit_map, self._dtype)
def _apply_unitary_to_tensor_(self, target_tensor: np.ndarray, available_buffer: np.ndarray, axes: Sequence[int], ) -> np.ndarray: return protocols.apply_unitary_to_tensor( controlled_gate.ControlledGate(common_gates.SWAP), target_tensor, available_buffer, axes, default=NotImplemented)
def _apply_unitary_to_tensor_( self, target_tensor: np.ndarray, available_buffer: np.ndarray, axes: Sequence[int], ) -> Union[np.ndarray, NotImplementedType]: return protocols.apply_unitary_to_tensor(self.gate, target_tensor, available_buffer, axes, default=NotImplemented)
def _apply_unitary_to_tensor_( self, target_tensor: np.ndarray, available_buffer: np.ndarray, axes: Sequence[int], ) -> np.ndarray: if protocols.is_parameterized(self): return NotImplemented p = 1j**(2 * self._exponent * self._global_shift) if p != 1: target_tensor *= p return protocols.apply_unitary_to_tensor( controlled_gate.ControlledGate( controlled_gate.ControlledGate(common_gates.X**self.exponent)), target_tensor, available_buffer, axes, default=NotImplemented)
def assert_has_consistent_apply_unitary( val: Any, *, qubit_count: Optional[int] = None) -> None: """Tests whether a value's _apply_unitary_to_tensor_ is correct. Contrasts the effects of the value's `_apply_unitary_to_tensor_` with the matrix returned by the value's `_unitary_` method. Args: val: The value under test. Should have a `__pow__` method. qubit_count: Usually inferred. The number of qubits the value acts on. This argument isn't needed if the gate has a unitary matrix or implements `cirq.SingleQubitGate`/`cirq.TwoQubitGate`/ `cirq.ThreeQubitGate`. """ expected = protocols.unitary(val, default=None) if qubit_count is not None: n = qubit_count elif expected is not None: n = expected.shape[0].bit_length() - 1 else: n = _infer_qubit_count(val) eye = np.eye(2 << n, dtype=np.complex128).reshape((2,) * (2 * n + 2)) actual = protocols.apply_unitary_to_tensor( val=val, target_tensor=eye, available_buffer=np.ones_like(eye) * float('nan'), axes=list(range(1, n + 1)), default=None) # If you don't have a unitary, you shouldn't be able to apply a unitary. if expected is None: assert actual is None else: expected = np.kron(np.eye(2), expected) # If you applied a unitary, it should match the one you say you have. if actual is not None: np.testing.assert_allclose( actual.reshape(2 << n, 2 << n), expected)